• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <gtest/gtest.h>  // For FRIEND_TEST
6 
7 #include "include/gestures.h"
8 #include "include/interpreter.h"
9 #include "include/prop_registry.h"
10 #include "include/tracer.h"
11 
12 #ifndef GESTURES_MOUSE_INTERPRETER_H_
13 #define GESTURES_MOUSE_INTERPRETER_H_
14 
15 namespace gestures {
16 
17 class MouseInterpreter : public Interpreter, public PropertyDelegate {
18   FRIEND_TEST(MouseInterpreterTest, SimpleTest);
19   FRIEND_TEST(MouseInterpreterTest, HighResolutionVerticalScrollTest);
20   FRIEND_TEST(MouseInterpreterTest, JankyScrollTest);
21   FRIEND_TEST(MouseInterpreterTest, WheelTickReportingHighResTest);
22   FRIEND_TEST(MouseInterpreterTest, WheelTickReportingLowResTest);
23  public:
24   MouseInterpreter(PropRegistry* prop_reg, Tracer* tracer);
~MouseInterpreter()25   virtual ~MouseInterpreter() {};
26 
27  protected:
28   virtual void SyncInterpretImpl(HardwareState* hwstate, stime_t* timeout);
29   // These functions interpret mouse events, which include button clicking and
30   // mouse movement. This function needs two consecutive HardwareState. If no
31   // mouse events are presented, result object is not modified. Scroll wheel
32   // events are not interpreted as they are handled differently for normal
33   // mice and multi-touch mice (ignored for multi-touch mice and accelerated
34   // for normal mice).
35   void InterpretMouseButtonEvent(const HardwareState& prev_state,
36                                  const HardwareState& hwstate);
37 
38   void InterpretMouseMotionEvent(const HardwareState& prev_state,
39                                  const HardwareState& hwstate);
40   // Check for scroll wheel events and produce scroll gestures.
41   void InterpretScrollWheelEvent(const HardwareState& hwstate,
42                                  bool is_vertical);
43   bool EmulateScrollWheel(const HardwareState& hwstate);
44  private:
45   struct WheelRecord {
WheelRecordWheelRecord46     WheelRecord(float v, stime_t t): value(v), timestamp(t) {}
WheelRecordWheelRecord47     WheelRecord(): value(0), timestamp(0) {}
48     float value;
49     stime_t timestamp;
50   };
51 
52   // Accelerate mouse scroll offsets so that it is larger when the user scroll
53   // the mouse wheel faster.
54   double ComputeScrollAccelFactor(double input_speed);
55 
56   Gesture CreateWheelGesture(stime_t start, stime_t end, float dx, float dy,
57                              int tick_120ths_dx, int tick_120ths_dy);
58 
59   HardwareState prev_state_;
60 
61   // Records last scroll wheel event.
62   WheelRecord last_wheel_, last_hwheel_;
63 
64   // Accumulators to measure scroll distance while doing scroll wheel emulation
65   double wheel_emulation_accu_x_;
66   double wheel_emulation_accu_y_;
67 
68   // True while wheel emulation is locked in.
69   bool wheel_emulation_active_;
70 
71   // f_approximated = a0 + a1*v + a2*v^2 + a3*v^3 + a4*v^4
72   double scroll_accel_curve_[5];
73 
74   // Reverse wheel scrolling.
75   BoolProperty reverse_scrolling_;
76 
77   // Enable high-resolution scrolling.
78   BoolProperty hi_res_scrolling_;
79 
80   // We use normal CDF to simulate scroll wheel acceleration curve. Use the
81   // following method to generate the coefficients of a degree-4 polynomial
82   // regression for a specific normal cdf in Python.
83   //
84   // Note: x for wheel value, v for velocity, y for scroll pixels (offset),
85   // and v = x / dt.
86   //
87   // The offset is computed as x * f(v) where f() outputs the acceleration
88   // factor for the given input speed. The formula allows us to produce similar
89   // offsets regardless of the mouse scrolling resolution. Since we want y to
90   // follow the normal CDF, we need to attenuate the case where x >= 1. This can
91   // happen when the user scrolls really fast, e.g., more than 1 unit within 8ms
92   // for a common, low-resolution mouse.
93   //
94   // In reality, v ranges from 1 to 120+ for an Apple Mighty Mouse, use range
95   // greater than that to minimize approximation error at the end points.
96   // In our case, the range is [-50, 200].
97   //
98   // Python (3) code:
99   // import numpy as np
100   // from scipy.stats import norm
101   // v = np.arange(-50, 201)
102   // f = (580 * norm.cdf(v, 100, 40) + 20) / np.maximum(v / 125.0, 1)
103   // coeff = np.flip(np.polyfit(v, f, 4), 0)
104   // Adjust the scroll acceleration curve
105   DoubleArrayProperty scroll_accel_curve_prop_;
106 
107   // when x is 177, the polynomial curve gives 450, the max pixels to scroll.
108   DoubleProperty scroll_max_allowed_input_speed_;
109 
110   // Force scroll wheel emulation for any devices
111   BoolProperty force_scroll_wheel_emulation_;
112 
113   // Multiplication factor to translate cursor motion into scrolling
114   DoubleProperty scroll_wheel_emulation_speed_;
115 
116   // Movement distance after which to start scroll wheel emulation [in mm]
117   DoubleProperty scroll_wheel_emulation_thresh_;
118 
119   // Whether to output GestureMouseWheel or GestureScroll structs from scrolls.
120   // TODO(chromium:1077644): remove once Chrome is migrated to the new structs.
121   BoolProperty output_mouse_wheel_gestures_;
122 };
123 
124 }  // namespace gestures
125 
126 #endif  // GESTURES_MOUSE_INTERPRETER_H_
127