diff options
author | Harry Cutts <hcutts@google.com> | 2023-01-13 18:34:21 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-01-13 18:34:21 +0000 |
commit | 9381183ad9ca92544eb1c45e0dada3bcca3744d1 (patch) | |
tree | 0b1f87b9b1633009765c1f27d7f2a0000c84eada | |
parent | 681529d6c173bd072287ac3b7e9e25dc2540fbb2 (diff) | |
parent | 0d4e0160efa20717934a23323805f5817d224032 (diff) | |
download | libchrome-gestures-9381183ad9ca92544eb1c45e0dada3bcca3744d1.tar.gz |
Merge remote-tracking branch 'aosp/upstream-main' into gestures-update am: 0d4e0160ef
Original change: https://android-review.googlesource.com/c/platform/external/libchrome-gestures/+/2388113
Change-Id: I9ab04f68154f943ac5665f683f19929a3cbe4bf0
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
26 files changed, 996 insertions, 45 deletions
diff --git a/METADATA.android b/METADATA.android index 6759c17..8df3226 100644 --- a/METADATA.android +++ b/METADATA.android @@ -6,7 +6,7 @@ third_party { type: GIT value: "https://chromium.googlesource.com/chromiumos/platform/gestures/" } - version: "c7054fe1a0729f9d84c5e6441a385bf362d7a6e7" - last_upgrade_date { year: 2022 month: 11 day: 23 } + version: "10ca30a7497231a1c978264f4220c863f5d35727" + last_upgrade_date { year: 2023 month: 01 day: 13 } license_type: NOTICE } @@ -51,6 +51,7 @@ TEST_OBJECTS=\ $(OBJDIR)/click_wiggle_filter_interpreter_unittest.o \ $(OBJDIR)/command_line.o \ $(OBJDIR)/filter_interpreter_unittest.o \ + $(OBJDIR)/finger_merge_filter_interpreter_unittest.o \ $(OBJDIR)/finger_metrics_unittest.o \ $(OBJDIR)/fling_stop_filter_interpreter_unittest.o \ $(OBJDIR)/gestures_unittest.o \ @@ -63,6 +64,7 @@ TEST_OBJECTS=\ $(OBJDIR)/logging_filter_interpreter_unittest.o \ $(OBJDIR)/lookahead_filter_interpreter_unittest.o \ $(OBJDIR)/non_linearity_filter_interpreter_unittest.o \ + $(OBJDIR)/metrics_filter_interpreter_unittest.o \ $(OBJDIR)/mouse_interpreter_unittest.o \ $(OBJDIR)/multitouch_mouse_interpreter_unittest.o \ $(OBJDIR)/palm_classifying_filter_interpreter_unittest.o \ @@ -70,12 +72,14 @@ TEST_OBJECTS=\ $(OBJDIR)/scaling_filter_interpreter_unittest.o \ $(OBJDIR)/sensor_jump_filter_interpreter_unittest.o \ $(OBJDIR)/split_correcting_filter_interpreter_unittest.o \ + $(OBJDIR)/stationary_wiggle_filter_interpreter_unittest.o \ $(OBJDIR)/string_util_unittest.o \ $(OBJDIR)/stuck_button_inhibitor_filter_interpreter_unittest.o \ $(OBJDIR)/t5r2_correcting_filter_interpreter_unittest.o \ $(OBJDIR)/timestamp_filter_interpreter_unittest.o \ $(OBJDIR)/trace_marker_unittest.o \ $(OBJDIR)/tracer_unittest.o \ + $(OBJDIR)/trend_classifying_filter_interpreter_unittest.o \ $(OBJDIR)/unittest_util.o \ $(OBJDIR)/util_unittest.o \ $(OBJDIR)/vector_unittest.o diff --git a/docs/gesture_properties.md b/docs/gesture_properties.md index 813601c..28eda53 100644 --- a/docs/gesture_properties.md +++ b/docs/gesture_properties.md @@ -18,9 +18,12 @@ such as "Scroll Accel Curve", "Mouse Reverse Scrolling", or "Palm Pressure". Each property has a type (integer, double, boolean, or string), and a size, which is the number of values of that type that it stores. (For strings, the -size is always 1.) Some properties are read-only, which normally means that -modifying them wouldn't make sense (for example, the "Device Vendor ID" -property, which reflects a hardware ID). +size is always 1.) + +Chromium creates some read-only properties, which normally means that modifying +them wouldn't make sense (for example, the "Device Vendor ID" property, which +reflects a hardware ID). However, the Gestures library itself does not do this, +so other clients don't need to support them. ## Changing properties without recompiling diff --git a/include/finger_merge_filter_interpreter.h b/include/finger_merge_filter_interpreter.h index e8d8ef7..44abd23 100644 --- a/include/finger_merge_filter_interpreter.h +++ b/include/finger_merge_filter_interpreter.h @@ -24,6 +24,7 @@ namespace gestures { // merging/merged finger(s). class FingerMergeFilterInterpreter : public FilterInterpreter { + FRIEND_TEST(FingerMergeFilterInterpreterTest, SimpleTest); public: FingerMergeFilterInterpreter(PropRegistry* prop_reg, Interpreter* next, diff --git a/include/gestures.h b/include/gestures.h index 07e4306..5a1acc9 100644 --- a/include/gestures.h +++ b/include/gestures.h @@ -160,6 +160,7 @@ struct HardwareProperties { // skip the flag so that we can have the option to use the not-that-accurate // positions. #define GESTURES_FINGER_WARP_TELEPORTATION (1 << 19) +#define GESTURES_FINGER_LARGE_PALM (1 << 20) #define GESTURES_FINGER_WARP_X (GESTURES_FINGER_WARP_X_NON_MOVE | \ GESTURES_FINGER_WARP_X_MOVE) @@ -343,21 +344,38 @@ typedef struct { float data[2]; } GestureMetrics; +// Describes the type of gesture that is being reported. enum GestureType { #ifdef GESTURES_INTERNAL kGestureTypeNull = -1, // internal to Gestures library only #endif // GESTURES_INTERNAL + // No longer used. kGestureTypeContactInitiated = 0, + // For touchpads, a movement of a single finger on the pad. For mice, a + // movement of the whole mouse. kGestureTypeMove, + // A two-finger scroll gesture on a touchpad. (See kGestureTypeMouseWheel for + // the mouse equivalent.) kGestureTypeScroll, + // A change in the buttons that are currently pressed on the device. kGestureTypeButtonsChange, + // The start or end of a fling motion, where scrolling should continue after + // the user's fingers have left the touchpad. kGestureTypeFling, + // A movement of three fingers on a touchpad. kGestureTypeSwipe, + // A movement of two fingers on a touchpad that are primarily moving closer to + // or further from each other. kGestureTypePinch, + // The end of a movement of three fingers on a touchpad. kGestureTypeSwipeLift, + // Used to report metrics to the client. kGestureTypeMetrics, + // A movement of four fingers on a touchpad. kGestureTypeFourFingerSwipe, + // The end of a movement of four fingers on a touchpad. kGestureTypeFourFingerSwipeLift, + // The movement of a scroll wheel on a mouse. kGestureTypeMouseWheel, }; @@ -522,8 +540,10 @@ typedef unsigned char GesturesPropBool; // These functions create a named property of given type. // data - data used by PropProvider -// loc - location of a variable to be updated by PropProvider. -// Set to NULL to create a ReadOnly property +// loc - location of a variable to be updated by PropProvider +// (Chromium calls its own GesturesPropCreate... functions with loc set +// to null to create read-only properties, but the Gestures library +// itself doesn't, so other clients don't need to support them.) // init - initial value for the property. // If the PropProvider has an alternate configuration source, it may // override this initial value, in which case *loc returns the @@ -532,9 +552,9 @@ typedef GesturesProp* (*GesturesPropCreateInt)(void* data, const char* name, int* loc, size_t count, const int* init); -typedef GesturesProp* (*GesturesPropCreateShort)(void* data, const char* name, - short* loc, size_t count, - const short* init); +// Deprecated: the gestures library no longer uses short gesture properties. +typedef GesturesProp* (*GesturesPropCreateShort_Deprecated)( + void*, const char*, short*, size_t, const short*); typedef GesturesProp* (*GesturesPropCreateBool)(void* data, const char* name, GesturesPropBool* loc, @@ -558,12 +578,17 @@ typedef GesturesPropBool (*GesturesPropGetHandler)(void* handler_data); // |handler_data| is a local context pointer that can be used by the handler. typedef void (*GesturesPropSetHandler)(void* handler_data); -// Register handlers to be called when a GesturesProp is accessed. -// The get handler, if not NULL, is called immediately before the property's -// value is to be read. This gives the library a chance to update its value. -// The set handler, if not NULL, is called immediately after the property's -// value is updated. This can be used to create a property that is used to -// trigger an action, or to force an update to multiple properties atomically. +// Register handlers for the client to call when a GesturesProp is accessed. +// +// The get handler, if not NULL, should be called immediately before the +// property's value is to be read. This gives the library a chance to update its +// value. +// +// The set handler, if not NULL, should be called immediately after the +// property's value is updated. This can be used to create a property that is +// used to trigger an action, or to force an update to multiple properties +// atomically. +// // Note: the handlers are called from non-signal/interrupt context typedef void (*GesturesPropRegisterHandlers)(void* data, GesturesProp* prop, void* handler_data, @@ -575,7 +600,9 @@ typedef void (*GesturesPropFree)(void* data, GesturesProp* prop); typedef struct GesturesPropProvider { GesturesPropCreateInt create_int_fn; - GesturesPropCreateShort create_short_fn; + // Deprecated: the library no longer uses short gesture properties, so this + // function pointer should be null. + GesturesPropCreateShort_Deprecated create_short_fn; GesturesPropCreateBool create_bool_fn; GesturesPropCreateString create_string_fn; GesturesPropCreateReal create_real_fn; diff --git a/include/haptic_button_generator_filter_interpreter.h b/include/haptic_button_generator_filter_interpreter.h index c563104..22a4a92 100644 --- a/include/haptic_button_generator_filter_interpreter.h +++ b/include/haptic_button_generator_filter_interpreter.h @@ -3,6 +3,7 @@ // found in the LICENSE file. #include <gtest/gtest.h> // for FRIEND_TEST +#include <set> #include "include/filter_interpreter.h" #include "include/gestures.h" @@ -24,6 +25,7 @@ class HapticButtonGeneratorFilterInterpreter : public FilterInterpreter { FRIEND_TEST(HapticButtonGeneratorFilterInterpreterTest, GesturePreventsButtonDownTest); FRIEND_TEST(HapticButtonGeneratorFilterInterpreterTest, DynamicThresholdTest); + FRIEND_TEST(HapticButtonGeneratorFilterInterpreterTest, PalmTest); public: // Takes ownership of |next|: explicit HapticButtonGeneratorFilterInterpreter(PropRegistry* prop_reg, @@ -42,6 +44,7 @@ class HapticButtonGeneratorFilterInterpreter : public FilterInterpreter { void ConsumeGesture(const Gesture& gesture) override; void HandleHardwareState(HardwareState* hwstate); virtual void HandleTimerImpl(stime_t now, stime_t *timeout) override; + void UpdatePalmState(HardwareState* hwstate); static const size_t kMaxSensitivitySettings = 5; @@ -51,6 +54,8 @@ class HapticButtonGeneratorFilterInterpreter : public FilterInterpreter { const double up_thresholds_[kMaxSensitivitySettings] = {80.0, 95.0, 105.0, 120.0, 135.0}; + std::set<short> palms_; + // Scaling factor for release force [0.0-1.0] double release_suppress_factor_; diff --git a/include/immediate_interpreter.h b/include/immediate_interpreter.h index 09878e4..261b3b0 100644 --- a/include/immediate_interpreter.h +++ b/include/immediate_interpreter.h @@ -347,7 +347,7 @@ class ImmediateInterpreter : public Interpreter, public PropertyDelegate { FRIEND_TEST(ImmediateInterpreterTest, PalmAtEdgeTest); FRIEND_TEST(ImmediateInterpreterTest, PalmReevaluateTest); FRIEND_TEST(ImmediateInterpreterTest, PalmTest); - FRIEND_TEST(ImmediateInterpreterTest, DISABLED_PinchTests); + FRIEND_TEST(ImmediateInterpreterTest, PinchTests); FRIEND_TEST(ImmediateInterpreterTest, ScrollResetTapTest); FRIEND_TEST(ImmediateInterpreterTest, ScrollThenFalseTapTest); FRIEND_TEST(ImmediateInterpreterTest, SemiMtActiveAreaTest); diff --git a/include/metrics_filter_interpreter.h b/include/metrics_filter_interpreter.h index d13ee93..60d5898 100644 --- a/include/metrics_filter_interpreter.h +++ b/include/metrics_filter_interpreter.h @@ -24,6 +24,10 @@ namespace gestures { // metrics lib here because it might introduce the deadlock problem. class MetricsFilterInterpreter : public FilterInterpreter { + FRIEND_TEST(MetricsFilterInterpreterTest, SimpleTestMultitouchMouse); + FRIEND_TEST(MetricsFilterInterpreterTest, SimpleTestPointingStick); + FRIEND_TEST(MetricsFilterInterpreterTest, SimpleTestTouchpad); + public: // Takes ownership of |next|: MetricsFilterInterpreter(PropRegistry* prop_reg, diff --git a/include/palm_classifying_filter_interpreter.h b/include/palm_classifying_filter_interpreter.h index 18cf3a7..8d5739b 100644 --- a/include/palm_classifying_filter_interpreter.h +++ b/include/palm_classifying_filter_interpreter.h @@ -97,6 +97,9 @@ class PalmClassifyingFilterInterpreter : public FilterInterpreter { // Same fingers state. This state is accumulated as fingers remain the same // and it's reset when fingers change. std::set<short> palm_; // tracking ids of known palms + // These contacts are a subset of palms_ which are marked as palms because + // they have a large contact size. + std::set<short> large_palm_; // These contacts have moved significantly and shouldn't be considered // stationary palms: std::set<short> non_stationary_palm_; diff --git a/include/scaling_filter_interpreter.h b/include/scaling_filter_interpreter.h index 749779f..25b4641 100644 --- a/include/scaling_filter_interpreter.h +++ b/include/scaling_filter_interpreter.h @@ -81,8 +81,11 @@ class ScalingFilterInterpreter : public FilterInterpreter { HardwareProperties friendly_props_; - // True if scrolling should be inverted - BoolProperty australian_scrolling_; + // When set to true, scroll and swipe gesture directions are inverted. + BoolProperty invert_scrolling_and_swiping_; + + // When set to true, only scroll gesture directions are inverted. + BoolProperty invert_scrolling_only_; // Output surface area (sq. mm) = // if surface_area_from_pressure_ diff --git a/include/stationary_wiggle_filter_interpreter.h b/include/stationary_wiggle_filter_interpreter.h index 92c2cb2..60fb0c5 100644 --- a/include/stationary_wiggle_filter_interpreter.h +++ b/include/stationary_wiggle_filter_interpreter.h @@ -3,6 +3,7 @@ // found in the LICENSE file. #include <map> +#include <gtest/gtest.h> // for FRIEND_TEST #include "include/filter_interpreter.h" #include "include/finger_metrics.h" @@ -122,6 +123,8 @@ class FingerEnergyHistory { }; class StationaryWiggleFilterInterpreter : public FilterInterpreter { + FRIEND_TEST(StationaryWiggleFilterInterpreterTest, SimpleTest); + public: // Takes ownership of |next|: StationaryWiggleFilterInterpreter(PropRegistry* prop_reg, diff --git a/include/trace_marker.h b/include/trace_marker.h index 73d61f6..d1fa9b2 100644 --- a/include/trace_marker.h +++ b/include/trace_marker.h @@ -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 <gtest/gtest.h> // for FRIEND_TEST #include <linux/limits.h> #include "include/macros.h" @@ -21,6 +22,8 @@ namespace gestures { // debugfs/tracing/trace class TraceMarker { + FRIEND_TEST(TraceMarkerTest, DeleteTraceMarkerTest); + public: static void CreateTraceMarker(); static void DeleteTraceMarker(); diff --git a/include/trend_classifying_filter_interpreter.h b/include/trend_classifying_filter_interpreter.h index f04e224..b2e8436 100644 --- a/include/trend_classifying_filter_interpreter.h +++ b/include/trend_classifying_filter_interpreter.h @@ -78,6 +78,7 @@ namespace gestures { // thumbs. class TrendClassifyingFilterInterpreter: public FilterInterpreter { + FRIEND_TEST(TrendClassifyingFilterInterpreterTest, SimpleTest); public: TrendClassifyingFilterInterpreter(PropRegistry* prop_reg, Interpreter* next, diff --git a/src/finger_merge_filter_interpreter_unittest.cc b/src/finger_merge_filter_interpreter_unittest.cc new file mode 100644 index 0000000..bd2d904 --- /dev/null +++ b/src/finger_merge_filter_interpreter_unittest.cc @@ -0,0 +1,136 @@ +// Copyright 2022 The ChromiumOS Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <gtest/gtest.h> + +#include "include/finger_merge_filter_interpreter.h" +#include "include/unittest_util.h" + +namespace gestures { + +class FingerMergeFilterInterpreterTest : public ::testing::Test {}; + +class FingerMergeFilterInterpreterTestInterpreter : public Interpreter { + public: + FingerMergeFilterInterpreterTestInterpreter() + : Interpreter(NULL, NULL, false), + handle_timer_called_(false) {} + + virtual void SyncInterpret(HardwareState* hwstate, stime_t* timeout) { + EXPECT_NE(static_cast<HardwareState*>(NULL), hwstate); + EXPECT_EQ(2, hwstate->finger_cnt); + prev_ = hwstate->fingers[0]; + } + + virtual void HandleTimer(stime_t now, stime_t* timeout) { + handle_timer_called_ = true; + } + + FingerState prev_; + bool handle_timer_called_; +}; + + +TEST(FingerMergeFilterInterpreterTest, SimpleTest) { + FingerMergeFilterInterpreter::Start loc = {1.0, 1.0, 1.0}; + FingerMergeFilterInterpreter::Start loc_eq = {1.0, 1.0, 1.0}; + FingerMergeFilterInterpreter::Start loc_ne0 = {9.0, 1.0, 1.0}; + FingerMergeFilterInterpreter::Start loc_ne1 = {1.0, 9.0, 1.0}; + FingerMergeFilterInterpreter::Start loc_ne2 = {1.0, 1.0, 9.0}; + + EXPECT_EQ(loc, loc_eq); + EXPECT_NE(loc, loc_ne0); + EXPECT_NE(loc, loc_ne1); + EXPECT_NE(loc, loc_ne2); + + + FingerMergeFilterInterpreterTestInterpreter* base_interpreter = + new FingerMergeFilterInterpreterTestInterpreter; + FingerMergeFilterInterpreter interpreter(NULL, base_interpreter, NULL); + + EXPECT_FALSE(interpreter.finger_merge_filter_enable_.val_); + 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 + }; + TestInterpreterWrapper wrapper(&interpreter, &hwprops); + + EXPECT_FALSE(base_interpreter->handle_timer_called_); + wrapper.HandleTimer(0.0, NULL); + EXPECT_TRUE(base_interpreter->handle_timer_called_); + + FingerState finger_states[] = { + // TM, Tm, WM, Wm, Press, Orientation, X, Y, TrID + // Consistent movement for 6 frames + {0, 0, 0, 0, 20, 0, 40, 20, 1, 0}, // 0 + {0, 0, 0, 0, 20, 0, 42, 22, 2, 0}, + + {0, 0, 0, 0, 20, 0, 40, 25, 1, 0}, // 2 + {0, 0, 0, 0, 20, 0, 42, 27, 2, 0}, + + {0, 0, 0, 0, 20, 0, 40, 30, 1, 0}, // 4 + {0, 0, 0, 0, 20, 0, 42, 32, 2, 0}, + + {0, 0, 0, 0, 20, 0, 40, 35, 1, 0}, // 6 + {0, 0, 0, 0, 20, 0, 42, 37, 2, 0}, + + {0, 0, 0, 0, 20, 0, 40, 40, 1, 0}, // 8 + {0, 0, 0, 0, 20, 0, 42, 42, 2, 0}, + + {0, 0, 0, 0, 20, 0, 40, 45, 1, 0}, // 10 + {0, 0, 0, 0, 20, 0, 42, 47, 2, 0}, + + {0, 0, 0, 0, 20, 0, 40, 50, 1, 0}, // 12 + {0, 0, 0, 0, 20, 0, 42, 52, 2, 0}, + + {0, 0, 0, 0, 20, 0, 40, 55, 1, 0}, // 14 + {0, 0, 0, 0, 20, 0, 42, 57, 2, 0}, + }; + + HardwareState hardware_states[] = { + // time, buttons, finger count, touch count, finger states pointer + make_hwstate(1.00, 0, 2, 2, &finger_states[0]), + make_hwstate(1.01, 0, 2, 2, &finger_states[2]), + make_hwstate(1.02, 0, 2, 2, &finger_states[4]), + make_hwstate(1.03, 0, 2, 2, &finger_states[6]), + make_hwstate(1.04, 0, 2, 2, &finger_states[8]), + make_hwstate(1.05, 0, 2, 2, &finger_states[10]), + make_hwstate(1.06, 0, 2, 2, &finger_states[12]), + make_hwstate(1.07, 0, 2, 2, &finger_states[14]), + }; + + for (size_t i = 0; i < arraysize(hardware_states); i++) { + HardwareState *hwstate = &hardware_states[i]; + wrapper.SyncInterpret(hwstate, NULL); + for (short j = 0; j < hwstate->finger_cnt; j++) { + FingerState *fs = hwstate->fingers; + EXPECT_TRUE(fs[j].flags & GESTURES_FINGER_MERGE); + } + } + + EXPECT_TRUE(interpreter.finger_merge_filter_enable_.val_); + EXPECT_EQ(interpreter.merge_distance_threshold_.val_, 140.0); + EXPECT_EQ(interpreter.max_pressure_threshold_.val_, 83.0); + EXPECT_EQ(interpreter.min_pressure_threshold_.val_, 51.0); + EXPECT_EQ(interpreter.min_major_threshold_.val_, 280.0); + EXPECT_EQ(interpreter.merged_major_pressure_ratio_.val_, 5.0); + EXPECT_EQ(interpreter.merged_major_threshold_.val_, 380.0); + EXPECT_EQ(interpreter.x_jump_min_displacement_.val_, 6.0); + EXPECT_EQ(interpreter.x_jump_max_displacement_.val_, 9.0); + EXPECT_EQ(interpreter.suspicious_angle_min_displacement_.val_, 7.0); + EXPECT_EQ(interpreter.max_x_move_.val_, 180.0); + EXPECT_EQ(interpreter.max_y_move_.val_, 60.0); + EXPECT_EQ(interpreter.max_age_.val_, 0.35); +} + +} // namespace gestures diff --git a/src/haptic_button_generator_filter_interpreter.cc b/src/haptic_button_generator_filter_interpreter.cc index 0fcbf9c..6d7fe52 100644 --- a/src/haptic_button_generator_filter_interpreter.cc +++ b/src/haptic_button_generator_filter_interpreter.cc @@ -10,6 +10,7 @@ #include "include/interpreter.h" #include "include/logging.h" #include "include/tracer.h" +#include "include/util.h" namespace gestures { @@ -59,6 +60,7 @@ void HapticButtonGeneratorFilterInterpreter::SyncInterpretImpl( HandleHardwareState(hwstate); stime_t next_timeout = NO_DEADLINE; next_->SyncInterpret(hwstate, &next_timeout); + UpdatePalmState(hwstate); *timeout = SetNextDeadlineAndReturnTimeoutVal( hwstate->timestamp, active_gesture_deadline_, next_timeout); } @@ -90,10 +92,13 @@ void HapticButtonGeneratorFilterInterpreter::HandleHardwareState( up_threshold *= release_suppress_factor_; - // Determine total force on touchpad in grams + // Determine maximum force on touchpad in grams double force = 0.0; for (short i = 0; i < hwstate->finger_cnt; i++) { - force = fmax(force, hwstate->fingers[i].pressure); + FingerState* fs = &hwstate->fingers[i]; + if (!SetContainsValue(palms_, fs->tracking_id)) { + force = fmax(force, fs->pressure); + } } force *= force_scale_.val_; force += force_translate_.val_; @@ -143,6 +148,18 @@ void HapticButtonGeneratorFilterInterpreter::HandleHardwareState( release_suppress_factor_ = 1.0; } +void HapticButtonGeneratorFilterInterpreter::UpdatePalmState( + HardwareState* hwstate) { + RemoveMissingIdsFromSet(&palms_, *hwstate); + for (short i = 0; i < hwstate->finger_cnt; i++) { + FingerState* fs = &hwstate->fingers[i]; + if (fs->flags & GESTURES_FINGER_LARGE_PALM) { + palms_.insert(fs->tracking_id); + } + } +} + + void HapticButtonGeneratorFilterInterpreter::HandleTimerImpl( stime_t now, stime_t *timeout) { stime_t next_timeout; diff --git a/src/haptic_button_generator_filter_interpreter_unittest.cc b/src/haptic_button_generator_filter_interpreter_unittest.cc index 798ab72..318a304 100644 --- a/src/haptic_button_generator_filter_interpreter_unittest.cc +++ b/src/haptic_button_generator_filter_interpreter_unittest.cc @@ -339,4 +339,69 @@ TEST(HapticButtonGeneratorFilterInterpreterTest, DynamicThresholdTest) { } } +TEST(HapticButtonGeneratorFilterInterpreterTest, PalmTest) { + HapticButtonGeneratorFilterInterpreterTestInterpreter* base_interpreter = + new HapticButtonGeneratorFilterInterpreterTestInterpreter; + HapticButtonGeneratorFilterInterpreter interpreter( + NULL, base_interpreter, NULL); + 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 + }; + TestInterpreterWrapper wrapper(&interpreter, &hwprops); + + interpreter.enabled_.val_ = true; + + FingerState fs[] = { + // TM, Tm, WM, Wm, pr, orient, x, y, id, flag + { 0, 0, 0, 0, 50, 0, 10, 1, 1, GESTURES_FINGER_LARGE_PALM }, + { 0, 0, 0, 0, 160, 0, 10, 1, 1, GESTURES_FINGER_LARGE_PALM }, + { 0, 0, 0, 0, 50, 0, 10, 1, 1, GESTURES_FINGER_LARGE_PALM }, + + { 0, 0, 0, 0, 50, 0, 10, 1, 1, GESTURES_FINGER_LARGE_PALM }, + { 0, 0, 0, 0, 50, 0, 10, 1, 2, 0 }, + { 0, 0, 0, 0, 160, 0, 10, 1, 1, GESTURES_FINGER_LARGE_PALM }, + { 0, 0, 0, 0, 80, 0, 10, 1, 2, 0 }, + + { 0, 0, 0, 0, 160, 0, 10, 1, 1, GESTURES_FINGER_LARGE_PALM }, + { 0, 0, 0, 0, 160, 0, 10, 1, 2, 0 }, + }; + HardwareState hs[] = { + // Expect not to set button down when a lone palm goes above 'down force + // threshold' + make_hwstate(2.01, 0, 1, 1, &fs[0]), + make_hwstate(2.03, 0, 1, 1, &fs[1]), + make_hwstate(2.05, 0, 1, 1, &fs[2]), + + // Expect not to set button down when there are multiple fingers and only a + // palm goes above 'down force threshold' + make_hwstate(4.01, 0, 2, 2, &fs[3]), + make_hwstate(4.03, 0, 2, 2, &fs[5]), + + // Expect to set button down when there are multiple fingers and a non-palm + // goes above 'down force threshold' + make_hwstate(4.05, 0, 2, 2, &fs[7]), + }; + + stime_t expected_buttons[] = { + 0, 0, 0, + 0, 0, + GESTURES_BUTTON_LEFT, + }; + + for (size_t i = 0; i < arraysize(hs); i++) { + stime_t timeout = NO_DEADLINE; + wrapper.SyncInterpret(&hs[i], &timeout); + EXPECT_EQ(hs[i].buttons_down, expected_buttons[i]); + } +} + } // namespace gestures diff --git a/src/immediate_interpreter_unittest.cc b/src/immediate_interpreter_unittest.cc index 661541a..f5dd9a0 100644 --- a/src/immediate_interpreter_unittest.cc +++ b/src/immediate_interpreter_unittest.cc @@ -2879,7 +2879,8 @@ TEST(ImmediateInterpreterTest, ChangeTimeoutTest) { enum PinchTestExpectedResult { kPinch, kNoPinch, - kAny + kAny, + kNull }; struct PinchTestInput { @@ -2887,7 +2888,7 @@ struct PinchTestInput { PinchTestExpectedResult expected_result; }; -TEST(ImmediateInterpreterTest, DISABLED_PinchTests) { +TEST(ImmediateInterpreterTest, PinchTests) { ImmediateInterpreter ii(NULL, NULL); ii.pinch_enable_.val_ = 1; HardwareProperties hwprops = { @@ -2976,8 +2977,8 @@ TEST(ImmediateInterpreterTest, DISABLED_PinchTests) { {make_hwstate(1.08, 0, 2, 2, &finger_states[6]), kAny}, {make_hwstate(1.09, 0, 2, 2, &finger_states[8]), kAny}, {make_hwstate(1.10, 0, 2, 2, &finger_states[8]), kAny}, - {make_hwstate(1.11, 0, 2, 2, &finger_states[10]), kAny}, - {make_hwstate(1.12, 0, 2, 2, &finger_states[10]), kPinch}, + {make_hwstate(1.11, 0, 2, 2, &finger_states[10]), kPinch}, + {make_hwstate(1.12, 0, 2, 2, &finger_states[10]), kNull}, {make_hwstate(1.13, 0, 0, 0, NULL), kAny}, // single finger pinch @@ -3019,6 +3020,10 @@ TEST(ImmediateInterpreterTest, DISABLED_PinchTests) { EXPECT_NE(kGestureTypePinch, gs->type); } } + // assert if NULL is not given back + if (input_states[idx].expected_result == kNull) { + ASSERT_EQ(reinterpret_cast<Gesture*>(NULL), gs); + } } } diff --git a/src/lookahead_filter_interpreter.cc b/src/lookahead_filter_interpreter.cc index 280d396..f7abaf5 100644 --- a/src/lookahead_filter_interpreter.cc +++ b/src/lookahead_filter_interpreter.cc @@ -86,6 +86,14 @@ void LookaheadFilterInterpreter::SyncInterpretImpl(HardwareState* hwstate, interpreter_due_ : interpreter_due_ + hwstate->timestamp, hwstate->timestamp, timeout); HandleTimerImpl(hwstate->timestamp, timeout); + + // Copy finger flags for upstream filters. + QState* q_node = queue_.Head(); + if (q_node->state_.SameFingersAs(*hwstate)) { + for (size_t i = 0; i < hwstate->finger_cnt; i++) { + hwstate->fingers[i].flags = q_node->state_.fingers[i].flags; + } + } } // Interpolates the two hardware states into out. @@ -124,8 +132,13 @@ void LookaheadFilterInterpreter::AssignTrackingIds() { // For semi-mt devices, drumrolls and quick moves are handled in // SemiMtCorrectingFilterInterpreter already. We need to bypass the detection // and tracking id reassignment here to make fast-scroll working correctly. - if (hwprops_->support_semi_mt || !drumroll_suppression_enable_.val_) + // For haptic touchpads, we need to bypass tracking id reassignment so the + // haptic button filter can have the same tracking ids. + if (hwprops_->support_semi_mt || + hwprops_->is_haptic_pad || + !drumroll_suppression_enable_.val_) { return; + } if (queue_.size() < 2) { // Always reassign trackingID on the very first hwstate so that // the next hwstate can inherit the trackingID mapping. @@ -464,6 +477,11 @@ void LookaheadFilterInterpreter::HandleTimerImpl(stime_t now, // Mark current node completed. This should be the only completed // node in the queue. node->completed_ = true; + + // Copy finger flags for upstream filters. + for (size_t i = 0; i < node->state_.finger_cnt; i++) { + node->state_.fingers[i].flags = hs_copy.fingers[i].flags; + } } UpdateInterpreterDue(next_timeout, now, timeout); } diff --git a/src/metrics_filter_interpreter_unittest.cc b/src/metrics_filter_interpreter_unittest.cc new file mode 100644 index 0000000..83bf09d --- /dev/null +++ b/src/metrics_filter_interpreter_unittest.cc @@ -0,0 +1,230 @@ +// Copyright 2022 The ChromiumOS Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <gtest/gtest.h> + +#include "include/metrics_filter_interpreter.h" +#include "include/unittest_util.h" + +namespace gestures { + +class MetricsFilterInterpreterTest : public ::testing::Test {}; + +class MetricsFilterInterpreterTestInterpreter : public Interpreter { + public: + MetricsFilterInterpreterTestInterpreter() + : Interpreter(NULL, NULL, false), + handle_timer_called_(false) {} + + virtual void SyncInterpret(HardwareState* hwstate, stime_t* timeout) { + EXPECT_NE(static_cast<HardwareState*>(NULL), hwstate); + EXPECT_EQ(1, hwstate->finger_cnt); + prev_ = hwstate->fingers[0]; + } + + virtual void HandleTimer(stime_t now, stime_t* timeout) { + handle_timer_called_ = true; + } + + FingerState prev_; + bool handle_timer_called_; +}; + + +TEST(MetricsFilterInterpreterTest, SimpleTestTouchpad) { + MetricsFilterInterpreterTestInterpreter* base_interpreter = + new MetricsFilterInterpreterTestInterpreter; + MetricsFilterInterpreter interpreter(NULL, base_interpreter, NULL, + 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_); + wrapper.HandleTimer(0.0, NULL); + EXPECT_TRUE(base_interpreter->handle_timer_called_); + + FingerState finger_states[] = { + // TM, Tm, WM, Wm, Press, Orientation, X, Y, TrID + // Consistent movement for 16 frames + {0, 0, 0, 0, 20, 0, 40, 20, 1, 0}, // 0 + {0, 0, 0, 0, 20, 0, 40, 25, 1, 0}, // 1 + {0, 0, 0, 0, 20, 0, 40, 30, 1, 0}, // 2 + {0, 0, 0, 0, 20, 0, 40, 35, 1, 0}, // 3 + {0, 0, 0, 0, 20, 0, 40, 40, 1, 0}, // 4 + {0, 0, 0, 0, 20, 0, 40, 45, 1, 0}, // 5 + {0, 0, 0, 0, 20, 0, 40, 50, 1, 0}, // 6 + {0, 0, 0, 0, 20, 0, 40, 55, 1, 0}, // 7 + {0, 0, 0, 0, 20, 0, 40, 60, 1, 0}, // 8 + {0, 0, 0, 0, 20, 0, 40, 65, 1, 0}, // 9 + {0, 0, 0, 0, 20, 0, 40, 70, 1, 0}, // 10 + {0, 0, 0, 0, 20, 0, 40, 75, 1, 0}, // 11 + {0, 0, 0, 0, 20, 0, 40, 80, 1, 0}, // 12 + {0, 0, 0, 0, 20, 0, 40, 85, 1, 0}, // 13 + {0, 0, 0, 0, 20, 0, 40, 90, 1, 0}, // 14 + {0, 0, 0, 0, 20, 0, 40, 95, 1, 0}, // 15 + }; + + HardwareState hardware_states[] = { + // time, buttons, finger count, touch count, finger states pointer + make_hwstate(1.00, 0, 1, 1, &finger_states[0]), + make_hwstate(1.01, 0, 1, 1, &finger_states[1]), + make_hwstate(1.02, 0, 1, 1, &finger_states[2]), + make_hwstate(1.03, 0, 1, 1, &finger_states[3]), + make_hwstate(1.04, 0, 1, 1, &finger_states[4]), + make_hwstate(1.05, 0, 1, 1, &finger_states[5]), + make_hwstate(1.06, 0, 1, 1, &finger_states[6]), + make_hwstate(1.07, 0, 1, 1, &finger_states[7]), + make_hwstate(1.08, 0, 1, 1, &finger_states[8]), + make_hwstate(1.09, 0, 1, 1, &finger_states[9]), + make_hwstate(1.10, 0, 1, 1, &finger_states[10]), + make_hwstate(1.11, 0, 1, 1, &finger_states[11]), + make_hwstate(1.12, 0, 1, 1, &finger_states[12]), + make_hwstate(1.13, 0, 1, 1, &finger_states[13]), + make_hwstate(1.14, 0, 1, 1, &finger_states[14]), + make_hwstate(1.15, 0, 1, 1, &finger_states[15]), + }; + + for (size_t i = 0; i < arraysize(hardware_states); i++) { + wrapper.SyncInterpret(&hardware_states[i], NULL); + } + + EXPECT_EQ(interpreter.devclass_, GESTURES_DEVCLASS_TOUCHPAD); + EXPECT_EQ(interpreter.mouse_movement_session_index_, 0); + EXPECT_EQ(interpreter.mouse_movement_current_session_length, 0); + EXPECT_EQ(interpreter.mouse_movement_current_session_start, 0.0); + EXPECT_EQ(interpreter.mouse_movement_current_session_last, 0.0); + EXPECT_EQ(interpreter.mouse_movement_current_session_distance, 0.0); + EXPECT_EQ(interpreter.noisy_ground_distance_threshold_.val_, 10.0); + EXPECT_EQ(interpreter.noisy_ground_time_threshold_.val_, 0.1); + EXPECT_EQ(interpreter.mouse_moving_time_threshold_.val_, 0.05); + EXPECT_EQ(interpreter.mouse_control_warmup_sessions_.val_, 100); +} + +TEST(MetricsFilterInterpreterTest, SimpleTestMultitouchMouse) { + MetricsFilterInterpreterTestInterpreter* base_interpreter = + new MetricsFilterInterpreterTestInterpreter; + MetricsFilterInterpreter interpreter(NULL, base_interpreter, NULL, + 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_); + wrapper.HandleTimer(0.0, NULL); + EXPECT_TRUE(base_interpreter->handle_timer_called_); + + FingerState finger_states[] = { + // TM, Tm, WM, Wm, Press, Orientation, X, Y, TrID + // Consistent movement for 16 frames + {0, 0, 0, 0, 20, 0, 40, 20, 1, 0}, // 0 + {0, 0, 0, 0, 20, 0, 40, 25, 1, 0}, // 1 + {0, 0, 0, 0, 20, 0, 40, 30, 1, 0}, // 2 + {0, 0, 0, 0, 20, 0, 40, 35, 1, 0}, // 3 + {0, 0, 0, 0, 20, 0, 40, 40, 1, 0}, // 4 + {0, 0, 0, 0, 20, 0, 40, 45, 1, 0}, // 5 + {0, 0, 0, 0, 20, 0, 40, 50, 1, 0}, // 6 + {0, 0, 0, 0, 20, 0, 40, 55, 1, 0}, // 7 + {0, 0, 0, 0, 20, 0, 40, 60, 1, 0}, // 8 + {0, 0, 0, 0, 20, 0, 40, 65, 1, 0}, // 9 + {0, 0, 0, 0, 20, 0, 40, 70, 1, 0}, // 10 + {0, 0, 0, 0, 20, 0, 40, 75, 1, 0}, // 11 + {0, 0, 0, 0, 20, 0, 40, 80, 1, 0}, // 12 + {0, 0, 0, 0, 20, 0, 40, 85, 1, 0}, // 13 + {0, 0, 0, 0, 20, 0, 40, 90, 1, 0}, // 14 + {0, 0, 0, 0, 20, 0, 40, 95, 1, 0}, // 15 + }; + + HardwareState hardware_states[] = { + // time, buttons, finger count, touch count, finger states pointer + make_hwstate(1.00, 0, 1, 1, &finger_states[0]), + make_hwstate(1.01, 0, 1, 1, &finger_states[1]), + make_hwstate(1.02, 0, 1, 1, &finger_states[2]), + make_hwstate(1.03, 0, 1, 1, &finger_states[3]), + make_hwstate(1.04, 0, 1, 1, &finger_states[4]), + make_hwstate(1.05, 0, 1, 1, &finger_states[5]), + make_hwstate(1.06, 0, 1, 1, &finger_states[6]), + make_hwstate(1.07, 0, 1, 1, &finger_states[7]), + make_hwstate(1.08, 0, 1, 1, &finger_states[8]), + make_hwstate(1.09, 0, 1, 1, &finger_states[9]), + make_hwstate(1.10, 0, 1, 1, &finger_states[10]), + make_hwstate(1.11, 0, 1, 1, &finger_states[11]), + make_hwstate(1.12, 0, 1, 1, &finger_states[12]), + make_hwstate(1.13, 0, 1, 1, &finger_states[13]), + make_hwstate(1.14, 0, 1, 1, &finger_states[14]), + make_hwstate(1.15, 0, 1, 1, &finger_states[15]), + }; + + for (size_t i = 0; i < arraysize(hardware_states); i++) { + wrapper.SyncInterpret(&hardware_states[i], NULL); + } + + EXPECT_EQ(interpreter.devclass_, GESTURES_DEVCLASS_MULTITOUCH_MOUSE); + EXPECT_EQ(interpreter.mouse_movement_session_index_, 0); + EXPECT_EQ(interpreter.mouse_movement_current_session_length, 0); + EXPECT_EQ(interpreter.mouse_movement_current_session_start, 0.0); + EXPECT_EQ(interpreter.mouse_movement_current_session_last, 0.0); + EXPECT_EQ(interpreter.mouse_movement_current_session_distance, 0.0); + EXPECT_EQ(interpreter.noisy_ground_distance_threshold_.val_, 10.0); + EXPECT_EQ(interpreter.noisy_ground_time_threshold_.val_, 0.1); + EXPECT_EQ(interpreter.mouse_moving_time_threshold_.val_, 0.05); + EXPECT_EQ(interpreter.mouse_control_warmup_sessions_.val_, 100); +} + +TEST(MetricsFilterInterpreterTest, SimpleTestPointingStick) { + MetricsFilterInterpreterTestInterpreter* base_interpreter = + new MetricsFilterInterpreterTestInterpreter; + MetricsFilterInterpreter interpreter(NULL, base_interpreter, NULL, + 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_); + wrapper.HandleTimer(0.0, NULL); + EXPECT_TRUE(base_interpreter->handle_timer_called_); + + EXPECT_EQ(interpreter.devclass_, GESTURES_DEVCLASS_POINTING_STICK); + EXPECT_EQ(interpreter.mouse_movement_session_index_, 0); + EXPECT_EQ(interpreter.mouse_movement_current_session_length, 0); + EXPECT_EQ(interpreter.mouse_movement_current_session_start, 0.0); + EXPECT_EQ(interpreter.mouse_movement_current_session_last, 0.0); + EXPECT_EQ(interpreter.mouse_movement_current_session_distance, 0.0); + EXPECT_EQ(interpreter.noisy_ground_distance_threshold_.val_, 10.0); + EXPECT_EQ(interpreter.noisy_ground_time_threshold_.val_, 0.1); + EXPECT_EQ(interpreter.mouse_moving_time_threshold_.val_, 0.05); + EXPECT_EQ(interpreter.mouse_control_warmup_sessions_.val_, 100); +} + +} // namespace gestures diff --git a/src/palm_classifying_filter_interpreter.cc b/src/palm_classifying_filter_interpreter.cc index 19a4f2f..7acbf58 100644 --- a/src/palm_classifying_filter_interpreter.cc +++ b/src/palm_classifying_filter_interpreter.cc @@ -164,6 +164,7 @@ bool PalmClassifyingFilterInterpreter::FingerInBottomArea( void PalmClassifyingFilterInterpreter::UpdatePalmState( const HardwareState& hwstate) { RemoveMissingIdsFromSet(&palm_, hwstate); + RemoveMissingIdsFromSet(&large_palm_, hwstate); RemoveMissingIdsFromMap(&pointing_, hwstate); RemoveMissingIdsFromSet(&non_stationary_palm_, hwstate); RemoveMissingIdsFromSet(&fingers_not_in_edge_, hwstate); @@ -180,6 +181,7 @@ void PalmClassifyingFilterInterpreter::UpdatePalmState( // Mark anything over the palm thresh as a palm if (fs.pressure >= palm_pressure_.val_ || fs.touch_major >= multi_palm_width_.val_) { + large_palm_.insert(fs.tracking_id); palm_.insert(fs.tracking_id); pointing_.erase(fs.tracking_id); continue; @@ -188,6 +190,7 @@ void PalmClassifyingFilterInterpreter::UpdatePalmState( if (hwstate.finger_cnt == 1 && hwstate.fingers[0].touch_major >= palm_width_.val_) { + large_palm_.insert(hwstate.fingers[0].tracking_id); palm_.insert(hwstate.fingers[0].tracking_id); pointing_.erase(hwstate.fingers[0].tracking_id); } @@ -214,6 +217,7 @@ void PalmClassifyingFilterInterpreter::UpdatePalmState( if (max_pressure_[fs.tracking_id] <= kFatFingerMaxPressure && max_width_[fs.tracking_id] <= kFatFingerMaxWidth && dist_sq > kFatFingerMinDistSq) { + large_palm_.erase(fs.tracking_id); palm_.erase(fs.tracking_id); } else { // Lock onto palm @@ -288,6 +292,9 @@ void PalmClassifyingFilterInterpreter::UpdatePalmState( void PalmClassifyingFilterInterpreter::UpdatePalmFlags(HardwareState* hwstate) { for (short i = 0; i < hwstate->finger_cnt; i++) { FingerState* fs = &hwstate->fingers[i]; + if (SetContainsValue(large_palm_, fs->tracking_id)) { + fs->flags |= GESTURES_FINGER_LARGE_PALM; + } if (SetContainsValue(palm_, fs->tracking_id)) { fs->flags |= GESTURES_FINGER_PALM; } else if (!MapContainsKey(pointing_, fs->tracking_id) && diff --git a/src/palm_classifying_filter_interpreter_unittest.cc b/src/palm_classifying_filter_interpreter_unittest.cc index 57d95fb..b1cbee1 100644 --- a/src/palm_classifying_filter_interpreter_unittest.cc +++ b/src/palm_classifying_filter_interpreter_unittest.cc @@ -286,14 +286,17 @@ TEST(PalmClassifyingFilterInterpreterTest, PalmAtEdgeTest) { break; case 0: // fallthrough case 1: - case 4: - case 5: case 8: case 9: case 10: case 12: base_interpreter->expected_flags_ = GESTURES_FINGER_PALM; break; + case 4: + case 5: + base_interpreter->expected_flags_ = + (GESTURES_FINGER_PALM | GESTURES_FINGER_LARGE_PALM); + break; default: ADD_FAILURE() << "Should be unreached."; break; @@ -659,7 +662,8 @@ TEST(PalmClassifyingFilterInterpreterTest, LargeTouchMajorTest) { input.touch_major_, 0, 0, 0, input.pressure_, 0, input.x_, input.y_, 1, 0 }; HardwareState hs = make_hwstate(input.now_, 0, 1, 1, &fs); - base_interpreter->expected_flags_ = GESTURES_FINGER_PALM; + base_interpreter->expected_flags_ = + (GESTURES_FINGER_PALM | GESTURES_FINGER_LARGE_PALM); wrapper.SyncInterpret(&hs, NULL); } } diff --git a/src/prop_registry_unittest.cc b/src/prop_registry_unittest.cc index 2226d80..1b994fb 100644 --- a/src/prop_registry_unittest.cc +++ b/src/prop_registry_unittest.cc @@ -22,8 +22,13 @@ class PropRegistryTestDelegate : public PropertyDelegate { public: PropRegistryTestDelegate() : call_cnt_(0) {} virtual void BoolWasWritten(BoolProperty* prop) { call_cnt_++; }; + virtual void BoolArrayWasWritten(BoolArrayProperty* prop) { call_cnt_++; }; virtual void DoubleWasWritten(DoubleProperty* prop) { call_cnt_++; }; + virtual void DoubleArrayWasWritten(DoubleArrayProperty* prop) { + call_cnt_++; + }; virtual void IntWasWritten(IntProperty* prop) { call_cnt_++; }; + virtual void IntArrayWasWritten(IntArrayProperty* prop) { call_cnt_++; }; virtual void StringWasWritten(StringProperty* prop) { call_cnt_++; }; int call_cnt_; @@ -82,6 +87,41 @@ TEST(PropRegistryTest, SimpleTest) { EXPECT_TRUE(strstr(ValueForProperty(stp2).c_str(), "bar")); stp2.HandleGesturesPropWritten(); EXPECT_EQ(expected_call_cnt, delegate.call_cnt_); + + + Json::Value my_bool_val = bp1.NewValue(); + Json::Value my_int_val = ip1.NewValue(); + Json::Value my_double_val = dp1.NewValue(); + Json::Value my_str_val = stp1.NewValue(); + EXPECT_TRUE(bp1.SetValue(my_bool_val)); + EXPECT_FALSE(bp1.SetValue(my_int_val)); + EXPECT_FALSE(bp1.SetValue(my_double_val)); + EXPECT_FALSE(bp1.SetValue(my_str_val)); + + EXPECT_FALSE(ip1.SetValue(my_bool_val)); + EXPECT_TRUE(ip1.SetValue(my_int_val)); + EXPECT_FALSE(ip1.SetValue(my_double_val)); + EXPECT_FALSE(ip1.SetValue(my_str_val)); + + EXPECT_FALSE(dp1.SetValue(my_bool_val)); + EXPECT_TRUE(dp1.SetValue(my_int_val)); + EXPECT_TRUE(dp1.SetValue(my_double_val)); + EXPECT_FALSE(dp1.SetValue(my_str_val)); + + EXPECT_FALSE(stp1.SetValue(my_bool_val)); + EXPECT_FALSE(stp1.SetValue(my_int_val)); + EXPECT_FALSE(stp1.SetValue(my_double_val)); + EXPECT_TRUE(stp1.SetValue(my_str_val)); + + // This code does not do anything but the code coverage + // hits for not covered areas due to not running the + // unused default virtual functions. + PropertyDelegate pd; + + pd.BoolWasWritten(&bp1); + pd.DoubleWasWritten(&dp1); + pd.IntWasWritten(&ip1); + pd.StringWasWritten(&stp1); } TEST(PropRegistryTest, PropChangeTest) { @@ -121,14 +161,6 @@ GesturesProp* MockGesturesPropCreateReal(void* data, const char* name, return dummy; } -GesturesProp* MockGesturesPropCreateShort(void* data, const char* name, - short* loc, size_t count, - const short* init) { - GesturesProp *dummy = new GesturesProp(); - *loc = 1; - return dummy; -} - GesturesProp* MockGesturesPropCreateString(void* data, const char* name, const char** loc, const char* const init) { @@ -152,7 +184,7 @@ void MockGesturesPropFree(void* data, GesturesProp* prop) { TEST(PropRegistryTest, SetAtCreateShouldNotifyTest) { GesturesPropProvider mock_gestures_props_provider = { MockGesturesPropCreateInt, - MockGesturesPropCreateShort, + NULL, MockGesturesPropCreateBool, MockGesturesPropCreateString, MockGesturesPropCreateReal, @@ -184,4 +216,101 @@ TEST(PropRegistryTest, DoublePromoteIntTest) { EXPECT_TRUE(my_double.SetValue(my_int_val)); EXPECT_TRUE(strstr(ValueForProperty(my_double).c_str(), "321")); } + +TEST(PropRegistryTest, BoolArrayTest) { + PropRegistry reg; + PropRegistry reg_with_delegate; + PropRegistryTestDelegate delegate; + + GesturesPropBool vals[] = { false, true }; + BoolArrayProperty my_bool_array_w_delegate( + ®, "MyBoolArray", vals, 2, &delegate); + EXPECT_EQ(0, delegate.call_cnt_); + my_bool_array_w_delegate.HandleGesturesPropWritten(); + EXPECT_EQ(1, delegate.call_cnt_); + delegate.BoolArrayWasWritten(&my_bool_array_w_delegate); + EXPECT_EQ(2, delegate.call_cnt_); + + IntProperty ip1(®, "hi", 567, &delegate); + StringProperty stp1(®, "hi", "foo", &delegate); + Json::Value my_bool_array_val = my_bool_array_w_delegate.NewValue(); + Json::Value my_int_val = ip1.NewValue(); + Json::Value my_str_val = stp1.NewValue(); + EXPECT_FALSE(my_bool_array_w_delegate.SetValue(my_int_val)); + EXPECT_FALSE(my_bool_array_w_delegate.SetValue(my_str_val)); + EXPECT_TRUE(my_bool_array_w_delegate.SetValue(my_bool_array_val)); + + // This code does not do anything but the code coverage + // hits for not covered areas due to not running the + // unused default virtual functions. + PropertyDelegate pd; + + BoolArrayProperty my_bool_array(®, "MyBoolArray", vals, 2); + pd.BoolArrayWasWritten(&my_bool_array); +} + +TEST(PropRegistryTest, DoubleArrayTest) { + PropRegistry reg; + PropRegistry reg_with_delegate; + PropRegistryTestDelegate delegate; + + double vals[] = { 0.0, 1.0 }; + DoubleArrayProperty my_double_array_w_delegate( + ®, "MyDoubleArray", vals, 2, &delegate); + EXPECT_EQ(0, delegate.call_cnt_); + my_double_array_w_delegate.HandleGesturesPropWritten(); + EXPECT_EQ(1, delegate.call_cnt_); + delegate.DoubleArrayWasWritten(&my_double_array_w_delegate); + EXPECT_EQ(2, delegate.call_cnt_); + + IntProperty ip1(®, "hi", 567, &delegate); + StringProperty stp1(®, "hi", "foo", &delegate); + Json::Value my_double_array_val = my_double_array_w_delegate.NewValue(); + Json::Value my_int_val = ip1.NewValue(); + Json::Value my_str_val = stp1.NewValue(); + EXPECT_FALSE(my_double_array_w_delegate.SetValue(my_int_val)); + EXPECT_FALSE(my_double_array_w_delegate.SetValue(my_str_val)); + EXPECT_TRUE(my_double_array_w_delegate.SetValue(my_double_array_val)); + + // This code does not do anything but the code coverage + // hits for not covered areas due to not running the + // unused default virtual functions. + PropertyDelegate pd; + + DoubleArrayProperty my_double_array(®, "MyDoubleArray", vals, 2); + pd.DoubleArrayWasWritten(&my_double_array); +} + +TEST(PropRegistryTest, IntArrayTest) { + PropRegistry reg; + PropRegistry reg_with_delegate; + PropRegistryTestDelegate delegate; + + int vals[] = { 0, 1 }; + IntArrayProperty my_int_array_w_delegate( + ®, "MyIntArray", vals, 2, &delegate); + EXPECT_EQ(0, delegate.call_cnt_); + my_int_array_w_delegate.HandleGesturesPropWritten(); + EXPECT_EQ(1, delegate.call_cnt_); + delegate.IntArrayWasWritten(&my_int_array_w_delegate); + EXPECT_EQ(2, delegate.call_cnt_); + + IntProperty ip1(®, "hi", 567, &delegate); + StringProperty stp1(®, "hi", "foo", &delegate); + Json::Value my_int_array_val = my_int_array_w_delegate.NewValue(); + Json::Value my_int_val = ip1.NewValue(); + Json::Value my_str_val = stp1.NewValue(); + EXPECT_FALSE(my_int_array_w_delegate.SetValue(my_int_val)); + EXPECT_FALSE(my_int_array_w_delegate.SetValue(my_str_val)); + EXPECT_TRUE(my_int_array_w_delegate.SetValue(my_int_array_val)); + + // This code does not do anything but the code coverage + // hits for not covered areas due to not running the + // unused default virtual functions. + PropertyDelegate pd; + + IntArrayProperty my_int_array(®, "MyIntArray", vals, 2); + pd.IntArrayWasWritten(&my_int_array); +} + } // namespace gestures diff --git a/src/scaling_filter_interpreter.cc b/src/scaling_filter_interpreter.cc index 97bde2b..1094455 100644 --- a/src/scaling_filter_interpreter.cc +++ b/src/scaling_filter_interpreter.cc @@ -25,7 +25,8 @@ ScalingFilterInterpreter::ScalingFilterInterpreter( screen_x_scale_(1.0), screen_y_scale_(1.0), orientation_scale_(1.0), - australian_scrolling_(prop_reg, "Australian Scrolling", false), + invert_scrolling_and_swiping_(prop_reg, "Australian Scrolling", false), + invert_scrolling_only_(prop_reg, "Invert Scrolling", false), surface_area_from_pressure_(prop_reg, "Compute Surface Area from Pressure", true), use_touch_size_for_haptic_pad_( @@ -255,7 +256,8 @@ void ScalingFilterInterpreter::ConsumeGesture(const Gesture& gs) { copy.details.scroll.ordinal_dx *= screen_x_scale_; copy.details.scroll.ordinal_dy *= screen_y_scale_; } - if (!australian_scrolling_.val_) { + if (!(invert_scrolling_and_swiping_.val_ || + invert_scrolling_only_.val_)) { copy.details.scroll.dx *= -1; copy.details.scroll.dy *= -1; copy.details.scroll.ordinal_dx *= -1; @@ -263,7 +265,8 @@ void ScalingFilterInterpreter::ConsumeGesture(const Gesture& gs) { } break; case kGestureTypeMouseWheel: - if (!australian_scrolling_.val_) { + if (!(invert_scrolling_and_swiping_.val_ || + invert_scrolling_only_.val_)) { copy.details.wheel.dx *= -1; copy.details.wheel.dy *= -1; copy.details.wheel.tick_120ths_dx *= -1; @@ -275,7 +278,8 @@ void ScalingFilterInterpreter::ConsumeGesture(const Gesture& gs) { copy.details.fling.vy *= screen_y_scale_; copy.details.fling.ordinal_vx *= screen_x_scale_; copy.details.fling.ordinal_vy *= screen_y_scale_; - if (!australian_scrolling_.val_) { + if (!(invert_scrolling_and_swiping_.val_ || + invert_scrolling_only_.val_)) { copy.details.fling.vx *= -1; copy.details.fling.vy *= -1; copy.details.fling.ordinal_vx *= -1; @@ -288,7 +292,7 @@ void ScalingFilterInterpreter::ConsumeGesture(const Gesture& gs) { copy.details.swipe.dy *= screen_y_scale_; copy.details.swipe.ordinal_dx *= screen_x_scale_; copy.details.swipe.ordinal_dy *= screen_y_scale_; - if (!australian_scrolling_.val_) { + if (!invert_scrolling_and_swiping_.val_) { copy.details.swipe.dy *= -1; copy.details.swipe.ordinal_dy *= -1; } @@ -299,7 +303,7 @@ void ScalingFilterInterpreter::ConsumeGesture(const Gesture& gs) { copy.details.four_finger_swipe.dy *= screen_y_scale_; copy.details.four_finger_swipe.ordinal_dx *= screen_x_scale_; copy.details.four_finger_swipe.ordinal_dy *= screen_y_scale_; - if (!australian_scrolling_.val_) { + if (!invert_scrolling_and_swiping_.val_) { copy.details.four_finger_swipe.dy *= -1; copy.details.four_finger_swipe.ordinal_dy *= -1; } diff --git a/src/stationary_wiggle_filter_interpreter_unittest.cc b/src/stationary_wiggle_filter_interpreter_unittest.cc new file mode 100644 index 0000000..83c541c --- /dev/null +++ b/src/stationary_wiggle_filter_interpreter_unittest.cc @@ -0,0 +1,152 @@ +// Copyright 2022 The ChromiumOS Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <gtest/gtest.h> + +#include "include/stationary_wiggle_filter_interpreter.h" +#include "include/unittest_util.h" + +namespace gestures { + +class StationaryWiggleFilterInterpreterTest : public ::testing::Test {}; + +class StationaryWiggleFilterInterpreterTestInterpreter : public Interpreter { + public: + StationaryWiggleFilterInterpreterTestInterpreter() + : Interpreter(NULL, NULL, false), + handle_timer_called_(false) {} + + virtual void SyncInterpret(HardwareState* hwstate, stime_t* timeout) { + EXPECT_NE(static_cast<HardwareState*>(NULL), hwstate); + EXPECT_EQ(1, hwstate->finger_cnt); + prev_ = hwstate->fingers[0]; + } + + virtual void HandleTimer(stime_t now, stime_t* timeout) { + handle_timer_called_ = true; + } + + FingerState prev_; + bool handle_timer_called_; +}; + + +TEST(StationaryWiggleFilterInterpreterTest, SimpleTest) { + FingerEnergy fe = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + FingerEnergy fe_eq = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + FingerEnergy fe_ne0 = {9.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + FingerEnergy fe_ne1 = {1.0, 9.0, 1.0, 1.0, 1.0, 1.0}; + FingerEnergy fe_ne2 = {1.0, 1.0, 9.0, 1.0, 1.0, 1.0}; + FingerEnergy fe_ne3 = {1.0, 1.0, 1.0, 9.0, 1.0, 1.0}; + FingerEnergy fe_ne4 = {1.0, 1.0, 1.0, 1.0, 9.0, 1.0}; + FingerEnergy fe_ne5 = {1.0, 1.0, 1.0, 1.0, 1.0, 9.0}; + + EXPECT_EQ(fe, fe_eq); + EXPECT_NE(fe, fe_ne0); + EXPECT_NE(fe, fe_ne1); + EXPECT_NE(fe, fe_ne2); + EXPECT_NE(fe, fe_ne3); + EXPECT_NE(fe, fe_ne4); + EXPECT_NE(fe, fe_ne5); + + + StationaryWiggleFilterInterpreterTestInterpreter* base_interpreter = + new StationaryWiggleFilterInterpreterTestInterpreter; + StationaryWiggleFilterInterpreter interpreter(NULL, base_interpreter, NULL); + + EXPECT_FALSE(interpreter.enabled_.val_); + 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 + }; + TestInterpreterWrapper wrapper(&interpreter, &hwprops); + + EXPECT_FALSE(base_interpreter->handle_timer_called_); + wrapper.HandleTimer(0.0, NULL); + EXPECT_TRUE(base_interpreter->handle_timer_called_); + + FingerState finger_states[] = { + // TM, Tm, WM, Wm, Press, Orientation, X, Y, TrID + // Consistent movement for 16 frames + {0, 0, 0, 0, 20, 0, 40, 20, 1, 0}, // 0 + {0, 0, 0, 0, 20, 0, 40, 25, 1, 0}, // 1 + {0, 0, 0, 0, 20, 0, 40, 30, 1, 0}, // 2 + {0, 0, 0, 0, 20, 0, 40, 35, 1, 0}, // 3 + {0, 0, 0, 0, 20, 0, 40, 40, 1, 0}, // 4 + {0, 0, 0, 0, 20, 0, 40, 45, 1, 0}, // 5 + {0, 0, 0, 0, 20, 0, 40, 50, 1, 0}, // 6 + {0, 0, 0, 0, 20, 0, 40, 55, 1, 0}, // 7 + {0, 0, 0, 0, 20, 0, 40, 60, 1, 0}, // 8 + {0, 0, 0, 0, 20, 0, 40, 65, 1, 0}, // 9 + {0, 0, 0, 0, 20, 0, 40, 70, 1, 0}, // 10 + {0, 0, 0, 0, 20, 0, 40, 75, 1, 0}, // 11 + {0, 0, 0, 0, 20, 0, 40, 80, 1, 0}, // 12 + {0, 0, 0, 0, 20, 0, 40, 85, 1, 0}, // 13 + {0, 0, 0, 0, 20, 0, 40, 90, 1, 0}, // 14 + {0, 0, 0, 0, 20, 0, 40, 95, 1, 0}, // 15 + }; + + HardwareState hardware_states[] = { + // time, buttons, finger count, touch count, finger states pointer + make_hwstate(1.00, 0, 1, 1, &finger_states[0]), + make_hwstate(1.01, 0, 1, 1, &finger_states[1]), + make_hwstate(1.02, 0, 1, 1, &finger_states[2]), + make_hwstate(1.03, 0, 1, 1, &finger_states[3]), + make_hwstate(1.04, 0, 1, 1, &finger_states[4]), + make_hwstate(1.05, 0, 1, 1, &finger_states[5]), + make_hwstate(1.06, 0, 1, 1, &finger_states[6]), + make_hwstate(1.07, 0, 1, 1, &finger_states[7]), + make_hwstate(1.08, 0, 1, 1, &finger_states[8]), + make_hwstate(1.09, 0, 1, 1, &finger_states[9]), + make_hwstate(1.10, 0, 1, 1, &finger_states[10]), + make_hwstate(1.11, 0, 1, 1, &finger_states[11]), + make_hwstate(1.12, 0, 1, 1, &finger_states[12]), + make_hwstate(1.13, 0, 1, 1, &finger_states[13]), + make_hwstate(1.14, 0, 1, 1, &finger_states[14]), + make_hwstate(1.15, 0, 1, 1, &finger_states[15]), + }; + + unsigned expected[] = { + 0, 0, 0, 0, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + GESTURES_FINGER_INSTANTANEOUS_MOVING, + }; + + for (size_t i = 0; i < arraysize(hardware_states); i++) { + HardwareState *hwstate = &hardware_states[i]; + wrapper.SyncInterpret(hwstate, NULL); + for (int j = 0; j < hwstate->finger_cnt; ++j) { + FingerState *fs = &hwstate->fingers[j]; + EXPECT_EQ(fs->flags & (GESTURES_FINGER_WARP_X | + GESTURES_FINGER_WARP_Y | + GESTURES_FINGER_INSTANTANEOUS_MOVING), + expected[i]); + } + } + + EXPECT_TRUE(interpreter.enabled_.val_); + EXPECT_EQ(interpreter.threshold_.val_, 0.012); + EXPECT_EQ(interpreter.hysteresis_.val_, 0.006); +} + +} // namespace gestures diff --git a/src/trace_marker_unittest.cc b/src/trace_marker_unittest.cc index 6b4a192..b7d1157 100644 --- a/src/trace_marker_unittest.cc +++ b/src/trace_marker_unittest.cc @@ -16,7 +16,14 @@ TEST(TraceMarkerTest, DeleteTraceMarkerTest) { EXPECT_EQ(NULL, TraceMarker::GetTraceMarker()); TraceMarker::CreateTraceMarker(); EXPECT_TRUE(NULL != TraceMarker::GetTraceMarker()); + TraceMarker::StaticTraceWrite("Test"); + EXPECT_EQ(-1, TraceMarker::GetTraceMarker()->fd_); + EXPECT_EQ(1, TraceMarker::trace_marker_count_); TraceMarker::DeleteTraceMarker(); EXPECT_EQ(NULL, TraceMarker::GetTraceMarker()); + TraceMarker::StaticTraceWrite("Test"); + EXPECT_EQ(0, TraceMarker::trace_marker_count_); + TraceMarker::DeleteTraceMarker(); + EXPECT_EQ(0, TraceMarker::trace_marker_count_); }; } // namespace gestures diff --git a/src/trend_classifying_filter_interpreter_unittest.cc b/src/trend_classifying_filter_interpreter_unittest.cc new file mode 100644 index 0000000..de45efe --- /dev/null +++ b/src/trend_classifying_filter_interpreter_unittest.cc @@ -0,0 +1,120 @@ +// Copyright 2022 The ChromiumOS Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <gtest/gtest.h> + +#include "include/trend_classifying_filter_interpreter.h" +#include "include/unittest_util.h" + +namespace gestures { + +class TrendClassifyingFilterInterpreterTest : public ::testing::Test {}; + +class TrendClassifyingFilterInterpreterTestInterpreter : public Interpreter { + public: + TrendClassifyingFilterInterpreterTestInterpreter() + : Interpreter(NULL, NULL, false), + handle_timer_called_(false) {} + + virtual void SyncInterpret(HardwareState* hwstate, stime_t* timeout) { + EXPECT_NE(static_cast<HardwareState*>(NULL), hwstate); + EXPECT_EQ(1, hwstate->finger_cnt); + prev_ = hwstate->fingers[0]; + } + + virtual void HandleTimer(stime_t now, stime_t* timeout) { + handle_timer_called_ = true; + } + + FingerState prev_; + bool handle_timer_called_; +}; + + +TEST(TrendClassifyingFilterInterpreterTest, SimpleTest) { + TrendClassifyingFilterInterpreterTestInterpreter* base_interpreter = + new TrendClassifyingFilterInterpreterTestInterpreter; + TrendClassifyingFilterInterpreter interpreter(NULL, base_interpreter, NULL); + + EXPECT_TRUE(interpreter.trend_classifying_filter_enable_.val_); + + EXPECT_FALSE(interpreter.second_order_enable_.val_); + interpreter.second_order_enable_.val_ = true; + 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 + }; + TestInterpreterWrapper wrapper(&interpreter, &hwprops); + + EXPECT_FALSE(base_interpreter->handle_timer_called_); + wrapper.HandleTimer(0.0, NULL); + EXPECT_TRUE(base_interpreter->handle_timer_called_); + + FingerState finger_states[] = { + // TM, Tm, WM, Wm, Press, Orientation, X, Y, TrID + // Consistent movement for 16 frames + {0, 0, 0, 0, 20, 0, 40, 20, 1, 0}, // 0 + {0, 0, 0, 0, 20, 0, 40, 25, 1, 0}, // 1 + {0, 0, 0, 0, 20, 0, 40, 30, 1, 0}, // 2 + {0, 0, 0, 0, 20, 0, 40, 35, 1, 0}, // 3 + {0, 0, 0, 0, 20, 0, 40, 40, 1, 0}, // 4 + {0, 0, 0, 0, 20, 0, 40, 45, 1, 0}, // 5 + {0, 0, 0, 0, 20, 0, 40, 50, 1, 0}, // 6 + {0, 0, 0, 0, 20, 0, 40, 55, 1, 0}, // 7 + {0, 0, 0, 0, 20, 0, 40, 60, 1, 0}, // 8 + {0, 0, 0, 0, 20, 0, 40, 65, 1, 0}, // 9 + {0, 0, 0, 0, 20, 0, 40, 70, 1, 0}, // 10 + {0, 0, 0, 0, 20, 0, 40, 75, 1, 0}, // 11 + {0, 0, 0, 0, 20, 0, 40, 80, 1, 0}, // 12 + {0, 0, 0, 0, 20, 0, 40, 85, 1, 0}, // 13 + {0, 0, 0, 0, 20, 0, 40, 90, 1, 0}, // 14 + {0, 0, 0, 0, 20, 0, 40, 95, 1, 0}, // 15 + }; + + HardwareState hardware_states[] = { + // time, buttons, finger count, touch count, finger states pointer + make_hwstate(1.00, 0, 1, 1, &finger_states[0]), + make_hwstate(1.01, 0, 1, 1, &finger_states[1]), + make_hwstate(1.02, 0, 1, 1, &finger_states[2]), + make_hwstate(1.03, 0, 1, 1, &finger_states[3]), + make_hwstate(1.04, 0, 1, 1, &finger_states[4]), + make_hwstate(1.05, 0, 1, 1, &finger_states[5]), + make_hwstate(1.06, 0, 1, 1, &finger_states[6]), + make_hwstate(1.07, 0, 1, 1, &finger_states[7]), + make_hwstate(1.08, 0, 1, 1, &finger_states[8]), + make_hwstate(1.09, 0, 1, 1, &finger_states[9]), + make_hwstate(1.10, 0, 1, 1, &finger_states[10]), + make_hwstate(1.11, 0, 1, 1, &finger_states[11]), + make_hwstate(1.12, 0, 1, 1, &finger_states[12]), + make_hwstate(1.13, 0, 1, 1, &finger_states[13]), + make_hwstate(1.14, 0, 1, 1, &finger_states[14]), + make_hwstate(1.15, 0, 1, 1, &finger_states[15]), + }; + + for (size_t i = 0; i < arraysize(hardware_states); i++) { + HardwareState *hwstate = &hardware_states[i]; + wrapper.SyncInterpret(hwstate, NULL); + + for (short j = 0; i < hwstate->finger_cnt; i++) { + FingerState *fs = &hwstate->fingers[j]; + EXPECT_EQ(fs->flags, 0); + } + } + + EXPECT_TRUE(interpreter.trend_classifying_filter_enable_.val_); + EXPECT_TRUE(interpreter.second_order_enable_.val_); + EXPECT_EQ(interpreter.min_num_of_samples_.val_, 6); + EXPECT_EQ(interpreter.z_threshold_.val_, 2.5758293035489004); +} + +} // namespace gestures |