Keychord

Description

A patch that change the Key struct to Keychord, letting user map a sequence of key instead of one singular keystroke.

*update 01/19/2022: change implementation to use array and pointer instead of dynamic heap allocation to minimize crash due heap allocation being too slow.

*update 07/19/2023: changed grabkeys function to match the changes made in dwm-6.4.

*update 2026-07-17: rebased onto dwm 6.8 and fixed event loss in the chord wait loop. While waiting for the next key of a chord, every event that was not a KeyPress was discarded. Discarding a ButtonPress that activated the GrabModeSync passive grab from grabbuttons() left pointer and keyboard frozen: only buttonpress()'s XAllowEvents can release that grab, and the loop cannot exit on its own, because the frozen keyboard delivers no further KeyPress. Ordinary input, XTEST and xdotool cannot break it; recovery needs a synthetic KeyPress sent with XSendEvent event_mask=0 to the _NET_SUPPORTING_WM_CHECK window (event_mask=0 delivers to the window's creator, bypassing the fact that dwm selects no KeyPressMask), followed by a synthetic ButtonPress to make buttonpress() run XAllowEvents. Absent such a tool the session is lost. A MapRequest arriving mid-chord was dropped the same way, leaving the window unmanaged. Events are now dispatched through handler[] as run() does.

Download

Authors