Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8ff5e5ec authored by Biswarup Pal's avatar Biswarup Pal
Browse files

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
parent 9a87716c
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -195,6 +195,13 @@ static constexpr size_t MAX_POINTERS = 16;
 */
#define MAX_POINTER_ID 31

/*
 * Number of high resolution mouse scroll units for one detent (mouse wheel click), as defined in
 * evdev. This is relevant when an input device is emitting REL_WHEEL_HI_RES or REL_HWHEEL_HI_RES
 * events.
 */
constexpr int32_t kEvdevMouseHighResScrollUnitsPerDetent = 120;

/*
 * Declare a concrete type for the NDK's input event forward declaration.
 */
+2 −0
Original line number Diff line number Diff line
@@ -77,6 +77,8 @@ public:

private:
    static const std::map<int, int> BUTTON_CODE_MAPPING;
    int32_t mAccumulatedHighResScrollX;
    int32_t mAccumulatedHighResScrollY;
};

class VirtualTouchscreen : public VirtualInputDevice {
+1 −0
Original line number Diff line number Diff line
@@ -258,6 +258,7 @@ cc_library {
    ],

    shared_libs: [
        "android.companion.virtualdevice.flags-aconfig-cc-host",
        "libbase",
        "libbinder",
        "libbinder_ndk",
+44 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <android/input.h>
#include <android/keycodes.h>
#include <android_companion_virtualdevice_flags.h>
#include <fcntl.h>
#include <input/Input.h>
#include <input/VirtualInputDevice.h>
@@ -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<int, int> 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,11 +278,45 @@ bool VirtualMouse::writeRelativeEvent(float relativeX, float relativeY,

bool VirtualMouse::writeScrollEvent(float xAxisMovement, float yAxisMovement,
                                    std::chrono::nanoseconds 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 ---
const std::map<int, UinputAction> VirtualTouchscreen::TOUCH_ACTION_MAPPING = {
        {AMOTION_EVENT_ACTION_DOWN, UinputAction::PRESS},
+2 −1
Original line number Diff line number Diff line
@@ -78,7 +78,6 @@ cc_defaults {
    name: "libinputreader_defaults",
    srcs: [":libinputreader_sources"],
    shared_libs: [
        "android.companion.virtualdevice.flags-aconfig-cc-host",
        "libbase",
        "libcap",
        "libcrypto",
@@ -116,6 +115,7 @@ cc_library_static {
        "libinputreader_defaults",
    ],
    shared_libs: [
        "android.companion.virtualdevice.flags-aconfig-cc-host",
        "libinputflinger_base",
    ],
    export_header_lib_headers: [
@@ -141,6 +141,7 @@ cc_library_shared {
    shared_libs: [
        // This should consist only of dependencies from inputflinger. Other dependencies should be
        // in cc_defaults so that they are included in the tests.
        "android.companion.virtualdevice.flags-aconfig-cc-host",
        "libinputflinger_base",
        "libjsoncpp",
    ],
Loading