xref: /aosp_15_r20/external/libchrome-gestures/src/mouse_interpreter.cc (revision aed3e5085e770be5b69ce25295ecf6ddf906af95)
1*aed3e508SAndroid Build Coastguard Worker // Copyright 2012 The ChromiumOS Authors
2*aed3e508SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*aed3e508SAndroid Build Coastguard Worker // found in the LICENSE file.
4*aed3e508SAndroid Build Coastguard Worker 
5*aed3e508SAndroid Build Coastguard Worker #include "include/mouse_interpreter.h"
6*aed3e508SAndroid Build Coastguard Worker 
7*aed3e508SAndroid Build Coastguard Worker #include <math.h>
8*aed3e508SAndroid Build Coastguard Worker 
9*aed3e508SAndroid Build Coastguard Worker #include "include/logging.h"
10*aed3e508SAndroid Build Coastguard Worker #include "include/macros.h"
11*aed3e508SAndroid Build Coastguard Worker #include "include/tracer.h"
12*aed3e508SAndroid Build Coastguard Worker 
13*aed3e508SAndroid Build Coastguard Worker namespace gestures {
14*aed3e508SAndroid Build Coastguard Worker 
15*aed3e508SAndroid Build Coastguard Worker /*
16*aed3e508SAndroid Build Coastguard Worker  * The number of subdivisions that `REL_WHEEL_HI_RES` and `REL_HWHEEL_HI_RES`
17*aed3e508SAndroid Build Coastguard Worker  * have relative to `REL_WHEEL` and `REL_HWHEEL` respectively.
18*aed3e508SAndroid Build Coastguard Worker  */
19*aed3e508SAndroid Build Coastguard Worker const static int REL_WHEEL_HI_RES_UNITS_PER_NOTCH = 120;
20*aed3e508SAndroid Build Coastguard Worker 
21*aed3e508SAndroid Build Coastguard Worker // Default value for mouse scroll sensitivity.
22*aed3e508SAndroid Build Coastguard Worker const static int kMouseScrollSensitivityDefaultValue = 3;
23*aed3e508SAndroid Build Coastguard Worker 
MouseInterpreter(PropRegistry * prop_reg,Tracer * tracer)24*aed3e508SAndroid Build Coastguard Worker MouseInterpreter::MouseInterpreter(PropRegistry* prop_reg, Tracer* tracer)
25*aed3e508SAndroid Build Coastguard Worker     : Interpreter(nullptr, tracer, false),
26*aed3e508SAndroid Build Coastguard Worker       wheel_emulation_accu_x_(0.0),
27*aed3e508SAndroid Build Coastguard Worker       wheel_emulation_accu_y_(0.0),
28*aed3e508SAndroid Build Coastguard Worker       wheel_emulation_active_(false),
29*aed3e508SAndroid Build Coastguard Worker       reverse_scrolling_(prop_reg, "Mouse Reverse Scrolling", false),
30*aed3e508SAndroid Build Coastguard Worker       scroll_acceleration_(prop_reg, "Mouse Scroll Acceleration", true),
31*aed3e508SAndroid Build Coastguard Worker       scroll_sensitivity_(prop_reg,"Mouse Scroll Sensitivity",
32*aed3e508SAndroid Build Coastguard Worker         kMouseScrollSensitivityDefaultValue),
33*aed3e508SAndroid Build Coastguard Worker       hi_res_scrolling_(prop_reg, "Mouse High Resolution Scrolling", true),
34*aed3e508SAndroid Build Coastguard Worker       scroll_velocity_buffer_size_(prop_reg, "Scroll Wheel Velocity Buffer", 3),
35*aed3e508SAndroid Build Coastguard Worker       scroll_accel_curve_prop_(prop_reg, "Mouse Scroll Accel Curve",
36*aed3e508SAndroid Build Coastguard Worker           scroll_accel_curve_, sizeof(scroll_accel_curve_) / sizeof(double)),
37*aed3e508SAndroid Build Coastguard Worker       scroll_max_allowed_input_speed_(prop_reg,
38*aed3e508SAndroid Build Coastguard Worker                                       "Mouse Scroll Max Input Speed",
39*aed3e508SAndroid Build Coastguard Worker                                       177.0),
40*aed3e508SAndroid Build Coastguard Worker       force_scroll_wheel_emulation_(prop_reg,
41*aed3e508SAndroid Build Coastguard Worker                                      "Force Scroll Wheel Emulation",
42*aed3e508SAndroid Build Coastguard Worker                                      false),
43*aed3e508SAndroid Build Coastguard Worker       scroll_wheel_emulation_speed_(prop_reg,
44*aed3e508SAndroid Build Coastguard Worker                                     "Scroll Wheel Emulation Speed",
45*aed3e508SAndroid Build Coastguard Worker                                     100.0),
46*aed3e508SAndroid Build Coastguard Worker       scroll_wheel_emulation_thresh_(prop_reg,
47*aed3e508SAndroid Build Coastguard Worker                                     "Scroll Wheel Emulation Threshold",
48*aed3e508SAndroid Build Coastguard Worker                                     1.0),
49*aed3e508SAndroid Build Coastguard Worker       output_mouse_wheel_gestures_(prop_reg,
50*aed3e508SAndroid Build Coastguard Worker                                    "Output Mouse Wheel Gestures", false) {
51*aed3e508SAndroid Build Coastguard Worker   InitName();
52*aed3e508SAndroid Build Coastguard Worker   memset(&prev_state_, 0, sizeof(prev_state_));
53*aed3e508SAndroid Build Coastguard Worker   // Scroll acceleration curve coefficients. See the definition for more
54*aed3e508SAndroid Build Coastguard Worker   // details on how to generate them.
55*aed3e508SAndroid Build Coastguard Worker   scroll_accel_curve_[0] = 1.0374e+01;
56*aed3e508SAndroid Build Coastguard Worker   scroll_accel_curve_[1] = 4.1773e-01;
57*aed3e508SAndroid Build Coastguard Worker   scroll_accel_curve_[2] = 2.5737e-02;
58*aed3e508SAndroid Build Coastguard Worker   scroll_accel_curve_[3] = 8.0428e-05;
59*aed3e508SAndroid Build Coastguard Worker   scroll_accel_curve_[4] = -9.1149e-07;
60*aed3e508SAndroid Build Coastguard Worker   scroll_max_allowed_input_speed_.SetDelegate(this);
61*aed3e508SAndroid Build Coastguard Worker }
62*aed3e508SAndroid Build Coastguard Worker 
SyncInterpretImpl(HardwareState & hwstate,stime_t * timeout)63*aed3e508SAndroid Build Coastguard Worker void MouseInterpreter::SyncInterpretImpl(HardwareState& hwstate,
64*aed3e508SAndroid Build Coastguard Worker                                          stime_t* timeout) {
65*aed3e508SAndroid Build Coastguard Worker   const char name[] = "MouseInterpreter::SyncInterpretImpl";
66*aed3e508SAndroid Build Coastguard Worker   LogHardwareStatePre(name, hwstate);
67*aed3e508SAndroid Build Coastguard Worker 
68*aed3e508SAndroid Build Coastguard Worker   if(!EmulateScrollWheel(hwstate)) {
69*aed3e508SAndroid Build Coastguard Worker     // Interpret mouse events in the order of pointer moves, scroll wheels and
70*aed3e508SAndroid Build Coastguard Worker     // button clicks.
71*aed3e508SAndroid Build Coastguard Worker     InterpretMouseMotionEvent(prev_state_, hwstate);
72*aed3e508SAndroid Build Coastguard Worker     // Note that unlike touchpad scrolls, we interpret and send separate events
73*aed3e508SAndroid Build Coastguard Worker     // for horizontal/vertical mouse wheel scrolls. This is partly to match what
74*aed3e508SAndroid Build Coastguard Worker     // the xf86-input-evdev driver does and is partly because not all code in
75*aed3e508SAndroid Build Coastguard Worker     // Chrome honors MouseWheelEvent that has both X and Y offsets.
76*aed3e508SAndroid Build Coastguard Worker     InterpretScrollWheelEvent(hwstate, true);
77*aed3e508SAndroid Build Coastguard Worker     InterpretScrollWheelEvent(hwstate, false);
78*aed3e508SAndroid Build Coastguard Worker     InterpretMouseButtonEvent(prev_state_, hwstate);
79*aed3e508SAndroid Build Coastguard Worker   }
80*aed3e508SAndroid Build Coastguard Worker   // Pass max_finger_cnt = 0 to DeepCopy() since we don't care fingers and
81*aed3e508SAndroid Build Coastguard Worker   // did not allocate any space for fingers.
82*aed3e508SAndroid Build Coastguard Worker   prev_state_.DeepCopy(hwstate, 0);
83*aed3e508SAndroid Build Coastguard Worker 
84*aed3e508SAndroid Build Coastguard Worker   LogHardwareStatePost(name, hwstate);
85*aed3e508SAndroid Build Coastguard Worker }
86*aed3e508SAndroid Build Coastguard Worker 
ComputeScrollAccelFactor(double input_speed)87*aed3e508SAndroid Build Coastguard Worker double MouseInterpreter::ComputeScrollAccelFactor(double input_speed) {
88*aed3e508SAndroid Build Coastguard Worker   double result = 0.0;
89*aed3e508SAndroid Build Coastguard Worker   double term = 1.0;
90*aed3e508SAndroid Build Coastguard Worker   double allowed_speed = fabs(input_speed);
91*aed3e508SAndroid Build Coastguard Worker   if (allowed_speed > scroll_max_allowed_input_speed_.val_)
92*aed3e508SAndroid Build Coastguard Worker     allowed_speed = scroll_max_allowed_input_speed_.val_;
93*aed3e508SAndroid Build Coastguard Worker 
94*aed3e508SAndroid Build Coastguard Worker   // Compute the scroll acceleration factor.
95*aed3e508SAndroid Build Coastguard Worker   for (size_t i = 0; i < arraysize(scroll_accel_curve_); i++) {
96*aed3e508SAndroid Build Coastguard Worker     result += term * scroll_accel_curve_[i];
97*aed3e508SAndroid Build Coastguard Worker     term *= allowed_speed;
98*aed3e508SAndroid Build Coastguard Worker   }
99*aed3e508SAndroid Build Coastguard Worker   return result;
100*aed3e508SAndroid Build Coastguard Worker }
101*aed3e508SAndroid Build Coastguard Worker 
EmulateScrollWheel(const HardwareState & hwstate)102*aed3e508SAndroid Build Coastguard Worker bool MouseInterpreter::EmulateScrollWheel(const HardwareState& hwstate) {
103*aed3e508SAndroid Build Coastguard Worker   const char name[] = "MouseInterpreter::EmulateScrollWheel";
104*aed3e508SAndroid Build Coastguard Worker 
105*aed3e508SAndroid Build Coastguard Worker   if (!force_scroll_wheel_emulation_.val_ && hwprops_->has_wheel)
106*aed3e508SAndroid Build Coastguard Worker     return false;
107*aed3e508SAndroid Build Coastguard Worker   bool down = hwstate.buttons_down & GESTURES_BUTTON_MIDDLE ||
108*aed3e508SAndroid Build Coastguard Worker               (hwstate.buttons_down & GESTURES_BUTTON_LEFT &&
109*aed3e508SAndroid Build Coastguard Worker                hwstate.buttons_down & GESTURES_BUTTON_RIGHT);
110*aed3e508SAndroid Build Coastguard Worker   bool prev_down = prev_state_.buttons_down & GESTURES_BUTTON_MIDDLE ||
111*aed3e508SAndroid Build Coastguard Worker                    (prev_state_.buttons_down & GESTURES_BUTTON_LEFT &&
112*aed3e508SAndroid Build Coastguard Worker                     prev_state_.buttons_down & GESTURES_BUTTON_RIGHT);
113*aed3e508SAndroid Build Coastguard Worker   bool raising = down && !prev_down;
114*aed3e508SAndroid Build Coastguard Worker   bool falling = !down && prev_down;
115*aed3e508SAndroid Build Coastguard Worker 
116*aed3e508SAndroid Build Coastguard Worker   // Reset scroll emulation detection on button down.
117*aed3e508SAndroid Build Coastguard Worker   if (raising) {
118*aed3e508SAndroid Build Coastguard Worker     wheel_emulation_accu_x_ = 0;
119*aed3e508SAndroid Build Coastguard Worker     wheel_emulation_accu_y_ = 0;
120*aed3e508SAndroid Build Coastguard Worker     wheel_emulation_active_ = false;
121*aed3e508SAndroid Build Coastguard Worker   }
122*aed3e508SAndroid Build Coastguard Worker 
123*aed3e508SAndroid Build Coastguard Worker   // Send button event if button has been released without scrolling.
124*aed3e508SAndroid Build Coastguard Worker   if (falling && !wheel_emulation_active_) {
125*aed3e508SAndroid Build Coastguard Worker     auto button_change = Gesture(kGestureButtonsChange,
126*aed3e508SAndroid Build Coastguard Worker                            prev_state_.timestamp,
127*aed3e508SAndroid Build Coastguard Worker                            hwstate.timestamp,
128*aed3e508SAndroid Build Coastguard Worker                            prev_state_.buttons_down,
129*aed3e508SAndroid Build Coastguard Worker                            prev_state_.buttons_down,
130*aed3e508SAndroid Build Coastguard Worker                            false); // is_tap
131*aed3e508SAndroid Build Coastguard Worker     LogGestureProduce(name, button_change);
132*aed3e508SAndroid Build Coastguard Worker     ProduceGesture(button_change);
133*aed3e508SAndroid Build Coastguard Worker   }
134*aed3e508SAndroid Build Coastguard Worker 
135*aed3e508SAndroid Build Coastguard Worker   if (down) {
136*aed3e508SAndroid Build Coastguard Worker     // Detect scroll emulation
137*aed3e508SAndroid Build Coastguard Worker     if (!wheel_emulation_active_) {
138*aed3e508SAndroid Build Coastguard Worker       wheel_emulation_accu_x_ += hwstate.rel_x;
139*aed3e508SAndroid Build Coastguard Worker       wheel_emulation_accu_y_ += hwstate.rel_y;
140*aed3e508SAndroid Build Coastguard Worker       double dist_sq = wheel_emulation_accu_x_ * wheel_emulation_accu_x_ +
141*aed3e508SAndroid Build Coastguard Worker                        wheel_emulation_accu_y_ * wheel_emulation_accu_y_;
142*aed3e508SAndroid Build Coastguard Worker       double thresh_sq = scroll_wheel_emulation_thresh_.val_ *
143*aed3e508SAndroid Build Coastguard Worker                          scroll_wheel_emulation_thresh_.val_;
144*aed3e508SAndroid Build Coastguard Worker       if (dist_sq > thresh_sq) {
145*aed3e508SAndroid Build Coastguard Worker         // Lock into scroll emulation until button is released.
146*aed3e508SAndroid Build Coastguard Worker         wheel_emulation_active_ = true;
147*aed3e508SAndroid Build Coastguard Worker       }
148*aed3e508SAndroid Build Coastguard Worker     }
149*aed3e508SAndroid Build Coastguard Worker 
150*aed3e508SAndroid Build Coastguard Worker     // Transform motion into scrolling.
151*aed3e508SAndroid Build Coastguard Worker     if (wheel_emulation_active_) {
152*aed3e508SAndroid Build Coastguard Worker       double scroll_x = hwstate.rel_x * scroll_wheel_emulation_speed_.val_;
153*aed3e508SAndroid Build Coastguard Worker       double scroll_y = hwstate.rel_y * scroll_wheel_emulation_speed_.val_;
154*aed3e508SAndroid Build Coastguard Worker 
155*aed3e508SAndroid Build Coastguard Worker       auto scroll = Gesture(kGestureScroll, hwstate.timestamp,
156*aed3e508SAndroid Build Coastguard Worker                             hwstate.timestamp, scroll_x, scroll_y);
157*aed3e508SAndroid Build Coastguard Worker       LogGestureProduce(name, scroll);
158*aed3e508SAndroid Build Coastguard Worker       ProduceGesture(scroll);
159*aed3e508SAndroid Build Coastguard Worker     }
160*aed3e508SAndroid Build Coastguard Worker     return true;
161*aed3e508SAndroid Build Coastguard Worker   }
162*aed3e508SAndroid Build Coastguard Worker 
163*aed3e508SAndroid Build Coastguard Worker   return false;
164*aed3e508SAndroid Build Coastguard Worker }
165*aed3e508SAndroid Build Coastguard Worker 
InterpretScrollWheelEvent(const HardwareState & hwstate,bool is_vertical)166*aed3e508SAndroid Build Coastguard Worker void MouseInterpreter::InterpretScrollWheelEvent(const HardwareState& hwstate,
167*aed3e508SAndroid Build Coastguard Worker                                                  bool is_vertical) {
168*aed3e508SAndroid Build Coastguard Worker   const char name[] = "MouseInterpreter::InterpretScrollWheelEvent";
169*aed3e508SAndroid Build Coastguard Worker 
170*aed3e508SAndroid Build Coastguard Worker   const size_t max_buffer_size = scroll_velocity_buffer_size_.val_;
171*aed3e508SAndroid Build Coastguard Worker   const float scroll_wheel_event_time_delta_min = 0.008 * max_buffer_size;
172*aed3e508SAndroid Build Coastguard Worker   bool use_high_resolution =
173*aed3e508SAndroid Build Coastguard Worker       is_vertical && hwprops_->wheel_is_hi_res
174*aed3e508SAndroid Build Coastguard Worker       && hi_res_scrolling_.val_;
175*aed3e508SAndroid Build Coastguard Worker   // Vertical wheel or horizontal wheel.
176*aed3e508SAndroid Build Coastguard Worker   WheelRecord current_wheel;
177*aed3e508SAndroid Build Coastguard Worker   current_wheel.timestamp = hwstate.timestamp;
178*aed3e508SAndroid Build Coastguard Worker   int ticks;
179*aed3e508SAndroid Build Coastguard Worker   std::vector<WheelRecord>* last_wheels;
180*aed3e508SAndroid Build Coastguard Worker   if (is_vertical) {
181*aed3e508SAndroid Build Coastguard Worker     // Only vertical high-res scrolling is supported for now.
182*aed3e508SAndroid Build Coastguard Worker     if (use_high_resolution) {
183*aed3e508SAndroid Build Coastguard Worker       current_wheel.change = hwstate.rel_wheel_hi_res
184*aed3e508SAndroid Build Coastguard Worker           / REL_WHEEL_HI_RES_UNITS_PER_NOTCH;
185*aed3e508SAndroid Build Coastguard Worker       ticks = hwstate.rel_wheel_hi_res;
186*aed3e508SAndroid Build Coastguard Worker     } else {
187*aed3e508SAndroid Build Coastguard Worker       current_wheel.change = hwstate.rel_wheel;
188*aed3e508SAndroid Build Coastguard Worker       ticks = hwstate.rel_wheel * REL_WHEEL_HI_RES_UNITS_PER_NOTCH;
189*aed3e508SAndroid Build Coastguard Worker     }
190*aed3e508SAndroid Build Coastguard Worker     last_wheels = &last_vertical_wheels_;
191*aed3e508SAndroid Build Coastguard Worker   } else {
192*aed3e508SAndroid Build Coastguard Worker     last_wheels = &last_horizontal_wheels_;
193*aed3e508SAndroid Build Coastguard Worker     current_wheel.change = hwstate.rel_hwheel;
194*aed3e508SAndroid Build Coastguard Worker     ticks = hwstate.rel_hwheel * REL_WHEEL_HI_RES_UNITS_PER_NOTCH;
195*aed3e508SAndroid Build Coastguard Worker   }
196*aed3e508SAndroid Build Coastguard Worker 
197*aed3e508SAndroid Build Coastguard Worker   // Check if the wheel is scrolled.
198*aed3e508SAndroid Build Coastguard Worker   if (current_wheel.change) {
199*aed3e508SAndroid Build Coastguard Worker     stime_t start_time, end_time = hwstate.timestamp;
200*aed3e508SAndroid Build Coastguard Worker     // Check if this scroll is in same direction as previous scroll event.
201*aed3e508SAndroid Build Coastguard Worker     if (!last_wheels->empty() &&
202*aed3e508SAndroid Build Coastguard Worker         ((current_wheel.change < 0 && last_wheels->back().change < 0) ||
203*aed3e508SAndroid Build Coastguard Worker          (current_wheel.change > 0 && last_wheels->back().change > 0))) {
204*aed3e508SAndroid Build Coastguard Worker       start_time = last_wheels->begin()->timestamp;
205*aed3e508SAndroid Build Coastguard Worker     } else {
206*aed3e508SAndroid Build Coastguard Worker       last_wheels->clear();
207*aed3e508SAndroid Build Coastguard Worker       start_time = end_time;
208*aed3e508SAndroid Build Coastguard Worker     }
209*aed3e508SAndroid Build Coastguard Worker 
210*aed3e508SAndroid Build Coastguard Worker     // We will only accelerate scrolls if we have filled our buffer of scroll
211*aed3e508SAndroid Build Coastguard Worker     // events all in the same direction. If the buffer is full, then calculate
212*aed3e508SAndroid Build Coastguard Worker     // scroll velocity using the average velocity of the entire buffer.
213*aed3e508SAndroid Build Coastguard Worker     float velocity;
214*aed3e508SAndroid Build Coastguard Worker     if (last_wheels->size() < max_buffer_size) {
215*aed3e508SAndroid Build Coastguard Worker       velocity = 0.0;
216*aed3e508SAndroid Build Coastguard Worker     } else {
217*aed3e508SAndroid Build Coastguard Worker       stime_t dt = end_time - last_wheels->back().timestamp;
218*aed3e508SAndroid Build Coastguard Worker       if (dt < scroll_wheel_event_time_delta_min) {
219*aed3e508SAndroid Build Coastguard Worker         // The first packets received after BT wakeup may be delayed, causing
220*aed3e508SAndroid Build Coastguard Worker         // the time delta between that and the subsequent packets to be
221*aed3e508SAndroid Build Coastguard Worker         // artificially very small.
222*aed3e508SAndroid Build Coastguard Worker         // Prevent small time deltas from triggering large amounts of
223*aed3e508SAndroid Build Coastguard Worker         // acceleration by enforcing a minimum time delta.
224*aed3e508SAndroid Build Coastguard Worker         dt = scroll_wheel_event_time_delta_min;
225*aed3e508SAndroid Build Coastguard Worker       }
226*aed3e508SAndroid Build Coastguard Worker 
227*aed3e508SAndroid Build Coastguard Worker       last_wheels->pop_back();
228*aed3e508SAndroid Build Coastguard Worker       float buffer_scroll_distance = current_wheel.change;
229*aed3e508SAndroid Build Coastguard Worker       for (auto wheel : *last_wheels) {
230*aed3e508SAndroid Build Coastguard Worker         buffer_scroll_distance += wheel.change;
231*aed3e508SAndroid Build Coastguard Worker       }
232*aed3e508SAndroid Build Coastguard Worker 
233*aed3e508SAndroid Build Coastguard Worker       velocity = buffer_scroll_distance / dt;
234*aed3e508SAndroid Build Coastguard Worker     }
235*aed3e508SAndroid Build Coastguard Worker     last_wheels->insert(last_wheels->begin(), current_wheel);
236*aed3e508SAndroid Build Coastguard Worker 
237*aed3e508SAndroid Build Coastguard Worker     // When scroll acceleration is off, the scroll factor does not relate to
238*aed3e508SAndroid Build Coastguard Worker     // scroll velocity. It's simply a constant multiplier to the wheel value.
239*aed3e508SAndroid Build Coastguard Worker     const double unaccel_scroll_factors[] = { 20.0, 36.0, 72.0, 112.0, 164.0 };
240*aed3e508SAndroid Build Coastguard Worker 
241*aed3e508SAndroid Build Coastguard Worker     float offset = current_wheel.change * (
242*aed3e508SAndroid Build Coastguard Worker       scroll_acceleration_.val_?
243*aed3e508SAndroid Build Coastguard Worker       ComputeScrollAccelFactor(velocity) :
244*aed3e508SAndroid Build Coastguard Worker       unaccel_scroll_factors[scroll_sensitivity_.val_ - 1]);
245*aed3e508SAndroid Build Coastguard Worker 
246*aed3e508SAndroid Build Coastguard Worker     if (is_vertical) {
247*aed3e508SAndroid Build Coastguard Worker       // For historical reasons the vertical wheel (REL_WHEEL) is inverted
248*aed3e508SAndroid Build Coastguard Worker       if (!reverse_scrolling_.val_) {
249*aed3e508SAndroid Build Coastguard Worker         offset = -offset;
250*aed3e508SAndroid Build Coastguard Worker         ticks = -ticks;
251*aed3e508SAndroid Build Coastguard Worker       }
252*aed3e508SAndroid Build Coastguard Worker       auto scroll_wheel = CreateWheelGesture(start_time, end_time,
253*aed3e508SAndroid Build Coastguard Worker                                              0, offset, 0, ticks);
254*aed3e508SAndroid Build Coastguard Worker       LogGestureProduce(name, scroll_wheel);
255*aed3e508SAndroid Build Coastguard Worker       ProduceGesture(scroll_wheel);
256*aed3e508SAndroid Build Coastguard Worker     } else {
257*aed3e508SAndroid Build Coastguard Worker       auto scroll_wheel = CreateWheelGesture(start_time, end_time,
258*aed3e508SAndroid Build Coastguard Worker                                              offset, 0, ticks, 0);
259*aed3e508SAndroid Build Coastguard Worker       LogGestureProduce(name, scroll_wheel);
260*aed3e508SAndroid Build Coastguard Worker       ProduceGesture(scroll_wheel);
261*aed3e508SAndroid Build Coastguard Worker     }
262*aed3e508SAndroid Build Coastguard Worker   }
263*aed3e508SAndroid Build Coastguard Worker }
264*aed3e508SAndroid Build Coastguard Worker 
CreateWheelGesture(stime_t start_time,stime_t end_time,float dx,float dy,int tick_120ths_dx,int tick_120ths_dy)265*aed3e508SAndroid Build Coastguard Worker Gesture MouseInterpreter::CreateWheelGesture(
266*aed3e508SAndroid Build Coastguard Worker     stime_t start_time, stime_t end_time, float dx, float dy,
267*aed3e508SAndroid Build Coastguard Worker     int tick_120ths_dx, int tick_120ths_dy) {
268*aed3e508SAndroid Build Coastguard Worker   if (output_mouse_wheel_gestures_.val_) {
269*aed3e508SAndroid Build Coastguard Worker     return Gesture(kGestureMouseWheel, start_time, end_time, dx, dy,
270*aed3e508SAndroid Build Coastguard Worker                    tick_120ths_dx, tick_120ths_dy);
271*aed3e508SAndroid Build Coastguard Worker   } else {
272*aed3e508SAndroid Build Coastguard Worker     return Gesture(kGestureScroll, start_time, end_time, dx, dy);
273*aed3e508SAndroid Build Coastguard Worker   }
274*aed3e508SAndroid Build Coastguard Worker }
275*aed3e508SAndroid Build Coastguard Worker 
InterpretMouseButtonEvent(const HardwareState & prev_state,const HardwareState & hwstate)276*aed3e508SAndroid Build Coastguard Worker void MouseInterpreter::InterpretMouseButtonEvent(
277*aed3e508SAndroid Build Coastguard Worker     const HardwareState& prev_state, const HardwareState& hwstate) {
278*aed3e508SAndroid Build Coastguard Worker   const char name[] = "MouseInterpreter::InterpretMouseButtonEvent";
279*aed3e508SAndroid Build Coastguard Worker 
280*aed3e508SAndroid Build Coastguard Worker   const unsigned buttons[] = {
281*aed3e508SAndroid Build Coastguard Worker     GESTURES_BUTTON_LEFT,
282*aed3e508SAndroid Build Coastguard Worker     GESTURES_BUTTON_MIDDLE,
283*aed3e508SAndroid Build Coastguard Worker     GESTURES_BUTTON_RIGHT,
284*aed3e508SAndroid Build Coastguard Worker     GESTURES_BUTTON_BACK,
285*aed3e508SAndroid Build Coastguard Worker     GESTURES_BUTTON_FORWARD,
286*aed3e508SAndroid Build Coastguard Worker     GESTURES_BUTTON_SIDE,
287*aed3e508SAndroid Build Coastguard Worker     GESTURES_BUTTON_EXTRA,
288*aed3e508SAndroid Build Coastguard Worker   };
289*aed3e508SAndroid Build Coastguard Worker   unsigned down = 0, up = 0;
290*aed3e508SAndroid Build Coastguard Worker 
291*aed3e508SAndroid Build Coastguard Worker   for (unsigned i = 0; i < arraysize(buttons); i++) {
292*aed3e508SAndroid Build Coastguard Worker     if (!(prev_state.buttons_down & buttons[i]) &&
293*aed3e508SAndroid Build Coastguard Worker         (hwstate.buttons_down & buttons[i]))
294*aed3e508SAndroid Build Coastguard Worker       down |= buttons[i];
295*aed3e508SAndroid Build Coastguard Worker     if ((prev_state.buttons_down & buttons[i]) &&
296*aed3e508SAndroid Build Coastguard Worker         !(hwstate.buttons_down & buttons[i]))
297*aed3e508SAndroid Build Coastguard Worker       up |= buttons[i];
298*aed3e508SAndroid Build Coastguard Worker   }
299*aed3e508SAndroid Build Coastguard Worker 
300*aed3e508SAndroid Build Coastguard Worker   if (down || up) {
301*aed3e508SAndroid Build Coastguard Worker     auto button_change = Gesture(kGestureButtonsChange,
302*aed3e508SAndroid Build Coastguard Worker                                  prev_state.timestamp,
303*aed3e508SAndroid Build Coastguard Worker                                  hwstate.timestamp,
304*aed3e508SAndroid Build Coastguard Worker                                  down,
305*aed3e508SAndroid Build Coastguard Worker                                  up,
306*aed3e508SAndroid Build Coastguard Worker                                  false); // is_tap
307*aed3e508SAndroid Build Coastguard Worker     LogGestureProduce(name, button_change);
308*aed3e508SAndroid Build Coastguard Worker     ProduceGesture(button_change);
309*aed3e508SAndroid Build Coastguard Worker   }
310*aed3e508SAndroid Build Coastguard Worker }
311*aed3e508SAndroid Build Coastguard Worker 
InterpretMouseMotionEvent(const HardwareState & prev_state,const HardwareState & hwstate)312*aed3e508SAndroid Build Coastguard Worker void MouseInterpreter::InterpretMouseMotionEvent(
313*aed3e508SAndroid Build Coastguard Worker     const HardwareState& prev_state,
314*aed3e508SAndroid Build Coastguard Worker     const HardwareState& hwstate) {
315*aed3e508SAndroid Build Coastguard Worker   const char name[] = "MouseInterpreter::InterpretMouseMotionEvent";
316*aed3e508SAndroid Build Coastguard Worker 
317*aed3e508SAndroid Build Coastguard Worker   if (hwstate.rel_x || hwstate.rel_y) {
318*aed3e508SAndroid Build Coastguard Worker     auto move = Gesture(kGestureMove,
319*aed3e508SAndroid Build Coastguard Worker                         prev_state.timestamp,
320*aed3e508SAndroid Build Coastguard Worker                         hwstate.timestamp,
321*aed3e508SAndroid Build Coastguard Worker                         hwstate.rel_x,
322*aed3e508SAndroid Build Coastguard Worker                         hwstate.rel_y);
323*aed3e508SAndroid Build Coastguard Worker     LogGestureProduce(name, move);
324*aed3e508SAndroid Build Coastguard Worker     ProduceGesture(move);
325*aed3e508SAndroid Build Coastguard Worker   }
326*aed3e508SAndroid Build Coastguard Worker }
327*aed3e508SAndroid Build Coastguard Worker 
328*aed3e508SAndroid Build Coastguard Worker }  // namespace gestures
329