struct Binding {
/** If true, the binding should be executed upon a KeyRelease event, not a
* KeyPress (the default). */
- bool release;
+ enum {
+ /* This binding will only be executed upon KeyPress events */
+ B_UPON_KEYPRESS = 0,
+ /* This binding will be executed either upon a KeyRelease event, or… */
+ B_UPON_KEYRELEASE = 1,
+ /* …upon a KeyRelease event, even if the modifiers don’t match. This
+ * state is triggered from get_binding() when the corresponding
+ * KeyPress (!) happens, so that users can release the modifier keys
+ * before releasing the actual key. */
+ B_UPON_KEYRELEASE_IGNORE_MODS = 2,
+ } release;
/** Symbol the user specified in configfile, if any. This needs to be
* stored with the binding to be able to re-convert it into a keycode
Binding *get_binding(uint16_t modifiers, bool key_release, xcb_keycode_t keycode) {
Binding *bind;
+ if (!key_release) {
+ /* On a KeyPress event, we first reset all
+ * B_UPON_KEYRELEASE_IGNORE_MODS bindings back to B_UPON_KEYRELEASE */
+ TAILQ_FOREACH(bind, bindings, bindings) {
+ if (bind->release == B_UPON_KEYRELEASE_IGNORE_MODS)
+ bind->release = B_UPON_KEYRELEASE;
+ }
+
+ /* Then we transition the KeyRelease bindings into a state where the
+ * modifiers no longer matter for the KeyRelease event so that users
+ * can release the modifier key before releasing the actual key. */
+ TAILQ_FOREACH(bind, bindings, bindings) {
+ if (bind->release == B_UPON_KEYRELEASE && !key_release)
+ bind->release = B_UPON_KEYRELEASE_IGNORE_MODS;
+ }
+ }
+
TAILQ_FOREACH(bind, bindings, bindings) {
- /* First compare the modifiers */
- if (bind->mods != modifiers)
+ /* First compare the modifiers (unless this is a
+ * B_UPON_KEYRELEASE_IGNORE_MODS binding and this is a KeyRelease
+ * event) */
+ if (bind->mods != modifiers &&
+ (bind->release != B_UPON_KEYRELEASE_IGNORE_MODS ||
+ !key_release))
continue;
/* Check if the binding is for a KeyPress or a KeyRelease event */
- if (bind->release != key_release)
+ if ((bind->release == B_UPON_KEYPRESS && key_release) ||
+ (bind->release >= B_UPON_KEYRELEASE && !key_release))
continue;
/* If a symbol was specified by the user, we need to look in