Files
whisper_voice/src/ui/qml/ModernKeySequenceRecorder.qml

132 lines
4.4 KiB
QML

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
}
}