Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-803GitHub issuePublicDecided· Out of scope

Layout widget switches only one of several real keyboards, so a laptop with an external keyboard half-switches

Reported by fabeider · filed Sep 8, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 days ago.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
AreaOutside the audited area· Decided by agents · verified
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Decided by agents and verified by a second, independent agent — see the decision.

Original report

Layout widget switches only one of several real keyboards, so a laptop with an external keyboard half-switchesrevision 1 · captured 2026-09-28 21:23 UTC via poll

What happens

Clicking the omarchy.keyboard-layout bar widget changes the label but not the
layout under the keys I am typing on. This is the symptom of #8964 and #10135, but
with a cause that survives the fix both of them propose: this machine has **two real
keyboards**, and the widget switches one of them.

Why the filter fixes do not reach it

#8964 and #10135 both address UNTYPED_KEYBOARDS letting a non-keyboard through, and
both resolve once the offending device is filtered out — #8964 notes that afterwards
"the widget sees 1 keyboard". That is the part this report does not duplicate.

cycleLayout() switches exactly one device, whatever selectKeyboard() settled on:

// shell/plugins/bar/widgets/KeyboardLayout.qml
root.bar.run("hyprctl switchxkblayout " + Util.shellQuote(root.keyboardName) + " next")

On a laptop with an external keyboard attached, two devices legitimately survive any
filter — here at-translated-set-2-keyboard (built-in) and
apple-inc.-magic-keyboard-with-numeric-keypad (external). Both are real keyboards
and both belong in the list, so no UNTYPED_KEYBOARDS change can separate them.

When both rest on the same layout, layoutIndex() ties, reduce keeps keyboards[0],
and that is whichever device Hyprland listed first — the built-in. That resting state
is the normal one and is exactly the state a click starts from. So the click advances
the built-in; the label follows it (now the furthest advanced, so selectKeyboard()
keeps choosing it) and reports the new layout, while the external keyboard under my
hands never moved.

No blocklist can decide which of two real keyboards a person is typing on.

Not #9552 either

#9552 reports the same wording — "bar label switches, typing doesn't" — from fcitx5
grabbing keys and committing against its own virtual keyboard. That is not this: on
this machine switching the typed-on keyboard directly does change typing,

$ hyprctl switchxkblayout apple-inc.-magic-keyboard-with-numeric-keypad next

and hl-virtual-keyboard-fcitx5 tracks the real keyboard's index rather than staying
on us. The compositor-to-app path works fine here; only the widget's choice of
device is wrong.

Steps to reproduce

  1. A laptop with its built-in keyboard, plus any external keyboard attached.
  2. Two layouts, e.g. kb_layout = "us,br".
  3. Put both keyboards on the same layout index (a hyprctl reload does it).
  4. Click the keyboard-layout bar widget.
  5. Type on the external keyboard.

Expected: typed characters follow the layout shown on the bar.
Actual: the label changes; the external keyboard still produces the old layout.

Evidence

BEFORE (both real keyboards rest on the same layout):
  at-translated-set-2-keyboard                   idx=0  English (US)
  apple-inc.-magic-keyboard-with-numeric-keypad  idx=0  English (US)

CLICK -> cycleLayout() switches only selectKeyboard()'s pick, keyboards[0]:
  $ hyprctl switchxkblayout at-translated-set-2-keyboard next

AFTER (the bar reads PT; the keyboard being typed on never moved):
  at-translated-set-2-keyboard                   idx=1  Portuguese (Brazil)
  apple-inc.-magic-keyboard-with-numeric-keypad  idx=0  English (US)

Suggested fix

Stop choosing. Move every typed keyboard, naming the target layout by index rather
than next so they cannot drift apart:

const target = layoutCount > 1 ? String((activeIndex + 1) % layoutCount) : "next"
for (const name of keyboardNames) {
  bar.run("hyprctl switchxkblayout " + Util.shellQuote(name) + " " + target)
}

The comment in cycleLayout() rules out switching the seat together because it
"would also carry the buttons along". That does not apply when only the filtered
keyboards are named — the buttons and virtual devices stay where they started, so
the reading still holds. It also makes selectKeyboard() matter only for the label,
never for correctness, which contains the blast radius of #8964 and #10135: a device
that slips through the filter would then be switched along with the real keyboards
instead of instead of them.

Addressing by index rather than next additionally repairs drift instead of
preserving it, which matters because grp:shifts_toggle creates drift routinely —
it advances only the keyboard the shifts were tapped on.

I have been running this locally as a cloned plugin; it fixes both the click and the
drift. Happy to open a PR.

Also, more filter names for #8964 / #10135

Not this issue, but data for those: on this Dell laptop the devices surviving
isTypedKeyboard() alongside the two real keyboards are intel-hid-events,
intel-hid-5-button-array, dell-wmi-hotkeys, dell-privacy-driver, and a webcam's
keyboard node (emeet-smartcam-s600:-emeet-smar). The suffix regex suggested in
#8964 catches dell-wmi-hotkeys but not the intel-hid-*, -privacy-driver or
webcam nodes.

System

  • Omarchy 4.0.3-1
  • Hyprland v0.56.2
  • Kernel 7.2.3-arch1-3
  • Dell laptop, 11th Gen Intel i5-1135G7, Intel Iris Xe Graphics
  • fcitx5 running
View raw text
## What happens

Clicking the `omarchy.keyboard-layout` bar widget changes the label but not the
layout under the keys I am typing on. This is the symptom of #8964 and #10135, but
with a cause that survives the fix both of them propose: this machine has **two real
keyboards**, and the widget switches one of them.

## Why the filter fixes do not reach it

#8964 and #10135 both address `UNTYPED_KEYBOARDS` letting a non-keyboard through, and
both resolve once the offending device is filtered out — #8964 notes that afterwards
"the widget sees 1 keyboard". That is the part this report does not duplicate.

`cycleLayout()` switches exactly one device, whatever `selectKeyboard()` settled on:

```qml
// shell/plugins/bar/widgets/KeyboardLayout.qml
root.bar.run("hyprctl switchxkblayout " + Util.shellQuote(root.keyboardName) + " next")
```

On a laptop with an external keyboard attached, two devices legitimately survive any
filter — here `at-translated-set-2-keyboard` (built-in) and
`apple-inc.-magic-keyboard-with-numeric-keypad` (external). Both are real keyboards
and both belong in the list, so no `UNTYPED_KEYBOARDS` change can separate them.

When both rest on the same layout, `layoutIndex()` ties, `reduce` keeps `keyboards[0]`,
and that is whichever device Hyprland listed first — the built-in. That resting state
is the normal one and is exactly the state a click starts from. So the click advances
the built-in; the label follows it (now the furthest advanced, so `selectKeyboard()`
keeps choosing it) and reports the new layout, while the external keyboard under my
hands never moved.

No blocklist can decide which of two real keyboards a person is typing on.

## Not #9552 either

#9552 reports the same wording — "bar label switches, typing doesn't" — from fcitx5
grabbing keys and committing against its own virtual keyboard. That is not this: on
this machine switching the typed-on keyboard directly does change typing,

```
$ hyprctl switchxkblayout apple-inc.-magic-keyboard-with-numeric-keypad next
```

and `hl-virtual-keyboard-fcitx5` tracks the real keyboard's index rather than staying
on `us`. The compositor-to-app path works fine here; only the widget's choice of
device is wrong.

## Steps to reproduce

1. A laptop with its built-in keyboard, plus any external keyboard attached.
2. Two layouts, e.g. `kb_layout = "us,br"`.
3. Put both keyboards on the same layout index (a `hyprctl reload` does it).
4. Click the keyboard-layout bar widget.
5. Type on the external keyboard.

**Expected:** typed characters follow the layout shown on the bar.
**Actual:** the label changes; the external keyboard still produces the old layout.

## Evidence

```
BEFORE (both real keyboards rest on the same layout):
  at-translated-set-2-keyboard                   idx=0  English (US)
  apple-inc.-magic-keyboard-with-numeric-keypad  idx=0  English (US)

CLICK -> cycleLayout() switches only selectKeyboard()'s pick, keyboards[0]:
  $ hyprctl switchxkblayout at-translated-set-2-keyboard next

AFTER (the bar reads PT; the keyboard being typed on never moved):
  at-translated-set-2-keyboard                   idx=1  Portuguese (Brazil)
  apple-inc.-magic-keyboard-with-numeric-keypad  idx=0  English (US)
```

## Suggested fix

Stop choosing. Move every typed keyboard, naming the target layout by index rather
than `next` so they cannot drift apart:

```qml
const target = layoutCount > 1 ? String((activeIndex + 1) % layoutCount) : "next"
for (const name of keyboardNames) {
  bar.run("hyprctl switchxkblayout " + Util.shellQuote(name) + " " + target)
}
```

The comment in `cycleLayout()` rules out switching the seat together because it
"would also carry the buttons along". That does not apply when only the filtered
keyboards are named — the buttons and virtual devices stay where they started, so
the reading still holds. It also makes `selectKeyboard()` matter only for the label,
never for correctness, which contains the blast radius of #8964 and #10135: a device
that slips through the filter would then be switched along with the real keyboards
instead of *instead of* them.

Addressing by index rather than `next` additionally repairs drift instead of
preserving it, which matters because `grp:shifts_toggle` creates drift routinely —
it advances only the keyboard the shifts were tapped on.

I have been running this locally as a cloned plugin; it fixes both the click and the
drift. Happy to open a PR.

## Also, more filter names for #8964 / #10135

Not this issue, but data for those: on this Dell laptop the devices surviving
`isTypedKeyboard()` alongside the two real keyboards are `intel-hid-events`,
`intel-hid-5-button-array`, `dell-wmi-hotkeys`, `dell-privacy-driver`, and a webcam's
keyboard node (`emeet-smartcam-s600:-emeet-smar`). The suffix regex suggested in
#8964 catches `dell-wmi-hotkeys` but not the `intel-hid-*`, `-privacy-driver` or
webcam nodes.

## System

- Omarchy 4.0.3-1
- Hyprland v0.56.2
- Kernel 7.2.3-arch1-3
- Dell laptop, 11th Gen Intel i5-1135G7, Intel Iris Xe Graphics
- fcitx5 running

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

Not linked to any known issue, other report or change yet.

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

  • Out of scopeDecided by agents · verified · 2026-10-09 11:14 UTC