Skip to content

Preserve user keyboard remaps in the Cua Hyprland plugin - #473

Merged
spencerbull merged 2 commits into
omacom:masterfrom
spencerbull:cua-agent-keymap-remaps
Sep 16, 2026
Merged

spencerbull merged 2 commits into
omacom:masterfrom
spencerbull:cua-agent-keymap-remaps

Conversation

@spencerbull

@spencerbull spencerbull commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

A keyboard remap such as Caps Lock -> Ctrl made the Cua Hyprland plugin refuse every raw input operation, including clicks and drags. Num Lock also independently blocked all foreground typing. This packages cua-hyprland-plugin 0.26.1-5 with independent US keymaps for both background agent keyboards and operation-specific foreground validation, preserving the user's keyboard configuration.

Plain pointer operations and activation no longer require a stock layout. Foreground input validates the requested key sequence against the actual XKB map and modifier state before activation or delivery. Compatible Num Lock state is preserved throughout delivery and cleanup. Keys whose symbols or shortcut semantics change, including affected keypad keys, still refuse; Caps Lock, other unsupported locks, held/latched modifiers, and nonzero layout groups remain guarded. State changes between validation and delivery cancel the operation. Arbitrary foreground layout translation, Unicode/IME, and broader background application admission remain outside this change.

The immutable upstream archive and ABI verifier remain intact. A separately checksummed downstream patch and complete final source inventory are checked before build, check, and packaging. The installed build record identifies the upstream base and downstream changes. Companion installation PR: omacom/omarchy#11342. Root keyboard_layout_independent and foreground_numlock_compatible markers remain available while input is disabled, allowing the installer to detect an older mapped module and request a fresh desktop session without hot replacement.

Validation:

  • Built with ./bin/build --package cua-hyprland-plugin for edge x86_64; all 19 CTests and five package-integrity tests pass. Nine Num Lock regression mutations are rejected.
  • Extracted-production tests exercise modifier capture, shared keyboards, preflight, initial modifier delivery, key dispatch, drift cancellation, and cleanup against real XKB state. Independent source and installer review found no blocking findings.
  • Installed the exact artifact and verified package files, module identity and consumer compatibility. A fresh login loaded the new capability successfully with ctrl:nocaps and Num Lock enabled.
  • Through the installed Cua Driver daemon's persistent MCP connection, launched ChatGPT, started a new chat, typed and submitted two questions, and observed 391 and Paris in fresh screenshots. Ctrl+A replaced a disposable draft correctly. Plugin dispatches increased from 0 to 161; no held keys/buttons or active leases remained, Num Lock stayed enabled, and saved configuration hashes were unchanged.

Artifact SHA-256: 6880a4b31dba6d94ceb8b976cea15b317fd6fd85c9b87cd1e551c1b18181c109. Module SHA-256: 190344569219179be4045e2d571e2d4e8c7b3944c6bdc5f973c945fed03e1f6d.

Draft pending complete native background qualification: ChatGPT exercised foreground input; Electron raw background input remains outside the admitted application set. Concurrent background lanes and the full upstream native matrix have not been replayed for this downstream candidate. Historical upstream qualification does not certify this patch.

Generated by Codex in T3 Code; independently reviewed by Codex.

Give background agent seats independent keymaps and check foreground keyboard compatibility per operation. Package the downstream patch with separate source integrity and build provenance, retaining the upstream ABI verifier.

Co-Authored-By: Codex XHigh <noreply@openai.com>
@spencerbull
spencerbull marked this pull request as ready for review September 16, 2026 05:07
@spencerbull
spencerbull merged commit 1f5b7a0 into omacom:master Sep 16, 2026
2 checks passed
@spencerbull
spencerbull deleted the cua-agent-keymap-remaps branch September 16, 2026 05:08
f-trycua added a commit to osamahbeig/cua that referenced this pull request Sep 28, 2026
…ged chords

Maintainer decision on trycua#3970: foreground keyboard delivery must not clear or
restore Num Lock or Caps Lock. Clearing them sent the focused client a
modifier change around every foreground action, and Omarchy turns Num Lock on
by default.

