Proof Portal
Omarchy
ProbeLabs65 findings · 95 requirementsA 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.
omarchy-hw-touchpad returns the wrong device when an external trackpad is connected (name regex + enumeration order)
Reported by alebak · filed Sep 15, 2026 · open at source
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
What happened
omarchy-hw-touchpad picks a touchpad by matching a name regex and taking whichever matching device Hyprland enumerates first. When a second touchpad-class device is connected, an external trackpad can shadow the built-in one — and which one wins depends only on device registration order, not on which device is internal.
On a ThinkPad E595 with an Apple Magic Trackpad connected over Bluetooth:
$ omarchy-hw-touchpad
synps/2-synaptics-touchpad # correct — but only because the Apple pad registered later
$ sudo modprobe -r psmouse && sudo modprobe psmouse # internal pad now re-registers last
$ sleep 2
$ omarchy-hw-touchpad
apple-wireless-trackpad # wrongNothing changed about the hardware — only the order in which the two devices registered.
hyprctl devices after the reload shows why:
1: lenovo-usb-receiver-1
2: lenovo-usb-receiver-consumer-control-1
3: apple-wireless-trackpad <- first() matches here
4: synps/2-synaptics-touchpad <- the device that should have been returned
5: tpps/2-elan-trackpointExpected
omarchy-hw-touchpad returns the built-in touchpad regardless of what else is connected, and regardless of registration order.
Consequences
Every consumer of the detection acts on the wrong device once it flips:
omarchy-toggle-input-device touchpad offdisables the external trackpad and leaves the built-in one live — the opposite of the user's intent.omarchy-toggle-input-device touchpad onis worse, becauseenable()clears the state file before resolving the device:
enable() {
rm -f "$NAME_FILE" # drops the persisted name of the internal pad
require_device # resolves to apple-wireless-trackpad
apply_device true # enables the Apple pad, which was already enabled
} The internal touchpad's persisted disable is lost, it stays disabled in the live session,
and it silently comes back on the next Hyprland reload. No error is printed at any point.
Note that the persisted state itself is fine — touchpad-disabled-name stores the resolved
device name, so default/hypr/disabled-input-device.lua re-applies it correctly. The defect
is purely in resolving which device to act on.
Cause
/usr/bin/omarchy-hw-touchpad:
device=$(hyprctl devices -j | jq -r '[.mice[] | .name | select(test("touchpad|trackpad"; "i"))] | first // empty')apple-wireless-trackpad matches touchpad|trackpad just as well as synps/2-synaptics-touchpad does, and first resolves the tie by enumeration order.
Suggested fix
udev already distinguishes internal from external touchpads, with no heuristics and no name matching:
$ udevadm info --query=property --name=/dev/input/event17 # built-in
ID_INPUT_TOUCHPAD=1
ID_BUS=i8042
ID_INPUT_TOUCHPAD_INTEGRATION=internal
$ udevadm info --query=property --name=/dev/input/event19 # Magic Trackpad
ID_INPUT_TOUCHPAD=1
ID_BUS=bluetooth
ID_INPUT_TOUCHPAD_INTEGRATION=externalResolving the built-in touchpad through ID_INPUT_TOUCHPAD=1 + ID_INPUT_TOUCHPAD_INTEGRATION=internal, then mapping it to its Hyprland device name, removes the ambiguity entirely.
It is worth noting that ID_INPUT_POINTINGSTICK=1 devices also carry ID_INPUT_MOUSE=1 (the ThinkPad TrackPoint does), so any pointer-classification logic needs to exclude pointing sticks explicitly.
One caveat for whoever implements this
ID_INPUT_TOUCHPAD_INTEGRATION is not guaranteed to be present. It is derived from ID_INTEGRATION in 65-integration.rules, which bails out early when ID_BUS is unset:
ENV{ID_BUS}=="", GOTO="integration_end"
ENV{ID_BUS}=="acpi|platform|i8042|i2c|rmi|spi|pci", ENV{ID_INTEGRATION}="internal"
ENV{ID_BUS}=="bluetooth", ENV{ID_INTEGRATION}="external"
DRIVERS=="usb", ATTRS{removable}=="fixed", ENV{ID_INTEGRATION}="internal"
DRIVERS=="usb", ATTRS{removable}=="removable|unknown", ENV{ID_INTEGRATION}="external"so a device with no ID_BUS, or a USB device matching none of the removable branches, ends up with the property absent. Those unclassified devices are likely to overlap with the unusual hardware in the issues listed below, so the lookup should fail safe: treat only a device explicitly marked internal as the built-in touchpad, and return nothing when the property is missing rather than falling back to a name match. Acting on the wrong device is worse than not acting.
(Worth noting for anyone reading the rules: the classification is by physical integration, not by connection type — a USB touchpad soldered to the board reports removable=fixed and is correctly classified internal.)
Related open issues — same root cause
These are all "omarchy-hw-touchpad fails to detect \<device\>" because the name regex matches too little:
- #9805 —
synaptics-tm3096-006not detected - #9252 — touchpads whose libinput name contains neither "touchpad" nor "trackpad" (
synaptics-tm3053-004) - #9190 — Apple
bcm5974trackpad not detected - #8376 — Apple Touch (MTP) trackpads not detected, so
omarchy-toggle-touchpadsilently does nothing
This report is the same defect seen from the other side — the regex matching too much rather than too little. A udev-based lookup would address all of them together.
System
| Omarchy | 4.0.3-1 |
| Hyprland | 0.56.2 |
| Kernel | 7.2.3-arch1-3 |
| CPU | AMD Ryzen 5 3500U with Radeon Vega Mobile Gfx |
| Machine | ThinkPad E595 |
| jq | 1.8.2 |
Devices involved: built-in SynPS/2 Synaptics TouchPad (i8042), TPPS/2 Elan TrackPoint (i8042), Apple Magic Trackpad over Bluetooth (apple-wireless-trackpad).
View raw text
## What happened
`omarchy-hw-touchpad` picks a touchpad by matching a name regex and taking whichever matching device Hyprland enumerates first. When a second touchpad-class device is connected, an external trackpad can shadow the built-in one — and which one wins depends only on device registration order, not on which device is internal.
On a ThinkPad E595 with an Apple Magic Trackpad connected over Bluetooth:
```console
$ omarchy-hw-touchpad
synps/2-synaptics-touchpad # correct — but only because the Apple pad registered later
$ sudo modprobe -r psmouse && sudo modprobe psmouse # internal pad now re-registers last
$ sleep 2
$ omarchy-hw-touchpad
apple-wireless-trackpad # wrong
```
Nothing changed about the hardware — only the order in which the two devices registered.
`hyprctl devices` after the reload shows why:
```
1: lenovo-usb-receiver-1
2: lenovo-usb-receiver-consumer-control-1
3: apple-wireless-trackpad <- first() matches here
4: synps/2-synaptics-touchpad <- the device that should have been returned
5: tpps/2-elan-trackpoint
```
## Expected
`omarchy-hw-touchpad` returns the built-in touchpad regardless of what else is connected, and regardless of registration order.
## Consequences
Every consumer of the detection acts on the wrong device once it flips:
- `omarchy-toggle-input-device touchpad off` disables the **external** trackpad and leaves the built-in one live — the opposite of the user's intent.
- `omarchy-toggle-input-device touchpad on` is worse, because `enable()` clears the state file *before* resolving the device:
```bash
enable() {
rm -f "$NAME_FILE" # drops the persisted name of the internal pad
require_device # resolves to apple-wireless-trackpad
apply_device true # enables the Apple pad, which was already enabled
}
```
The internal touchpad's persisted disable is lost, it stays disabled in the live session,
and it silently comes back on the next Hyprland reload. No error is printed at any point.
Note that the persisted state itself is fine — `touchpad-disabled-name` stores the resolved
device *name*, so `default/hypr/disabled-input-device.lua` re-applies it correctly. The defect
is purely in resolving *which* device to act on.
## Cause
`/usr/bin/omarchy-hw-touchpad`:
```bash
device=$(hyprctl devices -j | jq -r '[.mice[] | .name | select(test("touchpad|trackpad"; "i"))] | first // empty')
```
`apple-wireless-trackpad` matches `touchpad|trackpad` just as well as `synps/2-synaptics-touchpad` does, and `first` resolves the tie by enumeration order.
## Suggested fix
udev already distinguishes internal from external touchpads, with no heuristics and no name matching:
```console
$ udevadm info --query=property --name=/dev/input/event17 # built-in
ID_INPUT_TOUCHPAD=1
ID_BUS=i8042
ID_INPUT_TOUCHPAD_INTEGRATION=internal
$ udevadm info --query=property --name=/dev/input/event19 # Magic Trackpad
ID_INPUT_TOUCHPAD=1
ID_BUS=bluetooth
ID_INPUT_TOUCHPAD_INTEGRATION=external
```
Resolving the built-in touchpad through `ID_INPUT_TOUCHPAD=1` + `ID_INPUT_TOUCHPAD_INTEGRATION=internal`, then mapping it to its Hyprland device name, removes the ambiguity entirely.
It is worth noting that `ID_INPUT_POINTINGSTICK=1` devices also carry `ID_INPUT_MOUSE=1` (the ThinkPad TrackPoint does), so any pointer-classification logic needs to exclude pointing sticks explicitly.
### One caveat for whoever implements this
`ID_INPUT_TOUCHPAD_INTEGRATION` is not guaranteed to be present. It is derived from `ID_INTEGRATION` in `65-integration.rules`, which bails out early when `ID_BUS` is unset:
```
ENV{ID_BUS}=="", GOTO="integration_end"
ENV{ID_BUS}=="acpi|platform|i8042|i2c|rmi|spi|pci", ENV{ID_INTEGRATION}="internal"
ENV{ID_BUS}=="bluetooth", ENV{ID_INTEGRATION}="external"
DRIVERS=="usb", ATTRS{removable}=="fixed", ENV{ID_INTEGRATION}="internal"
DRIVERS=="usb", ATTRS{removable}=="removable|unknown", ENV{ID_INTEGRATION}="external"
```
so a device with no `ID_BUS`, or a USB device matching none of the `removable` branches, ends up with the property absent. Those unclassified devices are likely to overlap with the unusual hardware in the issues listed below, so the lookup should fail safe: treat only a device explicitly marked `internal` as the built-in touchpad, and return nothing when the property is missing rather than falling back to a name match. Acting on the wrong device is worse than not acting.
(Worth noting for anyone reading the rules: the classification is by *physical integration*, not by connection type — a USB touchpad soldered to the board reports `removable=fixed` and is correctly classified `internal`.)
## Related open issues — same root cause
These are all "`omarchy-hw-touchpad` fails to detect \<device\>" because the name regex matches too little:
- #9805 — `synaptics-tm3096-006` not detected
- #9252 — touchpads whose libinput name contains neither "touchpad" nor "trackpad" (`synaptics-tm3053-004`)
- #9190 — Apple `bcm5974` trackpad not detected
- #8376 — Apple Touch (MTP) trackpads not detected, so `omarchy-toggle-touchpad` silently does nothing
This report is the same defect seen from the other side — the regex matching *too much* rather than too little. A udev-based lookup would address all of them together.
## System
| | |
|---|---|
| Omarchy | 4.0.3-1 |
| Hyprland | 0.56.2 |
| Kernel | 7.2.3-arch1-3 |
| CPU | AMD Ryzen 5 3500U with Radeon Vega Mobile Gfx |
| Machine | ThinkPad E595 |
| jq | 1.8.2 |
Devices involved: built-in `SynPS/2 Synaptics TouchPad` (i8042), `TPPS/2 Elan TrackPoint` (i8042), Apple Magic Trackpad over Bluetooth (`apple-wireless-trackpad`).
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 14:00 UTC