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

Keyboard input under high load #520

Open
2e0byo opened this issue Mar 13, 2023 · 7 comments
Open

Keyboard input under high load #520

2e0byo opened this issue Mar 13, 2023 · 7 comments
Assignees
Labels
bug Something isn't working

Comments

@2e0byo
Copy link
Contributor

2e0byo commented Mar 13, 2023

Under high load or when typing rapidly, with winit (winit/glutin), keyboard input is frequently incorrect, e.g. enter becomes m, backspaces becomes h, tab becomes i. Clearly this is a translation problem between the event and the emacs key.

Adding flyspell mode to a buffer helps when reproducing this.

[I've decided to focus on glutin/winit this end, as the gtk gl code is apparently ridiculously slow. This is a bug in either gtk or hyprland, but I've not got the strength to work out which...]

[edit] to reproduce with spacemacs, hit SPC w TAB quickly enough and watch the complaint about SPC w i not being defined.

@2e0byo 2e0byo added the bug Something isn't working label Mar 13, 2023
@2e0byo 2e0byo self-assigned this Mar 13, 2023
@2e0byo
Copy link
Contributor Author

2e0byo commented Mar 13, 2023

The root cause is the input loop not reacting quickly enough. When a key is missed there's a missing KeyboardInput pressed event. The character event almost always lands, and always after the pressed event; since on winit we disable character events when a known key is pressed and re-enable when the released event is received, sometimes the character event then propagates through. Emacs doesn't expect to receive non-char keys this way, hence the translation (e.g. ^M for m).

Separately, keycode_to_emacs_key_name is used in two places: once to convert symbols, and here just to see if the key matches at all. Hopefully the compiler has optimised our call here ;)

Unfortunately Emacs really does want to handle keypresses itself. We could handle them all ourselves and then generate keypresses (e.g. C-c would generate C and then c), but the real solution is just to tune the event loop so it doesn't miss inputs.

@declantsien
Copy link
Contributor

If tao's keyboard input was working for you. You could always try winit new-keyboard-v3 branch.
As far as I know, tao's initial fork is based on this branch.
Not sure when this branch is going to merge into master.

I put some initial work here. You can test it out to see whether it works or not.

@2e0byo
Copy link
Contributor Author

2e0byo commented Mar 14, 2023

I saw that: there's a lot of work landing on winit all at once (an open PR for popup windows, for instance). But I think even tao was missing events (particularly resize events when opening new frames). I'm going to try ignoring the comments saying we have to run the event loop in the main thread, stick it in a background thread and pass events as messages via a queue. This should also cure some little problems with window coding tying up emacs' own pselect loop and generally improve responsiveness.

I think the tao event code works better purely because there are fewer events.

What was the problem with running the winit event loop in a new thread on macos?

@declantsien
Copy link
Contributor

declantsien commented Mar 14, 2023 via email

@2e0byo
Copy link
Contributor Author

2e0byo commented Mar 14, 2023

You may want to commented out these line[0], and test whether that is the cause. It is the fix for C-g been not working while Emacs is blocking.

Annoyingly this does cure it. But I don't understand why, as poll_a_event will catch and return the keyboard event, and then that code will push it into the events vector to be handled properly. Whereas some key pressed events were not getting through at all. I need to look at this with a fresh brain at some point.

What was the problem with running the winit event loop in a new thread on macos?

Drat. Somehow I'd missed winit's control inversion. How annoying. I might still play with any_thread() but that would obviously be linux only. The only other option other than using a hack like winit_main (which spawns a new thread and runs your main in that) would require moving the rest of the rust-side to a new thread; drat. At least now I can see why much better programmers than me didn't do what seemed so obvious to me :D

@declantsien
Copy link
Contributor

Would you like to try out the master branch with
./configure --with-winit --with-webrender.

Turns out we don't event_loop related code. We just need to register io fd using init_sigio,
and then pump events from read_socket_hook from terminal.

@2e0byo
Copy link
Contributor Author

2e0byo commented Mar 6, 2024

oh! that's cool. I'll get this building again and try it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants