From 65624f4165971f44e3d4782358a0df6d89f5ae92 Mon Sep 17 00:00:00 2001 From: ABeltramo Date: Sat, 10 Feb 2024 10:24:54 +0000 Subject: [PATCH] refactor: better split between input library and Moonlight specific code --- cmake/FindLIBEVDEV.cmake | 35 ----- src/core/src/core/input.hpp | 29 +--- .../src/platforms/linux/uinput/CMakeLists.txt | 45 ++---- .../src/platforms/linux/uinput/joypad.cpp | 12 +- .../src/platforms/linux/uinput/keyboard.cpp | 29 ---- .../platforms/linux/uinput/touchscreen.cpp | 8 +- .../src/platforms/linux/uinput/trackpad.cpp | 8 +- .../src/platforms/linux/uinput/uinput.hpp | 22 --- src/moonlight-server/CMakeLists.txt | 10 +- .../control/input_handler.cpp | 51 +++++-- src/moonlight-server/platforms/input.hpp | 30 ++++ .../platforms/input_linux.cpp | 141 ++++++++++++++++++ tests/platforms/linux/input.cpp | 6 +- tests/platforms/linux/testLibinput.cpp | 20 +-- 14 files changed, 259 insertions(+), 187 deletions(-) delete mode 100644 cmake/FindLIBEVDEV.cmake create mode 100644 src/moonlight-server/platforms/input.hpp create mode 100644 src/moonlight-server/platforms/input_linux.cpp diff --git a/cmake/FindLIBEVDEV.cmake b/cmake/FindLIBEVDEV.cmake deleted file mode 100644 index 5a8ff7ed..00000000 --- a/cmake/FindLIBEVDEV.cmake +++ /dev/null @@ -1,35 +0,0 @@ -# Adapted from: https://github.com/jpd002/Play-Dependencies/blob/master/cmake-modules/FindLIBEVDEV.cmake -# Find freedesktop.org's libevdev headers and library -# This module defines the following variables: -# -# LIBEVDEV_FOUND - true if libevdev header and library was found -# LIBEVDEV_INCLUDE_DIR - include path for libevdev -# LIBEVDEV_LIBRARY - library path for libevdev -# - -find_package(PkgConfig) -pkg_check_modules(LIBEVDEV libevdev>=1.0) - -SET(LIBEVDEV_SEARCH_PATHS - /usr/local - /usr - ) - -FIND_PATH(LIBEVDEV_INCLUDE_DIR libevdev/libevdev.h - HINTS $ENV{EVDEVDIR} - PATH_SUFFIXES include/libevdev-1.0 include/ - PATHS ${EVDEV_SEARCH_PATHS} - ) - -FIND_LIBRARY(LIBEVDEV_LIBRARY - NAMES libevdev.a evdev - HINTS - $ENV{EVDEVDIR} - PATH_SUFFIXES ${PATH_SUFFIXES} - PATHS ${EVDEV_SEARCH_PATHS} - ) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LIBEVDEV REQUIRED_VARS LIBEVDEV_LIBRARY LIBEVDEV_INCLUDE_DIR) - -mark_as_advanced(LIBEVDEV_INCLUDE_DIR) \ No newline at end of file diff --git a/src/core/src/core/input.hpp b/src/core/src/core/input.hpp index 26d79757..6c70a000 100644 --- a/src/core/src/core/input.hpp +++ b/src/core/src/core/input.hpp @@ -4,8 +4,6 @@ #include #include #include -#include -#include #include #include #include @@ -130,8 +128,9 @@ class Trackpad : public VirtualDevice { * * @param finger_nr * @param pressure A value between 0 and 1 + * @param orientation A value between -90 and 90 */ - void place_finger(int finger_nr, float x, float y, float pressure); + void place_finger(int finger_nr, float x, float y, float pressure, int orientation); void release_finger(int finger_nr); @@ -166,7 +165,7 @@ class TouchScreen : public VirtualDevice { * @param finger_nr * @param pressure A value between 0 and 1 */ - void place_finger(int finger_nr, float x, float y, float pressure); + void place_finger(int finger_nr, float x, float y, float pressure, int orientation); void release_finger(int finger_nr); }; @@ -255,19 +254,6 @@ class Keyboard : public VirtualDevice { void press(short key_code); void release(short key_code); - - /** - * Here we receive a single UTF-8 encoded char at a time, - * the trick is to convert it to UTF-32 then send CTRL+SHIFT+U+ in order to produce any - * unicode character, see: https://en.wikipedia.org/wiki/Unicode_input - * - * ex: - * - when receiving UTF-8 [0xF0 0x9F 0x92 0xA9] (which is '💩') - * - we'll convert it to UTF-32 [0x1F4A9] - * - then type: CTRL+SHIFT+U+1F4A9 - * see the conversion at: https://www.compart.com/en/unicode/U+1F4A9 - */ - void paste_utf(const std::basic_string &utf32); }; /** @@ -363,14 +349,9 @@ class Joypad : public VirtualDevice { void set_on_rumble(const std::function &callback); /** - * @see: Trackpad->place_finger - */ - void touchpad_place_finger(int finger_nr, float x, float y, float pressure); - - /** - * @see: Trackpad->release_finger + * If the joypad has been created with the TOUCHPAD capability this will return the associated trackpad */ - void touchpad_release_finger(int finger_nr); + std::optional get_trackpad() const; enum MOTION_TYPE : uint8_t { ACCELERATION = 0x01, diff --git a/src/core/src/platforms/linux/uinput/CMakeLists.txt b/src/core/src/platforms/linux/uinput/CMakeLists.txt index ab94620c..37dfed57 100644 --- a/src/core/src/platforms/linux/uinput/CMakeLists.txt +++ b/src/core/src/platforms/linux/uinput/CMakeLists.txt @@ -5,42 +5,19 @@ file(GLOB PRIVATE_LIST SRCS *.cpp) add_library(wolf_uinput) add_library(wolf::uinput ALIAS wolf_uinput) -find_package(LIBEVDEV) -if (NOT (LIBEVDEV_FOUND)) - message(FATAL_ERROR "Please install libevdev: CMake will Exit") -endif () - -target_link_libraries(wolf_uinput PUBLIC evdev) -target_include_directories(wolf_uinput PUBLIC ${LIBEVDEV_INCLUDE_DIR}) - -pkg_check_modules(LIBUDEV REQUIRED libudev) -target_link_libraries(wolf_uinput PUBLIC ${LIBUDEV_LIBRARIES}) -target_include_directories(wolf_uinput PUBLIC ${LIBUDEV_INCLUDE_DIR}) - - -message(STATUS "Adding input implementation for LINUX") +target_include_directories(wolf_uinput PRIVATE ../../../) -find_package(ICU 61.0 COMPONENTS uc REQUIRED) -target_link_libraries_system(wolf_uinput PRIVATE ICU::uc) +if (UNIX AND NOT APPLE) + find_package(PkgConfig) + pkg_check_modules(LIBEVDEV REQUIRED IMPORTED_TARGET libevdev) + target_link_libraries(wolf_uinput PUBLIC PkgConfig::LIBEVDEV) -target_include_directories(wolf_uinput PRIVATE ../../../) -target_sources(wolf_uinput - PUBLIC "keyboard.hpp" "uinput.hpp" - PRIVATE ${PRIVATE_LIST}) - -FetchContent_Declare( - immer - GIT_REPOSITORY https://github.com/arximboldi/immer.git - GIT_TAG e02cbd795e9424a8405a8cb01f659ad61c0cbbc7) -set(immer_BUILD_TESTS OFF) -set(immer_BUILD_EXAMPLES OFF) -set(immer_BUILD_DOCS OFF) -set(immer_BUILD_EXTRAS OFF) - -set(FPHSA_NAME_MISMATCHED on) # see: https://github.com/arximboldi/immer/issues/204 -FetchContent_MakeAvailable(immer) -target_link_libraries_system(wolf_uinput PUBLIC immer) -unset(FPHSA_NAME_MISMATCHED) + pkg_check_modules(LIBUDEV REQUIRED IMPORTED_TARGET libudev) + target_link_libraries(wolf_uinput PUBLIC PkgConfig::LIBUDEV) + target_sources(wolf_uinput + PUBLIC "keyboard.hpp" "uinput.hpp" + PRIVATE ${PRIVATE_LIST}) +endif () # We need this directory, and users of our library will need it too target_include_directories(wolf_uinput PUBLIC .) diff --git a/src/core/src/platforms/linux/uinput/joypad.cpp b/src/core/src/platforms/linux/uinput/joypad.cpp index 5b4391f3..d6bcfb27 100644 --- a/src/core/src/platforms/linux/uinput/joypad.cpp +++ b/src/core/src/platforms/linux/uinput/joypad.cpp @@ -768,16 +768,8 @@ void Joypad::set_on_led(const std::function &callback this->_state->on_led = callback; } -void Joypad::touchpad_place_finger(int finger_nr, float x, float y, float pressure) { - if (auto touchpad = this->_state->trackpad) { - touchpad->place_finger(finger_nr, x, y, pressure); - } -} - -void Joypad::touchpad_release_finger(int finger_nr) { - if (auto touchpad = this->_state->trackpad) { - touchpad->release_finger(finger_nr); - } +std::optional Joypad::get_trackpad() const { + return this->_state->trackpad; } } // namespace wolf::core::input \ No newline at end of file diff --git a/src/core/src/platforms/linux/uinput/keyboard.cpp b/src/core/src/platforms/linux/uinput/keyboard.cpp index 48a77720..2c3473c2 100644 --- a/src/core/src/platforms/linux/uinput/keyboard.cpp +++ b/src/core/src/platforms/linux/uinput/keyboard.cpp @@ -148,34 +148,5 @@ void Keyboard::release(short key_code) { } } -static void keyboard_ev(libevdev_uinput *keyboard, int linux_code, int event_code = 1) { - libevdev_uinput_write_event(keyboard, EV_KEY, linux_code, event_code); - libevdev_uinput_write_event(keyboard, EV_SYN, SYN_REPORT, 0); -} - -void Keyboard::paste_utf(const std::basic_string &utf32) { - /* To HEX string */ - auto hex_unicode = to_hex(utf32); - logs::log(logs::debug, "[INPUT] Typing U+{}", hex_unicode); - - keyboard_ev(this->_state->kb.get(), KEY_LEFTCTRL, 1); - keyboard_ev(this->_state->kb.get(), KEY_LEFTSHIFT, 1); - keyboard_ev(this->_state->kb.get(), KEY_U, 1); - keyboard_ev(this->_state->kb.get(), KEY_U, 0); - - for (auto &ch : hex_unicode) { - auto key_str = "KEY_"s + ch; - auto keycode = libevdev_event_code_from_name(EV_KEY, key_str.c_str()); - if (keycode == -1) { - logs::log(logs::warning, "[INPUT] Unable to find keycode for: {}", ch); - } else { - keyboard_ev(this->_state->kb.get(), keycode, 1); - keyboard_ev(this->_state->kb.get(), keycode, 0); - } - } - - keyboard_ev(this->_state->kb.get(), KEY_LEFTSHIFT, 0); - keyboard_ev(this->_state->kb.get(), KEY_LEFTCTRL, 0); -} } // namespace wolf::core::input \ No newline at end of file diff --git a/src/core/src/platforms/linux/uinput/touchscreen.cpp b/src/core/src/platforms/linux/uinput/touchscreen.cpp index 5f030f19..abec3239 100644 --- a/src/core/src/platforms/linux/uinput/touchscreen.cpp +++ b/src/core/src/platforms/linux/uinput/touchscreen.cpp @@ -132,10 +132,11 @@ TouchScreen::TouchScreen() { } } TouchScreen::~TouchScreen() {} -void TouchScreen::place_finger(int finger_nr, float x, float y, float pressure) { +void TouchScreen::place_finger(int finger_nr, float x, float y, float pressure, int orientation) { if (auto ts = this->_state->touch_screen.get()) { int scaled_x = (int)std::lround(TOUCH_MAX_X * x); int scaled_y = (int)std::lround(TOUCH_MAX_Y * y); + int scaled_orientation = std::clamp(orientation, -90, 90); if (_state->fingers.find(finger_nr) == _state->fingers.end()) { // Wow, a wild finger appeared! @@ -156,8 +157,9 @@ void TouchScreen::place_finger(int finger_nr, float x, float y, float pressure) libevdev_uinput_write_event(ts, EV_ABS, ABS_MT_POSITION_X, scaled_x); libevdev_uinput_write_event(ts, EV_ABS, ABS_Y, scaled_y); libevdev_uinput_write_event(ts, EV_ABS, ABS_MT_POSITION_Y, scaled_y); - libevdev_uinput_write_event(ts, EV_ABS, ABS_PRESSURE, (int)std::lround(pressure * PRESSURE_MAX)); - libevdev_uinput_write_event(ts, EV_ABS, ABS_MT_PRESSURE, (int)std::lround(pressure * PRESSURE_MAX)); + libevdev_uinput_write_event(ts, EV_ABS, ABS_PRESSURE, (int) std::lround(pressure * PRESSURE_MAX)); + libevdev_uinput_write_event(ts, EV_ABS, ABS_MT_PRESSURE, (int) std::lround(pressure * PRESSURE_MAX)); + libevdev_uinput_write_event(ts, EV_ABS, ABS_MT_ORIENTATION, scaled_orientation); libevdev_uinput_write_event(ts, EV_SYN, SYN_REPORT, 0); } diff --git a/src/core/src/platforms/linux/uinput/trackpad.cpp b/src/core/src/platforms/linux/uinput/trackpad.cpp index 2786118f..9521c201 100644 --- a/src/core/src/platforms/linux/uinput/trackpad.cpp +++ b/src/core/src/platforms/linux/uinput/trackpad.cpp @@ -116,8 +116,8 @@ std::optional create_trackpad() { // input_absinfo touch{0, 0, TOUCH_MAX, 4, 0, 0}; // libevdev_enable_event_code(dev, EV_ABS, ABS_MT_TOUCH_MAJOR, &touch); // libevdev_enable_event_code(dev, EV_ABS, ABS_MT_TOUCH_MINOR, &touch); - // input_absinfo orientation{0, -3, 4, 0, 0, 0}; - // libevdev_enable_event_code(dev, EV_ABS, ABS_MT_ORIENTATION, &orientation); + input_absinfo orientation{0, -90, 90, 0, 0, 0}; + libevdev_enable_event_code(dev, EV_ABS, ABS_MT_ORIENTATION, &orientation); // https://docs.kernel.org/input/event-codes.html#trackpads libevdev_enable_property(dev, INPUT_PROP_POINTER); @@ -143,10 +143,11 @@ Trackpad::Trackpad() { Trackpad::~Trackpad() {} -void Trackpad::place_finger(int finger_nr, float x, float y, float pressure) { +void Trackpad::place_finger(int finger_nr, float x, float y, float pressure, int orientation) { if (auto touchpad = this->_state->trackpad.get()) { int scaled_x = (int)std::lround(TOUCH_MAX_X * x); int scaled_y = (int)std::lround(TOUCH_MAX_Y * y); + int scaled_orientation = std::clamp(orientation, -90, 90); if (_state->fingers.find(finger_nr) == _state->fingers.end()) { // Wow, a wild finger appeared! @@ -188,6 +189,7 @@ void Trackpad::place_finger(int finger_nr, float x, float y, float pressure) { libevdev_uinput_write_event(touchpad, EV_ABS, ABS_MT_POSITION_Y, scaled_y); libevdev_uinput_write_event(touchpad, EV_ABS, ABS_PRESSURE, (int)std::lround(pressure * PRESSURE_MAX)); libevdev_uinput_write_event(touchpad, EV_ABS, ABS_MT_PRESSURE, (int)std::lround(pressure * PRESSURE_MAX)); + libevdev_uinput_write_event(touchpad, EV_ABS, ABS_MT_ORIENTATION, scaled_orientation); libevdev_uinput_write_event(touchpad, EV_SYN, SYN_REPORT, 0); } diff --git a/src/core/src/platforms/linux/uinput/uinput.hpp b/src/core/src/platforms/linux/uinput/uinput.hpp index aabf2a46..4d9e1f19 100644 --- a/src/core/src/platforms/linux/uinput/uinput.hpp +++ b/src/core/src/platforms/linux/uinput/uinput.hpp @@ -23,9 +23,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -54,25 +51,6 @@ std::vector fetch_events(const libevdev_ptr &dev, int max_ev */ std::vector fetch_events(int uinput_fd, int max_events = 50); -/** - * Takes an UTF-32 encoded string and returns a hex string representation of the bytes (uppercase) - * - * ex: ['💩'] = "1F4A9" // see UTF encoding at https://www.compart.com/en/unicode/U+1F4A9 - * - * adapted from: https://stackoverflow.com/a/7639754 - */ -static std::string to_hex(const std::basic_string &str) { - std::stringstream ss; - ss << std::hex << std::setfill('0'); - for (const auto &ch : str) { - ss << ch; - } - - std::string hex_unicode(ss.str()); - std::transform(hex_unicode.begin(), hex_unicode.end(), hex_unicode.begin(), ::toupper); - return hex_unicode; -} - static std::pair get_major_minor(const std::string &devnode) { struct stat buf {}; if (stat(devnode.c_str(), &buf) == -1) { diff --git a/src/moonlight-server/CMakeLists.txt b/src/moonlight-server/CMakeLists.txt index 7cd9e2ef..3baf07ac 100644 --- a/src/moonlight-server/CMakeLists.txt +++ b/src/moonlight-server/CMakeLists.txt @@ -58,7 +58,7 @@ FetchContent_Declare( ) find_package(PkgConfig) pkg_check_modules(LIBUNWIND QUIET libunwind) -if(LIBUNWIND_FOUND) +if (LIBUNWIND_FOUND) set(CPPTRACE_UNWIND_WITH_LIBUNWIND ON) else () message(WARNING "Missing libunwind, stacktraces will not be available.") @@ -70,7 +70,7 @@ FetchContent_MakeAvailable(cpptrace) find_package(Threads REQUIRED) find_package(OpenSSL REQUIRED) -find_package(Boost REQUIRED COMPONENTS log) +find_package(Boost REQUIRED COMPONENTS log locale) include_directories(${Boost_INCLUDE_DIRS}) target_link_libraries( @@ -97,6 +97,12 @@ file(GLOB SRC_LIST SRCS streaming/*.cpp) if (UNIX AND NOT APPLE) + message(STATUS "Adding input implementation for LINUX") + + find_package(ICU 61.0 COMPONENTS uc REQUIRED) # brought by libboost-locale-dev + target_link_libraries_system(wolf_runner PRIVATE ICU::uc) + + list(APPEND SRC_LIST platforms/input_linux.cpp) pkg_check_modules(LIBDRM IMPORTED_TARGET libdrm) pkg_check_modules(LIBPCI IMPORTED_TARGET libpci) diff --git a/src/moonlight-server/control/input_handler.cpp b/src/moonlight-server/control/input_handler.cpp index c89e1424..159dcd06 100644 --- a/src/moonlight-server/control/input_handler.cpp +++ b/src/moonlight-server/control/input_handler.cpp @@ -3,8 +3,8 @@ #include #include #include -#include #include +#include namespace control { @@ -95,7 +95,7 @@ float netfloat_to_0_1(const utils::netfloat &f) { } static inline float deg2rad(float degree) { - return M_PI * degree / 180.0; + return degree * (M_PI / 180.f); } void handle_input(state::StreamSession &session, @@ -183,13 +183,23 @@ void handle_input(state::StreamSession &session, } case UTF8_TEXT: { logs::log(logs::trace, "[INPUT] Received input of type: UTF8_TEXT"); + /* Here we receive a single UTF-8 encoded char at a time, + * the trick is to convert it to UTF-32 then send CTRL+SHIFT+U+ in order to produce any + * unicode character, see: https://en.wikipedia.org/wiki/Unicode_input + * + * ex: + * - when receiving UTF-8 [0xF0 0x9F 0x92 0xA9] (which is '💩') + * - we'll convert it to UTF-32 [0x1F4A9] + * - then type: CTRL+SHIFT+U+1F4A9 + * see the conversion at: https://www.compart.com/en/unicode/U+1F4A9 + */ auto txt_pkt = static_cast(pkt); auto size = boost::endian::big_to_native(txt_pkt->data_size) - sizeof(txt_pkt->packet_type) - 2; /* Reading input text as UTF-8 */ auto utf8 = boost::locale::conv::to_utf(txt_pkt->text, txt_pkt->text + size, "UTF-8"); /* Converting to UTF-32 */ auto utf32 = boost::locale::conv::utf_to_utf(utf8); - session.keyboard->paste_utf(utf32); + wolf::platforms::input::paste_utf(session.keyboard, utf32); break; } case TOUCH: { @@ -206,9 +216,24 @@ void handle_input(state::StreamSession &session, switch (touch_pkt->event_type) { case pkts::TOUCH_EVENT_HOVER: case pkts::TOUCH_EVENT_DOWN: - case pkts::TOUCH_EVENT_MOVE: - session.touch_screen->place_finger(finger_id, x, y, pressure_or_distance); + case pkts::TOUCH_EVENT_MOVE: { + // Convert our 0..360 range to -90..90 relative to Y axis + int adjusted_angle = touch_pkt->rotation; + + if (adjusted_angle > 90 && adjusted_angle < 270) { + // Lower hemisphere + adjusted_angle = 180 - adjusted_angle; + } + + // Wrap the value if it's out of range + if (adjusted_angle > 90) { + adjusted_angle -= 360; + } else if (adjusted_angle < -90) { + adjusted_angle += 360; + } + session.touch_screen->place_finger(finger_id, x, y, pressure_or_distance, adjusted_angle); break; + } case pkts::TOUCH_EVENT_UP: case pkts::TOUCH_EVENT_HOVER_LEAVE: case pkts::TOUCH_EVENT_CANCEL: @@ -345,18 +370,20 @@ void handle_input(state::StreamSession &session, case TOUCH_EVENT_MOVE: { // TODO: Moonlight seems to always pass 1.0 (0x0000803f little endian) // Values too high will be discarded by libinput as detecting palm pressure - auto pressure = std::clamp(utils::from_netfloat(touch_pkt->pressure), 0.0f, 0.5f); - selected_pad->touchpad_place_finger(pointer_id, - netfloat_to_0_1(touch_pkt->x), - netfloat_to_0_1(touch_pkt->y), - pressure); + if (auto trackpad = selected_pad->get_trackpad()) { + auto pressure = std::clamp(utils::from_netfloat(touch_pkt->pressure), 0.0f, 0.5f); + trackpad->place_finger(pointer_id, netfloat_to_0_1(touch_pkt->x), netfloat_to_0_1(touch_pkt->y), pressure, 0); + } break; } case TOUCH_EVENT_UP: case TOUCH_EVENT_HOVER_LEAVE: - case TOUCH_EVENT_CANCEL: - selected_pad->touchpad_release_finger(pointer_id); + case TOUCH_EVENT_CANCEL: { + if (auto trackpad = selected_pad->get_trackpad()) { + trackpad->release_finger(pointer_id); + } break; + } case TOUCH_EVENT_CANCEL_ALL: logs::log(logs::warning, "Received TOUCH_EVENT_CANCEL_ALL which isn't supported"); break; // TODO: remove all fingers diff --git a/src/moonlight-server/platforms/input.hpp b/src/moonlight-server/platforms/input.hpp new file mode 100644 index 00000000..38e83198 --- /dev/null +++ b/src/moonlight-server/platforms/input.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace wolf::platforms::input { +/** + * Takes an UTF-32 encoded string and returns a hex string representation of the bytes (uppercase) + * + * ex: ['💩'] = "1F4A9" // see UTF encoding at https://www.compart.com/en/unicode/U+1F4A9 + * + * adapted from: https://stackoverflow.com/a/7639754 + */ +static std::string to_hex(const std::basic_string &str) { + std::stringstream ss; + ss << std::hex << std::setfill('0'); + for (const auto &ch : str) { + ss << ch; + } + + std::string hex_unicode(ss.str()); + std::transform(hex_unicode.begin(), hex_unicode.end(), hex_unicode.begin(), ::toupper); + return hex_unicode; +} + +void paste_utf(std::shared_ptr keyboard, const std::basic_string &utf32); +} // namespace wolf::platforms::input \ No newline at end of file diff --git a/src/moonlight-server/platforms/input_linux.cpp b/src/moonlight-server/platforms/input_linux.cpp new file mode 100644 index 00000000..51f9132d --- /dev/null +++ b/src/moonlight-server/platforms/input_linux.cpp @@ -0,0 +1,141 @@ +#include "input.hpp" +#include +#include +#include + +namespace wolf::platforms::input { +using namespace std::string_literals; + +/** + * A map of linux scan code -> Moonlight keyboard code + */ +static const std::map key_mappings = {{KEY_BACKSPACE, 0x08}, + {KEY_TAB, 0x09}, + {KEY_ENTER, 0x0D}, + {KEY_LEFTSHIFT, 0x10}, + {KEY_LEFTCTRL, 0x11}, + {KEY_CAPSLOCK, 0x14}, + {KEY_ESC, 0x1B}, + {KEY_SPACE, 0x20}, + {KEY_PAGEUP, 0x21}, + {KEY_PAGEDOWN, 0x22}, + {KEY_END, 0x23}, + {KEY_HOME, 0x24}, + {KEY_LEFT, 0x25}, + {KEY_UP, 0x26}, + {KEY_RIGHT, 0x27}, + {KEY_DOWN, 0x28}, + {KEY_SYSRQ, 0x2C}, + {KEY_INSERT, 0x2D}, + {KEY_DELETE, 0x2E}, + {KEY_0, 0x30}, + {KEY_1, 0x31}, + {KEY_2, 0x32}, + {KEY_3, 0x33}, + {KEY_4, 0x34}, + {KEY_5, 0x35}, + {KEY_6, 0x36}, + {KEY_7, 0x37}, + {KEY_8, 0x38}, + {KEY_9, 0x39}, + {KEY_A, 0x41}, + {KEY_B, 0x42}, + {KEY_C, 0x43}, + {KEY_D, 0x44}, + {KEY_E, 0x45}, + {KEY_F, 0x46}, + {KEY_G, 0x47}, + {KEY_H, 0x48}, + {KEY_I, 0x49}, + {KEY_J, 0x4A}, + {KEY_K, 0x4B}, + {KEY_L, 0x4C}, + {KEY_M, 0x4D}, + {KEY_N, 0x4E}, + {KEY_O, 0x4F}, + {KEY_P, 0x50}, + {KEY_Q, 0x51}, + {KEY_R, 0x52}, + {KEY_S, 0x53}, + {KEY_T, 0x54}, + {KEY_U, 0x55}, + {KEY_V, 0x56}, + {KEY_W, 0x57}, + {KEY_X, 0x58}, + {KEY_Y, 0x59}, + {KEY_Z, 0x5A}, + {KEY_LEFTMETA, 0x5B}, + {KEY_RIGHTMETA, 0x5C}, + {KEY_KP0, 0x60}, + {KEY_KP1, 0x61}, + {KEY_KP2, 0x62}, + {KEY_KP3, 0x63}, + {KEY_KP4, 0x64}, + {KEY_KP5, 0x65}, + {KEY_KP6, 0x66}, + {KEY_KP7, 0x67}, + {KEY_KP8, 0x68}, + {KEY_KP9, 0x69}, + {KEY_KPASTERISK, 0x6A}, + {KEY_KPPLUS, 0x6B}, + {KEY_KPMINUS, 0x6D}, + {KEY_KPDOT, 0x6E}, + {KEY_KPSLASH, 0x6F}, + {KEY_F1, 0x70}, + {KEY_F2, 0x71}, + {KEY_F3, 0x72}, + {KEY_F4, 0x73}, + {KEY_F5, 0x74}, + {KEY_F6, 0x75}, + {KEY_F7, 0x76}, + {KEY_F8, 0x77}, + {KEY_F9, 0x78}, + {KEY_F10, 0x79}, + {KEY_F11, 0x7A}, + {KEY_F12, 0x7B}, + {KEY_NUMLOCK, 0x90}, + {KEY_SCROLLLOCK, 0x91}, + {KEY_LEFTSHIFT, 0xA0}, + {KEY_RIGHTSHIFT, 0xA1}, + {KEY_LEFTCTRL, 0xA2}, + {KEY_RIGHTCTRL, 0xA3}, + {KEY_LEFTALT, 0xA4}, + {KEY_RIGHTALT, 0xA5}, + {KEY_SEMICOLON, 0xBA}, + {KEY_EQUAL, 0xBB}, + {KEY_COMMA, 0xBC}, + {KEY_MINUS, 0xBD}, + {KEY_DOT, 0xBE}, + {KEY_SLASH, 0xBF}, + {KEY_GRAVE, 0xC0}, + {KEY_LEFTBRACE, 0xDB}, + {KEY_BACKSLASH, 0xDC}, + {KEY_RIGHTBRACE, 0xDD}, + {KEY_APOSTROPHE, 0xDE}, + {KEY_102ND, 0xE2}}; + +void paste_utf(std::shared_ptr keyboard, const std::basic_string &utf32) { + /* To HEX string */ + auto hex_unicode = to_hex(utf32); + logs::log(logs::debug, "[INPUT] Typing U+{}", hex_unicode); + + keyboard->press(0xA2); // LEFTCTRL + keyboard->press(0xA0); // LEFTSHIFT + keyboard->press(0x55); // U + keyboard->release(0x55); // U + + for (auto &ch : hex_unicode) { + auto key_str = "KEY_"s + ch; + auto keycode = libevdev_event_code_from_name(EV_KEY, key_str.c_str()); + if (keycode == -1) { + logs::log(logs::warning, "[INPUT] Unable to find keycode for: {}", ch); + } else { + keyboard->press(key_mappings.at(keycode)); + keyboard->release(key_mappings.at(keycode)); + } + } + + keyboard->release(0xA0); // LEFTSHIFT + keyboard->release(0xA2); // LEFTCTRL +} +} // namespace wolf::platforms::input \ No newline at end of file diff --git a/tests/platforms/linux/input.cpp b/tests/platforms/linux/input.cpp index f711413e..77582edb 100644 --- a/tests/platforms/linux/input.cpp +++ b/tests/platforms/linux/input.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include @@ -505,14 +505,14 @@ TEST_CASE("uinput - paste UTF8", "UINPUT") { SECTION("UTF8 to HEX") { auto utf8 = boost::locale::conv::to_utf("\xF0\x9F\x92\xA9", "UTF-8"); // UTF-8 '💩' auto utf32 = boost::locale::conv::utf_to_utf(utf8); - REQUIRE_THAT(to_hex(utf32), Equals("1F4A9")); + REQUIRE_THAT(wolf::platforms::input::to_hex(utf32), Equals("1F4A9")); } SECTION("UTF16 to HEX") { char16_t payload[] = {0xD83D, 0xDCA9}; // UTF-16 '💩' auto utf16 = std::u16string(payload, 2); auto utf32 = boost::locale::conv::utf_to_utf(utf16); - REQUIRE_THAT(to_hex(utf32), Equals("1F4A9")); + REQUIRE_THAT(wolf::platforms::input::to_hex(utf32), Equals("1F4A9")); } SECTION("Paste UTF8") { diff --git a/tests/platforms/linux/testLibinput.cpp b/tests/platforms/linux/testLibinput.cpp index 71c8242a..58555f21 100644 --- a/tests/platforms/linux/testLibinput.cpp +++ b/tests/platforms/linux/testLibinput.cpp @@ -164,7 +164,7 @@ TEST_CASE("virtual touch screen", "[LIBINPUT]") { auto TARGET_WIDTH = 1920; auto TARGET_HEIGHT = 1080; { // Put down one finger - touch.place_finger(0, 0.1, 0.1, 0.3); + touch.place_finger(0, 0.1, 0.1, 0.3, 45); event = get_event(li); REQUIRE(libinput_event_get_type(event.get()) == LIBINPUT_EVENT_TOUCH_DOWN); auto t_event = libinput_event_get_touch_event(event.get()); @@ -176,7 +176,7 @@ TEST_CASE("virtual touch screen", "[LIBINPUT]") { } { // Add a second finger - touch.place_finger(1, 0.2, 0.2, 0.3); + touch.place_finger(1, 0.2, 0.2, 0.3, -45); event = get_event(li); REQUIRE(libinput_event_get_type(event.get()) == LIBINPUT_EVENT_TOUCH_DOWN); auto t_event = libinput_event_get_touch_event(event.get()); @@ -219,27 +219,27 @@ TEST_CASE("virtual trackpad", "[LIBINPUT]") { LIBINPUT_CONFIG_SEND_EVENTS_ENABLED); { // TODO: I can see things happening on the logs but for some fucking reason I can't get the events - trackpad.place_finger(0, 0.1, 0.1, 0.3); + trackpad.place_finger(0, 0.1, 0.1, 0.3, 0); event = get_event(li); - trackpad.place_finger(1, 0.2, 0.2, 0.3); + trackpad.place_finger(1, 0.2, 0.2, 0.3, 0); event = get_event(li); std::this_thread::sleep_for(10ms); - trackpad.place_finger(0, 0.1, 0.11, 0.3); + trackpad.place_finger(0, 0.1, 0.11, 0.3, 0); event = get_event(li); - trackpad.place_finger(1, 0.2, 0.21, 0.3); + trackpad.place_finger(1, 0.2, 0.21, 0.3, 0); event = get_event(li); std::this_thread::sleep_for(10ms); - trackpad.place_finger(0, 0.1, 0.12, 0.3); + trackpad.place_finger(0, 0.1, 0.12, 0.3, 0); event = get_event(li); - trackpad.place_finger(1, 0.2, 0.22, 0.3); + trackpad.place_finger(1, 0.2, 0.22, 0.3, 0); event = get_event(li); std::this_thread::sleep_for(10ms); - trackpad.place_finger(0, 0.1, 0.13, 0.3); + trackpad.place_finger(0, 0.1, 0.13, 0.3, 0); event = get_event(li); - trackpad.place_finger(1, 0.2, 0.23, 0.3); + trackpad.place_finger(1, 0.2, 0.23, 0.3, 0); event = get_event(li); std::this_thread::sleep_for(10ms);