Non-QWERTY keyboards
Shoji defaults to Ctrl+Alt as the primary modifier. This
works on US QWERTY keyboards, but on European layouts the Option (Alt) key
produces special characters like @, {, }, ~, |, and accented letters.
Holding Alt to navigate windows will type those characters instead.
This page provides ready-to-use keybinding presets for non-QWERTY layouts.
The problem
On QWERTZ (German, Swiss, Czech), AZERTY (French, Belgian), and Nordic layouts, Alt+key combinations produce essential characters:
| Layout | Alt conflicts |
|---|---|
| QWERTZ | @ { } ~ | [ ] |
| AZERTY | @ # { } [ ] | ~ |
| Nordic | @ $ { } [ ] ~ | |
Shoji’s defaults already use Ctrl+Alt (not bare Alt) to reduce conflicts, but some combinations still collide. The presets below replace Alt entirely.
QWERTZ preset (German, Swiss, Austrian)
Uses Ctrl+Cmd as the primary modifier. No Alt key involved:
hs.loadSpoon("Shoji")
local mods = { "ctrl", "cmd" }local modsShift = { "ctrl", "cmd", "shift" }
spoon.Shoji:configure({ default_layout = "tall", enabled_layouts = { "tall", "wide", "bsp", "monocle" },})
spoon.Shoji:bindHotkeys({ -- Navigation focus_left = { mods, "h" }, focus_right = { mods, "l" }, focus_up = { mods, "k" }, focus_down = { mods, "j" }, focus_next = { mods, "n" }, focus_prev = { mods, "p" }, focus_last = { mods, "tab" },
-- Swapping swap_left = { modsShift, "h" }, swap_right = { modsShift, "l" }, swap_up = { modsShift, "k" }, swap_down = { modsShift, "j" }, swap_next = { modsShift, "n" }, swap_prev = { modsShift, "p" }, swap_main = { modsShift, "return" },
-- Layout cycle_layout_forward = { mods, "space" }, cycle_layout_backward = { modsShift, "space" }, increase_main_ratio = { mods, "=" }, decrease_main_ratio = { mods, "-" }, increase_main_count = { mods, "," }, decrease_main_count = { mods, "." }, retile_space = { modsShift, "r" }, reset_space = { modsShift, "0" },
-- Window state toggle_float = { modsShift, "t" }, toggle_zoom = { mods, "f" },
-- Help toggle_cheatsheet = { modsShift, "/" }, open_command_palette = { mods, "/" },
-- Regions send_to_next_region = { mods, "]" }, send_to_prev_region = { mods, "[" }, balance_regions = { modsShift, "b" },})
spoon.Shoji:start()AZERTY preset (French, Belgian)
Same approach. Uses Ctrl+Cmd:
local mods = { "ctrl", "cmd" }local modsShift = { "ctrl", "cmd", "shift" }
spoon.Shoji:bindHotkeys({ focus_left = { mods, "h" }, focus_right = { mods, "l" }, focus_up = { mods, "k" }, focus_down = { mods, "j" }, swap_left = { modsShift, "h" }, swap_right = { modsShift, "l" }, swap_up = { modsShift, "k" }, swap_down = { modsShift, "j" }, cycle_layout_forward = { mods, "space" }, swap_main = { modsShift, "return" }, toggle_float = { modsShift, "t" }, toggle_zoom = { mods, "f" },})Hyper key preset (any layout)
Map Caps Lock to a “Hyper” key (Ctrl+Alt+Cmd+Shift) using Karabiner-Elements. Then bind Shoji to single keys under Hyper:
local hyper = { "ctrl", "alt", "cmd", "shift" }
spoon.Shoji:bindHotkeys({ focus_left = { hyper, "h" }, focus_right = { hyper, "l" }, focus_up = { hyper, "k" }, focus_down = { hyper, "j" }, swap_left = { hyper, "left" }, swap_right = { hyper, "right" }, swap_up = { hyper, "up" }, swap_down = { hyper, "down" }, cycle_layout_forward = { hyper, "space" }, swap_main = { hyper, "return" }, toggle_float = { hyper, "t" }, toggle_zoom = { hyper, "f" },})This works on every keyboard layout because Hyper is a unique modifier combination that no OS or app reserves.
Karabiner rule for Caps Lock to Hyper (add to
~/.config/karabiner/karabiner.json):
{ "manipulators": [ { "from": { "key_code": "caps_lock" }, "to": [ { "key_code": "left_shift", "modifiers": ["left_command", "left_control", "left_option"] } ], "type": "basic" } ]}Choosing a modifier
| Modifier | Pros | Cons |
|---|---|---|
| Ctrl+Cmd | No extra tools needed, no Alt conflicts | May conflict with some app shortcuts |
| Hyper (Caps Lock) | Zero conflicts, works on any layout | Requires Karabiner-Elements |
| Ctrl+Alt (default) | Works on QWERTY out of the box | Conflicts with special chars on EU layouts |
Pick the modifier that avoids conflicts with both your keyboard layout and the apps you use most. You only need to override the bindings that conflict — unspecified actions keep their defaults.