ghostty icon indicating copy to clipboard operation
ghostty copied to clipboard

`key-remap` configuration to remap modifiers at the app-level

Open mitchellh opened this issue 10 months ago • 15 comments

Discussion: https://github.com/ghostty-org/ghostty/discussions/3493#discussioncomment-11827976

Introduce a new configuration key-remap which can be used to remap keys from one to another within the scope of Ghostty. Example:

key-remap = ctrl=super
key-remap = left_control=right_alt

This would act the same as if a user went to their OS config and remapped these keys. If a sided-modifier isn't specified, then left swaps with left, right swaps with right.

Notes:

  • This is a one way remap. In the example above, ctrl becomes super but super does not become ctrl.
  • Remaps are not transitive. If you remap ctrl=super and then alt=ctrl, then alt != super. Alt would be mapped to control.
  • This doesn't interact with keybind in any way. In the same way keybind is already roughly unaware of keyboard layouts (i.e. cmd+f works with f as specified by your layout), the same will happen in this case (i.e. cmd+f will trigger with a physical "ctrl" key if you remapped cmd=ctrl).

Additional scope limiting

For the initial creation of this feature, we should limit scope in the following ways:

  1. Only remap modifier keys
  2. Only work on macOS

There is a much more urgent need and request for this on macOS (see #3493) and macOS APIs give us a much easier way to do this by easily letting us insert event filters in the path. My attempts at doing this with GTK have thus far failed, but I think it's possible.

In the future, we can likely lift both of these limitations.

mitchellh avatar Jan 16 '25 21:01 mitchellh

Just repeating myself: this is only tagged macOS because I'm happy to close this one macOS supports this. This has been heavily requested by macOS users and the discussion explains many reasons why. I don't recall seeing any requests for this at all for Linux users but if there are it's been relatively few.

The design of the config does not preclude Linux support in the future.

mitchellh avatar Jan 16 '25 21:01 mitchellh

Hi, could you include this feature in 1.2.0 milestone?

chenzhiwei avatar Feb 17 '25 09:02 chenzhiwei

is this not the same as #4335?

Edit: for future readers, I asked this because I thought that remapping all the Ghostty keybindings, then remapping the ctrl modifier to cmd, would work. I hadn't realised that this would also apply to all keybindings of TUI applications (which is especially useful since most do not support the Kitty keyboard protocol, without which cmd is not bindable by the TUI).

00-kat avatar Feb 20 '25 08:02 00-kat

@00-kat #4335 is about using a modier key by itself to kick off an action (like double tapping ctrl to open a new terminal). This is about remapping the modifier keys themselves (e.g. making it so when I hit CTRL-C it behaves as if I'd hit CMD-C, and when I hit CMD-C it behaves as if I'd hit CTRL-C).

https://github.com/ghostty-org/ghostty/discussions/3493 talks about the motivation in detail but briefly: a lot of Mac users (especially ones who come from Windows or Linux) swap the CTRL and CMD keys in the OS, so that CTRL-C is copy and CTRL-S is save and everything works the way they're used to it working on other platforms. On other platforms, in a terminal though, CTRL-C is still "break", so you want CTRL and CMD swapped in all apps, except in your terminal program. The easiest way to do that is "swap them back" in the terminal. iterm2 makes this really easy, but ghostty sadly does not.

jwalton avatar Feb 20 '25 13:02 jwalton

FWIW I worked around this issue for now using Karabiner Elements and the following complex modification:

{
    "description": "CMD to CTRL in ghostty",
    "manipulators": [
        {
            "conditions": [
                {
                    "bundle_identifiers": [
                        "^com\\.mitchellh\\.ghostty$"
                    ],
                    "type": "frontmost_application_if"
                }
            ],
            "from": {
                "key_code": "left_command",
                "modifiers": { "optional": ["any"] }
            },
            "to": [{ "key_code": "left_control" }],
            "type": "basic"
        }
    ]
}

aauren avatar Mar 28 '25 20:03 aauren

@aauren Thanks - I was meaning to try that with a couple of exclusions (in particular cmd+tab for app switching, and perhaps also cmd+w for closing a pane/tab/window and cmd+t for new tab). I think I'd have to live without cmd+n for new window as ctrl+n is too useful.

peterjc avatar Mar 28 '25 21:03 peterjc

@aauren Oh that's interesting. Where do you define this? I just downloaded karabiner yesterday and remapped the right option key to right control. which doesn't behave inside of ghostty. I guess I can also do something similar to what you did and get it working therem? I tried this here

{
    "description": "Right Option to CTRL in Ghostty",
    "manipulators": [
        {
            "conditions": [
                {
                    "bundle_identifiers": [
                        "^com\\.mitchellh\\.ghostty$"
                    ],
                    "type": "frontmost_application_if"
                }
            ],
            "from": {
                "key_code": "right_option",
                "modifiers": { "optional": ["any"] }
            },
            "to": [{ "key_code": "right_control" }],
            "type": "basic"
        }
    ]
}

Didn't seem to work though hm.

DMunkei avatar Mar 29 '25 22:03 DMunkei

Here is a more complicated Karabiner Elements example which retains command+tab when in the terminal, but otherwise maps left-command to left-ctrl within the terminal. The approach is based on reading some of the discussions on the KE Github issue tracker, and other KE rules I have written.

  1. Install Karabiner Elements
  2. Open Karabiner Elements
  3. Click on "Complex Modifications" in left column
  4. Click on "Add you own rule"
  5. Paste in the following, and click "save"
{
    "description": "Left CMD to left CTRL in Ghostty/Wezterm (with exceptions)",
    "manipulators": [
        {
            "conditions": [
                {
                    "bundle_identifiers": [
                        "^com\\.mitchellh\\.ghostty$",
                        "^com\\.github\\.wez\\.wezterm$"
                    ],
                    "type": "frontmost_application_if"
                }
            ],
            "description": "Map left Cmd to left Ctrl in Ghostty/WezTerm",
            "from": {
                "key_code": "left_command",
                "modifiers": {
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "set_variable": {
                        "name": "command-mapped-to-ctrl",
                        "value": 1
                    }
                },
                {
                    "key_code": "left_control"
                }
            ],
            "to_after_key_up": {
                "set_variable": {
                    "name": "command-mapped-to-ctrl",
                    "value": 0
                }
            },
            "type": "basic"
        },
        {
            "conditions": [
                {
                    "name": "command-mapped-to-ctrl",
                    "type": "variable_if",
                    "value": 1
                },
                {
                    "bundle_identifiers": [
                        "^com\\.mitchellh\\.ghostty$",
                        "^com\\.github\\.wez\\.wezterm$"
                    ],
                    "type": "frontmost_application_if"
                }
            ],
            "description": "Revert Ctrl+Tab to Cmd+Tab",
            "from": {
                "key_code": "tab",
                "modifiers": {
                    "mandatory": [
                        "left_control"
                    ],
                    "optional": [
                        "any"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "tab",
                    "modifiers": [
                        "left_command"
                    ]
                }
            ],
            "type": "basic"
        }
    ]
}

This defines two rules,

  1. When in Ghostty or Wezterm, and left command is pressed, turn this into left control AND set a flag variable while this key is held down.
  2. When in Ghostty and Wezterm, and left-ctrl and tab are pressed, and the flag variable is set, infer this is really remapped left-command and tab, so turn it back into left-command and tab.

You could extend this to add additional exclusions, like command+w, although on reflection I quite like using ctrl+w at the terminal for delete word. Tricky.

I think if this was native to Ghostty, I'd want to be able to choose if Ghostty command shortcuts like cmd+w take priority (and in that example close the pane/tab/window) or are passed to the terminal as ctrl+w (which might delete word or whatever).

peterjc avatar Mar 31 '25 00:03 peterjc

That's an awesome example @peterjc! Pretty neat, to see your approach. Thanks for posting it!

@DMunkei The place where this is defined is under Complex Modifications then click Add Your Own Rule and paste that in.

If you find that its still not working, make sure that you enable the keyboard that you're using in Devices. On mine, I had to make sure that I enabled Modify events on the Apple Internal Keyboard / Trackpad

aauren avatar Mar 31 '25 00:03 aauren

I tried to do this with karabiner, but I have a Meta Key configured to switch applications. With the above karabiner setting, the Hyper Key does not work anymore. If I do the remapping in iterm2, it still works.

zbindenren avatar Apr 11 '25 08:04 zbindenren

@zbindenren and others - if you need help extending the Karabiner Elements example rule further, I suggest asking on thier discussion forum (with a link to the example above). I'm not immediately sure how to deal with hyper (ctrl+option+command+shift). Perhaps restrict the cmd to ctrl mapping to only be allowed with shift (the version I posted would activate with any other modifiers pressed, meaning ctrl+app just becomes ctrl)?

After trying it for a couple of days, I'm not currently using this KE rule myself. I'm too used to macOS with ctrl+c for cancel, and command+c for copy - and managed to kill one computational job on my first day with command mapped to control in the terminal.

peterjc avatar Apr 11 '25 09:04 peterjc

@zbindenren I think the issue is that the above config just remap command to ctrl but doesn't remap ctrl to command, making impossible to achieve ctrl+option+command+shift while in the terminal. Extending the rule to perform also the reverse mapping shouldn't be hard.

The main problem I have with the Karabiner approach is that the frontmost_application_if get triggered even if the key doesn't reach the specified app, which happen for example with the command+tab or the command+space shortcuts, and thus they need another Karabiner rule each. In my case, where I use command for many shortcuts of the window manager, this would require to add (and maintain consistent with the window manager configuration) many rules to Karabiner.

These issues would be solved with remapping natively implemented in the terminal since it would be applied only to the keys actually reaching the terminal.

filippo-biondi avatar Apr 11 '25 20:04 filippo-biondi

I think @filippo-biondi is exactly right. The best case scenario is that command mapping gets properly handled within ghostty. I was merely trying to point out a hacky workaround that might work for some people's workflows using KE.

For what it's worth, the way that my workflow works is that if I want to use the command key, I just use the command key on the right side of the space bar. I know that that won't work for everyone, there's a lot of muscle memory that tells you that you should be able to use the left command key. However I guess I got used to it back when even the item binding was less targeted. Even still it catches me every once in awhile.

I think that there are probably ways to work around individual key mappings that are common by making additional bindings in KE but doing so is probably a near endless rabbit hole so I can appreciate some folks not wanting to go down that path.

aauren avatar Apr 11 '25 22:04 aauren

Quick comment from the perspective of a current iTerm user wanting to switch to Ghostty: Not being able to configure this particular remap of right-cmd to ctrl sadly makes adopting Ghostty a complete non-starter for me.

I have personally used this iTerm feature for at least 8 years and so having to give up that way of working with the terminal is too big of a barrier to adopting Ghostty.

P.S.: I strongly agree with @aauren and @filippo-biondi that such a remap should be possible within Ghostty itself. P.P.S.: the Karabiner setup posted by @aauren did not work for me either :/

MultifokalHirn avatar May 27 '25 10:05 MultifokalHirn

I was going to stop people earlier but refrained as I thought that discussion ended already, but can we avoid polluting this thread with stuff about that Karabiner setup? Make a new Q&A Discussion (perhaps titled something like “Workarounds for missing key-remap”) and link it back here if you want to continue.

such a remap should be possible within Ghostty itself.

…and that's the entire point of this Issue. it's already an accepted feature request (otherwise, it wouldn't be an Issue → CONTRIBUTING.md § Issues are Actionable). Telling all 10+ subscribers how much you want this is just noise in people's inbox. Use the 👍️ reaction instead, please:

A screenshot of other 👍️ reactions on this Issue.

Edit: I don't want to make a new comment so adding it onto this one: I didn't mean to remove the Feature issue type, and it accidentally got removed when I pressed t; apologies.

00-kat avatar May 27 '25 11:05 00-kat

I wanted to switch from iTerm to Ghostty but not being able to remap right-option key to ctrl on MacOS is a non-starter for me.

Image

SalarKalantari avatar Aug 21 '25 11:08 SalarKalantari