@@ -191,31 +191,34 @@ Vector<uint8_t> WaylandThread::_wp_primary_selection_offer_read(struct wl_displa
191
191
return Vector<uint8_t >();
192
192
}
193
193
194
- // Sets up an `InputEventKey` and returns whether it has any meaningful value.
195
- bool WaylandThread::_seat_state_configure_key_event (SeatState &p_ss, Ref<InputEventKey> p_event, xkb_keycode_t p_keycode, bool p_pressed) {
196
- xkb_keysym_t shifted_sym = xkb_state_key_get_one_sym (p_ss.xkb_state , p_keycode);
194
+ Ref<InputEventKey> WaylandThread::_seat_state_get_key_event (SeatState *p_ss, xkb_keycode_t p_keycode, bool p_pressed) {
195
+ Ref<InputEventKey> event;
197
196
198
- xkb_keysym_t plain_sym = XKB_KEY_NoSymbol;
197
+ ERR_FAIL_NULL_V (p_ss, event);
198
+
199
+ Key shifted_key = KeyMappingXKB::get_keycode (xkb_state_key_get_one_sym (p_ss->xkb_state , p_keycode));
200
+
201
+ Key plain_key = Key::NONE;
199
202
// NOTE: xkbcommon's API really encourages to apply the modifier state but we
200
203
// only want a "plain" symbol so that we can convert it into a godot keycode.
201
204
const xkb_keysym_t *syms = nullptr ;
202
- int num_sys = xkb_keymap_key_get_syms_by_level (p_ss. xkb_keymap , p_keycode, p_ss. current_layout_index , 0 , &syms);
205
+ int num_sys = xkb_keymap_key_get_syms_by_level (p_ss-> xkb_keymap , p_keycode, p_ss-> current_layout_index , 0 , &syms);
203
206
if (num_sys > 0 && syms) {
204
- plain_sym = syms[0 ];
207
+ plain_key = KeyMappingXKB::get_keycode ( syms[0 ]) ;
205
208
}
206
209
207
210
Key physical_keycode = KeyMappingXKB::get_scancode (p_keycode);
208
211
KeyLocation key_location = KeyMappingXKB::get_location (p_keycode);
209
- uint32_t unicode = xkb_state_key_get_utf32 (p_ss. xkb_state , p_keycode);
212
+ uint32_t unicode = xkb_state_key_get_utf32 (p_ss-> xkb_state , p_keycode);
210
213
211
214
Key keycode = Key::NONE;
212
215
213
- if (KeyMappingXKB::is_sym_numpad (shifted_sym) || KeyMappingXKB::is_sym_numpad (plain_sym) ) {
214
- keycode = KeyMappingXKB::get_keycode (shifted_sym) ;
216
+ if ((shifted_key & Key::SPECIAL) != Key::NONE || (plain_key & Key::SPECIAL) != Key::NONE ) {
217
+ keycode = shifted_key ;
215
218
}
216
219
217
220
if (keycode == Key::NONE) {
218
- keycode = KeyMappingXKB::get_keycode (plain_sym) ;
221
+ keycode = plain_key ;
219
222
}
220
223
221
224
if (keycode == Key::NONE) {
@@ -227,41 +230,70 @@ bool WaylandThread::_seat_state_configure_key_event(SeatState &p_ss, Ref<InputEv
227
230
}
228
231
229
232
if (physical_keycode == Key::NONE && keycode == Key::NONE && unicode == 0 ) {
230
- return false ;
233
+ return event ;
231
234
}
232
235
233
- p_event->set_window_id (DisplayServer::MAIN_WINDOW_ID);
236
+ event.instantiate ();
237
+
238
+ event->set_window_id (DisplayServer::MAIN_WINDOW_ID);
234
239
235
240
// Set all pressed modifiers.
236
- p_event ->set_shift_pressed (p_ss. shift_pressed );
237
- p_event ->set_ctrl_pressed (p_ss. ctrl_pressed );
238
- p_event ->set_alt_pressed (p_ss. alt_pressed );
239
- p_event ->set_meta_pressed (p_ss. meta_pressed );
241
+ event ->set_shift_pressed (p_ss-> shift_pressed );
242
+ event ->set_ctrl_pressed (p_ss-> ctrl_pressed );
243
+ event ->set_alt_pressed (p_ss-> alt_pressed );
244
+ event ->set_meta_pressed (p_ss-> meta_pressed );
240
245
241
- p_event ->set_pressed (p_pressed);
242
- p_event ->set_keycode (keycode);
243
- p_event ->set_physical_keycode (physical_keycode);
244
- p_event ->set_location (key_location);
246
+ event ->set_pressed (p_pressed);
247
+ event ->set_keycode (keycode);
248
+ event ->set_physical_keycode (physical_keycode);
249
+ event ->set_location (key_location);
245
250
246
251
if (unicode != 0 ) {
247
- p_event ->set_key_label (fix_key_label (unicode, keycode));
252
+ event ->set_key_label (fix_key_label (unicode, keycode));
248
253
} else {
249
- p_event ->set_key_label (keycode);
254
+ event ->set_key_label (keycode);
250
255
}
251
256
252
257
if (p_pressed) {
253
- p_event ->set_unicode (fix_unicode (unicode));
258
+ event ->set_unicode (fix_unicode (unicode));
254
259
}
255
260
256
261
// Taken from DisplayServerX11.
257
- if (p_event ->get_keycode () == Key::BACKTAB) {
262
+ if (event ->get_keycode () == Key::BACKTAB) {
258
263
// Make it consistent across platforms.
259
- p_event ->set_keycode (Key::TAB);
260
- p_event ->set_physical_keycode (Key::TAB);
261
- p_event ->set_shift_pressed (true );
264
+ event ->set_keycode (Key::TAB);
265
+ event ->set_physical_keycode (Key::TAB);
266
+ event ->set_shift_pressed (true );
262
267
}
263
268
264
- return true ;
269
+ return event;
270
+ }
271
+
272
+ // NOTE: Due to the nature of the way keys are encoded, there's an ambiguity
273
+ // regarding "special" keys. In other words: there's no reliable way of
274
+ // switching between a special key and a character key if not marking a
275
+ // different Godot keycode, even if we're actually using the same XKB raw
276
+ // keycode. This means that, during this switch, the old key will get "stuck",
277
+ // as it will never receive a release event. This method returns the necessary
278
+ // event to fix this if needed.
279
+ Ref<InputEventKey> WaylandThread::_seat_state_get_unstuck_key_event (SeatState *p_ss, xkb_keycode_t p_keycode, bool p_pressed, Key p_key) {
280
+ Ref<InputEventKey> event;
281
+
282
+ if (p_pressed) {
283
+ Key *old_key = p_ss->pressed_keycodes .getptr (p_keycode);
284
+ if (old_key != nullptr && *old_key != p_key) {
285
+ print_verbose (vformat (" %s and %s have same keycode. Generating release event for %s" , keycode_get_string (*old_key), keycode_get_string (p_key), keycode_get_string (*old_key)));
286
+ event = _seat_state_get_key_event (p_ss, p_keycode, false );
287
+ if (event.is_valid ()) {
288
+ event->set_keycode (*old_key);
289
+ }
290
+ }
291
+ p_ss->pressed_keycodes [p_keycode] = p_key;
292
+ } else {
293
+ p_ss->pressed_keycodes .erase (p_keycode);
294
+ }
295
+
296
+ return event;
265
297
}
266
298
267
299
void WaylandThread::_set_current_seat (struct wl_seat *p_seat) {
@@ -1920,13 +1952,19 @@ void WaylandThread::_wl_keyboard_on_key(void *data, struct wl_keyboard *wl_keybo
1920
1952
ss->repeating_keycode = XKB_KEYCODE_INVALID;
1921
1953
}
1922
1954
1923
- Ref<InputEventKey> k;
1924
- k.instantiate ();
1925
-
1926
- if (!_seat_state_configure_key_event (*ss, k, xkb_keycode, pressed)) {
1955
+ Ref<InputEventKey> k = _seat_state_get_key_event (ss, xkb_keycode, pressed);
1956
+ if (!k.is_valid ()) {
1927
1957
return ;
1928
1958
}
1929
1959
1960
+ Ref<InputEventKey> uk = _seat_state_get_unstuck_key_event (ss, xkb_keycode, pressed, k->get_keycode ());
1961
+ if (uk.is_valid ()) {
1962
+ Ref<InputEventMessage> u_msg;
1963
+ u_msg.instantiate ();
1964
+ u_msg->event = uk;
1965
+ wayland_thread->push_message (u_msg);
1966
+ }
1967
+
1930
1968
Ref<InputEventMessage> msg;
1931
1969
msg.instantiate ();
1932
1970
msg->event = k;
@@ -3236,15 +3274,18 @@ void WaylandThread::seat_state_echo_keys(SeatState *p_ss) {
3236
3274
int keys_amount = (ticks_delta / p_ss->repeat_key_delay_msec );
3237
3275
3238
3276
for (int i = 0 ; i < keys_amount; i++) {
3239
- Ref<InputEventKey> k;
3240
- k.instantiate ();
3241
-
3242
- if (!_seat_state_configure_key_event (*p_ss, k, p_ss->repeating_keycode , true )) {
3277
+ Ref<InputEventKey> k = _seat_state_get_key_event (p_ss, p_ss->repeating_keycode , true );
3278
+ if (!k.is_valid ()) {
3243
3279
continue ;
3244
3280
}
3245
3281
3246
3282
k->set_echo (true );
3247
3283
3284
+ Ref<InputEventKey> uk = _seat_state_get_unstuck_key_event (p_ss, p_ss->repeating_keycode , true , k->get_keycode ());
3285
+ if (uk.is_valid ()) {
3286
+ Input::get_singleton ()->parse_input_event (uk);
3287
+ }
3288
+
3248
3289
Input::get_singleton ()->parse_input_event (k);
3249
3290
}
3250
3291
0 commit comments