catch Bluetooth AVRCP media keys and route to mpv if running

grabkeys() now iterates the full keymap and grabs every keycode that
maps to each bound keysym, instead of relying on XKeysymToKeycode which
returns only one. Bluetooth headsets (e.g. Jaybird X2 AVRCP) register as
a second keyboard with their own keycodes for XF86AudioPlay/Next/Prev,
so the single-keycode grab missed them.

The media-key bindings now try pauseallmpv first (per-instance IPC
control of any running mpv) and fall back to mpc when no mpv socket is
reachable.
This commit is contained in:
2026-04-23 22:48:03 +02:00
parent aad610d178
commit 2e6a4ed20f
2 changed files with 23 additions and 14 deletions
+7 -7
View File
@@ -266,13 +266,13 @@ static Key keys[] = {
{ 0, XF86XK_AudioMute, spawn, SHCMD("lmc mute; pkill -RTMIN+10 dwmblocks") }, { 0, XF86XK_AudioMute, spawn, SHCMD("lmc mute; pkill -RTMIN+10 dwmblocks") },
{ 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("lmc up 5; pkill -RTMIN+10 dwmblocks") }, { 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("lmc up 5; pkill -RTMIN+10 dwmblocks") },
{ 0, XF86XK_AudioLowerVolume, spawn, SHCMD("lmc down 5; pkill -RTMIN+10 dwmblocks") }, { 0, XF86XK_AudioLowerVolume, spawn, SHCMD("lmc down 5; pkill -RTMIN+10 dwmblocks") },
{ 0, XF86XK_AudioPrev, spawn, SHCMD("mpc prev") }, { 0, XF86XK_AudioPrev, spawn, SHCMD("pauseallmpv prev || mpc prev") },
{ 0, XF86XK_AudioNext, spawn, SHCMD("mpc next") }, { 0, XF86XK_AudioNext, spawn, SHCMD("pauseallmpv next || mpc next") },
{ 0, XF86XK_AudioPause, spawn, SHCMD("mpc pause") }, { 0, XF86XK_AudioPause, spawn, SHCMD("pauseallmpv pause || mpc pause") },
{ 0, XF86XK_AudioPlay, spawn, SHCMD("mpc toggle") }, { 0, XF86XK_AudioPlay, spawn, SHCMD("pauseallmpv toggle || mpc toggle") },
{ 0, XF86XK_AudioStop, spawn, SHCMD("mpc stop") }, { 0, XF86XK_AudioStop, spawn, SHCMD("pauseallmpv stop || mpc stop") },
{ 0, XF86XK_AudioRewind, spawn, SHCMD("mpc seek -10") }, { 0, XF86XK_AudioRewind, spawn, SHCMD("pauseallmpv seek-back || mpc seek -10") },
{ 0, XF86XK_AudioForward, spawn, SHCMD("mpc seek +10") }, { 0, XF86XK_AudioForward, spawn, SHCMD("pauseallmpv seek-fwd || mpc seek +10") },
{ 0, XF86XK_AudioMedia, spawn, SHCMD("st -e ncmpcpp") }, { 0, XF86XK_AudioMedia, spawn, SHCMD("st -e ncmpcpp") },
{ 0, XF86XK_Display, spawn, SHCMD("displayselect")}, { 0, XF86XK_Display, spawn, SHCMD("displayselect")},
+14 -5
View File
@@ -1037,16 +1037,25 @@ grabkeys(void)
{ {
updatenumlockmask(); updatenumlockmask();
{ {
unsigned int i, j; unsigned int i, j, k;
unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
KeyCode code; int start, end, skip;
KeySym *syms;
XUngrabKey(dpy, AnyKey, AnyModifier, root); XUngrabKey(dpy, AnyKey, AnyModifier, root);
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++) for (i = 0; i < LENGTH(keys); i++)
if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) if (keys[i].keysym == syms[(k - start) * skip])
for (j = 0; j < LENGTH(modifiers); j++) for (j = 0; j < LENGTH(modifiers); j++)
XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, XGrabKey(dpy, k,
True, GrabModeAsync, GrabModeAsync); keys[i].mod | modifiers[j],
root, True,
GrabModeAsync, GrabModeAsync);
XFree(syms);
} }
} }