You are not logged in.
Hi, cross posting from https://unix.stackexchange.com/question … -detection because it got 22 views over 14 days, and probably like 18 views are from myself... let me know if this is not ok to cross post
This is the developer of skippy-xd, which has been under active development with many new features in https://github.com/felixfung/skippy-xd!
Youtube demos are here: https://www.youtube.com/watch?v=R__zua04xe0 https://www.youtube.com/watch?v=reUDapFGnmQ https://www.youtube.com/watch?v=lS33Z2s8xrs
I would like to ask about different Unix/Linux solutions and mechanisms to keys binding, key holding and key detection.
Skippy-xd always has Alt-Tab solution, and can do the same for expose like modes. It is set up by the user using xbindkey or similar to bind to skippy-xd --switch --next, and then setting Alt as a pivot key. When skippy-xd is being activated, it detects whether the pivot key is being held; when the pivot key is not being held, skippy-xd deactivates and selects the focused window.
https://youtu.be/lS33Z2s8xrs?si=wkGJ0sqGrFTwwXVa&t=459
Recently, I realized the design/implementation was not complete: a user should be able to designate a pivot key (for example F11 or Super/Meta key, or even the new copilot key...) for expose and use it without a next command. The usage would be when the user press and hold F11/Super, the user can select with mouse and/or up/down/left/right, and when the user releases, skippy-xd would terminate and select the focused window.
I have implemented this successfully, except when the pivot key is set and held, other keys, including up/down/left/right, would not be registered. Here is where I would like to ask about Unix/Linux keys.
When I test with xev (without any hot keys set), holding F11 and after a delay hold n, it would first show rapid alternate KeyPress and KeyRelease events for F11, and then when n is pressed, KeyPress and KeyRelease events for n would register. Hence, I think in general, holding a key would not block pressing/holding another one.
However, when I debug the source code of skippy-xd,
while ((num_events = XEventsQueued(ps->dpy, QueuedAfterReading)))
{
// the while loop and XNextEvent() are existing code for event detection
XNextEvent(ps->dpy, &ev);
// this is for debugging purpose, to see if X events are detected at all
if (ev.type == KeyPress || ev.type == KeyRelease) {
XKeyEvent * const evk = &ev.xkey;
printfdf(true, "(): KeyPress | KeyRelease, keycode: %d:", evk->keycode);
}
// ...
When I set up with pivot key F11, use xbindkeys to bind F11 with skippy-xd --expose, and hold F11 to activate skippy-xd, and then tap/hold n, no logging will be produced. This is in contrast with when I don't set pivot key with F11, and do not bind F11 with skippy-xd --expose, when I activate skippy-xd, then hold F11, and then tap/hold n, logging of the key press and key release events are produced.
I interpret this as strange combinations/interference between the X key registration, key bindings, and even window focus state, although I am not certain.
I would like to ask what exactly is happening in terms of X key events, and what solutions for app key binding and coding key detection would be possible?
Thanks.
Update:
Mouse selection has always been working in this "pivot mode". I have verified X event registration on this:
if (mw && MotionNotify == ev.type)
{
// print to verify X event is registered
printfdf(true, "(): !!!");
// when mouse move within a client window, focus on it
// ...
Hence the issue is not that the event is not detected due to short-circuited event detection loop, but most probably that the keyboard event(s) were never registered in the first place, indicating the root cause of the issue is related to X key binding.
Any help would be appreciated. Thanks!
Last edited by felixfung (2024-09-08 03:47:55)
Offline
The shortcut daemon grabs the key and becomes its exclusive receiver and if you keep an autorepeating key down it'll fire like crazy, depending on what you bound it to, your process doesn't even live long enough to see the subsequent keypress.
Check xev whether F11 is keycode 95 and then run "xset -r 95", check xev again, the autorepeat should™ be gone.
=> does that cause the desired behavior?
The sane approach to this is to become your own shortcut daemon for the pivot key and discriminate the event handling by the internal state of your process.
---
let me know if this is not ok to cross post
This belongs into https://bbs.archlinux.org/viewforum.php?id=33 but as long as you're actually using arch I don't see anything wrong with asking this here.
You should however sync major developments between the boards because https://xkcd.com/979/
Offline
Check xev whether F11 is keycode 95 and then run "xset -r 95", check xev again, the autorepeat should™ be gone.
=> does that cause the desired behavior?
That's actually a brilliant idea, I didn't know/think of using xset to troubleshoot/debug this.
I confirmed F11 is 95 and did "xset -r 95", and confirmed autorepeat is gone, and on xev that e.g. F11 would not be blocking F12 *in the absence of xbindkeys on F11*.
However, the behaviour is identical to before.
In particular, with the debugging prints as before, it looks like hen F11 is held, mouse movements events can still be triggered, while keyboard events would not.
Hence I am still leaning to my guess that X binding is interfering with keyboard events?
Offline
The shortcut daemon will likely maintain the grab until the key is released.
You could possibly use the crest extension (for testing using xdotool) to release the key, grab the input and press it again, but as mentioned, the reasonable approach here is to become your own shortcut daemon.
Offline
I took some time to work on this again, and I realized when xbindkeys are NOT in use, there is NO issue with triggering the "pivot" key and/or the up/down/left/right key events, confirming it is xbindkeys and similar that is intercepting/grabbing the keys.
A quick code inspection (not 100% certain) of the source code of xbindkeys confirm that XGrabKey() is used. I find the English in the documentation of XGrabKey() to be really tough to understand while that of XGrabKeyboard() makes more sense. Would you be able confirm these two calls register the app/window to exclusively capture the relevant X events, in simple terms? https://tronche.com/gui/x/xlib/input/XGrabKey.html https://tronche.com/gui/x/xlib/input/XGrabKeyboard.html
If that's the case, then it is as you have been saying all along, that the hot key daemon(s) put itself as the exclusive receiver of the key, and implementing my bit of key detection independent of 3rd party daemons is needed. I have some idea how to do this, and I think overall it is perhaps a good approach going forward...
Offline
Yes, XGrabKeyboard grabs the entire keyboard, XGrabKey the selected keycode + modifiers and no other client (incl. skippy) will them unless and until XAllowEvents is used to replay the event.
implementing my bit of key detection independent of 3rd party daemons … is perhaps a good approach going forward
Offline
Hi Seth,
I have been working on a PR with a complete redesign of the relevant user interface based on what we discussed, to implement key detection on skippy-xd independent of any 3rd party hot key daemons: https://github.com/felixfung/skippy-xd/pull/140
And just then I found out: I can bypass the 3rd party hot key daemon key grab with e.g. an xbindkey config like this:
"skippy-xd --expose && killall xbindkeys && xbindkeys"
Super_L
"skippy-xd --paging && killall xbindkeys && xbindkeys"
F12
and setting the "pivot key" in the skippy-xd config file with
keysPivotSwitch = Alt_L
keysPivotExpose = Super_L
keysPivotPaging = F12
This hack ungrabs the "pivot" keys, and allows up/down/left/right/next/prev during "pivot" mode of skippy-xd, without any code change on skippy-xd. The keys Super_L and F12 are chosen strategically as one is a modifier key and the other is not. Both keys are tested to my current satisfaction.
I guess I have to sit back to think about which of the two approaches are superior, but on top of my head I actually prefer this xbindkeys hack. The reasons are as follows:
1. So far the skippy-xd set up is VERY clean and simple: use your favoured 3rd party app to set up hot key, and put in a "pivot" key in "pivot" mode.
2. So far the skippy-xd implementation is VERY simple: reading a named pipe's command to trigger activation, and if it is "pivot" mode, then scan the "pivot" key's holding status to release activation.
3. This allows foolproof user set up; in fact it works by default. In addition, set up with mouse hot corners or panel button activation is simple. In fact, activation is delegated to these 3rd party apps. This is in fact the UNIX/Linux philosophy.
4. The PR where skippy-xd acts as its own hot key daemon I am working on is pretty much working, except X11 is *#^$*!, and I need to iron out some details. This has always been my experience when I need to code directly on X11. Just this alone I prefer avoiding the nuisances of implementing hot key detection within skippy-xd, because it would introduce small bugs and edge cases here and there in skippy-xd, whereas 3rd party hot key daemons probably are pretty well tested.
You have always given quick and valuable responses and I would value it again, although to be honest so far I am heavily leaning towards the xbindkeys hack
Last edited by felixfung (2024-11-12 02:33:21)
Offline
And just then I found out: I can bypass the 3rd party hot key daemon key grab with e.g. an xbindkey config like this:
You're exploiting a race condition, that's not elegant nor reliable nor efficient not pretty nor smart and if it goes wrong the user will end up w/o their shortcut daemon.
Abandon that idea.
If you don't want to make skippy a shortcut daemon, you could allow some IPC mode where the invocation of "skippy-xd --expose" either starts skippy or sends a message (can be as simple a SGUSR1) to a running skippy-xd process which then intercepts that signal to operate the active expose mode.
Offline