From cf875ab292ffebdf6165c037a00e0fc344b39b74 Mon Sep 17 00:00:00 2001 From: Vaibhav Devmurari Date: Wed, 7 Sep 2022 11:35:49 +0000 Subject: Add new native keycodes for keyboard backlight up/down/toggle Also syncing all the keycodes in KeyEvents.java file to here for consistency. Test: None Bug: 245506418 Change-Id: I40c0b6f7d0e67ffc1ee01c6cb1dfbcfc96b37d62 --- libs/input/InputEventLabels.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'libs/input/InputEventLabels.cpp') diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index c0aa2e26a2..5990ee0d30 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -314,7 +314,26 @@ namespace android { DEFINE_KEYCODE(REFRESH), \ DEFINE_KEYCODE(THUMBS_UP), \ DEFINE_KEYCODE(THUMBS_DOWN), \ - DEFINE_KEYCODE(PROFILE_SWITCH) + DEFINE_KEYCODE(PROFILE_SWITCH), \ + DEFINE_KEYCODE(VIDEO_APP_1), \ + DEFINE_KEYCODE(VIDEO_APP_2), \ + DEFINE_KEYCODE(VIDEO_APP_3), \ + DEFINE_KEYCODE(VIDEO_APP_4), \ + DEFINE_KEYCODE(VIDEO_APP_5), \ + DEFINE_KEYCODE(VIDEO_APP_6), \ + DEFINE_KEYCODE(VIDEO_APP_7), \ + DEFINE_KEYCODE(VIDEO_APP_8), \ + DEFINE_KEYCODE(FEATURED_APP_1), \ + DEFINE_KEYCODE(FEATURED_APP_2), \ + DEFINE_KEYCODE(FEATURED_APP_3), \ + DEFINE_KEYCODE(FEATURED_APP_4), \ + DEFINE_KEYCODE(DEMO_APP_1), \ + DEFINE_KEYCODE(DEMO_APP_2), \ + DEFINE_KEYCODE(DEMO_APP_3), \ + DEFINE_KEYCODE(DEMO_APP_4), \ + DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_DOWN), \ + DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_UP), \ + DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_TOGGLE) // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. -- cgit v1.2.3-59-g8ed1b From 741111bd79f8ac9daa3d9fca35bc491fda08685b Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 12 Sep 2022 20:45:30 +0000 Subject: Add Android keycodes for stylus buttons Ensure the new stylus buttons are not yet sent to apps. DD: go/android-stylus-buttons Bug: 246394583 Test: Build, Presubmit Change-Id: I3f429c3435c90429c908fb77f8dbf964290d47aa --- include/android/keycodes.h | 11 +++++++++++ libs/input/InputEventLabels.cpp | 11 +++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'libs/input/InputEventLabels.cpp') diff --git a/include/android/keycodes.h b/include/android/keycodes.h index 16a13d6cd3..e5b5db2964 100644 --- a/include/android/keycodes.h +++ b/include/android/keycodes.h @@ -818,6 +818,17 @@ enum { /** Keyboard backlight Toggle key. * Toggles the keyboard backlight on/off. */ AKEYCODE_KEYBOARD_BACKLIGHT_TOGGLE = 307, + /** The primary button on the barrel of a stylus. + * This is usually the button closest to the tip of the stylus. */ + AKEYCODE_STYLUS_BUTTON_PRIMARY = 308, + /** The secondary button on the barrel of a stylus. + * This is usually the second button from the tip of the stylus. */ + AKEYCODE_STYLUS_BUTTON_SECONDARY = 309, + /** The tertiary button on the barrel of a stylus. + * This is usually the third button from the tip of the stylus. */ + AKEYCODE_STYLUS_BUTTON_TERTIARY = 310, + /** A button on the tail end of a stylus. */ + AKEYCODE_STYLUS_BUTTON_TAIL = 311, // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index 5990ee0d30..163a2fe924 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -23,6 +23,8 @@ namespace android { +// clang-format off + // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. #define KEYCODES_SEQUENCE \ @@ -333,7 +335,11 @@ namespace android { DEFINE_KEYCODE(DEMO_APP_4), \ DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_DOWN), \ DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_UP), \ - DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_TOGGLE) + DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_TOGGLE), \ + DEFINE_KEYCODE(STYLUS_BUTTON_PRIMARY), \ + DEFINE_KEYCODE(STYLUS_BUTTON_SECONDARY), \ + DEFINE_KEYCODE(STYLUS_BUTTON_TERTIARY), \ + DEFINE_KEYCODE(STYLUS_BUTTON_TAIL) // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. @@ -387,7 +393,6 @@ namespace android { DEFINE_AXIS(GENERIC_15), \ DEFINE_AXIS(GENERIC_16) - // NOTE: If you add new LEDs here, you must also add them to Input.h #define LEDS_SEQUENCE \ DEFINE_LED(NUM_LOCK), \ @@ -412,6 +417,8 @@ namespace android { DEFINE_FLAG(GESTURE), \ DEFINE_FLAG(WAKE) +// clang-format on + // --- InputEventLookup --- const std::unordered_map InputEventLookup::KEYCODES = {KEYCODES_SEQUENCE}; -- cgit v1.2.3-59-g8ed1b From 39b7ca2933ffde9094aed908a507158d20be3d7a Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Wed, 5 Oct 2022 15:55:48 +0000 Subject: Report motion offsets for touchpad swipes Adds two new axes, AXIS_GESTURE_X_OFFSET and AXIS_GESTURE_Y_OFFSET, which report the movement of swipe gestures on the touchpad as a fraction of the touchpad's size. Bug: 246758376 Test: check axis values come through in a test app Change-Id: I313410053a8db13273bd05a33d3a6a1f75081dae --- include/android/input.h | 17 +++++++- libs/input/InputEventLabels.cpp | 4 +- services/inputflinger/InputCommonConverter.cpp | 5 ++- .../reader/mapper/TouchInputMapper.cpp | 30 +++++++++----- services/inputflinger/tests/InputReader_test.cpp | 46 ++++++++++++++++++++++ 5 files changed, 89 insertions(+), 13 deletions(-) (limited to 'libs/input/InputEventLabels.cpp') diff --git a/include/android/input.h b/include/android/input.h index d906af6e0c..5d19c5cb13 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -771,6 +771,21 @@ enum { * The interpretation of a generic axis is device-specific. */ AMOTION_EVENT_AXIS_GENERIC_16 = 47, + /** + * Axis constant: X gesture offset axis of a motion event. + * + * - For a touch pad, reports the distance that a swipe gesture has moved in the X axis, as a + * proportion of the touch pad's size. For example, if a touch pad is 1000 units wide, and a + * swipe gesture starts at X = 500 then moves to X = 400, this axis would have a value of + * -0.1. + */ + AMOTION_EVENT_AXIS_GESTURE_X_OFFSET = 48, + /** + * Axis constant: Y gesture offset axis of a motion event. + * + * The same as {@link AMOTION_EVENT_AXIS_GESTURE_X_OFFSET}, but for the Y axis. + */ + AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET = 49, /** * Note: This is not an "Axis constant". It does not represent any axis, nor should it be used @@ -778,7 +793,7 @@ enum { * to make some computations (like iterating through all possible axes) cleaner. * Please update the value accordingly if you add a new axis. */ - AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GENERIC_16, + AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index 163a2fe924..b78fae3027 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -391,7 +391,9 @@ namespace android { DEFINE_AXIS(GENERIC_13), \ DEFINE_AXIS(GENERIC_14), \ DEFINE_AXIS(GENERIC_15), \ - DEFINE_AXIS(GENERIC_16) + DEFINE_AXIS(GENERIC_16), \ + DEFINE_AXIS(GESTURE_X_OFFSET), \ + DEFINE_AXIS(GESTURE_Y_OFFSET) // NOTE: If you add new LEDs here, you must also add them to Input.h #define LEDS_SEQUENCE \ diff --git a/services/inputflinger/InputCommonConverter.cpp b/services/inputflinger/InputCommonConverter.cpp index 23b6f57b23..6db89d4759 100644 --- a/services/inputflinger/InputCommonConverter.cpp +++ b/services/inputflinger/InputCommonConverter.cpp @@ -263,8 +263,11 @@ static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_13) == common static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_14) == common::Axis::GENERIC_14); static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_15) == common::Axis::GENERIC_15); static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_16) == common::Axis::GENERIC_16); +// TODO(hcutts): add GESTURE_X_OFFSET and GESTURE_Y_OFFSET. +// If you added a new axis, consider whether this should also be exposed as a HAL axis. Update the +// static_assert below and add the new axis here, or leave a comment summarizing your decision. static_assert(static_cast(AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE) == - static_cast(AMOTION_EVENT_AXIS_GENERIC_16)); + static_cast(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET)); static common::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) { common::VideoFrame out; diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index da58efde31..7f6785eaa6 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -3175,7 +3175,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits; // Add delta for all fingers and calculate a common movement delta. - float commonDeltaX = 0, commonDeltaY = 0; + int32_t commonDeltaRawX = 0, commonDeltaRawY = 0; BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value & mCurrentCookedState.fingerIdBits.value); for (BitSet32 idBits(commonIdBits); !idBits.isEmpty();) { @@ -3188,11 +3188,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi delta.dy += cpd.y - lpd.y; if (first) { - commonDeltaX = delta.dx; - commonDeltaY = delta.dy; + commonDeltaRawX = delta.dx; + commonDeltaRawY = delta.dy; } else { - commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); - commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); + commonDeltaRawX = calculateCommonVector(commonDeltaRawX, delta.dx); + commonDeltaRawY = calculateCommonVector(commonDeltaRawY, delta.dy); } } @@ -3298,7 +3298,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi // Move the reference points based on the overall group motion of the fingers // except in PRESS mode while waiting for a transition to occur. if (mPointerGesture.currentGestureMode != PointerGesture::Mode::PRESS && - (commonDeltaX || commonDeltaY)) { + (commonDeltaRawX || commonDeltaRawY)) { for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) { uint32_t id = idBits.clearFirstMarkedBit(); PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; @@ -3306,11 +3306,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi delta.dy = 0; } - mPointerGesture.referenceTouchX += commonDeltaX; - mPointerGesture.referenceTouchY += commonDeltaY; + mPointerGesture.referenceTouchX += commonDeltaRawX; + mPointerGesture.referenceTouchY += commonDeltaRawY; - commonDeltaX *= mPointerXMovementScale; - commonDeltaY *= mPointerYMovementScale; + float commonDeltaX = commonDeltaRawX * mPointerXMovementScale; + float commonDeltaY = commonDeltaRawY * mPointerYMovementScale; rotateDelta(mInputDeviceOrientation, &commonDeltaX, &commonDeltaY); mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); @@ -3341,6 +3341,16 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + if (mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) { + float xOffset = static_cast(commonDeltaRawX) / + (mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue); + float yOffset = static_cast(commonDeltaRawY) / + (mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue); + mPointerGesture.currentGestureCoords[0] + .setAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET, xOffset); + mPointerGesture.currentGestureCoords[0] + .setAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, yOffset); + } } else if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) { // FREEFORM mode. ALOGD_IF(DEBUG_GESTURES, diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index dded6a13e0..1e26265b46 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -10085,6 +10085,52 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthFreeform) { 0, 0, 0, 0, 0)); } +TEST_F(MultiTouchPointerModeTest, TwoFingerSwipeOffsets) { + preparePointerMode(25 /*xResolution*/, 25 /*yResolution*/); + MultiTouchInputMapper& mapper = addMapperAndConfigure(); + NotifyMotionArgs motionArgs; + + // Place two fingers down. + int32_t x1 = 100, y1 = 125, x2 = 550, y2 = 125; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); + ASSERT_EQ(0, motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET)); + ASSERT_EQ(0, motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET)); + + // Move the two fingers down and to the left. + int32_t movingDistance = 200; + x1 -= movingDistance; + y1 += movingDistance; + x2 -= movingDistance; + y2 += movingDistance; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(MotionClassification::TWO_FINGER_SWIPE, motionArgs.classification); + ASSERT_LT(motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET), 0); + ASSERT_GT(motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET), 0); +} + // --- JoystickInputMapperTest --- class JoystickInputMapperTest : public InputMapperTest { -- cgit v1.2.3-59-g8ed1b From 58120357b446182f8a2a047be49a9f35789c0d50 Mon Sep 17 00:00:00 2001 From: Vaibhav Devmurari Date: Tue, 6 Dec 2022 22:25:09 +0000 Subject: Add new KEYCODE_RECENT_APPS and corresponding mappings Test: manual Bug: 261621522 Change-Id: I282eb4b2b29a4790e287371ac9408120ff32997d --- include/android/keycodes.h | 2 ++ libs/input/InputEventLabels.cpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'libs/input/InputEventLabels.cpp') diff --git a/include/android/keycodes.h b/include/android/keycodes.h index e5b5db2964..d4ba321057 100644 --- a/include/android/keycodes.h +++ b/include/android/keycodes.h @@ -829,6 +829,8 @@ enum { AKEYCODE_STYLUS_BUTTON_TERTIARY = 310, /** A button on the tail end of a stylus. */ AKEYCODE_STYLUS_BUTTON_TAIL = 311, + /** Key to open recent apps (a.k.a. Overview) */ + AKEYCODE_RECENT_APPS = 312, // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index b78fae3027..dd7cbb5ba9 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -339,7 +339,8 @@ namespace android { DEFINE_KEYCODE(STYLUS_BUTTON_PRIMARY), \ DEFINE_KEYCODE(STYLUS_BUTTON_SECONDARY), \ DEFINE_KEYCODE(STYLUS_BUTTON_TERTIARY), \ - DEFINE_KEYCODE(STYLUS_BUTTON_TAIL) + DEFINE_KEYCODE(STYLUS_BUTTON_TAIL), \ + DEFINE_KEYCODE(RECENT_APPS) // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. -- cgit v1.2.3-59-g8ed1b From ef400b26ab180b0dd7a7cf8f306d2ac72fcfe40a Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Fri, 16 Dec 2022 21:26:24 +0000 Subject: Report two-finger touchpad swipes Bug: 251196347 Test: try out two-finger scroll gestures with an Apple Magic Trackpad 2 Test: atest inputflinger_tests Change-Id: I9e693350873b90bd50605ab348821224ae1121a8 --- include/android/input.h | 15 ++- libs/input/InputEventLabels.cpp | 4 +- services/inputflinger/InputCommonConverter.cpp | 4 +- .../reader/mapper/gestures/GestureConverter.cpp | 57 +++++++++++ .../reader/mapper/gestures/GestureConverter.h | 5 +- .../inputflinger/tests/GestureConverter_test.cpp | 111 +++++++++++++++++++++ .../inputflinger/tests/TestInputListenerMatchers.h | 18 ++++ 7 files changed, 209 insertions(+), 5 deletions(-) (limited to 'libs/input/InputEventLabels.cpp') diff --git a/include/android/input.h b/include/android/input.h index a0b46de260..e1aac65457 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -786,6 +786,19 @@ enum { * The same as {@link AMOTION_EVENT_AXIS_GESTURE_X_OFFSET}, but for the Y axis. */ AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET = 49, + /** + * Axis constant: X scroll distance axis of a motion event. + * + * - For a touch pad, reports the distance that should be scrolled in the X axis as a result of + * the user's two-finger scroll gesture, in display pixels. + */ + AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE = 50, + /** + * Axis constant: Y scroll distance axis of a motion event. + * + * The same as {@link AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE}, but for the Y axis. + */ + AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE = 51, /** * Note: This is not an "Axis constant". It does not represent any axis, nor should it be used @@ -793,7 +806,7 @@ enum { * to make some computations (like iterating through all possible axes) cleaner. * Please update the value accordingly if you add a new axis. */ - AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, + AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE, // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index dd7cbb5ba9..8ffd220ad8 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -394,7 +394,9 @@ namespace android { DEFINE_AXIS(GENERIC_15), \ DEFINE_AXIS(GENERIC_16), \ DEFINE_AXIS(GESTURE_X_OFFSET), \ - DEFINE_AXIS(GESTURE_Y_OFFSET) + DEFINE_AXIS(GESTURE_Y_OFFSET), \ + DEFINE_AXIS(GESTURE_SCROLL_X_DISTANCE), \ + DEFINE_AXIS(GESTURE_SCROLL_Y_DISTANCE) // NOTE: If you add new LEDs here, you must also add them to Input.h #define LEDS_SEQUENCE \ diff --git a/services/inputflinger/InputCommonConverter.cpp b/services/inputflinger/InputCommonConverter.cpp index 628ce6fc9a..ea0a429000 100644 --- a/services/inputflinger/InputCommonConverter.cpp +++ b/services/inputflinger/InputCommonConverter.cpp @@ -263,11 +263,11 @@ static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_13) == common static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_14) == common::Axis::GENERIC_14); static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_15) == common::Axis::GENERIC_15); static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_16) == common::Axis::GENERIC_16); -// TODO(hcutts): add GESTURE_X_OFFSET and GESTURE_Y_OFFSET. +// TODO(b/251196347): add GESTURE_{X,Y}_OFFSET and GESTURE_SCROLL_{X,Y}_DISTANCE. // If you added a new axis, consider whether this should also be exposed as a HAL axis. Update the // static_assert below and add the new axis here, or leave a comment summarizing your decision. static_assert(static_cast(AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE) == - static_cast(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET)); + static_cast(AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE)); static common::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) { common::VideoFrame out; diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp index ffc0523e97..575acb06b6 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp @@ -65,6 +65,10 @@ std::list GestureConverter::handleGesture(nsecs_t when, nsecs_t read return {handleMove(when, readTime, gesture)}; case kGestureTypeButtonsChange: return handleButtonsChange(when, readTime, gesture); + case kGestureTypeScroll: + return handleScroll(when, readTime, gesture); + case kGestureTypeFling: + return {handleFling(when, readTime, gesture)}; case kGestureTypeSwipe: return handleMultiFingerSwipe(when, readTime, 3, gesture.details.swipe.dx, gesture.details.swipe.dy); @@ -175,6 +179,59 @@ std::list GestureConverter::handleButtonsChange(nsecs_t when, nsecs_ return out; } +std::list GestureConverter::handleScroll(nsecs_t when, nsecs_t readTime, + const Gesture& gesture) { + std::list out; + PointerCoords& coords = mFakeFingerCoords[0]; + float xCursorPosition, yCursorPosition; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + if (mCurrentClassification != MotionClassification::TWO_FINGER_SWIPE) { + mCurrentClassification = MotionClassification::TWO_FINGER_SWIPE; + coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); + coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); + coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + mDownTime = when; + out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN, + /* actionButton= */ 0, mButtonState, /* pointerCount= */ 1, + mFingerProps.data(), mFakeFingerCoords.data(), xCursorPosition, + yCursorPosition)); + } + float deltaX = gesture.details.scroll.dx; + float deltaY = gesture.details.scroll.dy; + rotateDelta(mOrientation, &deltaX, &deltaY); + + coords.setAxisValue(AMOTION_EVENT_AXIS_X, coords.getAxisValue(AMOTION_EVENT_AXIS_X) - deltaX); + coords.setAxisValue(AMOTION_EVENT_AXIS_Y, coords.getAxisValue(AMOTION_EVENT_AXIS_Y) - deltaY); + // TODO(b/262876643): set AXIS_GESTURE_{X,Y}_OFFSET. + coords.setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE, gesture.details.scroll.dx); + coords.setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE, gesture.details.scroll.dy); + out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, /* actionButton= */ 0, + mButtonState, /* pointerCount= */ 1, mFingerProps.data(), + mFakeFingerCoords.data(), xCursorPosition, yCursorPosition)); + return out; +} + +NotifyArgs GestureConverter::handleFling(nsecs_t when, nsecs_t readTime, const Gesture& gesture) { + // We don't actually want to use the gestures library's fling velocity values (to ensure + // consistency between touchscreen and touchpad flings), so we're just using the "start fling" + // gestures as a marker for the end of a two-finger scroll gesture. + if (gesture.details.fling.fling_state != GESTURES_FLING_START || + mCurrentClassification != MotionClassification::TWO_FINGER_SWIPE) { + return {}; + } + + float xCursorPosition, yCursorPosition; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE, 0); + mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE, 0); + NotifyArgs args = makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, + /* actionButton= */ 0, mButtonState, /* pointerCount= */ 1, + mFingerProps.data(), mFakeFingerCoords.data(), xCursorPosition, + yCursorPosition); + mCurrentClassification = MotionClassification::NONE; + return args; +} + [[nodiscard]] std::list GestureConverter::handleMultiFingerSwipe(nsecs_t when, nsecs_t readTime, uint32_t fingerCount, diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h index ae5581d3ec..6bea2d922c 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h @@ -47,9 +47,12 @@ public: const Gesture& gesture); private: - NotifyArgs handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture); + [[nodiscard]] NotifyArgs handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture); [[nodiscard]] std::list handleButtonsChange(nsecs_t when, nsecs_t readTime, const Gesture& gesture); + [[nodiscard]] std::list handleScroll(nsecs_t when, nsecs_t readTime, + const Gesture& gesture); + [[nodiscard]] NotifyArgs handleFling(nsecs_t when, nsecs_t readTime, const Gesture& gesture); [[nodiscard]] std::list handleMultiFingerSwipe(nsecs_t when, nsecs_t readTime, uint32_t fingerCount, float dx, float dy); diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp index 1c7ec7665a..683e78e348 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -239,6 +239,117 @@ TEST_F(GestureConverterTest, DragWithButton) { WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); } +TEST_F(GestureConverterTest, Scroll) { + const nsecs_t downTime = 12345; + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + + Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, 10); + std::list args = converter.handleGesture(downTime, READ_TIME, startGesture); + ASSERT_EQ(2u, args.size()); + + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithDownTime(downTime))); + args.pop_front(); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithCoords(POINTER_X, POINTER_Y - 10), + WithGestureScrollDistance(0, 10, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + + Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, 5); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithCoords(POINTER_X, POINTER_Y - 15), + WithGestureScrollDistance(0, 5, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + + Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, + GESTURES_FLING_START); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithCoords(POINTER_X, POINTER_Y - 15), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); +} + +TEST_F(GestureConverterTest, Scroll_Rotated) { + const nsecs_t downTime = 12345; + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setOrientation(ui::ROTATION_90); + + Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, 10); + std::list args = converter.handleGesture(downTime, READ_TIME, startGesture); + ASSERT_EQ(2u, args.size()); + + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithDownTime(downTime))); + args.pop_front(); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithCoords(POINTER_X - 10, POINTER_Y), + WithGestureScrollDistance(0, 10, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + + Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, 5); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithCoords(POINTER_X - 15, POINTER_Y), + WithGestureScrollDistance(0, 5, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + + Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, + GESTURES_FLING_START); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithCoords(POINTER_X - 15, POINTER_Y), + WithGestureScrollDistance(0, 0, EPSILON), + WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); +} + +TEST_F(GestureConverterTest, Scroll_ClearsClassificationAndOffsetsAfterGesture) { + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + + Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, 10); + std::list args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + + Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, 5); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); + + Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, + GESTURES_FLING_START); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, flingGesture); + + Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionClassification(MotionClassification::NONE), + WithGestureScrollDistance(0, 0, EPSILON))); +} + TEST_F(GestureConverterTest, ThreeFingerSwipe_ClearsClassificationAndOffsetsAfterGesture) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h index 64c2c7511b..53e4066b20 100644 --- a/services/inputflinger/tests/TestInputListenerMatchers.h +++ b/services/inputflinger/tests/TestInputListenerMatchers.h @@ -100,6 +100,19 @@ MATCHER_P3(WithGestureOffset, dx, dy, epsilon, return xDiff <= epsilon && yDiff <= epsilon; } +MATCHER_P3(WithGestureScrollDistance, x, y, epsilon, + "InputEvent with specified touchpad gesture scroll distance") { + const auto argXDistance = + arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE); + const auto argYDistance = + arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE); + const double xDiff = fabs(argXDistance - x); + const double yDiff = fabs(argYDistance - y); + *result_listener << "expected gesture offset (" << x << ", " << y << ") within " << epsilon + << ", but got (" << argXDistance << ", " << argYDistance << ")"; + return xDiff <= epsilon && yDiff <= epsilon; +} + MATCHER_P(WithPressure, pressure, "InputEvent with specified pressure") { const auto argPressure = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); *result_listener << "expected pressure " << pressure << ", but got " << argPressure; @@ -141,4 +154,9 @@ MATCHER_P(WithEventTime, eventTime, "InputEvent with specified eventTime") { return arg.eventTime == eventTime; } +MATCHER_P(WithDownTime, downTime, "InputEvent with specified downTime") { + *result_listener << "expected down time " << downTime << ", but got " << arg.downTime; + return arg.downTime == downTime; +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From b1e8355b5967159230b80b207396230c671f6280 Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Tue, 20 Dec 2022 11:02:26 +0000 Subject: Report pinch gestures Bug: 251196347 Test: check events received by a custom tester app, and touches shown by pointer location overlay Test: atest inputflinger_tests Change-Id: I249ca6208091e3c4291c5be68c77339bf5f69a5b --- include/android/input.h | 27 +++- include/input/Input.h | 5 + libs/input/Input.cpp | 2 + libs/input/InputEventLabels.cpp | 3 +- services/inputflinger/InputCommonConverter.cpp | 5 +- .../reader/mapper/gestures/GestureConverter.cpp | 74 +++++++++++ .../reader/mapper/gestures/GestureConverter.h | 6 + .../inputflinger/tests/GestureConverter_test.cpp | 138 ++++++++++++++++++++- .../inputflinger/tests/TestInputListenerMatchers.h | 17 +++ 9 files changed, 269 insertions(+), 8 deletions(-) (limited to 'libs/input/InputEventLabels.cpp') diff --git a/include/android/input.h b/include/android/input.h index e1aac65457..d6f9d633b6 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -778,6 +778,9 @@ enum { * proportion of the touch pad's size. For example, if a touch pad is 1000 units wide, and a * swipe gesture starts at X = 500 then moves to X = 400, this axis would have a value of * -0.1. + * + * These values are relative to the state from the last event, not accumulated, so developers + * should make sure to process this axis value for all batched historical events. */ AMOTION_EVENT_AXIS_GESTURE_X_OFFSET = 48, /** @@ -791,6 +794,9 @@ enum { * * - For a touch pad, reports the distance that should be scrolled in the X axis as a result of * the user's two-finger scroll gesture, in display pixels. + * + * These values are relative to the state from the last event, not accumulated, so developers + * should make sure to process this axis value for all batched historical events. */ AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE = 50, /** @@ -799,6 +805,18 @@ enum { * The same as {@link AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE}, but for the Y axis. */ AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE = 51, + /** + * Axis constant: pinch scale factor of a motion event. + * + * - For a touch pad, reports the change in distance between the fingers when the user is making + * a pinch gesture, as a proportion of that distance when the gesture was last reported. For + * example, if the fingers were 50 units apart and are now 52 units apart, the scale factor + * would be 1.04. + * + * These values are relative to the state from the last event, not accumulated, so developers + * should make sure to process this axis value for all batched historical events. + */ + AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR = 52, /** * Note: This is not an "Axis constant". It does not represent any axis, nor should it be used @@ -806,7 +824,7 @@ enum { * to make some computations (like iterating through all possible axes) cleaner. * Please update the value accordingly if you add a new axis. */ - AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE, + AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR, // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. @@ -891,6 +909,13 @@ enum AMotionClassification : uint32_t { * why they have a separate constant from two-finger swipes. */ AMOTION_EVENT_CLASSIFICATION_MULTI_FINGER_SWIPE = 4, + /** + * Classification constant: pinch. + * + * The current event stream represents the user pinching with two fingers on a touchpad. The + * gesture is centered around the current cursor position. + */ + AMOTION_EVENT_CLASSIFICATION_PINCH = 5, }; /** diff --git a/include/input/Input.h b/include/input/Input.h index 7e62ac005e..cf5474c60d 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -308,6 +308,11 @@ enum class MotionClassification : uint8_t { * have a separate constant from two-finger swipes. */ MULTI_FINGER_SWIPE = AMOTION_EVENT_CLASSIFICATION_MULTI_FINGER_SWIPE, + /** + * The current gesture represents the user pinching with two fingers on a touchpad. The gesture + * is centered around the current cursor position. + */ + PINCH = AMOTION_EVENT_CLASSIFICATION_PINCH, }; /** diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 000775b42a..c247fdbe07 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -74,6 +74,8 @@ const char* motionClassificationToString(MotionClassification classification) { return "TWO_FINGER_SWIPE"; case MotionClassification::MULTI_FINGER_SWIPE: return "MULTI_FINGER_SWIPE"; + case MotionClassification::PINCH: + return "PINCH"; } } diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index 8ffd220ad8..7159e27b13 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -396,7 +396,8 @@ namespace android { DEFINE_AXIS(GESTURE_X_OFFSET), \ DEFINE_AXIS(GESTURE_Y_OFFSET), \ DEFINE_AXIS(GESTURE_SCROLL_X_DISTANCE), \ - DEFINE_AXIS(GESTURE_SCROLL_Y_DISTANCE) + DEFINE_AXIS(GESTURE_SCROLL_Y_DISTANCE), \ + DEFINE_AXIS(GESTURE_PINCH_SCALE_FACTOR) // NOTE: If you add new LEDs here, you must also add them to Input.h #define LEDS_SEQUENCE \ diff --git a/services/inputflinger/InputCommonConverter.cpp b/services/inputflinger/InputCommonConverter.cpp index ea0a429000..0c93f5ce40 100644 --- a/services/inputflinger/InputCommonConverter.cpp +++ b/services/inputflinger/InputCommonConverter.cpp @@ -263,11 +263,12 @@ static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_13) == common static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_14) == common::Axis::GENERIC_14); static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_15) == common::Axis::GENERIC_15); static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_16) == common::Axis::GENERIC_16); -// TODO(b/251196347): add GESTURE_{X,Y}_OFFSET and GESTURE_SCROLL_{X,Y}_DISTANCE. +// TODO(b/251196347): add GESTURE_{X,Y}_OFFSET, GESTURE_SCROLL_{X,Y}_DISTANCE, and +// GESTURE_PINCH_SCALE_FACTOR. // If you added a new axis, consider whether this should also be exposed as a HAL axis. Update the // static_assert below and add the new axis here, or leave a comment summarizing your decision. static_assert(static_cast(AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE) == - static_cast(AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE)); + static_cast(AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR)); static common::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) { common::VideoFrame out; diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp index 575acb06b6..e8e05b7663 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "TouchCursorInputMapperCommon.h" #include "input/Input.h" @@ -78,6 +79,8 @@ std::list GestureConverter::handleGesture(nsecs_t when, nsecs_t read case kGestureTypeSwipeLift: case kGestureTypeFourFingerSwipeLift: return handleMultiFingerSwipeLift(when, readTime); + case kGestureTypePinch: + return handlePinch(when, readTime, gesture); default: // TODO(b/251196347): handle more gesture types. return {}; @@ -321,6 +324,77 @@ NotifyArgs GestureConverter::handleFling(nsecs_t when, nsecs_t readTime, const G return out; } +[[nodiscard]] std::list GestureConverter::handlePinch(nsecs_t when, nsecs_t readTime, + const Gesture& gesture) { + std::list out; + float xCursorPosition, yCursorPosition; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + + // Pinch gesture phases are reported a little differently from others, in that the same details + // struct is used for all phases of the gesture, just with different zoom_state values. When + // zoom_state is START or END, dz will always be 1, so we don't need to move the pointers in + // those cases. + + if (mCurrentClassification != MotionClassification::PINCH) { + LOG_ALWAYS_FATAL_IF(gesture.details.pinch.zoom_state != GESTURES_ZOOM_START, + "First pinch gesture does not have the START zoom state (%d instead).", + gesture.details.pinch.zoom_state); + mCurrentClassification = MotionClassification::PINCH; + mPinchFingerSeparation = INITIAL_PINCH_SEPARATION_PX; + mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR, 1.0); + mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, + xCursorPosition - mPinchFingerSeparation / 2); + mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); + mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, + xCursorPosition + mPinchFingerSeparation / 2); + mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); + mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + mDownTime = when; + out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN, + /* actionButton= */ 0, mButtonState, /* pointerCount= */ 1, + mFingerProps.data(), mFakeFingerCoords.data(), xCursorPosition, + yCursorPosition)); + out.push_back(makeMotionArgs(when, readTime, + AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT, + /* actionButton= */ 0, mButtonState, /* pointerCount= */ 2, + mFingerProps.data(), mFakeFingerCoords.data(), xCursorPosition, + yCursorPosition)); + return out; + } + + if (gesture.details.pinch.zoom_state == GESTURES_ZOOM_END) { + mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR, 1.0); + out.push_back(makeMotionArgs(when, readTime, + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT, + /* actionButton= */ 0, mButtonState, /* pointerCount= */ 2, + mFingerProps.data(), mFakeFingerCoords.data(), xCursorPosition, + yCursorPosition)); + out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /* actionButton= */ 0, + mButtonState, /* pointerCount= */ 1, mFingerProps.data(), + mFakeFingerCoords.data(), xCursorPosition, yCursorPosition)); + mCurrentClassification = MotionClassification::NONE; + mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR, 0); + return out; + } + + mPinchFingerSeparation *= gesture.details.pinch.dz; + mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR, + gesture.details.pinch.dz); + mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, + xCursorPosition - mPinchFingerSeparation / 2); + mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); + mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, + xCursorPosition + mPinchFingerSeparation / 2); + mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); + out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, /* actionButton= */ 0, + mButtonState, /* pointerCount= */ 2, mFingerProps.data(), + mFakeFingerCoords.data(), xCursorPosition, yCursorPosition)); + return out; +} + NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action, int32_t actionButton, int32_t buttonState, uint32_t pointerCount, diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h index 6bea2d922c..8e8e3d9de3 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h @@ -57,6 +57,8 @@ private: uint32_t fingerCount, float dx, float dy); [[nodiscard]] std::list handleMultiFingerSwipeLift(nsecs_t when, nsecs_t readTime); + [[nodiscard]] std::list handlePinch(nsecs_t when, nsecs_t readTime, + const Gesture& gesture); NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action, int32_t actionButton, int32_t buttonState, @@ -79,7 +81,11 @@ private: nsecs_t mDownTime = 0; MotionClassification mCurrentClassification = MotionClassification::NONE; + // Only used when mCurrentClassification is MULTI_FINGER_SWIPE. uint32_t mSwipeFingerCount = 0; + static constexpr float INITIAL_PINCH_SEPARATION_PX = 200.0; + // Only used when mCurrentClassification is PINCH. + float mPinchFingerSeparation; static constexpr size_t MAX_FAKE_FINGERS = 4; // We never need any PointerProperties other than the finger tool type, so we can just keep a // const array of them. diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp index 683e78e348..b22c741475 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -40,7 +40,7 @@ protected: static constexpr int32_t DEVICE_ID = END_RESERVED_ID + 1000; static constexpr int32_t EVENTHUB_ID = 1; static constexpr stime_t ARBITRARY_GESTURE_TIME = 1.2; - static constexpr float POINTER_X = 100; + static constexpr float POINTER_X = 500; static constexpr float POINTER_Y = 200; void SetUp() { @@ -96,7 +96,7 @@ TEST_F(GestureConverterTest, Move) { WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithButtonState(0), WithPressure(0.0f))); - ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(95, 210)); + ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10)); } TEST_F(GestureConverterTest, Move_Rotated) { @@ -114,7 +114,7 @@ TEST_F(GestureConverterTest, Move_Rotated) { WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithButtonState(0), WithPressure(0.0f))); - ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(110, 205)); + ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X + 10, POINTER_Y + 5)); } TEST_F(GestureConverterTest, ButtonsChange) { @@ -218,7 +218,7 @@ TEST_F(GestureConverterTest, DragWithButton) { WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f))); - ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(95, 210)); + ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10)); // Release the button Gesture upGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, @@ -574,4 +574,134 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { WithPointerCount(1u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); } +TEST_F(GestureConverterTest, Pinch_Inwards) { + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + + Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, + GESTURES_ZOOM_START); + std::list args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + ASSERT_EQ(2u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithCoords(POINTER_X - 100, POINTER_Y), WithPointerCount(1u), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + args.pop_front(); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCoords(1, POINTER_X + 100, POINTER_Y), WithPointerCount(2u), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + + Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + /* dz= */ 0.8, GESTURES_ZOOM_UPDATE); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, updateGesture); + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(0.8f, EPSILON), + WithPointerCoords(0, POINTER_X - 80, POINTER_Y), + WithPointerCoords(1, POINTER_X + 80, POINTER_Y), WithPointerCount(2u), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + + Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, + GESTURES_ZOOM_END); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, endGesture); + ASSERT_EQ(2u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + args.pop_front(); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); +} + +TEST_F(GestureConverterTest, Pinch_Outwards) { + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + + Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, + GESTURES_ZOOM_START); + std::list args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + ASSERT_EQ(2u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithCoords(POINTER_X - 100, POINTER_Y), WithPointerCount(1u), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + args.pop_front(); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), + WithPointerCoords(1, POINTER_X + 100, POINTER_Y), WithPointerCount(2u), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + + Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + /* dz= */ 1.2, GESTURES_ZOOM_UPDATE); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, updateGesture); + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.2f, EPSILON), + WithPointerCoords(0, POINTER_X - 120, POINTER_Y), + WithPointerCoords(1, POINTER_X + 120, POINTER_Y), WithPointerCount(2u), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + + Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, + GESTURES_ZOOM_END); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, endGesture); + ASSERT_EQ(2u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + args.pop_front(); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithMotionClassification(MotionClassification::PINCH), + WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), + WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); +} + +TEST_F(GestureConverterTest, Pinch_ClearsClassificationAndScaleFactorAfterGesture) { + InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); + GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + + Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, + GESTURES_ZOOM_START); + std::list args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); + + Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, + /* dz= */ 1.2, GESTURES_ZOOM_UPDATE); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, updateGesture); + + Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, + GESTURES_ZOOM_END); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, endGesture); + + Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); + args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); + ASSERT_EQ(1u, args.size()); + ASSERT_THAT(std::get(args.front()), + AllOf(WithMotionClassification(MotionClassification::NONE), + WithGesturePinchScaleFactor(0, EPSILON))); +} + } // namespace android diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h index 53e4066b20..b9d96076f1 100644 --- a/services/inputflinger/tests/TestInputListenerMatchers.h +++ b/services/inputflinger/tests/TestInputListenerMatchers.h @@ -81,6 +81,14 @@ MATCHER_P2(WithCoords, x, y, "InputEvent with specified coords") { return argX == x && argY == y; } +MATCHER_P3(WithPointerCoords, pointer, x, y, "InputEvent with specified coords for pointer") { + const auto argX = arg.pointerCoords[pointer].getX(); + const auto argY = arg.pointerCoords[pointer].getY(); + *result_listener << "expected pointer " << pointer << " to have coords (" << x << ", " << y + << "), but got (" << argX << ", " << argY << ")"; + return argX == x && argY == y; +} + MATCHER_P2(WithRelativeMotion, x, y, "InputEvent with specified relative motion") { const auto argX = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); const auto argY = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); @@ -113,6 +121,15 @@ MATCHER_P3(WithGestureScrollDistance, x, y, epsilon, return xDiff <= epsilon && yDiff <= epsilon; } +MATCHER_P2(WithGesturePinchScaleFactor, factor, epsilon, + "InputEvent with specified touchpad pinch gesture scale factor") { + const auto argScaleFactor = + arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR); + *result_listener << "expected gesture scale factor " << factor << " within " << epsilon + << " but got " << argScaleFactor; + return fabs(argScaleFactor - factor) <= epsilon; +} + MATCHER_P(WithPressure, pressure, "InputEvent with specified pressure") { const auto argPressure = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); *result_listener << "expected pressure " << pressure << ", but got " << argPressure; -- cgit v1.2.3-59-g8ed1b From 5df3493d3cf633f8ac7447bc5474a0dfbc1a8359 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 23 Jan 2023 12:41:01 -0800 Subject: Validate axes and led labels correctly Before this CL, a number of checks for kl file validity were incorrect. Some of the APIs were supposed to return an invalid value, but instead were always returning a valid value, no matter what the input was. Correct these values by switching to std::optional. Bug: 266400536 Test: m libinput_tests && adb sync data && adb shell -t /data/nativetest64/libinput_tests/libinput_tests Change-Id: I4ef45f3249dca4f4f033fb85e9fecbc2ad1f1395 --- include/input/Input.h | 4 +- include/input/InputEventLabels.h | 12 ++-- libs/input/Input.cpp | 4 +- libs/input/InputEventLabels.cpp | 22 +++---- libs/input/KeyCharacterMap.cpp | 24 ++++---- libs/input/KeyLayoutMap.cpp | 106 +++++++++++++++++++------------- libs/input/tests/InputDevice_test.cpp | 14 +++++ libs/input/tests/data/bad_axis_label.kl | 17 +++++ libs/input/tests/data/bad_led_label.kl | 17 +++++ 9 files changed, 142 insertions(+), 78 deletions(-) create mode 100644 libs/input/tests/data/bad_axis_label.kl create mode 100644 libs/input/tests/data/bad_led_label.kl (limited to 'libs/input/InputEventLabels.cpp') diff --git a/include/input/Input.h b/include/input/Input.h index 30b0d6a67a..7573282fc1 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -529,7 +529,7 @@ public: inline nsecs_t getEventTime() const { return mEventTime; } static const char* getLabel(int32_t keyCode); - static int32_t getKeyCodeFromLabel(const char* label); + static std::optional getKeyCodeFromLabel(const char* label); void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, std::array hmac, int32_t action, int32_t flags, int32_t keyCode, @@ -842,7 +842,7 @@ public: } static const char* getLabel(int32_t axis); - static int32_t getAxisFromLabel(const char* label); + static std::optional getAxisFromLabel(const char* label); static std::string actionToString(int32_t action); diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h index b4374acdcc..4668fce116 100644 --- a/include/input/InputEventLabels.h +++ b/include/input/InputEventLabels.h @@ -35,22 +35,22 @@ struct InputEventLabel { class InputEventLookup { public: - static int lookupValueByLabel(const std::unordered_map& map, - const char* literal); + static std::optional lookupValueByLabel(const std::unordered_map& map, + const char* literal); static const char* lookupLabelByValue(const std::vector& vec, int value); - static int32_t getKeyCodeByLabel(const char* label); + static std::optional getKeyCodeByLabel(const char* label); static const char* getLabelByKeyCode(int32_t keyCode); - static uint32_t getKeyFlagByLabel(const char* label); + static std::optional getKeyFlagByLabel(const char* label); - static int32_t getAxisByLabel(const char* label); + static std::optional getAxisByLabel(const char* label); static const char* getAxisLabel(int32_t axisId); - static int32_t getLedByLabel(const char* label); + static std::optional getLedByLabel(const char* label); private: static const std::unordered_map KEYCODES; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index c356c2e5e9..133b260a61 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -299,7 +299,7 @@ const char* KeyEvent::getLabel(int32_t keyCode) { return InputEventLookup::getLabelByKeyCode(keyCode); } -int32_t KeyEvent::getKeyCodeFromLabel(const char* label) { +std::optional KeyEvent::getKeyCodeFromLabel(const char* label) { return InputEventLookup::getKeyCodeByLabel(label); } @@ -891,7 +891,7 @@ const char* MotionEvent::getLabel(int32_t axis) { return InputEventLookup::getAxisLabel(axis); } -int32_t MotionEvent::getAxisFromLabel(const char* label) { +std::optional MotionEvent::getAxisFromLabel(const char* label) { return InputEventLookup::getAxisByLabel(label); } diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index 7159e27b13..d97c1bb629 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -438,11 +438,11 @@ const std::unordered_map InputEventLookup::LEDS = {LEDS_SEQUEN const std::unordered_map InputEventLookup::FLAGS = {FLAGS_SEQUENCE}; -int InputEventLookup::lookupValueByLabel(const std::unordered_map& map, - const char* literal) { +std::optional InputEventLookup::lookupValueByLabel( + const std::unordered_map& map, const char* literal) { std::string str(literal); auto it = map.find(str); - return it != map.end() ? it->second : 0; + return it != map.end() ? std::make_optional(it->second) : std::nullopt; } const char* InputEventLookup::lookupLabelByValue(const std::vector& vec, @@ -453,8 +453,8 @@ const char* InputEventLookup::lookupLabelByValue(const std::vector InputEventLookup::getKeyCodeByLabel(const char* label) { + return lookupValueByLabel(KEYCODES, label); } const char* InputEventLookup::getLabelByKeyCode(int32_t keyCode) { @@ -464,20 +464,20 @@ const char* InputEventLookup::getLabelByKeyCode(int32_t keyCode) { return nullptr; } -uint32_t InputEventLookup::getKeyFlagByLabel(const char* label) { - return uint32_t(lookupValueByLabel(FLAGS, label)); +std::optional InputEventLookup::getKeyFlagByLabel(const char* label) { + return lookupValueByLabel(FLAGS, label); } -int32_t InputEventLookup::getAxisByLabel(const char* label) { - return int32_t(lookupValueByLabel(AXES, label)); +std::optional InputEventLookup::getAxisByLabel(const char* label) { + return lookupValueByLabel(AXES, label); } const char* InputEventLookup::getAxisLabel(int32_t axisId) { return lookupLabelByValue(AXES_NAMES, axisId); } -int32_t InputEventLookup::getLedByLabel(const char* label) { - return int32_t(lookupValueByLabel(LEDS, label)); +std::optional InputEventLookup::getLedByLabel(const char* label) { + return lookupValueByLabel(LEDS, label); } } // namespace android diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 6bfac40932..737bd15901 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -999,7 +999,7 @@ status_t KeyCharacterMap::Parser::parseMapKey() { mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + std::optional keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); if (!keyCode) { ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), keyCodeToken.string()); @@ -1010,19 +1010,19 @@ status_t KeyCharacterMap::Parser::parseMapKey() { ALOGD("Parsed map key %s: code=%d, keyCode=%d.", mapUsage ? "usage" : "scan code", code, keyCode); #endif - map.insert_or_assign(code, keyCode); + map.insert_or_assign(code, *keyCode); return NO_ERROR; } status_t KeyCharacterMap::Parser::parseKey() { String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + std::optional keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); if (!keyCode) { ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), keyCodeToken.string()); return BAD_VALUE; } - if (mMap->mKeys.indexOfKey(keyCode) >= 0) { + if (mMap->mKeys.indexOfKey(*keyCode) >= 0) { ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(), keyCodeToken.string()); return BAD_VALUE; @@ -1036,11 +1036,9 @@ status_t KeyCharacterMap::Parser::parseKey() { return BAD_VALUE; } -#if DEBUG_PARSER - ALOGD("Parsed beginning of key: keyCode=%d.", keyCode); -#endif - mKeyCode = keyCode; - mMap->mKeys.add(keyCode, new Key()); + ALOGD_IF(DEBUG_PARSER, "Parsed beginning of key: keyCode=%d.", *keyCode); + mKeyCode = *keyCode; + mMap->mKeys.add(*keyCode, new Key()); mState = STATE_KEY; return NO_ERROR; } @@ -1136,7 +1134,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { } else if (token == "fallback") { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string()); + std::optional keyCode = InputEventLookup::getKeyCodeByLabel(token.string()); if (!keyCode) { ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.", mTokenizer->getLocation().string(), @@ -1148,12 +1146,12 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { mTokenizer->getLocation().string()); return BAD_VALUE; } - behavior.fallbackKeyCode = keyCode; + behavior.fallbackKeyCode = *keyCode; haveFallback = true; } else if (token == "replace") { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string()); + std::optional keyCode = InputEventLookup::getKeyCodeByLabel(token.string()); if (!keyCode) { ALOGE("%s: Invalid key code label for replace, got '%s'.", mTokenizer->getLocation().string(), @@ -1170,7 +1168,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { mTokenizer->getLocation().string()); return BAD_VALUE; } - behavior.replacementKeyCode = keyCode; + behavior.replacementKeyCode = *keyCode; haveReplacement = true; } else { diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index 73710330d0..a2649f6f11 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "KeyLayoutMap" +#include #include #include #include @@ -54,6 +55,21 @@ const bool DEBUG_MAPPING = namespace android { namespace { +std::optional parseInt(const char* str) { + char* end; + errno = 0; + const int value = strtol(str, &end, 0); + if (end == str) { + LOG(ERROR) << "Could not parse " << str; + return {}; + } + if (errno == ERANGE) { + LOG(ERROR) << "Out of bounds: " << str; + return {}; + } + return value; +} + constexpr const char* WHITESPACE = " \t\r"; template @@ -336,16 +352,15 @@ status_t KeyLayoutMap::Parser::parseKey() { codeToken = mTokenizer->nextToken(WHITESPACE); } - char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); - if (*end) { + std::optional code = parseInt(codeToken.string()); + if (!code) { ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), mapUsage ? "usage" : "scan code", codeToken.string()); return BAD_VALUE; } std::unordered_map& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; - if (map.find(code) != map.end()) { + if (map.find(*code) != map.end()) { ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), mapUsage ? "usage" : "scan code", codeToken.string()); return BAD_VALUE; @@ -353,7 +368,7 @@ status_t KeyLayoutMap::Parser::parseKey() { mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + std::optional keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); if (!keyCode) { ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), keyCodeToken.string()); @@ -366,40 +381,39 @@ status_t KeyLayoutMap::Parser::parseKey() { if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break; String8 flagToken = mTokenizer->nextToken(WHITESPACE); - uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.string()); + std::optional flag = InputEventLookup::getKeyFlagByLabel(flagToken.string()); if (!flag) { ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), flagToken.string()); return BAD_VALUE; } - if (flags & flag) { + if (flags & *flag) { ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), flagToken.string()); return BAD_VALUE; } - flags |= flag; + flags |= *flag; } ALOGD_IF(DEBUG_PARSER, "Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.", - mapUsage ? "usage" : "scan code", code, keyCode, flags); + mapUsage ? "usage" : "scan code", *code, *keyCode, flags); Key key; - key.keyCode = keyCode; + key.keyCode = *keyCode; key.flags = flags; - map.insert({code, key}); + map.insert({*code, key}); return NO_ERROR; } status_t KeyLayoutMap::Parser::parseAxis() { String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); - char* end; - int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); - if (*end) { + std::optional scanCode = parseInt(scanCodeToken.string()); + if (!scanCode) { ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), scanCodeToken.string()); return BAD_VALUE; } - if (mMap->mAxes.find(scanCode) != mMap->mAxes.end()) { + if (mMap->mAxes.find(*scanCode) != mMap->mAxes.end()) { ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), scanCodeToken.string()); return BAD_VALUE; @@ -414,48 +428,53 @@ status_t KeyLayoutMap::Parser::parseAxis() { mTokenizer->skipDelimiters(WHITESPACE); String8 axisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.string()); - if (axisInfo.axis < 0) { + std::optional axis = InputEventLookup::getAxisByLabel(axisToken.string()); + if (!axis) { ALOGE("%s: Expected inverted axis label, got '%s'.", mTokenizer->getLocation().string(), axisToken.string()); return BAD_VALUE; } + axisInfo.axis = *axis; } else if (token == "split") { axisInfo.mode = AxisInfo::MODE_SPLIT; mTokenizer->skipDelimiters(WHITESPACE); String8 splitToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0)); - if (*end) { + std::optional splitValue = parseInt(splitToken.string()); + if (!splitValue) { ALOGE("%s: Expected split value, got '%s'.", mTokenizer->getLocation().string(), splitToken.string()); return BAD_VALUE; } + axisInfo.splitValue = *splitValue; mTokenizer->skipDelimiters(WHITESPACE); String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.string()); - if (axisInfo.axis < 0) { + std::optional axis = InputEventLookup::getAxisByLabel(lowAxisToken.string()); + if (!axis) { ALOGE("%s: Expected low axis label, got '%s'.", mTokenizer->getLocation().string(), lowAxisToken.string()); return BAD_VALUE; } + axisInfo.axis = *axis; mTokenizer->skipDelimiters(WHITESPACE); String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.string()); - if (axisInfo.highAxis < 0) { + std::optional highAxis = InputEventLookup::getAxisByLabel(highAxisToken.string()); + if (!highAxis) { ALOGE("%s: Expected high axis label, got '%s'.", mTokenizer->getLocation().string(), highAxisToken.string()); return BAD_VALUE; } + axisInfo.highAxis = *highAxis; } else { - axisInfo.axis = InputEventLookup::getAxisByLabel(token.string()); - if (axisInfo.axis < 0) { + std::optional axis = InputEventLookup::getAxisByLabel(token.string()); + if (!axis) { ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", mTokenizer->getLocation().string(), token.string()); return BAD_VALUE; } + axisInfo.axis = *axis; } for (;;) { @@ -467,12 +486,13 @@ status_t KeyLayoutMap::Parser::parseAxis() { if (keywordToken == "flat") { mTokenizer->skipDelimiters(WHITESPACE); String8 flatToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0)); - if (*end) { + std::optional flatOverride = parseInt(flatToken.string()); + if (!flatOverride) { ALOGE("%s: Expected flat value, got '%s'.", mTokenizer->getLocation().string(), flatToken.string()); return BAD_VALUE; } + axisInfo.flatOverride = *flatOverride; } else { ALOGE("%s: Expected keyword 'flat', got '%s'.", mTokenizer->getLocation().string(), keywordToken.string()); @@ -483,9 +503,9 @@ status_t KeyLayoutMap::Parser::parseAxis() { ALOGD_IF(DEBUG_PARSER, "Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, " "splitValue=%d, flatOverride=%d.", - scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue, + *scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue, axisInfo.flatOverride); - mMap->mAxes.insert({scanCode, axisInfo}); + mMap->mAxes.insert({*scanCode, axisInfo}); return NO_ERROR; } @@ -497,9 +517,8 @@ status_t KeyLayoutMap::Parser::parseLed() { mTokenizer->skipDelimiters(WHITESPACE); codeToken = mTokenizer->nextToken(WHITESPACE); } - char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); - if (*end) { + std::optional code = parseInt(codeToken.string()); + if (!code) { ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(), mapUsage ? "usage" : "scan code", codeToken.string()); return BAD_VALUE; @@ -507,7 +526,7 @@ status_t KeyLayoutMap::Parser::parseLed() { std::unordered_map& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode; - if (map.find(code) != map.end()) { + if (map.find(*code) != map.end()) { ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(), mapUsage ? "usage" : "scan code", codeToken.string()); return BAD_VALUE; @@ -515,19 +534,19 @@ status_t KeyLayoutMap::Parser::parseLed() { mTokenizer->skipDelimiters(WHITESPACE); String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.string()); - if (ledCode < 0) { + std::optional ledCode = InputEventLookup::getLedByLabel(ledCodeToken.string()); + if (!ledCode) { ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(), ledCodeToken.string()); return BAD_VALUE; } ALOGD_IF(DEBUG_PARSER, "Parsed led %s: code=%d, ledCode=%d.", mapUsage ? "usage" : "scan code", - code, ledCode); + *code, *ledCode); Led led; - led.ledCode = ledCode; - map.insert({code, led}); + led.ledCode = *ledCode; + map.insert({*code, led}); return NO_ERROR; } @@ -565,16 +584,15 @@ static std::optional getSensorDataIndex(String8 token) { // sensor 0x05 GYROSCOPE Z status_t KeyLayoutMap::Parser::parseSensor() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); - char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); - if (*end) { + std::optional code = parseInt(codeToken.string()); + if (!code) { ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().string(), "abs code", codeToken.string()); return BAD_VALUE; } std::unordered_map& map = mMap->mSensorsByAbsCode; - if (map.find(code) != map.end()) { + if (map.find(*code) != map.end()) { ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().string(), "abs code", codeToken.string()); return BAD_VALUE; @@ -599,13 +617,13 @@ status_t KeyLayoutMap::Parser::parseSensor() { } int32_t sensorDataIndex = indexOpt.value(); - ALOGD_IF(DEBUG_PARSER, "Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code, + ALOGD_IF(DEBUG_PARSER, "Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", *code, ftl::enum_string(sensorType).c_str(), sensorDataIndex); Sensor sensor; sensor.sensorType = sensorType; sensor.sensorDataIndex = sensorDataIndex; - map.emplace(code, sensor); + map.emplace(*code, sensor); return NO_ERROR; } diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp index 2344463241..ee961f0ffc 100644 --- a/libs/input/tests/InputDevice_test.cpp +++ b/libs/input/tests/InputDevice_test.cpp @@ -133,6 +133,20 @@ TEST_F(InputDeviceKeyMapTest, keyCharacteMapApplyMultipleOverlaysTest) { ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap); } +TEST_F(InputDeviceKeyMapTest, keyCharacteMapBadAxisLabel) { + std::string klPath = base::GetExecutableDirectory() + "/data/bad_axis_label.kl"; + + base::Result> ret = KeyLayoutMap::load(klPath); + ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath; +} + +TEST_F(InputDeviceKeyMapTest, keyCharacteMapBadLedLabel) { + std::string klPath = base::GetExecutableDirectory() + "/data/bad_led_label.kl"; + + base::Result> ret = KeyLayoutMap::load(klPath); + ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath; +} + TEST(InputDeviceKeyLayoutTest, DoesNotLoadWhenRequiredKernelConfigIsMissing) { #if !defined(__ANDROID__) GTEST_SKIP() << "Can't check kernel configs on host"; diff --git a/libs/input/tests/data/bad_axis_label.kl b/libs/input/tests/data/bad_axis_label.kl new file mode 100644 index 0000000000..689738077c --- /dev/null +++ b/libs/input/tests/data/bad_axis_label.kl @@ -0,0 +1,17 @@ +# Copyright (C) 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This KL should not be loaded because the axis label is not valid + +axis 0 DEFINITELY_NOT_AXIS_LABEL diff --git a/libs/input/tests/data/bad_led_label.kl b/libs/input/tests/data/bad_led_label.kl new file mode 100644 index 0000000000..293c0d2af4 --- /dev/null +++ b/libs/input/tests/data/bad_led_label.kl @@ -0,0 +1,17 @@ +# Copyright (C) 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This KL should not be loaded because the led label is invalid + +led 0 ABSOLUTELY_NOT_LED_LABEL -- cgit v1.2.3-59-g8ed1b From 1e63fc2fcb3d965d1df95e20b192565915d32fe8 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 23 Feb 2023 19:03:03 +0000 Subject: Improve logging of evdev events by using labels for recognized values When logging evdev events, use the human-readable labels for recognized values for the event type, the event code, and event value. Bug: 193231132 Test: Manual, by enabling raw events logging: setprop log.tag.InputReaderRawEvents DEBUG Change-Id: I8ed700a1e2d8659031514d2d8f9aef420b129dbc --- include/input/InputEventLabels.h | 8 +++ libs/input/Android.bp | 4 ++ libs/input/InputEventLabels.cpp | 84 ++++++++++++++++++++++++++++ services/inputflinger/reader/InputDevice.cpp | 17 +++--- 4 files changed, 104 insertions(+), 9 deletions(-) (limited to 'libs/input/InputEventLabels.cpp') diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h index 4668fce116..9dedd2b2da 100644 --- a/include/input/InputEventLabels.h +++ b/include/input/InputEventLabels.h @@ -30,6 +30,12 @@ struct InputEventLabel { int value; }; +struct EvdevEventLabel { + std::string type; + std::string code; + std::string value; +}; + // NOTE: If you want a new key code, axis code, led code or flag code in keylayout file, // then you must add it to InputEventLabels.cpp. @@ -52,6 +58,8 @@ public: static std::optional getLedByLabel(const char* label); + static EvdevEventLabel getLinuxEvdevLabel(int32_t type, int32_t code, int32_t value); + private: static const std::unordered_map KEYCODES; diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 48cb72cfb7..f38dd98428 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -69,6 +69,10 @@ cc_library { ], export_header_lib_headers: ["jni_headers"], + generated_headers: [ + "toolbox_input_labels", + ], + shared_libs: [ "libbase", "libcutils", diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index d97c1bb629..4a19227694 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -16,6 +16,9 @@ #include +#include +#include + #define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key } #define DEFINE_AXIS(axis) { #axis, AMOTION_EVENT_AXIS_##axis } #define DEFINE_LED(led) { #led, ALED_##led } @@ -480,4 +483,85 @@ std::optional InputEventLookup::getLedByLabel(const char* label) { return lookupValueByLabel(LEDS, label); } +namespace { + +struct label { + const char* name; + int value; +}; + +#define LABEL(constant) \ + { #constant, constant } +#define LABEL_END \ + { nullptr, -1 } + +static struct label ev_key_value_labels[] = { + {"UP", 0}, + {"DOWN", 1}, + {"REPEAT", 2}, + LABEL_END, +}; + +#include "input.h-labels.h" + +#undef LABEL +#undef LABEL_END + +std::string getLabel(const label* labels, int value) { + if (labels == nullptr) return std::to_string(value); + while (labels->name != nullptr && value != labels->value) { + labels++; + } + return labels->name != nullptr ? labels->name : std::to_string(value); +} + +const label* getCodeLabelsForType(int32_t type) { + switch (type) { + case EV_SYN: + return syn_labels; + case EV_KEY: + return key_labels; + case EV_REL: + return rel_labels; + case EV_ABS: + return abs_labels; + case EV_SW: + return sw_labels; + case EV_MSC: + return msc_labels; + case EV_LED: + return led_labels; + case EV_REP: + return rep_labels; + case EV_SND: + return snd_labels; + case EV_FF: + return ff_labels; + case EV_FF_STATUS: + return ff_status_labels; + default: + return nullptr; + } +} + +const label* getValueLabelsForTypeAndCode(int32_t type, int32_t code) { + if (type == EV_KEY) { + return ev_key_value_labels; + } + if (type == EV_MSC && code == ABS_MT_TOOL_TYPE) { + return mt_tool_labels; + } + return nullptr; +} + +} // namespace + +EvdevEventLabel InputEventLookup::getLinuxEvdevLabel(int32_t type, int32_t code, int32_t value) { + return { + .type = getLabel(ev_labels, type), + .code = getLabel(getCodeLabelsForType(type), code), + .value = getLabel(getValueLabelsForTypeAndCode(type, code), value), + }; +} + } // namespace android diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 002de2933b..6fd4ff35fc 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -413,21 +413,20 @@ std::list InputDevice::process(const RawEvent* rawEvents, size_t cou std::list out; for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) { if (debugRawEvents()) { - ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64, - rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, - rawEvent->when); + const auto [type, code, value] = + InputEventLookup::getLinuxEvdevLabel(rawEvent->type, rawEvent->code, + rawEvent->value); + ALOGD("Input event: eventHubDevice=%d type=%s code=%s value=%s when=%" PRId64, + rawEvent->deviceId, type.c_str(), code.c_str(), value.c_str(), rawEvent->when); } if (mDropUntilNextSync) { if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { mDropUntilNextSync = false; - if (debugRawEvents()) { - ALOGD("Recovered from input event buffer overrun."); - } + ALOGD_IF(debugRawEvents(), "Recovered from input event buffer overrun."); } else { - if (debugRawEvents()) { - ALOGD("Dropped input event while waiting for next input sync."); - } + ALOGD_IF(debugRawEvents(), + "Dropped input event while waiting for next input sync."); } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { ALOGI("Detected input event buffer overrun for device %s.", getName().c_str()); -- cgit v1.2.3-59-g8ed1b From 57680eb7c8a21ed28f359f9504eb000709a74d84 Mon Sep 17 00:00:00 2001 From: Max Zhang Date: Thu, 15 Dec 2022 18:15:39 +0000 Subject: [1/4] Add user customizable MACRO_x keys in frameworks Define keycode in frameworks/native as input labels Project details can be found at go/dipper-custom-button Bug: 269742724 Test: local build Change-Id: I9af8e14892f65e14319f34421063ef330a02078e (cherry picked from commit fcf20b80e15ad23e31bb33e422495eaed2fc7448) --- include/android/keycodes.h | 8 ++++++++ libs/input/InputEventLabels.cpp | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'libs/input/InputEventLabels.cpp') diff --git a/include/android/keycodes.h b/include/android/keycodes.h index d4ba321057..f8fb256fae 100644 --- a/include/android/keycodes.h +++ b/include/android/keycodes.h @@ -831,6 +831,14 @@ enum { AKEYCODE_STYLUS_BUTTON_TAIL = 311, /** Key to open recent apps (a.k.a. Overview) */ AKEYCODE_RECENT_APPS = 312, + /** User customizable key #1. */ + AKEYCODE_MACRO_1 = 313, + /** User customizable key #2. */ + AKEYCODE_MACRO_2 = 314, + /** User customizable key #3. */ + AKEYCODE_MACRO_3 = 315, + /** User customizable key #4. */ + AKEYCODE_MACRO_4 = 316, // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index 4a19227694..f99a7d640e 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -343,7 +343,11 @@ namespace android { DEFINE_KEYCODE(STYLUS_BUTTON_SECONDARY), \ DEFINE_KEYCODE(STYLUS_BUTTON_TERTIARY), \ DEFINE_KEYCODE(STYLUS_BUTTON_TAIL), \ - DEFINE_KEYCODE(RECENT_APPS) + DEFINE_KEYCODE(RECENT_APPS), \ + DEFINE_KEYCODE(MACRO_1), \ + DEFINE_KEYCODE(MACRO_2), \ + DEFINE_KEYCODE(MACRO_3), \ + DEFINE_KEYCODE(MACRO_4) // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. -- cgit v1.2.3-59-g8ed1b