Skip to content

Instantly share code, notes, and snippets.

@jackielii
Last active April 28, 2026 17:38
Show Gist options
  • Select an option

  • Save jackielii/9d24095af57ec35df0d46d38bbbe0449 to your computer and use it in GitHub Desktop.

Select an option

Save jackielii/9d24095af57ec35df0d46d38bbbe0449 to your computer and use it in GitHub Desktop.
skhd.zig builtin.skhdrc — convolution QMK keymap (caps_lock tap-hold, space-as-fn_layer) on a MacBook built-in keyboard via .device / .remap / fn_layer. Mirrors keymaps/jackie/keymap.c at https://github.com/jackielii/qmk_firmware/blob/jackie/keyboards/keebio/convolution/keymaps/jackie/keymap.c
# builtin.skhdrc — make the MacBook built-in keyboard behave like the
# convolution QMK keymap (keyboards/keebio/convolution/keymaps/jackie).
#
# Layout reference: keymap.c (layer 0 base, layer 2 fn). Tap-hold
# tapping_terms come from get_tapping_term in keymap.c.
#
# Loaded from ~/.config/skhd/skhdrc via `.load builtin.skhdrc`.
# Tap-hold and layer-hold rules are run by skhd-grabber (sudo install
# via `skhd --install-grabber`); the regular hotkey table is run by
# the per-user skhd agent.
# ── Device ────────────────────────────────────────────────────────
.device builtin { vendor: 0x05AC, product: 0x0342 }
# ── fn_layer mode (= QMK layer 2) ────────────────────────────────
# Capture mode so unbound keys don't leak through under the layer
# (e.g. accidentally typing while space is held shouldn't produce
# stray characters).
:: fn_layer @
# ── Tap-hold rules ────────────────────────────────────────────────
#
# JL_CTL_ESC: caps_lock → tap=esc, hold=lctrl. PREFER_HOLD = 120ms.
# Quick taps emit escape; held longer commits ctrl. permissive_hold
# so a nested down+up of another key while caps is held also commits
# the modifier (typing Ctrl+A by holding caps for ~50ms then a-down,
# a-up still triggers the ctrl combo).
.remap caps_lock [device builtin] {
tap : escape
hold : lctrl
timeout : 120ms
permissive_hold : on
retro_tap : off
}
# JL_LSPC: space → tap=space, hold=fn_layer. PREFER_TAP+50 = 300ms.
# retro_tap on so an accidentally over-held space still emits a space
# on release. Layer rules buffer non-source events through the
# pending window automatically (engine policy), so natural prose
# typing — space immediately followed by the next letter — produces
# the right characters in the right order.
.remap space [device builtin] {
tap : space
hold : fn_layer
timeout : 150ms
permissive_hold : on
retro_tap : on
}
# ── fn_layer bindings (= QMK layer 2) ────────────────────────────
# Positions match the convolution LAYOUT_all → keymap.c layer 2.
# Keycap labels are MacBook-relative; the same physical key on the
# convolution would have the same QMK binding.
# Number row → F-row.
fn_layer < 1 | f1
fn_layer < 2 | f2
fn_layer < 3 | f3
fn_layer < 4 | f4
fn_layer < 5 | f5
fn_layer < 6 | f6
fn_layer < 7 | f7
fn_layer < 8 | f8
fn_layer < 9 | f9
fn_layer < 0 | f10
# `-` and `=` are symbol keys; skhd's literal table covers only named
# keys (return, tab, escape, …), so reach them by macOS virtual
# keycode: 0x1B (minus) and 0x18 (equal).
fn_layer < 0x1B | f11
fn_layer < 0x18 | f12
# space - ] -> f13 for screenshot app
fn_layer < 0x1e | f13
# QWERTY row → app-switch / nav cluster.
fn_layer < tab | alt - tab # JL_ALT_TAB
fn_layer < q | alt - q # JL_ALT_Q (close window in macOS apps)
fn_layer < e | end
fn_layer < r | pageup
# 't' → pause has no clean macOS equivalent in skhd's literal table;
# leave 't' unbound (capture mode absorbs it) until we need it.
fn_layer < y | home
fn_layer < u | pagedown
fn_layer < i | pageup
fn_layer < o | end
fn_layer < p | up
fn_layer < n | down
# Home row → arrows + page nav.
fn_layer < f | pagedown
fn_layer < b | pagedown
fn_layer < h | left
fn_layer < j | down
fn_layer < k | up
fn_layer < l | right
fn_layer < return | mouse1
# This is the fallback in case the layer somehow gets stuck.
fn_layer < escape ; default
### mac fn key
# mac built-in keyboard {{{
# § -> ` and shift - § -> ~ (UK ISO MacBook layout)
# Top-left key (HID 'grave', sends §) → ISO key between L-shift and Z
# (HID 'non_us_backslash', the physical ` /~ on UK layout). hidutil
# rewrites the report at HID level, so shift modifier comes along
# automatically — no separate shift rule needed.
.remap non_us_backslash [device builtin] : grave
fn - j | down
fn - k | up
fn - h | left
fn - l | right
fn + shift - j | shift - down
fn + shift - k | shift - up
fn + shift - h | shift - left
fn + shift - l | shift - right
fn + ctrl - j | ctrl - down
fn + ctrl - k | ctrl - up
fn + ctrl - h | ctrl - left
fn + ctrl - l | ctrl - right
fn + alt - j | alt - down
fn + alt - k | alt - up
fn + alt - h | alt - left
fn + alt - l | alt - right
fn + ctrl + shift - j | ctrl + shift - down
fn + ctrl + shift - k | ctrl + shift - up
fn + ctrl + shift - h | ctrl + shift - left
fn + ctrl + shift - l | ctrl + shift - right
fn - u | pagedown
fn - i | pageup
fn - y [
@native_apps | home
* | cmd - left
]
fn - o [
@native_apps | end
* | cmd - right
]
fn + shift - u | shift - pagedown
fn + shift - i | shift - pageup
fn + shift - y [
@native_apps | shift - home
* | cmd + shift - left
]
fn + shift - o [
@native_apps | shift - end
* | cmd + shift - right
]
fn + cmd - j | cmd - down
fn + cmd - k | cmd - up
fn + cmd - h | cmd - left
fn + cmd - l | cmd - right
# }}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment