mooz / xkeysnail

Yet another keyboard remapping tool for X environment
891 stars 112 forks source link

Making multi-keystroke macros more reliable? #150

Open RedBearAK opened 2 years ago

RedBearAK commented 2 years ago

I've noticed that when trying to use macros they have a tendency to somehow crash or just stop outputting in the middle. Specifically this is with a multi-keystroke type of macro, like:

[K("x"), K("y"), K("z"), K("Space"), K("x"), K("y"), K("z"), K("Enter")], 

Ordinarily I would expect this to output:

xyz xyz
xyz xyz
xyz xyz
xyz xyz

With one line for each time I trigger the shortcut.

But what often happens, even if I wait a second between each trigger of the shortcut, is things like this:

xyz xyz
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xxyz xyz
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xx
xyz xyz
xyz xyz
xyz xyz
xyz xyz
xxyz xyz
xyz xyz
xyz xyz
xyz xyz
xyxyz xyz
xyz xyz
xyz xyz
xyzxyz xyz
xyz xyz
xy
xyz xyz
xyz xyz
xyz xyz

I thought maybe the more keys in the macro, the more likely one of these hiccups will happen. But it actually often seems to happen right near the beginning of the macro sequence, if it's going to happen at all. Notice how there are a number of lines where the macro stopped after the first, second or third character, but really no lines that stop near the end.

Is there any way to tighten up the code to keep this from happening? Seems like the function responsible just develops a poor working memory at times. Or a buffer is getting overwhelmed with keystrokes coming in too fast? Maybe the keystrokes need a few milliseconds of delay before the next one?

I don't know, I'm just throwing out ideas here.

@mooz @Lenbok @rbreaves

joshgoebel commented 2 years ago

And didn't we already figure out that this problem is basically nonexistent outside of the Kinto branch of xkeysnail?

Did we? Did you? That's not something I can confirm. I can't reproduce it, but that doesn't mean it's not an issue... but you've tried my code and 0.4.0... does the issue magically go away? If so then I'd consider it fixed. If you're still having the issue on 0.4.0 or my codebase then I'd say there is something deeper going on.

joshgoebel commented 2 years ago

I mean my version (and kinto mainline) sends a lot less bogus events, so that [seems to] HELP, but did it FIX it? I dunno... you tell me. :)

RedBearAK commented 2 years ago

@joshgoebel

I don't think there's strong evidence that it's never a problem on the other branches, necessarily, just that it doesn't seem to happen there in an easily replicateable way. I just want to make sure there's real evidence here that it's somehow a libinput problem that libinput could, and should, fix.

joshgoebel commented 2 years ago

I just want to make sure there's real evidence here that it's somehow a libinput problem that libinput could, and should, fix.

Well, just because it doesn't happen doesn't mean we're actually fixing the problem... it sounds like something is out of whack - things should not just "get lost" (or corrupted) between the Linux layer and the X layer... so your last tests likely proves there is some problem somewhere - for reals. And libinput would be the first place to check - they might have ideas to go further.

IE, it could be kinto is a "best case" for putting the right kind of pressure on the system to reveal the problem - not that it's itself causing it. But hard to say.

If you're not really experiencing it anymore I'm happy to let this drop on the floor for now... enough things to focus on.

ian-h-chamberlain commented 1 year ago

Sorry to revive an old issue but, from reading the thread I'm not sure exactly what the workaround is, and I started experiencing this myself. @RedBearAK where did you actually put the sleep you mentioned, and how long is it? I'd love to apply the same kind of workaround if possible.

RedBearAK commented 1 year ago

@ian-h-chamberlain

So, the fundamental problem here is that something (kernel input?) seems to get confused on the timing of the modifier key press-release cycle, which is theoretically being "pressed" before the non-modifier key it is supposed to affect, and "released" after that key is released.

This was an order of magnitude worse inside some GNOME Boxes virtual machines I was testing. To the point where even a lot of common shortcut combos were failing to do what was expected. On bare metal the issue is usually fixed with just a millisecond or so of "space" around the "normal" key press. In the VMs it took adding a window of about 50ms before and 70ms after the "normal" key press-release to provide a 99.9% cure for the issue.

I haven't used xkeysnail for several months, replacing it with Josh Goebel's fork keyszer, which has a number of new features and bug fixes, and some significantly different behavior in some ways. I worked out an API function that would insert a configurable delay inside the keymapper at the place that seemed the most effective after doing a LOT of testing. So the easiest way to deal with this problem is to switch to keyszer and use this in your config file to inject some delays appropriate to your situation.

throttle_delays(
    key_pre_delay_ms    = 2,    # default: 0 ms, range: 0 to 150 ms, suggested: 1-50 ms
    key_post_delay_ms   = 4,    # default: 0 ms, range: 0 to 150 ms, suggested: 1-100 ms
)

This is just an example from my bare metal install on Fedora, on a mid-range Ryzen laptop.

Here's the pull request that added the new API function. The delays are in the send_combo() function, in output.py.

https://github.com/joshgoebel/keyszer/pull/134/files

The new API is in mainline keyszer, so if you download the latest state from the green button on GitHub or do the below commands to get it, this feature should be there.

cd ~/Downloads
git clone https://github.com/joshgoebel/keyszer
cd keyszer
pip install --upgrade .
ian-h-chamberlain commented 1 year ago

Thanks for the detailed steps -- I had been considering switching to keyszer for a while anyway, so maybe this is another good reason to do it. I guess I was sort of hoping https://github.com/rbreaves/kinto/issues/718 might happen before I decided to switch, but I have enough custom stuff + issues at this point maybe I should just bite the bullet and swap over.

RedBearAK commented 1 year ago

@ian-h-chamberlain

There's a custom config in the comments on this pull request, along with some instructions for setting up keyszer that a few people have found useful. The two files in the "Files" tab of the page can be downloaded "raw" and used as a Kinto config, following the instructions in the comment.

https://github.com/rbreaves/kinto/pull/750#issuecomment-1451170466

Or, a much newer version of the config that I'm currently using is posted further down in the thread, which does not require messing with the keyboard type modmaps. With the last version I posted in the thread there may be a problem with an extra extension on one of the "include" files, like ".py.py". Have to fix that. Otherwise, it should be a good starting point for a Kinto-like config for keyszer. But with some new features. Like the automated keyboard types.