// Input & Shortcuts. // // The shortcut list is generated from `hyprctl binds -j` rather than typed out // here. The previous version was a hand-maintained array of nineteen entries // against a real keymap of a hundred and thirteen: it could not show the rest, // and it went stale the moment a bind changed. Every bind now carries its own // description in hypr/keybinds.lua, and this page just groups and renders them. // // The hardware settings above the list are real controls. Keyboard layout, // repeat behaviour, and pointer response are Hyprland's, so Panama owns them; // device-specific configuration stays with GNOME. import QtQuick import qs.config import qs.services SettingsPage { id: root // The chord of the bind currently being re-recorded, in the Lua form; empty // when nothing is being captured. Held here rather than per row so that // starting a new capture cancels any other. property string capturingChord: "" title: "Input & Shortcuts" lede: "The Forge mental model, carried forward into native tiling." SettingsCard { title: "Keyboard" // These were read-only text, on the grounds that a layout change needed // a compositor reload. It does not: setting input:kb_variant through // hl.config re-keymaps attached keyboards immediately -- verified by // watching active_keymap on a real keyboard change and change back. So // they are real controls. TextEntryRow { setting: "keyboardLayout"; placeholder: "us" } TextEntryRow { setting: "keyboardVariant"; placeholder: "none" } TextEntryRow { setting: "keyboardOptions"; placeholder: "compose:ralt" } SliderRow { setting: "keyRepeatDelay" } SliderRow { setting: "keyRepeatRate" } ToggleRow { setting: "numlockByDefault"; divider: false } } SettingsCard { title: "Hardware input" ActionRow { label: "Mouse, touchpad, and keyboard devices" detail: "Device-specific settings stay with Fedora's hardware-backed panels" action: "Open keyboard" divider: false onTriggered: SystemSettings.openGnomePanel("keyboard") } } // One card per group, built from what the compositor actually has bound. // // Both Repeaters address their model through an explicit id. Inside a // SettingsCard the surrounding `parent` is the card's internal Column, not // the card, so `parent.modelData` is undefined there and the rows silently // never appear -- the cards render with their heading and nothing under it. Repeater { model: Keybinds.grouped() SettingsCard { id: groupCard required property var modelData title: groupCard.modelData.name subtitle: groupCard.modelData.binds.length === 1 ? "1 shortcut" : `${groupCard.modelData.binds.length} shortcuts` Repeater { id: bindRows model: groupCard.modelData.binds SettingRow { id: bindRow required property var modelData required property int index readonly property bool capturing: root.capturingChord === bindRow.modelData.luaChord readonly property bool overridden: Keybinds.isOverridden(bindRow.modelData.luaChord) label: bindRow.modelData.description detail: bindRow.overridden ? "Moved from " + Keybinds.shippedChordFor(bindRow.modelData.luaChord) : "" controlWidth: 300 divider: bindRow.index < bindRows.count - 1 Item { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter width: 300 height: 30 ShortcutCapture { anchors.right: parent.right width: 230 height: 30 visible: bindRow.capturing focus: bindRow.capturing onCaptured: chord => { Keybinds.rebind(bindRow.modelData.luaChord, chord); root.capturingChord = ""; } onCancelled: root.capturingChord = "" } Row { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter visible: !bindRow.capturing spacing: 8 Text { anchors.verticalCenter: parent.verticalCenter text: bindRow.modelData.chord color: bindRow.overridden ? Theme.accent : Theme.fgDim font.family: Theme.fontFamily font.pixelSize: Theme.fontSize } SettingsButton { anchors.verticalCenter: parent.verticalCenter text: "Change" enabled: !Keybinds.reloading && !bindRow.modelData.mouse onClicked: root.capturingChord = bindRow.modelData.luaChord } SettingsButton { anchors.verticalCenter: parent.verticalCenter visible: bindRow.overridden text: "Reset" enabled: !Keybinds.reloading onClicked: Keybinds.resetBind(bindRow.modelData.luaChord) } } } } } } } SettingsCard { visible: Object.keys(Keybinds.overrides).length > 0 title: "Changed shortcuts" subtitle: "Rebinding stores only the new chord; what a shortcut does always comes from the desktop's configuration." ActionRow { label: "Restore every shipped shortcut" detail: Object.keys(Keybinds.overrides).length + (Object.keys(Keybinds.overrides).length === 1 ? " shortcut moved" : " shortcuts moved") action: "Restore all" divider: false enabled: !Keybinds.reloading onTriggered: Keybinds.resetAll() } } SettingsCard { visible: Keybinds.lastError !== "" title: "Shortcuts unavailable" subtitle: Keybinds.lastError ActionRow { label: "Read the keymap again" detail: "Shortcuts are read from the running compositor" action: "Retry" divider: false onTriggered: Keybinds.refresh() } } }