import QtQuick import QtQuick.Controls Rectangle { id: control implicitWidth: 140 implicitHeight: 32 color: "#1a1a20" radius: 6 activeFocusOnTab: true Accessible.role: Accessible.Button Accessible.name: control.currentSequence ? "Hotkey: " + control.currentSequence + ". Click to change" : "No hotkey set. Click to record" border.width: (activeFocus || recording) ? SettingsStyle.focusRingWidth : 1 border.color: activeFocus || recording ? SettingsStyle.accent : SettingsStyle.borderSubtle property string currentSequence: "" signal sequenceChanged(string seq) property bool recording: false onRecordingChanged: { if (recording) { ui.hotkeysEnabled = false } else { ui.hotkeysEnabled = true } } Text { anchors.centerIn: parent text: control.recording ? "Listening..." : (formatSequence(control.currentSequence) || "None") color: control.recording ? SettingsStyle.accent : (control.currentSequence ? "#ffffff" : "#ABABAB") font.family: "JetBrains Mono" font.pixelSize: 13 font.bold: true } MouseArea { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: { control.forceActiveFocus() control.recording = true } } Keys.onPressed: (event) => { if (!control.recording) return // Ignore specific standalone modifiers to allow combos if (event.key === Qt.Key_Control || event.key === Qt.Key_Shift || event.key === Qt.Key_Alt || event.key === Qt.Key_Meta) { return } // Build Modifier String var seq = "" if (event.modifiers & Qt.ControlModifier) seq += "ctrl+" if (event.modifiers & Qt.ShiftModifier) seq += "shift+" if (event.modifiers & Qt.AltModifier) seq += "alt+" if (event.modifiers & Qt.MetaModifier) seq += "win+" // Get Key Name var keyName = getKeyName(event.key, event.text) seq += keyName // Update control.currentSequence = seq control.sequenceChanged(seq) control.recording = false event.accepted = true } onActiveFocusChanged: { if (!activeFocus) control.recording = false } function formatSequence(seq) { if (!seq) return "" var parts = seq.split("+") for (var i = 0; i < parts.length; i++) { var p = parts[i] // Standardize modifiers if (p === "ctrl") parts[i] = "Ctrl" else if (p === "alt") parts[i] = "Alt" else if (p === "shift") parts[i] = "Shift" else if (p === "win") parts[i] = "Win" else if (p === "esc") parts[i] = "Esc" // Capitalize F-keys and others (e.g. f8 -> F8, space -> Space) else parts[i] = p.charAt(0).toUpperCase() + p.slice(1) } return parts.join(" + ") } function getKeyName(key, text) { // F-Keys if (key >= Qt.Key_F1 && key <= Qt.Key_F35) return "f" + (key - Qt.Key_F1 + 1) // Common Keys switch (key) { case Qt.Key_Space: return "space" case Qt.Key_Backspace: return "backspace" case Qt.Key_Tab: return "tab" case Qt.Key_Return: return "enter" case Qt.Key_Enter: return "enter" case Qt.Key_Escape: return "esc" case Qt.Key_Delete: return "delete" case Qt.Key_Insert: return "insert" case Qt.Key_Home: return "home" case Qt.Key_End: return "end" case Qt.Key_PageUp: return "pageup" case Qt.Key_PageDown: return "pagedown" case Qt.Key_Up: return "up" case Qt.Key_Down: return "down" case Qt.Key_Left: return "left" case Qt.Key_Right: return "right" case Qt.Key_CapsLock: return "capslock" case Qt.Key_NumLock: return "numlock" case Qt.Key_ScrollLock: return "scrolllock" case Qt.Key_Print: return "printscreen" case Qt.Key_Pause: return "pause" } // Letters and Numbers (Use text if available, fallback to manual) if (text && text.length > 0 && text.charCodeAt(0) >= 32) { return text.toLowerCase() } return "key" + key } }