- Leave the human keyboard's modifiers and locks untouched. Before consuming
  the grant or changing focus, simulate the whole KEY chord under the live
  keymap and lock state and admit it only when it means what the wire chord
  means on a neutral canonical US keyboard (symbols, consumed modifiers, and
  resulting modifier state). Num Lock is resolved through the live keymap.
- Refuse with specific details: foreground_keyboard_caps_lock under Caps
  Lock, foreground_keyboard_numlock_keypad when Num Lock changes a keypad key
  in the chord, foreground_unsupported_layout for a remapped chord, and
  foreground_keyboard_locked for any other lock. A modifier or lock change
  during the action refuses the rest of it (foreground_keyboard_state), and
  the unwind restores the human keyboard's current state.
- Keep the up-front typing-keymap qualification from the previous commit, so
  a different typing layout still refuses before any text is typed. Drop the
  per-key backstop and the byte-identical keymap comparison it replaced.
- Report keyboard_layout_independent and foreground_numlock_compatible in
  hyprctl -j cua:status for v3 builds, whether or not input is enabled, so
  Omarchy's Cua Input toggle can tell this module from an older one.
- Tests: the keymap and chord tests compile real keymaps, and the foreground
  modifier test compiles the production admission, dispatch, and unwind
  methods against fake compositor objects. They need xkbcommon and skip
  without it unless CUA_HYPRLAND_REQUIRE_XKBCOMMON is set. The mocked v3
  status test checks both fields.

Adapted from omacom/omarchy-pkgs#473 (independent-keymaps.patch, MIT).

