[hackers] [dwm] grabkeys: Avoid missing events when a keysym maps to multiple keycodes || Chris Down

From: <git_AT_suckless.org>
Date: Wed, 7 Dec 2022 23:06:34 +0100 (CET)

commit 89f9905714c1c1b2e8b09986dfbeca15b68d8af8
Author: Chris Down <chris_AT_chrisdown.name>
AuthorDate: Wed Dec 7 14:55:08 2022 +0000
Commit: Hiltjo Posthuma <hiltjo_AT_codemadness.org>
CommitDate: Wed Dec 7 23:06:26 2022 +0100

    grabkeys: Avoid missing events when a keysym maps to multiple keycodes
    
    It's not uncommon for one keysym to map to multiple keycodes. For
    example, the "play" button on my keyboard sends keycode 172, but my
    bluetooth headphones send keycode 208, both of which map back to
    XF86AudioPlay:
    
        % xmodmap -pke | grep XF86AudioPlay
        keycode 172 = XF86AudioPlay XF86AudioPause XF86AudioPlay XF86AudioPause
        keycode 208 = XF86AudioPlay NoSymbol XF86AudioPlay
        keycode 215 = XF86AudioPlay NoSymbol XF86AudioPlay
    
    This is a problem because the current code only grabs a single one of
    these keycodes, which means that events for any other keycode also
    mapping to the bound keysym will not be handled by dwm. In my case, this
    means that binding XF86AudioPlay does the right thing and correctly
    handles my keyboard's keys, but does nothing on my headphones. I'm not
    the only person affected by this, there are other reports[0].
    
    In order to fix this, we look at the mappings between keycodes and
    keysyms at grabkeys() time and pick out all matching keycodes rather
    than just the first one. The keypress() side of this doesn't need any
    changes because the keycode gets converted back to a canonical keysym
    before any action is taken.
    
    0: https://github.com/cdown/dwm/issues/11

diff --git a/dwm.c b/dwm.c
index 253aba7..03baf42 100644
--- a/dwm.c
+++ b/dwm.c
_AT_@ -955,16 +955,26 @@ grabkeys(void)
 {
         updatenumlockmask();
         {
- unsigned int i, j;
+ unsigned int i, j, k;
                 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
- KeyCode code;
+ int start, end, skip;
+ KeySym *syms;
 
                 XUngrabKey(dpy, AnyKey, AnyModifier, root);
- for (i = 0; i < LENGTH(keys); i++)
- if ((code = XKeysymToKeycode(dpy, keys[i].keysym)))
- for (j = 0; j < LENGTH(modifiers); j++)
- XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
- True, GrabModeAsync, GrabModeAsync);
+ XDisplayKeycodes(dpy, &start, &end);
+ syms = XGetKeyboardMapping(dpy, start, end - start + 1, &skip);
+ if (!syms)
+ return;
+ for (k = start; k <= end; k++)
+ for (i = 0; i < LENGTH(keys); i++)
+ /* skip modifier codes, we do that ourselves */
+ if (keys[i].keysym == syms[(k - start) * skip])
+ for (j = 0; j < LENGTH(modifiers); j++)
+ XGrabKey(dpy, k,
+ keys[i].mod | modifiers[j],
+ root, True,
+ GrabModeAsync, GrabModeAsync);
+ XFree(syms);
         }
 }
 
Received on Wed Dec 07 2022 - 23:06:34 CET

This archive was generated by hypermail 2.3.0 : Wed Dec 07 2022 - 23:12:30 CET