summaryrefslogtreecommitdiff
path: root/include/accel_filter_interpreter.h
blob: 024abb760dd21942d706bb68783e3e1ec0b4a77d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright 2012 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <math.h>

#include <memory>
#include <gtest/gtest.h>  // for FRIEND_TEST

#include "include/filter_interpreter.h"
#include "include/gestures.h"
#include "include/prop_registry.h"
#include "include/tracer.h"

#ifndef GESTURES_ACCEL_FILTER_INTERPRETER_H_
#define GESTURES_ACCEL_FILTER_INTERPRETER_H_

namespace gestures {

// This interpreter provides pointer and scroll acceleration based on
// an acceleration curve and the user's sensitivity setting.
//
// For additional documentation, see ../docs/accel_filter_interpreter.md.

class AccelFilterInterpreter : public FilterInterpreter {
  FRIEND_TEST(AccelFilterInterpreterTest, CurveSegmentInitializerTest);
  FRIEND_TEST(AccelFilterInterpreterTest, CustomAccelTest);
  FRIEND_TEST(AccelFilterInterpreterTest, SimpleTest);
  FRIEND_TEST(AccelFilterInterpreterTest, TimingTest);
  FRIEND_TEST(AccelFilterInterpreterTest, NotSmoothingTest);
  FRIEND_TEST(AccelFilterInterpreterTest, SmoothingTest);
  FRIEND_TEST(AccelFilterInterpreterTest, TinyMoveTest);
  FRIEND_TEST(AccelFilterInterpreterTest, UnacceleratedMouseTest);
  FRIEND_TEST(AccelFilterInterpreterTest, UnacceleratedTouchpadTest);
  FRIEND_TEST(AccelFilterInterpreterTest, TouchpadPointAccelCurveTest);
  FRIEND_TEST(AccelFilterInterpreterTest, TouchpadScrollAccelCurveTest);
 public:
  // Takes ownership of |next|:
  AccelFilterInterpreter(PropRegistry* prop_reg, Interpreter* next,
                         Tracer* tracer);
  virtual ~AccelFilterInterpreter() {}

  virtual void ConsumeGesture(const Gesture& gs);

 private:
  struct CurveSegment {
    CurveSegment() : x_(INFINITY), sqr_(0.0), mul_(1.0), int_(0.0) {}
    CurveSegment(float x, float s, float m, float b)
        : x_(x), sqr_(s), mul_(m), int_(b) {}
    CurveSegment(const CurveSegment& that)
        : x_(that.x_), sqr_(that.sqr_), mul_(that.mul_), int_(that.int_) {}
    // Be careful adding new members: We currently cast arrays of CurveSegment
    // to arrays of float (to expose to the properties system)
    double x_;  // Max X value of segment. User's point will be less than this.
    double sqr_;  // x^2 multiplier
    double mul_;  // Slope of line (x multiplier)
    double int_;  // Intercept of line
  };

  //**************************************************************************
  // Worker Funnctions that are used internal to this class as well
  // as giving internal information for testing/research purposes.

  // Calculate the Delta Time for a given gesture.
  //    in:     gs, provided Gesture
  //    ret:    delta time
  float get_dt(const Gesture& gs);

  // Calculate the Delta Time and adjust the value if the calculation gives
  // an out of bounds value.
  //    in:     gs, provided Gesture
  //    ret:    Reasonable Delta Time
  float get_adjusted_dt(const Gesture& gs);

  // The calculations in the ConsumeGestures is generic but works on
  // different fields based on what the gesture is.  This worker will
  // gather the correct values for the ConsumeGestures process.
  //    in:     gs, provided Gesture
  //    out:    dx, address of delta X
  //    out:    dy, address of delta Y
  //    out:    x_scale, value of X scaling factor
  //    out:    y_scale, value of Y scaling factor
  //    out:    scale_out_x, address of X value to adjust
  //    out:    scale_out_y, address of Y value to adjust
  //    out:    scale_out_x_ordinal, address of X orginal value to adjust
  //    out:    scale_out_y_ordinal, address of Y orginal value to adjust
  //    out:    segs, address of CurveSegment array to use
  //    out:    max_segs, number of array entries of segs
  //    ret:    true, acceleration expected
  //            false, acceleration not expected
  bool get_accel_parameters(
      Gesture& gs,
      float*& dx, float*& dy,
      float& x_scale, float& y_scale,
      float*& scale_out_x, float*& scale_out_y,
      float*& scale_out_x_ordinal, float*& scale_out_y_ordinal,
      CurveSegment*& segs, size_t& max_segs);

