diff options
author | 2022-11-15 17:38:36 +0000 | |
---|---|---|
committer | 2022-12-02 17:31:26 +0000 | |
commit | 1f48a4458506da6384ee15e2bdef2e2941b3fcc7 (patch) | |
tree | cf6d1c0a1c52af6496c0d1ac989e342b05a8557d | |
parent | 79cc9fa5f0d40938bdfcd971d5af9a0bcc8b440c (diff) |
Set up a GestureInterpreter and feed it events
This is a minimal setup of the gestures library, in that it doesn't have
a timer provider or property provider, but it's enough to be able to
feed it events and have it report the gestures it has detected.
This CL depends on https://r.android.com/2310648 to pull in the
Android.bp file and `SetCallback` rename from upstream, and
https://r.android.com/2314880 to pull in the deprecation of screen DPI
hardware properties.
Bug: 251196347
Test: connect Apple Magic Trackpad 2, make gestures, check logcat
Change-Id: Ib40880360c3865f0a98b7a067b7efe9fd8178212
7 files changed, 200 insertions, 8 deletions
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index 551ad7a398..f5ac8de53d 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -132,6 +132,7 @@ cc_library_shared { // This should consist only of dependencies from inputflinger. Other dependencies should be // in cc_defaults so that they are included in the tests. "libinputflinger_base", + "libjsoncpp", ], export_header_lib_headers: [ "libinputreader_headers", @@ -146,5 +147,6 @@ cc_library_shared { }, static_libs: [ "libc++fs", + "libchrome-gestures", ], } diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 6ca629835d..150a8aac0d 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -211,7 +211,8 @@ void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) { // Touchscreens and touchpad devices. // TODO(b/251196347): replace this with a proper flag. constexpr bool ENABLE_NEW_TOUCHPAD_STACK = false; - if (ENABLE_NEW_TOUCHPAD_STACK && classes.test(InputDeviceClass::TOUCHPAD)) { + if (ENABLE_NEW_TOUCHPAD_STACK && classes.test(InputDeviceClass::TOUCHPAD) && + classes.test(InputDeviceClass::TOUCH_MT)) { mappers.push_back(std::make_unique<TouchpadInputMapper>(*contextPtr)); } else if (classes.test(InputDeviceClass::TOUCH_MT)) { mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr)); diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index 3ad1de4cd4..8c5bce7d13 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -16,21 +16,165 @@ #include "../Macros.h" +#include <log/log_main.h> +#include <chrono> #include "TouchpadInputMapper.h" namespace android { +namespace { + +short getMaxTouchCount(const InputDeviceContext& context) { + if (context.hasKeyCode(BTN_TOOL_QUINTTAP)) return 5; + if (context.hasKeyCode(BTN_TOOL_QUADTAP)) return 4; + if (context.hasKeyCode(BTN_TOOL_TRIPLETAP)) return 3; + if (context.hasKeyCode(BTN_TOOL_DOUBLETAP)) return 2; + if (context.hasKeyCode(BTN_TOOL_FINGER)) return 1; + return 0; +} + +HardwareProperties createHardwareProperties(const InputDeviceContext& context) { + HardwareProperties props; + RawAbsoluteAxisInfo absMtPositionX; + context.getAbsoluteAxisInfo(ABS_MT_POSITION_X, &absMtPositionX); + props.left = absMtPositionX.minValue; + props.right = absMtPositionX.maxValue; + props.res_x = absMtPositionX.resolution; + + RawAbsoluteAxisInfo absMtPositionY; + context.getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &absMtPositionY); + props.top = absMtPositionY.minValue; + props.bottom = absMtPositionY.maxValue; + props.res_y = absMtPositionY.resolution; + + RawAbsoluteAxisInfo absMtOrientation; + context.getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &absMtOrientation); + props.orientation_minimum = absMtOrientation.minValue; + props.orientation_maximum = absMtOrientation.maxValue; + + RawAbsoluteAxisInfo absMtSlot; + context.getAbsoluteAxisInfo(ABS_MT_SLOT, &absMtSlot); + props.max_finger_cnt = absMtSlot.maxValue - absMtSlot.minValue + 1; + props.max_touch_cnt = getMaxTouchCount(context); + + // T5R2 ("Track 5, Report 2") is a feature of some old Synaptics touchpads that could track 5 + // fingers but only report the coordinates of 2 of them. We don't know of any external touchpads + // that did this, so assume false. + props.supports_t5r2 = false; + + props.support_semi_mt = context.hasInputProperty(INPUT_PROP_SEMI_MT); + props.is_button_pad = context.hasInputProperty(INPUT_PROP_BUTTONPAD); + + // Mouse-only properties, which will always be false. + props.has_wheel = false; + props.wheel_is_hi_res = false; + + // Linux Kernel haptic touchpad support isn't merged yet, so for now assume that no touchpads + // are haptic. + props.is_haptic_pad = false; + return props; +} + +void gestureInterpreterCallback(void* clientData, const struct Gesture* gesture) { + // TODO(b/251196347): turn the gesture into a NotifyArgs and dispatch it. + ALOGD("Gesture ready: %s", gesture->String().c_str()); +} + +} // namespace + TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext) - : InputMapper(deviceContext) {} + : InputMapper(deviceContext), + mGestureInterpreter(NewGestureInterpreter(), DeleteGestureInterpreter), + mTouchButtonAccumulator(deviceContext) { + mGestureInterpreter->Initialize(GESTURES_DEVCLASS_TOUCHPAD); + mGestureInterpreter->SetHardwareProperties(createHardwareProperties(deviceContext)); + mGestureInterpreter->SetCallback(gestureInterpreterCallback, nullptr); + // TODO(b/251196347): set a property provider, so we can change gesture properties. + // TODO(b/251196347): set a timer provider, so the library can use timers. + + RawAbsoluteAxisInfo slotAxisInfo; + getAbsoluteAxisInfo(ABS_MT_SLOT, &slotAxisInfo); + if (!slotAxisInfo.valid || slotAxisInfo.maxValue <= 0) { + ALOGW("Touchpad \"%s\" doesn't have a valid ABS_MT_SLOT axis, and probably won't work " + "properly.", + getDeviceName().c_str()); + } + mMotionAccumulator.configure(getDeviceContext(), slotAxisInfo.maxValue + 1, true); + mTouchButtonAccumulator.configure(); +} uint32_t TouchpadInputMapper::getSources() const { return AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD; } +std::list<NotifyArgs> TouchpadInputMapper::reset(nsecs_t when) { + mCursorButtonAccumulator.reset(getDeviceContext()); + mTouchButtonAccumulator.reset(); + mMscTimestamp = 0; + return InputMapper::reset(when); +} + std::list<NotifyArgs> TouchpadInputMapper::process(const RawEvent* rawEvent) { - ALOGD("TODO: process event type=0x%x code=0x%x value=0x%x", rawEvent->type, rawEvent->code, - rawEvent->value); + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } + if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) { + mMscTimestamp = rawEvent->value; + } + mCursorButtonAccumulator.process(rawEvent); + mMotionAccumulator.process(rawEvent); + mTouchButtonAccumulator.process(rawEvent); return {}; } +void TouchpadInputMapper::sync(nsecs_t when) { + HardwareState hwState; + // The gestures library uses doubles to represent timestamps in seconds. + hwState.timestamp = std::chrono::duration<stime_t>(std::chrono::nanoseconds(when)).count(); + hwState.msc_timestamp = + std::chrono::duration<stime_t>(std::chrono::microseconds(mMscTimestamp)).count(); + + hwState.buttons_down = 0; + if (mCursorButtonAccumulator.isLeftPressed()) { + hwState.buttons_down |= GESTURES_BUTTON_LEFT; + } + if (mCursorButtonAccumulator.isMiddlePressed()) { + hwState.buttons_down |= GESTURES_BUTTON_MIDDLE; + } + if (mCursorButtonAccumulator.isRightPressed()) { + hwState.buttons_down |= GESTURES_BUTTON_RIGHT; + } + if (mCursorButtonAccumulator.isBackPressed() || mCursorButtonAccumulator.isSidePressed()) { + hwState.buttons_down |= GESTURES_BUTTON_BACK; + } + if (mCursorButtonAccumulator.isForwardPressed() || mCursorButtonAccumulator.isExtraPressed()) { + hwState.buttons_down |= GESTURES_BUTTON_FORWARD; + } + + std::vector<FingerState> fingers; + for (size_t i = 0; i < mMotionAccumulator.getSlotCount(); i++) { + MultiTouchMotionAccumulator::Slot slot = mMotionAccumulator.getSlot(i); + if (slot.isInUse()) { + FingerState& fingerState = fingers.emplace_back(); + fingerState = {}; + fingerState.touch_major = slot.getTouchMajor(); + fingerState.touch_minor = slot.getTouchMinor(); + fingerState.width_major = slot.getToolMajor(); + fingerState.width_minor = slot.getToolMinor(); + fingerState.pressure = slot.getPressure(); + fingerState.orientation = slot.getOrientation(); + fingerState.position_x = slot.getX(); + fingerState.position_y = slot.getY(); + fingerState.tracking_id = slot.getTrackingId(); + } + } + hwState.fingers = fingers.data(); + hwState.finger_cnt = fingers.size(); + hwState.touch_cnt = mTouchButtonAccumulator.getTouchCount(); + + mGestureInterpreter->PushHardwareState(&hwState); + mMotionAccumulator.finishSync(); + mMscTimestamp = 0; +} + } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h index 81a76d27be..9d3a4b3e0d 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h @@ -16,10 +16,17 @@ #pragma once +#include <memory> + #include "EventHub.h" #include "InputDevice.h" #include "InputMapper.h" #include "NotifyArgs.h" +#include "accumulator/CursorButtonAccumulator.h" +#include "accumulator/MultiTouchMotionAccumulator.h" +#include "accumulator/TouchButtonAccumulator.h" + +#include "include/gestures.h" namespace android { @@ -27,8 +34,20 @@ class TouchpadInputMapper : public InputMapper { public: explicit TouchpadInputMapper(InputDeviceContext& deviceContext); - virtual uint32_t getSources() const override; - [[nodiscard]] virtual std::list<NotifyArgs> process(const RawEvent* rawEvent) override; + uint32_t getSources() const override; + [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override; + [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override; + +private: + void sync(nsecs_t when); + + std::unique_ptr<gestures::GestureInterpreter, void (*)(gestures::GestureInterpreter*)> + mGestureInterpreter; + + CursorButtonAccumulator mCursorButtonAccumulator; + MultiTouchMotionAccumulator mMotionAccumulator; + TouchButtonAccumulator mTouchButtonAccumulator; + int32_t mMscTimestamp = 0; }; } // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h index ed4c789cfd..138060483d 100644 --- a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h @@ -32,6 +32,14 @@ public: void process(const RawEvent* rawEvent); uint32_t getButtonState() const; + inline bool isLeftPressed() const { return mBtnLeft; } + inline bool isRightPressed() const { return mBtnRight; } + inline bool isMiddlePressed() const { return mBtnMiddle; } + inline bool isBackPressed() const { return mBtnBack; } + inline bool isSidePressed() const { return mBtnSide; } + inline bool isForwardPressed() const { return mBtnForward; } + inline bool isExtraPressed() const { return mBtnExtra; } + inline bool isTaskPressed() const { return mBtnTask; } private: bool mBtnLeft; diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp index bc23a8ec91..66017024eb 100644 --- a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp +++ b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp @@ -48,6 +48,7 @@ void TouchButtonAccumulator::reset() { mBtnToolDoubleTap = mDeviceContext.isKeyPressed(BTN_TOOL_DOUBLETAP); mBtnToolTripleTap = mDeviceContext.isKeyPressed(BTN_TOOL_TRIPLETAP); mBtnToolQuadTap = mDeviceContext.isKeyPressed(BTN_TOOL_QUADTAP); + mBtnToolQuintTap = mDeviceContext.isKeyPressed(BTN_TOOL_QUINTTAP); mHidUsageAccumulator.reset(); } @@ -100,6 +101,9 @@ void TouchButtonAccumulator::process(const RawEvent* rawEvent) { case BTN_TOOL_QUADTAP: mBtnToolQuadTap = rawEvent->value; break; + case BTN_TOOL_QUINTTAP: + mBtnToolQuintTap = rawEvent->value; + break; default: processMappedKey(rawEvent->code, rawEvent->value); } @@ -147,7 +151,8 @@ int32_t TouchButtonAccumulator::getToolType() const { if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { return AMOTION_EVENT_TOOL_TYPE_STYLUS; } - if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) { + if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap || + mBtnToolQuintTap) { return AMOTION_EVENT_TOOL_TYPE_FINGER; } return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; @@ -156,7 +161,7 @@ int32_t TouchButtonAccumulator::getToolType() const { bool TouchButtonAccumulator::isToolActive() const { return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush || mBtnToolMouse || mBtnToolLens || - mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap; + mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap || mBtnToolQuintTap; } bool TouchButtonAccumulator::isHovering() const { @@ -171,4 +176,15 @@ bool TouchButtonAccumulator::hasButtonTouch() const { return mHaveBtnTouch; } +int TouchButtonAccumulator::getTouchCount() const { + if (mBtnTouch) { + if (mBtnToolQuintTap) return 5; + if (mBtnToolQuadTap) return 4; + if (mBtnToolTripleTap) return 3; + if (mBtnToolDoubleTap) return 2; + if (mBtnToolFinger) return 1; + } + return 0; +} + } // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h index c2de23cee4..2e70e2e50d 100644 --- a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h @@ -41,6 +41,7 @@ public: bool isHovering() const; bool hasStylus() const; bool hasButtonTouch() const; + int getTouchCount() const; private: bool mHaveBtnTouch{}; @@ -60,6 +61,7 @@ private: bool mBtnToolDoubleTap{}; bool mBtnToolTripleTap{}; bool mBtnToolQuadTap{}; + bool mBtnToolQuintTap{}; HidUsageAccumulator mHidUsageAccumulator{}; |