Give Input keycaps, a shortcut search, and the missing pointer basics
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -3,6 +3,21 @@
|
||||
# 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.
|
||||
#
|
||||
# The presets became dropdowns and the raw strings moved into an "Advanced"
|
||||
# disclosure, which is the change this contract exists to bound. Collapsed is
|
||||
# fine -- a disclosure somebody can open is still the page telling them the
|
||||
# setting is there. Gone is not. So what is checked is that the raw
|
||||
# `keyboardOptions`, `keyboardVariant` and `keyboardLayout` fields are still on
|
||||
# THIS page, still editable, and still behind something that opens; not that
|
||||
# they are visible at rest.
|
||||
#
|
||||
# The reason for the distinction: every preset here writes one category of a
|
||||
# single comma-separated string. xkeyboard-config has hundreds of options and
|
||||
# the dropdowns offer eleven. Without the raw field, choosing anything else
|
||||
# means editing a preferences file by hand -- and worse, a preset would then
|
||||
# silently discard an option somebody had put there, with no way to see that it
|
||||
# had. The preservation rule below is only honest while the string is legible.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -16,26 +31,91 @@ fail() {
|
||||
exit 1
|
||||
}
|
||||
|
||||
[[ -r "$page" ]] || fail "cannot read $page"
|
||||
|
||||
# ── The presets ──────────────────────────────────────────────────────────────
|
||||
#
|
||||
# The values are pinned; the labels are matched loosely, because what an
|
||||
# xkb option string says is a fact and what a row is called is a wording
|
||||
# decision. `caps:escape_shifted_capslock` moving would change somebody's
|
||||
# keyboard. "Compose key" becoming "Compose" would not.
|
||||
|
||||
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
|
||||
'SystemSettings.commitPreference("keyboardOptions"'; do
|
||||
rg -Fq "$needle" "$page" || fail "Shortcuts is missing $needle"
|
||||
done
|
||||
|
||||
for label in 'Caps Lock' 'Compose' 'Layout switching'; do
|
||||
rg -qi "label: \"$label" "$page" || fail "Shortcuts has no \"$label\" row"
|
||||
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'
|
||||
|
||||
# ── The raw strings, wherever they now sit on the page ───────────────────────
|
||||
#
|
||||
# Matched as a block rather than a line, because these rows are nested inside a
|
||||
# disclosure now and a one-line `TextEntryRow { setting: "..." }` is no longer
|
||||
# how they are written.
|
||||
|
||||
python3 - "$page" <<'PY' || fail 'the raw XKB fields are no longer editable on the Keyboard page -- a preset that silently drops an unrecognised option is the failure this prevents'
|
||||
import re
|
||||
import sys
|
||||
|
||||
text = open(sys.argv[1], encoding="utf-8").read()
|
||||
missing = []
|
||||
for setting in ("keyboardOptions", "keyboardVariant", "keyboardLayout"):
|
||||
pattern = rf"TextEntryRow\s*\{{(?:(?!\n\s*[A-Z][A-Za-z0-9]*\s*\{{).)*?setting\s*:\s*\"{setting}\""
|
||||
if not re.search(pattern, text, re.S):
|
||||
missing.append(setting)
|
||||
if missing:
|
||||
print("missing raw editors for: " + ", ".join(missing), file=sys.stderr)
|
||||
raise SystemExit(1 if missing else 0)
|
||||
PY
|
||||
|
||||
# Collapsed is allowed; sealed shut is not. Something on the page has to open
|
||||
# the disclosure, and it has to be named so somebody knows what is behind it.
|
||||
rg -qi 'advanced' "$page" \
|
||||
|| fail 'the raw XKB fields are on the page but nothing names the section holding them'
|
||||
|
||||
python3 - "$page" <<'PY' || fail 'the Advanced section has no control that opens it, so the raw fields are present but unreachable'
|
||||
import re
|
||||
import sys
|
||||
|
||||
text = open(sys.argv[1], encoding="utf-8").read()
|
||||
# Whatever the state is called, a disclosure needs a handler that changes it.
|
||||
# `onClicked: root.showAdvanced = !root.showAdvanced`, `onTriggered:
|
||||
# root.advancedOpen = true`, an `expanded` id -- any of them satisfy this; a
|
||||
# hardcoded `visible: false` does not.
|
||||
handlers = re.findall(r"on(?:Clicked|Triggered|Toggled)\s*:.*", text)
|
||||
raise SystemExit(0 if any(re.search(r"advanced", line, re.I) for line in handlers) else 1)
|
||||
PY
|
||||
|
||||
# A field that exists but can never be shown is the same as no field.
|
||||
python3 - "$page" <<'PY' || fail 'a raw XKB field is pinned invisible, which is indistinguishable from removing it'
|
||||
import re
|
||||
import sys
|
||||
|
||||
text = open(sys.argv[1], encoding="utf-8").read()
|
||||
for setting in ("keyboardOptions", "keyboardVariant", "keyboardLayout"):
|
||||
pattern = rf"TextEntryRow\s*\{{((?:(?!\n\s*[A-Z][A-Za-z0-9]*\s*\{{).)*?setting\s*:\s*\"{setting}\".*?)\n"
|
||||
block = re.search(pattern, text, re.S)
|
||||
if block and re.search(r"visible\s*:\s*false", block.group(1)):
|
||||
print(f"{setting} is declared visible: false", file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
raise SystemExit(0)
|
||||
PY
|
||||
|
||||
# ── The values that survive a reload ─────────────────────────────────────────
|
||||
|
||||
rg -Fq 'kb_variant = prefs.get("keyboardVariant", "")' "$input" \
|
||||
|| fail 'Hyprland does not replay the stored keyboard variant'
|
||||
rg -Fq 'key: "keyboardOptions", type: "string", def: "caps:escape_shifted_capslock"' "$schema" \
|
||||
|
||||
Reference in New Issue
Block a user