From 4e04604696a93020226182cba17562def1890467 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 9 Apr 2023 11:55:03 -0500 Subject: [PATCH] Add support for keyboard input that is not normalized to US English layout This is used by the soft keyboards on Android and iOS --- src/input.cpp | 32 +++++++++++++++++++++++--------- src/platform/common.h | 2 +- src/platform/linux/input.cpp | 12 +++++++----- src/platform/macos/input.cpp | 2 +- src/platform/windows/input.cpp | 9 +++++---- 5 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index b0fc2791..381d3097 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -59,8 +59,22 @@ namespace input { gamepad_mask[id] = false; } + typedef uint32_t key_press_id_t; + key_press_id_t + make_kpid(uint16_t vk, uint8_t flags) { + return (key_press_id_t) vk << 8 | flags; + } + uint16_t + vk_from_kpid(key_press_id_t kpid) { + return kpid >> 8; + } + uint8_t + flags_from_kpid(key_press_id_t kpid) { + return kpid & 0xFF; + } + static task_pool_util::TaskPool::task_id_t key_press_repeat_id {}; - static std::unordered_map key_press {}; + static std::unordered_map key_press {}; static std::array mouse_press {}; static platf::input_t platf_input; @@ -449,16 +463,16 @@ namespace input { } void - repeat_key(short key_code) { + repeat_key(uint16_t key_code, uint8_t flags) { // If key no longer pressed, stop repeating - if (!key_press[key_code]) { + if (!key_press[make_kpid(key_code, flags)]) { key_press_repeat_id = nullptr; return; } - platf::keyboard(platf_input, map_keycode(key_code), false); + platf::keyboard(platf_input, map_keycode(key_code), false, flags); - key_press_repeat_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_period, key_code).task_id; + key_press_repeat_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_period, key_code, flags).task_id; } void @@ -470,7 +484,7 @@ namespace input { auto release = util::endian::little(packet->header.magic) == KEY_UP_EVENT_MAGIC; auto keyCode = packet->keyCode & 0x00FF; - auto &pressed = key_press[keyCode]; + auto &pressed = key_press[make_kpid(keyCode, packet->flags)]; if (!pressed) { if (!release) { // A new key has been pressed down, we need to check for key combo's @@ -484,7 +498,7 @@ namespace input { } if (config::input.key_repeat_delay.count() > 0) { - key_press_repeat_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_delay, keyCode).task_id; + key_press_repeat_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_delay, keyCode, packet->flags).task_id; } } else { @@ -500,7 +514,7 @@ namespace input { pressed = !release; update_shortcutFlags(&input->shortcutFlags, map_keycode(keyCode), release); - platf::keyboard(platf_input, map_keycode(keyCode), release); + platf::keyboard(platf_input, map_keycode(keyCode), release, packet->flags); } void @@ -731,7 +745,7 @@ namespace input { } for (auto &kp : key_press) { - platf::keyboard(platf_input, kp.first & 0x00FF, true); + platf::keyboard(platf_input, vk_from_kpid(kp.first) & 0x00FF, true, flags_from_kpid(kp.first)); key_press[kp.first] = false; } }); diff --git a/src/platform/common.h b/src/platform/common.h index e59d0a39..fa8104dc 100644 --- a/src/platform/common.h +++ b/src/platform/common.h @@ -436,7 +436,7 @@ namespace platf { void hscroll(input_t &input, int distance); void - keyboard(input_t &input, uint16_t modcode, bool release); + keyboard(input_t &input, uint16_t modcode, bool release, uint8_t flags); void gamepad(input_t &input, int nr, const gamepad_state_t &gamepad_state); void diff --git a/src/platform/linux/input.cpp b/src/platform/linux/input.cpp index 5749b307..9f277987 100644 --- a/src/platform/linux/input.cpp +++ b/src/platform/linux/input.cpp @@ -1337,14 +1337,15 @@ namespace platf { * @param input The input_t instance to use. * @param modcode The moonlight key code. * @param release Whether the event was a press (false) or a release (true) + * @param flags SS_KBE_FLAG_* values * * EXAMPLES: * ```cpp - * x_keyboard(input, 0x5A, false); // Press Z + * x_keyboard(input, 0x5A, false, 0); // Press Z * ``` */ static void - x_keyboard(input_t &input, uint16_t modcode, bool release) { + x_keyboard(input_t &input, uint16_t modcode, bool release, uint8_t flags) { #ifdef SUNSHINE_BUILD_X11 auto keycode = keysym(modcode); if (keycode.keysym == UNKNOWN) { @@ -1371,17 +1372,18 @@ namespace platf { * @param input The input_t instance to use. * @param modcode The moonlight key code. * @param release Whether the event was a press (false) or a release (true) + * @param flags SS_KBE_FLAG_* values * * EXAMPLES: * ```cpp - * keyboard(input, 0x5A, false); // Press Z + * keyboard(input, 0x5A, false, 0); // Press Z * ``` */ void - keyboard(input_t &input, uint16_t modcode, bool release) { + keyboard(input_t &input, uint16_t modcode, bool release, uint8_t flags) { auto keyboard = ((input_raw_t *) input.get())->keyboard_input.get(); if (!keyboard) { - x_keyboard(input, modcode, release); + x_keyboard(input, modcode, release, flags); return; } diff --git a/src/platform/macos/input.cpp b/src/platform/macos/input.cpp index 19948a95..7565351d 100644 --- a/src/platform/macos/input.cpp +++ b/src/platform/macos/input.cpp @@ -230,7 +230,7 @@ const KeyCodeMap kKeyCodesMap[] = { } void - keyboard(input_t &input, uint16_t modcode, bool release) { + keyboard(input_t &input, uint16_t modcode, bool release, uint8_t flags) { auto key = keysym(modcode); BOOST_LOG(debug) << "got keycode: 0x"sv << std::hex << modcode << ", translated to: 0x" << std::hex << key << ", release:" << release; diff --git a/src/platform/windows/input.cpp b/src/platform/windows/input.cpp index 69570f14..9c0372fe 100644 --- a/src/platform/windows/input.cpp +++ b/src/platform/windows/input.cpp @@ -338,15 +338,16 @@ namespace platf { } void - keyboard(input_t &input, uint16_t modcode, bool release) { + keyboard(input_t &input, uint16_t modcode, bool release, uint8_t flags) { auto raw = (input_raw_t *) input.get(); INPUT i {}; i.type = INPUT_KEYBOARD; auto &ki = i.ki; - // For some reason, MapVirtualKey(VK_LWIN, MAPVK_VK_TO_VSC) doesn't seem to work :/ - if (modcode != VK_LWIN && modcode != VK_RWIN && modcode != VK_PAUSE && raw->keyboard_layout != NULL) { + // If the client did not normalize this VK code to a US English layout, we can't accurately convert it to a scancode. + if (!(flags & SS_KBE_FLAG_NON_NORMALIZED) && modcode != VK_LWIN && modcode != VK_RWIN && modcode != VK_PAUSE && raw->keyboard_layout != NULL) { + // For some reason, MapVirtualKey(VK_LWIN, MAPVK_VK_TO_VSC) doesn't seem to work :/ ki.wScan = MapVirtualKeyEx(modcode, MAPVK_VK_TO_VSC, raw->keyboard_layout); } @@ -355,7 +356,7 @@ namespace platf { ki.dwFlags = KEYEVENTF_SCANCODE; } else { - // If there is no scancode mapping, send it as a regular VK event. + // If there is no scancode mapping or it's non-normalized, send it as a regular VK event. ki.wVk = modcode; }