From 8ff5e5ecde93d80549208f25563f351da90a8dfc Mon Sep 17 00:00:00 2001 From: Biswarup Pal Date: Sat, 15 Jun 2024 12:58:20 +0000 Subject: Support high-resolution scroll VirtualMouse currently supports -1f to 1f float scroll values, but it worked for integer values only as input framework supported only REL_HWHEEL and REL_WHEEL events. With the introduction of high-res scroll event support (REL_HWHEEL_HI_RES and REL_WHEEL_HI_RES), granular mouse scrolling can be done, and VirtualMouse scroll API would work for all float values. Flag: android.companion.virtualdevice.flags.high_resolution_scroll Test: atest VirtualMouseTest Bug: 335160780 Change-Id: I7b13ac1722b6fd31736fe1c0117d4de6e838261a --- libs/input/VirtualInputDevice.cpp | 48 +++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'libs/input/VirtualInputDevice.cpp') diff --git a/libs/input/VirtualInputDevice.cpp b/libs/input/VirtualInputDevice.cpp index b73ee65504..2e3e1a09b8 100644 --- a/libs/input/VirtualInputDevice.cpp +++ b/libs/input/VirtualInputDevice.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,8 @@ static bool isDebug() { namespace android { +namespace vd_flags = android::companion::virtualdevice::flags; + VirtualInputDevice::VirtualInputDevice(unique_fd fd) : mFd(std::move(fd)) {} VirtualInputDevice::~VirtualInputDevice() { @@ -253,7 +256,10 @@ const std::map VirtualMouse::BUTTON_CODE_MAPPING = { // clang-format on }; -VirtualMouse::VirtualMouse(unique_fd fd) : VirtualInputDevice(std::move(fd)) {} +VirtualMouse::VirtualMouse(unique_fd fd) + : VirtualInputDevice(std::move(fd)), + mAccumulatedHighResScrollX(0), + mAccumulatedHighResScrollY(0) {} VirtualMouse::~VirtualMouse() {} @@ -272,9 +278,43 @@ bool VirtualMouse::writeRelativeEvent(float relativeX, float relativeY, bool VirtualMouse::writeScrollEvent(float xAxisMovement, float yAxisMovement, std::chrono::nanoseconds eventTime) { - return writeInputEvent(EV_REL, REL_HWHEEL, xAxisMovement, eventTime) && - writeInputEvent(EV_REL, REL_WHEEL, yAxisMovement, eventTime) && - writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime); + if (!vd_flags::high_resolution_scroll()) { + return writeInputEvent(EV_REL, REL_HWHEEL, xAxisMovement, eventTime) && + writeInputEvent(EV_REL, REL_WHEEL, yAxisMovement, eventTime) && + writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime); + } + + const int32_t highResScrollX = xAxisMovement * kEvdevMouseHighResScrollUnitsPerDetent; + const int32_t highResScrollY = yAxisMovement * kEvdevMouseHighResScrollUnitsPerDetent; + bool highResScrollResult = + writeInputEvent(EV_REL, REL_HWHEEL_HI_RES, highResScrollX, eventTime) && + writeInputEvent(EV_REL, REL_WHEEL_HI_RES, highResScrollY, eventTime); + if (!highResScrollResult) { + return false; + } + + // According to evdev spec, a high-resolution mouse needs to emit REL_WHEEL / REL_HWHEEL events + // in addition to high-res scroll events. Regular scroll events can approximate high-res scroll + // events, so we send a regular scroll event when the accumulated scroll motion reaches a detent + // (single mouse wheel click). + mAccumulatedHighResScrollX += highResScrollX; + mAccumulatedHighResScrollY += highResScrollY; + const int32_t scrollX = mAccumulatedHighResScrollX / kEvdevMouseHighResScrollUnitsPerDetent; + const int32_t scrollY = mAccumulatedHighResScrollY / kEvdevMouseHighResScrollUnitsPerDetent; + if (scrollX != 0) { + if (!writeInputEvent(EV_REL, REL_HWHEEL, scrollX, eventTime)) { + return false; + } + mAccumulatedHighResScrollX %= kEvdevMouseHighResScrollUnitsPerDetent; + } + if (scrollY != 0) { + if (!writeInputEvent(EV_REL, REL_WHEEL, scrollY, eventTime)) { + return false; + } + mAccumulatedHighResScrollY %= kEvdevMouseHighResScrollUnitsPerDetent; + } + + return writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime); } // --- VirtualTouchscreen --- -- cgit v1.2.3-59-g8ed1b