summaryrefslogtreecommitdiff
path: root/AGENTS.md
diff options
context:
space:
mode:
Diffstat (limited to 'AGENTS.md')
-rw-r--r--AGENTS.md36
1 files changed, 35 insertions, 1 deletions
diff --git a/AGENTS.md b/AGENTS.md
index 52287de..097985c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -169,7 +169,7 @@ tracked config says so, and in no repo:
| `~/.localprofile` | interactive setup: aliases, prompt, anything that forks | `config/profile`, last |
| `~/.config/ssh/config-local` | ssh, this host only. See `config/ssh/config-local-example` | `config/ssh/entry`, before the shared defaults |
| `~/.config/git/config-local` | git, this host only -- the work identity, `includeIf` blocks. See `config/git/config-local-example` | `config/git/config`, after the `[user]` block above it, and git takes the last value |
-| `~/.config/hammerspoon/local.lua` | Hammerspoon: rebinding a hotkey set here shadows it. `require("dotlib")` for the same helpers init.lua uses. See `config/hammerspoon/local-example.lua` | `config/hammerspoon/init.lua`, last, in a `pcall` |
+| `~/.config/hammerspoon/local.lua` | Hammerspoon: rebinding a hotkey set here shadows it, and `capslock_off()` gives this machine its Caps Lock back. `require("dotlib")` for the same helpers init.lua uses. See `config/hammerspoon/local-example.lua` | `config/hammerspoon/init.lua`, last, in a `pcall` |
| `~/.config/ghostty-local` | Ghostty: later values replace earlier ones, `keybind` accumulates. See `config/ghostty/ghostty-local-example` | `config/ghostty/config`, last, as an optional `config-file` |
| `~/.local/share/alacritty/local.toml` | Alacritty | imported by `config/alacritty/alacritty.toml` |
| `~/.config/dot/skip` | which `link/` parts this machine does not want, one name per line | `link/lib.sh`, as each part starts |
@@ -356,6 +356,40 @@ Key environment features:
- Custom aliases and utility functions
- Performance profiling capabilities
+### Keyboard
+
+Caps Lock sends F20 on every Mac running the Hammerspoon config.
+`dotlib.capslock_f20()`, called early from `config/hammerspoon/init.lua`, does
+it with `hidutil`: the remap happens in the IOKit HID driver, below the window
+server, so the key is F20 to everything -- other apps, System Settings
+shortcuts, a password field, a VM. An `hs.eventtap` cannot reach Caps Lock at
+all, which is why `hs.hid` exists as a separate IOKit module, and why this is
+not a hotkey.
+
+`hidutil property --set` only touches the keyboards attached at that moment, so
+three things re-apply it: the call at startup, watchers for USB attach and
+system wake, and an `hs.eventtap` on `flagsChanged`. The tap is the general
+answer -- a mapped keyboard cannot produce a Caps Lock event, so an event
+arriving at all is proof of a keyboard that was missed, and the fault triggers
+its own repair. That press is spent repairing and toggles Caps Lock for an
+instant, cleared with `hs.hid.capslock.set(false)` -- also the only way to clear
+a stuck Caps Lock once the key itself sends F20. Re-posting the press as a
+synthetic F20 was tried and dropped: an `hs.hotkey` bound to `f20` did not fire
+for a posted event. The watchers are there to catch the two common cases --
+plugging a keyboard in, waking the machine -- before any key is pressed, which
+is why the repair press is rare. Caps Lock is `alphaShift` in the raw CGEvent flags and is absent from
+`event:getFlags()`, which covers only cmd/alt/shift/ctrl/fn.
+
+There is no launchd job and no `link/` part for this. The remap lives and dies
+with Hammerspoon, which already owns the keyboard on these machines.
+
+Nothing is bound to `f20` here; bind it like any other key. One machine gives
+the key back with `require("dotlib").capslock_off()` in its `local.lua` --
+shadowing cannot work, because the remap has already run by the time
+`local.lua` loads. `hs -c 'hs.inspect(require("dotlib").capslock_status())'`
+reports whether the watchers and the tap are still up; that needs `hs.ipc`,
+which `init.lua` requires for exactly this kind of check.
+
### Utility Scripts
The `bin/` directory contains various utility scripts for:
- Theme management (`theme`)