diff --git a/src/device_controller/keyboard/linux/keyboard_capturer.cpp b/src/device_controller/keyboard/linux/keyboard_capturer.cpp index 9da49e1..a5a7a74 100644 --- a/src/device_controller/keyboard/linux/keyboard_capturer.cpp +++ b/src/device_controller/keyboard/linux/keyboard_capturer.cpp @@ -6,6 +6,7 @@ #include "keyboard_converter.h" #include "platform.h" #include "rd_log.h" +#include "windows_key_metadata.h" namespace crossdesk { @@ -35,9 +36,12 @@ static int KeyboardEventHandler(Display* display, XEvent* event) { int key_code = key_it->second; bool is_key_down = (event->xkey.type == KeyPress); + uint32_t scan_code = 0; + bool extended = false; + LookupWindowsKeyMetadataFromVk(key_code, &scan_code, &extended); if (g_on_key_action) { - g_on_key_action(key_code, is_key_down, 0, false, g_user_ptr); + g_on_key_action(key_code, is_key_down, scan_code, extended, g_user_ptr); } } return 0; @@ -157,7 +161,9 @@ int KeyboardCapturer::SendKeyboardCommand(int key_code, bool is_down, use_wayland_portal_ = true; LOG_INFO("Keyboard controller initialized with Wayland portal backend"); } else { - LOG_WARN("Wayland keyboard control init failed, falling back to X11/XTest backend"); + LOG_WARN( + "Wayland keyboard control init failed, falling back to X11/XTest " + "backend"); } } diff --git a/src/device_controller/windows_key_metadata.h b/src/device_controller/windows_key_metadata.h new file mode 100644 index 0000000..5f4755e --- /dev/null +++ b/src/device_controller/windows_key_metadata.h @@ -0,0 +1,89 @@ +/* + * @Author: DI JUNKUN + * @Date: 2026-05-07 + * Copyright (c) 2026 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _WINDOWS_KEY_METADATA_H_ +#define _WINDOWS_KEY_METADATA_H_ + +#include + +namespace crossdesk { + +inline bool LookupWindowsKeyMetadataFromVk(int key_code, + uint32_t* scan_code_out, + bool* extended_out) { + if (scan_code_out == nullptr || extended_out == nullptr) { + return false; + } + + switch (key_code) { + case 0x21: // Page Up + *scan_code_out = 0x49; + *extended_out = true; + return true; + case 0x22: // Page Down + *scan_code_out = 0x51; + *extended_out = true; + return true; + case 0x23: // End + *scan_code_out = 0x4F; + *extended_out = true; + return true; + case 0x24: // Home + *scan_code_out = 0x47; + *extended_out = true; + return true; + case 0x25: // Left Arrow + *scan_code_out = 0x4B; + *extended_out = true; + return true; + case 0x26: // Up Arrow + *scan_code_out = 0x48; + *extended_out = true; + return true; + case 0x27: // Right Arrow + *scan_code_out = 0x4D; + *extended_out = true; + return true; + case 0x28: // Down Arrow + *scan_code_out = 0x50; + *extended_out = true; + return true; + case 0x2D: // Insert + *scan_code_out = 0x52; + *extended_out = true; + return true; + case 0x2E: // Delete + *scan_code_out = 0x53; + *extended_out = true; + return true; + case 0x6F: // Numpad / + *scan_code_out = 0x35; + *extended_out = true; + return true; + case 0xA3: // Right Ctrl + *scan_code_out = 0x1D; + *extended_out = true; + return true; + case 0xA5: // Right Alt + *scan_code_out = 0x38; + *extended_out = true; + return true; + case 0x5B: // Left Win + *scan_code_out = 0x5B; + *extended_out = true; + return true; + case 0x5C: // Right Win + *scan_code_out = 0x5C; + *extended_out = true; + return true; + default: + return false; + } +} + +} // namespace crossdesk + +#endif \ No newline at end of file diff --git a/src/gui/render_callback.cpp b/src/gui/render_callback.cpp index cec98cf..e6c75df 100644 --- a/src/gui/render_callback.cpp +++ b/src/gui/render_callback.cpp @@ -17,6 +17,7 @@ #include "platform.h" #include "rd_log.h" #include "render.h" +#include "windows_key_metadata.h" #if _WIN32 #include "interactive_state.h" #include "service_host.h" @@ -28,34 +29,66 @@ namespace crossdesk { namespace { -int TranslateSdlKeypadScancodeToVk(SDL_Scancode scancode) { - switch (scancode) { +int TranslateSdlKeypadScancodeToVk(const SDL_KeyboardEvent& event) { + const bool numlock_enabled = (event.mod & SDL_KMOD_NUM) != 0; + + switch (event.scancode) { case SDL_SCANCODE_NUMLOCKCLEAR: return 0x90; case SDL_SCANCODE_KP_ENTER: return 0x0D; case SDL_SCANCODE_KP_0: + if (!numlock_enabled) { + return 0x2D; + } return 0x60; case SDL_SCANCODE_KP_1: + if (!numlock_enabled) { + return 0x23; + } return 0x61; case SDL_SCANCODE_KP_2: + if (!numlock_enabled) { + return 0x28; + } return 0x62; case SDL_SCANCODE_KP_3: + if (!numlock_enabled) { + return 0x22; + } return 0x63; case SDL_SCANCODE_KP_4: + if (!numlock_enabled) { + return 0x25; + } return 0x64; case SDL_SCANCODE_KP_5: return 0x65; case SDL_SCANCODE_KP_6: + if (!numlock_enabled) { + return 0x27; + } return 0x66; case SDL_SCANCODE_KP_7: + if (!numlock_enabled) { + return 0x24; + } return 0x67; case SDL_SCANCODE_KP_8: + if (!numlock_enabled) { + return 0x26; + } return 0x68; case SDL_SCANCODE_KP_9: + if (!numlock_enabled) { + return 0x21; + } return 0x69; case SDL_SCANCODE_KP_PERIOD: case SDL_SCANCODE_KP_COMMA: + if (!numlock_enabled) { + return 0x2E; + } return 0x6E; case SDL_SCANCODE_KP_DIVIDE: return 0x6F; @@ -73,7 +106,7 @@ int TranslateSdlKeypadScancodeToVk(SDL_Scancode scancode) { } int TranslateSdlKeyboardEventToVk(const SDL_KeyboardEvent& event) { - const int keypad_key_code = TranslateSdlKeypadScancodeToVk(event.scancode); + const int keypad_key_code = TranslateSdlKeypadScancodeToVk(event); if (keypad_key_code >= 0) { return keypad_key_code; } @@ -200,9 +233,9 @@ int TranslateSdlKeyboardEventToVk(const SDL_KeyboardEvent& event) { } } -#if _WIN32 int NormalizeWindowsModifierVk(int key_code, uint32_t scan_code, bool extended) { +#if _WIN32 if (key_code != 0x10 && key_code != 0x11 && key_code != 0x12) { return key_code; } @@ -215,6 +248,11 @@ int NormalizeWindowsModifierVk(int key_code, uint32_t scan_code, const UINT normalized_vk = MapVirtualKeyW(scan_code_with_prefix, MAPVK_VSC_TO_VK_EX); return normalized_vk != 0 ? static_cast(normalized_vk) : key_code; +#else + (void)scan_code; + (void)extended; + return key_code; +#endif } void PopulateWindowsKeyMetadataFromVk(int key_code, uint32_t* scan_code_out, @@ -223,16 +261,20 @@ void PopulateWindowsKeyMetadataFromVk(int key_code, uint32_t* scan_code_out, return; } +#if _WIN32 const UINT scan_code = MapVirtualKeyW(static_cast(key_code), MAPVK_VK_TO_VSC_EX); if (scan_code == 0) { + LookupWindowsKeyMetadataFromVk(key_code, scan_code_out, extended_out); return; } *scan_code_out = static_cast(scan_code & 0xFF); *extended_out = (scan_code & 0xFF00) != 0; -} +#else + LookupWindowsKeyMetadataFromVk(key_code, scan_code_out, extended_out); #endif +} #if _WIN32 constexpr uint32_t kSecureDesktopInputLogIntervalMs = 2000; @@ -397,10 +439,10 @@ int Render::SendKeyCommand(int key_code, bool is_down, uint32_t scan_code, remote_action.k.flag = KeyFlag::key_up; } -#if _WIN32 if (scan_code == 0) { PopulateWindowsKeyMetadataFromVk(key_code, &scan_code, &extended); } +#if _WIN32 key_code = NormalizeWindowsModifierVk(key_code, scan_code, extended); #endif