From 7d01b5049850b4e0b9f354e840ac3d2dc8fba6ec Mon Sep 17 00:00:00 2001 From: ABeltramo Date: Wed, 8 Mar 2023 13:35:34 +0000 Subject: [PATCH] feat: implemented unicode input mode (#966) Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> --- .github/workflows/CI.yml | 2 + CMakeLists.txt | 4 +- docker/debian-bullseye.dockerfile | 1 + docker/ubuntu-20.04.dockerfile | 1 + docker/ubuntu-22.04.dockerfile | 1 + docs/source/building/linux.rst | 3 + .../linux/flatpak/dev.lizardbyte.sunshine.yml | 2 +- src/platform/linux/input.cpp | 72 ++++++++++++++++++- 8 files changed, 83 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 4350b536..ae875749 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -281,6 +281,7 @@ jobs: sudo apt-get update -y sudo apt-get install -y \ libboost-filesystem1.71-dev \ + libboost-locale1.71-dev \ libboost-log1.71-dev \ libboost-regex1.71-dev \ libboost-thread1.71-dev \ @@ -307,6 +308,7 @@ jobs: sudo apt-get install -y \ cmake \ libboost-filesystem-dev \ + libboost-locale-dev \ libboost-log-dev \ libboost-thread-dev \ libboost-program-options-dev diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c9c0341..156c1e63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,7 @@ if(WIN32) set(Boost_NO_BOOST_CMAKE ON) # cmake-lint: disable=C0103 endif() -find_package(Boost COMPONENTS log filesystem program_options REQUIRED) +find_package(Boost COMPONENTS locale log filesystem program_options REQUIRED) list(APPEND SUNSHINE_COMPILE_OPTIONS -Wall -Wno-missing-braces -Wno-maybe-uninitialized -Wno-sign-compare) @@ -790,6 +790,7 @@ elseif(UNIX) set(CPACK_DEBIAN_PACKAGE_DEPENDS "\ ${CPACK_DEB_PLATFORM_PACKAGE_DEPENDS} \ libboost-filesystem${Boost_VERSION}, \ + libboost-locale${Boost_VERSION}, \ libboost-log${Boost_VERSION}, \ libboost-program-options${Boost_VERSION}, \ libboost-thread${Boost_VERSION}, \ @@ -809,6 +810,7 @@ elseif(UNIX) set(CPACK_RPM_PACKAGE_REQUIRES "\ ${CPACK_RPM_PLATFORM_PACKAGE_REQUIRES} \ boost-filesystem >= ${Boost_VERSION}, \ + boost-locale >= ${Boost_VERSION}, \ boost-log >= ${Boost_VERSION}, \ boost-program-options >= ${Boost_VERSION}, \ boost-thread >= ${Boost_VERSION}, \ diff --git a/docker/debian-bullseye.dockerfile b/docker/debian-bullseye.dockerfile index cc8416ad..3b7faed0 100644 --- a/docker/debian-bullseye.dockerfile +++ b/docker/debian-bullseye.dockerfile @@ -25,6 +25,7 @@ apt-get install -y --no-install-recommends \ cmake=3.18.4* \ libavdevice-dev=7:4.3.* \ libboost-filesystem-dev=1.74.0* \ + libboost-locale-dev=1.74.0* \ libboost-log-dev=1.74.0* \ libboost-program-options-dev=1.74.0* \ libboost-thread-dev=1.74.0* \ diff --git a/docker/ubuntu-20.04.dockerfile b/docker/ubuntu-20.04.dockerfile index 0f151e83..5012a025 100644 --- a/docker/ubuntu-20.04.dockerfile +++ b/docker/ubuntu-20.04.dockerfile @@ -26,6 +26,7 @@ apt-get install -y --no-install-recommends \ g++-10=10.3.0* \ libavdevice-dev=7:4.2.* \ libboost-filesystem-dev=1.71.0* \ + libboost-locale-dev=1.71.0* \ libboost-log-dev=1.71.0* \ libboost-program-options-dev=1.71.0* \ libboost-thread-dev=1.71.0* \ diff --git a/docker/ubuntu-22.04.dockerfile b/docker/ubuntu-22.04.dockerfile index b1378031..79aca5eb 100644 --- a/docker/ubuntu-22.04.dockerfile +++ b/docker/ubuntu-22.04.dockerfile @@ -25,6 +25,7 @@ apt-get install -y --no-install-recommends \ cmake=3.22.1* \ libavdevice-dev=7:4.4.* \ libboost-filesystem-dev=1.74.0* \ + libboost-locale-dev=1.74.0* \ libboost-log-dev=1.74.0* \ libboost-program-options-dev=1.74.0* \ libboost-thread-dev=1.74.0* \ diff --git a/docs/source/building/linux.rst b/docs/source/building/linux.rst index 2cb4970e..bf095de7 100644 --- a/docs/source/building/linux.rst +++ b/docs/source/building/linux.rst @@ -16,6 +16,7 @@ Install Requirements cmake \ libavdevice-dev \ libboost-filesystem-dev \ + libboost-locale-dev \ libboost-log-dev \ libboost-program-options-dev \ libboost-thread-dev \ @@ -95,6 +96,7 @@ Install Requirements g++-10 \ libavdevice-dev \ libboost-filesystem-dev \ + libboost-locale-dev \ libboost-log-dev \ libboost-thread-dev \ libboost-program-options-dev \ @@ -142,6 +144,7 @@ Install Requirements cmake \ libavdevice-dev \ libboost-filesystem-dev \ + libboost-locale-dev \ libboost-log-dev \ libboost-thread-dev \ libboost-program-options-dev \ diff --git a/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml b/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml index d7789a79..c8fd7df8 100644 --- a/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml +++ b/packaging/linux/flatpak/dev.lizardbyte.sunshine.yml @@ -33,7 +33,7 @@ modules: buildsystem: simple build-commands: - cd tools/build && bison -y -d -o src/engine/jamgram.cpp src/engine/jamgram.y - - ./bootstrap.sh --prefix=$FLATPAK_DEST --with-libraries=system,thread,log,program_options || cat bootstrap.log + - ./bootstrap.sh --prefix=$FLATPAK_DEST --with-libraries=locale,log,program_options,system,thread - ./b2 install variant=release link=shared runtime-link=shared cxxflags="$CXXFLAGS" linkflags="$LDFLAGS" -j $FLATPAK_BUILDER_N_JOBS sources: diff --git a/src/platform/linux/input.cpp b/src/platform/linux/input.cpp index c4585e1c..ecdcec37 100644 --- a/src/platform/linux/input.cpp +++ b/src/platform/linux/input.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -1024,8 +1025,77 @@ void keyboard(input_t &input, uint16_t modcode, bool release) { keycode.pressed = 1; } +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); +} + +/** + * Takes an UTF-32 encoded string and returns a hex string representation of the bytes (uppercase) + * + * ex: ['👱'] = "1F471" // see UTF encoding at https://www.compart.com/en/unicode/U+1F471 + * + * adapted from: https://stackoverflow.com/a/7639754 + */ +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; +} + +/** + * 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 0x91 0xB1] (which is '👱') + * - we'll convert it to UTF-32 [0x1F471] + * - then type: CTRL+SHIFT+U+1F471 + * see the conversion at: https://www.compart.com/en/unicode/U+1F471 + */ void unicode(input_t &input, char *utf8, int size) { - BOOST_LOG(info) << "unicode: Unicode input not yet implemented for Linux."sv; + auto kb = ((input_raw_t *)input.get())->keyboard_input.get(); + if(!kb) { + return; + } + + /* Reading input text as UTF-8 */ + auto utf8_str = boost::locale::conv::to_utf(utf8, utf8 + size, "UTF-8"); + /* Converting to UTF-32 */ + auto utf32_str = boost::locale::conv::utf_to_utf(utf8_str); + /* To HEX string */ + auto hex_unicode = to_hex(utf32_str); + BOOST_LOG(debug) << "Unicode, typing U+"sv << hex_unicode; + + /* pressing + + U */ + keyboard_ev(kb, KEY_LEFTCTRL, 1); + keyboard_ev(kb, KEY_LEFTSHIFT, 1); + keyboard_ev(kb, KEY_U, 1); + keyboard_ev(kb, KEY_U, 0); + + /* input each HEX character */ + 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) { + BOOST_LOG(warning) << "Unicode, unable to find keycode for: "sv << ch; + } + else { + keyboard_ev(kb, keycode, 1); + keyboard_ev(kb, keycode, 0); + } + } + + /* releasing and */ + keyboard_ev(kb, KEY_LEFTSHIFT, 0); + keyboard_ev(kb, KEY_LEFTCTRL, 0); } int alloc_gamepad(input_t &input, int nr, rumble_queue_t rumble_queue) {