Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

X11 backend processes at most one key event per frame #372

Open
Aeledfyr opened this issue Jan 21, 2025 · 1 comment
Open

X11 backend processes at most one key event per frame #372

Aeledfyr opened this issue Jan 21, 2025 · 1 comment

Comments

@Aeledfyr
Copy link

Related: #284

The X11 backend appears to only process one key event each frame, which causes input latency and input buffering when pressing many keys or running at low frame-rates. This appears to be the root cause of the #284, which patched it in that specific case by disabling key-repeat.

A minimal demo program, running at 1fps to make the issue more visible:

use minifb::{InputCallback, Key, Window};
use std::sync::atomic::{AtomicU32, Ordering};

static FRAME: AtomicU32 = AtomicU32::new(0);

struct Input;
impl InputCallback for Input {
    fn add_char(&mut self, _uni_char: u32) {}
    fn set_key_state(&mut self, key: Key, state: bool) {
        let frame = FRAME.load(Ordering::SeqCst);
        println!("State change (frame {frame:04}): {key:?} {state}");
    }
}

fn main() {
    let mut window = Window::new("key - ESC to exit", 400, 400, Default::default()).unwrap();

    window.set_target_fps(1);
    window.set_input_callback(Box::new(Input));

    while window.is_open() && !window.is_key_down(Key::Escape) {
        FRAME.fetch_add(1, Ordering::SeqCst);
        window.update();
    }
}

Running this, with some logging added in x11::Window::raw_process_events, gives this log for pressing a bunch of keys at the same time:

Show log

In the below log, Processed {n} pending events is printing count in x11::Window::raw_process_events, and Skipped by XFilterEvent is printed when the XFilterEvent condition skips an event.

frame 6: Processing 0 pending events
frame 7: Processing 0 pending events
frame 8: Processing 0 pending events
frame 9: Processing 7 pending events
Skipped by XFilterEvent
Skipped by XFilterEvent
Skipped by XFilterEvent
Skipped by XFilterEvent
Skipped by XFilterEvent
Skipped by XFilterEvent
Skipped by XFilterEvent
frame 10: Processing 8 pending events
Skipped by XFilterEvent
Processed 1 event
State change (frame 0010): A true
Skipped by XFilterEvent
Skipped by XFilterEvent
Skipped by XFilterEvent
Skipped by XFilterEvent
Skipped by XFilterEvent
Skipped by XFilterEvent
frame 11: Processing 2 pending events
Skipped by XFilterEvent
Skipped by XFilterEvent
frame 12: Processing 1 pending events
Processed 1 event
State change (frame 0012): S true
frame 13: Processing 1 pending events
Skipped by XFilterEvent
frame 14: Processing 1 pending events
Processed 1 event
State change (frame 0014): K true
frame 15: Processing 1 pending events
Skipped by XFilterEvent
frame 16: Processing 1 pending events
Processed 1 event
State change (frame 0016): F true
...

The trace above was for pressing 8 keys at once; the press and release events are spread across frames 9, 10, and 11, but the events are only processed one at a time on alternating frames after that.

This seems like an issue with the XFilterEvent system -- it's filtering out the original events, but then takes forever to send back the reconstructed events. Removing the filter call and just passing the events through normally fixes the latency and buffering issues, but I assume that would break X compose handling (as stated in the comment).

@emoon
Copy link
Owner

emoon commented Jan 21, 2025

It was introduced in this PR 2b25400 by @john01dav I'm not really sure what the correct solution would be here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants