Skip to content

fix(keyd): stop asserting Alt on Framework key, remove xremap entirely - #2019

Merged
shunkakinoki merged 1 commit into
mainfrom
fix/remove-xremap-keyd-atomic-macros
Jul 7, 2026
Merged

fix(keyd): stop asserting Alt on Framework key, remove xremap entirely#2019
shunkakinoki merged 1 commit into
mainfrom
fix/remove-xremap-keyd-atomic-macros

Conversation

@shunkakinoki

@shunkakinoki shunkakinoki commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • Slack marked the hovered chat unread when copying with Framework+C: the [cmd_hyper:C-A-S-M] layer asserted Ctrl+Alt+Shift+Super the moment the Framework key was held, and Slack treats Alt+Click as "mark unread" - a stray trackpad tap (tap-to-click) while Alt was held triggered it
  • Rework the layer as Super-only ([cmd_hyper:M]) with an explicit atomic macro per key: Framework+key emits Ctrl+key (or the Hyper chord for Hyprland binds) in one clean event; Ctrl/Alt/Shift are never held speculatively
  • Framework+Tab now falls through as genuinely held Super+Tab, so hyprshell hold-to-cycle still works
  • With keyd emitting final combos directly, xremap has no job left: delete the module, home-manager imports, flake input, and the Hyprland restart hook
  • Ghostty handles clipboard natively: performable:ctrl+c copies only when a selection exists (restoring Ctrl+C SIGINT, which the xremap remap had eaten) and ctrl+v pastes

Test plan

  • make switch (keyd restarts via restartTriggers; xremap user service disappears)
  • Slack: Framework+C/V copies/pastes without marking the chat unread
  • Ghostty: Framework+C copies selection, Ctrl+C without selection interrupts, Framework+V pastes
  • Hyprland Hyper binds still fire: Framework+3/4/5 screenshots, Framework+F fullscreen, Framework+L lock, Framework+Space launcher, Framework+=/- zoom
  • Framework+Tab cycles windows via hyprshell (hold to cycle)

Summary by cubic

Reworked the Framework key in keyd to emit atomic shortcuts without asserting Ctrl/Alt/Shift. This fixes Slack marking chats unread on copy/paste and lets us remove xremap; Ghostty now handles clipboard natively and Ctrl+C SIGINT is restored.

  • Bug Fixes

    • Framework key is Super-only; per-key atomic macros emit Ctrl+key or Hyper chords (no speculative modifiers).
    • Framework+Tab passes through as held Super+Tab, preserving hyprshell hold-to-cycle.
  • Refactors

    • Removed xremap: deleted module, Home Manager imports, flake input, and the Hyprland restart hook.
    • Updated Ghostty bindings: performable:ctrl+c copies only with a selection; ctrl+v pastes; Ctrl+C remains SIGINT.

Written for commit 4106936. Summary will update on new commits.

Review in cubic

The [cmd_hyper:C-A-S-M] modifier layer asserted Ctrl+Alt+Shift+Super
the moment the Framework key was held. Slack treats Alt+Click as 'mark
unread', so a held Alt plus a stray trackpad tap (tap-to-click) kept
marking the hovered chat unread whenever Framework+C/V was pressed.

Rework the layer as Super-only ([cmd_hyper:M]) with an explicit atomic
macro per key: Framework+key emits Ctrl+key (or the Hyper chord for
Hyprland binds) in one clean event, and no Ctrl/Alt/Shift is ever held
speculatively. Framework+Tab falls through as genuinely held Super+Tab
for hyprshell hold-to-cycle.

With keyd emitting final combos directly, xremap had no job left:
delete the module, home-manager imports, flake input, and the Hyprland
restart hook. Ghostty now handles clipboard natively: performable
ctrl+c copies only when a selection exists (restoring Ctrl+C SIGINT,
which the xremap remap had eaten) and ctrl+v pastes.
@indent-zero

indent-zero Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor
PR Summary