  // Given a dx/dy/dt (non-fling motion) or, if dx and dy are nullptr,
  // vx/vy (fling velocity) calculate the speed.
  //    in:     dx, address of delta X
  //    in:     dy, address of delta Y
  //    in:     vx, value of X velocity (only valid if dx/dy are nullptr)
  //    in:     vy, value of Y velocity (only valid if dx/dy are nullptr)
  //    in:     dt, value of delta time (assumed 1 if dx/dy are nullptr)
  //    out:    speed, actual distance/delta time
  //    ret:    true, acceleration expected
  //            false, acceleration not expected
  bool get_actual_speed(
      float* dx, float* dy,
      float vx, float vy,
      float dt,
      float& speed);

  // Speed smoothing, this is currently disabled but can be enabled by
  // means of the smooth_accel_ Property.
  //    in:     gs, provided Gesture
  //    inout:  speed, actual speed on input and smoothed on output
  void smooth_speed(Gesture& gs, float& speed);

  // Map a speed on a given CurveSegment array to a ratio multiplier.
  //    in:     segs, address of CurveSegment array being used
  //    in:     max_segs, number of array entries in segs
  //    in:     speed, actual distance/delta time value
  //    ret:    determined gain to apply
  float RatioFromAccelCurve(CurveSegment const * segs,
                            size_t const max_segs,
                            float const speed);

  //**************************************************************************

  static const size_t kMaxCurveSegs = 3;
  static const size_t kMaxCustomCurveSegs = 20;
  static const size_t kMaxUnaccelCurveSegs = 1;

  static const size_t kMaxAccelCurves = 5;

  // curves for sensitivity 1..5
  CurveSegment point_curves_[kMaxAccelCurves][kMaxCurveSegs];
  CurveSegment old_mouse_point_curves_[kMaxAccelCurves][kMaxCurveSegs];
  CurveSegment mouse_point_curves_[kMaxAccelCurves][kMaxCurveSegs];
  CurveSegment scroll_curves_[kMaxAccelCurves][kMaxCurveSegs];

  // curves when acceleration is disabled.
  CurveSegment unaccel_point_curves_[kMaxAccelCurves];
  CurveSegment unaccel_mouse_curves_[kMaxAccelCurves];
  // TODO(zentaro): Add unaccelerated scroll curves.

  // Custom curves
  CurveSegment tp_custom_point_[kMaxCustomCurveSegs];
  CurveSegment tp_custom_scroll_[kMaxCustomCurveSegs];
  CurveSegment mouse_custom_point_[kMaxCustomCurveSegs];
  // Note: there is no mouse_custom_scroll_ b/c mouse wheel accel is
  // handled in the MouseInterpreter class.

  // See max* and min_reasonable_dt_ properties
  stime_t last_reasonable_dt_ = 0.05;

  // These are used to calculate acceleration, see smooth_accel_
  stime_t last_end_time_ = -1.0;

  std::vector<float> last_mags_;
  static const size_t kMaxLastMagsSize = 2;

  // These properties expose the custom curves (just above) to the
  // property system.
  DoubleArrayProperty tp_custom_point_prop_;
  DoubleArrayProperty tp_custom_scroll_prop_;
  DoubleArrayProperty mouse_custom_point_prop_;

  // These properties enable use of custom curves (just above).
  BoolProperty use_custom_tp_point_curve_;
  BoolProperty use_custom_tp_scroll_curve_;
  BoolProperty use_custom_mouse_curve_;

  IntProperty pointer_sensitivity_;  // [1..5]
  IntProperty scroll_sensitivity_;  // [1..5]

  DoubleProperty point_x_out_scale_;
  DoubleProperty point_y_out_scale_;
  DoubleProperty scroll_x_out_scale_;
  DoubleProperty scroll_y_out_scale_;

  // These properties are automatically set on mice-like devices:
  BoolProperty use_mouse_point_curves_;  // set on {touch,nontouch} mice
  BoolProperty use_mouse_scroll_curves_;  // set on nontouch mice
  // If use_mouse_point_curves_ is true, this is consulted to see which
  // curves to use:
  BoolProperty use_old_mouse_point_curves_;
  // Flag for disabling mouse/touchpad acceleration.
  BoolProperty pointer_acceleration_;

  // Sometimes on wireless hardware (e.g. Bluetooth), packets need to be
  // resent. This can lead to a time between packets that very large followed
  // by a very small one. Very small periods especially cause problems b/c they
  // make the velocity seem very fast, which leads to an exaggeration of
  // movement.
  // To compensate, we have bounds on what we expect a reasonable period to be.
  // Events that have too large or small a period get reassigned the last
  // reasonable period.
  DoubleProperty min_reasonable_dt_;
  DoubleProperty max_reasonable_dt_;

  // If we enable smooth accel, the past few magnitudes are used to compute the
  // multiplication factor.
  BoolProperty smooth_accel_;
};

}  // namespace gestures

#endif  // GESTURES_SCALING_FILTER_INTERPRETER_H_