not-fl3 / miniquad

Cross platform rendering in Rust
Apache License 2.0
1.54k stars 173 forks source link

Linux keyboard event handling gives char and down events in reverse order to Windows and Mac #417

Open caspark opened 8 months ago

caspark commented 8 months ago

Summary

On Linux, char and key down events are issued in that order, whereas Mac and Windows issue them as key down first and char second. This inconsistency causes bugs downstream, such as breaking egui-miniquad's copy and cut operations on Linux.

Details

Linux code looks like this currently:

let keycode = (*event).xkey.keycode as libc::c_int;
let key = keycodes::translate_key(&mut self.libx11, self.display, keycode);
let repeat = self.repeated_keycodes[(keycode & 0xff) as usize];
self.repeated_keycodes[(keycode & 0xff) as usize] = true;
let mods = keycodes::translate_mod((*event).xkey.state as libc::c_int);
let mut keysym: KeySym = 0;
(self.libx11.XLookupString)(
    &mut (*event).xkey,
    std::ptr::null_mut(),
    0 as libc::c_int,
    &mut keysym,
    std::ptr::null_mut(),
);
let chr = keycodes::keysym_to_unicode(keysym);
if chr > 0 {
    if let Some(chr) = std::char::from_u32(chr as u32) {
        event_handler.char_event(chr, mods, repeat);
    }
}
event_handler.key_down_event(key, mods, repeat);

In other words, the char_event callback is called before the key_down_event callback. Meanwhile:

Impact

This inconsistency seems to be a cause of a bug in egui-miniquad for me: it is coded to ignore char events if the ctrl modifier is pressed, but the modifier state is only updated when the keydown event is received. So if I copy or cut some text on Linux, then the char event is received first and egui-miniquad has not yet recorded that ctrl is held down, which means that the char event is passed on to egui and the selection is replaced with x or c.

Obviously this could be fixed in egui-miniquad by also updating its modifier state in the char handler too (and this is how I am working around it currently), but if all platforms are able to emit keydown events before char events (i.e. we guarantee that ordering as part of the miniquad API) then that won't be necessary.