diff --git a/default/hypr/input.lua b/default/hypr/input.lua index 6fddb9e0..c3c7d43f 100644 --- a/default/hypr/input.lua +++ b/default/hypr/input.lua @@ -21,24 +21,32 @@ local function read_vconsole() return values end +-- Layouts that can't type Latin letters. Keep in sync with the list in +-- etc/mkinitcpio.conf.d/omarchy_hooks.conf. +local non_latin_layouts = + " af am ara bd bg by et ge gr il in iq ir kg kh kz la lk mk mm mn mv np rs ru sy th tj ua " + local vconsole = read_vconsole() -local layout = vconsole.XKBLAYOUT or "us" -local variant = vconsole.XKBVARIANT or "" +local kb_layout = vconsole.XKBLAYOUT or "us" +local kb_variant = vconsole.XKBVARIANT or "" local kb_options = "compose:caps,shift:both_capslock" --- Prepend 'us' so Omarchy's Latin-keysym bindings resolve — Hyprland matches --- bindings against the first layout in kb_layout, not the currently active one. -if not (","..layout..","):find(",us,", 1, true) then - layout = "us," .. layout - variant = "," .. variant +-- Hyprland resolves keybindings against the first entry in kb_layout, not the +-- layout that's currently active, so Omarchy's Latin-keysym bindings (SUPER + W +-- and friends) only fire when a Latin layout leads. Installing with a non-Latin +-- one would otherwise leave the desktop unusable. +if non_latin_layouts:find(" " .. kb_layout:match("^[^,]*") .. " ", 1, true) then + kb_layout = "us," .. kb_layout + kb_variant = "," .. kb_variant + -- Reach the original layout with Left Alt + Right Alt. kb_options = kb_options .. ",grp:alts_toggle" end hl.config({ input = { - kb_layout = layout, - kb_variant = variant, + kb_layout = kb_layout, + kb_variant = kb_variant, kb_model = "", kb_options = kb_options, kb_rules = "", diff --git a/test/shell.d/hyprland-keyboard-layout-test.sh b/test/shell.d/hyprland-keyboard-layout-test.sh new file mode 100644 index 00000000..68626cc8 --- /dev/null +++ b/test/shell.d/hyprland-keyboard-layout-test.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +source "$(dirname "${BASH_SOURCE[0]}")/base-test.sh" + +require_command lua + +resolved_input() { + OMARCHY_PATH="$ROOT" OMARCHY_VCONSOLE="${1-}" lua <<'LUA' +package.path = os.getenv("OMARCHY_PATH") .. "/?.lua;" .. package.path + +local vconsole = os.getenv("OMARCHY_VCONSOLE") +local real_open = io.open + +io.open = function(path, mode) + if path ~= "/etc/vconsole.conf" then + return real_open(path, mode) + end + + if not vconsole then + return nil + end + + local file = io.tmpfile() + file:write(vconsole) + file:seek("set") + return file +end + +hl = { + config = function(config) + local input = config.input + print(("[%s] [%s] [%s]"):format(input.kb_layout, input.kb_variant, input.kb_options)) + end, +} + +o = { window = function() end } + +require("default.hypr.input") +LUA +} + +assert_input() { + local description="$1" + local expected="$2" + local actual + + if (( $# > 2 )); then + actual=$(resolved_input "$3") + else + actual=$(resolved_input) + fi + + [[ $actual == "$expected" ]] || + fail "$description" "expected: $expected"$'\n'"actual: $actual" + pass "$description" +} + +base_options="compose:caps,shift:both_capslock" +toggle_options="$base_options,grp:alts_toggle" + +assert_input "missing vconsole.conf falls back to us" "[us] [] [$base_options]" +assert_input "us layout passes through" "[us] [intl] [$base_options]" 'XKBLAYOUT=us +XKBVARIANT=intl +' +assert_input "latin layouts are left alone" "[de] [nodeadkeys] [$base_options]" 'XKBLAYOUT=de +XKBVARIANT=nodeadkeys +' +assert_input "non-latin layout gains us in front" "[us,ara] [,] [$toggle_options]" 'XKBLAYOUT=ara +' +assert_input "prepended us keeps variants aligned" "[us,ru] [,phonetic] [$toggle_options]" 'XKBLAYOUT=ru +XKBVARIANT=phonetic +' +assert_input "non-latin layout in front gains us even when us trails" "[us,il,us] [,] [$toggle_options]" 'XKBLAYOUT=il,us +' + +hooks_conf="$ROOT/etc/mkinitcpio.conf.d/omarchy_hooks.conf" +input_lua="$ROOT/default/hypr/input.lua" + +hooks_layouts=$(awk -F')' '/\) ;;$/ { gsub(/[[:space:]|]+/, "\n", $1); print $1 }' "$hooks_conf" | grep '^[a-z]\+$' | sort) +lua_layouts=$(sed -n '/^local non_latin_layouts =/,+1p' "$input_lua" | grep -o '"[^"]*"' | tr -d '"' | tr ' ' '\n' | grep '^[a-z]\+$' | sort) + +[[ -n $hooks_layouts ]] || fail "non-latin layout list is readable from omarchy_hooks.conf" +[[ $hooks_layouts == "$lua_layouts" ]] || + fail "non-latin layout lists stay in sync" "$(diff <(echo "$hooks_layouts") <(echo "$lua_layouts"))" +pass "non-latin layout lists stay in sync with the initramfs hook"