| // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <gtest/gtest.h> // For FRIEND_TEST |
| |
| #include "gestures/include/gestures.h" |
| #include "gestures/include/interpreter.h" |
| #include "gestures/include/prop_registry.h" |
| #include "gestures/include/tracer.h" |
| |
| #ifndef GESTURES_MOUSE_INTERPRETER_H_ |
| #define GESTURES_MOUSE_INTERPRETER_H_ |
| |
| namespace gestures { |
| |
| class MouseInterpreter : public Interpreter, public PropertyDelegate { |
| FRIEND_TEST(MouseInterpreterTest, SimpleTest); |
| FRIEND_TEST(MouseInterpreterTest, HighResolutionVerticalScrollTest); |
| public: |
| MouseInterpreter(PropRegistry* prop_reg, Tracer* tracer); |
| virtual ~MouseInterpreter() {}; |
| |
| protected: |
| virtual void SyncInterpretImpl(HardwareState* hwstate, stime_t* timeout); |
| // These functions interpret mouse events, which include button clicking and |
| // mouse movement. This function needs two consecutive HardwareState. If no |
| // mouse events are presented, result object is not modified. Scroll wheel |
| // events are not interpreted as they are handled differently for normal |
| // mice and multi-touch mice (ignored for multi-touch mice and accelerated |
| // for normal mice). |
| void InterpretMouseButtonEvent(const HardwareState& prev_state, |
| const HardwareState& hwstate); |
| |
| void InterpretMouseMotionEvent(const HardwareState& prev_state, |
| const HardwareState& hwstate); |
| // Check for scroll wheel events and produce scroll gestures. |
| void InterpretScrollWheelEvent(const HardwareState& hwstate, |
| bool is_vertical); |
| bool EmulateScrollWheel(const HardwareState& hwstate); |
| private: |
| struct WheelRecord { |
| WheelRecord(float v, stime_t t): value(v), timestamp(t) {} |
| WheelRecord(): value(0), timestamp(0) {} |
| float value; |
| stime_t timestamp; |
| }; |
| |
| // Accelerate mouse scroll offsets so that it is larger when the user scroll |
| // the mouse wheel faster. |
| double ComputeScrollAccelFactor(double input_speed); |
| |
| HardwareState prev_state_; |
| |
| // Records last scroll wheel event. |
| WheelRecord last_wheel_, last_hwheel_; |
| |
| // Accumulators to measure scroll distance while doing scroll wheel emulation |
| double wheel_emulation_accu_x_; |
| double wheel_emulation_accu_y_; |
| |
| // True while wheel emulation is locked in. |
| bool wheel_emulation_active_; |
| |
| // Reverse wheel scrolling. |
| BoolProperty reverse_scrolling_; |
| |
| // Enable high-resolution scrolling. |
| BoolProperty hi_res_scrolling_; |
| |
| // We use normal CDF to simulate scroll wheel acceleration curve. Use the |
| // following method to generate the coefficients of a degree-4 polynomial |
| // regression for a specific normal cdf in Python. |
| // |
| // Note: x for wheel value, v for velocity, y for scroll pixels (offset), |
| // and v = x / dt. |
| // |
| // The offset is computed as x * f(v) where f() outputs the acceleration |
| // factor for the given input speed. The formula allows us to produce similar |
| // offsets regardless of the mouse scrolling resolution. Since we want y to |
| // follow the normal CDF, we need to attenuate the case where x >= 1. This can |
| // happen when the user scrolls really fast, e.g., more than 1 unit within 8ms |
| // for a common, low-resolution mouse. |
| // |
| // In reality, v ranges from 1 to 120+ for an Apple Mighty Mouse, use range |
| // greater than that to minimize approximation error at the end points. |
| // In our case, the range is [-50, 200]. |
| // |
| // Python (3) code: |
| // import numpy as np |
| // from scipy.stats import norm |
| // v = np.arange(-50, 201) |
| // f = (580 * norm.cdf(v, 100, 40) + 20) / np.maximum(v / 125.0, 1) |
| // coeff = np.flip(np.polyfit(v, f, 4), 0) |
| |
| // f_approximated = a0 + a1*v + a2*v^2 + a3*v^3 + a4*v^4 |
| double scroll_accel_curve_[5]; |
| |
| // Adjust the scroll acceleration curve |
| DoubleArrayProperty scroll_accel_curve_prop_; |
| |
| // when x is 177, the polynomial curve gives 450, the max pixels to scroll. |
| DoubleProperty scroll_max_allowed_input_speed_; |
| |
| // Force scroll wheel emulation for any devices |
| BoolProperty force_scroll_wheel_emulation_; |
| |
| // Multiplication factor to translate cursor motion into scrolling |
| DoubleProperty scroll_wheel_emulation_speed_; |
| |
| // Movement distance after which to start scroll wheel emulation [in mm] |
| DoubleProperty scroll_wheel_emulation_thresh_; |
| }; |
| |
| } // namespace gestures |
| |
| #endif // GESTURES_MOUSE_INTERPRETER_H_ |