Co-authored-by: Spencer Bull <7035687+spencerbull@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
f-trycua added a commit to trycua/cua that referenced this pull request Sep 28, 2026
…eymap options (#3970)

* fix(cua-driver): allow Hyprland foreground typing with lock keys and keymap options

Foreground keyboard delivery refused whenever any keyboard had a lock
modifier set, and whenever the physical keymap was not byte-identical to
canonical evdev/pc105/us. Omarchy enables Num Lock by default
(numlock_by_default) and ships kb_options
compose:caps,shift:both_capslock_cancel, so type_text always refused with
foreground_keyboard_locked or unsupported_layout on a stock install.

- Lock modifiers no longer refuse. Agent keystrokes are delivered with
  locks cleared and the primary keyboard's modifier state is restored when
  the foreground action finishes. Held keys, latched modifiers and a
  non-zero layout group still refuse.
- Keymap qualification is per key: each pressed key must produce the same
  keysym under the physical keymap as under the canonical US keymap.
  Options that leave typed keys unchanged qualify; a differing key refuses
  before delivery.
- Update the input v3 contract and the Linux skill doc accordingly.

* fix(cua-driver): qualify the Hyprland typing keymap before activation

With per-key checking alone, a genuinely different layout (German, Dvorak,
swapped modifiers) refused at the first differing key, after earlier
characters of a string had already been typed. Qualify the physical keymap
once per keymap change instead: every key the KEY command can press (evdev
1-247 except the lock keys) must produce the same keysym as the canonical
US keymap, at the base level and, for non-modifier keys, with Shift held.
Options that only change Caps Lock or modifier chords still qualify.

layout_qualified() now uses that result, so a non-equivalent layout refuses
before activation. The per-key check stays as a backstop. The comparison
lives in keymap_equivalence.hpp with a test that compiles real keymaps and
skips when XKB data is unavailable; given a path it reports on a dumped
keymap (for example from `xkbcli dump-keymap-wayland`).

* fix(cua-driver): keep Hyprland foreground locks and admit only unchanged chords

Maintainer decision on #3970: foreground keyboard delivery must not clear or
restore Num Lock or Caps Lock. Clearing them sent the focused client a
modifier change around every foreground action, and Omarchy turns Num Lock on
by default.

- Leave the human keyboard's modifiers and locks untouched. Before consuming
  the grant or changing focus, simulate the whole KEY chord under the live
  keymap and lock state and admit it only when it means what the wire chord
  means on a neutral canonical US keyboard (symbols, consumed modifiers, and
  resulting modifier state). Num Lock is resolved through the live keymap.
- Refuse with specific details: foreground_keyboard_caps_lock under Caps
  Lock, foreground_keyboard_numlock_keypad when Num Lock changes a keypad key
  in the chord, foreground_unsupported_layout for a remapped chord, and
  foreground_keyboard_locked for any other lock. A modifier or lock change
  during the action refuses the rest of it (foreground_keyboard_state), and
  the unwind restores the human keyboard's current state.
- Keep the up-front typing-keymap qualification from the previous commit, so
  a different typing layout still refuses before any text is typed. Drop the
  per-key backstop and the byte-identical keymap comparison it replaced.
- Report keyboard_layout_independent and foreground_numlock_compatible in
  hyprctl -j cua:status for v3 builds, whether or not input is enabled, so
  Omarchy's Cua Input toggle can tell this module from an older one.
- Tests: the keymap and chord tests compile real keymaps, and the foreground
  modifier test compiles the production admission, dispatch, and unwind
  methods against fake compositor objects. They need xkbcommon and skip
  without it unless CUA_HYPRLAND_REQUIRE_XKBCOMMON is set. The mocked v3
  status test checks both fields.

Adapted from omacom/omarchy-pkgs#473 (independent-keymaps.patch, MIT).

Co-authored-by: Spencer Bull <7035687+spencerbull@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Francesco Bonacci <f@trycua.com>
Co-authored-by: Spencer Bull <7035687+spencerbull@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
spencerbull added a commit that referenced this pull request Oct 4, 2026
…#772)

* Rebase the Cua Hyprland plugin on Driver 0.32.0 source

Driver 0.31.0 took the independent agent keymaps and Num Lock handling from #473 upstream, so independent-keymaps.patch goes. Upstream also added an up-front check that every key the KEY command can press types the US keysym, modifier keys included, which refuses all foreground typing under ctrl:swapcaps, compose:ralt, altwin:swap_alt_win or compose:102. foreground-remaps.patch makes that check run the per-chord check every key already passes over exactly the chords Driver types text with, with Num Lock off and on, so a string is still admitted or refused before its first key and other remaps are left to the per-chord check.

0.32.0 also gives agent keyboards a real repeat rate, which stops single-seat clients like imv crashing on an agent seat (trycua/cua#4257).

cua-driver-bin stays at 0.28.2, which speaks the same input protocol v3: Driver 0.28.3 through 0.32.0 refuse desktop capture on Hyprland with more than one output or with one away from the origin (trycua/cua#4161).

Co-Authored-By: Codex XHigh <noreply@openai.com>

* Keep restarting fcitx5 from crashing Hyprland under the Cua plugin

With plugin input enabled, fcitx5 requests an input method for each of the three seats, and when it exits Hyprland 0.56.2 can still hold an input-method popup that is mapped although its wl_surface is gone: the popup's surface-destroy handler emits unmap but never clears m_mapped. Tearing down the input method then updates every popup, CInputPopup::updateBox dereferences the missing surface and Hyprland restarts in safe mode. Omarchy's omarchy-restart-xcompose reaches this in normal use.

The plugin now hooks CInputPopup::updateBox and CInputPopup::shouldBeRendered so a popup whose getSurface() is empty is neither placed nor rendered, reports the guard in cua:status, and removes the hooks on unload. The guard is compiled into the module only, so the mock-based tests are unchanged. foreground-remaps.patch becomes downstream.patch now that it carries both changes.

* Pin the Cua Hyprland plugin to Arch's hyprland 0.56.2-4 rebuild

Arch rebuilt Hyprland 0.56.2 against vulkan-sdk 1.4.363 and glslang. The executable and two headers change, so the plugin's exact compositor pin and hashes would block hyprland upgrades for anyone with it installed, and Cua's kit has no profile for it (trycua/cua#4216). The release, compiler and runtime are unchanged, so the derivation now also takes the re-measured compositor executable and header inventory; the build's verifier checks both against the installed package.

* Qualify the Cua plugin README on its input-method guard

The guard is installed best effort, so the README promises the fix only while it is active, and the activation checklist now asks for ime_popup_guard: true. 'No hooks' meant package-manager hooks, which the plugin's new function hooks made ambiguous.

Co-Authored-By: Codex XHigh <noreply@openai.com>

---------

Co-authored-by: Codex XHigh <noreply@openai.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant