Add curated XKB option presets

This commit is contained in:
Gabriel Brown
2026-08-18 12:55:54 -04:00
parent 1afa41526a
commit f9eba1e8c5
3 changed files with 110 additions and 2 deletions
+2 -2
View File
@@ -10,9 +10,9 @@ local prefs = require("prefs")
hl.config({
input = {
kb_layout = prefs.get("keyboardLayout", "us"),
kb_variant = "",
kb_variant = prefs.get("keyboardVariant", ""),
kb_model = "",
kb_options = "",
kb_options = prefs.get("keyboardOptions", ""),
kb_rules = "",
numlock_by_default = prefs.get("numlockByDefault", true),
@@ -21,6 +21,25 @@ SettingsPage {
// when nothing is being captured. Held here rather than per row so that
// starting a new capture cancels any other.
property string capturingChord: ""
readonly property string storedXkbOptions: String(DesktopPreferences.get("keyboardOptions") ?? "")
function xkbOptions(): var {
return root.storedXkbOptions
.split(",")
.map(option => option.trim())
.filter(option => option !== "");
}
function currentXkbOption(prefix: string): string {
return root.xkbOptions().find(option => option.indexOf(prefix) === 0) ?? "";
}
function setXkbOption(prefix: string, option: string): void {
const options = root.xkbOptions().filter(option => option.indexOf(prefix) !== 0);
if (option !== "")
options.push(option);
SystemSettings.commitPreference("keyboardOptions", options.join(","));
}
title: "Input & Shortcuts"
lede: "The Forge mental model, carried forward into native tiling."
@@ -35,6 +54,52 @@ SettingsPage {
// they are real controls.
TextEntryRow { setting: "keyboardLayout"; placeholder: "us" }
TextEntryRow { setting: "keyboardVariant"; placeholder: "none" }
ChoiceGrid {
width: parent.width
label: "Caps Lock"
detail: "Keep it conventional, or turn a prime keyboard position into Escape or Control"
current: root.currentXkbOption("caps:")
options: [
{ value: "", label: "Standard" },
{ value: "caps:escape_shifted_capslock", label: "Esc · Shift for Caps" },
{ value: "caps:escape", label: "Escape" },
{ value: "caps:ctrl_modifier", label: "Control" }
]
onPicked: value => root.setXkbOption("caps:", value)
}
ChoiceGrid {
width: parent.width
label: "Compose key"
detail: "Type accented characters and symbols with memorable key sequences"
current: root.currentXkbOption("compose:")
options: [
{ value: "", label: "Off" },
{ value: "compose:ralt", label: "Right Alt" },
{ value: "compose:rwin", label: "Right Super" },
{ value: "compose:menu", label: "Menu" }
]
onPicked: value => root.setXkbOption("compose:", value)
}
ChoiceGrid {
width: parent.width
label: "Layout switching"
detail: "Used when Keyboard layout contains more than one comma-separated layout"
current: root.currentXkbOption("grp:")
options: [
{ value: "", label: "Off" },
{ value: "grp:win_space_toggle", label: "Super + Space" },
{ value: "grp:alt_shift_toggle", label: "Alt + Shift" },
{ value: "grp:ctrl_shift_toggle", label: "Ctrl + Shift" },
{ value: "grp:caps_toggle", label: "Caps Lock" }
]
onPicked: value => root.setXkbOption("grp:", value)
}
// Presets preserve every option outside their own category. The raw
// value remains visible for less common xkeyboard-config features.
TextEntryRow { setting: "keyboardOptions"; placeholder: "compose:ralt" }
SliderRow { setting: "keyRepeatDelay" }
SliderRow { setting: "keyRepeatRate" }
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Common XKB behavior should be discoverable without hiding the raw option
# string from advanced users. This is source-only so it never remaps the live
# keyboard while the desktop is in use.
set -euo pipefail
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
page="$repo_dir/config/dot/quickshell/modules/settings/ShortcutsPage.qml"
input="$repo_dir/config/dot/hypr/input.lua"
fail() {
printf 'xkb presets contract: %s\n' "$1" >&2
exit 1
}
for needle in \
'function currentXkbOption(prefix: string): string' \
'function setXkbOption(prefix: string, option: string): void' \
'label: "Caps Lock"' \
'value: "caps:escape_shifted_capslock"' \
'value: "caps:ctrl_modifier"' \
'label: "Compose key"' \
'value: "compose:ralt"' \
'label: "Layout switching"' \
'value: "grp:win_space_toggle"' \
'SystemSettings.commitPreference("keyboardOptions"' \
'TextEntryRow { setting: "keyboardOptions"'; do
rg -Fq "$needle" "$page" || fail "Shortcuts is missing $needle"
done
# Picking one category must replace only that category, preserving advanced
# options from every other group.
rg -Fq 'option.indexOf(prefix) !== 0' "$page" \
|| fail 'preset updates do not preserve unrelated XKB options'
rg -Fq 'kb_variant = prefs.get("keyboardVariant", "")' "$input" \
|| fail 'Hyprland does not replay the stored keyboard variant'
rg -Fq 'kb_options = prefs.get("keyboardOptions", "")' "$input" \
|| fail 'Hyprland does not replay the stored keyboard options'
printf 'xkb presets contract: PASS\n'