Follow the keyboard being typed on in the layout widget (#6740)
* Read the keyboard being typed on rather than the one holding main The main flag names no keyboard for long. fcitx5 takes it with the virtual keyboard it binds to inject, and those are filtered out, so on a seat running an input method the pick lands on nothing at all: no label, and the widget hides itself off the bar. #6727 keeps polling in that state rather than settling it, and the poll has nothing new to read. Once fcitx5 unbinds, the flag lands on whichever device libinput listed last, as easily a lid switch as a keyboard, and a device that never receives the toggle reports the layout it started on forever, which is the reading #6574 opened. Every device carries the seat's layout list, but only the keyboard being typed on advances through it, so read the furthest-advanced one. activelayout names the keyboard it moved ahead of the layout, so take that name and let it settle the pick, and the click that switches it. * Leave the buttons out of the seat the widget reads Reading the keyboard being typed on left keyboardName standing for two things at once: the device a click switches, and the device activelayout last named. Only the second was still being set, so the first went empty until a switch happened -- which left the click doing nothing on a seat whose only switch is the click, and left the poll running forever on the one-keyboard install it was written to leave alone. Give each its own property, and set the switch target from the reading that confirmed the keyboard is there. Layout progress only points at the keyboard being typed on while the other devices stay where they started, and the ACPI power button, lid switch and sleep key never do move on their own -- but they answer to switchxkblayout and can hold the main flag, so anything that reads or switches whatever the seat hands back can end up describing a button, and unplugging the keyboard beside one leaves it standing in for the seat. Drop them where the virtual keyboards are already dropped. A reading that reaches hyprctl and finds no keyboard now clears the label rather than leaving a device that is gone described on the bar, told apart from the empty output a killed query leaves by the device list itself, and the watchdog asks again rather than waiting for a poll that a settled seat has already stopped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
David Heinemeier Hansson
parent
0fa3170504
commit
66e3f479a6
@@ -54,9 +54,72 @@ function shortLabel(description, briefs) {
|
||||
return label.substring(0, 3).toUpperCase()
|
||||
}
|
||||
|
||||
// Hyprland's activelayout event pairs the keyboard that switched with the layout
|
||||
// it moved to. Quickshell cuts the event into that many fields, so a description
|
||||
// carrying a comma of its own stays in one piece; a binding old enough to hand
|
||||
// back only the raw string gets split by hand. The virtual keyboard fcitx5 binds
|
||||
// to inject announces switches too, and names a keyboard nobody types on.
|
||||
function eventKeyboardName(event) {
|
||||
var parts
|
||||
|
||||
try {
|
||||
if (event && event.parse) parts = event.parse(2)
|
||||
} catch (error) {
|
||||
}
|
||||
|
||||
if (!parts) parts = String(event && event.data ? event.data : "").split(",")
|
||||
|
||||
var name = String(parts[0] || "")
|
||||
return name.indexOf("hl-virtual-keyboard") === 0 ? "" : name
|
||||
}
|
||||
|
||||
// Hyprland reports more than keyboards as keyboards. fcitx5 binds a virtual one
|
||||
// to inject through, which keeps the us layout the input method gave it, and the
|
||||
// ACPI power button, lid switch and sleep key each arrive carrying the seat's
|
||||
// layout list without anyone ever typing on them. Both answer to switchxkblayout
|
||||
// and both can hold the main flag, so a widget that reads or switches whatever
|
||||
// the seat hands it ends up describing a button. Leave them out and what remains
|
||||
// is keyboards, which is what the rest of this file can then assume.
|
||||
//
|
||||
// Missing a name here costs the accuracy the seat had before, never a keyboard:
|
||||
// anything unrecognised stays in the list.
|
||||
var UNTYPED_KEYBOARDS = /^(hl-virtual-keyboard|power-button|sleep-button|lid-switch|video-bus)/
|
||||
|
||||
function isTypedKeyboard(name) {
|
||||
return !UNTYPED_KEYBOARDS.test(String(name || ""))
|
||||
}
|
||||
|
||||
// Every keyboard on the seat carries the same layout list unless one was given
|
||||
// its own, but only the one being typed on advances through it. So the
|
||||
// furthest-advanced is the one worth reading, and a switch names the keyboard it
|
||||
// moved, which settles a seat holding two real keyboards outright.
|
||||
//
|
||||
// The name is taken whenever a keyboard still answers to it, wherever that
|
||||
// keyboard sits in the list. Comparing positions instead would read the wrong
|
||||
// keyboard the moment one wrapped from the last layout back to the first, which
|
||||
// is the ordinary way round a pair of them. Applying a layout to the whole seat
|
||||
// names a keyboard too, but leaves every one of them on the same layout, so the
|
||||
// label reads the same whichever of them the name settles on.
|
||||
function selectKeyboard(typed, namedByEvent) {
|
||||
var keyboards = typed || []
|
||||
|
||||
return keyboards.find(function (keyboard) {
|
||||
return keyboard.name === namedByEvent
|
||||
}) || keyboards.reduce(function (furthest, keyboard) {
|
||||
return layoutIndex(keyboard) > layoutIndex(furthest) ? keyboard : furthest
|
||||
}, keyboards[0])
|
||||
}
|
||||
|
||||
function layoutIndex(keyboard) {
|
||||
return (keyboard && keyboard.active_layout_index) || 0
|
||||
}
|
||||
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = {
|
||||
eventKeyboardName: eventKeyboardName,
|
||||
isTypedKeyboard: isTypedKeyboard,
|
||||
layoutBriefs: layoutBriefs,
|
||||
selectKeyboard: selectKeyboard,
|
||||
shortLabel: shortLabel
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user