From 08e8ff371dccf1e678dd26310d5e2eb62c8c7e27 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Thu, 8 Jun 2023 09:26:48 +0300 Subject: [PATCH] Implement keyboard_get_label_from_physical method. --- doc/classes/DisplayServer.xml | 8 +++++ platform/linuxbsd/x11/display_server_x11.cpp | 24 +++++++++++++++ platform/linuxbsd/x11/display_server_x11.h | 1 + platform/macos/display_server_macos.h | 1 + platform/macos/display_server_macos.mm | 11 +++++++ platform/windows/display_server_windows.cpp | 32 ++++++++++++++++++++ platform/windows/display_server_windows.h | 1 + servers/display_server.cpp | 5 +++ servers/display_server.h | 1 + 9 files changed, 84 insertions(+) diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index c7df56230455..1419cd950988 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -775,6 +775,14 @@ [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows. + + + + + Converts a physical (US QWERTY) [param keycode] to localized label printed on the key in the active keyboard layout. + [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows. + + diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index eada0bf29e8d..84e2d05fde6a 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -2970,6 +2970,30 @@ Key DisplayServerX11::keyboard_get_keycode_from_physical(Key p_keycode) const { return (Key)(key | modifiers); } +Key DisplayServerX11::keyboard_get_label_from_physical(Key p_keycode) const { + Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK; + Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK; + unsigned int xkeycode = KeyMappingX11::get_xlibcode(keycode_no_mod); + KeySym xkeysym = XkbKeycodeToKeysym(x11_display, xkeycode, keyboard_get_current_layout(), 0); + if (is_ascii_lower_case(xkeysym)) { + xkeysym -= ('a' - 'A'); + } + + Key key = KeyMappingX11::get_keycode(xkeysym); +#ifdef XKB_ENABLED + if (xkb_loaded_v08p) { + String keysym = String::chr(xkb_keysym_to_utf32(xkb_keysym_to_upper(xkeysym))); + key = fix_key_label(keysym[0], KeyMappingX11::get_keycode(xkeysym)); + } +#endif + + // If not found, fallback to QWERTY. + // This should match the behavior of the event pump + if (key == Key::NONE) { + return p_keycode; + } + return (Key)(key | modifiers); +} DisplayServerX11::Property DisplayServerX11::_read_property(Display *p_display, Window p_window, Atom p_property) { Atom actual_type = None; int actual_format = 0; diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index fd3a5dccfaab..4cc60b0f634c 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -500,6 +500,7 @@ class DisplayServerX11 : public DisplayServer { virtual String keyboard_get_layout_language(int p_index) const override; virtual String keyboard_get_layout_name(int p_index) const override; virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override; + virtual Key keyboard_get_label_from_physical(Key p_keycode) const override; virtual void process_events() override; diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index 495dc43c55d5..cd88595db73b 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -430,6 +430,7 @@ class DisplayServerMacOS : public DisplayServer { virtual String keyboard_get_layout_language(int p_index) const override; virtual String keyboard_get_layout_name(int p_index) const override; virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override; + virtual Key keyboard_get_label_from_physical(Key p_keycode) const override; virtual void process_events() override; virtual void force_process_and_drop_events() override; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index c24115d70589..cc2d108ca043 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -3491,6 +3491,17 @@ return (Key)(KeyMappingMacOS::remap_key(macos_keycode, 0, false) | modifiers); } +Key DisplayServerMacOS::keyboard_get_label_from_physical(Key p_keycode) const { + if (p_keycode == Key::PAUSE || p_keycode == Key::NONE) { + return p_keycode; + } + + Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK; + Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK; + unsigned int macos_keycode = KeyMappingMacOS::unmap_key(keycode_no_mod); + return (Key)(KeyMappingMacOS::remap_key(macos_keycode, 0, true) | modifiers); +} + void DisplayServerMacOS::process_events() { _THREAD_SAFE_METHOD_ diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index f971846959e4..294590e3e4c0 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1998,6 +1998,38 @@ Key DisplayServerWindows::keyboard_get_keycode_from_physical(Key p_keycode) cons return (Key)(KeyMappingWindows::get_keysym(vk) | modifiers); } +Key DisplayServerWindows::keyboard_get_label_from_physical(Key p_keycode) const { + Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK; + Key keycode_no_mod = (Key)(p_keycode & KeyModifierMask::CODE_MASK); + + if (keycode_no_mod == Key::PRINT || + keycode_no_mod == Key::KP_ADD || + keycode_no_mod == Key::KP_5 || + (keycode_no_mod >= Key::KEY_0 && keycode_no_mod <= Key::KEY_9)) { + return p_keycode; + } + + unsigned int scancode = KeyMappingWindows::get_scancode(keycode_no_mod); + if (scancode == 0) { + return p_keycode; + } + + Key keycode = KeyMappingWindows::get_keysym(MapVirtualKey(scancode, MAPVK_VSC_TO_VK)); + + HKL current_layout = GetKeyboardLayout(0); + static BYTE keyboard_state[256]; + memset(keyboard_state, 0, 256); + wchar_t chars[256] = {}; + UINT extended_code = MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX); + if (ToUnicodeEx(extended_code, scancode, keyboard_state, chars, 255, 4, current_layout) > 0) { + String keysym = String::utf16((char16_t *)chars, 255); + if (!keysym.is_empty()) { + return fix_key_label(keysym[0], keycode) | modifiers; + } + } + return p_keycode; +} + String _get_full_layout_name_from_registry(HKL p_layout) { String id = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\" + String::num_int64((int64_t)p_layout, 16, false).lpad(8, "0"); String ret; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 4a1619f3310c..9acdd1ef0012 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -621,6 +621,7 @@ class DisplayServerWindows : public DisplayServer { virtual String keyboard_get_layout_language(int p_index) const override; virtual String keyboard_get_layout_name(int p_index) const override; virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override; + virtual Key keyboard_get_label_from_physical(Key p_keycode) const override; virtual int tablet_get_driver_count() const override; virtual String tablet_get_driver_name(int p_driver) const override; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 516f2f1be6b9..442c06fe705c 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -520,6 +520,10 @@ Key DisplayServer::keyboard_get_keycode_from_physical(Key p_keycode) const { ERR_FAIL_V_MSG(p_keycode, "Not supported by this display server."); } +Key DisplayServer::keyboard_get_label_from_physical(Key p_keycode) const { + ERR_FAIL_V_MSG(p_keycode, "Not supported by this display server."); +} + void DisplayServer::force_process_and_drop_events() { } @@ -756,6 +760,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("keyboard_get_layout_language", "index"), &DisplayServer::keyboard_get_layout_language); ClassDB::bind_method(D_METHOD("keyboard_get_layout_name", "index"), &DisplayServer::keyboard_get_layout_name); ClassDB::bind_method(D_METHOD("keyboard_get_keycode_from_physical", "keycode"), &DisplayServer::keyboard_get_keycode_from_physical); + ClassDB::bind_method(D_METHOD("keyboard_get_label_from_physical", "keycode"), &DisplayServer::keyboard_get_label_from_physical); ClassDB::bind_method(D_METHOD("process_events"), &DisplayServer::process_events); ClassDB::bind_method(D_METHOD("force_process_and_drop_events"), &DisplayServer::force_process_and_drop_events); diff --git a/servers/display_server.h b/servers/display_server.h index d8e67b4f9271..65b4843b3ac1 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -498,6 +498,7 @@ class DisplayServer : public Object { virtual String keyboard_get_layout_language(int p_index) const; virtual String keyboard_get_layout_name(int p_index) const; virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const; + virtual Key keyboard_get_label_from_physical(Key p_keycode) const; virtual int tablet_get_driver_count() const { return 1; }; virtual String tablet_get_driver_name(int p_driver) const { return "default"; };