Loading services/inputflinger/include/InputReaderBase.h +9 −2 Original line number Diff line number Diff line Loading @@ -96,7 +96,8 @@ struct InputReaderConfiguration { // The key remapping has changed. KEY_REMAPPING = 1u << 14, // The mouse settings changed, this includes mouse reverse vertical scrolling. // The mouse settings changed, this includes mouse reverse vertical scrolling and swap // primary button. MOUSE_SETTINGS = 1u << 15, // All devices must be reopened. Loading Loading @@ -259,6 +260,11 @@ struct InputReaderConfiguration { // wheel downwards scrolls the content upwards. bool mouseReverseVerticalScrollingEnabled; // True if the connected mouse should have its primary button (default: left click) swapped, // so that the right click will be the primary action button and the left click will be the // secondary action. bool mouseSwapPrimaryButtonEnabled; InputReaderConfiguration() : virtualKeyQuietTime(0), defaultPointerDisplayId(ui::LogicalDisplayId::DEFAULT), Loading Loading @@ -290,7 +296,8 @@ struct InputReaderConfiguration { touchpadRightClickZoneEnabled(false), stylusButtonMotionEventsEnabled(true), stylusPointerIconEnabled(false), mouseReverseVerticalScrollingEnabled(false) {} mouseReverseVerticalScrollingEnabled(false), mouseSwapPrimaryButtonEnabled(false) {} std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const; std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueDisplayId) Loading services/inputflinger/reader/mapper/CursorInputMapper.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -548,6 +548,7 @@ void CursorInputMapper::configureOnChangeDisplayInfo(const InputReaderConfigurat void CursorInputMapper::configureOnChangeMouseSettings(const InputReaderConfiguration& config) { mMouseReverseVerticalScrolling = config.mouseReverseVerticalScrollingEnabled; mCursorButtonAccumulator.setSwapLeftRightButtons(config.mouseSwapPrimaryButtonEnabled); } } // namespace android services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp +8 −2 Original line number Diff line number Diff line Loading @@ -47,6 +47,10 @@ void CursorButtonAccumulator::clearButtons() { mBtnTask = 0; } void CursorButtonAccumulator::setSwapLeftRightButtons(bool shouldSwap) { mSwapLeftRightButtons = shouldSwap; } void CursorButtonAccumulator::process(const RawEvent& rawEvent) { if (rawEvent.type == EV_KEY) { switch (rawEvent.code) { Loading Loading @@ -81,10 +85,12 @@ void CursorButtonAccumulator::process(const RawEvent& rawEvent) { uint32_t CursorButtonAccumulator::getButtonState() const { uint32_t result = 0; if (mBtnLeft) { result |= AMOTION_EVENT_BUTTON_PRIMARY; result |= mSwapLeftRightButtons ? AMOTION_EVENT_BUTTON_SECONDARY : AMOTION_EVENT_BUTTON_PRIMARY; } if (mBtnRight) { result |= AMOTION_EVENT_BUTTON_SECONDARY; result |= mSwapLeftRightButtons ? AMOTION_EVENT_BUTTON_PRIMARY : AMOTION_EVENT_BUTTON_SECONDARY; } if (mBtnMiddle) { result |= AMOTION_EVENT_BUTTON_TERTIARY; Loading services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h +4 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,8 @@ public: inline bool isExtraPressed() const { return mBtnExtra; } inline bool isTaskPressed() const { return mBtnTask; } void setSwapLeftRightButtons(bool shouldSwap); private: bool mBtnLeft; bool mBtnRight; Loading @@ -51,6 +53,8 @@ private: bool mBtnExtra; bool mBtnTask; bool mSwapLeftRightButtons = false; void clearButtons(); }; Loading services/inputflinger/tests/CursorInputMapper_test.cpp +73 −1 Original line number Diff line number Diff line Loading @@ -205,9 +205,14 @@ TEST_F(CursorInputMapperUnitTest, HoverAndLeftButtonPress) { args.clear(); args += process(EV_KEY, BTN_LEFT, 1); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)), VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS)))); VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_PRESS), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY))))); ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)))); // Move some more. args.clear(); Loading @@ -220,10 +225,77 @@ TEST_F(CursorInputMapperUnitTest, HoverAndLeftButtonPress) { args.clear(); args += process(EV_KEY, BTN_LEFT, 0); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY))), VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)), VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)))); } /** * Test that enabling mouse swap primary button will have the left click result in a * `SECONDARY_BUTTON` event and a right click will result in a `PRIMARY_BUTTON` event. */ TEST_F(CursorInputMapperUnitTest, SwappedPrimaryButtonPress) { mReaderConfiguration.mouseSwapPrimaryButtonEnabled = true; createMapper(); std::list<NotifyArgs> args; // Now click the left mouse button , expect a `SECONDARY_BUTTON` button state. args.clear(); args += process(EV_KEY, BTN_LEFT, 1); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_PRESS), WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY))))); ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>( WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY)))); // Release the left button. args.clear(); args += process(EV_KEY, BTN_LEFT, 0); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY))), VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)), VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)))); // Now click the right mouse button , expect a `PRIMARY_BUTTON` button state. args.clear(); args += process(EV_KEY, BTN_RIGHT, 1); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_PRESS), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY))))); ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)))); // Release the right button. args.clear(); args += process(EV_KEY, BTN_RIGHT, 0); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)), VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)), VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)))); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY))), VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)), VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)))); } /** Loading Loading
services/inputflinger/include/InputReaderBase.h +9 −2 Original line number Diff line number Diff line Loading @@ -96,7 +96,8 @@ struct InputReaderConfiguration { // The key remapping has changed. KEY_REMAPPING = 1u << 14, // The mouse settings changed, this includes mouse reverse vertical scrolling. // The mouse settings changed, this includes mouse reverse vertical scrolling and swap // primary button. MOUSE_SETTINGS = 1u << 15, // All devices must be reopened. Loading Loading @@ -259,6 +260,11 @@ struct InputReaderConfiguration { // wheel downwards scrolls the content upwards. bool mouseReverseVerticalScrollingEnabled; // True if the connected mouse should have its primary button (default: left click) swapped, // so that the right click will be the primary action button and the left click will be the // secondary action. bool mouseSwapPrimaryButtonEnabled; InputReaderConfiguration() : virtualKeyQuietTime(0), defaultPointerDisplayId(ui::LogicalDisplayId::DEFAULT), Loading Loading @@ -290,7 +296,8 @@ struct InputReaderConfiguration { touchpadRightClickZoneEnabled(false), stylusButtonMotionEventsEnabled(true), stylusPointerIconEnabled(false), mouseReverseVerticalScrollingEnabled(false) {} mouseReverseVerticalScrollingEnabled(false), mouseSwapPrimaryButtonEnabled(false) {} std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const; std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueDisplayId) Loading
services/inputflinger/reader/mapper/CursorInputMapper.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -548,6 +548,7 @@ void CursorInputMapper::configureOnChangeDisplayInfo(const InputReaderConfigurat void CursorInputMapper::configureOnChangeMouseSettings(const InputReaderConfiguration& config) { mMouseReverseVerticalScrolling = config.mouseReverseVerticalScrollingEnabled; mCursorButtonAccumulator.setSwapLeftRightButtons(config.mouseSwapPrimaryButtonEnabled); } } // namespace android
services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp +8 −2 Original line number Diff line number Diff line Loading @@ -47,6 +47,10 @@ void CursorButtonAccumulator::clearButtons() { mBtnTask = 0; } void CursorButtonAccumulator::setSwapLeftRightButtons(bool shouldSwap) { mSwapLeftRightButtons = shouldSwap; } void CursorButtonAccumulator::process(const RawEvent& rawEvent) { if (rawEvent.type == EV_KEY) { switch (rawEvent.code) { Loading Loading @@ -81,10 +85,12 @@ void CursorButtonAccumulator::process(const RawEvent& rawEvent) { uint32_t CursorButtonAccumulator::getButtonState() const { uint32_t result = 0; if (mBtnLeft) { result |= AMOTION_EVENT_BUTTON_PRIMARY; result |= mSwapLeftRightButtons ? AMOTION_EVENT_BUTTON_SECONDARY : AMOTION_EVENT_BUTTON_PRIMARY; } if (mBtnRight) { result |= AMOTION_EVENT_BUTTON_SECONDARY; result |= mSwapLeftRightButtons ? AMOTION_EVENT_BUTTON_PRIMARY : AMOTION_EVENT_BUTTON_SECONDARY; } if (mBtnMiddle) { result |= AMOTION_EVENT_BUTTON_TERTIARY; Loading
services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h +4 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,8 @@ public: inline bool isExtraPressed() const { return mBtnExtra; } inline bool isTaskPressed() const { return mBtnTask; } void setSwapLeftRightButtons(bool shouldSwap); private: bool mBtnLeft; bool mBtnRight; Loading @@ -51,6 +53,8 @@ private: bool mBtnExtra; bool mBtnTask; bool mSwapLeftRightButtons = false; void clearButtons(); }; Loading
services/inputflinger/tests/CursorInputMapper_test.cpp +73 −1 Original line number Diff line number Diff line Loading @@ -205,9 +205,14 @@ TEST_F(CursorInputMapperUnitTest, HoverAndLeftButtonPress) { args.clear(); args += process(EV_KEY, BTN_LEFT, 1); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)), VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS)))); VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_PRESS), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY))))); ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)))); // Move some more. args.clear(); Loading @@ -220,10 +225,77 @@ TEST_F(CursorInputMapperUnitTest, HoverAndLeftButtonPress) { args.clear(); args += process(EV_KEY, BTN_LEFT, 0); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY))), VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)), VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)))); } /** * Test that enabling mouse swap primary button will have the left click result in a * `SECONDARY_BUTTON` event and a right click will result in a `PRIMARY_BUTTON` event. */ TEST_F(CursorInputMapperUnitTest, SwappedPrimaryButtonPress) { mReaderConfiguration.mouseSwapPrimaryButtonEnabled = true; createMapper(); std::list<NotifyArgs> args; // Now click the left mouse button , expect a `SECONDARY_BUTTON` button state. args.clear(); args += process(EV_KEY, BTN_LEFT, 1); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_PRESS), WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY))))); ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>( WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY)))); // Release the left button. args.clear(); args += process(EV_KEY, BTN_LEFT, 0); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY))), VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)), VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)))); // Now click the right mouse button , expect a `PRIMARY_BUTTON` button state. args.clear(); args += process(EV_KEY, BTN_RIGHT, 1); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)), VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_PRESS), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY))))); ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)))); // Release the right button. args.clear(); args += process(EV_KEY, BTN_RIGHT, 0); args += process(EV_SYN, SYN_REPORT, 0); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)), VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)), VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)))); ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>( AllOf(WithMotionAction(BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY))), VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)), VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)))); } /** Loading