fix(ui): clear stale combo when capture stops updating

This commit is contained in:
felixzsh
2026-08-26 18:47:29 -05:00
parent 48af33c2a7
commit 48a8020910
+17 -1
View File
@@ -29,6 +29,11 @@ Item {
// it. The history tick prunes entries whose linger window passed. With // it. The history tick prunes entries whose linger window passed. With
// historyCount 1 this is exactly "the current combo, lingering". // historyCount 1 this is exactly "the current combo, lingering".
property var entries: [] property var entries: []
// Epoch (seconds) of the last state payload we successfully parsed. Used
// to detect a dead capture: if no new payload arrives within maxStateAgeMs
// and the top combo was never released, we treat it as released so the
// panel self-heals instead of freezing on a stale combo forever.
property real lastStateT: 0
// How many combos stay on screen (1..5, default 1). Older entries fade // How many combos stay on screen (1..5, default 1). Older entries fade
// out via the entryOpacity() gradient; a count of 1 is the classic // out via the entryOpacity() gradient; a count of 1 is the classic
// current-combo-only display. // current-combo-only display.
@@ -467,9 +472,10 @@ Item {
if (!root.paused) { if (!root.paused) {
try { try {
var parsed = JSON.parse(stateFile.text()) var parsed = JSON.parse(stateFile.text())
if (parsed && Array.isArray(parsed.keys)) { if parsed && Array.isArray(parsed.keys) {
var age = Math.floor(Date.now() / 1000) - (parsed.t || 0) var age = Math.floor(Date.now() / 1000) - (parsed.t || 0)
if (age <= Math.ceil(root.maxStateAgeMs / 1000)) next = parsed.keys if (age <= Math.ceil(root.maxStateAgeMs / 1000)) next = parsed.keys
if ((parsed.t || 0) > 0) root.lastStateT = parsed.t
} }
} catch (e) {} } catch (e) {}
} if (next.length > 0 && root.mode === "bindings") { } if (next.length > 0 && root.mode === "bindings") {
@@ -529,6 +535,16 @@ Item {
repeat: true repeat: true
running: root.entries.length > 0 running: root.entries.length > 0
onTriggered: { onTriggered: {
// If the capture stopped updating (crashed, plugin unloaded, or a
// config reload disabled it), the top combo may be stuck with
// releasedAt === 0 forever because no empty "all keys up" payload
// ever arrives. Treat a stale state file as a release so the combo
// lingers normally and then clears, instead of freezing on screen.
if (root.entries.length > 0 && root.entries[0].releasedAt === 0 &&
root.lastStateT > 0 &&
Math.floor(Date.now() / 1000) - root.lastStateT > Math.ceil(root.maxStateAgeMs / 1000)) {
root.entries[0] = { keys: root.entries[0].keys, releasedAt: Date.now() }
}
var now = Date.now() var now = Date.now()
var kept = [] var kept = []
for (var i = 0; i < root.entries.length; i++) { for (var i = 0; i < root.entries.length; i++) {