backup: 2026-10-05 09:48

This commit is contained in:
2026-10-05 09:48:25 +03:00
parent 2a872c725b
commit 32009710da
34 changed files with 1914 additions and 110 deletions
+79
View File
@@ -0,0 +1,79 @@
:PROPERTIES:
:ID: c52036a9-25ec-4b8b-8b72-90fcd9ea65dd
:END:
#+title: azos/exwm
#+filetags: :project: :knowledge: :exwm:
#+title: azos/exwm
#+filetags: :project: :knowledge: :exwm:
Backlink: [[id:bf4dde56-0967-4374-94ed-771301e47c66][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= -> calls =exwm-input-grab-keyboard= (switches window to
full "line-mode": Emacs captures all keys)
- =C-c C-k= (EXWM's own default binding in =exwm-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, via =exwm-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 from =exwm-input-global-keys=), or
- it's in =exwm-input-prefix-keys=, or
- =(lookup-key (current-local-map) (vector event))= is non-nil — but
=current-local-map= only sees the buffer's own local map (effectively
=exwm-mode-map=), NOT minor-mode keymaps or =global-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 ... :before= on =exwm-input--on-KeyPress= /
=-on-KeyPress-line-mode= to 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, unlike =xdotool key --window ID= which uses SendEvent and can behave
differently.