jordansissel / xdotool

fake keyboard/mouse input, window management, and more
Other
3.18k stars 316 forks source link

key left stuck down by xdotool #384

Open jcbedacuk opened 2 years ago

jcbedacuk commented 2 years ago

If I send a key (let's call it q) to an application that has focus, and the application responds to the keydown event (sent via XTest) by quitting, then xdotool tries (and fails) to send the keyup by XSendEvent. This results in the XTest device key being down, and then q autorepeats in whatever window now has focus until cleared by pressing a physical version of the key. I'm not sure why it's necessary to use XTest normally (overriding an application's decision to ignore synthetic events should perhaps be a positive choice rather than a default). But given that it does, should it at least use the same value of use_xtest for an entire key sequence, rather than recomputing it for every event?

jordansissel commented 2 years ago

Hmm.. This does sound like odd behavior.

I can see a way (but haven't tested it) that xdotool might switch between XTEST and XSendEvent:

https://github.com/jordansissel/xdotool/blob/735e301665e7f9b8fe850588e88a3a0973695eec/xdo.c#L1546-L1554

When sending keys, if a window ID is non-zero, that is, you know which specific window to send keys to, xdotool will check if that window is currently focused, and if so, will use XTEST. If that window is not focused, then it uses XSendEvent.

This change was added in #85 due to #84.

I'm not sure why it's necessary to use XTest normally

Because too many programs ignore XSendEvent synthetic events which defeats the goals of xdotool. We try to make the best default choice, where possible, because a user wanting "Type the letter 'a'" should not have to know what XSendEvent and XTEST are, nor should they be required to understand any other deeper details about X11.

But given that it does, should it at least use the same value of use_xtest for an entire key sequence, rather than recomputing it for every event

I agree with you. It's worth revisiting how xdotool decides when to use XTEST vs XSendEvent and see about fixing your issue while at the same time not reviving the problem from #85/#84.

I can imagine some API changes that would make this simpler, though I haven't dug much into the code to see what changes might be needed.

gnab-gib-se commented 11 months ago

This is still an issue (not surprising since it's still open and no one has fixed it!):

$ xdotool --version
xdotool version 3.20211022.1
$ pacman -Qo /usr/lib/libxdo.so
/usr/lib/libxdo.so is owned by xdotool 3.20211022.1-1

and @jcbedacuk's description is spot-on.

As they stated, a straight-forward fix to this (no API changes required) would be to link keydown+keyup events sent by the same key event such that they cannot be sent via two different interfaces (keydown via XTEST and the subsequent keyup via XSendEvent in this case) resulting in the XTEST device ending up in an inconsistent state (and spamming a key repeatedly).

As in @jcbedacuk's case, mine was also caused by sending a key which closes the window. I tried using windowclose for this instead, but unfortunately in my case the window must be closed in a particular way to get the desired result so the appropriate key must be pressed (which for me is just Enter to select the default highlight button).

For anyone else stumbling into here in the future, after researching this issue and others which link to it I came up with the following workaround:

xdotool keydown --window ${windowid} Enter
xdotool keyup --window 0 Enter

This takes advantage of this comment from #85:

I think it's worth noting that doing key --window 0 a will send 'a' to the current window -- I don't know if this is documented, though. There's a special window value xdo uses for knowing when to act on the "current window" and that is 0.

and the code above to force the keyup to be sent to XTEST whether the ${windowid} was focused or not. In the event that it was focused (causing the keydown to be sent via XTEST) sending a keyup via XTEST to correct its state seems to be harmless to the current window (whatever it may be) and certainly more harmless than spamming keydown for that key instead.