Repository navigation
Conversation
|
One source-supported regression: fixed QWERTY positions change the injected shortcut on other Latin layouts. Preserve logical letters on non-QWERTY layoutsThe new keycode constants bypass keysym lookup, but a physical keycode does not preserve the letter across layouts. With a single Dvorak layout ( Source-traced normal-application chords, not observed application behavior:
Hyprland 0.56.2 accepts Impact: these shortcuts can invoke unrelated actions or do nothing instead of copy/paste/cut/select-all. Ctrl+Q can quit applications that bind it; individual client reactions were not tested. Suggested change: preserve logical letter selection on non-QWERTY layouts. Make the non-Latin fallback aware of the layout used for the injected event, rather than applying US physical positions globally. Verified: source inspection confirms that Review informationTest scope: conclusions are supported by pinned Omarchy/Hyprland source and XKB layout definitions. No compositor or application-level clipboard testing; proposed corrections are untested. Community review: Independent automated community review, unaffiliated with the Omarchy team, intended to help prepare PRs for their review. Automated AI review: Astra Medium initial inspection and synthesis, independent Opus 5.5 High and GPT 6 Sol Xhigh technical reviews, and a fresh Astra Medium editorial check. |
c2503ef to
02b3eb8
Compare
02b3eb8 to
290d0ed
Compare
|
Updated at "290d0ede" on current "quattro". Thanks @VivusCo for the detailed #12570 reproduction, and thanks @ivankuznetsov for catching the Dvorak boundary in #7375 and implementing the layout-aware resolver in "705c7fd". That prior work materially changed this revision — instead of replacing the broken keysym lookup with fixed QWERTY positions, this now resolves the logical clipboard letter from the configured primary XKB layout first. I also went back through #9130, #7375, and #7283 before updating this head:
The current patch now covers "A/C/V/X", not just "C/V/X". It preserves current "quattro" terminal behavior ("Ctrl+Shift+C/V") and resolves those logical letters through the same primary-layout mapping instead of reverting to the older "Insert" shortcuts. Regression coverage now includes:
The branch is one commit ahead / zero behind current "quattro". Thanks also @nazarenkodima, @Krol-X, @ivantsukev, and @yashranaway for the prior implementations/testing that made the compatibility boundaries much clearer. Executable repo tests and live compositor/application validation are still pending. |
Automated AI review
Follow-up on the earlier review, checked at Outcome: the earlier finding (fixed QWERTY positions change the shortcut on other Latin layouts) is resolved. Two narrower, configuration-specific issues remain in the new resolver, plus a robustness gap when the user's Compose file is broken. Earlier finding: resolvedVerified: the resolver now asks
Verified in sandboxed runs with real
Per-device keymaps and
|
|
Confirming measurement from a live non-Latin session (per @linyiru request in #12557): primary-layout resolution is the shape that survives a non-QWERTY primary. Environment: Hyprland 0.56.2, layouts us,ru,us. xkbcli how-to-type on us-dvorak gives C/V/X/A = 31/60/56/38, vs hardcoded QWERTY 54/55/53/38 in #9130 — so #9130 sends CTRL+J/K/Q on a Dvorak primary while this PR resolves correctly. Our ru pack runs the keycode equivalent live under RU secondary + QWERTY primary with no issues, which is consistent: both shapes agree exactly when the primary is QWERTY, and only this one holds otherwise. One note: this depends on xkbcli being present at runtime — worth a fallback (or a configure-time check) for minimal installs. |
…13007 # Conflicts: # default/hypr/bindings/clipboard.lua
…ted letter A keymap set through input.kb_file overrides the kb_* rules the resolver reads, so it sent the QWERTY position into a keymap that put another letter there: Ctrl+K for paste and Ctrl+Q for cut under a Dvorak kb_file. Fall back to the named key there, which Hyprland resolves against the real keymap. xkbcli lists a letter at every level it appears on, and in us(3l) an uppercase A on level 6 of another key sorted first, so select-all sent that key. Look up the lowercase letter and take only level 1, as an application reads a Ctrl chord. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The clipboard manager bind on quattro is a { panel = ... } bind, which o.bind turns into hl.dsp.global, so loading clipboard.lua against the fake hl needs it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Reviewed and tested at The bug is real and this fixes it. I loaded Pushed to your branch:
Tests on the worker: Still open: keyboards with their own Second opinion: Codex Medium reviewed the branch after these fixes. It raised the per-device case above. It also flagged that the resolver runs |
|
| local config = { | ||
| layout = tostring(hl.get_config("input.kb_layout") or "us"), | ||
| variant = tostring(hl.get_config("input.kb_variant") or ""), | ||
| model = tostring(hl.get_config("input.kb_model") or ""), | ||
| options = tostring(hl.get_config("input.kb_options") or ""), | ||
| rules = tostring(hl.get_config("input.kb_rules") or ""), |
There was a problem hiding this comment.
Keyboard overrides send wrong letters
resolve_primary_keycode reads only global input.kb_* settings. If a keyboard has its own Dvorak layout while the global layout is us, copy resolves to code:54 instead of Dvorak's code:31. The focused application receives the wrong shortcut.
Resolve against the keyboard used for the injected event, including its overrides, and include those settings in the cache key.
| local pipe = io.popen(table.concat(command, " ") .. " 2>/dev/null") | ||
| if not pipe then | ||
| keycode_cache[cache_key] = key | ||
| return key | ||
| end | ||
|
|
||
| local output = pipe:read("*a") or "" | ||
| pipe:close() |
There was a problem hiding this comment.
First shortcuts block desktop events
Each uncached shortcut runs xkbcli and waits for all its output inside the Hyprland callback. The compositor waits for a keymap build before sending the shortcut, once for each letter and again after settings change. A slow resolver also delays other desktop events.
Move this work out of the keypress callback, or resolve asynchronously and cache the result.
Summary
Fixes #12570.
Universal "SUPER+A/C/V/X" shortcuts currently inject logical letters through Hyprland's "send_key_state".
When a non-Latin XKB group such as Russian is active, Hyprland may fail to resolve the Latin keysym and report:
send_key_state: key not found
Using fixed QWERTY keycodes avoids that lookup, but introduces a different regression: physical key positions do not preserve logical "A/C/V/X" across layouts such as Dvorak and French AZERTY.
This revision resolves each logical clipboard letter against the configured primary XKB layout, then injects the resulting "code:N" keycode.
That gives us both invariants:
Behavior
For a primary QWERTY layout:
A → code:38
C → code:54
V → code:55
X → code:53
For a primary Dvorak layout, the same logical shortcuts resolve to their Dvorak positions instead:
C → code:31
V → code:60
X → code:56
For French AZERTY:
A → code:24
So "SUPER+A" still produces logical "Ctrl+A" instead of the fixed-QWERTY "Ctrl+Q" regression.
Implementation
The shortcut callback reads the current configured XKB inputs:
It resolves the requested logical letter with:
xkbcli how-to-type
and selects the keycode belonging to the primary configured layout.
Resolved values are cached by:
letter + layout + variant + model + options + rules
so repeated shortcuts do not spawn another resolver process unless the XKB configuration changes.
The fallback deliberately preserves the existing named-key behavior if resolution fails. It does not guess a QWERTY physical position.
Terminal behavior
Current "quattro" uses:
Ctrl+Shift+C
Ctrl+Shift+V
for terminal copy/paste.
This revision preserves those semantics.
Only the logical "C" / "V" position is resolved through the configured primary layout before injection.
It does not revert terminal behavior to the older "Ctrl+Insert" / "Shift+Insert" implementation.
Existing key-state timing
The existing "send_shortcut_once()" down/up lifecycle and its "50 ms" release timer are unchanged.
This PR addresses key resolution only.
The separate held-"SUPER" / synthetic retrigger concerns discussed in #7027 and #10701 are a different invariant and are intentionally not folded into this patch.
Related work / consolidation
This PR consolidates several overlapping attempts so maintainers do not need to reconstruct the history:
If this revision lands, #9130 should no longer need a separate review path for the same underlying fix.
Credits
Thanks @VivusCo for the current #12570 reproduction and for tracing the failure to active-group keysym resolution.
Thanks @nazarenkodima for the earlier #7375 work, and especially @ivankuznetsov for identifying the Dvorak boundary and implementing the primary-layout-aware resolver in "705c7fd". That prior work avoided repeating the same fixed-QWERTY mistake here.
Thanks @Krol-X and @ivantsukev for the additional real-layout testing and for documenting the compatibility requirements around QWERTY, Dvorak, Bulgarian/non-Latin layouts, and application behavior.
Thanks @yashranaway for keeping the fixed-keycode path moving in #9130 as well.
Regression coverage
"hyprland-default-config-test.sh" now exercises the production resolver against real "xkbcli" keymap resolution.
QWERTY + non-Latin secondary layout
us,ru
Requires:
SUPER+A → Ctrl + code:38
SUPER+C → Ctrl + code:54
SUPER+V → Ctrl + code:55
SUPER+X → Ctrl + code:53
Dvorak + non-Latin secondary layout
us,ru
variant: dvorak,
Requires:
SUPER+C → Ctrl + code:31
SUPER+V → Ctrl + code:60
SUPER+X → Ctrl + code:56
and verifies the current terminal semantics remain:
SUPER+C → Ctrl+Shift + logical C position
SUPER+V → Ctrl+Shift + logical V position
French AZERTY
fr,ru
Requires:
SUPER+A → Ctrl + code:24
so select-all cannot regress to the QWERTY physical "A" position.
The regression also pins the existing "50 ms" key-up timer so this change cannot silently absorb the separate dispatch-timing behavior.
Verification status
Rebuilt as one commit on current "quattro":
head: 290d0ed
base: 28ceaae
ahead: 1
behind: 0
The implementation and final diff have been audited against the prior #7375/#9130/#7283 lineage.
The historical layout-aware implementation in "705c7fd" was previously reported with focused QWERTY/Dvorak tests passing; this revision adapts that design to current "quattro", adds "SUPER+A", and preserves today's terminal "Ctrl+Shift+C/V" behavior.
Executable repository tests have not been rerun in this environment.
Final live acceptance should cover:
Fixes #12570.