Skip to content

feat: add xremap command key - #767

Merged
shunkakinoki merged 18 commits into
mainfrom
chore/xremap-command-key
Feb 9, 2026
Merged

feat: add xremap command key#767
shunkakinoki merged 18 commits into
mainfrom
chore/xremap-command-key

Conversation

@shunkakinoki

@shunkakinoki shunkakinoki commented Feb 9, 2026

Copy link
Copy Markdown
Owner

Changes

  • Add xremap/nix-flake input and NixOS module on matic
  • Enable xremap user service with wlroots support and device watching
  • Map Framework Hyper to Command-style Ctrl combos with Ghostty overrides

Technical Details

  • Restore uinput/input group + udev rule for xremap (requires log out/in)
  • Ghostty remaps Hyper+C/V to Ctrl+Shift+C/V to avoid SIGINT

Testing

  • make build
  • make switch
  • systemctl --user start xremap.service
  • systemctl --user status xremap.service

Generated with GitHub Copilot CLI by Claude Sonnet 4.5


Summary by cubic

Adds xremap on matic for a “Command key” feel by mapping the Framework Hyper key to Ctrl. Runs as a wlroots-backed user service that starts after the graphical session, restarts after Hyprland env import, and removes the nerdfonts meta package (keeps nerd-fonts.jetbrains-mono).

  • New Features

    • Integrates xremap module; user service with uinput + wlroots, watches the “keyd virtual keyboard.”
    • Adds udev rules for uinput/keyd devices and excludes xremap’s 1234:5678 in keyd to prevent input loops.
    • Ensures reliable startup: after graphical-session.target, Hyprland triggers a restart post env import, restart-on-failure with no rate limit.
    • Remaps Hyper→Ctrl globally; in Ghostty Hyper+C/V → Ctrl+Shift+C/V; leaves Hyper+3/4/5 for Hyprland screenshots/recording.
  • Migration

    • Ensure the user is in the input group; log out and back in to apply.
    • Build and switch, then start/check the user service: make build && make switch; systemctl --user start xremap.service; systemctl --user status xremap.service.

Written for commit 7fd6611. Summary will update on new commits.

Copilot AI review requested due to automatic review settings February 9, 2026 06:45
@mesa-dot-dev

mesa-dot-dev Bot commented Feb 9, 2026

Copy link
Copy Markdown

You do not have enough credits to review this pull request. Please purchase more credits to continue.

@coderabbitai

coderabbitai Bot commented Feb 9, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Added xremap as a flake input and integrated its NixOS module into the system configuration, including uinput/udev support, extensive remapping rules, a systemd user service, Hyprland startup restart, keyd device exclusion, and a conditional Falcon module inclusion.

Changes

Cohort / File(s) Summary
Flake inputs
flake.nix
Added new flake input xremap = { url = "github:xremap/nix-flake"; inputs.nixpkgs.follows = "nixpkgs"; }.
NixOS system config / xremap integration
named-hosts/matic/default.nix
Included inputs.xremap.nixosModules.default in modules; added services.xremap configuration (uinput, udev rules, remap definitions, per-user/app filters), added input to users.users.${username}.extraGroups, added systemd user service ordering and conditional ./falcon.nix inclusion; removed nerdfonts from fonts.packages.
Session startup hook
config/hyprland/hyprland.conf
Added a startup command to restart xremap after 1s during Hyprland session startup.
Keyd device exclusions
config/keyd/default.conf
Added comments and an exclusion entry -1234:5678 under [ids] to ignore xremap's default uinput device.

Sequence Diagram(s)

sequenceDiagram
    participant UserSession as User Session
    participant Hyprland as Hyprland
    participant SystemdUser as systemd -- user
    participant Xremap as xremap (user service)
    participant Udev as udev
    participant Keyd as keyd

    UserSession->>Hyprland: start session
    Hyprland->>SystemdUser: ensure user services active
    Hyprland->>Xremap: exec restart xremap (after 1s)
    SystemdUser->>Xremap: start/restart xremap.service
    Xremap->>Udev: create uinput device & emit udev rules
    Udev->>Keyd: devices appear (keyd ignores -1234:5678)
    Keyd-->>UserSession: input events (xremap device excluded)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped a flake into the tree,
Mapped keys and leaped quite merrily,
Services start with a tiny delay,
Devices hum and rules hold sway,
A little rabbit celebrates in keycap glee ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add xremap command key' directly relates to the main change: integrating xremap and enabling Command-key-style remapping of the Framework Hyper key to Ctrl combos.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The PR description comprehensively documents the changes, including xremap integration, service configuration, key remapping behavior, required user group changes, and testing steps.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/xremap-command-key

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 and usage tips.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @shunkakinoki, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request integrates xremap into the NixOS configuration for the matic host, enabling advanced keyboard remapping capabilities. The primary goal is to provide a 'Command-style Ctrl' experience by translating 'Hyper' key combinations, with special considerations for the Ghostty terminal to ensure proper copy/paste and undo functionality.

Highlights

  • Xremap Integration: Added xremap as a Nix flake input and integrated its NixOS module into the system configuration.
  • User Service Configuration: Enabled xremap as a user service with wlroots support and device watching for dynamic input handling.
  • Hyper Key Remapping: Implemented key remapping to translate 'Framework Hyper' key combinations (e.g., Hyper-A, Hyper-C) to 'Command-style Ctrl' combinations (e.g., Ctrl-A, Ctrl-C).
  • Ghostty Terminal Overrides: Included specific overrides for the Ghostty terminal, remapping Hyper+C/V to Ctrl+Shift+C/V and Hyper+Z to Ctrl+Z to prevent SIGINT issues and ensure proper copy/paste/undo functionality.
  • Input Device Access: Configured uinput and udev rules to ensure xremap has the necessary permissions and access to input devices.
Changelog
  • flake.lock
    • Added new flake inputs for crane, flake-parts_5, nixpkgs-lib_2, xremap, and xremap_2 to manage dependencies.
  • flake.nix
    • Added xremap as a new flake input, pointing to github:xremap/nix-flake and ensuring it follows the main nixpkgs.
  • named-hosts/matic/default.nix
    • Integrated the xremap NixOS module into the host configuration.
    • Added the input group to the user's extraGroups to grant necessary device access.
    • Enabled hardware.uinput and loaded the uinput kernel module for virtual input device creation.
    • Added a udev rule to grant the input group appropriate access to the uinput device.
    • Configured the xremap user service, enabling wlroots support and device watching.
    • Defined xremap keymaps: a global map translating 'Hyper' combinations (including letters, numbers, symbols, and navigation keys) to 'Ctrl' combinations, and a specific override for Ghostty to map 'Hyper-c' to 'C-Shift-c', 'Hyper-v' to 'C-Shift-v', and 'Hyper-z' to 'C-z'.
Activity
  • The pull request was generated using GitHub Copilot CLI by Claude Sonnet 4.5.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the summary. You can try again by commenting /gemini summary.

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 3 files

Copilot AI 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.

Pull request overview

Adds an xremap flake input and enables an xremap-based “Command-style” remapping on the matic NixOS host (including wlroots + device watching) to map a Framework “Hyper” chord into Ctrl-based shortcuts, with Ghostty-specific overrides.

Changes:

  • Add xremap/nix-flake as a flake input (and lock its dependency closure).
  • Import the xremap NixOS module on named-hosts/matic and enable the user service with wlroots + watch.
  • Configure uinput/udev access and define global + Ghostty-specific key remaps.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.

File Description
named-hosts/matic/default.nix Imports xremap module, enables uinput/udev + xremap user service, and defines the key remapping rules.
flake.nix Adds the xremap flake input.
flake.lock Locks xremap and newly introduced transitive flake inputs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 66 to 71
extraGroups = [
"wheel"
"networkmanager"
"input"
"video"
];

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

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

Adding the user to the input group grants broad read access to /dev/input/event* on many systems (i.e., keylogging capability). If xremap only needs access to /dev/uinput, consider avoiding input group membership and instead granting access just to the uinput node via a dedicated group or uaccess on that device only, to keep privileges minimal.

Copilot uses AI. Check for mistakes.
hardware.uinput.enable = true;
boot.kernelModules = [ "uinput" ];
services.udev.extraRules = ''
KERNEL=="uinput", GROUP="input", TAG+="uaccess", MODE:="0660", OPTIONS+="static_node=uinput"

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

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

The udev rule sets GROUP="input" for the uinput device, which ties the setup to the broad input group and duplicates the uaccess tagging approach. Consider switching this rule to a dedicated group (e.g., uinput) or relying on TAG+="uaccess" alone for the uinput node, so you don’t need to grant the user full input group privileges.

Suggested change
KERNEL=="uinput", GROUP="input", TAG+="uaccess", MODE:="0660", OPTIONS+="static_node=uinput"
KERNEL=="uinput", TAG+="uaccess", MODE:="0660", OPTIONS+="static_node=uinput"

Copilot uses AI. Check for mistakes.
Comment on lines +117 to +125
numbers = [
"0"
"1"
"2"
"6"
"7"
"8"
"9"
];

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

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

The numbers list skips "3", "4", and "5", so Hyper+3/4/5 won’t be remapped (and the omission is easy to miss because other sets are complete). If this is meant to cover all number keys, include the missing digits or generate the list programmatically to avoid accidental gaps.

Copilot uses AI. Check for mistakes.
@mesa-dot-dev

mesa-dot-dev Bot commented Feb 9, 2026

Copy link
Copy Markdown

Mesa Description

TL;DR

Integrates xremap on the matic host to enable a "Command key" feel by remapping the Framework Hyper key to Ctrl, ensuring it runs as a wlroots-backed user service and preventing input loops with keyd.

What changed?

  • flake.lock: Updated to reflect new dependencies from the xremap flake input.
  • flake.nix: Introduced xremap as a new flake input, sourced from github:xremap/nix-flake.
  • named-hosts/matic/default.nix: Configured and enabled xremap with uinput and udev rules, set up global and Ghostty-specific key remappings (e.g., Hyper to Ctrl, Hyper+C/V to Ctrl+Shift+C/V), and added a systemd user service for xremap. Also removed the generic nerdfonts package.
  • config/keyd/default.conf: Modified keyd configuration to exclude xremap's virtual keyboard device (1234:5678) to prevent input feedback loops.
  • config/hyprland/hyprland.conf: Added an exec-once command to restart the xremap user service with a delay during Hyprland startup.

Description generated by Mesa. Update settings

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@named-hosts/matic/default.nix`:
- Around line 117-125: The numbers array named "numbers" is missing "3", "4",
and "5" so Hyper+3/4/5 won't be remapped to Ctrl+3/4/5; either add the missing
entries ("3", "4", "5") to the numbers list in default.nix (the `numbers =
[...]` block) or, if their omission is intentional, add an inline comment next
to the `numbers` declaration (or above it) explaining that 3–5 are reserved
(e.g., for workspace switching in Hyprland) so future readers understand why
they are excluded.
🧹 Nitpick comments (2)
named-hosts/matic/default.nix (2)

146-155: The Hyper+z → C-z override in ghosttyRemap is redundant.

globalRemap already maps ${hyperPrefix}z to ${ctrlPrefix}z (i.e., C-z). The // merge on line 154 sets it to "C-z", which is identical. If this is intentional documentation of "we considered z and want it to stay as Ctrl+Z in Ghostty", a comment would clarify the intent. Otherwise, it can be removed.


85-178: Consider extracting the xremap configuration to a separate module file.

The keyd configuration is imported from ../../config/keyd (line 37), but the xremap config is defined inline (~90 lines). For consistency and to keep this file more manageable, consider extracting the xremap service configuration to a dedicated file (e.g., ../../config/xremap/default.nix or ./xremap.nix), passing in username and inputs as arguments.

This isn't urgent since the config is host-specific, but it would improve readability of this already-large file. Based on learnings, configurations should be kept modular across directories.

Comment thread named-hosts/matic/default.nix

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="named-hosts/matic/default.nix">

<violation number="1" location="named-hosts/matic/default.nix:161">
P2: Switching xremap to a user service requires the user to have read access to the input devices it watches. The udev rules set GROUP="input" but the user isn’t added to the input group (extraGroups only includes "inputs"), so the user service is likely to fail with permission errors. Add the user to the "input" group or grant uaccess in the udev rules.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread named-hosts/matic/default.nix

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="named-hosts/matic/default.nix">

<violation number="1" location="named-hosts/matic/default.nix:191">
P2: `StartLimitIntervalSec` is a `[Unit]` directive, but it’s currently placed inside `serviceConfig` (the `[Service]` section), so systemd will ignore it. Move it to the unit configuration (e.g., `unitConfig.StartLimitIntervalSec = 0;`) so the start-limit override actually applies.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread named-hosts/matic/default.nix Outdated
@shunkakinoki
shunkakinoki merged commit 1d18ef0 into main Feb 9, 2026
25 checks passed
@shunkakinoki
shunkakinoki deleted the chore/xremap-command-key branch February 9, 2026 08:22
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.

2 participants