Browse Source

Linux/BSD: Modify only keypad keys

The `keycode` field of `InputEventKey` is supposed to be "unshifted";
That is, what the key would output if no modifier keys were pressed.
This should match what's written on the key label, but `Key` enumerates
also all keypad keys, which require a modifier. We thus require some
extra checks for them.

Note that this can still allow "stuck keys", but that's an even deeper
problem.
Riteo 6 months ago
parent
commit
140a63be25

+ 24 - 0
platform/linuxbsd/wayland/key_mapping_xkb.cpp

@@ -369,6 +369,30 @@ void KeyMappingXKB::initialize() {
 	location_map[0x86] = KeyLocation::RIGHT;
 }
 
+bool KeyMappingXKB::is_sym_numpad(xkb_keysym_t p_keysym) {
+	switch (p_keysym) {
+		case XKB_KEY_KP_Multiply:
+		case XKB_KEY_KP_Divide:
+		case XKB_KEY_KP_Subtract:
+		case XKB_KEY_KP_Separator:
+		case XKB_KEY_KP_Add:
+		case XKB_KEY_KP_0:
+		case XKB_KEY_KP_1:
+		case XKB_KEY_KP_2:
+		case XKB_KEY_KP_3:
+		case XKB_KEY_KP_4:
+		case XKB_KEY_KP_5:
+		case XKB_KEY_KP_6:
+		case XKB_KEY_KP_7:
+		case XKB_KEY_KP_8:
+		case XKB_KEY_KP_9: {
+			return true;
+		} break;
+	}
+
+	return false;
+}
+
 Key KeyMappingXKB::get_keycode(xkb_keycode_t p_keysym) {
 	if (p_keysym >= 0x20 && p_keysym < 0x7E) { // ASCII, maps 1-1
 		if (p_keysym > 0x60 && p_keysym < 0x7B) { // Lowercase ASCII.

+ 1 - 0
platform/linuxbsd/wayland/key_mapping_xkb.h

@@ -56,6 +56,7 @@ class KeyMappingXKB {
 public:
 	static void initialize();
 
+	static bool is_sym_numpad(xkb_keysym_t p_keysym);
 	static Key get_keycode(xkb_keysym_t p_keysym);
 	static xkb_keycode_t get_xkb_keycode(Key p_keycode);
 	static Key get_scancode(unsigned int p_code);

+ 14 - 6
platform/linuxbsd/wayland/wayland_thread.cpp

@@ -193,18 +193,26 @@ Vector<uint8_t> WaylandThread::_wp_primary_selection_offer_read(struct wl_displa
 
 // Sets up an `InputEventKey` and returns whether it has any meaningful value.
 bool WaylandThread::_seat_state_configure_key_event(SeatState &p_ss, Ref<InputEventKey> p_event, xkb_keycode_t p_keycode, bool p_pressed) {
-	// NOTE: xkbcommon's API really encourages to apply the modifier state but we
-	// only want a "plain" symbol so that we can convert it into a godot keycode.
-	const xkb_keysym_t *syms = nullptr;
-	int num_sys = xkb_keymap_key_get_syms_by_level(p_ss.xkb_keymap, p_keycode, p_ss.current_layout_index, 0, &syms);
+	xkb_keysym_t shifted_sym = xkb_state_key_get_one_sym(p_ss.xkb_state, p_keycode);
 
 	Key physical_keycode = KeyMappingXKB::get_scancode(p_keycode);
 	KeyLocation key_location = KeyMappingXKB::get_location(p_keycode);
 	uint32_t unicode = xkb_state_key_get_utf32(p_ss.xkb_state, p_keycode);
 
 	Key keycode = Key::NONE;
-	if (num_sys > 0 && syms) {
-		keycode = KeyMappingXKB::get_keycode(syms[0]);
+
+	if (KeyMappingXKB::is_sym_numpad(shifted_sym)) {
+		keycode = KeyMappingXKB::get_keycode(shifted_sym);
+	}
+
+	if (keycode == Key::NONE) {
+		// NOTE: xkbcommon's API really encourages to apply the modifier state but we
+		// only want a "plain" symbol so that we can convert it into a godot keycode.
+		const xkb_keysym_t *syms = nullptr;
+		int num_sys = xkb_keymap_key_get_syms_by_level(p_ss.xkb_keymap, p_keycode, p_ss.current_layout_index, 0, &syms);
+		if (num_sys > 0 && syms) {
+			keycode = KeyMappingXKB::get_keycode(syms[0]);
+		}
 	}
 
 	if (keycode == Key::NONE) {

+ 32 - 5
platform/linuxbsd/x11/display_server_x11.cpp

@@ -3562,8 +3562,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
 	// XLookupString returns keysyms usable as nice keycodes.
 	char str[256] = {};
 	XKeyEvent xkeyevent_no_mod = *xkeyevent;
-	xkeyevent_no_mod.state &= ~ShiftMask;
-	xkeyevent_no_mod.state &= ~ControlMask;
+	xkeyevent_no_mod.state &= 0xFF00;
 	XLookupString(xkeyevent, str, 255, &keysym_unicode, nullptr);
 	XLookupString(&xkeyevent_no_mod, nullptr, 0, &keysym_keycode, nullptr);
 
@@ -3601,7 +3600,17 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
 
 		if (status == XLookupChars) {
 			bool keypress = xkeyevent->type == KeyPress;
-			Key keycode = KeyMappingX11::get_keycode(keysym_keycode);
+
+			Key keycode = Key::NONE;
+			if (KeyMappingX11::is_sym_numpad(keysym_unicode)) {
+				// Special case for numpad keys.
+				keycode = KeyMappingX11::get_keycode(keysym_unicode);
+			}
+
+			if (keycode == Key::NONE) {
+				keycode = KeyMappingX11::get_keycode(keysym_keycode);
+			}
+
 			Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
 
 			if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) {
@@ -3669,10 +3678,19 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
 		if (res == XKB_COMPOSE_FEED_ACCEPTED) {
 			if (xkb_compose_state_get_status(wd.xkb_state) == XKB_COMPOSE_COMPOSED) {
 				bool keypress = xkeyevent->type == KeyPress;
-				Key keycode = KeyMappingX11::get_keycode(keysym_keycode);
 				Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
 				KeyLocation key_location = KeyMappingX11::get_location(xkeyevent->keycode);
 
+				Key keycode = Key::NONE;
+				if (KeyMappingX11::is_sym_numpad(keysym_unicode)) {
+					// Special case for numpad keys.
+					keycode = KeyMappingX11::get_keycode(keysym_unicode);
+				}
+
+				if (keycode == Key::NONE) {
+					keycode = KeyMappingX11::get_keycode(keysym_keycode);
+				}
+
 				if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) {
 					keycode -= 'a' - 'A';
 				}
@@ -3733,7 +3751,16 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
 	// KeyMappingX11 just translated the X11 keysym to a PIGUI
 	// keysym, so it works in all platforms the same.
 
-	Key keycode = KeyMappingX11::get_keycode(keysym_keycode);
+	Key keycode = Key::NONE;
+	if (KeyMappingX11::is_sym_numpad(keysym_unicode)) {
+		// Special case for numpad keys.
+		keycode = KeyMappingX11::get_keycode(keysym_unicode);
+	}
+
+	if (keycode == Key::NONE) {
+		keycode = KeyMappingX11::get_keycode(keysym_keycode);
+	}
+
 	Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
 
 	KeyLocation key_location = KeyMappingX11::get_location(xkeyevent->keycode);

+ 24 - 0
platform/linuxbsd/x11/key_mapping_x11.cpp

@@ -1129,6 +1129,30 @@ void KeyMappingX11::initialize() {
 	location_map[0x86] = KeyLocation::RIGHT;
 }
 
+bool KeyMappingX11::is_sym_numpad(KeySym p_keysym) {
+	switch (p_keysym) {
+		case XK_KP_Multiply:
+		case XK_KP_Divide:
+		case XK_KP_Subtract:
+		case XK_KP_Separator:
+		case XK_KP_Add:
+		case XK_KP_0:
+		case XK_KP_1:
+		case XK_KP_2:
+		case XK_KP_3:
+		case XK_KP_4:
+		case XK_KP_5:
+		case XK_KP_6:
+		case XK_KP_7:
+		case XK_KP_8:
+		case XK_KP_9: {
+			return true;
+		} break;
+	}
+
+	return false;
+}
+
 Key KeyMappingX11::get_keycode(KeySym p_keysym) {
 	if (p_keysym >= 0x20 && p_keysym < 0x7E) { // ASCII, maps 1-1
 		if (p_keysym > 0x60 && p_keysym < 0x7B) { // Lowercase ASCII.

+ 1 - 0
platform/linuxbsd/x11/key_mapping_x11.h

@@ -61,6 +61,7 @@ class KeyMappingX11 {
 public:
 	static void initialize();
 
+	static bool is_sym_numpad(KeySym p_keysym);
 	static Key get_keycode(KeySym p_keysym);
 	static unsigned int get_xlibcode(Key p_keysym);
 	static Key get_scancode(unsigned int p_code);