Repository: godotengine/godot (language: cpp)

Issue:
[Linux] Numpad period key issues with `fr+oss` layout
### Tested versions

- Reproducible on master https://github.com/godotengine/godot/commit/36d90c73a843afa2807a0b8dcbfbf52bdb8a759c
- Reproducible on 4.3.beta3

### System information

Godot v4.4.beta (f0f5319b0) - Fedora Linux 41 (Workstation Edition) on Wayland - Wayland display driver, Single-window, 1 monitor - Vulkan (Forward+) - dedicated AMD Radeon RX Vega (RADV VEGA10) - AMD Ryzen 7 5800X 8-Core Processor (16 threads)

### Issue description

Read https://github.com/godotengine/godot/issues/102404#issuecomment-2644083394

> As requested, here are the System Infos:
> 
> > Godot v4.4.beta3 - Arch Linux [#1](https://github.com/godotengine/godot/issues/1) SMP PREEMPT_DYNAMIC Sun, 02 Feb 2025 01:02:29 +0000 on Wayland - Wayland display driver, Single-window, 1 monitor - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1650 (nvidia; 570.86.16) - Intel(R) Core(TM) i5-9300H CPU @ 2.40GHz (8 threads)
> 
> My window manager is Hyprland.
> 
> My keyboard layout is `fr_FR` and I tried from my laptop numpad and an external USB one. I also tested checking and unchecking "Prefer Wayland" in the editor settings, but both give the same result: the numpad `period` triggers the `delete` event.
> 
> Using Godot v4.4.beta1 gives the normal behavior. Using Godot v4.4.beta2 does not have numbers at all plus the `period` triggers `delete` as well. Using Godot v4.4.beta3 gives correct numbers but `period` triggers `delete`.
> 
> I tried to toggle the Num Lock button of course, but it does not affect the `period` button in Godot v4.4.beta3 and it does not affect any numpad key in Godot v4.4.beta2.
> 
> Changing my keyboard layout to `en` fixes the issue though. I hope this helps.
> 
> If you need more infos, don't hesitate to ask.



### Steps to reproduce

On X11 or Wayland:
- change your keyboard layout to `fr+oss`
- open the GDScript editor
- put some text
- try to add a period from the keypad
- see that it deletes instead

### Minimal reproduction project (MRP)

n/a


Discussion / hints:

Fix patch:
diff --git a/platform/linuxbsd/wayland/key_mapping_xkb.cpp b/platform/linuxbsd/wayland/key_mapping_xkb.cpp
index 04d8496c0838..99a98321adf8 100644
--- a/platform/linuxbsd/wayland/key_mapping_xkb.cpp
+++ b/platform/linuxbsd/wayland/key_mapping_xkb.cpp
@@ -378,6 +378,7 @@ bool KeyMappingXKB::is_sym_numpad(xkb_keysym_t p_keysym) {
 		case XKB_KEY_KP_Divide:
 		case XKB_KEY_KP_Separator:
 		case XKB_KEY_KP_Decimal:
+		case XKB_KEY_KP_Delete:
 		case XKB_KEY_KP_0:
 		case XKB_KEY_KP_1:
 		case XKB_KEY_KP_2:
diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp
index 6155d9e3675d..d2a9fde3ee67 100644
--- a/platform/linuxbsd/wayland/wayland_thread.cpp
+++ b/platform/linuxbsd/wayland/wayland_thread.cpp
@@ -195,24 +195,27 @@ Vector<uint8_t> WaylandThread::_wp_primary_selection_offer_read(struct wl_displa
 bool WaylandThread::_seat_state_configure_key_event(SeatState &p_ss, Ref<InputEventKey> p_event, xkb_keycode_t p_keycode, bool p_pressed) {
 	xkb_keysym_t shifted_sym = xkb_state_key_get_one_sym(p_ss.xkb_state, p_keycode);
 
+	xkb_keysym_t plain_sym = XKB_KEY_NoSymbol;
+	// 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) {
+		plain_sym = syms[0];
+	}
+
 	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 (KeyMappingXKB::is_sym_numpad(shifted_sym)) {
+	if (KeyMappingXKB::is_sym_numpad(shifted_sym) || KeyMappingXKB::is_sym_numpad(plain_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]);
-		}
+		keycode = KeyMappingXKB::get_keycode(plain_sym);
 	}
 
 	if (keycode == Key::NONE) {
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index cbf963c59a0e..e35b6e84e2e1 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -3765,7 +3765,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
 	// keysym, so it works in all platforms the same.
 
 	Key keycode = Key::NONE;
-	if (KeyMappingX11::is_sym_numpad(keysym_unicode)) {
+	if (KeyMappingX11::is_sym_numpad(keysym_unicode) || KeyMappingX11::is_sym_numpad(keysym_keycode)) {
 		// Special case for numpad keys.
 		keycode = KeyMappingX11::get_keycode(keysym_unicode);
 	}
diff --git a/platform/linuxbsd/x11/key_mapping_x11.cpp b/platform/linuxbsd/x11/key_mapping_x11.cpp
index 8a138f4bb476..b9c50825886f 100644
--- a/platform/linuxbsd/x11/key_mapping_x11.cpp
+++ b/platform/linuxbsd/x11/key_mapping_x11.cpp
@@ -1138,6 +1138,7 @@ bool KeyMappingX11::is_sym_numpad(KeySym p_keysym) {
 		case XK_KP_Divide:
 		case XK_KP_Separator:
 		case XK_KP_Decimal:
+		case XK_KP_Delete:
 		case XK_KP_0:
 		case XK_KP_1:
 		case XK_KP_2:


Test patch: