Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 30 additions & 21 deletions bin/omarchy-setup-keyboard
Original file line number Diff line number Diff line change
@@ -1,41 +1,50 @@
#!/bin/bash

# omarchy:summary=Configure the keyboard layout
# Setup keyboard layout for Omarchy
# Provides interactive keyboard layout configuration using the first-run script
# Re-runs the provisioning layout picker on a running system and persists the
# choice through localectl: the console keymap and XKB layout land in
# /etc/vconsole.conf, which default/hypr/input.lua reads for kb_layout.

set -euo pipefail

OMARCHY_PATH="${HOME}/.local/share/omarchy"
KEYBOARD_SCRIPT="${OMARCHY_PATH}/install/first-run/keyboard-layout.sh"

# Check if the keyboard layout script exists
if [[ ! -f "$KEYBOARD_SCRIPT" ]]; then
echo "Error: Keyboard layout setup script not found at:"
echo " $KEYBOARD_SCRIPT"
exit 1
fi
OMARCHY_PATH="${OMARCHY_PATH:-/usr/share/omarchy}"

# Check if gum is installed
if ! omarchy-cmd-present gum; then
echo "Error: gum is not installed. Please install it first:"
echo " sudo pacman -S gum"
exit 1
fi

# Display current keyboard layout
# The picker and layout table are shared with first-boot provisioning so this
# command can never offer a layout that setup could not have applied.
source "$OMARCHY_PATH/install/provisioning/setup-form.sh"

echo "Current keyboard layout configuration:"
echo ""
localectl status | grep -E "X11 Layout|VC Keymap" || echo " Layout: (unset or default)"
echo ""
echo "Starting keyboard layout configuration..."
echo ""

# Run the keyboard layout configuration script
# This always prompts so Menu > Setup > Keyboard Layout can change layouts later
bash "$KEYBOARD_SCRIPT" --force
# Esc and Ctrl+C both leave the current layout in place.
omarchy_prompt_keyboard || exit 0

# Apply the console keymap to the live VT when the command runs on one.
[[ $(tty 2>/dev/null) == /dev/tty* ]] && loadkeys "$keyboard" 2>/dev/null || true

if localectl --no-pager list-keymaps 2>/dev/null | grep -qix "$keyboard"; then
localectl set-keymap "$keyboard"
else
echo "Warning: keymap '$keyboard' is unknown to localectl; keeping the current console keymap"
fi

# --no-convert keeps the console keymap set above instead of deriving one from
# the XKB layout.
localectl --no-convert set-x11-keymap "$keyboard_xkb_layout" "" "$keyboard_xkb_variant"

# input.lua re-reads vconsole.conf on every config evaluation, so a reload
# applies the new layout without relaunching the session.
hyprctl reload >/dev/null 2>&1 || true

echo ""
echo "✓ Keyboard layout setup complete"
echo ""
echo "Note: The new layout will apply immediately to new applications."
echo "For Hyprland keybindings, you may need to restart Hyprland (Super+Shift+E > Relaunch)"
echo "✓ Keyboard layout set to $keyboard_label"
echo " Console keymap: $keyboard XKB: $keyboard_xkb_layout${keyboard_xkb_variant:+/$keyboard_xkb_variant}"
102 changes: 102 additions & 0 deletions tests/test-setup-keyboard.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/bin/bash
set -uo pipefail

ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
WORK=$(mktemp -d)
trap 'rm -rf "$WORK"' EXIT
pass=0
failures=0

check() {
local label="$1"
shift
if "$@"; then
echo "✓ $label"
((++pass))
else
echo "✗ $label"
((++failures))
fi
}

# Stub the interactive and system-touching commands; gum drains stdin first
# because the prompt pipes the layout list in — exiting early kills cut with
# SIGPIPE and pipefail reads that as a cancelled prompt.
make_stubs() {
local selection="$1"
rm -rf "$WORK/bin"
mkdir -p "$WORK/bin"
: >"$WORK/calls"

cat >"$WORK/bin/gum" <<STUB
#!/bin/bash
cat >/dev/null
if [[ -n '$selection' ]]; then
printf '%s\n' '$selection'
else
exit 1
fi
STUB

cat >"$WORK/bin/localectl" <<'STUB'
#!/bin/bash
local_ifs=$IFS
IFS='|'
printf '%s\n' "$*" >>"$OMARCHY_TEST_CALLS"
IFS=$local_ifs
case "$1" in
status)
echo " VC Keymap: us"
echo " X11 Layout: us"
;;
--no-pager)
printf 'us\nuk\ndvorak\n'
;;
esac
STUB

cat >"$WORK/bin/hyprctl" <<'STUB'
#!/bin/bash
IFS='|'
printf '%s\n' "$*" >>"$OMARCHY_TEST_CALLS"
STUB
chmod +x "$WORK/bin/"*
}

run_setup() {
OMARCHY_PATH="$ROOT" OMARCHY_TEST_CALLS="$WORK/calls" \
PATH="$WORK/bin:$ROOT/bin:$PATH" "$ROOT/bin/omarchy-setup-keyboard"
}

called() {
grep -qF "$1" "$WORK/calls"
}

not_called() {
! grep -qF "$1" "$WORK/calls"
}

make_stubs "English (UK)"
run_setup >/dev/null
check "English (UK) persists the uk console keymap" \
called "set-keymap|uk"
check "English (UK) persists the gb XKB layout" \
called "set-x11-keymap|gb"
check "a successful pick reloads Hyprland" \
called "reload"

make_stubs "English (US, Dvorak)"
run_setup >/dev/null
check "English (US, Dvorak) passes the dvorak variant through to XKB" \
called "set-x11-keymap|us||dvorak"

make_stubs ""
run_setup >/dev/null
check "cancelling the picker changes no keymap" \
not_called "set-keymap"
check "cancelling the picker changes no XKB layout" \
not_called "set-x11-keymap"

echo ""
echo "$pass checks passed, $failures failed"
exit $((failures > 0))
Loading