3.9 KiB
azos/exwm azos/exwm
Backlink: azos
Architecture
EXWM feature: azos-core/features/exwm/emacs/config.org (literate), packaged via
_pkg.nix (azos-emacs-exwm), enabled by azos.suites.exwm.enable.
Key custom keys:
s-r->exwm-reset-> callsexwm-input-grab-keyboard(switches window to full "line-mode": Emacs captures all keys)C-c C-k(EXWM's own default binding inexwm-mode-map) ->exwm-input-release-keyboard(switches to "char-mode": app captures keys)exwm-input-prefix-keys(config.org ~230): keys that always reach Emacs even in char-mode:C-x C-u C-h M-x M-& M-: M-\ s-d s-m s-r s-s s-q H-l C-w C-c C-@exwm-input-global-keys: s-f2, s-tab, s-w, s-0..9, s-&, always grabbed regardless of mode (system-wide, viaexwm-input--global-prefix-keys)
Gotchas
Line-mode does NOT mean "all keys reach Emacs unconditionally"
Even when an EXWM window is in full line-mode (grabbed via exwm-input-grab-keyboard,
an actual XGrabKey Modifiers:Any Key:Any on that window), EXWM's dispatcher
(exwm-input--on-KeyPress-line-mode -> exwm-input--event-passthrough-p) still
filters every keypress. A key is only sent to Emacs's command loop if:
- it's in
exwm-input--global-prefix-keys(derived fromexwm-input-global-keys), or - it's in
exwm-input-prefix-keys, or (lookup-key (current-local-map) (vector event))is non-nil — butcurrent-local-maponly sees the buffer's own local map (effectivelyexwm-mode-map), NOT minor-mode keymaps orglobal-map.
Consequence: any key bound ONLY via a global minor mode (e.g. this repo's
azos/global-minor-mode/keymap, which is how M-\ -> split-window-horizontally
is bound in azos-core/features/base/emacs/config.org) will silently fail inside
EXWM windows — the keypress gets bounced back to the underlying app instead of
running the Emacs command — even though (key-binding (kbd "M-\\")) correctly
resolves it when checked directly (that function walks the full keymap stack,
unlike the local-map-only check EXWM uses).
Fix: add the key to exwm-input-prefix-keys in
azos-core/features/exwm/emacs/config.org (~230). This is unrelated to EXWM
package version — confirmed the relevant dispatch functions
(exwm-input--event-passthrough-p, -on-KeyPress-line-mode,
-grab-keyboard=/-release-keyboard=, exwm-reset) are byte-identical across
a nix flake update that bumped emacs-exwm 0.34.0.20250919 -> 0.34.0.20260204.
C-h k "not working" inside EXWM is often just mid-sequence
C-h k is correctly wired (C-h is in exwm-input-prefix-keys). If it looks
inert, it's because describe-key is waiting for a third keypress (the key to
describe) — the minibuffer prompt is there, just easy to miss if focus/echo
isn't visible.
Debugging EXWM keybinding issues live
exwm-debug-mode does NOT enable exwm's internal logging (exwm--log checks the
special var exwm-debug at macro-EXPANSION time, so it's compiled out entirely
if the package was byte-compiled with it off — toggling the mode at runtime is a
no-op for logging). Instead, use emacsclient to:
- check real state:
(with-current-buffer BUF (list exwm--input-mode exwm--id)) - check real X input focus:
(slot-value (xcb:+request-unchecked+reply exwm--connection (make-instance 'xcb:GetInputFocus)) 'focus) - add temporary
advice-add ... :beforeonexwm-input--on-KeyPress/-on-KeyPress-line-modeto log which keys actually reach the dispatcher - simulate real physical keypresses (not just synthetic events aimed at a
window) with
nix shell nixpkgs#xdotool --command xdotool key --clearmodifiers <keys>— this uses XTEST and goes through the same X input pipeline as real hardware, unlikexdotool key --window IDwhich uses SendEvent and can behave differently.