Removes the xremap layer entirely and rewrites the keyd [cmd_hyper] (Framework key) layer so every combo is emitted atomically by keyd itself. Motivation: the old [cmd_hyper:C-A-S-M] base asserted Alt+Ctrl+Shift+Super the moment Framework was held, which combined with Slack's Alt+Click (mark unread) and tap-to-click was silently marking chats unread when the user pressed Framework+C/V. Ghostty now handles clipboard natively so Framework+C/V (now arriving as plain Ctrl+C/V) still copy/paste while Ctrl+C without a selection remains SIGINT.

  • Rewrote config/keyd/default.conf [cmd_hyper] as [cmd_hyper:M] with explicit per-key macros: letters/numbers/symbols/nav (minus Tab) → Ctrl+<key>; f/l/space/3/4/5/equal/minusCtrl+Alt+Shift+Super+<key> for Hyprland Hyper binds; Framework+Tab left unmapped so it becomes a genuinely held Super+Tab for hyprshell hold-to-cycle.
  • Dropped the xremap uinput exclusion (-1234:5678) from the keyd [ids] block now that xremap is gone.
  • Deleted home-manager/modules/xremap/default.nix, the module import in home-manager/modules/default.nix, the inputs.xremap wire-up in home-manager/default.nix, and the xremap flake input (plus transitive lock entries in flake.lock).
  • Removed the sleep 1 && systemctl --user restart xremap exec-once from config/hyprland/hyprland.conf.
  • Added performable:ctrl+c=copy_to_clipboard and ctrl+v=paste_from_clipboard to config/ghostty/config so Framework+C/V (arriving as bare Ctrl+C/V) copy/paste while Ctrl+C without a selection still sends SIGINT.

Issues

2 potential issues found:

  • Latent (trigger: adding future Framework+Ctrl+ mappings): [cmd_hyper+control] fallthrough now hits the explicit Ctrl+<key> table instead of the old Hyper base, so any Framework+Ctrl+<letter/number> combo other than 5 silently emits plain Ctrl+ and no longer reaches Hyprland's CTRL ALT SHIFT SUPER, … binds. → Autofix
  • Ghostty ctrl+v=paste_from_clipboard intercepts every terminal-side Ctrl-V (not just Framework+V), breaking vim's visual-block mode and readline quoted-insert inside Ghostty. → Autofix

CI Checks

Waiting for CI checks...


⚡ Autofix All Issues

@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@shunkakinoki
shunkakinoki merged commit b4630dc into main Jul 7, 2026
29 of 31 checks passed
@shunkakinoki
shunkakinoki deleted the fix/remove-xremap-keyd-atomic-macros branch July 7, 2026 15:19
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9f5fb8d3-7fdd-4988-8a43-24bfab6db428

📥 Commits

Reviewing files that changed from the base of the PR and between a91ec22 and 4106936.

⛔ Files ignored due to path filters (1)
  • flake.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • config/ghostty/config
  • config/hyprland/hyprland.conf
  • config/keyd/default.conf
  • flake.nix
  • home-manager/default.nix
  • home-manager/modules/default.nix
  • home-manager/modules/xremap/default.nix

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.


📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Updated keyboard shortcuts so plain Ctrl+C copies only when text is selected, while still sending interrupt when nothing is selected.
    • Added reliable Ctrl+V clipboard paste behavior.
    • Refined system startup to restart desktop portal services in the correct order for better app integration.
  • Bug Fixes

    • Simplified key remapping setup and removed an extra remapping layer, improving consistency across desktop and terminal apps.

Walkthrough

This PR removes the xremap dependency entirely: the flake input, home-manager module, and its imports are deleted, and Hyprland's startup no longer restarts xremap but instead restarts xdg-desktop-portal services. Key remapping functionality moves to a rewritten keyd cmd_hyper layer and new Ghostty native clipboard keybinds.

Changes

xremap removal and native remapping migration

Layer / File(s) Summary
Remove xremap dependency
flake.nix, home-manager/default.nix, home-manager/modules/default.nix, home-manager/modules/xremap/default.nix
xremap flake input, home-manager module import, and module file are removed; agenix module is imported in its place.
Hyprland startup restarts portals instead of xremap
config/hyprland/hyprland.conf
exec-once command switches from restarting the xremap service to sequentially restarting xdg-desktop-portal-hyprland, xdg-desktop-portal-gtk, and xdg-desktop-portal.
Rewritten keyd cmd_hyper layer
config/keyd/default.conf
Removes xremap device exclusion comment, replaces [cmd_hyper:C-A-S-M] with [cmd_hyper:M], adding macOS-style Ctrl-key mappings and Hyprland Hyper chord bindings.
Ghostty native clipboard keybinds
config/ghostty/config
Adds performable:ctrl+c=copy_to_clipboard and ctrl+v=paste_from_clipboard bindings.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested labels: bug

Poem

