Loading services/inputflinger/include/InputReaderBase.h +4 −0 Original line number Diff line number Diff line Loading @@ -245,6 +245,9 @@ struct InputReaderConfiguration { // True to use three-finger tap as a customizable shortcut; false to use it as a middle-click. bool touchpadThreeFingerTapShortcutEnabled; // True to enable system gestures (three- and four-finger swipes) on touchpads. bool touchpadSystemGesturesEnabled; // The set of currently disabled input devices. std::set<int32_t> disabledDevices; Loading Loading @@ -297,6 +300,7 @@ struct InputReaderConfiguration { shouldNotifyTouchpadHardwareState(false), touchpadRightClickZoneEnabled(false), touchpadThreeFingerTapShortcutEnabled(false), touchpadSystemGesturesEnabled(true), stylusButtonMotionEventsEnabled(true), stylusPointerIconEnabled(false), mouseReverseVerticalScrollingEnabled(false), Loading services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +3 −2 Original line number Diff line number Diff line Loading @@ -351,6 +351,7 @@ std::list<NotifyArgs> TouchpadInputMapper::reconfigure(nsecs_t when, bumpGeneration(); } std::list<NotifyArgs> out; if (!changes.any() || changes.test(InputReaderConfiguration::Change::TOUCHPAD_SETTINGS)) { mPropertyProvider.getProperty("Use Custom Touchpad Pointer Accel Curve") .setBoolValues({true}); Loading @@ -375,11 +376,11 @@ std::list<NotifyArgs> TouchpadInputMapper::reconfigure(nsecs_t when, mPropertyProvider.getProperty("Button Right Click Zone Enable") .setBoolValues({config.touchpadRightClickZoneEnabled}); mTouchpadHardwareStateNotificationsEnabled = config.shouldNotifyTouchpadHardwareState; mGestureConverter.setThreeFingerTapShortcutEnabled( config.touchpadThreeFingerTapShortcutEnabled); out += mGestureConverter.setEnableSystemGestures(when, config.touchpadSystemGesturesEnabled); } std::list<NotifyArgs> out; if ((!changes.any() && config.pointerCaptureRequest.isEnable()) || changes.test(InputReaderConfiguration::Change::POINTER_CAPTURE)) { mPointerCaptured = config.pointerCaptureRequest.isEnable(); Loading services/inputflinger/reader/mapper/gestures/GestureConverter.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,15 @@ std::list<NotifyArgs> GestureConverter::reset(nsecs_t when) { return out; } std::list<NotifyArgs> GestureConverter::setEnableSystemGestures(nsecs_t when, bool enable) { std::list<NotifyArgs> out; if (!enable && mCurrentClassification == MotionClassification::MULTI_FINGER_SWIPE) { out += handleMultiFingerSwipeLift(when, when); } mEnableSystemGestures = enable; return out; } void GestureConverter::populateMotionRanges(InputDeviceInfo& info) const { info.addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, SOURCE, 0.0f, 1.0f, 0, 0, 0); Loading Loading @@ -461,6 +470,9 @@ std::list<NotifyArgs> GestureConverter::endScroll(nsecs_t when, nsecs_t readTime uint32_t fingerCount, float dx, float dy) { std::list<NotifyArgs> out = {}; if (!mEnableSystemGestures) { return out; } if (mCurrentClassification != MotionClassification::MULTI_FINGER_SWIPE) { // If the user changes the number of fingers mid-way through a swipe (e.g. they start with Loading services/inputflinger/reader/mapper/gestures/GestureConverter.h +3 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,8 @@ public: mThreeFingerTapShortcutEnabled = enabled; } [[nodiscard]] std::list<NotifyArgs> setEnableSystemGestures(nsecs_t when, bool enable); void populateMotionRanges(InputDeviceInfo& info) const; [[nodiscard]] std::list<NotifyArgs> handleGesture(nsecs_t when, nsecs_t readTime, Loading Loading @@ -104,6 +106,7 @@ private: InputReaderContext& mReaderContext; const bool mEnableFlingStop; const bool mEnableNoFocusChange; bool mEnableSystemGestures{true}; bool mThreeFingerTapShortcutEnabled; Loading services/inputflinger/tests/GestureConverter_test.cpp +102 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ const auto TOUCHPAD_PALM_REJECTION_V2 = using testing::AllOf; using testing::Each; using testing::ElementsAre; using testing::IsEmpty; using testing::VariantWith; class GestureConverterTest : public testing::Test { Loading Loading @@ -849,6 +850,107 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { WithDisplayId(ui::LogicalDisplayId::DEFAULT))))); } TEST_F(GestureConverterTest, DisablingSystemGestures_IgnoresMultiFingerSwipe) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setDisplayId(ui::LogicalDisplayId::DEFAULT); std::list<NotifyArgs> args = converter.setEnableSystemGestures(ARBITRARY_TIME, false); ASSERT_THAT(args, IsEmpty()); Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/10); Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/5); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); args += converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); args += converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); args += converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); ASSERT_THAT(args, IsEmpty()); args = converter.setEnableSystemGestures(ARBITRARY_TIME, true); ASSERT_THAT(args, IsEmpty()); args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( WithMotionAction(AMOTION_EVENT_ACTION_DOWN)), VariantWith<NotifyMotionArgs>(WithMotionAction( AMOTION_EVENT_ACTION_POINTER_DOWN | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT)), VariantWith<NotifyMotionArgs>(WithMotionAction( AMOTION_EVENT_ACTION_POINTER_DOWN | 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT)), VariantWith<NotifyMotionArgs>( WithMotionAction(AMOTION_EVENT_ACTION_MOVE)))); ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>( WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE)))); } TEST_F(GestureConverterTest, DisablingSystemGestures_EndsOngoingMultiFingerSwipe) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setDisplayId(ui::LogicalDisplayId::DEFAULT); Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/10); std::list<NotifyArgs> args; args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); ASSERT_FALSE(args.empty()); // Disabling system gestures should end the swipe early. args = converter.setEnableSystemGestures(ARBITRARY_TIME, false); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction( AMOTION_EVENT_ACTION_POINTER_UP | 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification( MotionClassification::MULTI_FINGER_SWIPE), WithPointerCount(3u))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction( AMOTION_EVENT_ACTION_POINTER_UP | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification( MotionClassification::MULTI_FINGER_SWIPE), WithPointerCount(2u))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), WithMotionClassification( MotionClassification::MULTI_FINGER_SWIPE), WithPointerCount(1u))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), WithMotionClassification(MotionClassification::NONE))))); ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>( AllOf(WithToolType(ToolType::FINGER), WithDisplayId(ui::LogicalDisplayId::DEFAULT))))); // Further movement in the same swipe should be ignored. Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/5); args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); ASSERT_THAT(args, IsEmpty()); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); ASSERT_THAT(args, IsEmpty()); // But single-finger pointer motion should be reported. Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithRelativeMotion(-5, 10), WithButtonState(0))))); } TEST_F(GestureConverterTest, Pinch_Inwards) { input_flags::enable_touchpad_no_focus_change(true); Loading Loading
services/inputflinger/include/InputReaderBase.h +4 −0 Original line number Diff line number Diff line Loading @@ -245,6 +245,9 @@ struct InputReaderConfiguration { // True to use three-finger tap as a customizable shortcut; false to use it as a middle-click. bool touchpadThreeFingerTapShortcutEnabled; // True to enable system gestures (three- and four-finger swipes) on touchpads. bool touchpadSystemGesturesEnabled; // The set of currently disabled input devices. std::set<int32_t> disabledDevices; Loading Loading @@ -297,6 +300,7 @@ struct InputReaderConfiguration { shouldNotifyTouchpadHardwareState(false), touchpadRightClickZoneEnabled(false), touchpadThreeFingerTapShortcutEnabled(false), touchpadSystemGesturesEnabled(true), stylusButtonMotionEventsEnabled(true), stylusPointerIconEnabled(false), mouseReverseVerticalScrollingEnabled(false), Loading
services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +3 −2 Original line number Diff line number Diff line Loading @@ -351,6 +351,7 @@ std::list<NotifyArgs> TouchpadInputMapper::reconfigure(nsecs_t when, bumpGeneration(); } std::list<NotifyArgs> out; if (!changes.any() || changes.test(InputReaderConfiguration::Change::TOUCHPAD_SETTINGS)) { mPropertyProvider.getProperty("Use Custom Touchpad Pointer Accel Curve") .setBoolValues({true}); Loading @@ -375,11 +376,11 @@ std::list<NotifyArgs> TouchpadInputMapper::reconfigure(nsecs_t when, mPropertyProvider.getProperty("Button Right Click Zone Enable") .setBoolValues({config.touchpadRightClickZoneEnabled}); mTouchpadHardwareStateNotificationsEnabled = config.shouldNotifyTouchpadHardwareState; mGestureConverter.setThreeFingerTapShortcutEnabled( config.touchpadThreeFingerTapShortcutEnabled); out += mGestureConverter.setEnableSystemGestures(when, config.touchpadSystemGesturesEnabled); } std::list<NotifyArgs> out; if ((!changes.any() && config.pointerCaptureRequest.isEnable()) || changes.test(InputReaderConfiguration::Change::POINTER_CAPTURE)) { mPointerCaptured = config.pointerCaptureRequest.isEnable(); Loading
services/inputflinger/reader/mapper/gestures/GestureConverter.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,15 @@ std::list<NotifyArgs> GestureConverter::reset(nsecs_t when) { return out; } std::list<NotifyArgs> GestureConverter::setEnableSystemGestures(nsecs_t when, bool enable) { std::list<NotifyArgs> out; if (!enable && mCurrentClassification == MotionClassification::MULTI_FINGER_SWIPE) { out += handleMultiFingerSwipeLift(when, when); } mEnableSystemGestures = enable; return out; } void GestureConverter::populateMotionRanges(InputDeviceInfo& info) const { info.addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, SOURCE, 0.0f, 1.0f, 0, 0, 0); Loading Loading @@ -461,6 +470,9 @@ std::list<NotifyArgs> GestureConverter::endScroll(nsecs_t when, nsecs_t readTime uint32_t fingerCount, float dx, float dy) { std::list<NotifyArgs> out = {}; if (!mEnableSystemGestures) { return out; } if (mCurrentClassification != MotionClassification::MULTI_FINGER_SWIPE) { // If the user changes the number of fingers mid-way through a swipe (e.g. they start with Loading
services/inputflinger/reader/mapper/gestures/GestureConverter.h +3 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,8 @@ public: mThreeFingerTapShortcutEnabled = enabled; } [[nodiscard]] std::list<NotifyArgs> setEnableSystemGestures(nsecs_t when, bool enable); void populateMotionRanges(InputDeviceInfo& info) const; [[nodiscard]] std::list<NotifyArgs> handleGesture(nsecs_t when, nsecs_t readTime, Loading Loading @@ -104,6 +106,7 @@ private: InputReaderContext& mReaderContext; const bool mEnableFlingStop; const bool mEnableNoFocusChange; bool mEnableSystemGestures{true}; bool mThreeFingerTapShortcutEnabled; Loading
services/inputflinger/tests/GestureConverter_test.cpp +102 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ const auto TOUCHPAD_PALM_REJECTION_V2 = using testing::AllOf; using testing::Each; using testing::ElementsAre; using testing::IsEmpty; using testing::VariantWith; class GestureConverterTest : public testing::Test { Loading Loading @@ -849,6 +850,107 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { WithDisplayId(ui::LogicalDisplayId::DEFAULT))))); } TEST_F(GestureConverterTest, DisablingSystemGestures_IgnoresMultiFingerSwipe) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setDisplayId(ui::LogicalDisplayId::DEFAULT); std::list<NotifyArgs> args = converter.setEnableSystemGestures(ARBITRARY_TIME, false); ASSERT_THAT(args, IsEmpty()); Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/10); Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/5); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); args += converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); args += converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); args += converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); ASSERT_THAT(args, IsEmpty()); args = converter.setEnableSystemGestures(ARBITRARY_TIME, true); ASSERT_THAT(args, IsEmpty()); args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( WithMotionAction(AMOTION_EVENT_ACTION_DOWN)), VariantWith<NotifyMotionArgs>(WithMotionAction( AMOTION_EVENT_ACTION_POINTER_DOWN | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT)), VariantWith<NotifyMotionArgs>(WithMotionAction( AMOTION_EVENT_ACTION_POINTER_DOWN | 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT)), VariantWith<NotifyMotionArgs>( WithMotionAction(AMOTION_EVENT_ACTION_MOVE)))); ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>( WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE)))); } TEST_F(GestureConverterTest, DisablingSystemGestures_EndsOngoingMultiFingerSwipe) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setDisplayId(ui::LogicalDisplayId::DEFAULT); Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/10); std::list<NotifyArgs> args; args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture); ASSERT_FALSE(args.empty()); // Disabling system gestures should end the swipe early. args = converter.setEnableSystemGestures(ARBITRARY_TIME, false); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction( AMOTION_EVENT_ACTION_POINTER_UP | 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification( MotionClassification::MULTI_FINGER_SWIPE), WithPointerCount(3u))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction( AMOTION_EVENT_ACTION_POINTER_UP | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification( MotionClassification::MULTI_FINGER_SWIPE), WithPointerCount(2u))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), WithMotionClassification( MotionClassification::MULTI_FINGER_SWIPE), WithPointerCount(1u))), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), WithMotionClassification(MotionClassification::NONE))))); ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>( AllOf(WithToolType(ToolType::FINGER), WithDisplayId(ui::LogicalDisplayId::DEFAULT))))); // Further movement in the same swipe should be ignored. Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/5); args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture); ASSERT_THAT(args, IsEmpty()); Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME); args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture); ASSERT_THAT(args, IsEmpty()); // But single-finger pointer motion should be reported. Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithRelativeMotion(-5, 10), WithButtonState(0))))); } TEST_F(GestureConverterTest, Pinch_Inwards) { input_flags::enable_touchpad_no_focus_change(true); Loading