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"; };