wez / wezterm

A GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust
https://wezfurlong.org/wezterm/
Other
16.56k stars 741 forks source link

add ability to remap modifier and caps lock keys #1777

Open marcuslannister opened 2 years ago

marcuslannister commented 2 years ago

Is your feature request related to a problem? Please describe. No

Describe the solution you'd like Because I use CAPS key as Command key on macOS, It can save many times when I use Command key. And in Terminal I also want to remap my command key to control key, because many hot key will use control key.

Describe alternatives you've considered No

Additional context No

wez commented 2 years ago

Remapping modifiers cross platform is potentially a bit gnarly, so I'm not eager to work on this.

I would suggest looking at https://karabiner-elements.pqrs.org/ to remap globally; that's what I use on macOS to remap caps lock to a dual role (tap = ESC, hold = control) key.

marcuslannister commented 2 years ago

Got it and thanks for your quick reply.

qqldd commented 1 year ago

Also want to check if remap Command to Alt and Option to Super is possible. I usually use Emacs inside terminal but want consistent Meta/Alt key across Mac and Linux.

qqldd commented 1 year ago

I find a way in Karabiner Elements to swap Option <-> Command only for WezTerm, for others: Here is the example and my configs:

 {
        "conditions": [
            {
                "bundle_identifiers": [
                    "^com\\.github\\.wez\\.wezterm$"
                ],
                "type": "frontmost_application_if"
            }
        ],
        "description": "WezTerm Left Option to Cmd",
        "from": {
            "key_code": "left_option",
            "modifiers": {
                "optional": [
                    "any"
                ]
            }
        },
        "to": [
            {
                "key_code": "left_command",
                "lazy": true
            }
        ],
        "type": "basic"
    },
    {
        "conditions": [
            {
                "bundle_identifiers": [
                    "^com\\.github\\.wez\\.wezterm$"
                ],
                "type": "frontmost_application_if"
            }
        ],
        "description": "WezTerm Left Cmd to Option",
        "from": {
            "key_code": "left_command",
            "modifiers": {
                "optional": [
                    "any"
                ]
            }
        },
        "to": [
            {
                "key_code": "left_option",
                "lazy": true
            }
        ],
        "type": "basic"
    }
LintaoAmons commented 1 year ago

Thx @qqldd, this is exactly what I want~ I made some changes to the karabiner config~

{
  "title": "WezTerm switch option with cmd",
  "rules": [
    {
      "description": "WezTerm Left Option to Cmd",
      "manipulators": [
        {
          "conditions": [
            {
              "bundle_identifiers": ["^com\\.github\\.wez\\.wezterm$"],
              "type": "frontmost_application_if"
            }
          ],
          "from": {
            "key_code": "left_option",
            "modifiers": {
              "optional": ["any"]
            }
          },
          "to": [
            {
              "key_code": "left_command",
              "lazy": true
            }
          ],
          "type": "basic"
        }
      ]
    },
    {
      "description": "WezTerm Left Cmd to Option",
      "manipulators": [
        {
          "conditions": [
            {
              "bundle_identifiers": ["^com\\.github\\.wez\\.wezterm$"],
              "type": "frontmost_application_if"
            }
          ],
          "from": {
            "key_code": "left_command",
            "modifiers": {
              "optional": ["any"]
            }
          },
          "to": [
            {
              "key_code": "left_option",
              "lazy": true
            }
          ],
          "type": "basic"
        }
      ]
    }
  ]
}
LintaoAmons commented 1 year ago

Remapping modifiers cross platform is potentially a bit gnarly, so I'm not eager to work on this.

I would suggest looking at https://karabiner-elements.pqrs.org/ to remap globally; that's what I use on macOS to remap caps lock to a dual role (tap = ESC, hold = control) key.

To switch Opt and CMD when using wezterm is a good solution, but I tried this for one day, found that it not that good because some system wide keybindings is not consistent since cmd is in opt position.

@wez So maybe there's a way to deem CMD as META when using mac?

wez commented 1 year ago

If you look at the flow chart at https://wezfurlong.org/wezterm/config/keyboard-concepts.html#keyboard-processing-flow, where do you envision the modifier remapping happening?

LintaoAmons commented 1 year ago

Thx for your hint, I actually can just map the send key. And I finally come up with something that seems working well.

