Selaa lähdekoodia

Merge pull request #52684 from Frixuu/master

Rémi Verschelde 3 vuotta sitten
vanhempi
commit
a7011fa294

+ 8 - 0
doc/classes/DisplayServer.xml

@@ -276,6 +276,14 @@
 				[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
 			</description>
 		</method>
+		<method name="keyboard_get_keycode_from_physical" qualifiers="const">
+			<return type="int" enum="Key" />
+			<argument index="0" name="keycode" type="int" enum="Key" />
+			<description>
+				Converts a physical (US QWERTY) [code]keycode[/code] to one in the active keyboard layout.
+				[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+			</description>
+		</method>
 		<method name="keyboard_get_layout_count" qualifiers="const">
 			<return type="int" />
 			<description>

+ 18 - 0
platform/linuxbsd/display_server_x11.cpp

@@ -2068,6 +2068,24 @@ String DisplayServerX11::keyboard_get_layout_name(int p_index) const {
 	return ret;
 }
 
+Key DisplayServerX11::keyboard_get_keycode_from_physical(Key p_keycode) const {
+	unsigned int modifiers = p_keycode & KEY_MODIFIER_MASK;
+	unsigned int keycode_no_mod = p_keycode & KEY_CODE_MASK;
+	unsigned int xkeycode = KeyMappingX11::get_xlibcode((Key)keycode_no_mod);
+	KeySym xkeysym = XkbKeycodeToKeysym(x11_display, xkeycode, 0, 0);
+	if (xkeysym >= 'a' && xkeysym <= 'z') {
+		xkeysym -= ('a' - 'A');
+	}
+
+	Key key = KeyMappingX11::get_keycode(xkeysym);
+	// 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;

+ 1 - 0
platform/linuxbsd/display_server_x11.h

@@ -372,6 +372,7 @@ public:
 	virtual void keyboard_set_current_layout(int p_index) override;
 	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 void process_events() override;
 

+ 12 - 0
platform/linuxbsd/key_mapping_x11.cpp

@@ -309,6 +309,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;
+}
+
 Key KeyMappingX11::get_keycode(KeySym p_keysym) {
 	// kinda bruteforce.. could optimize.
 

+ 1 - 0
platform/linuxbsd/key_mapping_x11.h

@@ -45,6 +45,7 @@ class KeyMappingX11 {
 
 public:
 	static Key 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(Key p_code);
 	static unsigned int get_unicode_from_keysym(KeySym p_keysym);

+ 1 - 0
platform/osx/display_server_osx.h

@@ -305,6 +305,7 @@ public:
 	virtual void keyboard_set_current_layout(int p_index) override;
 	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 void process_events() override;
 	virtual void force_process_and_drop_events() override;

+ 154 - 134
platform/osx/display_server_osx.mm

@@ -930,146 +930,155 @@ static bool isNumpadKey(unsigned int key) {
 	return false;
 }
 
+// Keyboard symbol translation table
+static const Key _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_CTRL,
+	/* 3c */ KEY_SHIFT,
+	/* 3d */ KEY_ALT,
+	/* 3e */ KEY_CTRL,
+	/* 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 Key translateKey(unsigned int key) {
-	// Keyboard symbol translation table
-	static const Key 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_CTRL,
-		/* 3c */ KEY_SHIFT,
-		/* 3d */ KEY_ALT,
-		/* 3e */ KEY_CTRL,
-		/* 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,
-	};
-
 	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(Key key) {
+	for (int i = 0; i <= 126; i++) {
+		if (_osx_to_godot_table[i] == key) {
+			return i;
+		}
+	}
+	return 127;
 }
 
 struct _KeyCodeMap {
@@ -3200,6 +3209,17 @@ String DisplayServerOSX::keyboard_get_layout_name(int p_index) const {
 	return kbd_layouts[p_index].name;
 }
 
+Key DisplayServerOSX::keyboard_get_keycode_from_physical(Key p_keycode) const {
+	if (p_keycode == KEY_PAUSE) {
+		return p_keycode;
+	}
+
+	unsigned int modifiers = p_keycode & KEY_MODIFIER_MASK;
+	unsigned int keycode_no_mod = p_keycode & KEY_CODE_MASK;
+	unsigned int osx_keycode = unmapKey((Key)keycode_no_mod);
+	return (Key)(remapKey(osx_keycode, 0) | modifiers);
+}
+
 void DisplayServerOSX::_push_input(const Ref<InputEvent> &p_event) {
 	Ref<InputEvent> ev = p_event;
 	Input::get_singleton()->parse_input_event(ev);

+ 36 - 0
platform/windows/display_server_windows.cpp

@@ -1476,6 +1476,42 @@ String DisplayServerWindows::keyboard_get_layout_language(int p_index) const {
 	return String::utf16((const char16_t *)buf).substr(0, 2);
 }
 
+Key DisplayServerWindows::keyboard_get_keycode_from_physical(Key p_keycode) const {
+	unsigned int modifiers = p_keycode & KEY_MODIFIER_MASK;
+	Key keycode_no_mod = (Key)(p_keycode & KEY_CODE_MASK);
+
+	if (keycode_no_mod == KEY_PRINT ||
+			keycode_no_mod == KEY_KP_ADD ||
+			keycode_no_mod == KEY_KP_5 ||
+			(keycode_no_mod >= KEY_0 && keycode_no_mod <= KEY_9)) {
+		return p_keycode;
+	}
+
+	unsigned int scancode = KeyMappingWindows::get_scancode(keycode_no_mod);
+	if (scancode == 0) {
+		return p_keycode;
+	}
+
+	HKL current_layout = GetKeyboardLayout(0);
+	UINT vk = MapVirtualKeyEx(scancode, MAPVK_VSC_TO_VK, current_layout);
+	if (vk == 0) {
+		return p_keycode;
+	}
+
+	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 (Key)(char_code | modifiers);
+	}
+
+	return (Key)(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;

+ 1 - 0
platform/windows/display_server_windows.h

@@ -543,6 +543,7 @@ public:
 	virtual void keyboard_set_current_layout(int p_index) override;
 	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 int tablet_get_driver_count() const override;
 	virtual String tablet_get_driver_name(int p_driver) const override;

+ 10 - 0
platform/windows/key_mapping_windows.cpp

@@ -345,6 +345,16 @@ unsigned int KeyMappingWindows::get_keysym(unsigned int p_code) {
 	return KEY_UNKNOWN;
 }
 
+unsigned int KeyMappingWindows::get_scancode(Key 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++) {

+ 1 - 0
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(Key p_keycode);
 	static unsigned int get_scansym(unsigned int p_code, bool p_extended);
 	static bool is_extended_key(unsigned int p_code);
 };

+ 5 - 0
servers/display_server.cpp

@@ -285,6 +285,10 @@ String DisplayServer::keyboard_get_layout_name(int p_index) const {
 	return "Not supported";
 }
 
+Key DisplayServer::keyboard_get_keycode_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() {
 }
 
@@ -452,6 +456,7 @@ void DisplayServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("keyboard_set_current_layout", "index"), &DisplayServer::keyboard_set_current_layout);
 	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("process_events"), &DisplayServer::process_events);
 	ClassDB::bind_method(D_METHOD("force_process_and_drop_events"), &DisplayServer::force_process_and_drop_events);

+ 1 - 0
servers/display_server.h

@@ -343,6 +343,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 Key keyboard_get_keycode_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"; };