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.
[Bug] Modifier key (Shift) release events dropped with fcitx5-rime — Shift cannot switch Chinese/English (Hyprland 0.56.2 keybinds refactor regression)
Reported by jfdnet · filed Aug 18, 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
[Bug] Modifier key (Shift) release events dropped with fcitx5-rime — Shift cannot switch Chinese/English (Hyprland 0.56.2 keybinds refactor regression)
Summary
On Omarchy 4.0.0-1 (shipped Hyprland 0.56.2), when fcitx5-rime is the active IME, press events for the Shift modifier key reach the IME but the release events are dropped. This breaks Shift-to-toggle-Chinese/English for all Rime-based IME users, and additionally leaves fcitx5's modifier state stuck (every subsequent key carries the Shift modifier until something else clears it).
This is an upstream Hyprland bug (reported to hyprwm/Hyprland as #15886, auto-closed by the bot which requires a discussion first). Since Omarchy ships Hyprland 0.56.2 and this affects Omarchy users out of the box, reporting here so it can be tracked/pinned/fixed on this distribution.
Omarchy & System Details
- Omarchy: 4.0.0-1
- Hyprland: 0.56.2, commit
efb50993780079460b0cbed1363e2166a2de1d9f(2026-08-05, includes keybinds refactor #15568) - Kernel: 7.1.8-arch1-3
- CPU/GPU: Intel Panther Lake + NVIDIA RTX 5060 Max-Q (desktop renders on Intel)
- IME: fcitx5 5.1.21 + fcitx5-rime 5.1.14 (Wayland native input method protocol v1)
Steps to reproduce
- Use the default Omarchy setup (Hyprland + fcitx5-rime with 万象/wanxiang or any Rime schema).
- In Rime, configure the standard
ascii_composerShift toggle (switch_key: Shift_L: commit_code). - Focus a text input (e.g. ghostty), ensure fcitx5 is active.
- Tap the left Shift key.
Expected: Chinese ⇄ English toggles (Rime's ascii_composer toggles on Shift release within 500 ms).
Actual: nothing happens; fcitx5's Shift modifier state gets stuck.
Evidence (fcitx5 debug log, rimeengine.cpp:447 "Rime receive key")
Physical Shift tap — 5 presses, 0 releases:
Aug 18 10:58:05 Rime receive key: Key(Shift_L states=16) 0 <- press
Aug 18 10:58:06 Rime receive key: Key(Shift_L states=16) 0 <- press
Aug 18 10:58:06 Rime receive key: Key(Shift_L states=16) 0 <- press
Aug 18 10:58:06 Rime receive key: Key(Shift_L states=16) 0 <- press
Aug 18 10:58:06 Rime receive key: Key(Shift_L states=16) 0 <- press
(no "… 1" release event ever arrives)Normal keys in the same window deliver press+release correctly (0=press, 1=release):
Aug 18 10:58:01 Rime receive key: Key(a states=16) 0 <- press
Aug 18 10:58:01 Rime receive key: Key(a states=16) 1 <- release
Aug 18 10:58:02 Rime receive key: Key(a states=16) 0 <- press
Aug 18 10:58:02 Rime receive key: Key(a states=16) 1 <- releaseAfter the dropped release, the Shift modifier stays stuck on subsequent keys:
Aug 18 10:58:11 Rime receive key: Key(d states=16) 0
Aug 18 10:58:11 Rime receive key: Key(e states=16) 0
Aug 18 10:58:11 Rime receive key: Key(space states=16) 0Even wtype (virtual keyboard) injection mostly loses Shift releases: 16 presses reached the IME, only 2 releases.
Root cause analysis (upstream)
- Regression window: keybinds refactor hyprwm/Hyprland#15568 "keybinds: refactor, clean up code, move to new style" (merged 2026-08-05 — exactly this build's date).
src/keybinds/has had no commits since, so 0.56.2 ships the refactor with no follow-up fixes. - The release-drop is somewhere between
IKeyboard's key listener (which emits releases fine — normal keys prove it) andCInputMethodKeyboardGrabV2::sendKey(which has no filtering). Candidates:CKeybindManager::onKeyEventrelease handling, or theshareKeyFromAllKBsmerge inCInputManager::onKeyboardKey. - This machine has 6 keyboard devices (video-bus ×2, intel-hid-events, power-button, sleep-button, at-translated-set-2-keyboard); the multi-keyboard state merge may also be involved.
Workaround (verified working on this machine)
Since the Shift press reliably reaches the IME, toggle ascii_mode on press via a Rime Lua processor instead of relying on the release event (with a 300 ms window to distinguish taps from chords):
-- ~/.local/share/fcitx5/rime/lua/wanxiang/shift_toggle.lua
local M = {}
local get_ms = (rime_api and rime_api.get_time_ms) or function() return os.time() * 1000 end
local WINDOW_MS = 300
local shift_press_time, shift_toggled = 0, false
local function is_shift(r) return r == "Shift_L" or r == "Shift_R" end
local function toggle(ctx) ctx:set_option("ascii_mode", not ctx:get_option("ascii_mode")) end
function M.func(key, env)
local ctx, now = env.engine.context, get_ms()
if key:release() then return 2 end
local repr = key:repr()
if is_shift(repr) and not (key:ctrl() or key:alt() or key:super()) then
if now - shift_press_time < WINDOW_MS then
if shift_toggled then toggle(ctx); shift_toggled = false end
shift_press_time = 0
return 2
end
if shift_toggled then shift_toggled = false end
if ctx:is_composing() then ctx:commit() end
toggle(ctx); shift_toggled = true; shift_press_time = now
return 2
end
if shift_toggled then
if now - shift_press_time < WINDOW_MS then toggle(ctx) end
shift_toggled = false
end
return 2
end
return MPlus set ascii_composer.switch_key: Shift_L: noop / Shift_R: noop to disable Rime's release-based toggle (avoid double-toggle once upstream fixes the release delivery).
Ask
- Can Omarchy track/pin this Hyprland regression (and possibly carry a patch or bump Hyprland when the upstream fix lands)?
- Happy to provide more diagnostics (wev comparisons, bisect builds) or help test a fix.
View raw text
# [Bug] Modifier key (Shift) release events dropped with fcitx5-rime — Shift cannot switch Chinese/English (Hyprland 0.56.2 keybinds refactor regression)
## Summary
On Omarchy 4.0.0-1 (shipped Hyprland 0.56.2), when fcitx5-rime is the active IME, **press events for the Shift modifier key reach the IME but the release events are dropped**. This breaks Shift-to-toggle-Chinese/English for all Rime-based IME users, and additionally leaves fcitx5's modifier state **stuck** (every subsequent key carries the Shift modifier until something else clears it).
This is an upstream Hyprland bug (reported to hyprwm/Hyprland as #15886, auto-closed by the bot which requires a discussion first). Since Omarchy ships Hyprland 0.56.2 and this affects Omarchy users out of the box, reporting here so it can be tracked/pinned/fixed on this distribution.
## Omarchy & System Details
- Omarchy: 4.0.0-1
- Hyprland: 0.56.2, commit `efb50993780079460b0cbed1363e2166a2de1d9f` (2026-08-05, includes keybinds refactor #15568)
- Kernel: 7.1.8-arch1-3
- CPU/GPU: Intel Panther Lake + NVIDIA RTX 5060 Max-Q (desktop renders on Intel)
- IME: fcitx5 5.1.21 + fcitx5-rime 5.1.14 (Wayland native input method protocol v1)
## Steps to reproduce
1. Use the default Omarchy setup (Hyprland + fcitx5-rime with 万象/wanxiang or any Rime schema).
2. In Rime, configure the standard `ascii_composer` Shift toggle (`switch_key: Shift_L: commit_code`).
3. Focus a text input (e.g. ghostty), ensure fcitx5 is active.
4. Tap the left Shift key.
**Expected**: Chinese ⇄ English toggles (Rime's ascii_composer toggles on Shift *release* within 500 ms).
**Actual**: nothing happens; fcitx5's Shift modifier state gets stuck.
## Evidence (fcitx5 debug log, `rimeengine.cpp:447 "Rime receive key"`)
Physical Shift tap — 5 presses, **0 releases**:
```
Aug 18 10:58:05 Rime receive key: Key(Shift_L states=16) 0 <- press
Aug 18 10:58:06 Rime receive key: Key(Shift_L states=16) 0 <- press
Aug 18 10:58:06 Rime receive key: Key(Shift_L states=16) 0 <- press
Aug 18 10:58:06 Rime receive key: Key(Shift_L states=16) 0 <- press
Aug 18 10:58:06 Rime receive key: Key(Shift_L states=16) 0 <- press
(no "… 1" release event ever arrives)
```
Normal keys in the same window deliver press+release correctly (`0`=press, `1`=release):
```
Aug 18 10:58:01 Rime receive key: Key(a states=16) 0 <- press
Aug 18 10:58:01 Rime receive key: Key(a states=16) 1 <- release
Aug 18 10:58:02 Rime receive key: Key(a states=16) 0 <- press
Aug 18 10:58:02 Rime receive key: Key(a states=16) 1 <- release
```
After the dropped release, the Shift modifier stays stuck on subsequent keys:
```
Aug 18 10:58:11 Rime receive key: Key(d states=16) 0
Aug 18 10:58:11 Rime receive key: Key(e states=16) 0
Aug 18 10:58:11 Rime receive key: Key(space states=16) 0
```
Even wtype (virtual keyboard) injection mostly loses Shift releases: 16 presses reached the IME, only 2 releases.
## Root cause analysis (upstream)
- Regression window: keybinds refactor **hyprwm/Hyprland#15568 "keybinds: refactor, clean up code, move to new style"** (merged 2026-08-05 — exactly this build's date). `src/keybinds/` has had no commits since, so 0.56.2 ships the refactor with no follow-up fixes.
- The release-drop is somewhere between `IKeyboard`'s key listener (which emits releases fine — normal keys prove it) and `CInputMethodKeyboardGrabV2::sendKey` (which has no filtering). Candidates: `CKeybindManager::onKeyEvent` release handling, or the `shareKeyFromAllKBs` merge in `CInputManager::onKeyboardKey`.
- This machine has 6 keyboard devices (video-bus ×2, intel-hid-events, power-button, sleep-button, at-translated-set-2-keyboard); the multi-keyboard state merge may also be involved.
## Workaround (verified working on this machine)
Since the Shift *press* reliably reaches the IME, toggle `ascii_mode` on press via a Rime Lua processor instead of relying on the release event (with a 300 ms window to distinguish taps from chords):
```lua
-- ~/.local/share/fcitx5/rime/lua/wanxiang/shift_toggle.lua
local M = {}
local get_ms = (rime_api and rime_api.get_time_ms) or function() return os.time() * 1000 end
local WINDOW_MS = 300
local shift_press_time, shift_toggled = 0, false
local function is_shift(r) return r == "Shift_L" or r == "Shift_R" end
local function toggle(ctx) ctx:set_option("ascii_mode", not ctx:get_option("ascii_mode")) end
function M.func(key, env)
local ctx, now = env.engine.context, get_ms()
if key:release() then return 2 end
local repr = key:repr()
if is_shift(repr) and not (key:ctrl() or key:alt() or key:super()) then
if now - shift_press_time < WINDOW_MS then
if shift_toggled then toggle(ctx); shift_toggled = false end
shift_press_time = 0
return 2
end
if shift_toggled then shift_toggled = false end
if ctx:is_composing() then ctx:commit() end
toggle(ctx); shift_toggled = true; shift_press_time = now
return 2
end
if shift_toggled then
if now - shift_press_time < WINDOW_MS then toggle(ctx) end
shift_toggled = false
end
return 2
end
return M
```
Plus set `ascii_composer.switch_key: Shift_L: noop` / `Shift_R: noop` to disable Rime's release-based toggle (avoid double-toggle once upstream fixes the release delivery).
## Ask
- Can Omarchy track/pin this Hyprland regression (and possibly carry a patch or bump Hyprland when the upstream fix lands)?
- Happy to provide more diagnostics (wev comparisons, bisect builds) or help test a fix.
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 04:39 UTC