From dab4cf3ed6c533643800372dd636ba64f48deb0f Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Sun, 7 Mar 2021 17:16:42 +0200 Subject: [PATCH] Add `physical_scancode` (keyboard layout independent keycodes) to InputEventKey and InputMap. Fix non-latin keyboard layout keycodes on Linux/X11 (fallback to physical keycodes). --- core/os/input_event.cpp | 42 ++++- core/os/input_event.h | 5 + doc/classes/InputEventKey.xml | 14 +- editor/icons/icon_keyboard.svg | 2 +- editor/icons/icon_keyboard_physical.svg | 1 + editor/project_settings_editor.cpp | 50 +++++- editor/project_settings_editor.h | 2 + .../lib/src/org/godotengine/godot/Godot.java | 4 +- .../src/org/godotengine/godot/GodotLib.java | 2 +- .../godot/input/GodotInputHandler.java | 6 +- .../godot/input/GodotTextInputWrapper.java | 16 +- platform/android/java_godot_lib_jni.cpp | 4 +- platform/android/java_godot_lib_jni.h | 2 +- platform/android/os_android.cpp | 7 +- platform/android/os_android.h | 2 +- platform/iphone/os_iphone.mm | 1 + platform/javascript/os_javascript.cpp | 1 + platform/osx/os_osx.h | 1 + platform/osx/os_osx.mm | 10 ++ platform/uwp/app.cpp | 2 + platform/uwp/os_uwp.cpp | 1 + platform/uwp/os_uwp.h | 1 + platform/windows/key_mapping_windows.cpp | 163 ++++++++++++++++++ platform/windows/key_mapping_windows.h | 1 + platform/windows/os_windows.cpp | 3 + platform/x11/key_mapping_x11.cpp | 131 ++++++++++++++ platform/x11/key_mapping_x11.h | 1 + platform/x11/os_x11.cpp | 18 +- 28 files changed, 458 insertions(+), 35 deletions(-) create mode 100644 editor/icons/icon_keyboard_physical.svg diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 7bdbfcb6bea5..fa6d4acdf171 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -216,6 +216,13 @@ uint32_t InputEventKey::get_scancode() const { return scancode; } +void InputEventKey::set_physical_scancode(uint32_t p_scancode) { + physical_scancode = p_scancode; +} +uint32_t InputEventKey::get_physical_scancode() const { + return physical_scancode; +} + void InputEventKey::set_unicode(uint32_t p_unicode) { unicode = p_unicode; } @@ -248,6 +255,20 @@ uint32_t InputEventKey::get_scancode_with_modifiers() const { return sc; } +uint32_t InputEventKey::get_physical_scancode_with_modifiers() const { + uint32_t sc = physical_scancode; + if (get_control()) + sc |= KEY_MASK_CTRL; + if (get_alt()) + sc |= KEY_MASK_ALT; + if (get_shift()) + sc |= KEY_MASK_SHIFT; + if (get_metakey()) + sc |= KEY_MASK_META; + + return sc; +} + String InputEventKey::as_text() const { String kc = keycode_get_string(scancode); if (kc == String()) { @@ -275,10 +296,19 @@ bool InputEventKey::action_match(const Ref &p_event, bool *p_pressed return false; } - uint32_t code = get_scancode_with_modifiers(); - uint32_t event_code = key->get_scancode_with_modifiers(); + bool match = false; + if (get_scancode() == 0) { + uint32_t code = get_physical_scancode_with_modifiers(); + uint32_t event_code = key->get_physical_scancode_with_modifiers(); + + match = get_physical_scancode() == key->get_physical_scancode() && (!key->is_pressed() || (code & event_code) == code); + } else { + uint32_t code = get_scancode_with_modifiers(); + uint32_t event_code = key->get_scancode_with_modifiers(); + + match = get_scancode() == key->get_scancode() && (!key->is_pressed() || (code & event_code) == code); + } - bool match = get_scancode() == key->get_scancode() && (!key->is_pressed() || (code & event_code) == code); if (match) { if (p_pressed != nullptr) { *p_pressed = key->is_pressed(); @@ -308,15 +338,20 @@ void InputEventKey::_bind_methods() { ClassDB::bind_method(D_METHOD("set_scancode", "scancode"), &InputEventKey::set_scancode); ClassDB::bind_method(D_METHOD("get_scancode"), &InputEventKey::get_scancode); + ClassDB::bind_method(D_METHOD("set_physical_scancode", "scancode"), &InputEventKey::set_physical_scancode); + ClassDB::bind_method(D_METHOD("get_physical_scancode"), &InputEventKey::get_physical_scancode); + ClassDB::bind_method(D_METHOD("set_unicode", "unicode"), &InputEventKey::set_unicode); ClassDB::bind_method(D_METHOD("get_unicode"), &InputEventKey::get_unicode); ClassDB::bind_method(D_METHOD("set_echo", "echo"), &InputEventKey::set_echo); ClassDB::bind_method(D_METHOD("get_scancode_with_modifiers"), &InputEventKey::get_scancode_with_modifiers); + ClassDB::bind_method(D_METHOD("get_physical_scancode_with_modifiers"), &InputEventKey::get_physical_scancode_with_modifiers); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); ADD_PROPERTY(PropertyInfo(Variant::INT, "scancode"), "set_scancode", "get_scancode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "physical_scancode"), "set_physical_scancode", "get_physical_scancode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "unicode"), "set_unicode", "get_unicode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "echo"), "set_echo", "is_echo"); } @@ -324,6 +359,7 @@ void InputEventKey::_bind_methods() { InputEventKey::InputEventKey() { pressed = false; scancode = 0; + physical_scancode = 0; unicode = 0; ///unicode echo = false; } diff --git a/core/os/input_event.h b/core/os/input_event.h index 0376d0dd38e4..9880a0a9fd5b 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -269,6 +269,7 @@ class InputEventKey : public InputEventWithModifiers { bool pressed; /// otherwise release uint32_t scancode; ///< check keyboard.h , KeyCode enum, without modifier masks + uint32_t physical_scancode; uint32_t unicode; ///unicode bool echo; /// true if this is an echo key @@ -283,6 +284,9 @@ class InputEventKey : public InputEventWithModifiers { void set_scancode(uint32_t p_scancode); uint32_t get_scancode() const; + void set_physical_scancode(uint32_t p_scancode); + uint32_t get_physical_scancode() const; + void set_unicode(uint32_t p_unicode); uint32_t get_unicode() const; @@ -290,6 +294,7 @@ class InputEventKey : public InputEventWithModifiers { virtual bool is_echo() const; uint32_t get_scancode_with_modifiers() const; + uint32_t get_physical_scancode_with_modifiers() const; virtual bool action_match(const Ref &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; virtual bool shortcut_match(const Ref &p_event) const; diff --git a/doc/classes/InputEventKey.xml b/doc/classes/InputEventKey.xml index fd767851d6f6..79fabdcafad8 100644 --- a/doc/classes/InputEventKey.xml +++ b/doc/classes/InputEventKey.xml @@ -10,6 +10,14 @@ https://docs.godotengine.org/en/3.3/tutorials/inputs/inputevent.html + + + + + Returns the physical scancode combined with modifier keys such as [code]Shift[/code] or [code]Alt[/code]. See also [InputEventWithModifiers]. + To get a human-readable representation of the [InputEventKey] with modifiers, use [code]OS.get_scancode_string(event.get_physical_scancode_with_modifiers())[/code] where [code]event[/code] is the [InputEventKey]. + + @@ -23,11 +31,15 @@ If [code]true[/code], the key was already pressed before this event. It means the user is holding the key down. + + Key physical scancode, which corresponds to one of the [enum KeyList] constants. Represent the physical location of a key on the 101/102-key US QWERTY keyboard. + To get a human-readable representation of the [InputEventKey], use [code]OS.get_scancode_string(event.physical_scancode)[/code] where [code]event[/code] is the [InputEventKey]. + If [code]true[/code], the key's state is pressed. If [code]false[/code], the key's state is released. - The key scancode, which corresponds to one of the [enum KeyList] constants. + The key scancode, which corresponds to one of the [enum KeyList] constants. Represent key in the current keyboard layout. To get a human-readable representation of the [InputEventKey], use [code]OS.get_scancode_string(event.scancode)[/code] where [code]event[/code] is the [InputEventKey]. diff --git a/editor/icons/icon_keyboard.svg b/editor/icons/icon_keyboard.svg index 75b62fc0e302..b9dfab71ed2f 100644 --- a/editor/icons/icon_keyboard.svg +++ b/editor/icons/icon_keyboard.svg @@ -1 +1 @@ - + diff --git a/editor/icons/icon_keyboard_physical.svg b/editor/icons/icon_keyboard_physical.svg new file mode 100644 index 000000000000..4364e0b4fa52 --- /dev/null +++ b/editor/icons/icon_keyboard_physical.svg @@ -0,0 +1 @@ + diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index b002c9e82560..de12b3238f10 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -114,6 +114,7 @@ void ProjectSettingsEditor::_notification(int p_what) { translation_list->connect("button_pressed", this, "_translation_delete"); _update_actions(); popup_add->add_icon_item(get_icon("Keyboard", "EditorIcons"), TTR("Key "), INPUT_KEY); //"Key " - because the word 'key' has already been used as a key animation + popup_add->add_icon_item(get_icon("KeyboardPhysical", "EditorIcons"), TTR("Physical Key"), INPUT_KEY_PHYSICAL); popup_add->add_icon_item(get_icon("JoyButton", "EditorIcons"), TTR("Joy Button"), INPUT_JOY_BUTTON); popup_add->add_icon_item(get_icon("JoyAxis", "EditorIcons"), TTR("Joy Axis"), INPUT_JOY_MOTION); popup_add->add_icon_item(get_icon("Mouse", "EditorIcons"), TTR("Mouse Button"), INPUT_MOUSE_BUTTON); @@ -147,6 +148,7 @@ void ProjectSettingsEditor::_notification(int p_what) { search_box->set_clear_button_enabled(true); action_add_error->add_color_override("font_color", get_color("error_color", "Editor")); popup_add->set_item_icon(popup_add->get_item_index(INPUT_KEY), get_icon("Keyboard", "EditorIcons")); + popup_add->set_item_icon(popup_add->get_item_index(INPUT_KEY_PHYSICAL), get_icon("KeyboardPhysical", "EditorIcons")); popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_BUTTON), get_icon("JoyButton", "EditorIcons")); popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_MOTION), get_icon("JoyAxis", "EditorIcons")); popup_add->set_item_icon(popup_add->get_item_index(INPUT_MOUSE_BUTTON), get_icon("Mouse", "EditorIcons")); @@ -357,7 +359,14 @@ void ProjectSettingsEditor::_press_a_key_confirm() { Ref ie; ie.instance(); - ie->set_scancode(last_wait_for_key->get_scancode()); + if (press_a_key_physical) { + ie->set_physical_scancode(last_wait_for_key->get_physical_scancode()); + ie->set_scancode(0); + } else { + ie->set_physical_scancode(0); + ie->set_scancode(last_wait_for_key->get_scancode()); + } + ie->set_shift(last_wait_for_key->get_shift()); ie->set_alt(last_wait_for_key->get_alt()); ie->set_control(last_wait_for_key->get_control()); @@ -375,8 +384,14 @@ void ProjectSettingsEditor::_press_a_key_confirm() { if (aie.is_null()) { continue; } - if (aie->get_scancode_with_modifiers() == ie->get_scancode_with_modifiers()) { - return; + if (!press_a_key_physical) { + if (aie->get_scancode_with_modifiers() == ie->get_scancode_with_modifiers()) { + return; + } + } else { + if (aie->get_physical_scancode_with_modifiers() == ie->get_physical_scancode_with_modifiers()) { + return; + } } } @@ -444,7 +459,7 @@ void ProjectSettingsEditor::_wait_for_key(const Ref &p_event) { if (k.is_valid() && k->is_pressed() && k->get_scancode() != 0) { last_wait_for_key = p_event; - const String str = keycode_get_string(k->get_scancode_with_modifiers()); + const String str = (press_a_key_physical) ? keycode_get_string(k->get_physical_scancode_with_modifiers()) + TTR(" (Physical)") : keycode_get_string(k->get_scancode_with_modifiers()); press_a_key_label->set_text(str); press_a_key->get_ok()->set_disabled(false); @@ -457,12 +472,20 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref p_exiting_even switch (add_type) { case INPUT_KEY: { + press_a_key_physical = false; + press_a_key_label->set_text(TTR("Press a Key...")); + press_a_key->get_ok()->set_disabled(true); + last_wait_for_key = Ref(); + press_a_key->popup_centered(Size2(250, 80) * EDSCALE); + press_a_key->grab_focus(); + } break; + case INPUT_KEY_PHYSICAL: { + press_a_key_physical = true; press_a_key_label->set_text(TTR("Press a Key...")); press_a_key->get_ok()->set_disabled(true); last_wait_for_key = Ref(); press_a_key->popup_centered(Size2(250, 80) * EDSCALE); press_a_key->grab_focus(); - } break; case INPUT_MOUSE_BUTTON: { device_index_label->set_text(TTR("Mouse Button Index:")); @@ -538,7 +561,11 @@ void ProjectSettingsEditor::_edit_item(Ref p_exiting_event) { InputType ie_type; if ((Ref(p_exiting_event)).is_valid()) { - ie_type = INPUT_KEY; + if ((Ref(p_exiting_event))->get_scancode() != 0) { + ie_type = INPUT_KEY; + } else { + ie_type = INPUT_KEY_PHYSICAL; + } } else if ((Ref(p_exiting_event)).is_valid()) { ie_type = INPUT_JOY_BUTTON; @@ -729,10 +756,13 @@ void ProjectSettingsEditor::_update_actions() { Ref k = event; if (k.is_valid()) { - const String str = keycode_get_string(k->get_scancode_with_modifiers()); - + const String str = (k->get_scancode() == 0) ? keycode_get_string(k->get_physical_scancode_with_modifiers()) + TTR(" (Physical)") : keycode_get_string(k->get_scancode_with_modifiers()); action2->set_text(0, str); - action2->set_icon(0, get_icon("Keyboard", "EditorIcons")); + if ((k->get_scancode() != 0)) { + action2->set_icon(0, get_icon("Keyboard", "EditorIcons")); + } else { + action2->set_icon(0, get_icon("KeyboardPhysical", "EditorIcons")); + } } Ref jb = event; @@ -1925,6 +1955,8 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { add_child(popup_add); popup_add->connect("id_pressed", this, "_add_item"); + press_a_key_physical = false; + press_a_key = memnew(ConfirmationDialog); press_a_key->set_focus_mode(FOCUS_ALL); add_child(press_a_key); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index 57b148157c25..a540c8ce05b7 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -45,6 +45,7 @@ class ProjectSettingsEditor : public AcceptDialog { enum InputType { INPUT_KEY, + INPUT_KEY_PHYSICAL, INPUT_JOY_BUTTON, INPUT_JOY_MOTION, INPUT_MOUSE_BUTTON @@ -76,6 +77,7 @@ class ProjectSettingsEditor : public AcceptDialog { OptionButton *type; PopupMenu *popup_add; ConfirmationDialog *press_a_key; + bool press_a_key_physical; Label *press_a_key_label; ConfirmationDialog *device_input; OptionButton *device_id; diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 1b734c456fd7..a068b6433f0e 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -1056,8 +1056,8 @@ public void run() { int keyCode; if ((keyCode = cc[i]) != 0) { // Simulate key down and up... - GodotLib.key(0, keyCode, true); - GodotLib.key(0, keyCode, false); + GodotLib.key(0, 0, keyCode, true); + GodotLib.key(0, 0, keyCode, false); } } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java index 14ff0316e949..a700f7a116c3 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java @@ -138,7 +138,7 @@ public class GodotLib { /** * Forward regular key events from the main thread to the GL thread. */ - public static native void key(int p_scancode, int p_unicode_char, boolean p_pressed); + public static native void key(int p_keycode, int p_scancode, int p_unicode_char, boolean p_pressed); /** * Forward game device's key events from the main thread to the GL thread. diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java index 62ecaa9e393a..6f18b9d64e19 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java @@ -109,11 +109,12 @@ public void run() { }); } } else { + final int scanCode = event.getScanCode(); final int chr = event.getUnicodeChar(0); queueEvent(new Runnable() { @Override public void run() { - GodotLib.key(keyCode, chr, false); + GodotLib.key(keyCode, scanCode, chr, false); } }); }; @@ -154,11 +155,12 @@ public void run() { }); } } else { + final int scanCode = event.getScanCode(); final int chr = event.getUnicodeChar(0); queueEvent(new Runnable() { @Override public void run() { - GodotLib.key(keyCode, chr, true); + GodotLib.key(keyCode, scanCode, chr, true); } }); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java index 3e5fb947296f..c9eea0bcafbb 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java @@ -98,8 +98,8 @@ public void beforeTextChanged(final CharSequence pCharSequence, final int start, @Override public void run() { for (int i = 0; i < count; ++i) { - GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true); - GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false); + GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, true); + GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, false); if (mHasSelection) { mHasSelection = false; @@ -127,8 +127,8 @@ public void run() { // Return keys are handled through action events continue; } - GodotLib.key(0, key, true); - GodotLib.key(0, key, false); + GodotLib.key(0, 0, key, true); + GodotLib.key(0, 0, key, false); } } }); @@ -144,8 +144,8 @@ public boolean onEditorAction(final TextView pTextView, final int pActionID, fin public void run() { for (int i = 0; i < characters.length(); i++) { final int ch = characters.codePointAt(i); - GodotLib.key(0, ch, true); - GodotLib.key(0, ch, false); + GodotLib.key(0, 0, ch, true); + GodotLib.key(0, 0, ch, false); } } }); @@ -153,8 +153,8 @@ public void run() { if (pActionID == EditorInfo.IME_ACTION_DONE) { // Enter key has been pressed - GodotLib.key(KeyEvent.KEYCODE_ENTER, 0, true); - GodotLib.key(KeyEvent.KEYCODE_ENTER, 0, false); + GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, true); + GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, false); this.mView.requestFocus(); return true; diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index 240f66626968..b9f4a2f3cbcd 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -376,11 +376,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged( } } -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_scancode, jint p_unicode_char, jboolean p_pressed) { +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed) { if (step == 0) return; - os_android->process_key_event(p_scancode, p_unicode_char, p_pressed); + os_android->process_key_event(p_keycode, p_scancode, p_unicode_char, p_pressed); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) { diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h index ba7841c0d130..4b81e0879856 100644 --- a/platform/android/java_godot_lib_jni.h +++ b/platform/android/java_godot_lib_jni.h @@ -51,7 +51,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNI JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_scancode, jint p_unicode_char, jboolean p_pressed); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index ac8a82bcf0c4..d4b0fe9ca964 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -340,11 +340,12 @@ void OS_Android::process_event(Ref p_event) { input->parse_input_event(p_event); } -void OS_Android::process_key_event(int p_scancode, int p_unicode_char, bool p_pressed) { +void OS_Android::process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed) { Ref ev; ev.instance(); int val = p_unicode_char; - unsigned int scancode = android_get_keysym(p_scancode); + unsigned int scancode = android_get_keysym(p_keycode); + unsigned int phy_scancode = android_get_keysym(p_scancode); switch (scancode) { case KEY_SHIFT: { @@ -362,6 +363,8 @@ void OS_Android::process_key_event(int p_scancode, int p_unicode_char, bool p_pr } ev->set_scancode(scancode); + ev->set_physical_scancode(phy_scancode); + ev->set_unicode(val); ev->set_pressed(p_pressed); diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 22194d84d0f8..bb93e1f33a16 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -208,7 +208,7 @@ class OS_Android : public OS_Unix { void process_double_tap(int event_android_button_mask, Point2 p_pos); void process_scroll(Point2 p_pos); void process_joy_event(JoypadEvent p_event); - void process_key_event(int p_scancode, int p_unicode_char, bool p_pressed); + void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed); void process_event(Ref p_event); void init_video_mode(int p_video_width, int p_video_height); diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm index 566c91e8c2b2..b25d1e482545 100644 --- a/platform/iphone/os_iphone.mm +++ b/platform/iphone/os_iphone.mm @@ -213,6 +213,7 @@ ev->set_echo(false); ev->set_pressed(p_pressed); ev->set_scancode(p_key); + ev->set_physical_scancode(p_key); ev->set_unicode(p_key); perform_event(ev); }; diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index f5f075352cda..2657cb57fdd2 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -241,6 +241,7 @@ static Ref setup_key_event(const EmscriptenKeyboardEvent *emscrip ev->set_echo(emscripten_event->repeat); dom2godot_mod(emscripten_event, ev); ev->set_scancode(dom_code2godot_scancode(emscripten_event->code, emscripten_event->key)); + ev->set_physical_scancode(dom_code2godot_scancode(emscripten_event->code, emscripten_event->key)); String unicode = String::utf8(emscripten_event->key); // Check if empty or multi-character (e.g. `CapsLock`). diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 3795fdf0eae6..a9c6074a97c0 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -62,6 +62,7 @@ class OS_OSX : public OS_Unix { bool echo; bool raw; uint32_t scancode; + uint32_t physical_scancode; uint32_t unicode; }; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 7409125b3d8e..3b37f4fea253 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -143,6 +143,7 @@ - (void)sendEvent:(NSEvent *)event { get_key_modifier_state([event modifierFlags], k); k->set_pressed(true); k->set_scancode(KEY_PERIOD); + k->set_physical_scancode(KEY_PERIOD); k->set_echo([event isARepeat]); OS_OSX::singleton->push_input(k); @@ -612,6 +613,7 @@ - (void)insertText:(id)aString replacementRange:(NSRange)replacementRange { ke.echo = false; ke.raw = false; // IME input event ke.scancode = 0; + ke.physical_scancode = 0; ke.unicode = codepoint; push_to_key_event_buffer(ke); @@ -1192,6 +1194,7 @@ - (void)keyDown:(NSEvent *)event { ke.pressed = true; ke.echo = [event isARepeat]; ke.scancode = remapKey([event keyCode], [event modifierFlags]); + ke.physical_scancode = translateKey([event keyCode]); ke.raw = true; ke.unicode = [characters characterAtIndex:i]; @@ -1204,6 +1207,7 @@ - (void)keyDown:(NSEvent *)event { ke.pressed = true; ke.echo = [event isARepeat]; ke.scancode = remapKey([event keyCode], [event modifierFlags]); + ke.physical_scancode = translateKey([event keyCode]); ke.raw = false; ke.unicode = 0; @@ -1263,6 +1267,7 @@ - (void)flagsChanged:(NSEvent *)event { ke.osx_state = mod; ke.scancode = remapKey(key, mod); + ke.physical_scancode = translateKey(key); ke.unicode = 0; push_to_key_event_buffer(ke); @@ -1284,6 +1289,7 @@ - (void)keyUp:(NSEvent *)event { ke.pressed = false; ke.echo = [event isARepeat]; ke.scancode = remapKey([event keyCode], [event modifierFlags]); + ke.physical_scancode = translateKey([event keyCode]); ke.raw = true; ke.unicode = [characters characterAtIndex:i]; @@ -1296,6 +1302,7 @@ - (void)keyUp:(NSEvent *)event { ke.pressed = false; ke.echo = [event isARepeat]; ke.scancode = remapKey([event keyCode], [event modifierFlags]); + ke.physical_scancode = translateKey([event keyCode]); ke.raw = true; ke.unicode = 0; @@ -3146,6 +3153,7 @@ void _update_keyboard_layouts() { k->set_pressed(ke.pressed); k->set_echo(ke.echo); k->set_scancode(ke.scancode); + k->set_physical_scancode(ke.physical_scancode); k->set_unicode(ke.unicode); push_input(k); @@ -3158,6 +3166,7 @@ void _update_keyboard_layouts() { k->set_pressed(ke.pressed); k->set_echo(ke.echo); k->set_scancode(0); + k->set_physical_scancode(0); k->set_unicode(ke.unicode); push_input(k); @@ -3169,6 +3178,7 @@ void _update_keyboard_layouts() { k->set_pressed(ke.pressed); k->set_echo(ke.echo); k->set_scancode(ke.scancode); + k->set_physical_scancode(ke.physical_scancode); if (i + 1 < key_event_pos && key_event_buffer[i + 1].scancode == 0) { k->set_unicode(key_event_buffer[i + 1].unicode); diff --git a/platform/uwp/app.cpp b/platform/uwp/app.cpp index 9ffd46cec306..8e2b6da5c25e 100644 --- a/platform/uwp/app.cpp +++ b/platform/uwp/app.cpp @@ -393,12 +393,14 @@ void App::key_event(Windows::UI::Core::CoreWindow ^ sender, bool p_pressed, Wind ke.type = OS_UWP::KeyEvent::MessageType::KEY_EVENT_MESSAGE; ke.unicode = 0; ke.scancode = KeyMappingWindows::get_keysym((unsigned int)key_args->VirtualKey); + ke.physical_scancode = KeyMappingWindows::get_scansym((unsigned int)key_args->KeyStatus.ScanCode); ke.echo = (!p_pressed && !key_args->KeyStatus.IsKeyReleased) || (p_pressed && key_args->KeyStatus.WasKeyDown); } else { ke.type = OS_UWP::KeyEvent::MessageType::CHAR_EVENT_MESSAGE; ke.unicode = char_args->KeyCode; ke.scancode = 0; + ke.physical_scancode = 0; ke.echo = (!p_pressed && !char_args->KeyStatus.IsKeyReleased) || (p_pressed && char_args->KeyStatus.WasKeyDown); } diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 374c3c476198..c8ad16a5e952 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -607,6 +607,7 @@ void OS_UWP::process_key_events() { key_event->set_control(kev.control); key_event->set_echo(kev.echo); key_event->set_scancode(kev.scancode); + key_event->set_physical_scancode(kev.physical_scancode); key_event->set_unicode(kev.unicode); key_event->set_pressed(kev.pressed); diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index c6ba24c6c7d7..4965b30e2634 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -61,6 +61,7 @@ class OS_UWP : public OS { MessageType type; bool pressed; unsigned int scancode; + unsigned int physical_scancode; unsigned int unicode; bool echo; CorePhysicalKeyStatus status; diff --git a/platform/windows/key_mapping_windows.cpp b/platform/windows/key_mapping_windows.cpp index 929dc086c8e6..a5feb8147afd 100644 --- a/platform/windows/key_mapping_windows.cpp +++ b/platform/windows/key_mapping_windows.cpp @@ -237,6 +237,104 @@ VK_PA1 (0xFD) VK_OEM_CLEAR (0xFE) */ +static _WinTranslatePair _scancode_to_keycode[] = { + + { KEY_ESCAPE, 0x01 }, + { KEY_1, 0x02 }, + { KEY_2, 0x03 }, + { KEY_3, 0x04 }, + { KEY_4, 0x05 }, + { KEY_5, 0x06 }, + { KEY_6, 0x07 }, + { KEY_7, 0x08 }, + { KEY_8, 0x09 }, + { KEY_9, 0x0A }, + { KEY_0, 0x0B }, + { KEY_MINUS, 0x0C }, + { KEY_EQUAL, 0x0D }, + { KEY_BACKSPACE, 0x0E }, + { KEY_TAB, 0x0F }, + { KEY_Q, 0x10 }, + { KEY_W, 0x11 }, + { KEY_E, 0x12 }, + { KEY_R, 0x13 }, + { KEY_T, 0x14 }, + { KEY_Y, 0x15 }, + { KEY_U, 0x16 }, + { KEY_I, 0x17 }, + { KEY_O, 0x18 }, + { KEY_P, 0x19 }, + { KEY_BRACELEFT, 0x1A }, + { KEY_BRACERIGHT, 0x1B }, + { KEY_ENTER, 0x1C }, + { KEY_CONTROL, 0x1D }, + { KEY_A, 0x1E }, + { KEY_S, 0x1F }, + { KEY_D, 0x20 }, + { KEY_F, 0x21 }, + { KEY_G, 0x22 }, + { KEY_H, 0x23 }, + { KEY_J, 0x24 }, + { KEY_K, 0x25 }, + { KEY_L, 0x26 }, + { KEY_SEMICOLON, 0x27 }, + { KEY_APOSTROPHE, 0x28 }, + { KEY_QUOTELEFT, 0x29 }, + { KEY_SHIFT, 0x2A }, + { KEY_BACKSLASH, 0x2B }, + { KEY_Z, 0x2C }, + { KEY_X, 0x2D }, + { KEY_C, 0x2E }, + { KEY_V, 0x2F }, + { KEY_B, 0x30 }, + { KEY_N, 0x31 }, + { KEY_M, 0x32 }, + { KEY_COMMA, 0x33 }, + { KEY_PERIOD, 0x34 }, + { KEY_SLASH, 0x35 }, + { KEY_SHIFT, 0x36 }, + { KEY_PRINT, 0x37 }, + { KEY_ALT, 0x38 }, + { KEY_SPACE, 0x39 }, + { KEY_CAPSLOCK, 0x3A }, + { KEY_F1, 0x3B }, + { KEY_F2, 0x3C }, + { KEY_F3, 0x3D }, + { KEY_F4, 0x3E }, + { KEY_F5, 0x3F }, + { KEY_F6, 0x40 }, + { KEY_F7, 0x41 }, + { KEY_F8, 0x42 }, + { KEY_F9, 0x43 }, + { KEY_F10, 0x44 }, + { KEY_NUMLOCK, 0x45 }, + { KEY_SCROLLLOCK, 0x46 }, + { KEY_HOME, 0x47 }, + { KEY_UP, 0x48 }, + { KEY_PAGEUP, 0x49 }, + { KEY_KP_SUBTRACT, 0x4A }, + { KEY_LEFT, 0x4B }, + { KEY_KP_5, 0x4C }, + { KEY_RIGHT, 0x4D }, + { KEY_KP_ADD, 0x4E }, + { KEY_END, 0x4F }, + { KEY_DOWN, 0x50 }, + { KEY_PAGEDOWN, 0x51 }, + { KEY_INSERT, 0x52 }, + { KEY_DELETE, 0x53 }, + //{ KEY_???, 0x56 }, //NON US BACKSLASH + { KEY_F11, 0x57 }, + { KEY_F12, 0x58 }, + { KEY_META, 0x5B }, + { KEY_META, 0x5C }, + { KEY_MENU, 0x5D }, + { KEY_F13, 0x64 }, + { KEY_F14, 0x65 }, + { KEY_F15, 0x66 }, + { KEY_F16, 0x67 }, + { KEY_UNKNOWN, 0 } +}; + unsigned int KeyMappingWindows::get_keysym(unsigned int p_code) { for (int i = 0; _vk_to_keycode[i].keysym != KEY_UNKNOWN; i++) { if (_vk_to_keycode[i].keycode == p_code) { @@ -249,6 +347,71 @@ unsigned int KeyMappingWindows::get_keysym(unsigned int p_code) { return KEY_UNKNOWN; } +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++) { + if (_scancode_to_keycode[i].keycode == p_code) { + keycode = _scancode_to_keycode[i].keysym; + break; + } + } + + if (p_extended) { + switch (keycode) { + case KEY_ENTER: { + keycode = KEY_KP_ENTER; + } break; + case KEY_SLASH: { + keycode = KEY_KP_DIVIDE; + } break; + case KEY_CAPSLOCK: { + keycode = KEY_KP_ADD; + } break; + } + } else { + switch (keycode) { + case KEY_NUMLOCK: { + keycode = KEY_PAUSE; + } break; + case KEY_HOME: { + keycode = KEY_KP_7; + } break; + case KEY_UP: { + keycode = KEY_KP_8; + } break; + case KEY_PAGEUP: { + keycode = KEY_KP_9; + } break; + case KEY_LEFT: { + keycode = KEY_KP_4; + } break; + case KEY_RIGHT: { + keycode = KEY_KP_6; + } break; + case KEY_END: { + keycode = KEY_KP_1; + } break; + case KEY_DOWN: { + keycode = KEY_KP_2; + } break; + case KEY_PAGEDOWN: { + keycode = KEY_KP_3; + } break; + case KEY_INSERT: { + keycode = KEY_KP_0; + } break; + case KEY_DELETE: { + keycode = KEY_KP_PERIOD; + } break; + case KEY_PRINT: { + keycode = KEY_KP_MULTIPLY; + } break; + } + } + + return keycode; +} + bool KeyMappingWindows::is_extended_key(unsigned int p_code) { return p_code == VK_INSERT || p_code == VK_DELETE || diff --git a/platform/windows/key_mapping_windows.h b/platform/windows/key_mapping_windows.h index 412426be9a83..54f5fee28b57 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_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 f6453d88436e..c013e562462c 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1212,6 +1212,7 @@ void OS_Windows::process_key_events() { k->set_metakey(ke.meta); k->set_pressed(true); k->set_scancode(KeyMappingWindows::get_keysym(ke.wParam)); + k->set_physical_scancode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24))); k->set_unicode(ke.wParam); if (k->get_unicode() && gr_mem) { k->set_alt(false); @@ -1245,6 +1246,8 @@ void OS_Windows::process_key_events() { k->set_scancode(KeyMappingWindows::get_keysym(ke.wParam)); } + k->set_physical_scancode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24))); + if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) { k->set_unicode(key_event_buffer[i + 1].wParam); } diff --git a/platform/x11/key_mapping_x11.cpp b/platform/x11/key_mapping_x11.cpp index e2808572ccc0..6aae428c38ec 100644 --- a/platform/x11/key_mapping_x11.cpp +++ b/platform/x11/key_mapping_x11.cpp @@ -179,6 +179,137 @@ static _XTranslatePair _xkeysym_to_keycode[] = { { 0, 0 } }; +struct _TranslatePair { + unsigned int keysym; + unsigned int keycode; +}; + +static _TranslatePair _scancode_to_keycode[] = { + + { KEY_ESCAPE, 0x09 }, + { KEY_1, 0x0A }, + { KEY_2, 0x0B }, + { KEY_3, 0x0C }, + { KEY_4, 0x0D }, + { KEY_5, 0x0E }, + { KEY_6, 0x0F }, + { KEY_7, 0x10 }, + { KEY_8, 0x11 }, + { KEY_9, 0x12 }, + { KEY_0, 0x13 }, + { KEY_MINUS, 0x14 }, + { KEY_EQUAL, 0x15 }, + { KEY_BACKSPACE, 0x16 }, + { KEY_TAB, 0x17 }, + { KEY_Q, 0x18 }, + { KEY_W, 0x19 }, + { KEY_E, 0x1A }, + { KEY_R, 0x1B }, + { KEY_T, 0x1C }, + { KEY_Y, 0x1D }, + { KEY_U, 0x1E }, + { KEY_I, 0x1F }, + { KEY_O, 0x20 }, + { KEY_P, 0x21 }, + { KEY_BRACELEFT, 0x22 }, + { KEY_BRACERIGHT, 0x23 }, + { KEY_ENTER, 0x24 }, + { KEY_CONTROL, 0x25 }, + { KEY_A, 0x26 }, + { KEY_S, 0x27 }, + { KEY_D, 0x28 }, + { KEY_F, 0x29 }, + { KEY_G, 0x2A }, + { KEY_H, 0x2B }, + { KEY_J, 0x2C }, + { KEY_K, 0x2D }, + { KEY_L, 0x2E }, + { KEY_SEMICOLON, 0x2F }, + { KEY_APOSTROPHE, 0x30 }, + { KEY_QUOTELEFT, 0x31 }, + { KEY_SHIFT, 0x32 }, + { KEY_BACKSLASH, 0x33 }, + { KEY_Z, 0x34 }, + { KEY_X, 0x35 }, + { KEY_C, 0x36 }, + { KEY_V, 0x37 }, + { KEY_B, 0x38 }, + { KEY_N, 0x39 }, + { KEY_M, 0x3A }, + { KEY_COMMA, 0x3B }, + { KEY_PERIOD, 0x3C }, + { KEY_SLASH, 0x3D }, + { KEY_SHIFT, 0x3E }, + { KEY_KP_MULTIPLY, 0x3F }, + { KEY_ALT, 0x40 }, + { KEY_SPACE, 0x41 }, + { KEY_CAPSLOCK, 0x42 }, + { KEY_F1, 0x43 }, + { KEY_F2, 0x44 }, + { KEY_F3, 0x45 }, + { KEY_F4, 0x46 }, + { KEY_F5, 0x47 }, + { KEY_F6, 0x48 }, + { KEY_F7, 0x49 }, + { KEY_F8, 0x4A }, + { KEY_F9, 0x4B }, + { KEY_F10, 0x4C }, + { KEY_NUMLOCK, 0x4D }, + { KEY_SCROLLLOCK, 0x4E }, + { KEY_KP_7, 0x4F }, + { KEY_KP_8, 0x50 }, + { KEY_KP_9, 0x51 }, + { KEY_KP_SUBTRACT, 0x52 }, + { KEY_KP_4, 0x53 }, + { KEY_KP_5, 0x54 }, + { KEY_KP_6, 0x55 }, + { KEY_KP_ADD, 0x56 }, + { KEY_KP_1, 0x57 }, + { KEY_KP_2, 0x58 }, + { KEY_KP_3, 0x59 }, + { KEY_KP_0, 0x5A }, + { KEY_KP_PERIOD, 0x5B }, + //{ KEY_???, 0x5E }, //NON US BACKSLASH + { KEY_F11, 0x5F }, + { KEY_F12, 0x60 }, + { KEY_KP_ENTER, 0x68 }, + { KEY_CONTROL, 0x69 }, + { KEY_KP_DIVIDE, 0x6A }, + { KEY_PRINT, 0x6B }, + { KEY_ALT, 0x6C }, + { KEY_ENTER, 0x6D }, + { KEY_HOME, 0x6E }, + { KEY_UP, 0x6F }, + { KEY_PAGEUP, 0x70 }, + { KEY_LEFT, 0x71 }, + { KEY_RIGHT, 0x72 }, + { KEY_END, 0x73 }, + { KEY_DOWN, 0x74 }, + { KEY_PAGEDOWN, 0x75 }, + { KEY_INSERT, 0x76 }, + { KEY_DELETE, 0x77 }, + { KEY_VOLUMEMUTE, 0x79 }, + { KEY_VOLUMEDOWN, 0x7A }, + { KEY_VOLUMEUP, 0x7B }, + { KEY_PAUSE, 0x7F }, + { KEY_SUPER_L, 0x85 }, + { KEY_SUPER_R, 0x86 }, + { KEY_MENU, 0x87 }, + { KEY_UNKNOWN, 0 } +}; + +unsigned int KeyMappingX11::get_scancode(unsigned int p_code) { + unsigned int keycode = KEY_UNKNOWN; + for (int i = 0; _scancode_to_keycode[i].keysym != KEY_UNKNOWN; i++) { + if (_scancode_to_keycode[i].keycode == p_code) { + keycode = _scancode_to_keycode[i].keysym; + break; + } + } + + return keycode; +} + 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 aa75eeaca54c..dbd294ad70eb 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_scancode(unsigned int p_code); static KeySym get_keysym(unsigned int p_code); static unsigned int get_unicode_from_keysym(KeySym p_keysym); static KeySym get_keysym_from_unicode(unsigned int p_unicode); diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 3f9b17372406..1a888ac504f5 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -1890,6 +1890,7 @@ void OS_X11::_handle_key_event(XKeyEvent *p_event, LocalVector &p_events if (status == XLookupChars) { bool keypress = xkeyevent->type == KeyPress; unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode); + unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode); if (keycode >= 'a' && keycode <= 'z') { keycode -= 'a' - 'A'; } @@ -1899,10 +1900,14 @@ void OS_X11::_handle_key_event(XKeyEvent *p_event, LocalVector &p_events for (int i = 0; i < tmp.length(); i++) { Ref k; k.instance(); - if (keycode == 0 && tmp[i] == 0) { + if (physical_keycode == 0 && keycode == 0 && tmp[i] == 0) { continue; } + if (keycode == 0) { + keycode = physical_keycode; + } + get_key_modifier_state(xkeyevent->state, k); k->set_unicode(tmp[i]); @@ -1910,12 +1915,14 @@ void OS_X11::_handle_key_event(XKeyEvent *p_event, LocalVector &p_events k->set_pressed(keypress); k->set_scancode(keycode); + k->set_physical_scancode(physical_keycode); k->set_echo(false); if (k->get_scancode() == KEY_BACKTAB) { //make it consistent across platforms. k->set_scancode(KEY_TAB); + k->set_physical_scancode(KEY_TAB); k->set_shift(true); } @@ -1944,6 +1951,7 @@ void OS_X11::_handle_key_event(XKeyEvent *p_event, LocalVector &p_events // keysym, so it works in all platforms the same. unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode); + unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode); /* Phase 3, obtain a unicode character from the keysym */ @@ -1963,10 +1971,14 @@ void OS_X11::_handle_key_event(XKeyEvent *p_event, LocalVector &p_events bool keypress = xkeyevent->type == KeyPress; - if (keycode == 0 && unicode == 0) { + if (physical_keycode == 0 && keycode == 0 && unicode == 0) { return; } + if (keycode == 0) { + keycode = physical_keycode; + } + /* Phase 5, determine modifier mask */ // No problems here, except I had no way to @@ -2028,12 +2040,14 @@ void OS_X11::_handle_key_event(XKeyEvent *p_event, LocalVector &p_events } k->set_scancode(keycode); + k->set_physical_scancode(physical_keycode); k->set_unicode(unicode); k->set_echo(p_echo); if (k->get_scancode() == KEY_BACKTAB) { //make it consistent across platforms. k->set_scancode(KEY_TAB); + k->set_physical_scancode(KEY_TAB); k->set_shift(true); }