Add bar widget to pause and resume the key display
A keyboard glyph in the bar (WidgetButton, right section by default) toggles a pause flag at $XDG_RUNTIME_DIR/omarchy-key-visualizer.paused that the panel and every bar widget instance watch, so a click on any monitor updates all of them. While paused the panel ignores key state and hides; the button dims. Also exposes pause/resume/toggle over the key-visualizer IPC target.
This commit is contained in:
@@ -0,0 +1,61 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import qs.Ui
|
||||||
|
import qs.Commons
|
||||||
|
|
||||||
|
// Bar toggle for the Key Visualizer: a keyboard glyph that pauses/resumes the
|
||||||
|
// on-screen key display. Pause state is a flag file in the runtime dir
|
||||||
|
// ($XDG_RUNTIME_DIR/omarchy-key-visualizer.paused) that the panel and every bar
|
||||||
|
// widget instance watch, so one click updates all of them. The widget is
|
||||||
|
// dimmed while paused.
|
||||||
|
BarWidget {
|
||||||
|
id: root
|
||||||
|
moduleName: "felixzsh.key-visualizer"
|
||||||
|
|
||||||
|
property bool paused: false
|
||||||
|
|
||||||
|
readonly property string pausePath: {
|
||||||
|
var runtime = Quickshell.env("XDG_RUNTIME_DIR")
|
||||||
|
return (runtime && runtime.length > 0 ? runtime : "/tmp") + "/omarchy-key-visualizer.paused"
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
var cmd = root.paused
|
||||||
|
? "rm -f " + Util.shellQuote(root.pausePath)
|
||||||
|
: "printf 1 > " + Util.shellQuote(root.pausePath)
|
||||||
|
toggleProc.command = ["sh", "-c", cmd]
|
||||||
|
toggleProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: toggleProc
|
||||||
|
}
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
id: pauseFlag
|
||||||
|
path: root.pausePath
|
||||||
|
watchChanges: true
|
||||||
|
printErrors: false
|
||||||
|
onLoaded: root.paused = (text() === "1")
|
||||||
|
onFileChanged: reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: button.implicitWidth
|
||||||
|
implicitHeight: button.implicitHeight
|
||||||
|
|
||||||
|
WidgetButton {
|
||||||
|
id: button
|
||||||
|
anchors.fill: parent
|
||||||
|
bar: root.bar
|
||||||
|
text: "\uF030C" // nf-md-keyboard_outline
|
||||||
|
fontSize: Style.font.icon
|
||||||
|
horizontalMargin: 6
|
||||||
|
active: !root.paused
|
||||||
|
dimmed: root.paused
|
||||||
|
tooltipText: root.paused
|
||||||
|
? "Key Visualizer — paused (click to resume)"
|
||||||
|
: "Key Visualizer — click to pause"
|
||||||
|
onPressed: function() { root.toggle() }
|
||||||
|
}
|
||||||
|
}
|
||||||
+50
-8
@@ -34,6 +34,15 @@ Item {
|
|||||||
return (runtime && runtime.length > 0 ? runtime : "/tmp") + "/omarchy-key-visualizer.json"
|
return (runtime && runtime.length > 0 ? runtime : "/tmp") + "/omarchy-key-visualizer.json"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pause flag shared with the bar widget: while the file holds "1" the
|
||||||
|
// display is frozen (keys are ignored). The bar button writes/removes the
|
||||||
|
// file; both sides watch it, so a click on any monitor updates all of them.
|
||||||
|
property bool paused: false
|
||||||
|
readonly property string pausePath: {
|
||||||
|
var runtime = Quickshell.env("XDG_RUNTIME_DIR")
|
||||||
|
return (runtime && runtime.length > 0 ? runtime : "/tmp") + "/omarchy-key-visualizer.paused"
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------- layout
|
// ------------------------------------------------------------- layout
|
||||||
|
|
||||||
readonly property int cardPad: Style.space(10)
|
readonly property int cardPad: Style.space(10)
|
||||||
@@ -73,14 +82,15 @@ Item {
|
|||||||
|
|
||||||
function apply() {
|
function apply() {
|
||||||
var next = []
|
var next = []
|
||||||
try {
|
if (!root.paused) {
|
||||||
var parsed = JSON.parse(stateFile.text())
|
try {
|
||||||
if (parsed && Array.isArray(parsed.keys)) {
|
var parsed = JSON.parse(stateFile.text())
|
||||||
var age = Math.floor(Date.now() / 1000) - (parsed.t || 0)
|
if (parsed && Array.isArray(parsed.keys)) {
|
||||||
if (age <= Math.ceil(root.maxStateAgeMs / 1000)) next = parsed.keys
|
var age = Math.floor(Date.now() / 1000) - (parsed.t || 0)
|
||||||
}
|
if (age <= Math.ceil(root.maxStateAgeMs / 1000)) next = parsed.keys
|
||||||
} catch (e) {}
|
}
|
||||||
if (next.length === 0) {
|
} catch (e) {}
|
||||||
|
} if (next.length === 0) {
|
||||||
// Keys were released: keep the last combo on screen for the linger
|
// Keys were released: keep the last combo on screen for the linger
|
||||||
// window, then clear it. A fresh press restarts the timer below.
|
// window, then clear it. A fresh press restarts the timer below.
|
||||||
hideTimer.restart()
|
hideTimer.restart()
|
||||||
@@ -109,6 +119,34 @@ Item {
|
|||||||
onFileChanged: reload()
|
onFileChanged: reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
id: pauseFile
|
||||||
|
path: root.pausePath
|
||||||
|
watchChanges: true
|
||||||
|
printErrors: false
|
||||||
|
onLoaded: root.paused = (text() === "1")
|
||||||
|
onFileChanged: reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
onPausedChanged: if (root.paused) {
|
||||||
|
hideTimer.stop()
|
||||||
|
root.keys = []
|
||||||
|
root.opened = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPaused(p) {
|
||||||
|
if (p === root.paused) return
|
||||||
|
var cmd = p
|
||||||
|
? "printf 1 > " + Util.shellQuote(root.pausePath)
|
||||||
|
: "rm -f " + Util.shellQuote(root.pausePath)
|
||||||
|
pauseToggleProc.command = ["sh", "-c", cmd]
|
||||||
|
pauseToggleProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: pauseToggleProc
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------- capture hook injection
|
// ------------------------------------------------- capture hook injection
|
||||||
//
|
//
|
||||||
// The capture script (key-visualizer.lua) must run inside Hyprland's Lua
|
// The capture script (key-visualizer.lua) must run inside Hyprland's Lua
|
||||||
@@ -177,6 +215,10 @@ Item {
|
|||||||
target: "key-visualizer"
|
target: "key-visualizer"
|
||||||
function ping(): string { return "ok" }
|
function ping(): string { return "ok" }
|
||||||
function state(): string { return root.opened ? "open" : "closed" }
|
function state(): string { return root.opened ? "open" : "closed" }
|
||||||
|
function paused(): string { return root.paused ? "true" : "false" }
|
||||||
|
function pause(): string { root.setPaused(true); return "ok" }
|
||||||
|
function resume(): string { root.setPaused(false); return "ok" }
|
||||||
|
function toggle(): string { root.setPaused(!root.paused); return "ok" }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------- display
|
// ------------------------------------------------------------- display
|
||||||
|
|||||||
+11
-3
@@ -2,11 +2,19 @@
|
|||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"id": "felixzsh.key-visualizer",
|
"id": "felixzsh.key-visualizer",
|
||||||
"name": "Key Visualizer",
|
"name": "Key Visualizer",
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"description": "Shows the keys you press on screen. Great for keybinding tutorials, demos, and screencasts.",
|
"description": "Shows the keys you press on screen. Great for keybinding tutorials, demos, and screencasts.",
|
||||||
"kinds": ["panel"],
|
"kinds": ["panel", "bar-widget"],
|
||||||
"keepLoaded": true,
|
"keepLoaded": true,
|
||||||
"entryPoints": {
|
"entryPoints": {
|
||||||
"panel": "KeyVisualizer.qml"
|
"panel": "KeyVisualizer.qml",
|
||||||
|
"barWidget": "BarWidget.qml"
|
||||||
|
},
|
||||||
|
"barWidget": {
|
||||||
|
"displayName": "Key Visualizer",
|
||||||
|
"description": "Pause or resume the on-screen key display",
|
||||||
|
"category": "Tools",
|
||||||
|
"allowMultiple": false,
|
||||||
|
"defaultSection": "right"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user