-
Notifications
You must be signed in to change notification settings - Fork 125
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
state: support querying whether virtual modifiers are active #36
base: master
Are you sure you want to change the base?
Conversation
This allows the user to query directly whether "NumLock", "Super", "Meta", "Alt" etc. are active, rather than resorting to the real modifiers or just guessing. This should help e.g. toolkits which have things like Meta in the modifier masks they report. Demo: $ sudo ./test/interactive keysyms [ Caps_Lock ] unicode [ ] group [ English (US) (0) ] mods [ ] leds [ ] keysyms [ A ] unicode [ A ] group [ English (US) (0) ] mods [ -Lock ] leds [ Caps Lock ] keysyms [ Num_Lock ] unicode [ ] group [ English (US) (0) ] mods [ Lock ] leds [ Caps Lock ] keysyms [ KP_1 ] unicode [ 1 ] group [ English (US) (0) ] mods [ Lock -Mod2 -NumLock ] leds [ Caps Lock Num Lock ] keysyms [ Shift_R ] unicode [ ] group [ English (US) (0) ] mods [ Lock Mod2 NumLock ] leds [ Caps Lock Num Lock ] keysyms [ a ] unicode [ a ] group [ English (US) (0) ] mods [ Shift Lock Mod2 NumLock ] leds [ Caps Lock Num Lock ] keysyms [ Meta_L ] unicode [ ] group [ English (US) (0) ] mods [ -Shift Lock Mod2 NumLock ] leds [ Caps Lock Num Lock ] keysyms [ Meta_L ] unicode [ ] group [ English (US) (0) ] mods [ -Shift Lock Mod2 NumLock ] leds [ Caps Lock Num Lock ] keysyms [ a ] unicode [ a ] group [ English (US) (0) ] mods [ Shift Lock Mod1 Mod2 NumLock Alt Meta ] leds [ Caps Lock Num Lock ] keysyms [ Super_L ] unicode [ ] group [ English (US) (0) ] mods [ Shift Lock Mod1 Mod2 NumLock Alt Meta ] leds [ Caps Lock Num Lock ] keysyms [ a ] unicode [ a ] group [ English (US) (0) ] mods [ Shift Lock Mod1 Mod2 Mod4 NumLock Alt Meta Super ] leds [ Caps Lock Num Lock ] keysyms [ Control_L ] unicode [ ] group [ English (US) (0) ] mods [ Shift Lock Mod1 Mod2 Mod4 NumLock Alt Meta Super ] leds [ Caps Lock Num Lock ] keysyms [ a ] unicode [ a ] group [ English (US) (0) ] mods [ Shift Lock Control Mod1 Mod2 Mod4 NumLock Alt Meta Super ] leds [ Caps Lock Num Lock ] Previously, NumLock, Alt, Meta, Super would not be here. To facilitate this support, we also add #defines for the names of the Meta, Super, Hyper and NumLock modifiers. These are set freely in xkeyboard-config, but are essentially treated as ABI there. Also, the standard explicitly recommends the names for NumLock, Alt and Meta: http://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#conventions We also change the define of Alt from "Mod1" to "Alt"; this is more correct, and safe. "Mod1" continues to work as before. One case that needs special consideration are the xkb_state_mod_indices_are_active() and mod_names_are_active() functions. By default, they perform an exclusive match on the modifiers that are passed to them. With virtual modifiers in the mix, you often get unexpected modifiers as well, which break it. I'm not really sure have exclusive-by-default is a good idea, because it also breaks when the user just pressed Num Lock of Caps Lock. However, for now we just revert to the old behavior of real-mods-only for these functions, which should be fine in most cases. We can revisit this later, when something more clever comes to mind. *** To get the virtual modifiers in, we essentially change just two things: 1. When SetMods/LockMods(modifiers=modMapMods) is used, we also add the modifiers in the key's vmodmap (in addition the key's modmap). The vmodmap of a key is set by virtualMod fields in interprets, or directly in the 'key' statements in xkb_symbols. It essentially contains the virtual modifiers that are bound to this key. 2. We no longer mask out virtual modifiers from the effective modifier masks in types, actions and indicators. This means mostly that if a type specifies e.g. "map[NumLock+LevelThree] = Level4", the active modifier mask in the state will in fact be matched against the NumLock and LevelThree modifiers. Together with 1, this works out nicely, and our tests all pass. Signed-off-by: Ran Benita <[email protected]>
This was, as you can probably guess from the comments and the code itself, my intention. But I never really managed to resolve a lot of you mentioned. Unfortunately I don't have any bright ideas on the subject either ... |
Perhaps it is better not to try to unify API between X11 and Wayland / evdev. X11 clients can do something like this: https://codereview.qt-project.org/#/c/253377/ . It is an experimental work-in-progress patch for some other issue, but the relevant parts for this topic are QXcbKeyboard::modifiers() and modMaskToIndex(uint mask). See also where modMaskToIndex() is called. For Wayland / evdev use case you could add xkb_state_mod_index_is_active2(), which uses virtual names. Having a separate function would avoid compatibility concerns. I don't know if that would make libxkbcommon internal code too complex.
One thing that I do not understand is why default xmodmap output on Ubuntu has this confusing Mod (with 'us' keyboard layout):
The only way how to know if the modifier in the 'state' is Alt or Meta is to look at the pressed keys. But keeping track of the pressed keys does not sound super reliable, probably WM global shortcuts or keyboard grabbing can make the things go out of sync. Without distinguishing the actual keysym, the API would report 2 modifiers as being active, right? ` |
We started to hit this in implementation of global shortcuts for KWin compositor. Any chance this issue could be reinforced? |
Here's a pure client-side hack that queries the entire keymap to find mapping between real modifiers and virtual modifiers using xkbcommon. This is part of my daily driver on Fedora 34 Plasma Wayland session. Is there a way to make this more efficient?
|
I have been playing with this and I found 2 interesting cases with Using
|
This is an old patch that I thought would be more visible in a PR. See the commit message for an explanation. It makes it possible for library users to query virtual modifiers directly (e.g.
Alt
,NumLock
) instead of only the 8 core mods.This is not safe to apply:
The major issue is that this will not work for xkbcommon-x11 -- the event that feeds the state to this library,
XkbStateNotify
, only sends real mods and not the virtual ones. For Wayland and evdev there is no such problem.We can work around this by mapping back real mods -> vmods, but this is lossy (either over-matching or under-matching, depending on the strategy) and not very nice.
This is backward-compatible, but not forward-compatible, i.e. if a program starts using
"Hyper"
for instance, it will fail silently (i.e. never active) in older versions. I also changed the definitions of a few mod names inxkbcommon-names.h
, which would cause the same problem if compiled on new version but run on old one.If a user does any sort of exclusive matching on the modifiers, this will suddenly fail, since new mods are added. I patched the
are_matching
functions to avoid it, but I prefer not to, and also most [all?] users useserialize_mods
instead of these functions.There are probably other unforeseen consequences...
However, I think if I can solve the first problem this will be a really nice thing to have, as users could finally forget about the obscure
ModX
mods and how they are mapped and use the nice names (which are also more precise).