Loading services/inputflinger/reader/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -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", Loading @@ -146,5 +147,6 @@ cc_library_shared { }, static_libs: [ "libc++fs", "libchrome-gestures", ], } services/inputflinger/reader/InputDevice.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -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)); Loading services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +147 −3 Original line number Diff line number Diff line Loading @@ -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 services/inputflinger/reader/mapper/TouchpadInputMapper.h +21 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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 services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h +8 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading
services/inputflinger/reader/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -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", Loading @@ -146,5 +147,6 @@ cc_library_shared { }, static_libs: [ "libc++fs", "libchrome-gestures", ], }
services/inputflinger/reader/InputDevice.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -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)); Loading
services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +147 −3 Original line number Diff line number Diff line Loading @@ -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
services/inputflinger/reader/mapper/TouchpadInputMapper.h +21 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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
services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h +8 −0 Original line number Diff line number Diff line Loading @@ -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; Loading