diff options
| author | 2022-12-08 11:51:18 +0000 | |
|---|---|---|
| committer | 2022-12-08 11:51:18 +0000 | |
| commit | 09e64ee6f6e442b382b4e790b8316ffd2ee5cbbe (patch) | |
| tree | 424f84cea157575d13fc1e300d23acc39f98643d | |
| parent | f5ebfdef32d43fa650fa7aae18c6333373913121 (diff) | |
| parent | 74235548729b615df5e85443ae3d4128fe041c79 (diff) | |
Merge "Convert touchpad gestures into pointer moves & clicks"
| -rw-r--r-- | services/inputflinger/reader/mapper/TouchpadInputMapper.cpp | 201 | ||||
| -rw-r--r-- | services/inputflinger/reader/mapper/TouchpadInputMapper.h | 27 |
2 files changed, 219 insertions, 9 deletions
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index 8c5bce7d13..de6e4b0193 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -16,8 +16,11 @@ #include "../Macros.h" -#include <log/log_main.h> #include <chrono> + +#include <android/input.h> +#include <log/log_main.h> +#include "TouchCursorInputMapperCommon.h" #include "TouchpadInputMapper.h" namespace android { @@ -75,9 +78,26 @@ HardwareProperties createHardwareProperties(const InputDeviceContext& context) { 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()); +void gestureInterpreterCallback(void* clientData, const Gesture* gesture) { + TouchpadInputMapper* mapper = static_cast<TouchpadInputMapper*>(clientData); + mapper->consumeGesture(gesture); +} + +uint32_t gesturesButtonToMotionEventButton(uint32_t gesturesButton) { + switch (gesturesButton) { + case GESTURES_BUTTON_LEFT: + return AMOTION_EVENT_BUTTON_PRIMARY; + case GESTURES_BUTTON_MIDDLE: + return AMOTION_EVENT_BUTTON_TERTIARY; + case GESTURES_BUTTON_RIGHT: + return AMOTION_EVENT_BUTTON_SECONDARY; + case GESTURES_BUTTON_BACK: + return AMOTION_EVENT_BUTTON_BACK; + case GESTURES_BUTTON_FORWARD: + return AMOTION_EVENT_BUTTON_FORWARD; + default: + return 0; + } } } // namespace @@ -85,10 +105,15 @@ void gestureInterpreterCallback(void* clientData, const struct Gesture* gesture) TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext) : InputMapper(deviceContext), mGestureInterpreter(NewGestureInterpreter(), DeleteGestureInterpreter), + mPointerController(getContext()->getPointerController(getDeviceId())), mTouchButtonAccumulator(deviceContext) { mGestureInterpreter->Initialize(GESTURES_DEVCLASS_TOUCHPAD); mGestureInterpreter->SetHardwareProperties(createHardwareProperties(deviceContext)); - mGestureInterpreter->SetCallback(gestureInterpreterCallback, nullptr); + // Even though we don't explicitly delete copy/move semantics, it's safe to + // give away a pointer to TouchpadInputMapper here because + // 1) mGestureInterpreter's lifecycle is determined by TouchpadInputMapper, and + // 2) TouchpadInputMapper is stored as a unique_ptr and not moved. + mGestureInterpreter->SetCallback(gestureInterpreterCallback, this); // 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. @@ -103,6 +128,12 @@ TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext) mTouchButtonAccumulator.configure(); } +TouchpadInputMapper::~TouchpadInputMapper() { + if (mPointerController != nullptr) { + mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE); + } +} + uint32_t TouchpadInputMapper::getSources() const { return AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD; } @@ -111,12 +142,15 @@ std::list<NotifyArgs> TouchpadInputMapper::reset(nsecs_t when) { mCursorButtonAccumulator.reset(getDeviceContext()); mTouchButtonAccumulator.reset(); mMscTimestamp = 0; + + mButtonState = 0; return InputMapper::reset(when); } std::list<NotifyArgs> TouchpadInputMapper::process(const RawEvent* rawEvent) { + std::list<NotifyArgs> out = {}; if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); + out = sync(rawEvent->when, rawEvent->readTime); } if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) { mMscTimestamp = rawEvent->value; @@ -124,10 +158,10 @@ std::list<NotifyArgs> TouchpadInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mMotionAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); - return {}; + return out; } -void TouchpadInputMapper::sync(nsecs_t when) { +std::list<NotifyArgs> TouchpadInputMapper::sync(nsecs_t when, nsecs_t readTime) { HardwareState hwState; // The gestures library uses doubles to represent timestamps in seconds. hwState.timestamp = std::chrono::duration<stime_t>(std::chrono::nanoseconds(when)).count(); @@ -172,9 +206,160 @@ void TouchpadInputMapper::sync(nsecs_t when) { hwState.finger_cnt = fingers.size(); hwState.touch_cnt = mTouchButtonAccumulator.getTouchCount(); + mProcessing = true; mGestureInterpreter->PushHardwareState(&hwState); + mProcessing = false; + + std::list<NotifyArgs> out = processGestures(when, readTime); + mMotionAccumulator.finishSync(); mMscTimestamp = 0; + return out; +} + +void TouchpadInputMapper::consumeGesture(const Gesture* gesture) { + ALOGD("Gesture ready: %s", gesture->String().c_str()); + if (!mProcessing) { + ALOGE("Received gesture outside of the normal processing flow; ignoring it."); + return; + } + mGesturesToProcess.push_back(*gesture); +} + +std::list<NotifyArgs> TouchpadInputMapper::processGestures(nsecs_t when, nsecs_t readTime) { + std::list<NotifyArgs> out = {}; + for (Gesture& gesture : mGesturesToProcess) { + switch (gesture.type) { + case kGestureTypeMove: + out.push_back(handleMove(when, readTime, gesture)); + break; + case kGestureTypeButtonsChange: + out += handleButtonsChange(when, readTime, gesture); + break; + default: + // TODO(b/251196347): handle more gesture types. + break; + } + } + mGesturesToProcess.clear(); + return out; +} + +NotifyArgs TouchpadInputMapper::handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture) { + PointerProperties props; + props.clear(); + props.id = 0; + props.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + + mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); + mPointerController->move(gesture.details.move.dx, gesture.details.move.dy); + mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE); + float xCursorPosition, yCursorPosition; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + + PointerCoords coords; + coords.clear(); + coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); + coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); + coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, gesture.details.move.dx); + coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, gesture.details.move.dy); + const bool down = isPointerDown(mButtonState); + coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); + + const int32_t action = down ? AMOTION_EVENT_ACTION_MOVE : AMOTION_EVENT_ACTION_HOVER_MOVE; + return makeMotionArgs(when, readTime, action, /* actionButton= */ 0, mButtonState, + /* pointerCount= */ 1, &props, &coords, xCursorPosition, yCursorPosition); +} + +std::list<NotifyArgs> TouchpadInputMapper::handleButtonsChange(nsecs_t when, nsecs_t readTime, + const Gesture& gesture) { + std::list<NotifyArgs> out = {}; + + mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER); + mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE); + + PointerProperties props; + props.clear(); + props.id = 0; + props.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + + float xCursorPosition, yCursorPosition; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + + PointerCoords coords; + coords.clear(); + coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); + coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); + coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0); + coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0); + const uint32_t buttonsPressed = gesture.details.buttons.down; + bool pointerDown = isPointerDown(mButtonState) || + buttonsPressed & + (GESTURES_BUTTON_LEFT | GESTURES_BUTTON_MIDDLE | GESTURES_BUTTON_RIGHT); + coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerDown ? 1.0f : 0.0f); + + uint32_t newButtonState = mButtonState; + std::list<NotifyArgs> pressEvents = {}; + for (uint32_t button = 1; button <= GESTURES_BUTTON_FORWARD; button <<= 1) { + if (buttonsPressed & button) { + uint32_t actionButton = gesturesButtonToMotionEventButton(button); + newButtonState |= actionButton; + pressEvents.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_PRESS, + actionButton, newButtonState, + /* pointerCount= */ 1, &props, &coords, + xCursorPosition, yCursorPosition)); + } + } + if (!isPointerDown(mButtonState) && isPointerDown(newButtonState)) { + mDownTime = when; + out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN, + /* actionButton= */ 0, newButtonState, /* pointerCount= */ 1, + &props, &coords, xCursorPosition, yCursorPosition)); + } + out.splice(out.end(), pressEvents); + + // The same button may be in both down and up in the same gesture, in which case we should treat + // it as having gone down and then up. So, we treat a single button change gesture as two state + // changes: a set of buttons going down, followed by a set of buttons going up. + mButtonState = newButtonState; + + const uint32_t buttonsReleased = gesture.details.buttons.up; + for (uint32_t button = 1; button <= GESTURES_BUTTON_FORWARD; button <<= 1) { + if (buttonsReleased & button) { + uint32_t actionButton = gesturesButtonToMotionEventButton(button); + newButtonState &= ~actionButton; + out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_RELEASE, + actionButton, newButtonState, /* pointerCount= */ 1, + &props, &coords, xCursorPosition, yCursorPosition)); + } + } + if (isPointerDown(mButtonState) && !isPointerDown(newButtonState)) { + coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.0f); + out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /* actionButton= */ 0, + newButtonState, /* pointerCount= */ 1, &props, &coords, + xCursorPosition, yCursorPosition)); + } + mButtonState = newButtonState; + return out; +} + +NotifyMotionArgs TouchpadInputMapper::makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action, + int32_t actionButton, int32_t buttonState, + uint32_t pointerCount, + const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, + float xCursorPosition, float yCursorPosition) { + // TODO(b/260226362): consider what the appropriate source for these events is. + const uint32_t source = AINPUT_SOURCE_MOUSE; + + return NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), source, + mPointerController->getDisplayId(), /* policyFlags= */ 0, action, + /* actionButton= */ actionButton, /* flags= */ 0, + getContext()->getGlobalMetaState(), buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, + pointerProperties, pointerCoords, + /* xPrecision= */ 1.0f, /* yPrecision= */ 1.0f, xCursorPosition, + yCursorPosition, /* downTime= */ mDownTime, /* videoFrames= */ {}); } } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h index 9d3a4b3e0d..fe6b1fe759 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h @@ -18,6 +18,8 @@ #include <memory> +#include <PointerControllerInterface.h> + #include "EventHub.h" #include "InputDevice.h" #include "InputMapper.h" @@ -33,21 +35,44 @@ namespace android { class TouchpadInputMapper : public InputMapper { public: explicit TouchpadInputMapper(InputDeviceContext& deviceContext); + ~TouchpadInputMapper(); uint32_t getSources() const override; [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override; [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override; + void consumeGesture(const Gesture* gesture); + private: - void sync(nsecs_t when); + [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime); + [[nodiscard]] std::list<NotifyArgs> processGestures(nsecs_t when, nsecs_t readTime); + NotifyArgs handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture); + [[nodiscard]] std::list<NotifyArgs> handleButtonsChange(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, + uint32_t pointerCount, + const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, float xCursorPosition, + float yCursorPosition); std::unique_ptr<gestures::GestureInterpreter, void (*)(gestures::GestureInterpreter*)> mGestureInterpreter; + std::shared_ptr<PointerControllerInterface> mPointerController; CursorButtonAccumulator mCursorButtonAccumulator; MultiTouchMotionAccumulator mMotionAccumulator; TouchButtonAccumulator mTouchButtonAccumulator; int32_t mMscTimestamp = 0; + + bool mProcessing = false; + std::vector<Gesture> mGesturesToProcess; + + // The current button state according to the gestures library, but converted into MotionEvent + // button values (AMOTION_EVENT_BUTTON_...). + uint32_t mButtonState = 0; + nsecs_t mDownTime = 0; }; } // namespace android |