1 // Copyright 2012 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <math.h> 6 7 #include <memory> 8 #include <gtest/gtest.h> // for FRIEND_TEST 9 10 #include "include/filter_interpreter.h" 11 #include "include/gestures.h" 12 #include "include/prop_registry.h" 13 #include "include/tracer.h" 14 15 #ifndef GESTURES_ACCEL_FILTER_INTERPRETER_H_ 16 #define GESTURES_ACCEL_FILTER_INTERPRETER_H_ 17 18 namespace gestures { 19 20 // This interpreter provides pointer and scroll acceleration based on 21 // an acceleration curve and the user's sensitivity setting. 22 // 23 // For additional documentation, see ../docs/accel_filter_interpreter.md. 24 25 class AccelFilterInterpreter : public FilterInterpreter { 26 FRIEND_TEST(AccelFilterInterpreterTest, CurveSegmentInitializerTest); 27 FRIEND_TEST(AccelFilterInterpreterTest, CustomAccelTest); 28 FRIEND_TEST(AccelFilterInterpreterTest, SimpleTest); 29 FRIEND_TEST(AccelFilterInterpreterTest, TimingTest); 30 FRIEND_TEST(AccelFilterInterpreterTest, NotSmoothingTest); 31 FRIEND_TEST(AccelFilterInterpreterTest, SmoothingTest); 32 FRIEND_TEST(AccelFilterInterpreterTest, TinyMoveTest); 33 FRIEND_TEST(AccelFilterInterpreterTest, BadGestureTest); 34 FRIEND_TEST(AccelFilterInterpreterTest, BadDeltaTTest); 35 FRIEND_TEST(AccelFilterInterpreterTest, BadSpeedFlingTest); 36 FRIEND_TEST(AccelFilterInterpreterTest, BadSpeedMoveTest); 37 FRIEND_TEST(AccelFilterInterpreterTest, UnacceleratedMouseTest); 38 FRIEND_TEST(AccelFilterInterpreterTest, UnacceleratedTouchpadTest); 39 FRIEND_TEST(AccelFilterInterpreterTest, TouchpadPointAccelCurveTest); 40 FRIEND_TEST(AccelFilterInterpreterTest, TouchpadScrollAccelCurveTest); 41 FRIEND_TEST(AccelFilterInterpreterTest, AccelDebugDataTest); 42 public: 43 // Takes ownership of |next|: 44 AccelFilterInterpreter(PropRegistry* prop_reg, Interpreter* next, 45 Tracer* tracer); ~AccelFilterInterpreter()46 virtual ~AccelFilterInterpreter() {} 47 48 virtual void ConsumeGesture(const Gesture& gs); 49 50 private: 51 struct CurveSegment { CurveSegmentCurveSegment52 CurveSegment() : x_(INFINITY), sqr_(0.0), mul_(1.0), int_(0.0) {} CurveSegmentCurveSegment53 CurveSegment(float x, float s, float m, float b) 54 : x_(x), sqr_(s), mul_(m), int_(b) {} CurveSegmentCurveSegment55 CurveSegment(const CurveSegment& that) 56 : x_(that.x_), sqr_(that.sqr_), mul_(that.mul_), int_(that.int_) {} 57 // Be careful adding new members: We currently cast arrays of CurveSegment 58 // to arrays of float (to expose to the properties system) 59 double x_; // Max X value of segment. User's point will be less than this. 60 double sqr_; // x^2 multiplier 61 double mul_; // Slope of line (x multiplier) 62 double int_; // Intercept of line 63 }; 64 65 //************************************************************************** 66 // Worker Funnctions that are used internal to this class as well 67 // as giving internal information for testing/research purposes. 68 69 // Calculate the Delta Time for a given gesture. 70 // in: gs, provided Gesture 71 // ret: delta time 72 float get_dt(const Gesture& gs); 73 74 // Calculate the Delta Time and adjust the value if the calculation gives 75 // an out of bounds value. 76 // in: gs, provided Gesture 77 // ret: Reasonable Delta Time 78 float get_adjusted_dt(const Gesture& gs); 79 80 // The calculations in the ConsumeGestures is generic but works on 81 // different fields based on what the gesture is. This worker will 82 // gather the correct values for the ConsumeGestures process. 83 // in: gs, provided Gesture 84 // out: dx, address of delta X 85 // out: dy, address of delta Y 86 // out: x_scale, value of X scaling factor 87 // out: y_scale, value of Y scaling factor 88 // out: scale_out_x, address of X value to adjust 89 // out: scale_out_y, address of Y value to adjust 90 // out: scale_out_x_ordinal, address of X orginal value to adjust 91 // out: scale_out_y_ordinal, address of Y orginal value to adjust 92 // out: segs, address of CurveSegment array to use 93 // out: max_segs, number of array entries of segs 94 // ret: true, acceleration expected 95 // false, acceleration not expected 96 bool get_accel_parameters( 97 Gesture& gs, 98 float*& dx, float*& dy, 99 float& x_scale, float& y_scale, 100 float*& scale_out_x, float*& scale_out_y, 101 float*& scale_out_x_ordinal, float*& scale_out_y_ordinal, 102 CurveSegment*& segs, size_t& max_segs); 103 104 // Given a dx/dy/dt (non-fling motion) or, if dx and dy are nullptr, 105 // vx/vy (fling velocity) calculate the speed. 106 // in: dx, address of delta X 107 // in: dy, address of delta Y 108 // in: vx, value of X velocity (only valid if dx/dy are nullptr) 109 // in: vy, value of Y velocity (only valid if dx/dy are nullptr) 110 // in: dt, value of delta time (assumed 1 if dx/dy are nullptr) 111 // out: speed, actual distance/delta time 112 // ret: true, acceleration expected 113 // false, acceleration not expected 114 bool get_actual_speed( 115 float* dx, float* dy, 116 float vx, float vy, 117 float dt, 118 float& speed); 119 120 // Speed smoothing, this is currently disabled but can be enabled by 121 // means of the smooth_accel_ Property. 122 // in: gs, provided Gesture 123 // inout: speed, actual speed on input and smoothed on output 124 void smooth_speed(const Gesture& gs, float& speed); 125 126 // Map a speed on a given CurveSegment array to a ratio multiplier. 127 // in: segs, address of CurveSegment array being used 128 // in: max_segs, number of array entries in segs 129 // in: speed, actual distance/delta time value 130 // ret: determined gain to apply 131 float RatioFromAccelCurve(const CurveSegment* segs, 132 const size_t max_segs, 133 const float speed); 134 135 template<typename T> LogDebugData(const T & debug_data)136 void LogDebugData(const T& debug_data) { 137 using EventDebug = ActivityLog::EventDebug; 138 if (EventDebugLoggingIsEnabled(EventDebug::Accel)) 139 log_->LogDebugData(debug_data); 140 } 141 142 //************************************************************************** 143 144 static const size_t kMaxCurveSegs = 3; 145 static const size_t kMaxCustomCurveSegs = 20; 146 static const size_t kMaxUnaccelCurveSegs = 1; 147 148 static const size_t kMaxAccelCurves = 5; 149 150 // curves for sensitivity 1..5 151 CurveSegment point_curves_[kMaxAccelCurves][kMaxCurveSegs]; 152 CurveSegment old_mouse_point_curves_[kMaxAccelCurves][kMaxCurveSegs]; 153 CurveSegment mouse_point_curves_[kMaxAccelCurves][kMaxCurveSegs]; 154 CurveSegment scroll_curves_[kMaxAccelCurves][kMaxCurveSegs]; 155 156 // curves when acceleration is disabled. 157 CurveSegment unaccel_point_curves_[kMaxAccelCurves]; 158 CurveSegment unaccel_mouse_curves_[kMaxAccelCurves]; 159 // TODO(zentaro): Add unaccelerated scroll curves. 160 161 // Custom curves 162 CurveSegment tp_custom_point_[kMaxCustomCurveSegs]; 163 CurveSegment tp_custom_scroll_[kMaxCustomCurveSegs]; 164 CurveSegment mouse_custom_point_[kMaxCustomCurveSegs]; 165 // Note: there is no mouse_custom_scroll_ b/c mouse wheel accel is 166 // handled in the MouseInterpreter class. 167 168 // See max* and min_reasonable_dt_ properties 169 stime_t last_reasonable_dt_ = 0.05; 170 171 // These are used to calculate acceleration, see smooth_accel_ 172 stime_t last_end_time_ = -1.0; 173 174 std::vector<float> last_mags_; 175 static const size_t kMaxLastMagsSize = 2; 176 177 // These properties expose the custom curves (just above) to the 178 // property system. 179 DoubleArrayProperty tp_custom_point_prop_; 180 DoubleArrayProperty tp_custom_scroll_prop_; 181 DoubleArrayProperty mouse_custom_point_prop_; 182 183 // These properties enable use of custom curves (just above). 184 BoolProperty use_custom_tp_point_curve_; 185 BoolProperty use_custom_tp_scroll_curve_; 186 BoolProperty use_custom_mouse_curve_; 187 188 IntProperty pointer_sensitivity_; // [1..5] 189 IntProperty scroll_sensitivity_; // [1..5] 190 191 DoubleProperty point_x_out_scale_; 192 DoubleProperty point_y_out_scale_; 193 DoubleProperty scroll_x_out_scale_; 194 DoubleProperty scroll_y_out_scale_; 195 196 // These properties are automatically set on mice-like devices: 197 BoolProperty use_mouse_point_curves_; // set on {touch,nontouch} mice 198 BoolProperty use_mouse_scroll_curves_; // set on nontouch mice 199 // If use_mouse_point_curves_ is true, this is consulted to see which 200 // curves to use: 201 BoolProperty use_old_mouse_point_curves_; 202 // Flag for disabling mouse/touchpad acceleration. 203 BoolProperty pointer_acceleration_; 204 205 // Sometimes on wireless hardware (e.g. Bluetooth), packets need to be 206 // resent. This can lead to a time between packets that very large followed 207 // by a very small one. Very small periods especially cause problems b/c they 208 // make the velocity seem very fast, which leads to an exaggeration of 209 // movement. 210 // To compensate, we have bounds on what we expect a reasonable period to be. 211 // Events that have too large or small a period get reassigned the last 212 // reasonable period. 213 DoubleProperty min_reasonable_dt_; 214 DoubleProperty max_reasonable_dt_; 215 216 // If we enable smooth accel, the past few magnitudes are used to compute the 217 // multiplication factor. 218 BoolProperty smooth_accel_; 219 }; 220 221 } // namespace gestures 222 223 #endif // GESTURES_SCALING_FILTER_INTERPRETER_H_ 224