diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-02-02 23:49:05 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-02-02 23:49:05 +0000 |
commit | ad4fde5e2f19c1cf1961c3b13410cd5e93a0738d (patch) | |
tree | ffff4c26722421cd89f9fa94770ca0ea9b71f6cc | |
parent | 0ea5089e9e2084084c73e759ccab0044c1d2a601 (diff) | |
parent | ff1aa200b87ad5497d844a9a41c9756f7deb28b4 (diff) | |
download | libchrome-gestures-simpleperf-release.tar.gz |
Snap for 11400057 from ff1aa200b87ad5497d844a9a41c9756f7deb28b4 to simpleperf-releasesimpleperf-release
Change-Id: Ife6d4db27bf1d0bfce5d63849b948217030a1798
72 files changed, 3816 insertions, 1739 deletions
@@ -18,7 +18,7 @@ license { } cc_defaults { - name: "libchrome-gestures_cflags", + name: "libchrome-gestures_defaults", cflags: [ "-fno-exceptions", "-fno-strict-aliasing", @@ -39,6 +39,27 @@ cc_defaults { "-D_FILE_OFFSET_BITS=64", "-DGESTURES_INTERNAL=1", ], + sanitize: { + all_undefined: true, + integer_overflow: true, + undefined: true, + }, + arch: { + x86_64: { + sanitize: { + all_undefined: false, + integer_overflow: false, + undefined: false, + }, + } + }, + target: { + host: { + sanitize: { + address: true, + }, + }, + }, } cc_library_headers { @@ -52,7 +73,7 @@ cc_library_headers { cc_library_static { name: "libchrome-gestures", defaults: [ - "libchrome-gestures_cflags", + "libchrome-gestures_defaults", ], local_include_dirs: ["."], header_libs: [ @@ -102,18 +123,13 @@ cc_library_static { "//frameworks/native/services/inputflinger:__subpackages__", ], rtti: true, - sanitize: { - cfi: true, - integer_overflow: true, - misc_undefined: ["bounds"], - }, host_supported: true, } cc_test { name: "libchrome-gestures_test", defaults: [ - "libchrome-gestures_cflags", + "libchrome-gestures_defaults", ], srcs: [ "src/accel_filter_interpreter_unittest.cc", @@ -168,5 +184,11 @@ cc_test { "-Wno-sign-compare", ], host_supported: false, + sanitize: { + hwaddress: true, + diag: { + integer_overflow: true, + }, + }, test_suites: ["general-tests"], } diff --git a/METADATA.android b/METADATA index 3fbc1b0..c2fe6b5 100644 --- a/METADATA.android +++ b/METADATA @@ -6,7 +6,7 @@ third_party { type: GIT value: "https://chromium.googlesource.com/chromiumos/platform/gestures/" } - version: "4c2dbaf9f9f64e07edcd46b161fe0e4bc62b950c" - last_upgrade_date { year: 2023 month: 8 day: 21 } + version: "b31ef0adcaff61c045e95158cb9720543b42b531" + last_upgrade_date { year: 2023 month: 12 day: 13 } license_type: NOTICE } diff --git a/include/accel_filter_interpreter.h b/include/accel_filter_interpreter.h index 024abb7..6e5fd47 100644 --- a/include/accel_filter_interpreter.h +++ b/include/accel_filter_interpreter.h @@ -30,10 +30,15 @@ class AccelFilterInterpreter : public FilterInterpreter { FRIEND_TEST(AccelFilterInterpreterTest, NotSmoothingTest); FRIEND_TEST(AccelFilterInterpreterTest, SmoothingTest); FRIEND_TEST(AccelFilterInterpreterTest, TinyMoveTest); + FRIEND_TEST(AccelFilterInterpreterTest, BadGestureTest); + FRIEND_TEST(AccelFilterInterpreterTest, BadDeltaTTest); + FRIEND_TEST(AccelFilterInterpreterTest, BadSpeedFlingTest); + FRIEND_TEST(AccelFilterInterpreterTest, BadSpeedMoveTest); FRIEND_TEST(AccelFilterInterpreterTest, UnacceleratedMouseTest); FRIEND_TEST(AccelFilterInterpreterTest, UnacceleratedTouchpadTest); FRIEND_TEST(AccelFilterInterpreterTest, TouchpadPointAccelCurveTest); FRIEND_TEST(AccelFilterInterpreterTest, TouchpadScrollAccelCurveTest); + FRIEND_TEST(AccelFilterInterpreterTest, AccelDebugDataTest); public: // Takes ownership of |next|: AccelFilterInterpreter(PropRegistry* prop_reg, Interpreter* next, @@ -116,16 +121,23 @@ class AccelFilterInterpreter : public FilterInterpreter { // 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); + void smooth_speed(const 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); + float RatioFromAccelCurve(const CurveSegment* segs, + const size_t max_segs, + const float speed); + + template<typename T> + void LogDebugData(const T& debug_data) { + using EventDebug = ActivityLog::EventDebug; + if (EventDebugLoggingIsEnabled(EventDebug::Accel)) + log_->LogDebugData(debug_data); + } //************************************************************************** diff --git a/include/activity_log.h b/include/activity_log.h index d5d6b43..a5ebde3 100644 --- a/include/activity_log.h +++ b/include/activity_log.h @@ -13,6 +13,11 @@ #include <gtest/gtest.h> // For FRIEND_TEST #include <json/value.h> +// This should be set by build system: +#ifndef VCSID +#define VCSID "Unknown" +#endif // VCSID + // This is a class that circularly buffers all incoming and outgoing activity // so that end users can report issues and engineers can reproduce them. @@ -28,6 +33,10 @@ class ActivityLog { FRIEND_TEST(ActivityLogTest, EncodePropChangeDoubleTest); FRIEND_TEST(ActivityLogTest, EncodePropChangeIntTest); FRIEND_TEST(ActivityLogTest, EncodePropChangeShortTest); + FRIEND_TEST(ActivityLogTest, GestureConsumeTest); + FRIEND_TEST(ActivityLogTest, GestureProduceTest); + FRIEND_TEST(ActivityLogTest, HardwareStatePreTest); + FRIEND_TEST(ActivityLogTest, HardwareStatePostTest); FRIEND_TEST(LoggingFilterInterpreterTest, SimpleTest); FRIEND_TEST(PropRegistryTest, PropChangeTest); public: @@ -38,19 +47,126 @@ class ActivityLog { stime_t timestamp; }; struct PropChangeEntry { - const char* name; + std::string name; // No string variant because string values can't change std::variant<GesturesPropBool, double, int, short> value; }; + + struct HardwareStatePre { + std::string name; + HardwareState hwstate; + }; + struct HardwareStatePost { + std::string name; + HardwareState hwstate; + }; + struct GestureConsume { + std::string name; + Gesture gesture; + }; + struct GestureProduce { + std::string name; + Gesture gesture; + }; + struct HandleTimerPre { + std::string name; + bool timeout_is_present; + stime_t now; + stime_t timeout; + }; + struct HandleTimerPost { + std::string name; + bool timeout_is_present; + stime_t now; + stime_t timeout; + }; + struct AccelGestureDebug { + bool no_accel_for_gesture_type; + bool no_accel_for_small_dt; + bool no_accel_for_small_speed; + bool no_accel_for_bad_gain; + bool dropped_gesture; + bool x_y_are_velocity; + float x_scale, y_scale; + float dt; + float adjusted_dt; + float speed; + float smoothed_speed; + float gain_x, gain_y; + }; + struct TimestampGestureDebug { + stime_t skew; + }; + struct TimestampHardwareStateDebug { + bool is_using_fake; + union { + struct { + bool was_first_or_backward; + stime_t prev_msc_timestamp_in; + stime_t prev_msc_timestamp_out; + }; + struct { + bool was_divergence_reset; + stime_t fake_timestamp_in; + stime_t fake_timestamp_delta; + stime_t fake_timestamp_out; + }; + }; + stime_t skew; + stime_t max_skew; + }; + struct Entry { std::variant<HardwareState, TimerCallbackEntry, CallbackRequestEntry, Gesture, - PropChangeEntry> details; + PropChangeEntry, + HardwareStatePre, + HardwareStatePost, + GestureConsume, + GestureProduce, + HandleTimerPre, + HandleTimerPost, + AccelGestureDebug, + TimestampGestureDebug, + TimestampHardwareStateDebug> details; + }; + + enum class EventDebug { + // Base Event Types + Gesture = 0, + HardwareState, + HandleTimer, + // FilterInterpreter Debug Detail Event Types + Accel, + Box, + ClickWiggle, + FingerMerge, + FlingStop, + HapticButtonGenerator, + Iir, + IntegratGesture, + Logging, + Lookahead, + Metrics, + NonLinearity, + PalmClassifying, + Scaling, + SensorJump, + SplitCorrecting, + StationaryWiggle, + StuckButtonInhibitor, + T5R2Correcting, + Timestamp, + TrendClassifying, + // Interpreter Debug Detail Event Types + ImmediateInterpreter, + MouseInterpreter, + MultitouchMouseInterpreter, }; explicit ActivityLog(PropRegistry* prop_reg); @@ -63,6 +179,24 @@ class ActivityLog { void LogGesture(const Gesture& gesture); void LogPropChange(const PropChangeEntry& prop_change); + // Debug extensions for Log*() + void LogGestureConsume(const std::string& name, const Gesture& gesture); + void LogGestureProduce(const std::string& name, const Gesture& gesture); + void LogHardwareStatePre(const std::string& name, + const HardwareState& hwstate); + void LogHardwareStatePost(const std::string& name, + const HardwareState& hwstate); + void LogHandleTimerPre(const std::string& name, + stime_t now, const stime_t* timeout); + void LogHandleTimerPost(const std::string& name, + stime_t now, const stime_t* timeout); + + template<typename T> + void LogDebugData(const T& debug_data) { + Entry* entry = PushBack(); + entry->details = debug_data; + } + // Dump allocates, and thus must not be called on a signal handler. void Dump(const char* filename); void Clear() { head_idx_ = size_ = 0; } @@ -81,11 +215,18 @@ class ActivityLog { static const char kKeyNext[]; static const char kKeyRoot[]; static const char kKeyType[]; + static const char kKeyMethodName[]; static const char kKeyHardwareState[]; + static const char kKeyHardwareStatePre[]; + static const char kKeyHardwareStatePost[]; static const char kKeyTimerCallback[]; static const char kKeyCallbackRequest[]; static const char kKeyGesture[]; + static const char kKeyGestureConsume[]; + static const char kKeyGestureProduce[]; static const char kKeyPropChange[]; + static const char kKeyHandleTimerPre[]; + static const char kKeyHandleTimerPost[]; // HardwareState keys: static const char kKeyHardwareStateTimestamp[]; static const char kKeyHardwareStateButtonsDown[]; @@ -106,9 +247,9 @@ class ActivityLog { static const char kKeyFingerStatePositionY[]; static const char kKeyFingerStateTrackingId[]; static const char kKeyFingerStateFlags[]; - // TimerCallback keys: - static const char kKeyTimerCallbackNow[]; - // CallbackRequest keys: + // Timer/Callback keys: + static const char kKeyTimerNow[]; + static const char kKeyHandleTimerTimeout[]; static const char kKeyCallbackRequestWhen[]; // Gesture keys: static const char kKeyGestureType[]; @@ -126,16 +267,10 @@ class ActivityLog { static const char kValueGestureTypeMetrics[]; static const char kKeyGestureStartTime[]; static const char kKeyGestureEndTime[]; - static const char kKeyGestureMoveDX[]; - static const char kKeyGestureMoveDY[]; - static const char kKeyGestureMoveOrdinalDX[]; - static const char kKeyGestureMoveOrdinalDY[]; - static const char kKeyGestureScrollDX[]; - static const char kKeyGestureScrollDY[]; - static const char kKeyGestureScrollOrdinalDX[]; - static const char kKeyGestureScrollOrdinalDY[]; - static const char kKeyGestureMouseWheelDX[]; - static const char kKeyGestureMouseWheelDY[]; + static const char kKeyGestureDX[]; + static const char kKeyGestureDY[]; + static const char kKeyGestureOrdinalDX[]; + static const char kKeyGestureOrdinalDY[]; static const char kKeyGestureMouseWheelTicksDX[]; static const char kKeyGestureMouseWheelTicksDY[]; static const char kKeyGesturePinchDZ[]; @@ -148,14 +283,6 @@ class ActivityLog { static const char kKeyGestureFlingOrdinalVX[]; static const char kKeyGestureFlingOrdinalVY[]; static const char kKeyGestureFlingState[]; - static const char kKeyGestureSwipeDX[]; - static const char kKeyGestureSwipeDY[]; - static const char kKeyGestureSwipeOrdinalDX[]; - static const char kKeyGestureSwipeOrdinalDY[]; - static const char kKeyGestureFourFingerSwipeDX[]; - static const char kKeyGestureFourFingerSwipeDY[]; - static const char kKeyGestureFourFingerSwipeOrdinalDX[]; - static const char kKeyGestureFourFingerSwipeOrdinalDY[]; static const char kKeyGestureMetricsType[]; static const char kKeyGestureMetricsData1[]; static const char kKeyGestureMetricsData2[]; @@ -189,6 +316,37 @@ class ActivityLog { static const char kKeyProperties[]; + // AccelFilterInterpreter Debug Data keys: + static const char kKeyAccelGestureDebug[]; + static const char kKeyAccelDebugNoAccelBadGain[]; + static const char kKeyAccelDebugNoAccelGestureType[]; + static const char kKeyAccelDebugNoAccelSmallDt[]; + static const char kKeyAccelDebugNoAccelSmallSpeed[]; + static const char kKeyAccelDebugDroppedGesture[]; + static const char kKeyAccelDebugXYAreVelocity[]; + static const char kKeyAccelDebugXScale[]; + static const char kKeyAccelDebugYScale[]; + static const char kKeyAccelDebugDt[]; + static const char kKeyAccelDebugAdjustedDt[]; + static const char kKeyAccelDebugSpeed[]; + static const char kKeyAccelDebugSmoothSpeed[]; + static const char kKeyAccelDebugGainX[]; + static const char kKeyAccelDebugGainY[]; + + // Timestamp Debug Data keys: + static const char kKeyTimestampGestureDebug[]; + static const char kKeyTimestampHardwareStateDebug[]; + static const char kKeyTimestampDebugIsUsingFake[]; + static const char kKeyTimestampDebugWasFirstOrBackward[]; + static const char kKeyTimestampDebugPrevMscTimestampIn[]; + static const char kKeyTimestampDebugPrevMscTimestampOut[]; + static const char kKeyTimestampDebugWasDivergenceReset[]; + static const char kKeyTimestampDebugFakeTimestampIn[]; + static const char kKeyTimestampDebugFakeTimestampDelta[]; + static const char kKeyTimestampDebugFakeTimestampOut[]; + static const char kKeyTimestampDebugSkew[]; + static const char kKeyTimestampDebugMaxSkew[]; + private: // Extends the tail of the buffer by one element and returns that new element. // This may cause an older element to be overwritten if the buffer is full. @@ -198,10 +356,26 @@ class ActivityLog { // JSON-encoders for various types Json::Value EncodeHardwareProperties() const; + + Json::Value EncodeHardwareStateCommon(const HardwareState& hwstate); Json::Value EncodeHardwareState(const HardwareState& hwstate); + Json::Value EncodeHardwareState(const HardwareStatePre& hwstate); + Json::Value EncodeHardwareState(const HardwareStatePost& hwstate); + Json::Value EncodeHardwareStateDebug( + const TimestampHardwareStateDebug& debug_data); + Json::Value EncodeTimerCallback(stime_t timestamp); + Json::Value EncodeHandleTimer(const HandleTimerPre& handle); + Json::Value EncodeHandleTimer(const HandleTimerPost& handle); Json::Value EncodeCallbackRequest(stime_t timestamp); + + Json::Value EncodeGestureCommon(const Gesture& gesture); Json::Value EncodeGesture(const Gesture& gesture); + Json::Value EncodeGesture(const GestureConsume& gesture); + Json::Value EncodeGesture(const GestureProduce& gesture); + Json::Value EncodeGestureDebug(const AccelGestureDebug& debug_data); + Json::Value EncodeGestureDebug(const TimestampGestureDebug& debug_data); + Json::Value EncodePropChange(const PropChangeEntry& prop_change); // Encode user-configurable properties diff --git a/include/box_filter_interpreter.h b/include/box_filter_interpreter.h index 4316e00..7155125 100644 --- a/include/box_filter_interpreter.h +++ b/include/box_filter_interpreter.h @@ -35,6 +35,7 @@ namespace gestures { class BoxFilterInterpreter : public FilterInterpreter, public PropertyDelegate { FRIEND_TEST(BoxFilterInterpreterTest, SimpleTest); + FRIEND_TEST(BoxFilterInterpreterTest, ZeroSizeBoxTest); public: // Takes ownership of |next|: BoxFilterInterpreter(PropRegistry* prop_reg, Interpreter* next, diff --git a/include/finger_metrics.h b/include/finger_metrics.h index d518641..1773a94 100644 --- a/include/finger_metrics.h +++ b/include/finger_metrics.h @@ -74,6 +74,7 @@ class FingerMetrics { public: FingerMetrics(); explicit FingerMetrics(short tracking_id); + FingerMetrics(short tracking_id, stime_t timestamp); FingerMetrics(const FingerState& state, stime_t timestamp); // Update the finger metrics from a FingerState. @@ -148,6 +149,12 @@ class Metrics { // Clear all finger information void Clear(); + // Set the origin timestamp for a particular finger for testing purposes. + // Prefer calling Update with a whole HardwareState instead. + // TODO(b/307933752): remove this method once its last usage (in + // TapToClickStateMachineTest::check_hwstates) is removed. + void SetFingerOriginTimestampForTesting(short tracking_id, stime_t time); + private: vector<FingerMetrics, kMaxFingers> fingers_; diff --git a/include/fling_stop_filter_interpreter.h b/include/fling_stop_filter_interpreter.h index 62c5ae0..577cebd 100644 --- a/include/fling_stop_filter_interpreter.h +++ b/include/fling_stop_filter_interpreter.h @@ -22,6 +22,8 @@ namespace gestures { class FlingStopFilterInterpreter : public FilterInterpreter { FRIEND_TEST(FlingStopFilterInterpreterTest, SimpleTest); + FRIEND_TEST(FlingStopFilterInterpreterTest, FlingGestureTest); + FRIEND_TEST(FlingStopFilterInterpreterTest, FlingStopMultimouseMoveTest); public: // Takes ownership of |next|: FlingStopFilterInterpreter(PropRegistry* prop_reg, diff --git a/include/gestures.h b/include/gestures.h index 318a22c..3ccaa20 100644 --- a/include/gestures.h +++ b/include/gestures.h @@ -48,9 +48,9 @@ stime_t StimeFromTimespec(const struct timespec*); struct HardwareProperties { // Touch properties // The minimum X coordinate that the device can report. - float left; + float left = 0; // The minimum Y coordinate that the device can report. - float top; + float top = 0; // The maximum X coordinate that the device can report. float right; // The maximum Y coordinate that the device can report. @@ -165,6 +165,10 @@ struct HardwareProperties { // Describes a single contact on a touch surface. Generally, the fields have the // same meaning as the equivalent ABS_MT_... axis in the Linux evdev protocol. struct FingerState { + enum class ToolType { + kFinger = 0, + kPalm, + }; // The large and small radii of the ellipse of the finger touching the pad. float touch_major, touch_minor; @@ -188,6 +192,8 @@ struct FingerState { // A bit field of flags that are used internally by the library. (See the // GESTURES_FINGER_* constants.) Should be set to 0 on incoming FingerStates. unsigned flags; + + ToolType tool_type = ToolType::kFinger; #ifdef __cplusplus bool NonFlagsEquals(const FingerState& that) const { return touch_major == that.touch_major && @@ -215,6 +221,8 @@ struct FingerState { #define GESTURES_BUTTON_RIGHT 4 #define GESTURES_BUTTON_BACK 8 #define GESTURES_BUTTON_FORWARD 16 +#define GESTURES_BUTTON_SIDE 32 +#define GESTURES_BUTTON_EXTRA 64 // Describes one frame of data from the input device. struct HardwareState { @@ -235,12 +243,14 @@ struct HardwareState { // The number of fingers touching the pad, which may be more than finger_cnt. unsigned short touch_cnt; // A pointer to an array of FingerState structs with finger_cnt entries, - // representing the contacts currently being tracked. The order in which - // FingerStates appear need not be stable between HardwareStates — only the - // tracking ID is used to track individual contacts over time. Accordingly, - // when a finger is lifted from the pad (and therefore its ABS_MT_TRACKING_ID - // becomes -1), the client should simply stop including it in this array, - // rather than including a final FingerState for it. + // representing the contacts currently being tracked. If finger_cnt is 0, this + // pointer will be null. + // + // The order in which FingerStates appear need not be stable between + // HardwareStates — only the tracking ID is used to track individual contacts + // over time. Accordingly, when a finger is lifted from the pad (and therefore + // its ABS_MT_TRACKING_ID becomes -1), the client should simply stop including + // it in this array, rather than including a final FingerState for it. struct FingerState* fingers; // Mouse axes, which have the same meanings as the Linux evdev axes of the @@ -657,6 +667,7 @@ typedef struct GesturesPropProvider { namespace gestures { class Interpreter; +class IntProperty; class PropRegistry; class LoggingFilterInterpreter; class Tracer; @@ -702,6 +713,7 @@ struct GestureInterpreter { std::unique_ptr<Tracer> tracer_; std::unique_ptr<Interpreter> interpreter_; std::unique_ptr<MetricsProperties> mprops_; + std::unique_ptr<IntProperty> stack_version_; GesturesTimerProvider* timer_provider_; void* timer_provider_data_; diff --git a/include/haptic_button_generator_filter_interpreter.h b/include/haptic_button_generator_filter_interpreter.h index 90632b5..4f17780 100644 --- a/include/haptic_button_generator_filter_interpreter.h +++ b/include/haptic_button_generator_filter_interpreter.h @@ -23,6 +23,8 @@ class HapticButtonGeneratorFilterInterpreter : public FilterInterpreter { FRIEND_TEST(HapticButtonGeneratorFilterInterpreterTest, SimpleTest); FRIEND_TEST(HapticButtonGeneratorFilterInterpreterTest, NotHapticTest); FRIEND_TEST(HapticButtonGeneratorFilterInterpreterTest, + NotHapticConsumeGestureTest); + FRIEND_TEST(HapticButtonGeneratorFilterInterpreterTest, GesturePreventsButtonDownTest); FRIEND_TEST(HapticButtonGeneratorFilterInterpreterTest, DynamicThresholdTest); FRIEND_TEST(HapticButtonGeneratorFilterInterpreterTest, PalmTest); diff --git a/include/immediate_interpreter.h b/include/immediate_interpreter.h index 7f7ed61..1be420e 100644 --- a/include/immediate_interpreter.h +++ b/include/immediate_interpreter.h @@ -127,12 +127,12 @@ class HardwareStateBuffer { // Pops most recently pushed state void PopState(); - const HardwareState* Get(size_t idx) const { - return &states_[(idx + newest_index_) % size_]; + const HardwareState& Get(size_t idx) const { + return states_[(idx + newest_index_) % size_]; } - HardwareState* Get(size_t idx) { - return const_cast<HardwareState*>( + HardwareState& Get(size_t idx) { + return const_cast<HardwareState&>( const_cast<const HardwareStateBuffer*>(this)->Get(idx)); } @@ -344,6 +344,7 @@ class ImmediateInterpreter : public Interpreter, public PropertyDelegate { FRIEND_TEST(ImmediateInterpreterTest, ClickTest); FRIEND_TEST(ImmediateInterpreterTest, FlingDepthTest); FRIEND_TEST(ImmediateInterpreterTest, GetGesturingFingersTest); + FRIEND_TEST(ImmediateInterpreterTest, GetGesturingFingersWithEmptyStateTest); FRIEND_TEST(ImmediateInterpreterTest, PalmAtEdgeTest); FRIEND_TEST(ImmediateInterpreterTest, PalmReevaluateTest); FRIEND_TEST(ImmediateInterpreterTest, PalmTest); @@ -355,13 +356,13 @@ class ImmediateInterpreter : public Interpreter, public PropertyDelegate { FRIEND_TEST(ImmediateInterpreterTest, StationaryPalmTest); FRIEND_TEST(ImmediateInterpreterTest, SwipeTest); FRIEND_TEST(ImmediateInterpreterTest, TapRecordTest); - FRIEND_TEST(ImmediateInterpreterTest, TapToClickEnableTest); FRIEND_TEST(ImmediateInterpreterTest, TapToClickKeyboardTest); FRIEND_TEST(ImmediateInterpreterTest, TapToClickLowPressureBeginOrEndTest); FRIEND_TEST(ImmediateInterpreterTest, ThumbRetainReevaluateTest); FRIEND_TEST(ImmediateInterpreterTest, ThumbRetainTest); FRIEND_TEST(ImmediateInterpreterTest, WarpedFingersTappingTest); FRIEND_TEST(ImmediateInterpreterTest, ZeroClickInitializationTest); + FRIEND_TEST(ImmediateInterpreterTtcEnableTest, TapToClickEnableTest); friend class TapRecord; friend class TapToClickStateMachineTest; friend class FingerButtonClick; @@ -398,8 +399,8 @@ class ImmediateInterpreter : public Interpreter, public PropertyDelegate { bool device_reports_pressure() const { return hwprops_->reports_pressure; } - stime_t finger_origin_timestamp(short finger_id) const { - return origin_timestamps_.at(finger_id); + stime_t finger_origin_timestamp(short tracking_id) const { + return metrics_->GetFinger(tracking_id)->origin_time(); } private: @@ -627,10 +628,7 @@ class ImmediateInterpreter : public Interpreter, public PropertyDelegate { Gesture result_; Gesture prev_result_; - // Time when a contact arrived. Persists even when fingers change. - std::map<short, stime_t> origin_timestamps_; - - // Total distance travelled by a finger since the origin_timestamps_. + // Total distance travelled by a finger since its origin timestamp. std::map<short, float> distance_walked_; // Button data diff --git a/include/integral_gesture_filter_interpreter.h b/include/integral_gesture_filter_interpreter.h index 97f466c..7add202 100644 --- a/include/integral_gesture_filter_interpreter.h +++ b/include/integral_gesture_filter_interpreter.h @@ -18,6 +18,7 @@ namespace gestures { // can be accumulated and together create a move of a single pixel. class IntegralGestureFilterInterpreter : public FilterInterpreter { + FRIEND_TEST(IntegralGestureFilterInterpreterTestInterpreter, ConsumeGesture); public: // Takes ownership of |next|: explicit IntegralGestureFilterInterpreter(Interpreter* next, Tracer* tracer); diff --git a/include/interpreter.h b/include/interpreter.h index f293580..4481f2d 100644 --- a/include/interpreter.h +++ b/include/interpreter.h @@ -38,6 +38,11 @@ class Interpreter { FRIEND_TEST(InterpreterTest, ResetLogTest); FRIEND_TEST(InterpreterTest, LoggingDisabledByDefault); FRIEND_TEST(LoggingFilterInterpreterTest, LogResetHandlerTest); + FRIEND_TEST(InterpreterTest, EventDebugLoggingEnableTest); + FRIEND_TEST(InterpreterTest, LogHardwareStateTest); + FRIEND_TEST(InterpreterTest, LogGestureTest); + FRIEND_TEST(InterpreterTest, LogHandleTimerTest); + FRIEND_TEST(TimestampFilterInterpreterParmTest, TimestampDebugLoggingTest); public: Interpreter(PropRegistry* prop_reg, Tracer* tracer, bool force_log_creation); virtual ~Interpreter(); @@ -90,12 +95,32 @@ class Interpreter { stime_t* timeout) {} virtual void HandleTimerImpl(stime_t now, stime_t* timeout) {} + bool EventLoggingIsEnabled(); void SetEventLoggingEnabled(bool enabled); + bool EventDebugLoggingIsEnabled(ActivityLog::EventDebug event); + uint32_t GetEventDebugLoggingEnabled(); + void SetEventDebugLoggingEnabled(uint32_t enabled); + void EventDebugLoggingDisable(ActivityLog::EventDebug event); + void EventDebugLoggingEnable(ActivityLog::EventDebug event); + + void LogGestureConsume(const std::string& name, const Gesture& gesture); + void LogGestureProduce(const std::string& name, const Gesture& gesture); + void LogHardwareStatePre(const std::string& name, + const HardwareState& hwstate); + void LogHardwareStatePost(const std::string& name, + const HardwareState& hwstate); + void LogHandleTimerPre(const std::string& name, + stime_t now, const stime_t* timeout); + void LogHandleTimerPost(const std::string& name, + stime_t now, const stime_t* timeout); + private: const char* name_; Tracer* tracer_; + bool enable_event_logging_ = false; + uint32_t enable_event_debug_logging_ = 0; void LogOutputs(const Gesture* result, stime_t* timeout, const char* action); }; diff --git a/include/logging_filter_interpreter.h b/include/logging_filter_interpreter.h index ffc1685..5718d97 100644 --- a/include/logging_filter_interpreter.h +++ b/include/logging_filter_interpreter.h @@ -36,6 +36,7 @@ class LoggingFilterInterpreter : public FilterInterpreter, private: void Dump(const char* filename); + IntProperty event_debug_logging_enable_; BoolProperty event_logging_enable_; IntProperty logging_notify_; // Reset the log by setting the property value. diff --git a/include/lookahead_filter_interpreter.h b/include/lookahead_filter_interpreter.h index 3eab4ad..19c536e 100644 --- a/include/lookahead_filter_interpreter.h +++ b/include/lookahead_filter_interpreter.h @@ -30,9 +30,11 @@ class LookaheadFilterInterpreter : public FilterInterpreter { FRIEND_TEST(LookaheadFilterInterpreterTest, QuickMoveTest); FRIEND_TEST(LookaheadFilterInterpreterTest, QuickSwipeTest); FRIEND_TEST(LookaheadFilterInterpreterTest, SemiMtNoTrackingIdAssignmentTest); - FRIEND_TEST(LookaheadFilterInterpreterTest, SimpleTest); + FRIEND_TEST(LookaheadFilterInterpreterParmTest, SimpleTest); FRIEND_TEST(LookaheadFilterInterpreterTest, SpuriousCallbackTest); FRIEND_TEST(LookaheadFilterInterpreterTest, VariableDelayTest); + FRIEND_TEST(LookaheadFilterInterpreterTest, AddFingerFlingTest); + FRIEND_TEST(LookaheadFilterInterpreterTest, ConsumeGestureTest); public: LookaheadFilterInterpreter(PropRegistry* prop_reg, Interpreter* next, diff --git a/include/mouse_interpreter.h b/include/mouse_interpreter.h index dc024b2..e56be37 100644 --- a/include/mouse_interpreter.h +++ b/include/mouse_interpreter.h @@ -21,6 +21,7 @@ class MouseInterpreter : public Interpreter, public PropertyDelegate { FRIEND_TEST(MouseInterpreterTest, JankyScrollTest); FRIEND_TEST(MouseInterpreterTest, WheelTickReportingHighResTest); FRIEND_TEST(MouseInterpreterTest, WheelTickReportingLowResTest); + FRIEND_TEST(MouseInterpreterTest, EmulateScrollWheelTest); public: MouseInterpreter(PropRegistry* prop_reg, Tracer* tracer); virtual ~MouseInterpreter() {}; diff --git a/include/palm_classifying_filter_interpreter.h b/include/palm_classifying_filter_interpreter.h index 4ef88bd..53fcafe 100644 --- a/include/palm_classifying_filter_interpreter.h +++ b/include/palm_classifying_filter_interpreter.h @@ -25,6 +25,7 @@ namespace gestures { // bottom area of the pad. class PalmClassifyingFilterInterpreter : public FilterInterpreter { + FRIEND_TEST(PalmClassifyingFilterInterpreterTest, ExternallyMarkedPalmTest); FRIEND_TEST(PalmClassifyingFilterInterpreterTest, PalmAtEdgeTest); FRIEND_TEST(PalmClassifyingFilterInterpreterTest, PalmReevaluateTest); FRIEND_TEST(PalmClassifyingFilterInterpreterTest, PalmTest); diff --git a/include/timestamp_filter_interpreter.h b/include/timestamp_filter_interpreter.h index 9e95a4d..6604efa 100644 --- a/include/timestamp_filter_interpreter.h +++ b/include/timestamp_filter_interpreter.h @@ -27,6 +27,8 @@ class TimestampFilterInterpreter : public FilterInterpreter { FRIEND_TEST(TimestampFilterInterpreterTest, FakeTimestampTest); FRIEND_TEST(TimestampFilterInterpreterTest, FakeTimestampJumpForwardTest); FRIEND_TEST(TimestampFilterInterpreterTest, FakeTimestampFallBackwardTest); + FRIEND_TEST(TimestampFilterInterpreterTest, GestureDebugTest); + FRIEND_TEST(TimestampFilterInterpreterParmTest, TimestampDebugLoggingTest); public: // Takes ownership of |next|: explicit TimestampFilterInterpreter(PropRegistry* prop_reg, @@ -56,16 +58,27 @@ class TimestampFilterInterpreter : public FilterInterpreter { // - hwstate.timestamp uses CLOCK_MONOTONIC as the time base, possibly with // fine tuning provided by MSC_TIMESTAMP. // - hwstate.msc_timestamp should not be used. - void ChangeTimestampDefault(HardwareState& hwstate); + void ChangeTimestampDefault( + HardwareState& hwstate, + ActivityLog::TimestampHardwareStateDebug& debug_data); // If neither hwstate.timestamp nor hwstate.msc_timestamp has reliable // deltas, we use fake_timestamp_delta_ as the delta between consecutive // reports, but don't allow our faked timestamp to diverge too far from // hwstate.timestamp. - void ChangeTimestampUsingFake(HardwareState& hwstate); + void ChangeTimestampUsingFake( + HardwareState& hwstate, + ActivityLog::TimestampHardwareStateDebug& debug_data); void ConsumeGesture(const Gesture& gs); + template<typename T> + void LogDebugData(const T& debug_data) { + using EventDebug = ActivityLog::EventDebug; + if (EventDebugLoggingIsEnabled(EventDebug::Timestamp)) + log_->LogDebugData(debug_data); + } + stime_t prev_msc_timestamp_; // Difference between msc_timestamp and timestamp as of last timestamp reset. diff --git a/src/accel_filter_interpreter.cc b/src/accel_filter_interpreter.cc index 99bd298..23f7ac3 100644 --- a/src/accel_filter_interpreter.cc +++ b/src/accel_filter_interpreter.cc @@ -161,12 +161,15 @@ AccelFilterInterpreter::AccelFilterInterpreter(PropRegistry* prop_reg, } void AccelFilterInterpreter::ConsumeGesture(const Gesture& gs) { + const char name[] = "AccelFilterInterpreter::ConsumeGesture"; + LogGestureConsume(name, gs); + auto debug_data = ActivityLog::AccelGestureDebug{}; + // Use a copy of the gesture gs during the calculations and // adjustments so the original is left alone. Gesture gs_copy = gs; - // Setup the parameters for acceleration calculations based on gesture - // type. + // Setup the parameters for acceleration calculations based on gesture type. float* dx; float* dy; float x_scale; @@ -185,42 +188,68 @@ void AccelFilterInterpreter::ConsumeGesture(const Gesture& gs) { scale_out_x_ordinal, scale_out_y_ordinal, segs, max_segs)) { // It was determined no acceleration was required. + debug_data.no_accel_for_gesture_type = true; + LogDebugData(debug_data); + LogGestureProduce(name, gs); ProduceGesture(gs); return; } + debug_data.x_y_are_velocity = (dx == nullptr || dy == nullptr); + debug_data.x_scale = x_scale; + debug_data.y_scale = y_scale; + debug_data.dt = get_dt(gs); + debug_data.adjusted_dt = get_adjusted_dt(gs); float speed; if (!get_actual_speed(dx, dy, - gs_copy.details.fling.vx, gs_copy.details.fling.vy, + gs.details.fling.vx, gs.details.fling.vy, get_adjusted_dt(gs), speed)) { // dt was too small, don't accelerate. + debug_data.no_accel_for_small_dt = true; + LogDebugData(debug_data); + LogGestureProduce(name, gs); ProduceGesture(gs); return; } - smooth_speed(gs_copy, speed); + debug_data.speed = speed; + smooth_speed(gs, speed); + debug_data.smoothed_speed = speed; // Avoid scaling if the speed is too small. if (speed < 0.00001) { - if (gs.type == kGestureTypeFling) - ProduceGesture(gs); // Filter out zero length gestures. - return; // Avoid division by 0. - } - - // Find the appropriate ratio and apply scaling. - auto ratio = RatioFromAccelCurve(segs, max_segs, speed); - if (ratio > 0.0) { - *scale_out_x *= ratio * x_scale; - *scale_out_y *= ratio * y_scale; - - if (gs.type == kGestureTypeFling || - gs.type == kGestureTypeScroll) { - // We don't accelerate the ordinal values as we do for normal ones - // because this is how the Chrome needs it. - *scale_out_x_ordinal *= x_scale; - *scale_out_y_ordinal *= y_scale; + debug_data.no_accel_for_small_speed = true; + if (gs.type != kGestureTypeFling) + debug_data.dropped_gesture = true; + LogDebugData(debug_data); + if (gs.type == kGestureTypeFling) { + LogGestureProduce(name, gs); + ProduceGesture(gs); // Filter out zero length gestures. + } + } else { + // Find the appropriate ratio and apply scaling. + auto ratio = RatioFromAccelCurve(segs, max_segs, speed); + debug_data.gain_x = ratio; + debug_data.gain_y = ratio; + if (ratio > 0.0) { + *scale_out_x *= ratio * x_scale; + *scale_out_y *= ratio * y_scale; + + if (gs.type == kGestureTypeFling || + gs.type == kGestureTypeScroll) { + // We don't accelerate the ordinal values as we do for normal ones + // because this is how the Chrome needs it. + *scale_out_x_ordinal *= x_scale; + *scale_out_y_ordinal *= y_scale; + } + LogDebugData(debug_data); + LogGestureProduce(name, gs_copy); + ProduceGesture(gs_copy); + } else { + debug_data.no_accel_for_bad_gain = true; + debug_data.dropped_gesture = true; + LogDebugData(debug_data); } - ProduceGesture(gs_copy); } } @@ -383,7 +412,7 @@ bool AccelFilterInterpreter::get_actual_speed( return true; } -void AccelFilterInterpreter::smooth_speed(Gesture& gs, float& speed) { +void AccelFilterInterpreter::smooth_speed(const Gesture& gs, float& speed) { // Perform smoothing, if it is enabled. if (smooth_accel_.val_) { // Check if clock changed backwards. @@ -408,14 +437,14 @@ void AccelFilterInterpreter::smooth_speed(Gesture& gs, float& speed) { } float AccelFilterInterpreter::RatioFromAccelCurve( - CurveSegment const* segs, - size_t const max_segs, - float const speed) { + const CurveSegment* segs, + const size_t max_segs, + const float speed) { if (speed <= 0.0) return 0.0; for (size_t i = 0; i < max_segs; ++i) { - CurveSegment const & seg = segs[i]; + const CurveSegment& seg = segs[i]; if (speed <= seg.x_) { return (seg.sqr_ * speed) + seg.mul_ + (seg.int_ / speed); } diff --git a/src/accel_filter_interpreter_unittest.cc b/src/accel_filter_interpreter_unittest.cc index b5ee16f..58e634d 100644 --- a/src/accel_filter_interpreter_unittest.cc +++ b/src/accel_filter_interpreter_unittest.cc @@ -22,6 +22,8 @@ using std::vector; namespace gestures { +using EventDebug = ActivityLog::EventDebug; + class AccelFilterInterpreterTest : public ::testing::Test { protected: HardwareState empty_hwstate_ = {}; @@ -177,6 +179,225 @@ TEST_F(AccelFilterInterpreterTest, TinyMoveTest) { out->details.scroll.dx); } +TEST_F(AccelFilterInterpreterTest, BadGestureTest) { + PropRegistry prop_reg; + AccelFilterInterpreterTestInterpreter* base_interpreter = + new AccelFilterInterpreterTestInterpreter; + AccelFilterInterpreter accel_interpreter(&prop_reg, base_interpreter, + nullptr); + TestInterpreterWrapper interpreter(&accel_interpreter); + + accel_interpreter.SetEventLoggingEnabled(true); + accel_interpreter.EventDebugLoggingEnable(EventDebug::Gesture); + accel_interpreter.EventDebugLoggingEnable(EventDebug::Accel); + accel_interpreter.log_.reset(new ActivityLog(&prop_reg)); + + // AccelFilterInterpreter should not add gain to a ButtonsChange gesture. + base_interpreter->return_values_.push_back(Gesture(kGestureButtonsChange, + 1, // start time + 2, // end time + 0, // down + 0, // up + false)); // is_tap + + // Send the ButtonsChange into AccelFilterInterpreter. The filter + // should send it right back out. + EXPECT_EQ(accel_interpreter.log_->size(), 0); + Gesture* out = interpreter.SyncInterpret(empty_hwstate_, nullptr); + ASSERT_NE(nullptr, out); + EXPECT_EQ(kGestureTypeButtonsChange, out->type); + + // Encode the log into Json + Json::Value node; + Json::Value tree = accel_interpreter.log_->EncodeCommonInfo(); + + // Verify the Json information + EXPECT_EQ(accel_interpreter.log_->size(), 5); + node = tree[ActivityLog::kKeyRoot][0]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyHardwareState)); + node = tree[ActivityLog::kKeyRoot][1]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureConsume)); + node = tree[ActivityLog::kKeyRoot][2]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyAccelGestureDebug)); + node = tree[ActivityLog::kKeyRoot][3]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureProduce)); + node = tree[ActivityLog::kKeyRoot][4]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGesture)); + accel_interpreter.log_->Clear(); +} + +TEST_F(AccelFilterInterpreterTest, BadDeltaTTest) { + PropRegistry prop_reg; + AccelFilterInterpreterTestInterpreter* base_interpreter = + new AccelFilterInterpreterTestInterpreter; + AccelFilterInterpreter accel_interpreter(&prop_reg, base_interpreter, + nullptr); + TestInterpreterWrapper interpreter(&accel_interpreter); + + accel_interpreter.SetEventLoggingEnabled(true); + accel_interpreter.EventDebugLoggingEnable(EventDebug::Gesture); + accel_interpreter.EventDebugLoggingEnable(EventDebug::Accel); + accel_interpreter.log_.reset(new ActivityLog(&prop_reg)); + + // Change the bounds for reasonable minimum Dt. This will allow the filter + // to keep a very small Dt without adjusting it. + accel_interpreter.min_reasonable_dt_.val_ = 0; + + // Send the filter a very small Dt and have the logic catch that it + // is too small. This will not allow a fictitious Dt to be used but + // will just not apply gain to this specific gesture. + base_interpreter->return_values_.push_back(Gesture(kGestureMove, + 1, // start time + 1.000001, // end time + 4, // dx + 0)); // dy + + // Send the Move into AccelFilterInterpreter. No gain should be applied + // to Dx, even though this small of a Dt would normally have added a lot + // of gain. + EXPECT_EQ(accel_interpreter.log_->size(), 0); + Gesture* out = interpreter.SyncInterpret(empty_hwstate_, nullptr); + ASSERT_NE(nullptr, out); + EXPECT_EQ(kGestureTypeMove, out->type); + EXPECT_EQ(fabsf(out->details.move.dx), 4); + + // Encode the log into Json + Json::Value node; + Json::Value tree = accel_interpreter.log_->EncodeCommonInfo(); + + // Verify the Json information + EXPECT_EQ(accel_interpreter.log_->size(), 5); + node = tree[ActivityLog::kKeyRoot][0]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyHardwareState)); + node = tree[ActivityLog::kKeyRoot][1]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureConsume)); + node = tree[ActivityLog::kKeyRoot][2]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyAccelGestureDebug)); + node = tree[ActivityLog::kKeyRoot][3]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureProduce)); + node = tree[ActivityLog::kKeyRoot][4]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGesture)); + accel_interpreter.log_->Clear(); +} + +TEST_F(AccelFilterInterpreterTest, BadSpeedFlingTest) { + PropRegistry prop_reg; + AccelFilterInterpreterTestInterpreter* base_interpreter = + new AccelFilterInterpreterTestInterpreter; + AccelFilterInterpreter accel_interpreter(&prop_reg, base_interpreter, + nullptr); + TestInterpreterWrapper interpreter(&accel_interpreter); + + accel_interpreter.SetEventLoggingEnabled(true); + accel_interpreter.EventDebugLoggingEnable(EventDebug::Gesture); + accel_interpreter.EventDebugLoggingEnable(EventDebug::Accel); + accel_interpreter.log_.reset(new ActivityLog(&prop_reg)); + + // Change the bounds for reasonable maximum Dt. This will allow the filter + // to keep a large Dt without adjusting it. + accel_interpreter.max_reasonable_dt_.val_ = 1000; + + // Send the filter a Fling with a large Dt and have the logic catch that it + // is too big. This will not allow a fictitious Dt to be used but will + // just not apply gain to this specific gesture. + base_interpreter->return_values_.push_back(Gesture(kGestureFling, + 1, // start time + 2, // end time + 0.000001, // vx + 0, // vy + 0)); // state + + // Send the Fling into AccelFilterInterpreter. No gain should be applied + // to Vx. + EXPECT_EQ(accel_interpreter.log_->size(), 0); + Gesture* out = interpreter.SyncInterpret(empty_hwstate_, nullptr); + ASSERT_NE(nullptr, out); + EXPECT_EQ(kGestureTypeFling, out->type); + EXPECT_NEAR(fabsf(out->details.fling.vx), 0.000001, 0.0000001); + + // Encode the log into Json + Json::Value node; + Json::Value tree = accel_interpreter.log_->EncodeCommonInfo(); + + // Verify the Json information + EXPECT_EQ(accel_interpreter.log_->size(), 5); + node = tree[ActivityLog::kKeyRoot][0]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyHardwareState)); + node = tree[ActivityLog::kKeyRoot][1]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureConsume)); + node = tree[ActivityLog::kKeyRoot][2]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyAccelGestureDebug)); + node = tree[ActivityLog::kKeyRoot][3]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureProduce)); + node = tree[ActivityLog::kKeyRoot][4]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGesture)); + accel_interpreter.log_->Clear(); +} + +TEST_F(AccelFilterInterpreterTest, BadSpeedMoveTest) { + PropRegistry prop_reg; + AccelFilterInterpreterTestInterpreter* base_interpreter = + new AccelFilterInterpreterTestInterpreter; + AccelFilterInterpreter accel_interpreter(&prop_reg, base_interpreter, + nullptr); + TestInterpreterWrapper interpreter(&accel_interpreter); + + accel_interpreter.SetEventLoggingEnabled(true); + accel_interpreter.EventDebugLoggingEnable(EventDebug::Gesture); + accel_interpreter.EventDebugLoggingEnable(EventDebug::Accel); + accel_interpreter.log_.reset(new ActivityLog(&prop_reg)); + + // Change the bounds for reasonable maximum Dt. This will allow the filter + // to keep a large Dt without adjusting it. + accel_interpreter.max_reasonable_dt_.val_ = 1000; + + // Send the filter a Move with a large Dt and have the logic catch that it + // is too big. This will not allow a fictitious Dt to be used but will + // just not apply gain to this specific gesture. + base_interpreter->return_values_.push_back(Gesture(kGestureMove, + 1, // start time + 1000, // end time + 0.0001, // dx + 0)); // dy + + // Send the Move into AccelFilterInterpreter. The gesture should be dropped. + EXPECT_EQ(accel_interpreter.log_->size(), 0); + Gesture* out = interpreter.SyncInterpret(empty_hwstate_, nullptr); + ASSERT_EQ(nullptr, out); + + // Encode the log into Json + Json::Value node; + Json::Value tree = accel_interpreter.log_->EncodeCommonInfo(); + + // Verify the Json information + EXPECT_EQ(accel_interpreter.log_->size(), 3); + node = tree[ActivityLog::kKeyRoot][0]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyHardwareState)); + node = tree[ActivityLog::kKeyRoot][1]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureConsume)); + node = tree[ActivityLog::kKeyRoot][2]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyAccelGestureDebug)); + accel_interpreter.log_->Clear(); +} + TEST_F(AccelFilterInterpreterTest, TimingTest) { AccelFilterInterpreterTestInterpreter* base_interpreter = new AccelFilterInterpreterTestInterpreter; @@ -889,4 +1110,55 @@ TEST_F(AccelFilterInterpreterTest, TouchpadScrollAccelCurveTest) { } } +TEST_F(AccelFilterInterpreterTest, AccelDebugDataTest) { + PropRegistry prop_reg; + AccelFilterInterpreterTestInterpreter* base_interpreter = + new AccelFilterInterpreterTestInterpreter; + AccelFilterInterpreter accel_interpreter(&prop_reg, base_interpreter, + nullptr); + TestInterpreterWrapper interpreter(&accel_interpreter); + + accel_interpreter.SetEventLoggingEnabled(true); + accel_interpreter.EventDebugLoggingEnable(EventDebug::Gesture); + accel_interpreter.EventDebugLoggingEnable(EventDebug::HardwareState); + accel_interpreter.EventDebugLoggingEnable(EventDebug::Accel); + accel_interpreter.log_.reset(new ActivityLog(&prop_reg)); + + accel_interpreter.scroll_x_out_scale_.val_ = + accel_interpreter.scroll_y_out_scale_.val_ = 1.0; + + base_interpreter->return_values_.push_back(Gesture(kGestureScroll, + 2, // start time + 2.1, // end time + 4.1, // dx + -10.3)); // dy + + Gesture* out = interpreter.SyncInterpret(empty_hwstate_, nullptr); + ASSERT_NE(nullptr, out); + EXPECT_EQ(kGestureTypeScroll, out->type); + + // Encode the log into Json + Json::Value node; + Json::Value tree = accel_interpreter.log_->EncodeCommonInfo(); + + // Verify the Json information + EXPECT_EQ(accel_interpreter.log_->size(), 5); + node = tree[ActivityLog::kKeyRoot][0]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyHardwareState)); + node = tree[ActivityLog::kKeyRoot][1]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureConsume)); + node = tree[ActivityLog::kKeyRoot][2]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyAccelGestureDebug)); + node = tree[ActivityLog::kKeyRoot][3]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureProduce)); + node = tree[ActivityLog::kKeyRoot][4]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGesture)); + accel_interpreter.log_->Clear(); +} + } // namespace gestures diff --git a/src/activity_log.cc b/src/activity_log.cc index 249ad45..9e6bfbf 100644 --- a/src/activity_log.cc +++ b/src/activity_log.cc @@ -19,11 +19,6 @@ #include "include/prop_registry.h" #include "include/string_util.h" -// This should be set by build system: -#ifndef VCSID -#define VCSID "Unknown" -#endif // VCSID - #define QUINTTAP_COUNT 5 /* BTN_TOOL_QUINTTAP - Five fingers on trackpad */ using std::set; @@ -33,7 +28,9 @@ namespace { // Helper to std::visit with lambdas. template <typename... V> -struct Visitor : V... {}; +struct Visitor : V... { + using V::operator()...; +}; // Explicit deduction guide (not needed as of C++20). template <typename... V> Visitor(V...) -> Visitor<V...>; @@ -104,6 +101,56 @@ void ActivityLog::LogPropChange(const PropChangeEntry& prop_change) { entry->details = prop_change; } +void ActivityLog::LogGestureConsume( + const std::string& name, const Gesture& gesture) { + GestureConsume gesture_consume { name, gesture }; + Entry* entry = PushBack(); + entry->details = gesture_consume; +} + +void ActivityLog::LogGestureProduce( + const std::string& name, const Gesture& gesture) { + GestureProduce gesture_produce { name, gesture }; + Entry* entry = PushBack(); + entry->details = gesture_produce; +} + +void ActivityLog::LogHardwareStatePre(const std::string& name, + const HardwareState& hwstate) { + HardwareStatePre hwstate_pre { name, hwstate }; + Entry* entry = PushBack(); + entry->details = hwstate_pre; +} + +void ActivityLog::LogHardwareStatePost(const std::string& name, + const HardwareState& hwstate) { + HardwareStatePost hwstate_post { name, hwstate }; + Entry* entry = PushBack(); + entry->details = hwstate_post; +} + +void ActivityLog::LogHandleTimerPre(const std::string& name, + stime_t now, const stime_t* timeout) { + HandleTimerPre handle; + handle.name = name; + handle.now = now; + handle.timeout_is_present = (timeout != nullptr); + handle.timeout = (timeout == nullptr) ? 0 : *timeout; + Entry* entry = PushBack(); + entry->details = handle; +} + +void ActivityLog::LogHandleTimerPost(const std::string& name, + stime_t now, const stime_t* timeout) { + HandleTimerPost handle; + handle.name = name; + handle.now = now; + handle.timeout_is_present = (timeout != nullptr); + handle.timeout = (timeout == nullptr) ? 0 : *timeout; + Entry* entry = PushBack(); + entry->details = handle; +} + void ActivityLog::Dump(const char* filename) { string data = Encode(); WriteFile(filename, data.c_str(), data.size()); @@ -143,9 +190,9 @@ Json::Value ActivityLog::EncodeHardwareProperties() const { return ret; } -Json::Value ActivityLog::EncodeHardwareState(const HardwareState& hwstate) { +Json::Value ActivityLog::EncodeHardwareStateCommon( + const HardwareState& hwstate) { Json::Value ret(Json::objectValue); - ret[kKeyType] = Json::Value(kKeyHardwareState); ret[kKeyHardwareStateButtonsDown] = Json::Value(hwstate.buttons_down); ret[kKeyHardwareStateTouchCnt] = Json::Value(hwstate.touch_cnt); ret[kKeyHardwareStateTimestamp] = Json::Value(hwstate.timestamp); @@ -177,10 +224,52 @@ Json::Value ActivityLog::EncodeHardwareState(const HardwareState& hwstate) { return ret; } +Json::Value ActivityLog::EncodeHardwareState(const HardwareState& hwstate) { + auto ret = EncodeHardwareStateCommon(hwstate); + ret[kKeyType] = Json::Value(kKeyHardwareState); + return ret; +} + +Json::Value ActivityLog::EncodeHardwareState( + const HardwareStatePre& pre_hwstate) { + auto ret = EncodeHardwareStateCommon(pre_hwstate.hwstate); + ret[kKeyType] = Json::Value(kKeyHardwareStatePre); + ret[kKeyMethodName] = Json::Value(pre_hwstate.name); + return ret; +} + +Json::Value ActivityLog::EncodeHardwareState( + const HardwareStatePost& post_hwstate) { + auto ret = EncodeHardwareStateCommon(post_hwstate.hwstate); + ret[kKeyType] = Json::Value(kKeyHardwareStatePost); + ret[kKeyMethodName] = Json::Value(post_hwstate.name); + return ret; +} + +Json::Value ActivityLog::EncodeHandleTimer(const HandleTimerPre& handle) { + Json::Value ret(Json::objectValue); + ret[kKeyType] = Json::Value(kKeyHandleTimerPre); + ret[kKeyMethodName] = Json::Value(handle.name); + ret[kKeyTimerNow] = Json::Value(handle.now); + if (handle.timeout_is_present) + ret[kKeyHandleTimerTimeout] = Json::Value(handle.timeout); + return ret; +} + +Json::Value ActivityLog::EncodeHandleTimer(const HandleTimerPost& handle) { + Json::Value ret(Json::objectValue); + ret[kKeyType] = Json::Value(kKeyHandleTimerPost); + ret[kKeyMethodName] = Json::Value(handle.name); + ret[kKeyTimerNow] = Json::Value(handle.now); + if (handle.timeout_is_present) + ret[kKeyHandleTimerTimeout] = Json::Value(handle.timeout); + return ret; +} + Json::Value ActivityLog::EncodeTimerCallback(stime_t timestamp) { Json::Value ret(Json::objectValue); ret[kKeyType] = Json::Value(kKeyTimerCallback); - ret[kKeyTimerCallbackNow] = Json::Value(timestamp); + ret[kKeyTimerNow] = Json::Value(timestamp); return ret; } @@ -191,9 +280,8 @@ Json::Value ActivityLog::EncodeCallbackRequest(stime_t timestamp) { return ret; } -Json::Value ActivityLog::EncodeGesture(const Gesture& gesture) { +Json::Value ActivityLog::EncodeGestureCommon(const Gesture& gesture) { Json::Value ret(Json::objectValue); - ret[kKeyType] = Json::Value(kKeyGesture); ret[kKeyGestureStartTime] = Json::Value(gesture.start_time); ret[kKeyGestureEndTime] = Json::Value(gesture.end_time); @@ -206,26 +294,24 @@ Json::Value ActivityLog::EncodeGesture(const Gesture& gesture) { break; case kGestureTypeMove: ret[kKeyGestureType] = Json::Value(kValueGestureTypeMove); - ret[kKeyGestureMoveDX] = Json::Value(gesture.details.move.dx); - ret[kKeyGestureMoveDY] = Json::Value(gesture.details.move.dy); - ret[kKeyGestureMoveOrdinalDX] = - Json::Value(gesture.details.move.ordinal_dx); - ret[kKeyGestureMoveOrdinalDY] = - Json::Value(gesture.details.move.ordinal_dy); + ret[kKeyGestureDX] = Json::Value(gesture.details.move.dx); + ret[kKeyGestureDY] = Json::Value(gesture.details.move.dy); + ret[kKeyGestureOrdinalDX] = Json::Value(gesture.details.move.ordinal_dx); + ret[kKeyGestureOrdinalDY] = Json::Value(gesture.details.move.ordinal_dy); break; case kGestureTypeScroll: ret[kKeyGestureType] = Json::Value(kValueGestureTypeScroll); - ret[kKeyGestureScrollDX] = Json::Value(gesture.details.scroll.dx); - ret[kKeyGestureScrollDY] = Json::Value(gesture.details.scroll.dy); - ret[kKeyGestureScrollOrdinalDX] = + ret[kKeyGestureDX] = Json::Value(gesture.details.scroll.dx); + ret[kKeyGestureDY] = Json::Value(gesture.details.scroll.dy); + ret[kKeyGestureOrdinalDX] = Json::Value(gesture.details.scroll.ordinal_dx); - ret[kKeyGestureScrollOrdinalDY] = + ret[kKeyGestureOrdinalDY] = Json::Value(gesture.details.scroll.ordinal_dy); break; case kGestureTypeMouseWheel: ret[kKeyGestureType] = Json::Value(kValueGestureTypeMouseWheel); - ret[kKeyGestureMouseWheelDX] = Json::Value(gesture.details.wheel.dx); - ret[kKeyGestureMouseWheelDY] = Json::Value(gesture.details.wheel.dy); + ret[kKeyGestureDX] = Json::Value(gesture.details.wheel.dx); + ret[kKeyGestureDY] = Json::Value(gesture.details.wheel.dy); ret[kKeyGestureMouseWheelTicksDX] = Json::Value(gesture.details.wheel.tick_120ths_dx); ret[kKeyGestureMouseWheelTicksDY] = @@ -259,11 +345,11 @@ Json::Value ActivityLog::EncodeGesture(const Gesture& gesture) { break; case kGestureTypeSwipe: ret[kKeyGestureType] = Json::Value(kValueGestureTypeSwipe); - ret[kKeyGestureSwipeDX] = Json::Value(gesture.details.swipe.dx); - ret[kKeyGestureSwipeDY] = Json::Value(gesture.details.swipe.dy); - ret[kKeyGestureSwipeOrdinalDX] = + ret[kKeyGestureDX] = Json::Value(gesture.details.swipe.dx); + ret[kKeyGestureDY] = Json::Value(gesture.details.swipe.dy); + ret[kKeyGestureOrdinalDX] = Json::Value(gesture.details.swipe.ordinal_dx); - ret[kKeyGestureSwipeOrdinalDY] = + ret[kKeyGestureOrdinalDY] = Json::Value(gesture.details.swipe.ordinal_dy); break; case kGestureTypeSwipeLift: @@ -271,13 +357,13 @@ Json::Value ActivityLog::EncodeGesture(const Gesture& gesture) { break; case kGestureTypeFourFingerSwipe: ret[kKeyGestureType] = Json::Value(kValueGestureTypeFourFingerSwipe); - ret[kKeyGestureFourFingerSwipeDX] = + ret[kKeyGestureDX] = Json::Value(gesture.details.four_finger_swipe.dx); - ret[kKeyGestureFourFingerSwipeDY] = + ret[kKeyGestureDY] = Json::Value(gesture.details.four_finger_swipe.dy); - ret[kKeyGestureFourFingerSwipeOrdinalDX] = + ret[kKeyGestureOrdinalDX] = Json::Value(gesture.details.four_finger_swipe.ordinal_dx); - ret[kKeyGestureFourFingerSwipeOrdinalDY] = + ret[kKeyGestureOrdinalDY] = Json::Value(gesture.details.four_finger_swipe.ordinal_dy); break; case kGestureTypeFourFingerSwipeLift: @@ -299,6 +385,26 @@ Json::Value ActivityLog::EncodeGesture(const Gesture& gesture) { return ret; } +Json::Value ActivityLog::EncodeGesture(const Gesture& gesture) { + auto ret = EncodeGestureCommon(gesture); + ret[kKeyType] = Json::Value(kKeyGesture); + return ret; +} + +Json::Value ActivityLog::EncodeGesture(const GestureConsume& gesture_consume) { + auto ret = EncodeGestureCommon(gesture_consume.gesture); + ret[kKeyType] = Json::Value(kKeyGestureConsume); + ret[kKeyMethodName] = Json::Value(gesture_consume.name); + return ret; +} + +Json::Value ActivityLog::EncodeGesture(const GestureProduce& gesture_produce) { + auto ret = EncodeGestureCommon(gesture_produce.gesture); + ret[kKeyType] = Json::Value(kKeyGestureProduce); + ret[kKeyMethodName] = Json::Value(gesture_produce.name); + return ret; +} + Json::Value ActivityLog::EncodePropChange(const PropChangeEntry& prop_change) { Json::Value ret(Json::objectValue); ret[kKeyType] = Json::Value(kKeyPropChange); @@ -334,6 +440,67 @@ Json::Value ActivityLog::EncodePropChange(const PropChangeEntry& prop_change) { return ret; } +Json::Value ActivityLog::EncodeGestureDebug( + const AccelGestureDebug& debug_data) { + Json::Value ret(Json::objectValue); + ret[kKeyType] = Json::Value(kKeyAccelGestureDebug); + ret[kKeyAccelDebugDroppedGesture] = Json::Value(debug_data.dropped_gesture); + if (debug_data.no_accel_for_gesture_type) + ret[kKeyAccelDebugNoAccelGestureType] = Json::Value(true); + else if (debug_data.no_accel_for_small_dt) + ret[kKeyAccelDebugNoAccelSmallDt] = Json::Value(true); + else if (debug_data.no_accel_for_small_speed) + ret[kKeyAccelDebugNoAccelSmallSpeed] = Json::Value(true); + else if (debug_data.no_accel_for_bad_gain) + ret[kKeyAccelDebugNoAccelBadGain] = Json::Value(true); + ret[kKeyAccelDebugXYAreVelocity] = Json::Value(debug_data.x_y_are_velocity); + ret[kKeyAccelDebugXScale] = Json::Value(debug_data.x_scale); + ret[kKeyAccelDebugYScale] = Json::Value(debug_data.y_scale); + ret[kKeyAccelDebugDt] = Json::Value(debug_data.dt); + ret[kKeyAccelDebugAdjustedDt] = Json::Value(debug_data.adjusted_dt); + ret[kKeyAccelDebugSpeed] = Json::Value(debug_data.speed); + if (debug_data.speed != debug_data.smoothed_speed) + ret[kKeyAccelDebugSmoothSpeed] = Json::Value(debug_data.smoothed_speed); + ret[kKeyAccelDebugGainX] = Json::Value(debug_data.gain_x); + ret[kKeyAccelDebugGainY] = Json::Value(debug_data.gain_y); + return ret; +} + +Json::Value ActivityLog::EncodeGestureDebug( + const TimestampGestureDebug& debug_data) { + Json::Value ret(Json::objectValue); + ret[kKeyType] = Json::Value(kKeyTimestampGestureDebug); + ret[kKeyTimestampDebugSkew] = Json::Value(debug_data.skew); + return ret; +} + +Json::Value ActivityLog::EncodeHardwareStateDebug( + const TimestampHardwareStateDebug& debug_data) { + Json::Value ret(Json::objectValue); + ret[kKeyType] = Json::Value(kKeyTimestampHardwareStateDebug); + ret[kKeyTimestampDebugIsUsingFake] = Json::Value(debug_data.is_using_fake); + if (debug_data.is_using_fake) { + ret[kKeyTimestampDebugWasFirstOrBackward] = + Json::Value(debug_data.was_first_or_backward); + ret[kKeyTimestampDebugPrevMscTimestampIn] = + Json::Value(debug_data.prev_msc_timestamp_in); + ret[kKeyTimestampDebugPrevMscTimestampOut] = + Json::Value(debug_data.prev_msc_timestamp_out); + } else { + ret[kKeyTimestampDebugWasDivergenceReset] = + Json::Value(debug_data.was_divergence_reset); + ret[kKeyTimestampDebugFakeTimestampIn] = + Json::Value(debug_data.fake_timestamp_in); + ret[kKeyTimestampDebugFakeTimestampDelta] = + Json::Value(debug_data.fake_timestamp_delta); + ret[kKeyTimestampDebugFakeTimestampOut] = + Json::Value(debug_data.fake_timestamp_out); + } + ret[kKeyTimestampDebugSkew] = Json::Value(debug_data.skew); + ret[kKeyTimestampDebugMaxSkew] = Json::Value(debug_data.max_skew); + return ret; +} + Json::Value ActivityLog::EncodePropRegistry() { Json::Value ret(Json::objectValue); if (!prop_reg_) @@ -357,6 +524,12 @@ Json::Value ActivityLog::EncodeCommonInfo() { [this, &entries](HardwareState hwstate) { entries.append(EncodeHardwareState(hwstate)); }, + [this, &entries](HardwareStatePre hwstate) { + entries.append(EncodeHardwareState(hwstate)); + }, + [this, &entries](HardwareStatePost hwstate) { + entries.append(EncodeHardwareState(hwstate)); + }, [this, &entries](TimerCallbackEntry now) { entries.append(EncodeTimerCallback(now.timestamp)); }, @@ -366,9 +539,30 @@ Json::Value ActivityLog::EncodeCommonInfo() { [this, &entries](Gesture gesture) { entries.append(EncodeGesture(gesture)); }, + [this, &entries](GestureConsume gesture) { + entries.append(EncodeGesture(gesture)); + }, + [this, &entries](GestureProduce gesture) { + entries.append(EncodeGesture(gesture)); + }, [this, &entries](PropChangeEntry prop_change) { entries.append(EncodePropChange(prop_change)); }, + [this, &entries](HandleTimerPre handle) { + entries.append(EncodeHandleTimer(handle)); + }, + [this, &entries](HandleTimerPost handle) { + entries.append(EncodeHandleTimer(handle)); + }, + [this, &entries](AccelGestureDebug debug_data) { + entries.append(EncodeGestureDebug(debug_data)); + }, + [this, &entries](TimestampGestureDebug debug_data) { + entries.append(EncodeGestureDebug(debug_data)); + }, + [this, &entries](TimestampHardwareStateDebug debug_data) { + entries.append(EncodeHardwareStateDebug(debug_data)); + }, [](auto arg) { Err("Unknown entry type"); } @@ -400,10 +594,19 @@ const char ActivityLog::kKeyInterpreterName[] = "interpreterName"; const char ActivityLog::kKeyNext[] = "nextLayer"; const char ActivityLog::kKeyRoot[] = "entries"; const char ActivityLog::kKeyType[] = "type"; +const char ActivityLog::kKeyMethodName[] = "methodName"; const char ActivityLog::kKeyHardwareState[] = "hardwareState"; +const char ActivityLog::kKeyHardwareStatePre[] = "debugHardwareStatePre"; +const char ActivityLog::kKeyHardwareStatePost[] = "debugHardwareStatePost"; const char ActivityLog::kKeyTimerCallback[] = "timerCallback"; const char ActivityLog::kKeyCallbackRequest[] = "callbackRequest"; const char ActivityLog::kKeyGesture[] = "gesture"; +const char ActivityLog::kKeyGestureConsume[] = "debugGestureConsume"; +const char ActivityLog::kKeyGestureProduce[] = "debugGestureProduce"; +const char ActivityLog::kKeyHandleTimerPre[] = "debugHandleTimerPre"; +const char ActivityLog::kKeyHandleTimerPost[] = "debugHandleTimerPost"; +const char ActivityLog::kKeyTimerNow[] = "now"; +const char ActivityLog::kKeyHandleTimerTimeout[] = "timeout"; const char ActivityLog::kKeyPropChange[] = "propertyChange"; const char ActivityLog::kKeyHardwareStateTimestamp[] = "timestamp"; const char ActivityLog::kKeyHardwareStateButtonsDown[] = "buttonsDown"; @@ -423,7 +626,6 @@ const char ActivityLog::kKeyFingerStatePositionX[] = "positionX"; const char ActivityLog::kKeyFingerStatePositionY[] = "positionY"; const char ActivityLog::kKeyFingerStateTrackingId[] = "trackingId"; const char ActivityLog::kKeyFingerStateFlags[] = "flags"; -const char ActivityLog::kKeyTimerCallbackNow[] = "now"; const char ActivityLog::kKeyCallbackRequestWhen[] = "when"; const char ActivityLog::kKeyGestureType[] = "gestureType"; const char ActivityLog::kValueGestureTypeContactInitiated[] = @@ -442,16 +644,10 @@ const char ActivityLog::kValueGestureTypeFourFingerSwipeLift[] = const char ActivityLog::kValueGestureTypeMetrics[] = "metrics"; const char ActivityLog::kKeyGestureStartTime[] = "startTime"; const char ActivityLog::kKeyGestureEndTime[] = "endTime"; -const char ActivityLog::kKeyGestureMoveDX[] = "dx"; -const char ActivityLog::kKeyGestureMoveDY[] = "dy"; -const char ActivityLog::kKeyGestureMoveOrdinalDX[] = "ordinalDx"; -const char ActivityLog::kKeyGestureMoveOrdinalDY[] = "ordinalDy"; -const char ActivityLog::kKeyGestureScrollDX[] = "dx"; -const char ActivityLog::kKeyGestureScrollDY[] = "dy"; -const char ActivityLog::kKeyGestureScrollOrdinalDX[] = "ordinalDx"; -const char ActivityLog::kKeyGestureScrollOrdinalDY[] = "ordinalDy"; -const char ActivityLog::kKeyGestureMouseWheelDX[] = "dx"; -const char ActivityLog::kKeyGestureMouseWheelDY[] = "dy"; +const char ActivityLog::kKeyGestureDX[] = "dx"; +const char ActivityLog::kKeyGestureDY[] = "dy"; +const char ActivityLog::kKeyGestureOrdinalDX[] = "ordinalDx"; +const char ActivityLog::kKeyGestureOrdinalDY[] = "ordinalDy"; const char ActivityLog::kKeyGestureMouseWheelTicksDX[] = "ticksDx"; const char ActivityLog::kKeyGestureMouseWheelTicksDY[] = "ticksDy"; const char ActivityLog::kKeyGesturePinchDZ[] = "dz"; @@ -464,14 +660,6 @@ const char ActivityLog::kKeyGestureFlingVY[] = "vy"; const char ActivityLog::kKeyGestureFlingOrdinalVX[] = "ordinalVx"; const char ActivityLog::kKeyGestureFlingOrdinalVY[] = "ordinalVy"; const char ActivityLog::kKeyGestureFlingState[] = "flingState"; -const char ActivityLog::kKeyGestureSwipeDX[] = "dx"; -const char ActivityLog::kKeyGestureSwipeDY[] = "dy"; -const char ActivityLog::kKeyGestureSwipeOrdinalDX[] = "ordinalDx"; -const char ActivityLog::kKeyGestureSwipeOrdinalDY[] = "ordinalDy"; -const char ActivityLog::kKeyGestureFourFingerSwipeDX[] = "dx"; -const char ActivityLog::kKeyGestureFourFingerSwipeDY[] = "dy"; -const char ActivityLog::kKeyGestureFourFingerSwipeOrdinalDX[] = "ordinalDx"; -const char ActivityLog::kKeyGestureFourFingerSwipeOrdinalDY[] = "ordinalDy"; const char ActivityLog::kKeyGestureMetricsType[] = "metricsType"; const char ActivityLog::kKeyGestureMetricsData1[] = "data1"; const char ActivityLog::kKeyGestureMetricsData2[] = "data2"; @@ -504,5 +692,42 @@ const char ActivityLog::kKeyHardwarePropHasWheel[] = "hasWheel"; const char ActivityLog::kKeyProperties[] = "properties"; +const char ActivityLog::kKeyAccelGestureDebug[] = "debugAccelGesture"; +const char ActivityLog::kKeyAccelDebugNoAccelBadGain[] = "noAccelBadGain"; +const char ActivityLog::kKeyAccelDebugNoAccelGestureType[] = "noAccelBadType"; +const char ActivityLog::kKeyAccelDebugNoAccelSmallDt[] = "noAccelSmallDt"; +const char ActivityLog::kKeyAccelDebugNoAccelSmallSpeed[] = + "noAccelSmallSpeed"; +const char ActivityLog::kKeyAccelDebugDroppedGesture[] = "gestureDropped"; +const char ActivityLog::kKeyAccelDebugXYAreVelocity[] = "XYAreVelocity"; +const char ActivityLog::kKeyAccelDebugXScale[] = "XScale"; +const char ActivityLog::kKeyAccelDebugYScale[] = "YScale"; +const char ActivityLog::kKeyAccelDebugDt[] = "dt"; +const char ActivityLog::kKeyAccelDebugAdjustedDt[] = "adjDt"; +const char ActivityLog::kKeyAccelDebugSpeed[] = "speed"; +const char ActivityLog::kKeyAccelDebugSmoothSpeed[] = "smoothSpeed"; +const char ActivityLog::kKeyAccelDebugGainX[] = "gainX"; +const char ActivityLog::kKeyAccelDebugGainY[] = "gainY"; + +const char ActivityLog::kKeyTimestampGestureDebug[] = "debugTimestampGesture"; +const char ActivityLog::kKeyTimestampHardwareStateDebug[] = + "debugTimestampHardwareState"; +const char ActivityLog::kKeyTimestampDebugIsUsingFake[] = "isUsingFake"; +const char ActivityLog::kKeyTimestampDebugWasFirstOrBackward[] = + "wasFirstOrBackward"; +const char ActivityLog::kKeyTimestampDebugPrevMscTimestampIn[] = + "prevMscTimestampIn"; +const char ActivityLog::kKeyTimestampDebugPrevMscTimestampOut[] = + "prevMscTimestampOut"; +const char ActivityLog::kKeyTimestampDebugWasDivergenceReset[] = + "wasDivergenceReset"; +const char ActivityLog::kKeyTimestampDebugFakeTimestampIn[] = + "fakeTimestampIn"; +const char ActivityLog::kKeyTimestampDebugFakeTimestampDelta[] = + "fakeTimestampDelta"; +const char ActivityLog::kKeyTimestampDebugFakeTimestampOut[] = + "fakeTimestampOut"; +const char ActivityLog::kKeyTimestampDebugSkew[] = "skew"; +const char ActivityLog::kKeyTimestampDebugMaxSkew[] = "maxSkew"; } // namespace gestures diff --git a/src/activity_log_unittest.cc b/src/activity_log_unittest.cc index aadf2f5..36dd6c0 100644 --- a/src/activity_log_unittest.cc +++ b/src/activity_log_unittest.cc @@ -33,24 +33,24 @@ TEST(ActivityLogTest, SimpleTest) { EXPECT_TRUE(strstr(log.Encode().c_str(), "foobarstr")); HardwareProperties hwprops = { - 6011, // left edge - 6012, // top edge - 6013, // right edge - 6014, // bottom edge - 6015, // x pixels/TP width - 6016, // y pixels/TP height - 6017, // x screen DPI - 6018, // y screen DPI - 6019, // orientation minimum - 6020, // orientation maximum - 6021, // max fingers - 6022, // max touch - 1, // t5r2 - 0, // semi-mt - 1, // is button pad, - 0, // has wheel - 0, // vertical wheel is high resolution - 0, // is haptic pad + .left = 6011, + .top = 6012, + .right = 6013, + .bottom = 6014, + .res_x = 6015, + .res_y = 6016, + .screen_x_dpi = 6017, + .screen_y_dpi = 6018, + .orientation_minimum = 6019, + .orientation_maximum = 6020, + .max_finger_cnt = 6021, + .max_touch_cnt = 6022, + .supports_t5r2 = 1, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; log.SetHardwareProperties(hwprops); @@ -131,10 +131,6 @@ TEST(ActivityLogTest, SimpleTest) { TEST(ActivityLogTest, WrapAroundTest) { ActivityLog log(nullptr); -#ifndef __ANDROID__ - // Disabling this test with DISABLED_ prefix is not sufficient as just by compiling this - // section causes the hwasan crash at runtime in some other tests - // TODO(b/311110623): re-enable this section once we've tracked down the hwasan crash // overfill the buffer const size_t fill_size = (ActivityLog::kBufferSize * 3) / 2; for (size_t i = 0; i < fill_size; i++) @@ -144,7 +140,6 @@ TEST(ActivityLogTest, WrapAroundTest) { log.LogCallbackRequest(static_cast<stime_t>(fill_size)); string second_prefix = log.Encode().substr(0, prefix_length); EXPECT_NE(first_prefix, second_prefix); -#endif } TEST(ActivityLogTest, VersionTest) { @@ -227,4 +222,273 @@ TEST(ActivityLogTest, EncodePropChangeShortTest) { ActivityLog::kValuePropChangeTypeShort); } +TEST(ActivityLogTest, HardwareStatePreTest) { + PropRegistry prop_reg; + ActivityLog log(&prop_reg); + + HardwareProperties hwprops = { + .left = 6011, + .top = 6012, + .right = 6013, + .bottom = 6014, + .res_x = 6015, + .res_y = 6016, + .screen_x_dpi = 6017, + .screen_y_dpi = 6018, + .orientation_minimum = 6019, + .orientation_maximum = 6020, + .max_finger_cnt = 6021, + .max_touch_cnt = 6022, + .supports_t5r2 = 1, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, + }; + log.SetHardwareProperties(hwprops); + + FingerState fs = { 0.0, 0.0, 0.0, 0.0, 9.0, 0.0, 3.0, 4.0, 22, 0 }; + HardwareState hs = make_hwstate(1.0, 0, 1, 1, &fs); + + ActivityLog::Entry* entry; + Json::Value result; + + EXPECT_EQ(0, log.size()); + + // Build and log a HardwareStatePre structure + log.LogHardwareStatePre("ActivityLogTest_HwStateTest", hs); + ASSERT_EQ(1, log.size()); + entry = log.GetEntry(0); + ASSERT_TRUE(std::holds_alternative<ActivityLog::HardwareStatePre> + (entry->details)); + + // Encode the HardwareStatePre into Json + result = log.EncodeCommonInfo(); + result = result[ActivityLog::kKeyRoot][0]; + + // Verify the Json information + EXPECT_EQ(result[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyHardwareStatePre)); + EXPECT_EQ(result[ActivityLog::kKeyMethodName], + Json::Value("ActivityLogTest_HwStateTest")); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateButtonsDown], + Json::Value(hs.buttons_down)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateTouchCnt], + Json::Value(hs.touch_cnt)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateTimestamp], + Json::Value(hs.timestamp)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateRelX], Json::Value(hs.rel_x)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateRelY], Json::Value(hs.rel_y)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateRelWheel], + Json::Value(hs.rel_wheel)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateRelHWheel], + Json::Value(hs.rel_hwheel)); + log.Clear(); +} + +TEST(ActivityLogTest, HardwareStatePostTest) { + PropRegistry prop_reg; + ActivityLog log(&prop_reg); + + HardwareProperties hwprops = { + .left = 6011, + .top = 6012, + .right = 6013, + .bottom = 6014, + .res_x = 6015, + .res_y = 6016, + .screen_x_dpi = 6017, + .screen_y_dpi = 6018, + .orientation_minimum = 6019, + .orientation_maximum = 6020, + .max_finger_cnt = 6021, + .max_touch_cnt = 6022, + .supports_t5r2 = 1, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, + }; + log.SetHardwareProperties(hwprops); + + FingerState fs = { 0.0, 0.0, 0.0, 0.0, 9.0, 0.0, 3.0, 4.0, 22, 0 }; + HardwareState hs = make_hwstate(1.0, 0, 1, 1, &fs); + + ActivityLog::Entry* entry; + Json::Value result; + + EXPECT_EQ(0, log.size()); + + // Build and log a HardwareStatePost structure + log.LogHardwareStatePost("ActivityLogTest_HwStateTest", hs); + ASSERT_EQ(1, log.size()); + entry = log.GetEntry(0); + ASSERT_TRUE(std::holds_alternative<ActivityLog::HardwareStatePost> + (entry->details)); + + // Encode the HardwareStatePost into Json + result = log.EncodeCommonInfo(); + result = result[ActivityLog::kKeyRoot][0]; + + // Verify the Json information + EXPECT_EQ(result[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyHardwareStatePost)); + EXPECT_EQ(result[ActivityLog::kKeyMethodName], + Json::Value("ActivityLogTest_HwStateTest")); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateButtonsDown], + Json::Value(hs.buttons_down)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateTouchCnt], + Json::Value(hs.touch_cnt)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateTimestamp], + Json::Value(hs.timestamp)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateRelX], Json::Value(hs.rel_x)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateRelY], Json::Value(hs.rel_y)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateRelWheel], + Json::Value(hs.rel_wheel)); + EXPECT_EQ(result[ActivityLog::kKeyHardwareStateRelHWheel], + Json::Value(hs.rel_hwheel)); + log.Clear(); +} + + +TEST(ActivityLogTest, GestureConsumeTest) { + PropRegistry prop_reg; + ActivityLog log(&prop_reg); + ActivityLog::Entry* entry; + Json::Value result; + + EXPECT_EQ(0, log.size()); + + // Build and log a GestureConsume structure + Gesture move(kGestureMove, 1.0, 2.0, 773, 4.0); + log.LogGestureConsume("ActivityLogTest_GestureTest", move); + ASSERT_EQ(1, log.size()); + entry = log.GetEntry(0); + ASSERT_TRUE(std::holds_alternative<ActivityLog::GestureConsume> + (entry->details)); + + // Encode the GestureConsume into Json + result = log.EncodeCommonInfo(); + result = result[ActivityLog::kKeyRoot][0]; + + // Verify the Json information + EXPECT_EQ(result[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureConsume)); + EXPECT_EQ(result[ActivityLog::kKeyMethodName], + Json::Value("ActivityLogTest_GestureTest")); + EXPECT_EQ(result[ActivityLog::kKeyGestureType], + Json::Value(ActivityLog::kValueGestureTypeMove)); + EXPECT_EQ(result[ActivityLog::kKeyGestureDX], + Json::Value(move.details.move.dx)); + EXPECT_EQ(result[ActivityLog::kKeyGestureDY], + Json::Value(move.details.move.dy)); + EXPECT_EQ(result[ActivityLog::kKeyGestureOrdinalDX], + Json::Value(move.details.move.ordinal_dx)); + EXPECT_EQ(result[ActivityLog::kKeyGestureOrdinalDY], + Json::Value(move.details.move.ordinal_dy)); + log.Clear(); +} + +TEST(ActivityLogTest, GestureProduceTest) { + PropRegistry prop_reg; + ActivityLog log(&prop_reg); + ActivityLog::Entry* entry; + Json::Value result; + + EXPECT_EQ(0, log.size()); + + // Build and log a GestureProduce structure + Gesture scroll(kGestureScroll, 1.0, 2.0, 312, 4.0); + log.LogGestureProduce("ActivityLogTest_GestureTest", scroll); + ASSERT_EQ(1, log.size()); + entry = log.GetEntry(0); + ASSERT_TRUE(std::holds_alternative<ActivityLog::GestureProduce> + (entry->details)); + + // Encode the GestureProduce into Json + result = log.EncodeCommonInfo(); + result = result[ActivityLog::kKeyRoot][0]; + + // Verify the Json information + EXPECT_EQ(result[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureProduce)); + EXPECT_EQ(result[ActivityLog::kKeyMethodName], + Json::Value("ActivityLogTest_GestureTest")); + EXPECT_EQ(result[ActivityLog::kKeyGestureType], + Json::Value(ActivityLog::kValueGestureTypeScroll)); + EXPECT_EQ(result[ActivityLog::kKeyGestureDX], + Json::Value(scroll.details.scroll.dx)); + EXPECT_EQ(result[ActivityLog::kKeyGestureDY], + Json::Value(scroll.details.scroll.dy)); + EXPECT_EQ(result[ActivityLog::kKeyGestureOrdinalDX], + Json::Value(scroll.details.scroll.ordinal_dx)); + EXPECT_EQ(result[ActivityLog::kKeyGestureOrdinalDY], + Json::Value(scroll.details.scroll.ordinal_dy)); + log.Clear(); +} + +TEST(ActivityLogTest, HandleTimerPreTest) { + PropRegistry prop_reg; + ActivityLog log(&prop_reg); + ActivityLog::Entry* entry; + Json::Value result; + stime_t timeout = 1; + + EXPECT_EQ(0, log.size()); + + // Build and log a HandleTimerPre structure + log.LogHandleTimerPre("ActivityLogTest_HandleTimerTest", 0, &timeout); + EXPECT_EQ(1, log.size()); + entry = log.GetEntry(0); + EXPECT_TRUE(std::holds_alternative<ActivityLog::HandleTimerPre> + (entry->details)); + + // Encode the HandleTimerPre into Json + result = log.EncodeCommonInfo(); + result = result[ActivityLog::kKeyRoot][0]; + + // Verify the Json information + EXPECT_EQ(result[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyHandleTimerPre)); + EXPECT_EQ(result[ActivityLog::kKeyMethodName], + Json::Value("ActivityLogTest_HandleTimerTest")); + EXPECT_EQ(result[ActivityLog::kKeyTimerNow], + Json::Value(static_cast<stime_t>(0))); + EXPECT_EQ(result[ActivityLog::kKeyHandleTimerTimeout], Json::Value(timeout)); + log.Clear(); +} + +TEST(ActivityLogTest, HandleTimerPostTest) { + PropRegistry prop_reg; + ActivityLog log(&prop_reg); + ActivityLog::Entry* entry; + Json::Value result; + stime_t timeout = 1; + + EXPECT_EQ(0, log.size()); + + // Build and log a HandleTimerPost structure + log.LogHandleTimerPost("ActivityLogTest_HandleTimerTest", 0, &timeout); + EXPECT_EQ(1, log.size()); + entry = log.GetEntry(0); + EXPECT_TRUE(std::holds_alternative<ActivityLog::HandleTimerPost> + (entry->details)); + + // Encode the HandleTimerPost into Json + result = log.EncodeCommonInfo(); + result = result[ActivityLog::kKeyRoot][0]; + + // Verify the Json information + EXPECT_EQ(result[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyHandleTimerPost)); + EXPECT_EQ(result[ActivityLog::kKeyMethodName], + Json::Value("ActivityLogTest_HandleTimerTest")); + EXPECT_EQ(result[ActivityLog::kKeyTimerNow], + Json::Value(static_cast<stime_t>(0))); + EXPECT_EQ(result[ActivityLog::kKeyHandleTimerTimeout], Json::Value(timeout)); + log.Clear(); +} + } // namespace gestures diff --git a/src/activity_replay.cc b/src/activity_replay.cc index 47039cb..e020be9 100644 --- a/src/activity_replay.cc +++ b/src/activity_replay.cc @@ -25,7 +25,9 @@ namespace { // Helper to std::visit with lambdas. template <typename... V> -struct Visitor : V... {}; +struct Visitor : V... { + using V::operator()...; +}; // Explicit deduction guide (not needed as of C++20). template <typename... V> Visitor(V...) -> Visitor<V...>; @@ -334,11 +336,11 @@ bool ActivityReplay::ParseFingerState(const Json::Value& entry, } bool ActivityReplay::ParseTimerCallback(const Json::Value& entry) { - if (!entry.isMember(ActivityLog::kKeyTimerCallbackNow)) { + if (!entry.isMember(ActivityLog::kKeyTimerNow)) { Err("can't parse timercallback"); return false; } - log_.LogTimerCallback(entry[ActivityLog::kKeyTimerCallbackNow].asDouble()); + log_.LogTimerCallback(entry[ActivityLog::kKeyTimerNow].asDouble()); return true; } @@ -407,86 +409,86 @@ bool ActivityReplay::ParseGesture(const Json::Value& entry) { bool ActivityReplay::ParseGestureMove(const Json::Value& entry, Gesture* out_gs) { out_gs->type = kGestureTypeMove; - if (!entry.isMember(ActivityLog::kKeyGestureMoveDX)) { + if (!entry.isMember(ActivityLog::kKeyGestureDX)) { Err("can't parse move dx"); return false; } - out_gs->details.move.dx = entry[ActivityLog::kKeyGestureMoveDX].asDouble(); - if (!entry.isMember(ActivityLog::kKeyGestureMoveDY)) { + out_gs->details.move.dx = entry[ActivityLog::kKeyGestureDX].asDouble(); + if (!entry.isMember(ActivityLog::kKeyGestureDY)) { Err("can't parse move dy"); return false; } - out_gs->details.move.dy = entry[ActivityLog::kKeyGestureMoveDY].asDouble(); - if (!entry.isMember(ActivityLog::kKeyGestureMoveOrdinalDX)) { + out_gs->details.move.dy = entry[ActivityLog::kKeyGestureDY].asDouble(); + if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDX)) { Err("can't parse move ordinal_dx"); return false; } out_gs->details.move.ordinal_dx = - entry[ActivityLog::kKeyGestureMoveOrdinalDX].asDouble(); - if (!entry.isMember(ActivityLog::kKeyGestureMoveOrdinalDY)) { + entry[ActivityLog::kKeyGestureOrdinalDX].asDouble(); + if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDY)) { Err("can't parse move ordinal_dy"); return false; } out_gs->details.move.ordinal_dy = - entry[ActivityLog::kKeyGestureMoveOrdinalDY].asDouble(); + entry[ActivityLog::kKeyGestureOrdinalDY].asDouble(); return true; } bool ActivityReplay::ParseGestureScroll(const Json::Value& entry, Gesture* out_gs) { out_gs->type = kGestureTypeScroll; - if (!entry.isMember(ActivityLog::kKeyGestureScrollDX)) { + if (!entry.isMember(ActivityLog::kKeyGestureDX)) { Err("can't parse scroll dx"); return false; } out_gs->details.scroll.dx = - entry[ActivityLog::kKeyGestureScrollDX].asDouble(); - if (!entry.isMember(ActivityLog::kKeyGestureScrollDY)) { + entry[ActivityLog::kKeyGestureDX].asDouble(); + if (!entry.isMember(ActivityLog::kKeyGestureDY)) { Err("can't parse scroll dy"); return false; } out_gs->details.scroll.dy = - entry[ActivityLog::kKeyGestureScrollDY].asDouble(); - if (!entry.isMember(ActivityLog::kKeyGestureScrollOrdinalDX)) { + entry[ActivityLog::kKeyGestureDY].asDouble(); + if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDX)) { Err("can't parse scroll ordinal_dx"); return false; } out_gs->details.scroll.ordinal_dx = - entry[ActivityLog::kKeyGestureScrollOrdinalDX].asDouble(); - if (!entry.isMember(ActivityLog::kKeyGestureScrollOrdinalDY)) { + entry[ActivityLog::kKeyGestureOrdinalDX].asDouble(); + if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDY)) { Err("can't parse scroll ordinal_dy"); return false; } out_gs->details.scroll.ordinal_dy = - entry[ActivityLog::kKeyGestureScrollOrdinalDY].asDouble(); + entry[ActivityLog::kKeyGestureOrdinalDY].asDouble(); return true; } bool ActivityReplay::ParseGestureSwipe(const Json::Value& entry, Gesture* out_gs) { out_gs->type = kGestureTypeSwipe; - if (!entry.isMember(ActivityLog::kKeyGestureSwipeDX)) { + if (!entry.isMember(ActivityLog::kKeyGestureDX)) { Err("can't parse swipe dx"); return false; } - out_gs->details.swipe.dx = entry[ActivityLog::kKeyGestureSwipeDX].asDouble(); - if (!entry.isMember(ActivityLog::kKeyGestureSwipeDY)) { + out_gs->details.swipe.dx = entry[ActivityLog::kKeyGestureDX].asDouble(); + if (!entry.isMember(ActivityLog::kKeyGestureDY)) { Err("can't parse swipe dy"); return false; } - out_gs->details.swipe.dy = entry[ActivityLog::kKeyGestureSwipeDY].asDouble(); - if (!entry.isMember(ActivityLog::kKeyGestureSwipeOrdinalDX)) { + out_gs->details.swipe.dy = entry[ActivityLog::kKeyGestureDY].asDouble(); + if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDX)) { Err("can't parse swipe ordinal_dx"); return false; } out_gs->details.swipe.ordinal_dx = - entry[ActivityLog::kKeyGestureSwipeOrdinalDX].asDouble(); - if (!entry.isMember(ActivityLog::kKeyGestureSwipeOrdinalDY)) { + entry[ActivityLog::kKeyGestureOrdinalDX].asDouble(); + if (!entry.isMember(ActivityLog::kKeyGestureOrdinalDY)) { Err("can't parse swipe ordinal_dy"); return false; } out_gs->details.swipe.ordinal_dy = - entry[ActivityLog::kKeyGestureSwipeOrdinalDY].asDouble(); + entry[ActivityLog::kKeyGestureOrdinalDY].asDouble(); return true; } @@ -736,12 +738,12 @@ bool ActivityReplay::ReplayPropChange( for (::set<Property*>::iterator it = props.begin(), e = props.end(); it != e; ++it) { prop = *it; - if (strcmp(prop->name(), entry.name) == 0) + if (strcmp(prop->name(), entry.name.c_str()) == 0) break; prop = nullptr; } if (!prop) { - Err("Unable to find prop %s to set.", entry.name); + Err("Unable to find prop %s to set.", entry.name.c_str()); return false; } bool valid_property = true; diff --git a/src/box_filter_interpreter.cc b/src/box_filter_interpreter.cc index 3745e7a..b798b0c 100644 --- a/src/box_filter_interpreter.cc +++ b/src/box_filter_interpreter.cc @@ -21,7 +21,11 @@ BoxFilterInterpreter::BoxFilterInterpreter(PropRegistry* prop_reg, void BoxFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { + const char name[] = "BoxFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + if (box_width_.val_ == 0.0 && box_height_.val_ == 0.0) { + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); return; } @@ -63,6 +67,7 @@ void BoxFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, for (size_t i = 0; i < hwstate.finger_cnt; i++) previous_output_[hwstate.fingers[i].tracking_id] = hwstate.fingers[i]; + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } diff --git a/src/box_filter_interpreter_unittest.cc b/src/box_filter_interpreter_unittest.cc index 01b81c7..b2f37d7 100644 --- a/src/box_filter_interpreter_unittest.cc +++ b/src/box_filter_interpreter_unittest.cc @@ -19,6 +19,18 @@ using std::make_pair; using std::pair; using std::vector; +static const HardwareProperties hwprops = { + .right = 100, .bottom = 100, + .res_x = 1, .res_y = 1, + .screen_x_dpi = 0, .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 1, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, +}; + namespace gestures { class BoxFilterInterpreterTest : public ::testing::Test {}; @@ -51,21 +63,8 @@ TEST(BoxFilterInterpreterTest, SimpleTest) { BoxFilterInterpreterTestInterpreter* base_interpreter = new BoxFilterInterpreterTestInterpreter; BoxFilterInterpreter interpreter(nullptr, base_interpreter, nullptr); - interpreter.box_width_.val_ = 1.0; interpreter.box_height_.val_ = 1.0; - - HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, 1, // x res (pixels/mm), y res (pixels/mm) - 1, 1, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 5, 5, // max fingers, max_touch, - 0, 0, 1, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad - }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); EXPECT_FALSE(base_interpreter->handle_timer_called_); @@ -97,4 +96,41 @@ TEST(BoxFilterInterpreterTest, SimpleTest) { } } +TEST(BoxFilterInterpreterTest, ZeroSizeBoxTest) { + BoxFilterInterpreterTestInterpreter* base_interpreter = + new BoxFilterInterpreterTestInterpreter; + BoxFilterInterpreter interpreter(nullptr, base_interpreter, nullptr); + interpreter.box_width_.val_ = 0.0; + interpreter.box_height_.val_ = 0.0; + TestInterpreterWrapper wrapper(&interpreter, &hwprops); + + EXPECT_FALSE(base_interpreter->handle_timer_called_); + wrapper.HandleTimer(0.0, nullptr); + EXPECT_TRUE(base_interpreter->handle_timer_called_); + + FingerState fs = { 0, 0, 0, 0, 1, 0, 3.0, 0.0, 1, 0 }; + HardwareState hs = make_hwstate(0.0, 0, 1, 1, &fs); + + InputAndExpectedOutput data[] = { + { 3.0, 3.0 }, + { 4.0, 4.0 }, + { 3.0, 3.0 }, + { 4.0, 4.0 }, + { 5.0, 5.0 }, + { 6.0, 6.0 }, + { 5.0, 5.0 }, + { 4.0, 4.0 }, + }; + + stime_t now = 0.0; + const stime_t kTimeDelta = 0.01; + for (size_t i = 0; i < arraysize(data); i++) { + now += kTimeDelta; + hs.timestamp = now; + fs.position_y = data[i].in; + wrapper.SyncInterpret(hs, nullptr); + EXPECT_FLOAT_EQ(data[i].out, fs.position_y) << "i=" << i; + } +} + } // namespace gestures diff --git a/src/click_wiggle_filter_interpreter.cc b/src/click_wiggle_filter_interpreter.cc index 636a27e..e4f9b10 100644 --- a/src/click_wiggle_filter_interpreter.cc +++ b/src/click_wiggle_filter_interpreter.cc @@ -31,6 +31,9 @@ ClickWiggleFilterInterpreter::ClickWiggleFilterInterpreter( void ClickWiggleFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { + const char name[] = "ClickWiggleFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + UpdateClickWiggle(hwstate); SetWarpFlags(hwstate); @@ -42,6 +45,7 @@ void ClickWiggleFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, prev_pressure_[fs.tracking_id] = fs.pressure; } + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } diff --git a/src/click_wiggle_filter_interpreter_unittest.cc b/src/click_wiggle_filter_interpreter_unittest.cc index b8f7b06..a7168d9 100644 --- a/src/click_wiggle_filter_interpreter_unittest.cc +++ b/src/click_wiggle_filter_interpreter_unittest.cc @@ -55,24 +55,22 @@ TEST(ClickWiggleFilterInterpreterTest, WiggleSuppressTest) { new ClickWiggleFilterInterpreterTestInterpreter; ClickWiggleFilterInterpreter interpreter(nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 92, // right edge - 61, // bottom edge - 1, // x pixels/TP width - 1, // y pixels/TP height - 26, // x screen DPI - 26, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 0, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 92, + .bottom = 61, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 0, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -131,24 +129,22 @@ TEST(ClickWiggleFilterInterpreterTest, OneFingerClickSuppressTest) { new ClickWiggleFilterInterpreterTestInterpreter; ClickWiggleFilterInterpreter interpreter(nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 92, // right edge - 61, // bottom edge - 1, // x pixels/TP width - 1, // y pixels/TP height - 26, // x screen DPI - 26, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 0, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 92, + .bottom = 61, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 0, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -202,24 +198,22 @@ TEST(ClickWiggleFilterInterpreter, ThumbClickTest) { new ClickWiggleFilterInterpreterTestInterpreter; ClickWiggleFilterInterpreter interpreter(nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 92, // right edge - 61, // bottom edge - 1, // x pixels/TP width - 1, // y pixels/TP height - 26, // x screen DPI - 26, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 0, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 92, + .bottom = 61, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 0, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -258,24 +252,22 @@ TEST(ClickWiggleFilterInterpreter, TimeBackwardsTest) { new ClickWiggleFilterInterpreterTestInterpreter; ClickWiggleFilterInterpreter interpreter(nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 92, // right edge - 61, // bottom edge - 1, // x pixels/TP width - 1, // y pixels/TP height - 26, // x screen DPI - 26, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 0, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 92, + .bottom = 61, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 0, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -326,24 +318,22 @@ TEST(ClickWiggleFilterInterpreter, ThumbClickWiggleWithPalmTest) { new ClickWiggleFilterInterpreterTestInterpreter; ClickWiggleFilterInterpreter interpreter(nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0.000000, // left edge - 0.000000, // top edge - 106.666672, // right edge - 68.000000, // bottom edge - 1.000000, // x pixels/TP width - 1.000000, // y pixels/TP height - 25.400000, // x screen DPI - 25.400000, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 15, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 106.666672, + .bottom = 68.000000, + .res_x = 1.000000, + .res_y = 1.000000, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 15, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); diff --git a/src/finger_merge_filter_interpreter.cc b/src/finger_merge_filter_interpreter.cc index 1597e00..c75ac14 100644 --- a/src/finger_merge_filter_interpreter.cc +++ b/src/finger_merge_filter_interpreter.cc @@ -45,8 +45,13 @@ FingerMergeFilterInterpreter::FingerMergeFilterInterpreter( void FingerMergeFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { + const char name[] = "FingerMergeFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + if (finger_merge_filter_enable_.val_) UpdateFingerMergeState(hwstate); + + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } diff --git a/src/finger_merge_filter_interpreter_unittest.cc b/src/finger_merge_filter_interpreter_unittest.cc index 0c85915..fc804d4 100644 --- a/src/finger_merge_filter_interpreter_unittest.cc +++ b/src/finger_merge_filter_interpreter_unittest.cc @@ -52,15 +52,15 @@ TEST(FingerMergeFilterInterpreterTest, SimpleTest) { interpreter.finger_merge_filter_enable_.val_ = true; HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, 1, // x res (pixels/mm), y res (pixels/mm) - 1, 1, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 5, 5, // max fingers, max_touch, - 0, 0, 1, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 1, .res_y = 1, + .screen_x_dpi = 0, .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 1, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); diff --git a/src/finger_metrics.cc b/src/finger_metrics.cc index 4f62942..a79ea10 100644 --- a/src/finger_metrics.cc +++ b/src/finger_metrics.cc @@ -34,6 +34,10 @@ FingerMetrics::FingerMetrics() FingerMetrics::FingerMetrics(short tracking_id) : tracking_id_(tracking_id) {} +FingerMetrics::FingerMetrics(short tracking_id, stime_t timestamp) + : tracking_id_(tracking_id), + origin_time_(timestamp) {} + FingerMetrics::FingerMetrics(const FingerState& state, stime_t timestamp) : tracking_id_(state.tracking_id), @@ -132,4 +136,13 @@ void Metrics::Clear() { fingers_.clear(); } +void Metrics::SetFingerOriginTimestampForTesting(short tracking_id, + stime_t time) { + if (auto iter = fingers_.find(FingerMetrics(tracking_id)); + iter != fingers_.end()) { + fingers_.erase(iter); + } + fingers_.push_back(FingerMetrics(tracking_id, time)); +} + } // namespace gestures diff --git a/src/fling_stop_filter_interpreter.cc b/src/fling_stop_filter_interpreter.cc index 2ce44f6..5cf3c78 100644 --- a/src/fling_stop_filter_interpreter.cc +++ b/src/fling_stop_filter_interpreter.cc @@ -25,6 +25,9 @@ FlingStopFilterInterpreter::FlingStopFilterInterpreter( void FlingStopFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { + const char name[] = "FlingStopFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + fingers_of_last_hwstate_.clear(); for (int i = 0; i < hwstate.finger_cnt; i++) fingers_of_last_hwstate_.insert(hwstate.fingers[i].tracking_id); @@ -37,15 +40,19 @@ void FlingStopFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, } if (hwstate.timestamp > fling_stop_deadline_) { // sub in a fling before processing other interpreters - ProduceGesture(Gesture(kGestureFling, prev_timestamp_, - hwstate.timestamp, 0.0, 0.0, - GESTURES_FLING_TAP_DOWN)); + auto fling_tap_down = Gesture(kGestureFling, prev_timestamp_, + hwstate.timestamp, 0.0, 0.0, + GESTURES_FLING_TAP_DOWN); + LogGestureProduce(name, fling_tap_down); + ProduceGesture(fling_tap_down); + fling_stop_already_sent_ = true; fling_stop_deadline_ = NO_DEADLINE; } } stime_t next_timeout = NO_DEADLINE; + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, &next_timeout); *timeout = SetNextDeadlineAndReturnTimeoutVal(hwstate.timestamp, @@ -62,7 +69,6 @@ bool FlingStopFilterInterpreter::NeedsExtraTime( num_new_fingers++; } } - return (num_new_fingers >= 2); } @@ -80,6 +86,9 @@ bool FlingStopFilterInterpreter::FlingStopNeeded(const Gesture& gesture) const { } void FlingStopFilterInterpreter::ConsumeGesture(const Gesture& gesture) { + const char name[] = "FlingStopFilterInterpreter::ConsumeGesture"; + LogGestureConsume(name, gesture); + if (gesture.type == kGestureTypeFling) { fingers_present_for_last_fling_ = fingers_of_last_hwstate_; already_extended_ = false; @@ -87,11 +96,15 @@ void FlingStopFilterInterpreter::ConsumeGesture(const Gesture& gesture) { if (FlingStopNeeded(gesture)) { // sub in a fling before a new gesture - ProduceGesture(Gesture(kGestureFling, gesture.start_time, - gesture.start_time, 0.0, 0.0, - GESTURES_FLING_TAP_DOWN)); + auto fling_tap_down = Gesture(kGestureFling, gesture.start_time, + gesture.start_time, 0.0, 0.0, + GESTURES_FLING_TAP_DOWN); + LogGestureProduce(name, fling_tap_down); + ProduceGesture(fling_tap_down); } + LogGestureProduce(name, gesture); ProduceGesture(gesture); + fling_stop_deadline_ = NO_DEADLINE; prev_gesture_type_ = gesture.type; fling_stop_already_sent_ = false; @@ -117,6 +130,9 @@ void FlingStopFilterInterpreter::UpdateFlingStopDeadline( void FlingStopFilterInterpreter::HandleTimerImpl(stime_t now, stime_t* timeout) { + const char name[] = "FlingStopFilterInterpreter::HandleTimerImpl"; + LogHandleTimerPre(name, now, timeout); + stime_t next_timeout; if (ShouldCallNextTimer(fling_stop_deadline_)) { if (next_timer_deadline_ > now) { @@ -133,9 +149,12 @@ void FlingStopFilterInterpreter::HandleTimerImpl(stime_t now, return; } fling_stop_deadline_ = NO_DEADLINE; - ProduceGesture(Gesture(kGestureFling, prev_timestamp_, - now, 0.0, 0.0, - GESTURES_FLING_TAP_DOWN)); + auto fling_tap_down = Gesture(kGestureFling, prev_timestamp_, + now, 0.0, 0.0, + GESTURES_FLING_TAP_DOWN); + LogGestureProduce(name, fling_tap_down); + ProduceGesture(fling_tap_down); + fling_stop_already_sent_ = true; next_timeout = next_timer_deadline_ == NO_DEADLINE || next_timer_deadline_ <= now @@ -144,6 +163,7 @@ void FlingStopFilterInterpreter::HandleTimerImpl(stime_t now, } *timeout = SetNextDeadlineAndReturnTimeoutVal(now, fling_stop_deadline_, next_timeout); + LogHandleTimerPost(name, now, timeout); } } // namespace gestures diff --git a/src/fling_stop_filter_interpreter_unittest.cc b/src/fling_stop_filter_interpreter_unittest.cc index 6410d2f..8637cf9 100644 --- a/src/fling_stop_filter_interpreter_unittest.cc +++ b/src/fling_stop_filter_interpreter_unittest.cc @@ -142,4 +142,48 @@ TEST(FlingStopFilterInterpreterTest, SimpleTest) { } } +TEST(FlingStopFilterInterpreterTest, FlingGestureTest) { + FlingStopFilterInterpreterTestInterpreter* base_interpreter = + new FlingStopFilterInterpreterTestInterpreter; + FlingStopFilterInterpreter interpreter(nullptr, base_interpreter, nullptr, + GESTURES_DEVCLASS_TOUCHPAD); + + Gesture fling(kGestureFling, 0.0, 1.0, 0.0, 0.0, GESTURES_FLING_TAP_DOWN); + Gesture swipelift(kGestureSwipeLift, 1.0, 2.0); + Gesture swipe4flift(kGestureFourFingerSwipeLift, 1.0, 2.0); + Gesture move(kGestureMove, 1.0, 2.0, 3.0, 4.0); + + interpreter.fling_stop_already_sent_ = true; + interpreter.ConsumeGesture(fling); + interpreter.ConsumeGesture(fling); + EXPECT_EQ(interpreter.prev_gesture_type_, kGestureTypeFling); + interpreter.ConsumeGesture(swipelift); + EXPECT_EQ(interpreter.prev_gesture_type_, kGestureTypeSwipeLift); + interpreter.ConsumeGesture(swipe4flift); + EXPECT_EQ(interpreter.prev_gesture_type_, kGestureTypeFourFingerSwipeLift); + + interpreter.fling_stop_already_sent_ = false; + interpreter.ConsumeGesture(fling); + interpreter.ConsumeGesture(fling); + EXPECT_EQ(interpreter.prev_gesture_type_, kGestureTypeFling); + interpreter.ConsumeGesture(swipelift); + EXPECT_EQ(interpreter.prev_gesture_type_, kGestureTypeSwipeLift); + interpreter.ConsumeGesture(swipe4flift); + EXPECT_EQ(interpreter.prev_gesture_type_, kGestureTypeFourFingerSwipeLift); + + interpreter.ConsumeGesture(move); + EXPECT_EQ(interpreter.prev_gesture_type_, kGestureTypeMove); +} + +TEST(FlingStopFilterInterpreterTest, FlingStopMultimouseMoveTest) { + FlingStopFilterInterpreterTestInterpreter* base_interpreter = + new FlingStopFilterInterpreterTestInterpreter; + FlingStopFilterInterpreter interpreter(nullptr, base_interpreter, nullptr, + GESTURES_DEVCLASS_MULTITOUCH_MOUSE); + + Gesture move(kGestureMove, 1.0, 2.0, 3.0, 4.0); + interpreter.ConsumeGesture(move); + EXPECT_EQ(interpreter.prev_gesture_type_, kGestureTypeMove); +} + } // namespace gestures diff --git a/src/gestures.cc b/src/gestures.cc index f50211c..b4d5271 100644 --- a/src/gestures.cc +++ b/src/gestures.cc @@ -203,7 +203,11 @@ void HardwareState::DeepCopy(const HardwareState& that, buttons_down = that.buttons_down; touch_cnt = that.touch_cnt; finger_cnt = min(that.finger_cnt, max_finger_cnt); - memcpy(fingers, that.fingers, finger_cnt * sizeof(FingerState)); + if(that.fingers != nullptr) { + memcpy(fingers, that.fingers, finger_cnt * sizeof(FingerState)); + } else if (finger_cnt > 0) { + Err("HardwareState with no finger data but %d finger count", finger_cnt); + } rel_x = that.rel_x; rel_y = that.rel_y; rel_wheel = that.rel_wheel; @@ -531,8 +535,9 @@ void GestureInterpreter::set_callback(GestureReadyFunction callback, void GestureInterpreter::InitializeTouchpad(void) { if (prop_reg_.get()) { - IntProperty stack_version(prop_reg_.get(), "Touchpad Stack Version", 2); - if (stack_version.val_ == 2) { + stack_version_ = std::make_unique<IntProperty>(prop_reg_.get(), + "Touchpad Stack Version", 2); + if (stack_version_->val_ == 2) { InitializeTouchpad2(); return; } diff --git a/src/gestures_unittest.cc b/src/gestures_unittest.cc index 6a22b2f..6b00902 100644 --- a/src/gestures_unittest.cc +++ b/src/gestures_unittest.cc @@ -342,15 +342,12 @@ TEST(GesturesTest, SimpleTest) { gs_ptr->Initialize(GESTURES_DEVCLASS_POINTING_STICK); DeleteGestureInterpreter(gs_ptr); -#ifndef __ANDROID__ - // TODO(b/311110623): re-enable this section once we've tracked down the hwasan crash gs_ptr = NewGestureInterpreter(); EXPECT_NE(nullptr, gs_ptr); gs_ptr->Initialize(GESTURES_DEVCLASS_MULTITOUCH_MOUSE); std::string activity = gs_ptr->EncodeActivityLog(); EXPECT_NE(activity.size(), 0); DeleteGestureInterpreter(gs_ptr); -#endif EXPECT_EQ("1073741824", FingerState::FlagsString(1 << 30)); } @@ -435,16 +432,17 @@ TEST(GesturesTest, HardwareStateGetFingerStateTest) { TEST(GesturesTest, HardwarePropertiesToStringTest) { HardwareProperties hp = { - 1009.5, 1002.4, 1003.9, 1004.5, // left, top, right, bottom - 1005.4, 1006.9, // res_x, res_y - 1007.4, 1008.5, // x, y screen dpi - -1, // orientation minimum - 2, // orientation maximum - 12, // max fingers - 11, // max touches - 0, 1, 1, // t5r2, semi-mt, is_button_pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // is_haptic_pad + .left = 1009.5, .top = 1002.4, .right = 1003.9, .bottom = 1004.5, + .res_x = 1005.4, .res_y = 1006.9, + .screen_x_dpi = 1007.4, + .screen_y_dpi = 1008.5, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 12, + .max_touch_cnt = 11, + .supports_t5r2 = 0, .support_semi_mt = 1, .is_button_pad = 1, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; string str = hp.String(); fprintf(stderr, "str: %s\n", str.c_str()); @@ -529,4 +527,48 @@ TEST(GesturesTest, HardwareStateToStringTest) { return; } +TEST(GesturesTest, HardwareStateDeepCopyWithFingersTest) { + FingerState fingerStates[] = { + { 1.0, 2.0, 3.0, 4.5, 30.0, 11.0, 20.0, 30.0, 14, 0 }, + { 1.5, 2.5, 3.5, 5.0, 30.5, 11.5, 20.5, 30.5, 15, 0 } + }; + const HardwareState hardwareState = make_hwstate(1.123, 1, 2, 2, fingerStates); + + HardwareState hardwareStateCopy; + hardwareStateCopy.fingers = new FingerState[hardwareState.finger_cnt]; + hardwareStateCopy.DeepCopy(hardwareState, hardwareState.finger_cnt); + + EXPECT_EQ(hardwareStateCopy.String(), hardwareState.String()); + delete[] hardwareStateCopy.fingers; +} + +TEST(GesturesTest, HardwareStateDeepCopyWithoutFingersTest) { + const HardwareState hardwareState = make_hwstate(1.123, 1, 0, 2, nullptr); + + HardwareState hardwareStateCopy; + hardwareStateCopy.DeepCopy(hardwareState, hardwareState.finger_cnt); + + EXPECT_EQ(hardwareStateCopy.String(), hardwareState.String()); +} + +TEST(GesturesTest, InvalidHardwareStateDeepCopyTest) { + // 2 finger_cnt without any fingersState(s) specified + const HardwareState invalidHardwareState = make_hwstate(1.123, 1, 2, 2, nullptr); + + HardwareState hardwareStateCopy; + hardwareStateCopy.DeepCopy(invalidHardwareState, invalidHardwareState.finger_cnt); + + EXPECT_EQ(invalidHardwareState.timestamp, hardwareStateCopy.timestamp); + EXPECT_EQ(invalidHardwareState.buttons_down, hardwareStateCopy.buttons_down); + EXPECT_EQ(invalidHardwareState.finger_cnt, hardwareStateCopy.finger_cnt); + EXPECT_EQ(invalidHardwareState.touch_cnt, hardwareStateCopy.touch_cnt); + EXPECT_EQ(invalidHardwareState.fingers, hardwareStateCopy.fingers); + EXPECT_EQ(invalidHardwareState.rel_x, hardwareStateCopy.rel_x); + EXPECT_EQ(invalidHardwareState.rel_y, hardwareStateCopy.rel_y); + EXPECT_EQ(invalidHardwareState.rel_wheel, hardwareStateCopy.rel_wheel); + EXPECT_EQ(invalidHardwareState.rel_wheel_hi_res, hardwareStateCopy.rel_wheel_hi_res); + EXPECT_EQ(invalidHardwareState.rel_hwheel, hardwareStateCopy.rel_wheel); + EXPECT_EQ(invalidHardwareState.msc_timestamp, hardwareStateCopy.msc_timestamp); +} + } // namespace gestures diff --git a/src/haptic_button_generator_filter_interpreter.cc b/src/haptic_button_generator_filter_interpreter.cc index 5cdad9f..93f9aa6 100644 --- a/src/haptic_button_generator_filter_interpreter.cc +++ b/src/haptic_button_generator_filter_interpreter.cc @@ -57,8 +57,14 @@ void HapticButtonGeneratorFilterInterpreter::Initialize( void HapticButtonGeneratorFilterInterpreter::SyncInterpretImpl( HardwareState& hwstate, stime_t* timeout) { + const char name[] = + "HapticButtonGeneratorFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + HandleHardwareState(hwstate); stime_t next_timeout = NO_DEADLINE; + + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, &next_timeout); UpdatePalmState(hwstate); *timeout = SetNextDeadlineAndReturnTimeoutVal( @@ -162,6 +168,9 @@ void HapticButtonGeneratorFilterInterpreter::UpdatePalmState( void HapticButtonGeneratorFilterInterpreter::HandleTimerImpl( stime_t now, stime_t *timeout) { + const char name[] = "HapticButtonGeneratorFilterInterpreter::HandleTimerImpl"; + LogHandleTimerPre(name, now, timeout); + stime_t next_timeout; if (ShouldCallNextTimer(active_gesture_deadline_)) { next_timeout = NO_DEADLINE; @@ -185,11 +194,16 @@ void HapticButtonGeneratorFilterInterpreter::HandleTimerImpl( *timeout = SetNextDeadlineAndReturnTimeoutVal(now, active_gesture_deadline_, next_timeout); + LogHandleTimerPost(name, now, timeout); } void HapticButtonGeneratorFilterInterpreter::ConsumeGesture( const Gesture& gesture) { + const char name[] = "HapticButtonGeneratorFilterInterpreter::ConsumeGesture"; + LogGestureConsume(name, gesture); + if (!enabled_.val_ || !is_haptic_pad_) { + LogGestureProduce(name, gesture); ProduceGesture(gesture); return; } @@ -237,6 +251,7 @@ void HapticButtonGeneratorFilterInterpreter::ConsumeGesture( release_suppress_factor_ = fmax(release_suppress_factor_, 0.1); } + LogGestureProduce(name, gesture); ProduceGesture(gesture); } diff --git a/src/haptic_button_generator_filter_interpreter_unittest.cc b/src/haptic_button_generator_filter_interpreter_unittest.cc index 97d3219..8fef528 100644 --- a/src/haptic_button_generator_filter_interpreter_unittest.cc +++ b/src/haptic_button_generator_filter_interpreter_unittest.cc @@ -46,16 +46,17 @@ TEST(HapticButtonGeneratorFilterInterpreterTest, SimpleTest) { HapticButtonGeneratorFilterInterpreter interpreter( nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 10, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 1, // haptic pad + .right = 100, .bottom = 100, + .res_x = 10, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 1, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -134,16 +135,17 @@ TEST(HapticButtonGeneratorFilterInterpreterTest, NotHapticTest) { HapticButtonGeneratorFilterInterpreter interpreter( nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 10, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 10, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -183,6 +185,60 @@ TEST(HapticButtonGeneratorFilterInterpreterTest, NotHapticTest) { } } +TEST(HapticButtonGeneratorFilterInterpreterTest, NotHapticConsumeGestureTest) { + HapticButtonGeneratorFilterInterpreter interpreter( + nullptr, nullptr, nullptr); + interpreter.is_haptic_pad_ = false; + interpreter.active_gesture_deadline_ = 0.0; + interpreter.release_suppress_factor_ = 0.0; + + const Gesture kFling(kGestureFling, 0, 0, 20, 0, GESTURES_FLING_START); + const Gesture kMove(kGestureMove, 2, 3, 4.0, 5.0); + const Gesture kScroll(kGestureScroll, 0, 0, 20, 0); + + // Verify no state change happens when a Fling is sent to haptics + // when this is not a haptics device + interpreter.active_gesture_ = false; + interpreter.ConsumeGesture(kFling); + EXPECT_FALSE(interpreter.active_gesture_); + EXPECT_EQ(interpreter.active_gesture_deadline_, 0.0); + EXPECT_EQ(interpreter.release_suppress_factor_, 0.0); + + interpreter.active_gesture_ = true; + interpreter.ConsumeGesture(kFling); + EXPECT_TRUE(interpreter.active_gesture_); + EXPECT_EQ(interpreter.active_gesture_deadline_, 0.0); + EXPECT_EQ(interpreter.release_suppress_factor_, 0.0); + + // Verify no state change happens when a MOVE is sent to haptics + // when this is not a haptics device + interpreter.active_gesture_ = false; + interpreter.ConsumeGesture(kMove); + EXPECT_FALSE(interpreter.active_gesture_); + EXPECT_EQ(interpreter.active_gesture_deadline_, 0.0); + EXPECT_EQ(interpreter.release_suppress_factor_, 0.0); + + interpreter.active_gesture_ = true; + interpreter.ConsumeGesture(kMove); + EXPECT_TRUE(interpreter.active_gesture_); + EXPECT_EQ(interpreter.active_gesture_deadline_, 0.0); + EXPECT_EQ(interpreter.release_suppress_factor_, 0.0); + + // Verify no state change happens when a Scroll is sent to haptics + // when this is not a haptics device + interpreter.active_gesture_ = false; + interpreter.ConsumeGesture(kScroll); + EXPECT_FALSE(interpreter.active_gesture_); + EXPECT_EQ(interpreter.active_gesture_deadline_, 0.0); + EXPECT_EQ(interpreter.release_suppress_factor_, 0.0); + + interpreter.active_gesture_ = true; + interpreter.ConsumeGesture(kScroll); + EXPECT_TRUE(interpreter.active_gesture_); + EXPECT_EQ(interpreter.active_gesture_deadline_, 0.0); + EXPECT_EQ(interpreter.release_suppress_factor_, 0.0); +} + TEST(HapticButtonGeneratorFilterInterpreterTest, GesturePreventsButtonDownTest) { HapticButtonGeneratorFilterInterpreterTestInterpreter* base_interpreter = @@ -190,16 +246,17 @@ TEST(HapticButtonGeneratorFilterInterpreterTest, HapticButtonGeneratorFilterInterpreter interpreter( nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 10, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 1, // haptic pad + .right = 100, .bottom = 100, + .res_x = 10, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 1, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -266,16 +323,17 @@ TEST(HapticButtonGeneratorFilterInterpreterTest, DynamicThresholdTest) { HapticButtonGeneratorFilterInterpreter interpreter( nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 10, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 1, // haptic pad + .right = 100, .bottom = 100, + .res_x = 10, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 1, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -346,16 +404,17 @@ TEST(HapticButtonGeneratorFilterInterpreterTest, PalmTest) { HapticButtonGeneratorFilterInterpreter interpreter( nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 10, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 1, // haptic pad + .right = 100, .bottom = 100, + .res_x = 10, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 1, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); diff --git a/src/iir_filter_interpreter.cc b/src/iir_filter_interpreter.cc index 2387650..5ea513d 100644 --- a/src/iir_filter_interpreter.cc +++ b/src/iir_filter_interpreter.cc @@ -53,6 +53,9 @@ IirFilterInterpreter::IirFilterInterpreter(PropRegistry* prop_reg, void IirFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { + const char name[] = "IirFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + // Delete old entries from map short dead_ids[histories_.size() + 1]; size_t dead_ids_len = 0; @@ -152,6 +155,7 @@ void IirFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, fs = *hist->NextOut(); hist->Increment(); } + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } diff --git a/src/iir_filter_interpreter_unittest.cc b/src/iir_filter_interpreter_unittest.cc index c7a3b81..d1c8b8c 100644 --- a/src/iir_filter_interpreter_unittest.cc +++ b/src/iir_filter_interpreter_unittest.cc @@ -109,13 +109,15 @@ TEST(IirFilterInterpreterTest, SemiMTIIRTest) { IirFilterInterpreter interpreter(nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0, 0, 100, 60, // left, top, right, bottom - 1.0, 1.0, 25.4, 25.4, // x res, y res, x DPI, y DPI - -1, // orientation minimum - 2, // orientation maximum - 2, 3, 0, 0, 0, // max_fingers, max_touch, t5r2, semi_mt, is_button_pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // is_haptic_pad + .right = 100, .bottom = 60, + .res_x = 1.0, .res_y = 1.0, + .screen_x_dpi = 0, .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 3, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); diff --git a/src/immediate_interpreter.cc b/src/immediate_interpreter.cc index 5f134b8..c1aa568 100644 --- a/src/immediate_interpreter.cc +++ b/src/immediate_interpreter.cc @@ -342,7 +342,7 @@ void HardwareStateBuffer::Reset(size_t max_finger_cnt) { void HardwareStateBuffer::PushState(const HardwareState& state) { newest_index_ = (newest_index_ + size_ - 1) % size_; - Get(0)->DeepCopy(state, max_finger_cnt_); + Get(0).DeepCopy(state, max_finger_cnt_); } void HardwareStateBuffer::PopState() { @@ -385,12 +385,12 @@ bool ScrollManager::StationaryFingerPressureChangingSignificantly( bool pressure_is_increasing = false; bool pressure_direction_established = false; const FingerState* prev = ¤t; - stime_t now = state_buffer.Get(0)->timestamp; + stime_t now = state_buffer.Get(0).timestamp; stime_t duration = 0.0; if (max_pressure_change_duration_.val_ > 0.0) { for (size_t i = 1; i < state_buffer.Size(); i++) { - const HardwareState& state = *state_buffer.Get(i); + const HardwareState& state = state_buffer.Get(i); stime_t local_duration = now - state.timestamp; if (local_duration > max_pressure_change_duration_.val_) break; @@ -419,8 +419,8 @@ bool ScrollManager::StationaryFingerPressureChangingSignificantly( // To disable this feature, max_pressure_change_duration_ can be set to a // negative number. When this occurs it reverts to just checking the last // event, not looking through the backlog as well. - prev = state_buffer.Get(1)->GetFingerState(current.tracking_id); - duration = now - state_buffer.Get(1)->timestamp; + prev = state_buffer.Get(1).GetFingerState(current.tracking_id); + duration = now - state_buffer.Get(1).timestamp; } if (max_stationary_speed_.val_ != 0.0) { @@ -459,12 +459,12 @@ bool ScrollManager::FillResultScroll( bool pressure_changing = false; for (FingerMap::const_iterator it = gs_fingers.begin(), e = gs_fingers.end(); it != e; ++it) { - const FingerState* fs = state_buffer.Get(0)->GetFingerState(*it); - const FingerState* prev = state_buffer.Get(1)->GetFingerState(*it); + const FingerState* fs = state_buffer.Get(0).GetFingerState(*it); + const FingerState* prev = state_buffer.Get(1).GetFingerState(*it); if (!prev) return false; const stime_t dt = - state_buffer.Get(0)->timestamp - state_buffer.Get(1)->timestamp; + state_buffer.Get(0).timestamp - state_buffer.Get(1).timestamp; pressure_changing = pressure_changing || StationaryFingerPressureChangingSignificantly(state_buffer, *fs); @@ -523,8 +523,8 @@ bool ScrollManager::FillResultScroll( if (max_mag_sq > 0) { did_generate_scroll_ = true; *result = Gesture(kGestureScroll, - state_buffer.Get(1)->timestamp, - state_buffer.Get(0)->timestamp, + state_buffer.Get(1).timestamp, + state_buffer.Get(0).timestamp, dx, dy); } if (prev_gesture_type != kGestureTypeScroll || prev_gs_fingers != gs_fingers) @@ -533,7 +533,7 @@ bool ScrollManager::FillResultScroll( !FloatEq(dx, 0.0) || !FloatEq(dy, 0.0)) scroll_buffer->Insert( dx, dy, - state_buffer.Get(0)->timestamp - state_buffer.Get(1)->timestamp); + state_buffer.Get(0).timestamp - state_buffer.Get(1).timestamp); return true; } @@ -703,8 +703,8 @@ done: float vx = out.dt ? (out.dx / out.dt) : 0.0; float vy = out.dt ? (out.dy / out.dt) : 0.0; *result = Gesture(kGestureFling, - state_buffer.Get(1)->timestamp, - state_buffer.Get(0)->timestamp, + state_buffer.Get(1).timestamp, + state_buffer.Get(0).timestamp, vx, vy, GESTURES_FLING_START); @@ -1000,6 +1000,7 @@ ImmediateInterpreter::ImmediateInterpreter(PropRegistry* prop_reg, last_movement_timestamp_(-1.0), swipe_is_vertical_(false), current_gesture_type_(kGestureTypeNull), + prev_gesture_type_(kGestureTypeNull), state_buffer_(8), scroll_buffer_(20), pinch_guess_start_(-1.0), @@ -1146,7 +1147,10 @@ ImmediateInterpreter::ImmediateInterpreter(PropRegistry* prop_reg, void ImmediateInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { - if (!state_buffer_.Get(0)->fingers) { + const char name[] = "ImmediateInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + + if (!state_buffer_.Get(0).fingers) { Err("Must call SetHardwareProperties() before Push()."); return; } @@ -1155,8 +1159,8 @@ void ImmediateInterpreter::SyncInterpretImpl(HardwareState& hwstate, FillOriginInfo(hwstate); result_.type = kGestureTypeNull; - const bool same_fingers = state_buffer_.Get(1)->SameFingersAs(hwstate) && - (hwstate.buttons_down == state_buffer_.Get(1)->buttons_down); + const bool same_fingers = state_buffer_.Get(1).SameFingersAs(hwstate) && + (hwstate.buttons_down == state_buffer_.Get(1).buttons_down); if (!same_fingers) { // Fingers changed, do nothing this time FingerMap new_gs_fingers; @@ -1174,13 +1178,13 @@ void ImmediateInterpreter::SyncInterpretImpl(HardwareState& hwstate, moving_finger_id_ = -1; } - if (hwstate.finger_cnt < state_buffer_.Get(1)->finger_cnt && + if (hwstate.finger_cnt < state_buffer_.Get(1).finger_cnt && AnyGesturingFingerLeft(hwstate, prev_active_gs_fingers_)) { finger_leave_time_ = hwstate.timestamp; } // Check if clock changed backwards - if (hwstate.timestamp < state_buffer_.Get(1)->timestamp) + if (hwstate.timestamp < state_buffer_.Get(1).timestamp) ResetTime(); UpdatePointingFingers(hwstate); @@ -1225,11 +1229,16 @@ void ImmediateInterpreter::SyncInterpretImpl(HardwareState& hwstate, active_gs_fingers.begin(), active_gs_fingers.end(), std::inserter(non_gs_fingers_, non_gs_fingers_.begin())); + LogGestureProduce(name, result_); ProduceGesture(result_); } + LogHardwareStatePost(name, hwstate); } void ImmediateInterpreter::HandleTimerImpl(stime_t now, stime_t* timeout) { + const char name[] = "ImmediateInterpreter::HandleTimerImpl"; + LogHandleTimerPre(name, now, timeout); + result_.type = kGestureTypeNull; // Tap-to-click always aborts when real button(s) are being used, so we // don't need to worry about conflicts with these two types of callback. @@ -1239,28 +1248,29 @@ void ImmediateInterpreter::HandleTimerImpl(stime_t now, stime_t* timeout) { false, now, timeout); - if (result_.type != kGestureTypeNull) + if (result_.type != kGestureTypeNull) { + LogGestureProduce(name, result_); ProduceGesture(result_); + } + LogHandleTimerPost(name, now, timeout); } void ImmediateInterpreter::FillOriginInfo( const HardwareState& hwstate) { - RemoveMissingIdsFromMap(&origin_timestamps_, hwstate); RemoveMissingIdsFromMap(&distance_walked_, hwstate); for (size_t i = 0; i < hwstate.finger_cnt; i++) { const FingerState& fs = hwstate.fingers[i]; - if (MapContainsKey(origin_timestamps_, fs.tracking_id) && + if (distance_walked_.find(fs.tracking_id) != distance_walked_.end() && state_buffer_.Size() > 1 && - state_buffer_.Get(1)->GetFingerState(fs.tracking_id)) { + state_buffer_.Get(1).GetFingerState(fs.tracking_id)) { float delta_x = hwstate.GetFingerState(fs.tracking_id)->position_x - - state_buffer_.Get(1)->GetFingerState(fs.tracking_id)->position_x; + state_buffer_.Get(1).GetFingerState(fs.tracking_id)->position_x; float delta_y = hwstate.GetFingerState(fs.tracking_id)->position_y - - state_buffer_.Get(1)->GetFingerState(fs.tracking_id)->position_y; + state_buffer_.Get(1).GetFingerState(fs.tracking_id)->position_y; distance_walked_[fs.tracking_id] += sqrtf(delta_x * delta_x + delta_y * delta_y); continue; } - origin_timestamps_[fs.tracking_id] = hwstate.timestamp; distance_walked_[fs.tracking_id] = 0.0; } } @@ -1338,8 +1348,8 @@ bool ImmediateInterpreter::EarlyZoomPotential(const HardwareState& hwstate) if (finger1 == nullptr || finger2 == nullptr) return false; // Wait for a longer time if fingers arrived together - stime_t t1 = origin_timestamps_.at(id1); - stime_t t2 = origin_timestamps_.at(id2); + stime_t t1 = metrics_->GetFinger(id1)->origin_time(); + stime_t t2 = metrics_->GetFinger(id2)->origin_time(); if (fabs(t1 - t2) < evaluation_timeout_.val_ && hwstate.timestamp - max(t1, t2) < thumb_pinch_evaluation_timeout_.val_ * thumb_pinch_delay_factor_.val_) @@ -1363,10 +1373,10 @@ bool ImmediateInterpreter::EarlyZoomPotential(const HardwareState& hwstate) bool motionless_cycles = false; for (int i = 1; i < min<int>(state_buffer_.Size(), pinch_zoom_min_events_.val_); i++) { - const FingerState* curr1 = state_buffer_.Get(i - 1)->GetFingerState(id1); - const FingerState* curr2 = state_buffer_.Get(i - 1)->GetFingerState(id2); - const FingerState* prev1 = state_buffer_.Get(i)->GetFingerState(id1); - const FingerState* prev2 = state_buffer_.Get(i)->GetFingerState(id2); + const FingerState* curr1 = state_buffer_.Get(i - 1).GetFingerState(id1); + const FingerState* curr2 = state_buffer_.Get(i - 1).GetFingerState(id2); + const FingerState* prev1 = state_buffer_.Get(i).GetFingerState(id1); + const FingerState* prev2 = state_buffer_.Get(i).GetFingerState(id2); if (!curr1 || !curr2 || !prev1 || !prev2) { motionless_cycles = true; break; @@ -1406,23 +1416,23 @@ bool ImmediateInterpreter::ZoomFingersAreConsistent( int id2 = *(++fingers_.begin()); const FingerState* curr1 = state_buffer.Get(min<int>(state_buffer.Size() - 1, - pinch_zoom_min_events_.val_))->GetFingerState(id1); + pinch_zoom_min_events_.val_)).GetFingerState(id1); const FingerState* curr2 = state_buffer.Get(min<int>(state_buffer.Size() - 1, - pinch_zoom_min_events_.val_))->GetFingerState(id2); + pinch_zoom_min_events_.val_)).GetFingerState(id2); if (!curr1 || !curr2) return false; for (int i = 0; i < min<int>(state_buffer.Size(), pinch_zoom_min_events_.val_); i++) { - const FingerState* prev1 = state_buffer.Get(i)->GetFingerState(id1); - const FingerState* prev2 = state_buffer.Get(i)->GetFingerState(id2); + const FingerState* prev1 = state_buffer.Get(i).GetFingerState(id1); + const FingerState* prev2 = state_buffer.Get(i).GetFingerState(id2); if (!prev1 || !prev2) return false; float dot = FingersAngle(prev1, prev2, curr1, curr2); if (dot >= 0) return false; } - const FingerState* last1 = state_buffer.Get(0)->GetFingerState(id1); - const FingerState* last2 = state_buffer.Get(0)->GetFingerState(id2); + const FingerState* last1 = state_buffer.Get(0).GetFingerState(id1); + const FingerState* last2 = state_buffer.Get(0).GetFingerState(id2); float angle = FingersAngle(last1, last2, curr1, curr2); if (angle > pinch_zoom_max_angle_.val_) return false; @@ -1438,19 +1448,19 @@ bool ImmediateInterpreter::InwardPinch( const FingerState* curr = state_buffer.Get(min<int>(state_buffer.Size(), - pinch_zoom_min_events_.val_))->GetFingerState(id); + pinch_zoom_min_events_.val_)).GetFingerState(id); if (!curr) return false; for (int i = 0; i < min<int>(state_buffer.Size(), pinch_zoom_min_events_.val_); i++) { - const FingerState* prev = state_buffer.Get(i)->GetFingerState(id); + const FingerState* prev = state_buffer.Get(i).GetFingerState(id); if (!prev) return false; float dot = (curr->position_y - prev->position_y); if (dot <= 0) return false; } - const FingerState* last = state_buffer.Get(0)->GetFingerState(id); + const FingerState* last = state_buffer.Get(0).GetFingerState(id); float dot_last = (curr->position_y - last->position_y); float size_last = sqrt((curr->position_x - last->position_x) * (curr->position_x - last->position_x) + @@ -1490,15 +1500,15 @@ float ImmediateInterpreter::FingersAngle(const FingerState* prev1, bool ImmediateInterpreter::ScrollAngle(const FingerState& finger1, const FingerState& finger2) { const FingerState* curr1 = state_buffer_.Get( - min<int>(state_buffer_.Size() - 1, 3))-> - GetFingerState(finger1.tracking_id); + min<int>(state_buffer_.Size() - 1, 3)) + .GetFingerState(finger1.tracking_id); const FingerState* curr2 = state_buffer_.Get( - min<int>(state_buffer_.Size() - 1, 3))-> - GetFingerState(finger2.tracking_id); + min<int>(state_buffer_.Size() - 1, 3)) + .GetFingerState(finger2.tracking_id); const FingerState* last1 = - state_buffer_.Get(0)->GetFingerState(finger1.tracking_id); + state_buffer_.Get(0).GetFingerState(finger1.tracking_id); const FingerState* last2 = - state_buffer_.Get(0)->GetFingerState(finger2.tracking_id); + state_buffer_.Get(0).GetFingerState(finger2.tracking_id); if (last1 && last2 && curr1 && curr2) { if (FingersAngle(last1, last2, curr1, curr2) < scroll_min_angle_.val_) return false; @@ -1561,7 +1571,7 @@ void ImmediateInterpreter::UpdateThumbState(const HardwareState& hwstate) { (min_fs->flags & GESTURES_FINGER_WARP_Y_MOVE)); float min_dist_sq = DistanceTravelledSq(*min_fs, false, true); float min_dt = hwstate.timestamp - - origin_timestamps_[min_fs->tracking_id]; + metrics_->GetFinger(min_fs->tracking_id)->origin_time(); float thumb_dist_sq_thresh = min_dist_sq * thumb_movement_factor_.val_ * thumb_movement_factor_.val_; float thumb_speed_sq_thresh = min_dist_sq * @@ -1572,10 +1582,12 @@ void ImmediateInterpreter::UpdateThumbState(const HardwareState& hwstate) { if (pinch_enable_.val_ && hwstate.finger_cnt == 2) { float dt1 = hwstate.timestamp - - origin_timestamps_[hwstate.fingers[0].tracking_id]; + metrics_->GetFinger(hwstate.fingers[0].tracking_id) + ->origin_time(); float dist_sq1 = DistanceTravelledSq(hwstate.fingers[0], true, true); float dt2 = hwstate.timestamp - - origin_timestamps_[hwstate.fingers[1].tracking_id]; + metrics_->GetFinger(hwstate.fingers[1].tracking_id) + ->origin_time(); float dist_sq2 = DistanceTravelledSq(hwstate.fingers[1], true, true); if (dist_sq1 * dt1 && dist_sq2 * dt2) similar_movement = max((dist_sq1 * dt1 * dt1) / (dist_sq2 * dt2 * dt2), @@ -1593,7 +1605,8 @@ void ImmediateInterpreter::UpdateThumbState(const HardwareState& hwstate) { thumb_dist_sq_thresh *= thumb_pinch_threshold_ratio_.val_; } float dist_sq = DistanceTravelledSq(fs, false, true); - float dt = hwstate.timestamp - origin_timestamps_[fs.tracking_id]; + float dt = hwstate.timestamp - + metrics_->GetFinger(fs.tracking_id)->origin_time(); bool closer_to_origin = dist_sq <= thumb_dist_sq_thresh; bool slower_moved = (dist_sq * min_dt && dist_sq * min_dt * min_dt < @@ -1635,13 +1648,15 @@ void ImmediateInterpreter::UpdateThumbState(const HardwareState& hwstate) { dist_sq * min_dt * min_dt / (thumb_speed_sq_thresh * dt * dt) > thumb_pinch_min_movement_.val_ && similar_movement; - bool might_be_pinch = (slow_pinch_guess && - hwstate.timestamp - - origin_timestamps_[fs.tracking_id] < 2 * - thumb_pinch_evaluation_timeout_.val_ && - ZoomFingersAreConsistent(state_buffer_)); + stime_t origin_time = + metrics_->GetFinger(fs.tracking_id) ->origin_time(); + bool might_be_pinch = + slow_pinch_guess && + hwstate.timestamp - origin_time < 2 * + thumb_pinch_evaluation_timeout_.val_ && + ZoomFingersAreConsistent(state_buffer_); if (relatively_motionless || - hwstate.timestamp - origin_timestamps_[fs.tracking_id] > + hwstate.timestamp - origin_time > thumb_pinch_evaluation_timeout_.val_) { if (!might_be_pinch) continue; @@ -1655,11 +1670,11 @@ void ImmediateInterpreter::UpdateThumbState(const HardwareState& hwstate) { // Decrease the timer as the finger is thumb-like in the previous // frame. const FingerState* prev = - state_buffer_.Get(1)->GetFingerState(fs.tracking_id); + state_buffer_.Get(1).GetFingerState(fs.tracking_id); if (!prev) continue; thumb_eval_timer_[fs.tracking_id] -= - hwstate.timestamp - state_buffer_.Get(1)->timestamp; + hwstate.timestamp - state_buffer_.Get(1).timestamp; } else { // The finger wasn't thumb-like in the frame. Remove it from the thumb // list. @@ -1714,6 +1729,10 @@ FingerMap ImmediateInterpreter::GetGesturingFingers( if (pointing_.size() <= kMaxGesturingFingers) return pointing_; + if (hwstate.finger_cnt <= 0) { + return {}; + } + const FingerState* fs[hwstate.finger_cnt]; for (size_t i = 0; i < hwstate.finger_cnt; ++i) fs[i] = &hwstate.fingers[i]; @@ -1823,8 +1842,10 @@ void ImmediateInterpreter::UpdateCurrentGestureType( // ambiguous. Only move if they've been down long enough. if (new_gs_type == kGestureTypeMove && hwstate.timestamp - - min(origin_timestamps_[fingers[0]->tracking_id], - origin_timestamps_[fingers[1]->tracking_id]) < + min(metrics_->GetFinger(fingers[0]->tracking_id) + ->origin_time(), + metrics_->GetFinger(fingers[1]->tracking_id) + ->origin_time()) < evaluation_timeout_.val_) new_gs_type = kGestureTypeNull; } @@ -2203,7 +2224,7 @@ bool ImmediateInterpreter::IsTooCloseToThumb(const FingerState& finger) const { tapping_finger_min_separation_.val_; for (std::map<short, stime_t>::const_iterator it = thumb_.begin(); it != thumb_.end(); ++it) { - const FingerState* thumb = state_buffer_.Get(0)->GetFingerState(it->first); + const FingerState* thumb = state_buffer_.Get(0).GetFingerState(it->first); float xdist = fabsf(finger.position_x - thumb->position_x); float ydist = fabsf(finger.position_y - thumb->position_y); if (xdist * xdist + ydist * ydist < kMin2fDistThreshSq) @@ -2554,7 +2575,7 @@ void ImmediateInterpreter::UpdateTapGesture( } Log("UpdateTapGesture: Tap Generated"); result_ = Gesture(kGestureButtonsChange, - state_buffer_.Get(1)->timestamp, + state_buffer_.Get(1).timestamp, now, down, up, @@ -2628,7 +2649,7 @@ void ImmediateInterpreter::UpdateTapState( // Gesturing finger wasn't in prev state. It's new. const FingerState* fs = hwstate->GetFingerState(*it); if (FingerTooCloseToTap(*hwstate, *fs) || - FingerTooCloseToTap(*state_buffer_.Get(1), *fs) || + FingerTooCloseToTap(state_buffer_.Get(1), *fs) || SetContainsValue(tap_dead_fingers_, fs->tracking_id)) continue; added_fingers.insert(*it); @@ -2714,7 +2735,7 @@ void ImmediateInterpreter::UpdateTapState( hwstate->timestamp - last_movement_timestamp_ >= motion_tap_prevent_timeout_.val_) { tap_record_.Update( - *hwstate, *state_buffer_.Get(1), added_fingers, removed_fingers, + *hwstate, state_buffer_.Get(1), added_fingers, removed_fingers, dead_fingers); if (tap_record_.TapBegan()) SetTapToClickState(kTtcFirstTapBegan, now); @@ -2730,7 +2751,7 @@ void ImmediateInterpreter::UpdateTapState( break; } tap_record_.Update( - *hwstate, *state_buffer_.Get(1), added_fingers, + *hwstate, state_buffer_.Get(1), added_fingers, removed_fingers, dead_fingers); Log("TTC: Is tap? %d Is moving? %d", tap_record_.TapComplete(), @@ -2755,7 +2776,7 @@ void ImmediateInterpreter::UpdateTapState( tap_record_.Clear(); tap_record_.Update( - *hwstate, *state_buffer_.Get(1), added_fingers, removed_fingers, + *hwstate, state_buffer_.Get(1), added_fingers, removed_fingers, dead_fingers); // If more than one finger is touching: Send click @@ -2780,10 +2801,10 @@ void ImmediateInterpreter::UpdateTapState( break; } if (hwstate) - tap_record_.Update(*hwstate, *state_buffer_.Get(1), added_fingers, + tap_record_.Update(*hwstate, state_buffer_.Get(1), added_fingers, removed_fingers, dead_fingers); - if (!tap_record_.Motionless(*hwstate, *state_buffer_.Get(1), + if (!tap_record_.Motionless(*hwstate, state_buffer_.Get(1), tap_max_movement_.val_)) { tap_drag_last_motion_time_ = now; } @@ -2832,7 +2853,7 @@ void ImmediateInterpreter::UpdateTapState( case kTtcDrag: if (hwstate) tap_record_.Update( - *hwstate, *state_buffer_.Get(1), added_fingers, removed_fingers, + *hwstate, state_buffer_.Get(1), added_fingers, removed_fingers, dead_fingers); if (tap_record_.TapComplete()) { tap_record_.Clear(); @@ -2854,7 +2875,7 @@ void ImmediateInterpreter::UpdateTapState( case kTtcDragRelease: if (!added_fingers.empty()) { tap_record_.Update( - *hwstate, *state_buffer_.Get(1), added_fingers, removed_fingers, + *hwstate, state_buffer_.Get(1), added_fingers, removed_fingers, dead_fingers); SetTapToClickState(kTtcDragRetouch, now); } else if (is_timeout) { @@ -2865,7 +2886,7 @@ void ImmediateInterpreter::UpdateTapState( case kTtcDragRetouch: if (hwstate) tap_record_.Update( - *hwstate, *state_buffer_.Get(1), added_fingers, removed_fingers, + *hwstate, state_buffer_.Get(1), added_fingers, removed_fingers, dead_fingers); if (tap_record_.TapComplete()) { *buttons_up = GESTURES_BUTTON_LEFT; @@ -3034,7 +3055,7 @@ void ImmediateInterpreter::UpdateStartedMovingTime( void ImmediateInterpreter::UpdateButtons(const HardwareState& hwstate, stime_t* timeout) { // TODO(miletus): To distinguish between left/right buttons down - bool prev_button_down = state_buffer_.Get(1)->buttons_down; + bool prev_button_down = state_buffer_.Get(1).buttons_down; bool button_down = hwstate.buttons_down; if (!prev_button_down && !button_down) return; @@ -3066,7 +3087,7 @@ void ImmediateInterpreter::UpdateButtons(const HardwareState& hwstate, button_evaluation_timeout; button_type_ = EvaluateButtonType(hwstate, button_down_time); - if (!hwstate.SameFingersAs(*state_buffer_.Get(0))) { + if (!hwstate.SameFingersAs(state_buffer_.Get(0))) { // Fingers have changed since last state, reset timeout button_down_deadline_ = hwstate.timestamp + button_finger_timeout; } @@ -3082,7 +3103,7 @@ void ImmediateInterpreter::UpdateButtons(const HardwareState& hwstate, if (result_.type == kGestureTypeButtonsChange) Err("Gesture type already button?!"); result_ = Gesture(kGestureButtonsChange, - state_buffer_.Get(1)->timestamp, + state_buffer_.Get(1).timestamp, hwstate.timestamp, button_type_, 0, @@ -3096,7 +3117,7 @@ void ImmediateInterpreter::UpdateButtons(const HardwareState& hwstate, // Send button up if (result_.type != kGestureTypeButtonsChange) result_ = Gesture(kGestureButtonsChange, - state_buffer_.Get(1)->timestamp, + state_buffer_.Get(1).timestamp, hwstate.timestamp, 0, button_type_, @@ -3123,7 +3144,7 @@ void ImmediateInterpreter::UpdateButtonsTimeout(stime_t now) { return; sent_button_down_ = true; result_ = Gesture(kGestureButtonsChange, - state_buffer_.Get(1)->timestamp, + state_buffer_.Get(1).timestamp, now, button_type_, 0, @@ -3144,13 +3165,13 @@ void ImmediateInterpreter::FillResultGesture( if (moving_finger_id_ >= 0) current = hwstate.GetFingerState(moving_finger_id_); - const HardwareState* prev_hs = state_buffer_.Get(1); - if (prev_hs && !current) { + const HardwareState& prev_hs = state_buffer_.Get(1); + if (!current) { float curr_dist_sq = -1; for (FingerMap::const_iterator it = fingers.begin(), e = fingers.end(); it != e; ++it) { const FingerState* fs = hwstate.GetFingerState(*it); - const FingerState* prev_fs = prev_hs->GetFingerState(fs->tracking_id); + const FingerState* prev_fs = prev_hs.GetFingerState(fs->tracking_id); if (!prev_fs) break; float dist_sq = DistSq(*fs, *prev_fs); @@ -3165,14 +3186,14 @@ void ImmediateInterpreter::FillResultGesture( // Find corresponding finger id in previous state const FingerState* prev = - state_buffer_.Get(1)->GetFingerState(current->tracking_id); - const FingerState* prev2 = !state_buffer_.Get(2) ? nullptr : - state_buffer_.Get(2)->GetFingerState(current->tracking_id); + state_buffer_.Get(1).GetFingerState(current->tracking_id); + const FingerState* prev2 = + state_buffer_.Get(2).GetFingerState(current->tracking_id); if (!prev || !current) return; if (current->flags & GESTURES_FINGER_MERGE) return; - stime_t dt = hwstate.timestamp - state_buffer_.Get(1)->timestamp; + stime_t dt = hwstate.timestamp - state_buffer_.Get(1).timestamp; bool suppress_finger_movement = scroll_manager_.SuppressStationaryFingerMovement( *current, *prev, dt) || @@ -3180,7 +3201,7 @@ void ImmediateInterpreter::FillResultGesture( state_buffer_, *current); if (quick_acceleration_factor_.val_ && prev2) { stime_t dt2 = - state_buffer_.Get(1)->timestamp - state_buffer_.Get(2)->timestamp; + state_buffer_.Get(1).timestamp - state_buffer_.Get(2).timestamp; float dist_sq = DistSq(*current, *prev); float dist_sq2 = DistSq(*prev, *prev2); if (dist_sq2 * dt && // have prev dist and current time @@ -3193,7 +3214,7 @@ void ImmediateInterpreter::FillResultGesture( if (suppress_finger_movement) { scroll_manager_.prev_result_suppress_finger_movement_ = true; result_ = Gesture(kGestureMove, - state_buffer_.Get(1)->timestamp, + state_buffer_.Get(1).timestamp, hwstate.timestamp, 0, 0); @@ -3225,7 +3246,7 @@ void ImmediateInterpreter::FillResultGesture( if (dsq_total >= dsq_total_thresh) { zero_move = dsq == 0.0; result_ = Gesture(kGestureMove, - state_buffer_.Get(1)->timestamp, + state_buffer_.Get(1).timestamp, hwstate.timestamp, dx, dy); @@ -3258,7 +3279,7 @@ void ImmediateInterpreter::FillResultGesture( &FingerState::position_y }; for (FingerMap::const_iterator it = fingers.begin(), e = fingers.end(); it != e; ++it) { - if (!state_buffer_.Get(1)->GetFingerState(*it)) { + if (!state_buffer_.Get(1).GetFingerState(*it)) { Err("missing prev state?"); continue; } @@ -3270,7 +3291,7 @@ void ImmediateInterpreter::FillResultGesture( continue; float FingerState::*field = fields[i]; float delta = hwstate.GetFingerState(*it)->*field - - state_buffer_.Get(1)->GetFingerState(*it)->*field; + state_buffer_.Get(1).GetFingerState(*it)->*field; // The multiply is to see if they have the same sign: if (sum_delta[i] == 0.0 || sum_delta[i] * delta > 0) { sum_delta[i] += delta; @@ -3283,7 +3304,7 @@ void ImmediateInterpreter::FillResultGesture( } if (current_gesture_type_ == kGestureTypeSwipe) { result_ = Gesture( - kGestureSwipe, state_buffer_.Get(1)->timestamp, + kGestureSwipe, state_buffer_.Get(1).timestamp, hwstate.timestamp, (!swipe_is_vertical_ && finger_cnt[0]) ? sum_delta[0] / finger_cnt[0] : 0.0, @@ -3291,7 +3312,7 @@ void ImmediateInterpreter::FillResultGesture( sum_delta[1] / finger_cnt[1] : 0.0); } else if (current_gesture_type_ == kGestureTypeFourFingerSwipe) { result_ = Gesture( - kGestureFourFingerSwipe, state_buffer_.Get(1)->timestamp, + kGestureFourFingerSwipe, state_buffer_.Get(1).timestamp, hwstate.timestamp, (!swipe_is_vertical_ && finger_cnt[0]) ? sum_delta[0] / finger_cnt[0] : 0.0, @@ -3302,14 +3323,14 @@ void ImmediateInterpreter::FillResultGesture( } case kGestureTypeSwipeLift: { result_ = Gesture(kGestureSwipeLift, - state_buffer_.Get(1)->timestamp, + state_buffer_.Get(1).timestamp, hwstate.timestamp); break; } case kGestureTypeFourFingerSwipeLift: { result_ = Gesture(kGestureFourFingerSwipeLift, - state_buffer_.Get(1)->timestamp, + state_buffer_.Get(1).timestamp, hwstate.timestamp); break; } diff --git a/src/immediate_interpreter_unittest.cc b/src/immediate_interpreter_unittest.cc index 04c822e..c7c6db2 100644 --- a/src/immediate_interpreter_unittest.cc +++ b/src/immediate_interpreter_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include <stdio.h> +#include <string> #include <vector> #include <gtest/gtest.h> @@ -61,24 +62,22 @@ TEST(ImmediateInterpreterTest, MoveDownTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 1000, // right edge - 1000, // bottom edge - 500, // pixels/TP width - 500, // pixels/TP height - 96, // screen DPI x - 96, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 1000, + .bottom = 1000, + .res_x = 500, + .res_y = 500, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); @@ -125,24 +124,22 @@ TEST(ImmediateInterpreterTest, MoveUpWithRestingThumbTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 1000, // right edge - 1000, // bottom edge - 50, // pixels/TP width - 50, // pixels/TP height - 96, // screen DPI x - 96, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 1000, + .bottom = 1000, + .res_x = 50, + .res_y = 50, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); @@ -191,24 +188,22 @@ TEST(ImmediateInterpreterTest, MoveUpWithRestingThumbTest) { TEST(ImmediateInterpreterTest, SemiMtScrollUpWithRestingThumbTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 1000, // right edge - 1000, // bottom edge - 20, // pixels/TP width - 20, // pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 3, // max touch - 0, // tripletap - 1, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 1000, + .bottom = 1000, + .res_x = 20, + .res_y = 20, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 3, + .supports_t5r2 = 0, + .support_semi_mt = 1, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); @@ -252,24 +247,22 @@ TEST(ImmediateInterpreterTest, SemiMtScrollUpWithRestingThumbTest) { void ScrollUpTest(float pressure_a, float pressure_b) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 1000, // right edge - 1000, // bottom edge - 20, // pixels/TP width - 20, // pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 1000, + .bottom = 1000, + .res_x = 20, + .res_y = 20, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); @@ -326,24 +319,22 @@ TEST(ImmediateInterpreterTest, FatFingerScrollUpTest) { TEST(ImmediateInterpreterTest, ScrollThenFalseTapTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 1000, // right edge - 1000, // bottom edge - 20, // pixels/TP width - 20, // pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 1000, + .bottom = 1000, + .res_x = 20, + .res_y = 20, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); @@ -397,24 +388,22 @@ TEST(ImmediateInterpreterTest, ScrollThenFalseTapTest) { TEST(ImmediateInterpreterTest, FlingTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); @@ -511,24 +500,22 @@ TEST(ImmediateInterpreterTest, FlingTest) { TEST(ImmediateInterpreterTest, DelayedStartScrollTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); @@ -572,24 +559,22 @@ TEST(ImmediateInterpreterTest, DelayedStartScrollTest) { TEST(ImmediateInterpreterTest, ScrollReevaluateTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; FingerState finger_states[] = { @@ -647,24 +632,22 @@ TEST(ImmediateInterpreterTest, ScrollReevaluateTest) { TEST(ImmediateInterpreterTest, OneFingerThenTwoDelayedStartScrollTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; FingerState finger_states[] = { @@ -729,24 +712,22 @@ struct OneFatFingerScrollTestInputs { TEST(ImmediateInterpreterTest, OneFatFingerScrollTest) { std::unique_ptr<ImmediateInterpreter> ii; HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 106.666672, // right edge - 68.000000, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 25.4, // screen DPI x - 25.4, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 15, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - true, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - false, // is haptic pad + .right = 106.666672, + .bottom = 68.000000, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 15, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = true, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = false, }; TestInterpreterWrapper wrapper(ii.get(), &hwprops); // 4 runs that were failing, but now pass: @@ -899,24 +880,22 @@ struct NoLiftoffScrollTestInputs { TEST(ImmediateInterpreterTest, NoLiftoffScrollTest) { std::unique_ptr<ImmediateInterpreter> ii; HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 106.666672, // right edge - 68.000000, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 25.4, // screen DPI x - 25.4, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 15, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - true, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - false, // is haptic pad + .right = 106.666672, + .bottom = 68.000000, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 15, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = true, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = false, }; TestInterpreterWrapper wrapper(ii.get(), &hwprops); @@ -1037,24 +1016,22 @@ struct HardwareStateAnScrollExpectations { TEST(ImmediateInterpreterTest, DiagonalSnapTest) { std::unique_ptr<ImmediateInterpreter> ii; HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(ii.get(), &hwprops); @@ -1151,24 +1128,22 @@ TEST(ImmediateInterpreterTest, DiagonalSnapTest) { TEST(ImmediateInterpreterTest, RestingFingerTest) { std::unique_ptr<ImmediateInterpreter> ii; HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(ii.get(), &hwprops); @@ -1221,24 +1196,22 @@ TEST(ImmediateInterpreterTest, RestingFingerTest) { TEST(ImmediateInterpreterTest, ThumbRetainTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 1, // x screen DPI - 1, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; FingerState finger_states[] = { @@ -1275,24 +1248,22 @@ TEST(ImmediateInterpreterTest, ThumbRetainTest) { TEST(ImmediateInterpreterTest, ThumbRetainReevaluateTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 1, // x screen DPI - 1, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; FingerState finger_states[] = { @@ -1326,24 +1297,22 @@ TEST(ImmediateInterpreterTest, ThumbRetainReevaluateTest) { TEST(ImmediateInterpreterTest, SetHardwarePropertiesTwiceTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 1000, // right edge - 1000, // bottom edge - 500, // pixels/TP width - 500, // pixels/TP height - 96, // screen DPI x - 96, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 1000, + .bottom = 1000, + .res_x = 500, + .res_y = 500, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; hwprops.max_finger_cnt = 3; TestInterpreterWrapper wrapper(&ii, &hwprops); @@ -1368,24 +1337,22 @@ TEST(ImmediateInterpreterTest, SetHardwarePropertiesTwiceTest) { TEST(ImmediateInterpreterTest, AmbiguousPalmCoScrollTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // x pixels/TP width - 1, // y pixels/TP height - 1, // x screen DPI - 1, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 5, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); @@ -1453,24 +1420,22 @@ TEST(ImmediateInterpreterTest, AmbiguousPalmCoScrollTest) { TEST(ImmediateInterpreterTest, PressureChangeMoveTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 1000, // right edge - 1000, // bottom edge - 500, // x pixels/TP width - 500, // y pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 1000, + .bottom = 1000, + .res_x = 500, + .res_y = 500, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); @@ -1516,29 +1481,27 @@ TEST(ImmediateInterpreterTest, PressureChangeMoveTest) { TEST(ImmediateInterpreterTest, GetGesturingFingersTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 1000, // right edge - 1000, // bottom edge - 500, // pixels/TP width - 500, // pixels/TP height - 96, // screen DPI x - 96, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 1000, + .bottom = 1000, + .res_x = 500, + .res_y = 500, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); FingerState finger_states[] = { - // TM, Tm, WM, Wm, Press, Orientation, X, Y, TrID + // TM, Tm, WM, Wm, Press, Orientation, X, Y, TrID, flags {0, 0, 0, 0, 1, 0, 61, 70, 91, 0}, {0, 0, 0, 0, 1, 0, 62, 65, 92, 0}, {0, 0, 0, 0, 1, 0, 62, 69, 93, 0}, @@ -1599,6 +1562,27 @@ TEST(ImmediateInterpreterTest, GetGesturingFingersTest) { EXPECT_TRUE(ids.end() != ids.find(92)); } +TEST(ImmediateInterpreterTest, GetGesturingFingersWithEmptyStateTest) { + ImmediateInterpreter ii(nullptr, nullptr); + HardwareProperties hwprops = {}; + TestInterpreterWrapper wrapper(&ii, &hwprops); + + FingerState finger_states[] = { + // TM, Tm, WM, Wm, Press, Orientation, X, Y, TrID, flags + {0, 0, 0, 0, 1, 0, 61, 70, 91, 0}, + {0, 0, 0, 0, 1, 0, 62, 65, 92, 0}, + {0, 0, 0, 0, 1, 0, 62, 69, 93, 0}, + {0, 0, 0, 0, 1, 0, 62, 61, 94, 0}, + {0, 0, 0, 0, 1, 0, 63, 80, 95, 0}, + }; + HardwareState five_finger_hwstate = + make_hwstate(200000, 0, 5, 5, &finger_states[0]); + HardwareState no_finger_hwstate = make_hwstate(200001, 0, 0, 0, nullptr); + ii.ResetSameFingersState(five_finger_hwstate); + ii.UpdatePointingFingers(five_finger_hwstate); + EXPECT_TRUE(ii.GetGesturingFingers(no_finger_hwstate).empty()); +} + namespace { std::set<short> MkSet() { return std::set<short>(); @@ -1625,6 +1609,8 @@ std::set<short> MkSet(short id1, short id2, short id3) { TEST(ImmediateInterpreterTest, TapRecordTest) { ImmediateInterpreter ii(nullptr, nullptr); + HardwareProperties hwprops = {}; + TestInterpreterWrapper wrapper(&ii, &hwprops); TapRecord tr(&ii); EXPECT_FALSE(tr.TapComplete()); // two finger IDs: @@ -1650,15 +1636,13 @@ TEST(ImmediateInterpreterTest, TapRecordTest) { make_hwstate(0.5, 0, 1, 1, &fs[2]), }; - /* Hack: Tap recorder points to immediate interpreter and assummes it contains - * valid values, so we need to insert some origin timestamps */ - const_cast<ImmediateInterpreter*>(tr.immediate_interpreter_)-> - origin_timestamps_[kF1] = 0; - const_cast<ImmediateInterpreter*>(tr.immediate_interpreter_)-> - origin_timestamps_[kF2] = 0; + // Hack: TapRecord uses ImmediateInterpreter's FingerMetrics for origin + // timestamps, so we need to populate those. + ii.metrics_->Update(hw[0]); tr.Update(hw[0], nullstate, MkSet(kF1), MkSet(), MkSet()); EXPECT_FALSE(tr.Moving(hw[0], kTapMoveDist)); EXPECT_FALSE(tr.TapComplete()); + ii.metrics_->Update(hw[1]); tr.Update(hw[1], hw[0], MkSet(), MkSet(), MkSet()); EXPECT_FALSE(tr.Moving(hw[1], kTapMoveDist)); EXPECT_FALSE(tr.TapComplete()); @@ -1763,13 +1747,18 @@ protected: } if (!hwstate || hwstate->timestamp != 0.0) { - same_fingers = ii_->state_buffer_.Get(1)->SameFingersAs(states[i].hws); + same_fingers = ii_->state_buffer_.Get(1).SameFingersAs(states[i].hws); } if (hwstate) ii_->state_buffer_.PushState(*hwstate); - for (auto finger: states[i].gesturing_fingers) - ii_->origin_timestamps_.emplace(finger, 0); + // TODO(b/307933752): this is unrealistic compared to the actual code that + // tracks origin timestamps, but making it more realistic (by calling + // ii_->metrics_->Update(*hwstate)) causes + // OneFingerTapThenMoveAfterDelayDoesNotDrag to fail. + for (auto finger: states[i].gesturing_fingers) { + ii_->metrics_->SetFingerOriginTimestampForTesting(finger, 0); + } ii_->UpdateTapState( hwstate, states[i].gesturing_fingers, same_fingers, now, &buttons_down, &buttons_up, &timeout); @@ -1853,12 +1842,12 @@ protected: double tap_timeout_ = 0.05; private: const HardwareProperties hwprops_ = { - .left = 0, - .top = 0, .right = 200, .bottom = 200, .res_x = 1.0, // pixels/TP width .res_y = 1.0, // pixels/TP height + .screen_x_dpi = 0, + .screen_y_dpi = 0, .orientation_minimum = -1, .orientation_maximum = 2, .max_finger_cnt = 5, @@ -1984,6 +1973,11 @@ TEST_F(TapToClickStateMachineTest, OneFingerTapAndDrag) { } TEST_F(TapToClickStateMachineTest, OneFingerTapThenMoveAfterDelayDoesNotDrag) { + // TODO(b/307933752): this test fails if more realistic origin timestamps are + // set in TapToClickStateMachineTest::check_hwstates (i.e. calling + // ii_->metrics_->Update instead of setting the origin timestamps of + // gesturing_fingers to 0). Check whether that's a problem with the test or + // the code it's testing. FingerState tap_fs = {0, 0, 0, 0, 50, 0, 4, 4, 91, 0}; FingerState move_fs[] = { {0, 0, 0, 0, 50, 0, 4, 4, 95, 0}, @@ -2691,24 +2685,22 @@ struct TapToClickLowPressureBeginOrEndInputs { TEST(ImmediateInterpreterTest, TapToClickLowPressureBeginOrEndTest) { std::unique_ptr<ImmediateInterpreter> ii; HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 106.666672, // right edge - 68.000000, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 25.4, // screen DPI x - 25.4, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 15, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - true, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - false, // is haptic pad + .right = 106.666672, + .bottom = 68.000000, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 15, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = true, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = false, }; TestInterpreterWrapper wrapper(ii.get(), &hwprops); @@ -2781,24 +2773,22 @@ TEST(ImmediateInterpreterTest, TapToClickKeyboardTest) { std::unique_ptr<ImmediateInterpreter> ii; HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 200, // right edge - 200, // bottom edge - 1.0, // pixels/TP width - 1.0, // pixels/TP height - 1.0, // screen DPI x - 1.0, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 5, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 200, + .bottom = 200, + .res_x = 1.0, + .res_y = 1.0, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(ii.get(), &hwprops); @@ -2836,8 +2826,7 @@ TEST(ImmediateInterpreterTest, TapToClickKeyboardTest) { stime_t timeout = NO_DEADLINE; std::set<short> gs = hwstates[i].finger_cnt == 1 ? MkSet(91) : MkSet(); - for (auto finger: gs) - ii->origin_timestamps_.emplace(finger, 0); + ii->metrics_->Update(hwstates[i]); ii->UpdateTapState( &hwstates[i], gs, @@ -2855,30 +2844,49 @@ TEST(ImmediateInterpreterTest, TapToClickKeyboardTest) { } } -TEST(ImmediateInterpreterTest, TapToClickEnableTest) { - std::unique_ptr<ImmediateInterpreter> ii; +enum class TtcEnableTestMode { + TapEnabled = 0, + TapDisabledDuringGesture, + TapDisabledBeforeGestureWhileIdle, + TapPausedDuringGesture, + TapPausedBeforeGestureWhileIdle, +}; + +class ImmediateInterpreterTtcEnableTest : + public testing::TestWithParam<TtcEnableTestMode> {}; + +TEST_P(ImmediateInterpreterTtcEnableTest, TapToClickEnableTest) { + ImmediateInterpreter ii(nullptr, nullptr); + ii.drag_lock_enable_.val_ = 1; + ii.motion_tap_prevent_timeout_.val_ = 0; + ii.tap_drag_timeout_.val_ = 0.05; + ii.tap_enable_.val_ = 1; + ii.tap_drag_enable_.val_ = 1; + ii.tap_paused_.val_ = 0; + ii.tap_move_dist_.val_ = 1.0; + ii.tap_timeout_.val_ = 0.05; + EXPECT_EQ(kIdl, ii.tap_to_click_state_); + EXPECT_TRUE(ii.tap_enable_.val_); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 200, // right edge - 200, // bottom edge - 1.0, // pixels/TP width - 1.0, // pixels/TP height - 1.0, // screen DPI x - 1.0, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 5, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 200, + .bottom = 200, + .res_x = 1.0, + .res_y = 1.0, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; - TestInterpreterWrapper wrapper(ii.get(), &hwprops); + TestInterpreterWrapper wrapper(&ii, &hwprops); FingerState fs[] = { // TM, Tm, WM, Wm, Press, Orientation, X, Y, TrID @@ -2906,110 +2914,104 @@ TEST(ImmediateInterpreterTest, TapToClickEnableTest) { {make_hwstate(0.99,0,0,0,nullptr),.99,MkSet(),0,kBL,kIdl,false} }; - for (int iter = 0; iter < 5; ++iter) { - for (size_t i = 0; i < arraysize(hwsgs_list); ++i) { - string desc; - stime_t disable_time = 0.0; - stime_t pause_time = 0.0; - switch (iter) { - case 0: // test with tap enabled - desc = StringPrintf("State %zu (tap enabled)", i); - disable_time = -1; // unreachable time - pause_time = -1; - break; - case 1: // test with tap disabled during gesture - desc = StringPrintf("State %zu (tap disabled during gesture)", i); - disable_time = 0.02; - pause_time = -1; - break; - case 2: // test with tap disabled before gesture (while Idle) - desc = StringPrintf("State %zu (tap disabled while Idle)", i); - disable_time = 0.00; - pause_time = -1; - break; - case 3: // test with tap paused during gesture - desc = StringPrintf("State %zu (tap paused during gesture)", i); - disable_time = -1; - pause_time = 0.02; - break; - case 4: // test with tap paused before gesture (while Idle) - desc = StringPrintf("State %zu (tap paused while Idle)", i); - disable_time = 0.00; - pause_time = -1; - break; - } + for (size_t i = 0; i < arraysize(hwsgs_list); ++i) { + string desc; + stime_t disable_time = 0.0; + stime_t pause_time = 0.0; + switch (GetParam()) { + case TtcEnableTestMode::TapEnabled: + desc = "tap enabled"; + disable_time = -1; // unreachable time + pause_time = -1; + break; + case TtcEnableTestMode::TapDisabledDuringGesture: + desc = "tap disabled during gesture"; + disable_time = 0.02; + pause_time = -1; + break; + case TtcEnableTestMode::TapDisabledBeforeGestureWhileIdle: + desc = "tap disabled while Idle"; + disable_time = 0.00; + pause_time = -1; + break; + case TtcEnableTestMode::TapPausedDuringGesture: + desc = "tap paused during gesture"; + disable_time = -1; + pause_time = 0.02; + break; + case TtcEnableTestMode::TapPausedBeforeGestureWhileIdle: + desc = "tap paused while Idle"; + disable_time = 0.00; + pause_time = -1; + break; + } + SCOPED_TRACE(StringPrintf("State %zu (%s)", i, desc.c_str())); - HWStateGs &hwsgs = hwsgs_list[i]; - HardwareState* hwstate = &hwsgs.hws; - stime_t now = hwsgs.callback_now; - if (hwsgs.callback_now >= 0.0) - hwstate = nullptr; - else - now = hwsgs.hws.timestamp; + HWStateGs &hwsgs = hwsgs_list[i]; + HardwareState* hwstate = &hwsgs.hws; + stime_t now = hwsgs.callback_now; + if (hwsgs.callback_now >= 0.0) + hwstate = nullptr; + else + now = hwsgs.hws.timestamp; - bool same_fingers = false; - if (hwstate && hwstate->timestamp == 0.0) { - // Reset imm interpreter - fprintf(stderr, "Resetting imm interpreter, i = %zd\n", i); - ii.reset(new ImmediateInterpreter(nullptr, nullptr)); - wrapper.Reset(ii.get()); - ii->drag_lock_enable_.val_ = 1; - ii->motion_tap_prevent_timeout_.val_ = 0; - ii->tap_drag_timeout_.val_ = 0.05; - ii->tap_enable_.val_ = 1; - ii->tap_drag_enable_.val_ = 1; - ii->tap_paused_.val_ = 0; - ii->tap_move_dist_.val_ = 1.0; - ii->tap_timeout_.val_ = 0.05; - EXPECT_EQ(kIdl, ii->tap_to_click_state_); - EXPECT_TRUE(ii->tap_enable_.val_); - } else { - same_fingers = ii->state_buffer_.Get(1)->SameFingersAs(hwsgs.hws); - } + bool same_fingers = false; + if (!hwstate || hwstate->timestamp != 0.0) { + same_fingers = ii.state_buffer_.Get(1).SameFingersAs(hwsgs.hws); + } - // Disable tap in the middle of the gesture - if (hwstate && hwstate->timestamp == disable_time) - ii->tap_enable_.val_ = 0; + // Disable tap in the middle of the gesture + if (hwstate && hwstate->timestamp == disable_time) + ii.tap_enable_.val_ = 0; - if (hwstate && hwstate->timestamp == pause_time) - ii->tap_paused_.val_ = true; + if (hwstate && hwstate->timestamp == pause_time) + ii.tap_paused_.val_ = true; - if (hwstate) - ii->state_buffer_.PushState(*hwstate); - unsigned bdown = 0; - unsigned bup = 0; - stime_t tm = NO_DEADLINE; - for (auto finger: hwsgs.gesturing_fingers) - ii->origin_timestamps_.emplace(finger, 0); - ii->UpdateTapState( - hwstate, hwsgs.gesturing_fingers, same_fingers, now, &bdown, &bup, - &tm); - ii->prev_gs_fingers_ = hwsgs.gesturing_fingers; - - switch (iter) { - case 0: // tap should be enabled - case 1: - case 3: - EXPECT_EQ(hwsgs.expected_down, bdown) << desc; - EXPECT_EQ(hwsgs.expected_up, bup) << desc; - if (hwsgs.timeout) - EXPECT_GT(tm, 0.0) << desc; - else - EXPECT_DOUBLE_EQ(NO_DEADLINE, tm) << desc; - EXPECT_EQ(hwsgs.expected_state, ii->tap_to_click_state_) << desc; - break; - case 2: // tap should be disabled - case 4: - EXPECT_EQ(0, bdown) << desc; - EXPECT_EQ(0, bup) << desc; - EXPECT_DOUBLE_EQ(NO_DEADLINE, tm) << desc; - EXPECT_EQ(kIdl, ii->tap_to_click_state_) << desc; - break; - } + if (hwstate) { + ii.metrics_->Update(*hwstate); + ii.state_buffer_.PushState(*hwstate); + } + unsigned buttons_down = 0; + unsigned buttons_up = 0; + stime_t timeout = NO_DEADLINE; + ii.UpdateTapState( + hwstate, hwsgs.gesturing_fingers, same_fingers, now, &buttons_down, + &buttons_up, &timeout); + ii.prev_gs_fingers_ = hwsgs.gesturing_fingers; + + switch (GetParam()) { + case TtcEnableTestMode::TapEnabled: + case TtcEnableTestMode::TapDisabledDuringGesture: + case TtcEnableTestMode::TapPausedDuringGesture: + // tap should be enabled + EXPECT_EQ(hwsgs.expected_down, buttons_down); + EXPECT_EQ(hwsgs.expected_up, buttons_up); + if (hwsgs.timeout) + EXPECT_GT(timeout, 0.0); + else + EXPECT_DOUBLE_EQ(NO_DEADLINE, timeout); + EXPECT_EQ(hwsgs.expected_state, ii.tap_to_click_state_); + break; + case TtcEnableTestMode::TapDisabledBeforeGestureWhileIdle: + case TtcEnableTestMode::TapPausedBeforeGestureWhileIdle: + // tap should be disabled + EXPECT_EQ(0, buttons_down); + EXPECT_EQ(0, buttons_up); + EXPECT_DOUBLE_EQ(NO_DEADLINE, timeout); + EXPECT_EQ(kIdl, ii.tap_to_click_state_); + break; } } } +INSTANTIATE_TEST_SUITE_P( + ImmediateInterpreterTtc, ImmediateInterpreterTtcEnableTest, + testing::Values(TtcEnableTestMode::TapEnabled, + TtcEnableTestMode::TapDisabledDuringGesture, + TtcEnableTestMode::TapDisabledBeforeGestureWhileIdle, + TtcEnableTestMode::TapPausedDuringGesture, + TtcEnableTestMode::TapPausedBeforeGestureWhileIdle)); + struct ClickTestHardwareStateAndExpectations { HardwareState hs; stime_t timeout; @@ -3020,24 +3022,22 @@ struct ClickTestHardwareStateAndExpectations { TEST(ImmediateInterpreterTest, ClickTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // x pixels/mm - 1, // y pixels/mm - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); EXPECT_FLOAT_EQ(10.0, ii.tapping_finger_min_separation_.val_); @@ -3114,24 +3114,22 @@ struct BigHandsRightClickInputAndExpectations { // right click. TEST(ImmediateInterpreterTest, BigHandsRightClickTest) { HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 106.666672, // right edge - 68.000000, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 25.4, // screen DPI x - 25.4, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 15, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - true, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - false, // is haptic pad + .right = 106.666672, + .bottom = 68.000000, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 15, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = true, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = false, }; BigHandsRightClickInputAndExpectations records[] = { { make_hwstate(1329527921.327647, 0, 2, 2, nullptr), 0, 0, @@ -3269,24 +3267,22 @@ TEST(ImmediateInterpreterTest, BigHandsRightClickTest) { TEST(ImmediateInterpreterTest, ChangeTimeoutTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 1000, // right edge - 1000, // bottom edge - 500, // pixels/TP width - 500, // pixels/TP height - 96, // screen DPI x - 96, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 1000, + .bottom = 1000, + .res_x = 500, + .res_y = 500, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; FingerState finger_states[] = { @@ -3376,24 +3372,22 @@ TEST(ImmediateInterpreterTest, PinchTests) { ImmediateInterpreter ii(nullptr, nullptr); ii.pinch_enable_.val_ = 1; HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; FingerState finger_states[] = { @@ -3523,24 +3517,22 @@ struct AvoidAccidentalPinchTestInput { TEST(ImmediateInterpreterTest, AvoidAccidentalPinchTest) { std::unique_ptr<ImmediateInterpreter> ii; HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 106.666672, // right edge - 68.000000, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 25.4, // screen DPI x - 25.4, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 15, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - true, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - false, // is haptic pad + .right = 106.666672, + .bottom = 68.000000, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 15, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = true, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = false, }; TestInterpreterWrapper wrapper(ii.get(), &hwprops); @@ -3681,24 +3673,22 @@ TEST(ImmediateInterpreterTest, SemiMtActiveAreaTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties old_hwprops = { - 0, // left edge - 0, // top edge - 90.404251, // right edge - 48.953846, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 133, // screen DPI x - 133, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 3, // max touch - 0, // t5r2 - 1, // semi-mt - true, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - false, // is haptic pad + .right = 90.404251, + .bottom = 48.953846, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 3, + .supports_t5r2 = 0, + .support_semi_mt = 1, + .is_button_pad = true, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = false, }; const unsigned kNonPalmFlags = GESTURES_FINGER_WARP_X | @@ -3731,24 +3721,22 @@ TEST(ImmediateInterpreterTest, SemiMtActiveAreaTest) { } HardwareProperties new_hwprops = { - 0, // left edge - 0, // top edge - 96.085106, // right edge - 57.492310, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 133, // screen DPI x - 133, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 3, // max touch - 0, // t5r2 - 1, // semi-mt - true, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - false, // is haptic pad + .right = 96.085106, + .bottom = 57.492310, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 3, + .supports_t5r2 = 0, + .support_semi_mt = 1, + .is_button_pad = true, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = false, }; FingerState new_finger_states[] = { @@ -3783,24 +3771,22 @@ TEST(ImmediateInterpreterTest, SemiMtNoPinchTest) { ii.pinch_enable_.val_ = 1; HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 90.404251, // right edge - 48.953846, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 133, // screen DPI x - 133, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 3, // max touch - 0, // t5r2 - 0, // semi-mt - true, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - false, // is haptic pad + .right = 90.404251, + .bottom = 48.953846, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 3, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = true, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = false, }; FingerState finger_state[] = { @@ -3861,24 +3847,22 @@ TEST(ImmediateInterpreterTest, WarpedFingersTappingTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 90.404251, // right edge - 48.953846, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 133, // screen DPI x - 133, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 3, // max touch - 0, // t5r2 - 1, // semi-mt - true, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - false, // is haptic pad + .right = 90.404251, + .bottom = 48.953846, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 3, + .supports_t5r2 = 0, + .support_semi_mt = 1, + .is_button_pad = true, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = false, }; unsigned flags = GESTURES_FINGER_WARP_X_NON_MOVE | @@ -3923,24 +3907,22 @@ TEST(ImmediateInterpreterTest, WarpedFingersTappingTest) { TEST(ImmediateInterpreterTest, FlingDepthTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 1, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 1, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; FingerState finger_states[] = { @@ -4022,24 +4004,22 @@ TEST(ImmediateInterpreterTest, ScrollResetTapTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 96.085106, // right edge - 57.492310, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 25.4, // screen DPI x - 25.4, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 3, // max touch - 0, // t5r2 - 1, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 96.085106, + .bottom = 57.492310, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 3, + .supports_t5r2 = 0, + .support_semi_mt = 1, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; FingerState finger_state[] = { @@ -4093,24 +4073,22 @@ TEST(ImmediateInterpreterTest, ZeroClickInitializationTest) { ImmediateInterpreter ii(nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 1000, // right edge - 1000, // bottom edge - 500, // pixels/TP width - 500, // pixels/TP height - 96, // screen DPI x - 96, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // tripletap - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 1000, + .bottom = 1000, + .res_x = 500, + .res_y = 500, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&ii, &hwprops); diff --git a/src/integral_gesture_filter_interpreter.cc b/src/integral_gesture_filter_interpreter.cc index 20e1d3a..12df856 100644 --- a/src/integral_gesture_filter_interpreter.cc +++ b/src/integral_gesture_filter_interpreter.cc @@ -27,8 +27,13 @@ IntegralGestureFilterInterpreter::IntegralGestureFilterInterpreter( void IntegralGestureFilterInterpreter::SyncInterpretImpl( HardwareState& hwstate, stime_t* timeout) { + const char name[] = "IntegralGestureFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + can_clear_remainders_ = hwstate.finger_cnt == 0 && hwstate.touch_cnt == 0; stime_t next_timeout = NO_DEADLINE; + + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, &next_timeout); *timeout = SetNextDeadlineAndReturnTimeoutVal( hwstate.timestamp, remainder_reset_deadline_, next_timeout); @@ -36,6 +41,9 @@ void IntegralGestureFilterInterpreter::SyncInterpretImpl( void IntegralGestureFilterInterpreter::HandleTimerImpl( stime_t now, stime_t *timeout) { + const char name[] = "IntegralGestureFilterInterpreter::HandleTimerImpl"; + LogHandleTimerPre(name, now, timeout); + stime_t next_timeout; if (ShouldCallNextTimer(remainder_reset_deadline_)) { if (next_timer_deadline_ > now) { @@ -64,6 +72,7 @@ void IntegralGestureFilterInterpreter::HandleTimerImpl( *timeout = SetNextDeadlineAndReturnTimeoutVal(now, remainder_reset_deadline_, next_timeout); + LogHandleTimerPost(name, now, timeout); } namespace { @@ -79,13 +88,18 @@ float Truncate(float input, float* overflow) { // absolute value of an input is < 1, we will change it to 0, unless // there has been enough fractional accumulation to bring it above 1. void IntegralGestureFilterInterpreter::ConsumeGesture(const Gesture& gesture) { + const char name[] = "IntegralGestureFilterInterpreter::ConsumeGesture"; + LogGestureConsume(name, gesture); + Gesture copy = gesture; switch (gesture.type) { case kGestureTypeMove: if (gesture.details.move.dx != 0.0 || gesture.details.move.dy != 0.0 || gesture.details.move.ordinal_dx != 0.0 || - gesture.details.move.ordinal_dy != 0.0) + gesture.details.move.ordinal_dy != 0.0) { + LogGestureProduce(name, gesture); ProduceGesture(gesture); + } break; case kGestureTypeScroll: copy.details.scroll.dx = Truncate(copy.details.scroll.dx, @@ -99,10 +113,14 @@ void IntegralGestureFilterInterpreter::ConsumeGesture(const Gesture& gesture) { if (copy.details.scroll.dx != 0.0 || copy.details.scroll.dy != 0.0 || copy.details.scroll.ordinal_dx != 0.0 || copy.details.scroll.ordinal_dy != 0.0) { + LogGestureProduce(name, copy); ProduceGesture(copy); } else if (copy.details.scroll.stop_fling) { - ProduceGesture(Gesture(kGestureFling, copy.start_time, copy.end_time, - 0, 0, GESTURES_FLING_TAP_DOWN)); + auto fling_tap_down = Gesture(kGestureFling, + copy.start_time, copy.end_time, + 0, 0, GESTURES_FLING_TAP_DOWN); + LogGestureProduce(name, fling_tap_down); + ProduceGesture(fling_tap_down); } remainder_reset_deadline_ = copy.end_time + 1.0; break; @@ -114,11 +132,13 @@ void IntegralGestureFilterInterpreter::ConsumeGesture(const Gesture& gesture) { if (copy.details.wheel.dx != 0.0 || copy.details.wheel.dy != 0.0 || copy.details.wheel.tick_120ths_dx != 0.0 || copy.details.wheel.tick_120ths_dy != 0.0) { + LogGestureProduce(name, copy); ProduceGesture(copy); } remainder_reset_deadline_ = copy.end_time + 1.0; break; default: + LogGestureProduce(name, gesture); ProduceGesture(gesture); break; } diff --git a/src/integral_gesture_filter_interpreter_unittest.cc b/src/integral_gesture_filter_interpreter_unittest.cc index a17056d..bebd37a 100644 --- a/src/integral_gesture_filter_interpreter_unittest.cc +++ b/src/integral_gesture_filter_interpreter_unittest.cc @@ -220,4 +220,28 @@ TEST(IntegralGestureFilterInterpreterTest, SlowScrollTest) { EXPECT_FLOAT_EQ(1.0, out->details.scroll.dy); } +TEST(IntegralGestureFilterInterpreterTestInterpreter, ConsumeGesture) { + PropRegistry prop_reg; + IntegralGestureFilterInterpreterTestInterpreter* base_interpreter = + new IntegralGestureFilterInterpreterTestInterpreter; + IntegralGestureFilterInterpreter interpreter(base_interpreter, nullptr); + + using EventDebug = ActivityLog::EventDebug; + interpreter.SetEventLoggingEnabled(true); + interpreter.EventDebugLoggingEnable(EventDebug::Gesture); + interpreter.log_.reset(new ActivityLog(&prop_reg)); + + Gesture move(kGestureMove, 0, 0.1, 5, 6); + Gesture mouse_wheel(kGestureMouseWheel, 0.2, 0.3, 0.0010, 0, 0, 1); + Gesture button_change(kGestureButtonsChange, 0.4, 0.5, 0, 0, false); + + EXPECT_EQ(interpreter.log_->size(), 0); + interpreter.ConsumeGesture(move); + EXPECT_EQ(interpreter.log_->size(), 2); + interpreter.ConsumeGesture(mouse_wheel); + EXPECT_EQ(interpreter.log_->size(), 4); + interpreter.ConsumeGesture(button_change); + EXPECT_EQ(interpreter.log_->size(), 6); +} + } // namespace gestures diff --git a/src/interpreter.cc b/src/interpreter.cc index e3a7356..cee8dd3 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -20,6 +20,8 @@ using std::string; namespace gestures { +using EventDebug = ActivityLog::EventDebug; + Interpreter::Interpreter(PropRegistry* prop_reg, Tracer* tracer, bool force_log_creation) @@ -49,7 +51,7 @@ void Interpreter::Trace(const char* message, const char* name) { void Interpreter::SyncInterpret(HardwareState& hwstate, stime_t* timeout) { AssertWithReturn(initialized_); - if (enable_event_logging_ && log_.get()) { + if (EventLoggingIsEnabled()) { Trace("log: start: ", "LogHardwareState"); log_->LogHardwareState(hwstate); Trace("log: end: ", "LogHardwareState"); @@ -65,7 +67,7 @@ void Interpreter::SyncInterpret(HardwareState& hwstate, void Interpreter::HandleTimer(stime_t now, stime_t* timeout) { AssertWithReturn(initialized_); - if (enable_event_logging_ && log_.get()) { + if (EventLoggingIsEnabled()) { Trace("log: start: ", "LogTimerCallback"); log_->LogTimerCallback(now); Trace("log: end: ", "LogTimerCallback"); @@ -144,15 +146,40 @@ void Interpreter::InitName() { } } +bool Interpreter::EventLoggingIsEnabled() { + return enable_event_logging_ && log_.get(); +} + void Interpreter::SetEventLoggingEnabled(bool enabled) { // TODO(b/185844310): log an event when touch logging is enabled or disabled. enable_event_logging_ = enabled; } +bool Interpreter::EventDebugLoggingIsEnabled(ActivityLog::EventDebug event) { + return EventLoggingIsEnabled() && + (enable_event_debug_logging_ & (1 << static_cast<int>(event))); +} + +uint32_t Interpreter::GetEventDebugLoggingEnabled() { + return enable_event_debug_logging_; +} + +void Interpreter::SetEventDebugLoggingEnabled(uint32_t enabled) { + enable_event_debug_logging_ = enabled; +} + +void Interpreter::EventDebugLoggingDisable(ActivityLog::EventDebug event) { + enable_event_debug_logging_ &= ~(1 << static_cast<int>(event)); +} + +void Interpreter::EventDebugLoggingEnable(ActivityLog::EventDebug event) { + enable_event_debug_logging_ |= (1 << static_cast<int>(event)); +} + void Interpreter::LogOutputs(const Gesture* result, stime_t* timeout, const char* action) { - if (!enable_event_logging_ || !log_.get()) + if (!EventLoggingIsEnabled()) return; Trace("log: start: ", action); if (result) @@ -161,4 +188,41 @@ void Interpreter::LogOutputs(const Gesture* result, log_->LogCallbackRequest(*timeout); Trace("log: end: ", action); } + +void Interpreter::LogGestureConsume( + const std::string& name, const Gesture& gesture) { + if (EventDebugLoggingIsEnabled(EventDebug::Gesture)) + log_->LogGestureConsume(name, gesture); +} + +void Interpreter::LogGestureProduce( + const std::string& name, const Gesture& gesture) { + if (EventDebugLoggingIsEnabled(EventDebug::Gesture)) + log_->LogGestureProduce(name, gesture); +} + +void Interpreter::LogHardwareStatePre( + const std::string& name, const HardwareState& hwstate) { + if (EventDebugLoggingIsEnabled(EventDebug::HardwareState)) + log_->LogHardwareStatePre(name, hwstate); +} + +void Interpreter::LogHardwareStatePost( + const std::string& name, const HardwareState& hwstate) { + if (EventDebugLoggingIsEnabled(EventDebug::HardwareState)) + log_->LogHardwareStatePost(name, hwstate); +} + +void Interpreter::LogHandleTimerPre( + const std::string& name, stime_t now, const stime_t* timeout) { + if (EventDebugLoggingIsEnabled(EventDebug::HandleTimer)) + log_->LogHandleTimerPre(name, now, timeout); +} + +void Interpreter::LogHandleTimerPost( + const std::string& name, stime_t now, const stime_t* timeout) { + if (EventDebugLoggingIsEnabled(EventDebug::HandleTimer)) + log_->LogHandleTimerPost(name, now, timeout); +} + } // namespace gestures diff --git a/src/interpreter_unittest.cc b/src/interpreter_unittest.cc index a64fa01..e0d1cff 100644 --- a/src/interpreter_unittest.cc +++ b/src/interpreter_unittest.cc @@ -67,6 +67,7 @@ class InterpreterTestInterpreter : public Interpreter { virtual void HandleTimerImpl(stime_t now, stime_t* timeout) { handle_timer_call_count_++; + Interpreter::HandleTimerImpl(now, timeout); ProduceGesture(return_value_); } }; @@ -80,16 +81,17 @@ TEST(InterpreterTest, SimpleTest) { MetricsProperties mprops(&prop_reg); HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 10, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - 1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 1, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 10, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = 1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(base_interpreter, &hwprops); @@ -209,4 +211,97 @@ TEST(InterpreterTest, LoggingDisabledByDefault) { wrapper.SyncInterpret(hardware_state, &timeout); EXPECT_EQ(base_interpreter->log_->size(), 0); } + +TEST(InterpreterTest, EventDebugLoggingEnableTest) { + InterpreterResetLogTestInterpreter* base_interpreter = + new InterpreterResetLogTestInterpreter(); + + base_interpreter->SetEventDebugLoggingEnabled(0); + EXPECT_EQ(base_interpreter->GetEventDebugLoggingEnabled(), 0); + + using EventDebug = ActivityLog::EventDebug; + base_interpreter->EventDebugLoggingEnable(EventDebug::HardwareState); + EXPECT_EQ(base_interpreter->GetEventDebugLoggingEnabled(), + 1 << static_cast<int>(EventDebug::HardwareState)); + + base_interpreter->EventDebugLoggingDisable(EventDebug::HardwareState); + EXPECT_EQ(base_interpreter->GetEventDebugLoggingEnabled(), 0); +} + +TEST(InterpreterTest, LogHardwareStateTest) { + PropRegistry prop_reg; + InterpreterResetLogTestInterpreter* base_interpreter = + new InterpreterResetLogTestInterpreter(); + + FingerState fs = { 0.0, 0.0, 0.0, 0.0, 9.0, 0.0, 3.0, 4.0, 22, 0 }; + HardwareState hs = make_hwstate(1.0, 0, 1, 1, &fs); + + base_interpreter->SetEventLoggingEnabled(false); + base_interpreter->SetEventDebugLoggingEnabled(0); + + base_interpreter->LogHardwareStatePre( + "InterpreterTest_LogHardwareStateTest", hs); + EXPECT_EQ(base_interpreter->log_->size(), 0); + + base_interpreter->LogHardwareStatePost( + "InterpreterTest_LogHardwareStateTest", hs); + EXPECT_EQ(base_interpreter->log_->size(), 0); + + using EventDebug = ActivityLog::EventDebug; + base_interpreter->SetEventLoggingEnabled(true); + base_interpreter->EventDebugLoggingEnable(EventDebug::HardwareState); + + base_interpreter->LogHardwareStatePre( + "InterpreterTest_LogHardwareStateTest", hs); + EXPECT_EQ(base_interpreter->log_->size(), 1); + + base_interpreter->LogHardwareStatePost( + "InterpreterTest_LogHardwareStateTest", hs); + EXPECT_EQ(base_interpreter->log_->size(), 2); +} + +TEST(InterpreterTest, LogGestureTest) { + PropRegistry prop_reg; + InterpreterResetLogTestInterpreter* base_interpreter = + new InterpreterResetLogTestInterpreter(); + + Gesture move(kGestureMove, 1.0, 2.0, 773, 4.0); + + base_interpreter->SetEventLoggingEnabled(false); + base_interpreter->SetEventDebugLoggingEnabled(0); + base_interpreter->LogGestureConsume("InterpreterTest_LogGestureTest", move); + EXPECT_EQ(base_interpreter->log_->size(), 0); + base_interpreter->LogGestureProduce("InterpreterTest_LogGestureTest", move); + EXPECT_EQ(base_interpreter->log_->size(), 0); + + + using EventDebug = ActivityLog::EventDebug; + base_interpreter->SetEventLoggingEnabled(true); + base_interpreter->EventDebugLoggingEnable(EventDebug::Gesture); + base_interpreter->LogGestureConsume("InterpreterTest_LogGestureTest", move); + EXPECT_EQ(base_interpreter->log_->size(), 1); + base_interpreter->LogGestureProduce("InterpreterTest_LogGestureTest", move); + EXPECT_EQ(base_interpreter->log_->size(), 2); +} + +TEST(InterpreterTest, LogHandleTimerTest) { + PropRegistry prop_reg; + InterpreterResetLogTestInterpreter* base_interpreter = + new InterpreterResetLogTestInterpreter(); + + using EventDebug = ActivityLog::EventDebug; + base_interpreter->SetEventLoggingEnabled(true); + base_interpreter->EventDebugLoggingEnable(EventDebug::HandleTimer); + + stime_t timeout = 10; + + base_interpreter->LogHandleTimerPre("InterpreterTest_LogHandleTimerTest", + 0, &timeout); + EXPECT_EQ(base_interpreter->log_->size(), 1); + + base_interpreter->LogHandleTimerPost("InterpreterTest_LogHandleTimerTest", + 0, &timeout); + EXPECT_EQ(base_interpreter->log_->size(), 2); +} + } // namespace gestures diff --git a/src/logging_filter_interpreter.cc b/src/logging_filter_interpreter.cc index 2c43238..3d65ad6 100644 --- a/src/logging_filter_interpreter.cc +++ b/src/logging_filter_interpreter.cc @@ -17,6 +17,8 @@ LoggingFilterInterpreter::LoggingFilterInterpreter(PropRegistry* prop_reg, Interpreter* next, Tracer* tracer) : FilterInterpreter(prop_reg, next, tracer, true), + event_debug_logging_enable_(prop_reg, + "Event Debug Logging Components Enable", 0), event_logging_enable_(prop_reg, "Event Logging Enable", false), logging_notify_(prop_reg, "Logging Notify", 0), logging_reset_(prop_reg, "Logging Reset", 0), @@ -26,6 +28,8 @@ LoggingFilterInterpreter::LoggingFilterInterpreter(PropRegistry* prop_reg, InitName(); if (prop_reg && log_.get()) prop_reg->set_activity_log(log_.get()); + event_debug_logging_enable_.SetDelegate(this); + IntWasWritten(&event_debug_logging_enable_); event_logging_enable_.SetDelegate(this); BoolWasWritten(&event_logging_enable_); logging_notify_.SetDelegate(this); @@ -35,8 +39,12 @@ LoggingFilterInterpreter::LoggingFilterInterpreter(PropRegistry* prop_reg, void LoggingFilterInterpreter::IntWasWritten(IntProperty* prop) { if (prop == &logging_notify_) Dump(log_location_.val_); - if (prop == &logging_reset_) + else if (prop == &logging_reset_) Clear(); + else if (prop == &event_debug_logging_enable_) { + Log("Event Debug Enabled 0x%X", event_debug_logging_enable_.val_); + SetEventDebugLoggingEnabled(event_debug_logging_enable_.val_); + } }; void LoggingFilterInterpreter::BoolWasWritten(BoolProperty* prop) { diff --git a/src/logging_filter_interpreter_unittest.cc b/src/logging_filter_interpreter_unittest.cc index 001a4ee..fb4ebaa 100644 --- a/src/logging_filter_interpreter_unittest.cc +++ b/src/logging_filter_interpreter_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <cstdio> #include <string> #include <gtest/gtest.h> @@ -40,17 +41,28 @@ TEST(LoggingFilterInterpreterTest, LogResetHandlerTest) { interpreter.event_logging_enable_.SetValue(Json::Value(true)); interpreter.BoolWasWritten(&interpreter.event_logging_enable_); + using EventDebug = ActivityLog::EventDebug; + EXPECT_EQ(interpreter.enable_event_debug_logging_, 0); + interpreter.event_debug_logging_enable_.SetValue( + Json::Value((1 << static_cast<int>(EventDebug::Gesture)) | + (1 << static_cast<int>(EventDebug::HardwareState)))); + interpreter.IntWasWritten(&interpreter.event_debug_logging_enable_); + EXPECT_EQ(interpreter.enable_event_debug_logging_, + (1 << static_cast<int>(EventDebug::Gesture)) | + (1 << static_cast<int>(EventDebug::HardwareState))); + HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 10, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch, - 1, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 10, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -76,8 +88,17 @@ TEST(LoggingFilterInterpreterTest, LogResetHandlerTest) { std::string str = interpreter.EncodeActivityLog(); EXPECT_NE(0, str.size()); - const char* filename = "testlog.dump"; - interpreter.Dump(filename); + // std::tmpnam is considered unsafe because another process could create the + // temporary file after time std::tmpnam returns the name but before the code + // actually opens it. Because this is just test code, we don't need to be + // concerned about such security holes here. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + const char* filename = std::tmpnam(nullptr); +#pragma GCC diagnostic pop + ASSERT_NE(nullptr, filename) << "Couldn't generate a temporary file name"; + interpreter.log_location_.SetValue(Json::Value(filename)); + interpreter.IntWasWritten(&interpreter.logging_notify_); std::string read_str = ""; bool couldRead = ReadFileToString(filename, &read_str); diff --git a/src/lookahead_filter_interpreter.cc b/src/lookahead_filter_interpreter.cc index d42643c..7a5c8fd 100644 --- a/src/lookahead_filter_interpreter.cc +++ b/src/lookahead_filter_interpreter.cc @@ -45,6 +45,9 @@ LookaheadFilterInterpreter::LookaheadFilterInterpreter( void LookaheadFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { + const char name[] = "LookaheadFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + // Keep track of where the last node is in the current queue_ auto const queue_was_not_empty = !queue_.empty(); QState* old_back_node = queue_was_not_empty ? &queue_.back() : nullptr; @@ -91,6 +94,8 @@ void LookaheadFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, hwstate.fingers[i].flags = q_node.state_.fingers[i].flags; } } + + LogHardwareStatePost(name, hwstate); } // Interpolates the two hardware states into out. @@ -353,6 +358,9 @@ void LookaheadFilterInterpreter::TapDownOccurringGesture(stime_t now) { return; if (queue_.size() < 2) return; // Not enough data to know + + const char name[] = "LookaheadFilterInterpreter::TapDownOccurringGesture"; + HardwareState& hs = queue_.back().state_; if (queue_.back().state_.timestamp != now) return; // We didn't push a new hardware state now @@ -361,15 +369,21 @@ void LookaheadFilterInterpreter::TapDownOccurringGesture(stime_t now) { HardwareState& prev_hs = queue_.at(-2).state_; if (hs.finger_cnt > prev_hs.finger_cnt) { // Finger was added. - ProduceGesture(Gesture(kGestureFling, prev_hs.timestamp, hs.timestamp, - 0, 0, GESTURES_FLING_TAP_DOWN)); + auto fling_tap_down = Gesture(kGestureFling, + prev_hs.timestamp, hs.timestamp, + 0, 0, GESTURES_FLING_TAP_DOWN); + LogGestureProduce(name, fling_tap_down); + ProduceGesture(fling_tap_down); return; } // Go finger by finger for a final check for (size_t i = 0; i < hs.finger_cnt; i++) if (!prev_hs.GetFingerState(hs.fingers[i].tracking_id)) { - ProduceGesture(Gesture(kGestureFling, prev_hs.timestamp, hs.timestamp, - 0, 0, GESTURES_FLING_TAP_DOWN)); + auto fling_tap_down = Gesture(kGestureFling, + prev_hs.timestamp, hs.timestamp, + 0, 0, GESTURES_FLING_TAP_DOWN); + LogGestureProduce(name, fling_tap_down); + ProduceGesture(fling_tap_down); return; } } @@ -416,6 +430,9 @@ void LookaheadFilterInterpreter::AttemptInterpolation() { void LookaheadFilterInterpreter::HandleTimerImpl(stime_t now, stime_t* timeout) { + const char name[] = "LookaheadFilterInterpreter::HandleTimerImpl"; + LogHandleTimerPre(name, now, timeout); + stime_t next_timeout = NO_DEADLINE; // Determine if a FlingTapDown gesture needs to be produced @@ -492,9 +509,13 @@ void LookaheadFilterInterpreter::HandleTimerImpl(stime_t now, UpdateInterpreterDue(next_timeout, now, timeout); } UpdateInterpreterDue(next_timeout, now, timeout); + LogHandleTimerPost(name, now, timeout); } void LookaheadFilterInterpreter::ConsumeGesture(const Gesture& gesture) { + const char name[] = "LookaheadFilterInterpreter::ConsumeGesture"; + LogGestureConsume(name, gesture); + QState& node = queue_.front(); float distance_sq = 0.0; @@ -510,6 +531,7 @@ void LookaheadFilterInterpreter::ConsumeGesture(const Gesture& gesture) { break; default: // Non-movement: just allow it. + LogGestureProduce(name, gesture); ProduceGesture(gesture); return; } @@ -518,6 +540,7 @@ void LookaheadFilterInterpreter::ConsumeGesture(const Gesture& gesture) { min_nonsuppress_speed_.val_ * min_nonsuppress_speed_.val_ * time_delta * time_delta; if (distance_sq >= min_nonsuppress_dist_sq) { + LogGestureProduce(name, gesture); ProduceGesture(gesture); return; } @@ -528,6 +551,7 @@ void LookaheadFilterInterpreter::ConsumeGesture(const Gesture& gesture) { return; // suppress } + LogGestureProduce(name, gesture); ProduceGesture(gesture); } diff --git a/src/lookahead_filter_interpreter_unittest.cc b/src/lookahead_filter_interpreter_unittest.cc index dca378e..5aed753 100644 --- a/src/lookahead_filter_interpreter_unittest.cc +++ b/src/lookahead_filter_interpreter_unittest.cc @@ -13,6 +13,7 @@ #include "include/gestures.h" #include "include/lookahead_filter_interpreter.h" +#include "include/string_util.h" #include "include/unittest_util.h" #include "include/util.h" @@ -22,6 +23,9 @@ using std::pair; namespace gestures { class LookaheadFilterInterpreterTest : public ::testing::Test {}; +class LookaheadFilterInterpreterParmTest : + public LookaheadFilterInterpreterTest, + public testing::WithParamInterface<int> {}; class LookaheadFilterInterpreterTestInterpreter : public Interpreter { public: @@ -88,21 +92,22 @@ class LookaheadFilterInterpreterTestInterpreter : public Interpreter { std::set<short> all_ids_; }; -TEST(LookaheadFilterInterpreterTest, SimpleTest) { +TEST_P(LookaheadFilterInterpreterParmTest, SimpleTest) { LookaheadFilterInterpreterTestInterpreter* base_interpreter = nullptr; std::unique_ptr<LookaheadFilterInterpreter> interpreter; HardwareProperties initial_hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 10, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 1, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 10, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops); @@ -137,6 +142,8 @@ TEST(LookaheadFilterInterpreterTest, SimpleTest) { stime_t expected_timeout = 0.0; Gesture expected_movement; + int suppress = GetParam(); + for (size_t i = 3; i < arraysize(hs); ++i) { if (i % 3 == 0) { base_interpreter = new LookaheadFilterInterpreterTestInterpreter; @@ -159,6 +166,7 @@ TEST(LookaheadFilterInterpreterTest, SimpleTest) { wrapper.Reset(interpreter.get()); interpreter->min_delay_.val_ = 0.05; expected_timeout = interpreter->min_delay_.val_; + interpreter->suppress_immediate_tapdown_.val_ = suppress; } stime_t timeout = NO_DEADLINE; Gesture* out = wrapper.SyncInterpret(hs[i], &timeout); @@ -204,6 +212,9 @@ TEST(LookaheadFilterInterpreterTest, SimpleTest) { } } } +INSTANTIATE_TEST_SUITE_P(LookaheadFilterInterpreter, + LookaheadFilterInterpreterParmTest, + testing::Values(0, 1)); class LookaheadFilterInterpreterVariableDelayTestInterpreter : public Interpreter { @@ -233,16 +244,17 @@ TEST(LookaheadFilterInterpreterTest, VariableDelayTest) { LookaheadFilterInterpreter interpreter(nullptr, base_interpreter, nullptr); HardwareProperties initial_hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, // x res (pixels/mm) - 1, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 5, 5, // max fingers, max_touch, - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &initial_hwprops); @@ -309,16 +321,17 @@ TEST(LookaheadFilterInterpreterTest, NoTapSetTest) { interpreter.min_delay_.val_ = 0.0; HardwareProperties initial_hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, // x res (pixels/mm) - 1, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 5, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; FingerState fs[] = { @@ -364,16 +377,17 @@ TEST(LookaheadFilterInterpreterTest, SpuriousCallbackTest) { std::unique_ptr<LookaheadFilterInterpreter> interpreter; HardwareProperties initial_hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 10, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 1, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 10, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops); @@ -417,16 +431,17 @@ TEST(LookaheadFilterInterpreterTest, TimeGoesBackwardsTest) { LookaheadFilterInterpreter interpreter(nullptr, base_interpreter, nullptr); HardwareProperties initial_hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, // x res (pixels/mm) - 1, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 1, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &initial_hwprops); @@ -512,16 +527,17 @@ TEST(LookaheadFilterInterpreterTest, InterpolateTest) { std::unique_ptr<LookaheadFilterInterpreter> interpreter; HardwareProperties initial_hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 10, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 1, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 10, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops); @@ -593,16 +609,17 @@ TEST(LookaheadFilterInterpreterTest, InterpolationOverdueTest) { std::unique_ptr<LookaheadFilterInterpreter> interpreter; HardwareProperties initial_hwprops = { - 0, 0, 10, 10, // left, top, right, bottom - 1, // x res (pixels/mm) - 1, // y res (pixels/mm) - 25, 25, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 1, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 10, .bottom = 10, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops); @@ -668,16 +685,17 @@ TEST(LookaheadFilterInterpreterTest, DrumrollTest) { std::unique_ptr<LookaheadFilterInterpreter> interpreter; HardwareProperties initial_hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, // x res (pixels/mm) - 1, // y res (pixels/mm) - 25, 25, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 1, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops); @@ -744,16 +762,17 @@ TEST(LookaheadFilterInterpreterTest, QuickMoveTest) { std::unique_ptr<LookaheadFilterInterpreter> interpreter; HardwareProperties initial_hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, // x res (pixels/mm) - 1, // y res (pixels/mm) - 25, 25, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 1, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops); @@ -840,24 +859,22 @@ TEST(LookaheadFilterInterpreterTest, QuickSwipeTest) { std::unique_ptr<LookaheadFilterInterpreter> interpreter; HardwareProperties initial_hwprops = { - 0.000000, // left edge - 0.000000, // top edge - 95.934784, // right edge - 65.259262, // bottom edge - 1.000000, // x pixels/TP width - 1.000000, // y pixels/TP height - 25.400000, // x screen DPI - 25.400000, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 1, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 95.934784, + .bottom = 65.259262, + .res_x = 1.000000, + .res_y = 1.000000, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 1, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops); @@ -937,24 +954,22 @@ TEST(LookaheadFilterInterpreterTest, CyapaDrumrollTest) { std::unique_ptr<LookaheadFilterInterpreter> interpreter; HardwareProperties initial_hwprops = { - 0.000000, // left edge - 0.000000, // top edge - 106.666672, // right edge - 68.000000, // bottom edge - 1.000000, // x pixels/TP width - 1.000000, // y pixels/TP height - 25.400000, // x screen DPI - 25.400000, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 15, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 0, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 106.666672, + .bottom = 68.000000, + .res_x = 1.000000, + .res_y = 1.000000, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 15, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 0, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(interpreter.get(), &initial_hwprops); @@ -1147,24 +1162,22 @@ TEST(LookaheadFilterInterpreterTest, CyapaQuickTwoFingerMoveTest) { interpreter.min_delay_.val_ = 0.0; HardwareProperties initial_hwprops = { - 0.000000, // left edge - 0.000000, // top edge - 106.666672, // right edge - 68.000000, // bottom edge - 1.000000, // x pixels/TP width - 1.000000, // y pixels/TP height - 25.400000, // x screen DPI - 25.400000, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 15, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 0, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 106.666672, + .bottom = 68.000000, + .res_x = 1.000000, + .res_y = 1.000000, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 15, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 0, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &initial_hwprops); @@ -1212,16 +1225,17 @@ TEST(LookaheadFilterInterpreterTest, SemiMtNoTrackingIdAssignmentTest) { std::unique_ptr<LookaheadFilterInterpreter> interpreter; HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, // x res (pixels/mm) - 1, // y res (pixels/mm) - 25, 25, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 1, 1, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 1, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(interpreter.get(), &hwprops); @@ -1275,4 +1289,122 @@ TEST(LookaheadFilterInterpreterTest, SemiMtNoTrackingIdAssignmentTest) { } } +TEST(LookaheadFilterInterpreterTest, AddFingerFlingTest) { + LookaheadFilterInterpreterTestInterpreter* base_interpreter = nullptr; + std::unique_ptr<LookaheadFilterInterpreter> interpreter; + + HardwareProperties hwprops = { + .right = 100, .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 1, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, + }; + TestInterpreterWrapper wrapper(interpreter.get(), &hwprops); + + base_interpreter = new LookaheadFilterInterpreterTestInterpreter; + interpreter.reset(new LookaheadFilterInterpreter( + nullptr, base_interpreter, nullptr)); + wrapper.Reset(interpreter.get()); + + // Gesture Consumer that verifies and counts each Fling type gesture + class FlingConsumer : public GestureConsumer { + public: + void ConsumeGesture(const Gesture& gesture) { + EXPECT_EQ(gesture.type, kGestureTypeFling); + ++gestures_consumed_; + } + int gestures_consumed_ = 0; + } fling_consumer{}; + interpreter->consumer_ = &fling_consumer; + + FingerState fs[] = { + // TM, Tm, WM, Wm, pr, orient, x, y, id + { 0, 0, 0, 0, 5, 0, 76, 45, 20, 0}, // 0 - One Finger + + { 0, 0, 0, 0, 62, 0, 56, 43, 20, 0}, // 1 - Two Fingers + { 0, 0, 0, 0, 62, 0, 76, 41, 21, 0}, + }; + HardwareState hs[] = { + make_hwstate(328.989039, 0, 1, 1, &fs[0]), + make_hwstate(329.013853, 0, 2, 2, &fs[1]), + }; + + // Disable Suppress Immediate Tapdown + interpreter->suppress_immediate_tapdown_.val_ = 0; + + // Run through the two hardware states and verify a fling is detected + stime_t timeout = NO_DEADLINE; + EXPECT_EQ(fling_consumer.gestures_consumed_, 0); + wrapper.SyncInterpret(hs[0], &timeout); + EXPECT_EQ(fling_consumer.gestures_consumed_, 0); + wrapper.SyncInterpret(hs[1], &timeout); + EXPECT_EQ(fling_consumer.gestures_consumed_, 1); +} + +TEST(LookaheadFilterInterpreterTest, ConsumeGestureTest) { + LookaheadFilterInterpreterTestInterpreter* base_interpreter = nullptr; + std::unique_ptr<LookaheadFilterInterpreter> interpreter; + + HardwareProperties hwprops = { + .right = 100, .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 1, .support_semi_mt = 1, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, + }; + TestInterpreterWrapper wrapper(interpreter.get(), &hwprops); + + base_interpreter = new LookaheadFilterInterpreterTestInterpreter; + interpreter.reset(new LookaheadFilterInterpreter( + nullptr, base_interpreter, nullptr)); + wrapper.Reset(interpreter.get()); + + // Gesture Consumer that counts each Metrics and Scroll type gesture + class TestGestureConsumer : public GestureConsumer { + public: + void ConsumeGesture(const Gesture& gesture) { + if (gesture.type == kGestureTypeMetrics) + ++metric_gestures_consumed_; + else if (gesture.type == kGestureTypeScroll) + ++scroll_gestures_consumed_; + } + int metric_gestures_consumed_ = 0; + int scroll_gestures_consumed_ = 0; + } test_consumer{}; + interpreter->consumer_ = &test_consumer; + + // Both gestures counters should start with zero + EXPECT_EQ(test_consumer.metric_gestures_consumed_, 0); + EXPECT_EQ(test_consumer.scroll_gestures_consumed_, 0); + + // Push a Metrics gesture into the interpreter + interpreter->ConsumeGesture(Gesture(kGestureMetrics, 0, 0, + kGestureMetricsTypeMouseMovement, + 0, 0)); + + // Verify it was detected + EXPECT_EQ(test_consumer.metric_gestures_consumed_, 1); + EXPECT_EQ(test_consumer.scroll_gestures_consumed_, 0); + + // Push a Scroll gesture into the interpreter + interpreter->ConsumeGesture(Gesture(kGestureScroll, 0, 0, 0, 0)); + + // Verify it was detected + EXPECT_EQ(test_consumer.metric_gestures_consumed_, 1); + EXPECT_EQ(test_consumer.scroll_gestures_consumed_, 1); +} + } // namespace gestures diff --git a/src/metrics_filter_interpreter.cc b/src/metrics_filter_interpreter.cc index 02b536e..d5adf9c 100644 --- a/src/metrics_filter_interpreter.cc +++ b/src/metrics_filter_interpreter.cc @@ -43,6 +43,9 @@ MetricsFilterInterpreter::MetricsFilterInterpreter( void MetricsFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { + const char name[] = "MetricsFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + if (devclass_ == GESTURES_DEVCLASS_TOUCHPAD) { // Right now, we only want to update finger states for built-in touchpads // because all the generated metrics gestures would be put under each @@ -61,6 +64,8 @@ void MetricsFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, devclass_ == GESTURES_DEVCLASS_POINTING_STICK) { UpdateMouseMovementState(hwstate); } + + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } diff --git a/src/metrics_filter_interpreter_unittest.cc b/src/metrics_filter_interpreter_unittest.cc index a7ede0a..f078aa3 100644 --- a/src/metrics_filter_interpreter_unittest.cc +++ b/src/metrics_filter_interpreter_unittest.cc @@ -9,6 +9,22 @@ namespace gestures { +namespace { + +const HardwareProperties hwprops = { + .right = 100, .bottom = 100, + .res_x = 1, .res_y = 1, + .screen_x_dpi = 0, .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 1, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, +}; + +} // namespace + class MetricsFilterInterpreterTest : public ::testing::Test {}; class MetricsFilterInterpreterTestInterpreter : public Interpreter { @@ -37,17 +53,6 @@ TEST(MetricsFilterInterpreterTest, SimpleTestTouchpad) { MetricsFilterInterpreter interpreter(nullptr, base_interpreter, nullptr, GESTURES_DEVCLASS_TOUCHPAD); - HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, 1, // x res (pixels/mm), y res (pixels/mm) - 1, 1, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 5, 5, // max fingers, max_touch, - 0, 0, 1, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad - }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); EXPECT_FALSE(base_interpreter->handle_timer_called_); @@ -117,17 +122,6 @@ TEST(MetricsFilterInterpreterTest, SimpleTestMultitouchMouse) { MetricsFilterInterpreter interpreter(nullptr, base_interpreter, nullptr, GESTURES_DEVCLASS_MULTITOUCH_MOUSE); - HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, 1, // x res (pixels/mm), y res (pixels/mm) - 1, 1, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 5, 5, // max fingers, max_touch, - 0, 0, 1, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad - }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); EXPECT_FALSE(base_interpreter->handle_timer_called_); @@ -197,17 +191,6 @@ TEST(MetricsFilterInterpreterTest, SimpleTestPointingStick) { MetricsFilterInterpreter interpreter(nullptr, base_interpreter, nullptr, GESTURES_DEVCLASS_POINTING_STICK); - HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, 1, // x res (pixels/mm), y res (pixels/mm) - 1, 1, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 5, 5, // max fingers, max_touch, - 0, 0, 1, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad - }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); EXPECT_FALSE(base_interpreter->handle_timer_called_); diff --git a/src/mouse_interpreter.cc b/src/mouse_interpreter.cc index 3518b98..6ed44e7 100644 --- a/src/mouse_interpreter.cc +++ b/src/mouse_interpreter.cc @@ -63,6 +63,9 @@ MouseInterpreter::MouseInterpreter(PropRegistry* prop_reg, Tracer* tracer) void MouseInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { + const char name[] = "MouseInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + if(!EmulateScrollWheel(hwstate)) { // Interpret mouse events in the order of pointer moves, scroll wheels and // button clicks. @@ -78,6 +81,8 @@ void MouseInterpreter::SyncInterpretImpl(HardwareState& hwstate, // Pass max_finger_cnt = 0 to DeepCopy() since we don't care fingers and // did not allocate any space for fingers. prev_state_.DeepCopy(hwstate, 0); + + LogHardwareStatePost(name, hwstate); } double MouseInterpreter::ComputeScrollAccelFactor(double input_speed) { @@ -96,9 +101,10 @@ double MouseInterpreter::ComputeScrollAccelFactor(double input_speed) { } bool MouseInterpreter::EmulateScrollWheel(const HardwareState& hwstate) { + const char name[] = "MouseInterpreter::EmulateScrollWheel"; + if (!force_scroll_wheel_emulation_.val_ && hwprops_->has_wheel) return false; - bool down = hwstate.buttons_down & GESTURES_BUTTON_MIDDLE || (hwstate.buttons_down & GESTURES_BUTTON_LEFT && hwstate.buttons_down & GESTURES_BUTTON_RIGHT); @@ -117,12 +123,14 @@ bool MouseInterpreter::EmulateScrollWheel(const HardwareState& hwstate) { // Send button event if button has been released without scrolling. if (falling && !wheel_emulation_active_) { - ProduceGesture(Gesture(kGestureButtonsChange, + auto button_change = Gesture(kGestureButtonsChange, prev_state_.timestamp, hwstate.timestamp, prev_state_.buttons_down, prev_state_.buttons_down, - false)); // is_tap + false); // is_tap + LogGestureProduce(name, button_change); + ProduceGesture(button_change); } if (down) { @@ -144,8 +152,11 @@ bool MouseInterpreter::EmulateScrollWheel(const HardwareState& hwstate) { if (wheel_emulation_active_) { double scroll_x = hwstate.rel_x * scroll_wheel_emulation_speed_.val_; double scroll_y = hwstate.rel_y * scroll_wheel_emulation_speed_.val_; - ProduceGesture(Gesture(kGestureScroll, hwstate.timestamp, - hwstate.timestamp, scroll_x, scroll_y)); + + auto scroll = Gesture(kGestureScroll, hwstate.timestamp, + hwstate.timestamp, scroll_x, scroll_y); + LogGestureProduce(name, scroll); + ProduceGesture(scroll); } return true; } @@ -155,6 +166,8 @@ bool MouseInterpreter::EmulateScrollWheel(const HardwareState& hwstate) { void MouseInterpreter::InterpretScrollWheelEvent(const HardwareState& hwstate, bool is_vertical) { + const char name[] = "MouseInterpreter::InterpretScrollWheelEvent"; + const float scroll_wheel_event_time_delta_min = 0.008; bool use_high_resolution = is_vertical && hwprops_->wheel_is_hi_res @@ -200,9 +213,7 @@ void MouseInterpreter::InterpretScrollWheelEvent(const HardwareState& hwstate, // When scroll acceleration is off, the scroll factor does not relate to // scroll velocity. It's simply a constant multiplier to the wheel value. - // TODO(zhangwenyu): This is gated behind a flag in settings and final - // values will be updated after some experimentations. - const double unaccel_scroll_factors[] = { 8.0, 20.0, 36.0, 64.0, 108.0 }; + const double unaccel_scroll_factors[] = { 20.0, 36.0, 72.0, 112.0, 164.0 }; float velocity = current_wheel_value / dt; float offset = current_wheel_value * ( @@ -218,11 +229,15 @@ void MouseInterpreter::InterpretScrollWheelEvent(const HardwareState& hwstate, offset = -offset; ticks = -ticks; } - ProduceGesture( - CreateWheelGesture(start_time, end_time, 0, offset, 0, ticks)); + auto scroll_wheel = CreateWheelGesture(start_time, end_time, + 0, offset, 0, ticks); + LogGestureProduce(name, scroll_wheel); + ProduceGesture(scroll_wheel); } else { - ProduceGesture( - CreateWheelGesture(start_time, end_time, offset, 0, ticks, 0)); + auto scroll_wheel = CreateWheelGesture(start_time, end_time, + offset, 0, ticks, 0); + LogGestureProduce(name, scroll_wheel); + ProduceGesture(scroll_wheel); } } } @@ -240,12 +255,16 @@ Gesture MouseInterpreter::CreateWheelGesture( void MouseInterpreter::InterpretMouseButtonEvent( const HardwareState& prev_state, const HardwareState& hwstate) { + const char name[] = "MouseInterpreter::InterpretMouseButtonEvent"; + const unsigned buttons[] = { GESTURES_BUTTON_LEFT, GESTURES_BUTTON_MIDDLE, GESTURES_BUTTON_RIGHT, GESTURES_BUTTON_BACK, - GESTURES_BUTTON_FORWARD + GESTURES_BUTTON_FORWARD, + GESTURES_BUTTON_SIDE, + GESTURES_BUTTON_EXTRA, }; unsigned down = 0, up = 0; @@ -259,24 +278,30 @@ void MouseInterpreter::InterpretMouseButtonEvent( } if (down || up) { - ProduceGesture(Gesture(kGestureButtonsChange, - prev_state.timestamp, - hwstate.timestamp, - down, - up, - false)); // is_tap + auto button_change = Gesture(kGestureButtonsChange, + prev_state.timestamp, + hwstate.timestamp, + down, + up, + false); // is_tap + LogGestureProduce(name, button_change); + ProduceGesture(button_change); } } void MouseInterpreter::InterpretMouseMotionEvent( const HardwareState& prev_state, const HardwareState& hwstate) { + const char name[] = "MouseInterpreter::InterpretMouseMotionEvent"; + if (hwstate.rel_x || hwstate.rel_y) { - ProduceGesture(Gesture(kGestureMove, - prev_state.timestamp, - hwstate.timestamp, - hwstate.rel_x, - hwstate.rel_y)); + auto move = Gesture(kGestureMove, + prev_state.timestamp, + hwstate.timestamp, + hwstate.rel_x, + hwstate.rel_y); + LogGestureProduce(name, move); + ProduceGesture(move); } } diff --git a/src/mouse_interpreter_unittest.cc b/src/mouse_interpreter_unittest.cc index b2d644c..57267d8 100644 --- a/src/mouse_interpreter_unittest.cc +++ b/src/mouse_interpreter_unittest.cc @@ -14,10 +14,22 @@ namespace gestures { HardwareProperties make_hwprops_for_mouse( unsigned has_wheel, unsigned wheel_is_hi_res) { return { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // touch-specific properties - has_wheel, - wheel_is_hi_res, - 0, // is_haptic_pad + .right = 0, + .bottom = 0, + .res_x = 0, + .res_y = 0, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = 0, + .orientation_maximum = 0, + .max_finger_cnt = 0, + .max_touch_cnt = 0, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 0, + .has_wheel = has_wheel, + .wheel_is_hi_res = wheel_is_hi_res, + .is_haptic_pad = 0, }; } @@ -277,4 +289,94 @@ TEST(MouseInterpreterTest, WheelTickReportingLowResTest) { EXPECT_EQ( 0, gs->details.wheel.tick_120ths_dy); } +TEST(MouseInterpreterTest, EmulateScrollWheelTest) { + HardwareProperties hwprops = make_hwprops_for_mouse(0, 0); + MouseInterpreter mi(nullptr, nullptr); + TestInterpreterWrapper wrapper(&mi, &hwprops); + Gesture* gs; + + HardwareState hwstates[] = { + { 200000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 }, + { 210000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 9, -7, 0, 0, 0, 0.0 }, + { 220000, GESTURES_BUTTON_LEFT, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 }, + { 230000, GESTURES_BUTTON_LEFT + GESTURES_BUTTON_RIGHT, 0, 0, nullptr, + 0, 0, 0, 0, 0, 0.0 }, + { 240000, GESTURES_BUTTON_LEFT + GESTURES_BUTTON_RIGHT, 0, 0, nullptr, + 2, 2, 0, 0, 0, 0.0 }, + { 250000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 }, + { 260000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 9, -7, 0, 0, 0, 0.0 }, + { 270000, GESTURES_BUTTON_MIDDLE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 }, + { 280000, GESTURES_BUTTON_MIDDLE, 0, 0, nullptr, 0, 0, 0, 0, 0, 0.0 }, + { 290000, GESTURES_BUTTON_NONE, 0, 0, nullptr, 0, 0, -3, -360, 4, 0.0 }, + }; + + mi.output_mouse_wheel_gestures_.val_ = true; + + gs = wrapper.SyncInterpret(hwstates[0], nullptr); + EXPECT_EQ(nullptr, gs); + + gs = wrapper.SyncInterpret(hwstates[1], nullptr); + ASSERT_NE(nullptr, gs); + EXPECT_EQ(kGestureTypeMove, gs->type); + EXPECT_EQ(9, gs->details.move.dx); + EXPECT_EQ(-7, gs->details.move.dy); + EXPECT_EQ(200000, gs->start_time); + EXPECT_EQ(210000, gs->end_time); + + gs = wrapper.SyncInterpret(hwstates[2], nullptr); + ASSERT_NE(nullptr, gs); + EXPECT_EQ(kGestureTypeButtonsChange, gs->type); + EXPECT_EQ(1, gs->details.buttons.down); + EXPECT_EQ(0, gs->details.buttons.up); + EXPECT_EQ(210000, gs->start_time); + EXPECT_EQ(220000, gs->end_time); + + gs = wrapper.SyncInterpret(hwstates[3], nullptr); + ASSERT_EQ(nullptr, gs); + + // Temporarily adjust the threshold to force wheel_emulation_active_ + auto thresh = mi.scroll_wheel_emulation_thresh_.val_; + mi.scroll_wheel_emulation_thresh_.val_ = 0.1; + EXPECT_FALSE(mi.wheel_emulation_active_); + gs = wrapper.SyncInterpret(hwstates[4], nullptr); + EXPECT_TRUE(mi.wheel_emulation_active_); + ASSERT_NE(nullptr, gs); + EXPECT_EQ(kGestureTypeScroll, gs->type); + EXPECT_EQ(200, gs->details.scroll.dx); + EXPECT_EQ(200, gs->details.scroll.dy); + EXPECT_EQ(240000, gs->start_time); + EXPECT_EQ(240000, gs->end_time); + mi.scroll_wheel_emulation_thresh_.val_ = thresh; + + gs = wrapper.SyncInterpret(hwstates[5], nullptr); + ASSERT_NE(nullptr, gs); + EXPECT_EQ(kGestureTypeButtonsChange, gs->type); + EXPECT_EQ(0, gs->details.buttons.down); + EXPECT_EQ(5, gs->details.buttons.up); + EXPECT_EQ(240000, gs->start_time); + EXPECT_EQ(250000, gs->end_time); + + gs = wrapper.SyncInterpret(hwstates[6], nullptr); + ASSERT_NE(nullptr, gs); + EXPECT_EQ(kGestureTypeMove, gs->type); + EXPECT_EQ(9, gs->details.move.dx); + EXPECT_EQ(-7, gs->details.move.dy); + EXPECT_EQ(250000, gs->start_time); + EXPECT_EQ(260000, gs->end_time); + + gs = wrapper.SyncInterpret(hwstates[7], nullptr); + ASSERT_EQ(nullptr, gs); + + gs = wrapper.SyncInterpret(hwstates[8], nullptr); + ASSERT_EQ(nullptr, gs); + + gs = wrapper.SyncInterpret(hwstates[9], nullptr); + ASSERT_NE(nullptr, gs); + EXPECT_EQ(kGestureTypeButtonsChange, gs->type); + EXPECT_EQ(0, gs->details.buttons.down); + EXPECT_EQ(2, gs->details.buttons.up); + EXPECT_EQ(280000, gs->start_time); + EXPECT_EQ(290000, gs->end_time); +} + } // namespace gestures diff --git a/src/multitouch_mouse_interpreter.cc b/src/multitouch_mouse_interpreter.cc index e4163f2..18974ea 100644 --- a/src/multitouch_mouse_interpreter.cc +++ b/src/multitouch_mouse_interpreter.cc @@ -62,7 +62,10 @@ void MultitouchMouseInterpreter::ProduceGesture(const Gesture& gesture) { void MultitouchMouseInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { - if (!state_buffer_.Get(0)->fingers) { + const char name[] = "MultitouchMouseInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + + if (!state_buffer_.Get(0).fingers) { Err("Must call SetHardwareProperties() before interpreting anything."); return; } @@ -107,15 +110,15 @@ void MultitouchMouseInterpreter::SyncInterpretImpl(HardwareState& hwstate, // TODO(clchiou): Remove palm and thumb. gs_fingers_.clear(); size_t num_fingers = std::min(kMaxGesturingFingers, - (size_t)state_buffer_.Get(0)->finger_cnt); - const FingerState* fs = state_buffer_.Get(0)->fingers; + (size_t)state_buffer_.Get(0).finger_cnt); + const FingerState* fs = state_buffer_.Get(0).fingers; for (size_t i = 0; i < num_fingers; i++) gs_fingers_.insert(fs[i].tracking_id); InterpretScrollWheelEvent(hwstate, true); InterpretScrollWheelEvent(hwstate, false); - InterpretMouseButtonEvent(prev_state_, *state_buffer_.Get(0)); - InterpretMouseMotionEvent(prev_state_, *state_buffer_.Get(0)); + InterpretMouseButtonEvent(prev_state_, state_buffer_.Get(0)); + InterpretMouseMotionEvent(prev_state_, state_buffer_.Get(0)); bool should_interpret_multitouch = true; @@ -124,26 +127,24 @@ void MultitouchMouseInterpreter::SyncInterpretImpl(HardwareState& hwstate, // was rel data, and the previous finger data exactly matches this finger // data, we remove the last hardware state from our buffer. This is okay // because we already processed the rel data. - if (state_buffer_.Get(0) && state_buffer_.Get(1)) { - HardwareState* prev_hs = state_buffer_.Get(1); - HardwareState* cur_hs = state_buffer_.Get(0); - bool cur_has_rel = cur_hs->rel_x || cur_hs->rel_y || - cur_hs->rel_wheel || cur_hs->rel_hwheel; - bool different_fingers = prev_hs->touch_cnt != cur_hs->touch_cnt || - prev_hs->finger_cnt != cur_hs->finger_cnt; - if (!different_fingers && cur_has_rel) { - // Compare actual fingers themselves - for (size_t i = 0; i < cur_hs->finger_cnt; i++) { - if (!cur_hs->fingers[i].NonFlagsEquals(prev_hs->fingers[i])) { - different_fingers = true; - break; - } - } - if (!different_fingers) { - state_buffer_.PopState(); - should_interpret_multitouch = false; + const HardwareState& prev_hs = state_buffer_.Get(1); + const HardwareState& cur_hs = state_buffer_.Get(0); + bool cur_has_rel = cur_hs.rel_x || cur_hs.rel_y || + cur_hs.rel_wheel || cur_hs.rel_hwheel; + bool different_fingers = prev_hs.touch_cnt != cur_hs.touch_cnt || + prev_hs.finger_cnt != cur_hs.finger_cnt; + if (!different_fingers && cur_has_rel) { + // Compare actual fingers themselves + for (size_t i = 0; i < cur_hs.finger_cnt; i++) { + if (!cur_hs.fingers[i].NonFlagsEquals(prev_hs.fingers[i])) { + different_fingers = true; + break; } } + if (!different_fingers) { + state_buffer_.PopState(); + should_interpret_multitouch = false; + } } if (should_interpret_multitouch) @@ -156,6 +157,8 @@ void MultitouchMouseInterpreter::SyncInterpretImpl(HardwareState& hwstate, prev_gs_fingers_ = gs_fingers_; prev_gesture_type_ = current_gesture_type_; + + LogHardwareStatePost(name, hwstate); } void MultitouchMouseInterpreter::Initialize( @@ -168,10 +171,12 @@ void MultitouchMouseInterpreter::Initialize( } void MultitouchMouseInterpreter::InterpretMultitouchEvent() { + const char name[] = "MultitouchMouseInterpreter::InterpretMultitouchEvent"; + Gesture result; // If a gesturing finger just left, do fling/lift - if (should_fling_ && AnyGesturingFingerLeft(*state_buffer_.Get(0), + if (should_fling_ && AnyGesturingFingerLeft(state_buffer_.Get(0), prev_gs_fingers_)) { current_gesture_type_ = kGestureTypeFling; scroll_manager_.FillResultFling(state_buffer_, scroll_buffer_, &result); @@ -207,7 +212,7 @@ void MultitouchMouseInterpreter::InterpretMultitouchEvent() { should_fling_ = true; bool hold_off_scroll = false; - const HardwareState& state = *state_buffer_.Get(0); + const HardwareState& state = state_buffer_.Get(0); // Check small finger movements when button is down if (state.buttons_down) { float dist_sq, dt; @@ -236,8 +241,10 @@ void MultitouchMouseInterpreter::InterpretMultitouchEvent() { } scroll_manager_.UpdateScrollEventBuffer(current_gesture_type_, &scroll_buffer_); - if (result.type != kGestureTypeNull) + if (result.type != kGestureTypeNull) { + LogGestureProduce(name, result); ProduceGesture(result); + } prev_result_ = result; } diff --git a/src/multitouch_mouse_interpreter_unittest.cc b/src/multitouch_mouse_interpreter_unittest.cc index 48bba29..ba23e40 100644 --- a/src/multitouch_mouse_interpreter_unittest.cc +++ b/src/multitouch_mouse_interpreter_unittest.cc @@ -18,16 +18,17 @@ TEST(MultitouchMouseInterpreterTest, SimpleTest) { Gesture* gs; HardwareProperties hwprops = { - 133, 728, 10279, 5822, // left, top, right, bottom - (10279.0 - 133.0) / 100.0, // x res (pixels/mm) - (5822.0 - 728.0) / 60, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .left = 133, .top = 728, .right = 10279, .bottom = 5822, + .res_x = (10279.0 - 133.0) / 100.0, + .res_y = (5822.0 - 728.0) / 60, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&mi, &hwprops); diff --git a/src/non_linearity_filter_interpreter.cc b/src/non_linearity_filter_interpreter.cc index 658ba61..df0e765 100644 --- a/src/non_linearity_filter_interpreter.cc +++ b/src/non_linearity_filter_interpreter.cc @@ -112,6 +112,9 @@ abort_load: void NonLinearityFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { + const char name[] = "NonLinearityFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + if (enabled_.val_ && err_.get() && hwstate.finger_cnt == 1) { FingerState* finger = &(hwstate.fingers[0]); if (finger) { @@ -121,6 +124,7 @@ void NonLinearityFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, finger->position_y -= error.y_error; } } + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } diff --git a/src/palm_classifying_filter_interpreter.cc b/src/palm_classifying_filter_interpreter.cc index 808aca0..1551f94 100644 --- a/src/palm_classifying_filter_interpreter.cc +++ b/src/palm_classifying_filter_interpreter.cc @@ -45,12 +45,17 @@ PalmClassifyingFilterInterpreter::PalmClassifyingFilterInterpreter( void PalmClassifyingFilterInterpreter::SyncInterpretImpl( HardwareState& hwstate, stime_t* timeout) { + const char name[] = "PalmClassifyingFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + FillOriginInfo(hwstate); FillMaxPressureWidthInfo(hwstate); UpdateDistanceInfo(hwstate); UpdatePalmState(hwstate); UpdatePalmFlags(hwstate); FillPrevInfo(hwstate); + + LogHardwareStatePost(name, hwstate); if (next_.get()) next_->SyncInterpret(hwstate, timeout); } @@ -186,6 +191,11 @@ void PalmClassifyingFilterInterpreter::UpdatePalmState( pointing_.erase(fs.tracking_id); continue; } + // Mark externally reported palms + if(fs.tool_type == FingerState::ToolType::kPalm){ + palm_.insert(fs.tracking_id); + pointing_.erase(fs.tracking_id); + } } if (hwstate.finger_cnt == 1 && diff --git a/src/palm_classifying_filter_interpreter_unittest.cc b/src/palm_classifying_filter_interpreter_unittest.cc index 4d814ff..61c1c88 100644 --- a/src/palm_classifying_filter_interpreter_unittest.cc +++ b/src/palm_classifying_filter_interpreter_unittest.cc @@ -12,6 +12,7 @@ #include "include/gestures.h" #include "include/palm_classifying_filter_interpreter.h" +#include "include/string_util.h" #include "include/unittest_util.h" #include "include/util.h" @@ -46,24 +47,22 @@ class PalmClassifyingFilterInterpreterTestInterpreter : public Interpreter { TEST(PalmClassifyingFilterInterpreterTest, PalmTest) { PalmClassifyingFilterInterpreter pci(nullptr, nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 1000, // right edge - 1000, // bottom edge - 500, // x pixels/TP width - 500, // y pixels/TP height - 96, // x screen DPI - 96, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 2, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 1000, + .bottom = 1000, + .res_x = 500, + .res_y = 500, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&pci, &hwprops); @@ -123,27 +122,89 @@ TEST(PalmClassifyingFilterInterpreterTest, PalmTest) { } } +TEST(PalmClassifyingFilterInterpreterTest, ExternallyMarkedPalmTest) { + PalmClassifyingFilterInterpreterTestInterpreter* base_interpreter = + new PalmClassifyingFilterInterpreterTestInterpreter; + PalmClassifyingFilterInterpreter pci(nullptr, base_interpreter, nullptr); + HardwareProperties hwprops = { + .right = 1000, + .bottom = 1000, + .res_x = 500, + .res_y = 500, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, + }; + + TestInterpreterWrapper wrapper(&pci, &hwprops); + + const float kPr = pci.palm_pressure_.val_ / 2; + + FingerState finger_states[] = { + // TM, Tm, WM, Wm, Press, Orientation, X, Y, TrID, flags, ToolType + {0, 0, 0, 0, kPr, 0, 600, 500, 1, 0}, + {0, 0, 0, 0, kPr, 0, 600, 500, 1, 0}, + // mark the touch as palm + {0, 0, 0, 0, kPr, 0, 600, 500, 1, 0, FingerState::ToolType::kPalm}, + {0, 0, 0, 0, kPr, 0, 600, 500, 1, 0, FingerState::ToolType::kPalm}, + }; + HardwareState hardware_state[] = { + // time, buttons, finger count, touch count, finger states pointer + make_hwstate(0.00, 0, 1, 1, &finger_states[0]), + make_hwstate(4.00, 0, 1, 1, &finger_states[1]), + make_hwstate(5.00, 0, 1, 1, &finger_states[2]), + make_hwstate(5.01, 0, 1, 1, &finger_states[3]), + }; + + for (size_t i = 0; i < arraysize(hardware_state); ++i) { + SCOPED_TRACE(StringPrintf("i = %zu", i)); + if(i > 1) { + base_interpreter->expected_flags_ = GESTURES_FINGER_PALM; + } + else { + base_interpreter->expected_flags_ = 0; + } + wrapper.SyncInterpret(hardware_state[i], nullptr); + if (i > 1) { + // After the second frame finger is marked as palm + EXPECT_FALSE(SetContainsValue(pci.pointing_, 1)); + EXPECT_TRUE(SetContainsValue(pci.palm_, 1)); + } + else { + EXPECT_TRUE(SetContainsValue(pci.pointing_, 1)); + EXPECT_FALSE(SetContainsValue(pci.palm_, 1)); + } + } +} + TEST(PalmClassifyingFilterInterpreterTest, StationaryPalmTest) { PalmClassifyingFilterInterpreter pci(nullptr, nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // x pixels/TP width - 1, // y pixels/TP height - 1, // x screen DPI - 1, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 5, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&pci, &hwprops); @@ -187,24 +248,22 @@ TEST(PalmClassifyingFilterInterpreterTest, PalmAtEdgeTest) { std::unique_ptr<PalmClassifyingFilterInterpreter> pci( new PalmClassifyingFilterInterpreter(nullptr, nullptr, nullptr)); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // x pixels/mm - 1, // y pixels/mm - 1, // x screen px/mm - 1, // y screen px/mm - -1, // orientation minimum - 2, // orientation maximum - 5, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(pci.get(), &hwprops); @@ -316,24 +375,22 @@ struct PalmReevaluateTestInputs { TEST(PalmClassifyingFilterInterpreterTest, PalmReevaluateTest) { PalmClassifyingFilterInterpreter pci(nullptr, nullptr, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 106.666672, // right edge - 68.000000, // bottom edge - 1, // pixels/TP width - 1, // pixels/TP height - 25.4, // screen DPI x - 25.4, // screen DPI y - -1, // orientation minimum - 2, // orientation maximum - 15, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - true, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - false, // is haptic pad + .right = 106.666672, + .bottom = 68.000000, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 15, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = true, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = false, }; TestInterpreterWrapper wrapper(&pci, &hwprops); @@ -407,24 +464,22 @@ TEST(PalmClassifyingFilterInterpreterTest, LargeTouchMajorTest) { new PalmClassifyingFilterInterpreterTestInterpreter; PalmClassifyingFilterInterpreter pci(nullptr, base_interpreter, nullptr); HardwareProperties hwprops = { - 0, // left edge - 0, // top edge - 100, // right edge - 100, // bottom edge - 1, // x pixels/mm - 1, // y pixels/mm - 1, // x screen px/mm - 1, // y screen px/mm - -1, // orientation minimum - 2, // orientation maximum - 5, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 100, + .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&pci, &hwprops); diff --git a/src/scaling_filter_interpreter.cc b/src/scaling_filter_interpreter.cc index aa04b20..6045801 100644 --- a/src/scaling_filter_interpreter.cc +++ b/src/scaling_filter_interpreter.cc @@ -55,7 +55,12 @@ ScalingFilterInterpreter::ScalingFilterInterpreter( void ScalingFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { + const char name[] = "ScalingFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + ScaleHardwareState(hwstate); + + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } @@ -214,6 +219,9 @@ void ScalingFilterInterpreter::ScaleTouchpadHardwareState( } void ScalingFilterInterpreter::ConsumeGesture(const Gesture& gs) { + const char name[] = "ScalingFilterInterpreter::ConsumeGesture"; + LogGestureConsume(name, gs); + Gesture copy = gs; switch (copy.type) { case kGestureTypeMove: { @@ -310,6 +318,8 @@ void ScalingFilterInterpreter::ConsumeGesture(const Gesture& gs) { default: break; } + + LogGestureProduce(name, copy); ProduceGesture(copy); } diff --git a/src/scaling_filter_interpreter_unittest.cc b/src/scaling_filter_interpreter_unittest.cc index a42eb1b..6d1c529 100644 --- a/src/scaling_filter_interpreter_unittest.cc +++ b/src/scaling_filter_interpreter_unittest.cc @@ -98,8 +98,6 @@ class ScalingFilterInterpreterTestInterpreter : public Interpreter { EXPECT_FLOAT_EQ(expected_hwprops_.bottom, hw_props->bottom); EXPECT_FLOAT_EQ(expected_hwprops_.res_x, hw_props->res_x); EXPECT_FLOAT_EQ(expected_hwprops_.res_y, hw_props->res_y); - EXPECT_FLOAT_EQ(expected_hwprops_.screen_x_dpi, hw_props->screen_x_dpi); - EXPECT_FLOAT_EQ(expected_hwprops_.screen_y_dpi, hw_props->screen_y_dpi); EXPECT_FLOAT_EQ(expected_hwprops_.orientation_minimum, hw_props->orientation_minimum); EXPECT_FLOAT_EQ(expected_hwprops_.orientation_maximum, @@ -132,25 +130,30 @@ TEST(ScalingFilterInterpreterTest, SimpleTest) { ScalingFilterInterpreter interpreter(nullptr, base_interpreter, nullptr, GESTURES_DEVCLASS_TOUCHPAD); HardwareProperties initial_hwprops = { - 133, 728, 10279, 5822, // left, top, right, bottom - (10279.0 - 133.0) / 100.0, // x res (pixels/mm) - (5822.0 - 728.0) / 60, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .left = 133, .top = 728, .right = 10279, .bottom = 5822, + .res_x = (10279.0 - 133.0) / 100.0, + .res_y = (5822.0 - 728.0) / 60, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; HardwareProperties expected_hwprops = { - 0, 0, 100, 60, // left, top, right, bottom - 1.0, 1.0, 25.4, 25.4, // x res, y res, x DPI, y DPI - -M_PI_4, // orientation minimum (1 tick above X-axis) - M_PI_2, // orientation maximum - 2, 5, 0, 0, 0, // max_fingers, max_touch, t5r2, semi_mt, is button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // is haptic pad + .right = 100, .bottom = 60, + .res_x = 1.0, + .res_y = 1.0, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -M_PI_4, // (1 tick above X-axis) + .orientation_maximum = M_PI_2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; base_interpreter->expected_hwprops_ = expected_hwprops; @@ -278,25 +281,26 @@ TEST(ScalingFilterInterpreterTest, ResolutionFallback) { ScalingFilterInterpreter interpreter(nullptr, base_interpreter, nullptr, GESTURES_DEVCLASS_TOUCHPAD); HardwareProperties initial_hwprops = { - 0, 0, 2000, 1000, // left, top, right, bottom - 0, 0, // X/Y resolutions (pixels/mm) - 0, 0, // screen DPI X, Y (deprecated) - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 2000, .bottom = 1000, + .res_x = 0, .res_y = 0, + .screen_x_dpi = 0, .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; HardwareProperties expected_hwprops = { - 0, 0, 2000 / 32.0, 1000 / 32.0, // left, top, right, bottom - 1, 1, // X/Y resolutions (pixels/mm) - 25.4, 25.4, // x DPI, y DPI - -M_PI_4, // orientation minimum (1 tick above X-axis) - M_PI_2, // orientation maximum - 2, 5, 0, 0, 0, // max_fingers, max_touch, t5r2, semi_mt, is button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // is haptic pad + .right = 2000 / 32.0, .bottom = 1000 / 32.0, + .res_x = 1, .res_y = 1, + .screen_x_dpi = 0, .screen_y_dpi = 0, + .orientation_minimum = -M_PI_4, // (1 tick above X-axis) + .orientation_maximum = M_PI_2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; base_interpreter->expected_hwprops_ = expected_hwprops; @@ -429,25 +433,28 @@ TEST(ScalingFilterInterpreterTest, TouchMajorAndMinorTest) { interpreter.tp_y_bias_.val_ = e_y; HardwareProperties hwprops = { - 0, 0, 500, 1000, // left, top, right, bottom - 5, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -31, // orientation minimum - 32, // orientation maximum - 2, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 1, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 500, .bottom = 1000, + .res_x = 5, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -31, + .orientation_maximum = 32, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 1, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; HardwareProperties expected_hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1.0, 1.0, 25.4, 25.4, // x res, y res, x DPI, y DPI - -M_PI * 31 / 64, // orientation minimum (1 tick above X-axis) - M_PI_2, // orientation maximum - 2, 5, 0, 0, 0, // max_fingers, max_touch, t5r2, semi_mt, button pad - 1, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 1.0, .res_y = 1.0, + .screen_x_dpi = 0, .screen_y_dpi = 0, + .orientation_minimum = -M_PI * 31 / 64, // (1 tick above X-axis) + .orientation_maximum = M_PI_2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 1, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; // Test 1: Touch major and touch minor scaling with orientation diff --git a/src/sensor_jump_filter_interpreter.cc b/src/sensor_jump_filter_interpreter.cc index 4f327d8..2044541 100644 --- a/src/sensor_jump_filter_interpreter.cc +++ b/src/sensor_jump_filter_interpreter.cc @@ -32,6 +32,9 @@ SensorJumpFilterInterpreter::SensorJumpFilterInterpreter(PropRegistry* prop_reg, void SensorJumpFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, stime_t* timeout) { + const char name[] = "SensorJumpFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + if (!enabled_.val_) { next_->SyncInterpret(hwstate, timeout); return; @@ -130,6 +133,7 @@ void SensorJumpFilterInterpreter::SyncInterpretImpl(HardwareState& hwstate, previous_input_[1] = previous_input_[0]; previous_input_[0] = current_input; + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } diff --git a/src/sensor_jump_filter_interpreter_unittest.cc b/src/sensor_jump_filter_interpreter_unittest.cc index 3caf3c4..64a13e5 100644 --- a/src/sensor_jump_filter_interpreter_unittest.cc +++ b/src/sensor_jump_filter_interpreter_unittest.cc @@ -59,15 +59,15 @@ TEST(SensorJumpFilterInterpreterTest, SimpleTest) { interpreter.enabled_.val_ = 1; HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, 1, // x res (pixels/mm), y res (pixels/mm) - 1, 1, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 5, 5, // max fingers, max_touch - 0, 0, 1, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 1, .res_y = 1, + .screen_x_dpi = 0, .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 1, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -122,15 +122,15 @@ TEST(SensorJumpFilterInterpreterTest, ActualLogTest) { interpreter.enabled_.val_ = 1; HardwareProperties hwprops = { - 0, 0, 106.666672, 68, // left, top, right, bottom - 1, 1, // x res (pixels/mm), y res (pixels/mm) - 25.4, 25.4, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 15, 5, // max fingers, max_touch, - 0, 0, 1, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 106.666672, .bottom = 68, + .res_x = 1, .res_y = 1, + .screen_x_dpi = 0, .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 15, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 1, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); diff --git a/src/split_correcting_filter_interpreter.cc b/src/split_correcting_filter_interpreter.cc index e1dcc30..2895d48 100644 --- a/src/split_correcting_filter_interpreter.cc +++ b/src/split_correcting_filter_interpreter.cc @@ -25,6 +25,9 @@ SplitCorrectingFilterInterpreter::SplitCorrectingFilterInterpreter( void SplitCorrectingFilterInterpreter::SyncInterpretImpl( HardwareState& hwstate, stime_t* timeout) { + const char name[] = "SplitCorrectingFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + // Update internal state if (enabled_.val_) { RemoveMissingUnmergedContacts(hwstate); @@ -36,6 +39,7 @@ void SplitCorrectingFilterInterpreter::SyncInterpretImpl( // Use internal state to update hwstate UpdateHwState(hwstate); } + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } diff --git a/src/split_correcting_filter_interpreter_unittest.cc b/src/split_correcting_filter_interpreter_unittest.cc index 3445bd9..a0c6ea8 100644 --- a/src/split_correcting_filter_interpreter_unittest.cc +++ b/src/split_correcting_filter_interpreter_unittest.cc @@ -70,21 +70,21 @@ void DoTest(InputEventWithExpectations* events, size_t events_len, bool t5r2) { interpreter.Enable(); HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, // res_x - 1, // res_y - 133, // screen_x_dpi - 133, // screen_y_dpi - -1, // orientation minimum - 2, // orientation maximum - 5, // max finger cnt - static_cast<unsigned short>(t5r2 ? 2 : 5), // max touch cnt - t5r2 ? 1u : 0u, // supports_t5r2 - 0, // support_semi_mt - 1, // is_button_pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is_haptic_pad + .right = 100, .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, + .max_touch_cnt = static_cast<unsigned short>(t5r2 ? 2 : 5), + .supports_t5r2 = t5r2 ? 1u : 0u, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -167,21 +167,21 @@ TEST(SplitCorrectingFilterInterpreterTest, FalseMergeTest) { interpreter.Enable(); HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, // res_x - 1, // res_y - 133, // screen_x_dpi - 133, // screen_y_dpi - -1, // orientation minimum - 2, // orientation maximum - 5, // max finger cnt - 5, // max touch cnt - 0, // supports_t5r2 - 0, // support_semi_mt - 1, // is_button_pad - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is_haptic_pad + .right = 100, .bottom = 100, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); @@ -323,24 +323,22 @@ TEST(SplitCorrectingFilterInterpreterTest, LumpyThumbSplitTest) { base_interpreter->expect_finger_ids_ = true; HardwareProperties hwprops = { - 0.0, // left edge - 0.0, // top edge - 106.666672, // right edge - 68.0, // bottom edge - 1.0, // x pixels/TP width - 1.0, // y pixels/TP height - 25.4, // x screen DPI - 25.4, // y screen DPI - -1, // orientation minimum - 2, // orientation maximum - 15, // max fingers - 5, // max touch - 0, // t5r2 - 0, // semi-mt - 1, // is button pad, - 0, // has_wheel - 0, // wheel_is_hi_res - 0, // is haptic pad + .right = 106.666672, + .bottom = 68.0, + .res_x = 1.0, + .res_y = 1.0, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 15, + .max_touch_cnt = 5, + .supports_t5r2 = 0, + .support_semi_mt = 0, + .is_button_pad = 1, + .has_wheel = 0, + .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); diff --git a/src/stationary_wiggle_filter_interpreter.cc b/src/stationary_wiggle_filter_interpreter.cc index bcde6e9..3ec85b1 100644 --- a/src/stationary_wiggle_filter_interpreter.cc +++ b/src/stationary_wiggle_filter_interpreter.cc @@ -110,8 +110,13 @@ StationaryWiggleFilterInterpreter::StationaryWiggleFilterInterpreter( void StationaryWiggleFilterInterpreter::SyncInterpretImpl( HardwareState& hwstate, stime_t* timeout) { + const char name[] = "StationaryWiggleFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + if (enabled_.val_) UpdateStationaryFlags(hwstate); + + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } diff --git a/src/stationary_wiggle_filter_interpreter_unittest.cc b/src/stationary_wiggle_filter_interpreter_unittest.cc index 2367e7e..1ac5e9b 100644 --- a/src/stationary_wiggle_filter_interpreter_unittest.cc +++ b/src/stationary_wiggle_filter_interpreter_unittest.cc @@ -59,15 +59,15 @@ TEST(StationaryWiggleFilterInterpreterTest, SimpleTest) { interpreter.enabled_.val_ = true; HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, 1, // x res (pixels/mm), y res (pixels/mm) - 1, 1, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 5, 5, // max fingers, max_touch, - 0, 0, 1, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 1, .res_y = 1, + .screen_x_dpi = 0, .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 1, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); diff --git a/src/stuck_button_inhibitor_filter_interpreter.cc b/src/stuck_button_inhibitor_filter_interpreter.cc index 4566ab2..d5b0999 100644 --- a/src/stuck_button_inhibitor_filter_interpreter.cc +++ b/src/stuck_button_inhibitor_filter_interpreter.cc @@ -20,14 +20,23 @@ StuckButtonInhibitorFilterInterpreter::StuckButtonInhibitorFilterInterpreter( void StuckButtonInhibitorFilterInterpreter::SyncInterpretImpl( HardwareState& hwstate, stime_t* timeout) { + const char name[] = + "StuckButtonInhibitorFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + HandleHardwareState(hwstate); + stime_t next_timeout = NO_DEADLINE; + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, &next_timeout); HandleTimeouts(next_timeout, timeout); } void StuckButtonInhibitorFilterInterpreter::HandleTimerImpl( stime_t now, stime_t* timeout) { + const char name[] = "StuckButtonInhibitorFilterInterpreter::HandleTimerImpl"; + LogHandleTimerPre(name, now, timeout); + stime_t next_timeout = NO_DEADLINE; if (next_expects_timer_) { next_->HandleTimer(now, &next_timeout); @@ -37,13 +46,16 @@ void StuckButtonInhibitorFilterInterpreter::HandleTimerImpl( return; } else { Err("Mouse button seems stuck down. Sending button-up."); - ProduceGesture(Gesture(kGestureButtonsChange, - now, now, 0, sent_buttons_down_, - false)); // is_tap + auto button_change = Gesture(kGestureButtonsChange, + now, now, 0, sent_buttons_down_, + false); // is_tap + LogGestureProduce(name, button_change); + ProduceGesture(button_change); sent_buttons_down_ = 0; } } HandleTimeouts(next_timeout, timeout); + LogHandleTimerPost(name, now, timeout); } void StuckButtonInhibitorFilterInterpreter::HandleHardwareState( @@ -54,6 +66,9 @@ void StuckButtonInhibitorFilterInterpreter::HandleHardwareState( void StuckButtonInhibitorFilterInterpreter::ConsumeGesture( const Gesture& gesture) { + const char name[] = "StuckButtonInhibitorFilterInterpreter::ConsumeGesture"; + LogGestureConsume(name, gesture); + if (gesture.type == kGestureTypeButtonsChange) { Gesture result = gesture; // process buttons going down @@ -73,8 +88,10 @@ void StuckButtonInhibitorFilterInterpreter::ConsumeGesture( sent_buttons_down_ &= ~result.details.buttons.up; if (!result.details.buttons.up && !result.details.buttons.down) return; // skip gesture + LogGestureProduce(name, result); ProduceGesture(result); } else { + LogGestureProduce(name, gesture); ProduceGesture(gesture); } } diff --git a/src/stuck_button_inhibitor_filter_interpreter_unittest.cc b/src/stuck_button_inhibitor_filter_interpreter_unittest.cc index e4fd50b..f983f28 100644 --- a/src/stuck_button_inhibitor_filter_interpreter_unittest.cc +++ b/src/stuck_button_inhibitor_filter_interpreter_unittest.cc @@ -79,16 +79,17 @@ TEST(StuckButtonInhibitorFilterInterpreterTest, SimpleTest) { StuckButtonInhibitorFilterInterpreter interpreter(base_interpreter, nullptr); HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 10, // x res (pixels/mm) - 10, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 10, + .res_y = 10, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); diff --git a/src/t5r2_correcting_filter_interpreter.cc b/src/t5r2_correcting_filter_interpreter.cc index 8fe8c60..30ebbd7 100644 --- a/src/t5r2_correcting_filter_interpreter.cc +++ b/src/t5r2_correcting_filter_interpreter.cc @@ -20,6 +20,9 @@ T5R2CorrectingFilterInterpreter::T5R2CorrectingFilterInterpreter( void T5R2CorrectingFilterInterpreter::SyncInterpretImpl( HardwareState& hwstate, stime_t* timeout) { + const char name[] = "T5R2CorrectingFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + if (touch_cnt_correct_enabled_.val_ && hwstate.finger_cnt == 0 && last_finger_cnt_ == 0 && hwstate.touch_cnt != 0 && hwstate.touch_cnt == last_touch_cnt_) { @@ -27,6 +30,8 @@ void T5R2CorrectingFilterInterpreter::SyncInterpretImpl( } last_touch_cnt_ = hwstate.touch_cnt; last_finger_cnt_ = hwstate.finger_cnt; + + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } diff --git a/src/t5r2_correcting_filter_interpreter_unittest.cc b/src/t5r2_correcting_filter_interpreter_unittest.cc index e6d6261..c297457 100644 --- a/src/t5r2_correcting_filter_interpreter_unittest.cc +++ b/src/t5r2_correcting_filter_interpreter_unittest.cc @@ -68,16 +68,17 @@ TEST(T5R2CorrectingFilterInterpreterTest, SimpleTest) { std::unique_ptr<T5R2CorrectingFilterInterpreter> interpreter; HardwareProperties hwprops = { - 0, 0, 10, 10, // left, top, right, bottom - 1, // x res (pixels/mm) - 1, // y res (pixels/mm) - 133, 133, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 2, 5, // max fingers, max_touch - 0, 0, 0, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 10, .bottom = 10, + .res_x = 1, + .res_y = 1, + .screen_x_dpi = 0, + .screen_y_dpi = 0, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 2, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 0, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(interpreter.get(), &hwprops); diff --git a/src/timestamp_filter_interpreter.cc b/src/timestamp_filter_interpreter.cc index ed5104d..b3d7bd6 100644 --- a/src/timestamp_filter_interpreter.cc +++ b/src/timestamp_filter_interpreter.cc @@ -26,23 +26,34 @@ TimestampFilterInterpreter::TimestampFilterInterpreter( void TimestampFilterInterpreter::SyncInterpretImpl( HardwareState& hwstate, stime_t* timeout) { + const char name[] = "TimestampFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + auto debug_data = ActivityLog::TimestampHardwareStateDebug{}; + if (fake_timestamp_delta_.val_ == 0.0) - ChangeTimestampDefault(hwstate); + ChangeTimestampDefault(hwstate, debug_data); else - ChangeTimestampUsingFake(hwstate); + ChangeTimestampUsingFake(hwstate, debug_data); + + LogDebugData(debug_data); + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } void TimestampFilterInterpreter::ChangeTimestampDefault( - HardwareState& hwstate) { + HardwareState& hwstate, + ActivityLog::TimestampHardwareStateDebug& debug_data) { // Check if this is the first event or there has been a jump backwards. + debug_data.prev_msc_timestamp_in = prev_msc_timestamp_; if (prev_msc_timestamp_ < 0.0 || hwstate.msc_timestamp == 0.0 || hwstate.msc_timestamp < prev_msc_timestamp_) { msc_timestamp_offset_ = hwstate.timestamp - hwstate.msc_timestamp; max_skew_ = 0.0; + debug_data.was_first_or_backward = true; } prev_msc_timestamp_ = hwstate.msc_timestamp; + debug_data.prev_msc_timestamp_out = prev_msc_timestamp_; stime_t new_timestamp = hwstate.msc_timestamp + msc_timestamp_offset_; skew_ = new_timestamp - hwstate.timestamp; @@ -50,34 +61,57 @@ void TimestampFilterInterpreter::ChangeTimestampDefault( hwstate.timestamp = new_timestamp; hwstate.msc_timestamp = 0.0; + debug_data.skew = skew_; + debug_data.max_skew = max_skew_; } void TimestampFilterInterpreter::ChangeTimestampUsingFake( - HardwareState& hwstate) { + HardwareState& hwstate, + ActivityLog::TimestampHardwareStateDebug& debug_data) { + debug_data.is_using_fake = true; + debug_data.fake_timestamp_in = fake_timestamp_; + debug_data.fake_timestamp_delta = fake_timestamp_delta_.val_; fake_timestamp_ += fake_timestamp_delta_.val_; if (fabs(fake_timestamp_ - hwstate.timestamp) > fake_timestamp_max_divergence_) { fake_timestamp_ = hwstate.timestamp; max_skew_ = 0.0; + debug_data.was_divergence_reset = true; } + debug_data.fake_timestamp_out = fake_timestamp_; skew_ = fake_timestamp_ - hwstate.timestamp; max_skew_ = std::max(max_skew_, skew_); hwstate.timestamp = fake_timestamp_; + debug_data.skew = skew_; + debug_data.max_skew = max_skew_; } void TimestampFilterInterpreter::HandleTimerImpl(stime_t now, stime_t* timeout) { + const char name[] = "TimestampFilterInterpreter::HandleTimerImpl"; + LogHandleTimerPre(name, now, timeout); + // Adjust the timestamp by the largest skew_ since reset. This ensures that // the callback isn't ignored because it looks like it's coming too early. - next_->HandleTimer(now + max_skew_, timeout); + now += max_skew_; + next_->HandleTimer(now, timeout); + + LogHandleTimerPost(name, now, timeout); } void TimestampFilterInterpreter::ConsumeGesture(const Gesture& gs) { + const char name[] = "TimestampFilterInterpreter::ConsumeGesture"; + LogGestureConsume(name, gs); + auto debug_data = ActivityLog::TimestampGestureDebug{ skew_ }; + // Adjust gesture timestamp by latest skew to match browser clock Gesture copy = gs; copy.start_time -= skew_; copy.end_time -= skew_; + + LogDebugData(debug_data); + LogGestureProduce(name, copy); ProduceGesture(copy); } diff --git a/src/timestamp_filter_interpreter_unittest.cc b/src/timestamp_filter_interpreter_unittest.cc index 425d97e..482148f 100644 --- a/src/timestamp_filter_interpreter_unittest.cc +++ b/src/timestamp_filter_interpreter_unittest.cc @@ -5,13 +5,19 @@ #include <gtest/gtest.h> #include "include/gestures.h" +#include "include/string_util.h" #include "include/timestamp_filter_interpreter.h" #include "include/unittest_util.h" #include "include/util.h" namespace gestures { +using EventDebug = ActivityLog::EventDebug; + class TimestampFilterInterpreterTest : public ::testing::Test {}; +class TimestampFilterInterpreterParmTest : + public TimestampFilterInterpreterTest, + public testing::WithParamInterface<stime_t> {}; class TimestampFilterInterpreterTestInterpreter : public Interpreter { public: @@ -219,4 +225,95 @@ TEST(TimestampFilterInterpreterTest, FakeTimestampFallBackwardTest) { // the last reset. EXPECT_FLOAT_EQ(adjusted_timestamp, 2.025); } + +TEST(TimestampFilterInterpreterTest, GestureDebugTest) { + PropRegistry prop_reg; + TimestampFilterInterpreter interpreter(&prop_reg, nullptr, nullptr); + + using EventDebug = ActivityLog::EventDebug; + interpreter.SetEventLoggingEnabled(true); + interpreter.EventDebugLoggingEnable(EventDebug::Gesture); + interpreter.EventDebugLoggingEnable(EventDebug::HardwareState); + interpreter.EventDebugLoggingEnable(EventDebug::HandleTimer); + interpreter.EventDebugLoggingEnable(EventDebug::Timestamp); + interpreter.log_.reset(new ActivityLog(&prop_reg)); + + EXPECT_EQ(interpreter.log_->size(), 0); + interpreter.ConsumeGesture(Gesture(kGestureButtonsChange, + 1, // start time + 2, // end time + 0, // down + 0, // up + false)); // is_tap + + // Encode the log into Json + Json::Value node; + Json::Value tree = interpreter.log_->EncodeCommonInfo(); + + // Verify the Json information + EXPECT_EQ(interpreter.log_->size(), 3); + node = tree[ActivityLog::kKeyRoot][0]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureConsume)); + node = tree[ActivityLog::kKeyRoot][1]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyTimestampGestureDebug)); + EXPECT_EQ(node[ActivityLog::kKeyTimestampDebugSkew], + Json::Value(interpreter.skew_)); + node = tree[ActivityLog::kKeyRoot][2]; + EXPECT_EQ(node[ActivityLog::kKeyType], + Json::Value(ActivityLog::kKeyGestureProduce)); + interpreter.log_->Clear(); +} + +TEST_P(TimestampFilterInterpreterParmTest, TimestampDebugLoggingTest) { + PropRegistry prop_reg; + TimestampFilterInterpreterTestInterpreter* base_interpreter = + new TimestampFilterInterpreterTestInterpreter; + TimestampFilterInterpreter interpreter(&prop_reg, base_interpreter, nullptr); + TestInterpreterWrapper wrapper(&interpreter); + + interpreter.SetEventLoggingEnabled(true); + interpreter.EventDebugLoggingEnable(EventDebug::Gesture); + interpreter.EventDebugLoggingEnable(EventDebug::HardwareState); + interpreter.EventDebugLoggingEnable(EventDebug::HandleTimer); + interpreter.EventDebugLoggingEnable(EventDebug::Timestamp); + interpreter.log_.reset(new ActivityLog(&prop_reg)); + interpreter.fake_timestamp_delta_.val_ = GetParam(); + + HardwareState hs = make_hwstate_times(1.000, 0.000); + wrapper.SyncInterpret(hs, nullptr); + + // Encode the log into Json + Json::Value node; + Json::Value tree = interpreter.log_->EncodeCommonInfo(); + + // Verify the Json information + EXPECT_EQ(interpreter.log_->size(), 4); + node = tree[ActivityLog::kKeyRoot][0]; + EXPECT_EQ(node[ActivityLog::kKeyType].asString(), + ActivityLog::kKeyHardwareState); + node = tree[ActivityLog::kKeyRoot][1]; + EXPECT_EQ(node[ActivityLog::kKeyType].asString(), + ActivityLog::kKeyHardwareStatePre); + + node = tree[ActivityLog::kKeyRoot][2]; + EXPECT_EQ(node[ActivityLog::kKeyType].asString(), + ActivityLog::kKeyTimestampHardwareStateDebug); + if (interpreter.fake_timestamp_delta_.val_ == 0.0) { + EXPECT_FALSE(node[ActivityLog::kKeyTimestampDebugIsUsingFake].asBool()); + } else { + EXPECT_TRUE(node[ActivityLog::kKeyTimestampDebugIsUsingFake].asBool()); + } + + node = tree[ActivityLog::kKeyRoot][3]; + EXPECT_EQ(node[ActivityLog::kKeyType].asString(), + ActivityLog::kKeyHardwareStatePost); + interpreter.log_->Clear(); +} + +INSTANTIATE_TEST_SUITE_P(TimestampFilterInterpreter, + TimestampFilterInterpreterParmTest, + testing::Values(0.000, 0.010)); + } // namespace gestures diff --git a/src/trend_classifying_filter_interpreter.cc b/src/trend_classifying_filter_interpreter.cc index 50597cf..d039daf 100644 --- a/src/trend_classifying_filter_interpreter.cc +++ b/src/trend_classifying_filter_interpreter.cc @@ -45,8 +45,13 @@ TrendClassifyingFilterInterpreter::TrendClassifyingFilterInterpreter( void TrendClassifyingFilterInterpreter::SyncInterpretImpl( HardwareState& hwstate, stime_t* timeout) { + const char name[] = "TrendClassifyingFilterInterpreter::SyncInterpretImpl"; + LogHardwareStatePre(name, hwstate); + if (trend_classifying_filter_enable_.val_) UpdateFingerState(hwstate); + + LogHardwareStatePost(name, hwstate); next_->SyncInterpret(hwstate, timeout); } diff --git a/src/trend_classifying_filter_interpreter_unittest.cc b/src/trend_classifying_filter_interpreter_unittest.cc index ce4da42..80e069e 100644 --- a/src/trend_classifying_filter_interpreter_unittest.cc +++ b/src/trend_classifying_filter_interpreter_unittest.cc @@ -44,15 +44,15 @@ TEST(TrendClassifyingFilterInterpreterTest, SimpleTest) { EXPECT_TRUE(interpreter.second_order_enable_.val_); HardwareProperties hwprops = { - 0, 0, 100, 100, // left, top, right, bottom - 1, 1, // x res (pixels/mm), y res (pixels/mm) - 1, 1, // scrn DPI X, Y - -1, // orientation minimum - 2, // orientation maximum - 5, 5, // max fingers, max_touch, - 0, 0, 1, // t5r2, semi, button pad - 0, 0, // has wheel, vertical wheel is high resolution - 0, // haptic pad + .right = 100, .bottom = 100, + .res_x = 1, .res_y = 1, + .screen_x_dpi = 1, .screen_y_dpi = 1, + .orientation_minimum = -1, + .orientation_maximum = 2, + .max_finger_cnt = 5, .max_touch_cnt = 5, + .supports_t5r2 = 0, .support_semi_mt = 0, .is_button_pad = 1, + .has_wheel = 0, .wheel_is_hi_res = 0, + .is_haptic_pad = 0, }; TestInterpreterWrapper wrapper(&interpreter, &hwprops); |