diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index fc376f73e9b..9ee452ba289 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -573,6 +573,10 @@ String _OS::keyboard_get_layout_name(int p_index) const {
return OS::get_singleton()->keyboard_get_layout_name(p_index);
}
+uint32_t _OS::keyboard_get_scancode_from_physical(uint32_t p_scancode) const {
+ return OS::get_singleton()->keyboard_get_scancode_from_physical(p_scancode);
+}
+
String _OS::get_model_name() const {
return OS::get_singleton()->get_model_name();
}
@@ -1355,6 +1359,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("keyboard_set_current_layout", "index"), &_OS::keyboard_set_current_layout);
ClassDB::bind_method(D_METHOD("keyboard_get_layout_language", "index"), &_OS::keyboard_get_layout_language);
ClassDB::bind_method(D_METHOD("keyboard_get_layout_name", "index"), &_OS::keyboard_get_layout_name);
+ ClassDB::bind_method(D_METHOD("keyboard_get_scancode_from_physical", "scancode"), &_OS::keyboard_get_scancode_from_physical);
ClassDB::bind_method(D_METHOD("can_draw"), &_OS::can_draw);
ClassDB::bind_method(D_METHOD("is_userfs_persistent"), &_OS::is_userfs_persistent);
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 60b5fb61bc3..d2dcd570c8d 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -263,6 +263,7 @@ public:
void keyboard_set_current_layout(int p_index);
String keyboard_get_layout_language(int p_index) const;
String keyboard_get_layout_name(int p_index) const;
+ uint32_t keyboard_get_scancode_from_physical(uint32_t p_scancode) const;
String get_model_name() const;
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 709295aa3e6..bdac38412c6 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -215,6 +215,10 @@ int OS::get_virtual_keyboard_height() const {
return 0;
}
+uint32_t OS::keyboard_get_scancode_from_physical(uint32_t p_scancode) const {
+ return p_scancode;
+}
+
void OS::set_cursor_shape(CursorShape p_shape) {
}
diff --git a/core/os/os.h b/core/os/os.h
index 2370a5ec12b..e44710b452d 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -409,6 +409,7 @@ public:
// returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
virtual int get_virtual_keyboard_height() const;
+ virtual uint32_t keyboard_get_scancode_from_physical(uint32_t p_scancode) const;
virtual void set_cursor_shape(CursorShape p_shape);
virtual CursorShape get_cursor_shape() const;
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 85f41654244..8bcd88b4b04 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -711,6 +711,14 @@
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+
+
+
+
+ Converts a physical (US QWERTY) [code]scancode[/code] to one in the active keyboard layout.
+ [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+
+
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 53aa7c9184f..f31234a2527 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -264,6 +264,7 @@ public:
virtual void keyboard_set_current_layout(int p_index);
virtual String keyboard_get_layout_language(int p_index) const;
virtual String keyboard_get_layout_name(int p_index) const;
+ virtual uint32_t keyboard_get_scancode_from_physical(uint32_t p_scancode) const;
virtual void move_window_to_foreground();
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 4e51a62e6f0..b05370d5424 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -940,145 +940,154 @@ static bool isNumpadKey(unsigned int key) {
return false;
}
-// Translates a OS X keycode to a Godot keycode
-//
-static int translateKey(unsigned int key) {
- // Keyboard symbol translation table
- static const unsigned int table[128] = {
- /* 00 */ KEY_A,
- /* 01 */ KEY_S,
- /* 02 */ KEY_D,
- /* 03 */ KEY_F,
- /* 04 */ KEY_H,
- /* 05 */ KEY_G,
- /* 06 */ KEY_Z,
- /* 07 */ KEY_X,
- /* 08 */ KEY_C,
- /* 09 */ KEY_V,
- /* 0a */ KEY_SECTION, /* ISO Section */
- /* 0b */ KEY_B,
- /* 0c */ KEY_Q,
- /* 0d */ KEY_W,
- /* 0e */ KEY_E,
- /* 0f */ KEY_R,
- /* 10 */ KEY_Y,
- /* 11 */ KEY_T,
- /* 12 */ KEY_1,
- /* 13 */ KEY_2,
- /* 14 */ KEY_3,
- /* 15 */ KEY_4,
- /* 16 */ KEY_6,
- /* 17 */ KEY_5,
- /* 18 */ KEY_EQUAL,
- /* 19 */ KEY_9,
- /* 1a */ KEY_7,
- /* 1b */ KEY_MINUS,
- /* 1c */ KEY_8,
- /* 1d */ KEY_0,
- /* 1e */ KEY_BRACERIGHT,
- /* 1f */ KEY_O,
- /* 20 */ KEY_U,
- /* 21 */ KEY_BRACELEFT,
- /* 22 */ KEY_I,
- /* 23 */ KEY_P,
- /* 24 */ KEY_ENTER,
- /* 25 */ KEY_L,
- /* 26 */ KEY_J,
- /* 27 */ KEY_APOSTROPHE,
- /* 28 */ KEY_K,
- /* 29 */ KEY_SEMICOLON,
- /* 2a */ KEY_BACKSLASH,
- /* 2b */ KEY_COMMA,
- /* 2c */ KEY_SLASH,
- /* 2d */ KEY_N,
- /* 2e */ KEY_M,
- /* 2f */ KEY_PERIOD,
- /* 30 */ KEY_TAB,
- /* 31 */ KEY_SPACE,
- /* 32 */ KEY_QUOTELEFT,
- /* 33 */ KEY_BACKSPACE,
- /* 34 */ KEY_UNKNOWN,
- /* 35 */ KEY_ESCAPE,
- /* 36 */ KEY_META,
- /* 37 */ KEY_META,
- /* 38 */ KEY_SHIFT,
- /* 39 */ KEY_CAPSLOCK,
- /* 3a */ KEY_ALT,
- /* 3b */ KEY_CONTROL,
- /* 3c */ KEY_SHIFT,
- /* 3d */ KEY_ALT,
- /* 3e */ KEY_CONTROL,
- /* 3f */ KEY_UNKNOWN, /* Function */
- /* 40 */ KEY_UNKNOWN, /* F17 */
- /* 41 */ KEY_KP_PERIOD,
- /* 42 */ KEY_UNKNOWN,
- /* 43 */ KEY_KP_MULTIPLY,
- /* 44 */ KEY_UNKNOWN,
- /* 45 */ KEY_KP_ADD,
- /* 46 */ KEY_UNKNOWN,
- /* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */
- /* 48 */ KEY_VOLUMEUP, /* VolumeUp */
- /* 49 */ KEY_VOLUMEDOWN, /* VolumeDown */
- /* 4a */ KEY_VOLUMEMUTE, /* Mute */
- /* 4b */ KEY_KP_DIVIDE,
- /* 4c */ KEY_KP_ENTER,
- /* 4d */ KEY_UNKNOWN,
- /* 4e */ KEY_KP_SUBTRACT,
- /* 4f */ KEY_UNKNOWN, /* F18 */
- /* 50 */ KEY_UNKNOWN, /* F19 */
- /* 51 */ KEY_EQUAL, /* KeypadEqual */
- /* 52 */ KEY_KP_0,
- /* 53 */ KEY_KP_1,
- /* 54 */ KEY_KP_2,
- /* 55 */ KEY_KP_3,
- /* 56 */ KEY_KP_4,
- /* 57 */ KEY_KP_5,
- /* 58 */ KEY_KP_6,
- /* 59 */ KEY_KP_7,
- /* 5a */ KEY_UNKNOWN, /* F20 */
- /* 5b */ KEY_KP_8,
- /* 5c */ KEY_KP_9,
- /* 5d */ KEY_YEN, /* JIS Yen */
- /* 5e */ KEY_UNDERSCORE, /* JIS Underscore */
- /* 5f */ KEY_COMMA, /* JIS KeypadComma */
- /* 60 */ KEY_F5,
- /* 61 */ KEY_F6,
- /* 62 */ KEY_F7,
- /* 63 */ KEY_F3,
- /* 64 */ KEY_F8,
- /* 65 */ KEY_F9,
- /* 66 */ KEY_UNKNOWN, /* JIS Eisu */
- /* 67 */ KEY_F11,
- /* 68 */ KEY_UNKNOWN, /* JIS Kana */
- /* 69 */ KEY_F13,
- /* 6a */ KEY_F16,
- /* 6b */ KEY_F14,
- /* 6c */ KEY_UNKNOWN,
- /* 6d */ KEY_F10,
- /* 6e */ KEY_MENU,
- /* 6f */ KEY_F12,
- /* 70 */ KEY_UNKNOWN,
- /* 71 */ KEY_F15,
- /* 72 */ KEY_INSERT, /* Really Help... */
- /* 73 */ KEY_HOME,
- /* 74 */ KEY_PAGEUP,
- /* 75 */ KEY_DELETE,
- /* 76 */ KEY_F4,
- /* 77 */ KEY_END,
- /* 78 */ KEY_F2,
- /* 79 */ KEY_PAGEDOWN,
- /* 7a */ KEY_F1,
- /* 7b */ KEY_LEFT,
- /* 7c */ KEY_RIGHT,
- /* 7d */ KEY_DOWN,
- /* 7e */ KEY_UP,
- /* 7f */ KEY_UNKNOWN,
- };
+// Keyboard symbol translation table
+static const unsigned int _osx_to_godot_table[128] = {
+ /* 00 */ KEY_A,
+ /* 01 */ KEY_S,
+ /* 02 */ KEY_D,
+ /* 03 */ KEY_F,
+ /* 04 */ KEY_H,
+ /* 05 */ KEY_G,
+ /* 06 */ KEY_Z,
+ /* 07 */ KEY_X,
+ /* 08 */ KEY_C,
+ /* 09 */ KEY_V,
+ /* 0a */ KEY_SECTION, /* ISO Section */
+ /* 0b */ KEY_B,
+ /* 0c */ KEY_Q,
+ /* 0d */ KEY_W,
+ /* 0e */ KEY_E,
+ /* 0f */ KEY_R,
+ /* 10 */ KEY_Y,
+ /* 11 */ KEY_T,
+ /* 12 */ KEY_1,
+ /* 13 */ KEY_2,
+ /* 14 */ KEY_3,
+ /* 15 */ KEY_4,
+ /* 16 */ KEY_6,
+ /* 17 */ KEY_5,
+ /* 18 */ KEY_EQUAL,
+ /* 19 */ KEY_9,
+ /* 1a */ KEY_7,
+ /* 1b */ KEY_MINUS,
+ /* 1c */ KEY_8,
+ /* 1d */ KEY_0,
+ /* 1e */ KEY_BRACERIGHT,
+ /* 1f */ KEY_O,
+ /* 20 */ KEY_U,
+ /* 21 */ KEY_BRACELEFT,
+ /* 22 */ KEY_I,
+ /* 23 */ KEY_P,
+ /* 24 */ KEY_ENTER,
+ /* 25 */ KEY_L,
+ /* 26 */ KEY_J,
+ /* 27 */ KEY_APOSTROPHE,
+ /* 28 */ KEY_K,
+ /* 29 */ KEY_SEMICOLON,
+ /* 2a */ KEY_BACKSLASH,
+ /* 2b */ KEY_COMMA,
+ /* 2c */ KEY_SLASH,
+ /* 2d */ KEY_N,
+ /* 2e */ KEY_M,
+ /* 2f */ KEY_PERIOD,
+ /* 30 */ KEY_TAB,
+ /* 31 */ KEY_SPACE,
+ /* 32 */ KEY_QUOTELEFT,
+ /* 33 */ KEY_BACKSPACE,
+ /* 34 */ KEY_UNKNOWN,
+ /* 35 */ KEY_ESCAPE,
+ /* 36 */ KEY_META,
+ /* 37 */ KEY_META,
+ /* 38 */ KEY_SHIFT,
+ /* 39 */ KEY_CAPSLOCK,
+ /* 3a */ KEY_ALT,
+ /* 3b */ KEY_CONTROL,
+ /* 3c */ KEY_SHIFT,
+ /* 3d */ KEY_ALT,
+ /* 3e */ KEY_CONTROL,
+ /* 3f */ KEY_UNKNOWN, /* Function */
+ /* 40 */ KEY_UNKNOWN, /* F17 */
+ /* 41 */ KEY_KP_PERIOD,
+ /* 42 */ KEY_UNKNOWN,
+ /* 43 */ KEY_KP_MULTIPLY,
+ /* 44 */ KEY_UNKNOWN,
+ /* 45 */ KEY_KP_ADD,
+ /* 46 */ KEY_UNKNOWN,
+ /* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */
+ /* 48 */ KEY_VOLUMEUP, /* VolumeUp */
+ /* 49 */ KEY_VOLUMEDOWN, /* VolumeDown */
+ /* 4a */ KEY_VOLUMEMUTE, /* Mute */
+ /* 4b */ KEY_KP_DIVIDE,
+ /* 4c */ KEY_KP_ENTER,
+ /* 4d */ KEY_UNKNOWN,
+ /* 4e */ KEY_KP_SUBTRACT,
+ /* 4f */ KEY_UNKNOWN, /* F18 */
+ /* 50 */ KEY_UNKNOWN, /* F19 */
+ /* 51 */ KEY_EQUAL, /* KeypadEqual */
+ /* 52 */ KEY_KP_0,
+ /* 53 */ KEY_KP_1,
+ /* 54 */ KEY_KP_2,
+ /* 55 */ KEY_KP_3,
+ /* 56 */ KEY_KP_4,
+ /* 57 */ KEY_KP_5,
+ /* 58 */ KEY_KP_6,
+ /* 59 */ KEY_KP_7,
+ /* 5a */ KEY_UNKNOWN, /* F20 */
+ /* 5b */ KEY_KP_8,
+ /* 5c */ KEY_KP_9,
+ /* 5d */ KEY_YEN, /* JIS Yen */
+ /* 5e */ KEY_UNDERSCORE, /* JIS Underscore */
+ /* 5f */ KEY_COMMA, /* JIS KeypadComma */
+ /* 60 */ KEY_F5,
+ /* 61 */ KEY_F6,
+ /* 62 */ KEY_F7,
+ /* 63 */ KEY_F3,
+ /* 64 */ KEY_F8,
+ /* 65 */ KEY_F9,
+ /* 66 */ KEY_UNKNOWN, /* JIS Eisu */
+ /* 67 */ KEY_F11,
+ /* 68 */ KEY_UNKNOWN, /* JIS Kana */
+ /* 69 */ KEY_F13,
+ /* 6a */ KEY_F16,
+ /* 6b */ KEY_F14,
+ /* 6c */ KEY_UNKNOWN,
+ /* 6d */ KEY_F10,
+ /* 6e */ KEY_MENU,
+ /* 6f */ KEY_F12,
+ /* 70 */ KEY_UNKNOWN,
+ /* 71 */ KEY_F15,
+ /* 72 */ KEY_INSERT, /* Really Help... */
+ /* 73 */ KEY_HOME,
+ /* 74 */ KEY_PAGEUP,
+ /* 75 */ KEY_DELETE,
+ /* 76 */ KEY_F4,
+ /* 77 */ KEY_END,
+ /* 78 */ KEY_F2,
+ /* 79 */ KEY_PAGEDOWN,
+ /* 7a */ KEY_F1,
+ /* 7b */ KEY_LEFT,
+ /* 7c */ KEY_RIGHT,
+ /* 7d */ KEY_DOWN,
+ /* 7e */ KEY_UP,
+ /* 7f */ KEY_UNKNOWN,
+};
+// Translates a OS X keycode to a Godot keycode
+static int translateKey(unsigned int key) {
if (key >= 128)
return KEY_UNKNOWN;
- return table[key];
+ return _osx_to_godot_table[key];
+}
+
+// Translates a Godot keycode back to a OSX keycode
+static unsigned int unmapKey(int key) {
+ for (int i = 0; i <= 126; i++) {
+ if (_osx_to_godot_table[i] == key) {
+ return i;
+ }
+ }
+ return 127;
}
struct _KeyCodeMap {
@@ -3210,6 +3219,17 @@ String OS_OSX::keyboard_get_layout_name(int p_index) const {
return kbd_layouts[p_index].name;
}
+uint32_t OS_OSX::keyboard_get_scancode_from_physical(uint32_t p_scancode) const {
+ if (p_scancode == KEY_PAUSE) {
+ return p_scancode;
+ }
+
+ unsigned int modifiers = p_scancode & KEY_MODIFIER_MASK;
+ unsigned int scancode_no_mod = p_scancode & KEY_CODE_MASK;
+ unsigned int osx_scancode = unmapKey((uint32_t)scancode_no_mod);
+ return (uint32_t)(remapKey(osx_scancode, 0) | modifiers);
+}
+
void OS_OSX::process_events() {
while (true) {
NSEvent *event = [NSApp
diff --git a/platform/windows/key_mapping_windows.cpp b/platform/windows/key_mapping_windows.cpp
index a3cbb6675db..2be61302cf4 100644
--- a/platform/windows/key_mapping_windows.cpp
+++ b/platform/windows/key_mapping_windows.cpp
@@ -347,6 +347,16 @@ unsigned int KeyMappingWindows::get_keysym(unsigned int p_code) {
return KEY_UNKNOWN;
}
+unsigned int KeyMappingWindows::get_scancode(unsigned int p_keycode) {
+ for (int i = 0; _scancode_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
+ if (_scancode_to_keycode[i].keysym == p_keycode) {
+ return _scancode_to_keycode[i].keycode;
+ }
+ }
+
+ return 0;
+}
+
unsigned int KeyMappingWindows::get_scansym(unsigned int p_code, bool p_extended) {
unsigned int keycode = KEY_UNKNOWN;
for (int i = 0; _scancode_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
diff --git a/platform/windows/key_mapping_windows.h b/platform/windows/key_mapping_windows.h
index 9929b72f388..76f3c90ab18 100644
--- a/platform/windows/key_mapping_windows.h
+++ b/platform/windows/key_mapping_windows.h
@@ -42,6 +42,7 @@ class KeyMappingWindows {
public:
static unsigned int get_keysym(unsigned int p_code);
+ static unsigned int get_scancode(unsigned int p_keycode);
static unsigned int get_scansym(unsigned int p_code, bool p_extended);
static bool is_extended_key(unsigned int p_code);
};
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 95488a15160..487cc3a39c5 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -3237,6 +3237,42 @@ String OS_Windows::keyboard_get_layout_language(int p_index) const {
return String(buf).substr(0, 2);
}
+uint32_t OS_Windows::keyboard_get_scancode_from_physical(uint32_t p_scancode) const {
+ unsigned int modifiers = p_scancode & KEY_MODIFIER_MASK;
+ uint32_t scancode_no_mod = (uint32_t)(p_scancode & KEY_CODE_MASK);
+
+ if (scancode_no_mod == KEY_PRINT ||
+ scancode_no_mod == KEY_KP_ADD ||
+ scancode_no_mod == KEY_KP_5 ||
+ (scancode_no_mod >= KEY_0 && scancode_no_mod <= KEY_9)) {
+ return p_scancode;
+ }
+
+ unsigned int scancode = KeyMappingWindows::get_scancode(scancode_no_mod);
+ if (scancode == 0) {
+ return p_scancode;
+ }
+
+ HKL current_layout = GetKeyboardLayout(0);
+ UINT vk = MapVirtualKeyEx(scancode, MAPVK_VSC_TO_VK, current_layout);
+ if (vk == 0) {
+ return p_scancode;
+ }
+
+ UINT char_code = MapVirtualKeyEx(vk, MAPVK_VK_TO_CHAR, current_layout) & 0x7FFF;
+ // Unlike a similar Linux/BSD check which matches full Latin-1 range,
+ // we limit these to ASCII to fix some layouts, including Arabic ones
+ if (char_code >= 32 && char_code <= 127) {
+ // Godot uses 'braces' instead of 'brackets'
+ if (char_code == KEY_BRACKETLEFT || char_code == KEY_BRACKETRIGHT) {
+ char_code += 32;
+ }
+ return (uint32_t)(char_code | modifiers);
+ }
+
+ return (uint32_t)(KeyMappingWindows::get_keysym(vk) | modifiers);
+}
+
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/os_windows.h b/platform/windows/os_windows.h
index 688c77860fb..6dea669f50d 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -527,6 +527,7 @@ public:
virtual void keyboard_set_current_layout(int p_index);
virtual String keyboard_get_layout_language(int p_index) const;
virtual String keyboard_get_layout_name(int p_index) const;
+ virtual uint32_t keyboard_get_scancode_from_physical(uint32_t p_scancode) const;
virtual void enable_for_stealing_focus(ProcessID pid);
virtual void move_window_to_foreground();
diff --git a/platform/x11/key_mapping_x11.cpp b/platform/x11/key_mapping_x11.cpp
index 985aa4d0ef4..073b8f1bfc0 100644
--- a/platform/x11/key_mapping_x11.cpp
+++ b/platform/x11/key_mapping_x11.cpp
@@ -310,6 +310,18 @@ unsigned int KeyMappingX11::get_scancode(unsigned int p_code) {
return keycode;
}
+unsigned int KeyMappingX11::get_xlibcode(unsigned int p_keysym) {
+ unsigned int code = 0;
+ for (int i = 0; _scancode_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
+ if (_scancode_to_keycode[i].keysym == p_keysym) {
+ code = _scancode_to_keycode[i].keycode;
+ break;
+ }
+ }
+
+ return code;
+}
+
unsigned int KeyMappingX11::get_keycode(KeySym p_keysym) {
// kinda bruteforce.. could optimize.
diff --git a/platform/x11/key_mapping_x11.h b/platform/x11/key_mapping_x11.h
index 2539d59ea34..7769d85c4bb 100644
--- a/platform/x11/key_mapping_x11.h
+++ b/platform/x11/key_mapping_x11.h
@@ -45,6 +45,7 @@ class KeyMappingX11 {
public:
static unsigned int get_keycode(KeySym p_keysym);
+ static unsigned int get_xlibcode(unsigned int p_keysym);
static unsigned int get_scancode(unsigned int p_code);
static KeySym get_keysym(unsigned int p_code);
static unsigned int get_unicode_from_keysym(KeySym p_keysym);
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 922e60fd422..6aa99a163ef 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -4104,6 +4104,24 @@ String OS_X11::keyboard_get_layout_name(int p_index) const {
return ret;
}
+uint32_t OS_X11::keyboard_get_scancode_from_physical(uint32_t p_scancode) const {
+ unsigned int modifiers = p_scancode & KEY_MODIFIER_MASK;
+ unsigned int scancode_no_mod = p_scancode & KEY_CODE_MASK;
+ unsigned int xkeycode = KeyMappingX11::get_xlibcode((uint32_t)scancode_no_mod);
+ KeySym xkeysym = XkbKeycodeToKeysym(x11_display, xkeycode, 0, 0);
+ if (xkeysym >= 'a' && xkeysym <= 'z') {
+ xkeysym -= ('a' - 'A');
+ }
+
+ uint32_t key = KeyMappingX11::get_keycode(xkeysym);
+ // If not found, fallback to QWERTY.
+ // This should match the behavior of the event pump
+ if (key == 0) {
+ return p_scancode;
+ }
+ return (uint32_t)(key | modifiers);
+}
+
void OS_X11::update_real_mouse_position() {
Window root_return, child_return;
int root_x, root_y, win_x, win_y;
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index 1ee5e6d51f6..6b9d32516ee 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -361,6 +361,7 @@ public:
virtual void keyboard_set_current_layout(int p_index);
virtual String keyboard_get_layout_language(int p_index) const;
virtual String keyboard_get_layout_name(int p_index) const;
+ virtual uint32_t keyboard_get_scancode_from_physical(uint32_t p_scancode) const;
void update_real_mouse_position();
OS_X11();