A rabbit hopped through config files bare,
Bid xremap farewell with a twitch of the hair,
Now keyd and Ghostty take up the chore,
Ctrl+C, Ctrl+V — clean paths once more,
Portals restart in tidy array,
Hop, hop, hooray for a simpler day! 🐇✨

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/remove-xremap-keyd-atomic-macros

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request removes xremap from the configuration and migrates macOS-style command key remappings directly into keyd under the [cmd_hyper:M] layer. It also introduces copy/paste keybindings in Ghostty. Feedback on these changes highlights two main issues: first, mapping the arrow keys to C-left/C-right in keyd conflicts with Hyprland's workspace switching shortcuts and does not accurately replicate macOS-style line navigation; second, binding ctrl+v globally in Ghostty intercepts all Ctrl+V keystrokes, which breaks native terminal features like Vim's blockwise visual mode.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread config/keyd/default.conf
Comment on lines +78 to +81
left = C-left
right = C-right
up = C-up
down = C-down

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In macOS, Cmd+Left and Cmd+Right are used to navigate to the start and end of the line (which map to home and end in Linux), while Cmd+Up and Cmd+Down navigate to the top and bottom of the document (which map to Ctrl+Home and Ctrl+End in Linux).

Currently, you have mapped them to C-left, C-right, C-up, and C-down. However, in config/hyprland/hyprland.conf (lines 343-344), you have bound CTRL, left and CTRL, right globally to switch workspaces:

bind = CTRL, left, workspace, e-1
bind = CTRL, right, workspace, e+1

As a result, pressing Framework+Left or Framework+Right will trigger a workspace switch instead of cursor navigation.

Mapping them to home, end, C-home, and C-end instead will perfectly replicate macOS-style line and document navigation while avoiding the conflict with Hyprland's workspace switching.

left = home
right = end
up = C-home
down = C-end

Comment thread config/ghostty/config
# Framework+C/V arrive as plain Ctrl+C/V (keyd, see config/keyd/default.conf).
# performable: copy only when a selection exists; otherwise Ctrl+C stays SIGINT.
keybind = performable:ctrl+c=copy_to_clipboard
keybind = ctrl+v=paste_from_clipboard

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Binding ctrl+v globally in Ghostty to paste_from_clipboard will intercept all Ctrl+V keystrokes.

Because keyd maps the Framework key to Ctrl (v = C-v), both physical Ctrl+V and Framework+V will emit Ctrl+V and trigger a paste. This completely disables the terminal's native Ctrl+V functionality, such as blockwise visual mode in Vim/Neovim or quoted-insert in bash/zsh.

Since ctrl+q is also bound to quit (line 52), Vim users won't easily be able to fall back to Ctrl+Q for visual block mode either. Consider keeping the default paste shortcut (ctrl+shift+v) or using a different non-conflicting key combination if you rely on terminal applications that require raw Ctrl+V input.

Comment thread config/ghostty/config
# Framework+C/V arrive as plain Ctrl+C/V (keyd, see config/keyd/default.conf).
# performable: copy only when a selection exists; otherwise Ctrl+C stays SIGINT.
keybind = performable:ctrl+c=copy_to_clipboard
keybind = ctrl+v=paste_from_clipboard

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In-terminal Ctrl-V is now hijacked as paste. Unlike the performable:ctrl+c line above, keybind = ctrl+v=paste_from_clipboard is unconditional, and there is no way to distinguish a keyd-emitted Framework+V from a real user Ctrl-V — both arrive at Ghostty as bare Ctrl+V. So:

  • vim normal-mode Ctrl-V (visual-block) now pastes instead of entering block-select.
  • bash / readline Ctrl-V (quoted-insert, used to type raw ^M, ^[, etc.) now pastes.
  • Any TUI that binds Ctrl+V loses it inside Ghostty.

The old xremap flow avoided this because the Ghostty-only keymap rewrote Framework's Ctrl+V to Ctrl+Shift+V, leaving real Ctrl+V for TUIs. With xremap gone that distinction is lost.

Options:

  • Keep Ctrl+V=paste only in Ghostty on macOS (macos- scoped keybind) and rely on Ctrl+Shift+V on Linux where TUI conflicts matter.
  • Or accept the trade-off and note it in a comment (some users won't mind).
  • performable:ctrl+v=paste_from_clipboard does not help here — performable: for paste keys is based on clipboard non-emptiness, not TUI focus, so it would still swallow Ctrl-V any time there's clipboard content.

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