diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index b74dbdce5473..b09c81d806e2 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 bdb160e6a6ea..a7f947534227 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -2980,6 +2980,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 180362923ba3..70703d42c308 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -502,6 +502,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 93fa93b2592e..2a7b2ce2a9bd 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -433,6 +433,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 fb691c93eff7..a4db78b69731 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -3499,6 +3499,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 4ef6bf6cb114..f88cbd44b73f 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -2010,6 +2010,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 7228de7d317b..9d1088675b37 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -623,6 +623,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 41fa0d2d4770..313e7218ed6d 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() { } @@ -757,6 +761,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 fc8207f2d366..e6d9c51a679d 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -499,6 +499,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"; };