local wezterm = require("wezterm")
local act = wezterm.action

function macCMDtoMeta()
    local keys = "abdefghijklmnopqrstuwxyz" -- no c,v
    local keymappings = {}

    for i = 1, #keys do
        local c = keys:sub(i, i)
        table.insert(keymappings, {
            key = c,
            mods = "CMD",
            action = act.SendKey({
                key = c,
                mods = "META",
            }),
        })
        table.insert(keymappings, {
            key = c,
            mods = "CMD|CTRL",
            action = act.SendKey({
                key = c,
                mods = "META|CTRL",
            }),
        })
    end
    return keymappings
end

return {
    font = wezterm.font_with_fallback({
        "Hack Nerd Font Mono",
    }),
    color_scheme = "Gruvbox dark, medium (base16)",
    keys = macCMDtoMeta(),

    font_size = 18.0,
    hide_tab_bar_if_only_one_tab = true,
}
z0al commented 1 year ago

Remapping modifiers cross platform is potentially a bit gnarly, so I'm not eager to work on this.

@wez I'd love to have an interceptor kind of function that listens to and potentially modify keyboard events right before the "Send key to terminal" step

image

The workaround from @LintaoAmons is fine for a subset of chars but it's not optimal if I want to literally remap every occurrence of a specific modifier for all chars, symbols, ..etc.

My use case: I use Linux, Mac, and Windows almost daily, so I have the CMD and Ctrl swapped in Mac which solves most of my problems except for the terminal.

While I can change Wezterm own keybinds to use the appropriate modifier based on the OS I need a way to still use ctrl for terminal-based apps like Vim (as in, I press ctrl -> OS swaps it with CMD -> Wezterm's SendKey sends Ctrl). So having the ability to override what gets sent to these apps would fix the final piece of the puzzle for me. Currently, I use Karabiner but it's messy, and with every shortcut, I add I have to make two: one for all apps and one for Terminals.

I don't know if that would make it any better in terms of implementation/maintenance but just throwing ideas here and am open to feedback.

z0al commented 1 year ago

I imagine a something like public Lua interface of windowmods_to_termwiz_mods would suffice for my need.

dinvlad commented 1 year ago

@LintaoAmons, sorry to revive - have you tried that script with CMD|SHIFT -> META|SHIFT, by any chance? This latter remap doesn't appear to work, for some reason.

Edit: in fact, even CMD|CTRL remap doesn't appear to be working for me - a key combination like Ctrl-Cmd-h still registers as Ctrl-Win-h inside the terminal. Not sure what I'm doing wrong..

LintaoAmons commented 1 year ago

@dinvlad

wezterm/.wezterm.lua

Here's my up-to-date config, it working fine for me, and should be fine for you. If not maybe you should debug some other possible reason outside wezterm?

dinvlad commented 1 year ago

@LintaoAmons thanks, and sorry for spam - does this work for you inside a terminal, or even more specifically inside Tmux? I'm probably missing something obvious - I'll create a discussion if it's more appropriate to discuss there. For now, I just created a different mapping that doesn't involve CMD, and the new binding seems to be working fine, as a workaround.

LintaoAmons commented 1 year ago

@dinvlad Yes, it's working both in tmux and vim(within or without tmux)~

dinvlad commented 1 year ago

@LintaoAmons thanks for your help - I got it working. Not sure what the ultimate culprit was, but I did all of the following:

-- Swap Cmd <-> Option on macOS if wezterm.target_triple:match("darwin$") then for i = 0, 127 do local key = string.char(i)

            for _, mods in ipairs({ "", "|CTRL", "|SHIFT" }) do
                    if mods == "" and (key == "c" or key == "v") then
                            goto continue
                    end
                    for from, to in pairs({ CMD = "OPT", OPT = "CMD" }) do
                            table.insert(config.keys, {
                                    key = key,
                                    mods = from .. mods,
                                    action = act.SendKey({
                                            key = key,
                                            mods = to .. mods,
                                    }),
                            })
                    end
                    ::continue::
            end
    end

end



* did a full restart of Tmux and WezTerm plus `killall tmux wezterm-mux-server` - since I've noticed that at least some settings didn't apply until I exited all Tmux sessions and stopped WezTerm Unix domain.