Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wezterm preventing CTRL + / from entering vim #3180

Open
miversen33 opened this issue Mar 1, 2023 · 28 comments
Open

Wezterm preventing CTRL + / from entering vim #3180

miversen33 opened this issue Mar 1, 2023 · 28 comments
Labels
docs Primarily or only affects documentation keyboard Keyboard mapping/handling

Comments

@miversen33
Copy link

miversen33 commented Mar 1, 2023

What Operating System(s) are you seeing this problem on?

Linux X11

Which Wayland compositor or X11 Window manager(s) are you using?

X11 with Gnome Shell

gnome-shell v: 43.2 driver: X: loaded: modesetting

WezTerm version

20230219-070657-23211fc8

Did you try the latest nightly build to see if the issue is better (or worse!) than your current version?

Yes, and I updated the version box above to show the version of the nightly that I tried

Describe the bug

I don't really know how to word this so I will simply describe the behavior I am seeing vs what I see in other terminal emulators

In Wezterm, if I open vim, enter insert mode, and press CTRL+/, vim inserts / into the editor. This is not the correct key combination, instead I should see ^_ (I can't remember what this key code actually is, but regardless).

In Alacritty/Konsole/Windows Terminal, this operation performs correct (^_ is inserted into the buffer as opposed to /)

To Reproduce

  • Open vim
  • Enter Insert Mode
  • Press CTRL and / at the same time
  • Observe the buffer show /
    image

Configuration

return {}

Expected Behavior

Properly pass uncaptured key events to underlying programs

Logs

14:08:16.021  WARN   mux::localpane > unknown DeviceControlMode::Enter EnterDeviceControlMode(params: [], intermediates: [], byte: 't' 0x74, ignored_extra_intermediates=false)
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 6d m
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 75 u
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 78 x
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 3b ;
14:08:16.021  WARN   mux::localpane > unknown DeviceControlMode::Enter EnterDeviceControlMode(params: [], intermediates: [], byte: 't' 0x74, ignored_extra_intermediates=false)
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 6d m
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 75 u
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 78 x
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 3b ;
14:08:16.021  WARN   mux::localpane > unknown DeviceControlMode::Enter EnterDeviceControlMode(params: [], intermediates: [], byte: 't' 0x74, ignored_extra_intermediates=false)
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 6d m
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 75 u
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 78 x
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 3b ;
14:08:16.021  WARN   mux::localpane > unknown DeviceControlMode::Enter EnterDeviceControlMode(params: [], intermediates: [], byte: 't' 0x74, ignored_extra_intermediates=false)
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 6d m
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 75 u
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 78 x
14:08:16.021  WARN   mux::localpane > unhandled DeviceControlMode::Data 3b ;
14:08:22.505  WARN   mux::localpane > unknown DeviceControlMode::Enter EnterDeviceControlMode(params: [], intermediates: [], byte: 't' 0x74, ignored_extra_intermediates=false)
14:08:22.505  WARN   mux::localpane > unhandled DeviceControlMode::Data 6d m
14:08:22.505  WARN   mux::localpane > unhandled DeviceControlMode::Data 75 u
14:08:22.505  WARN   mux::localpane > unhandled DeviceControlMode::Data 78 x
14:08:22.505  WARN   mux::localpane > unhandled DeviceControlMode::Data 3b ;
14:08:22.520  WARN   mux::localpane > unknown DeviceControlMode::Enter EnterDeviceControlMode(params: [], intermediates: [], byte: 'z' 0x7a, ignored_extra_intermediates=false)
14:08:22.520  WARN   mux::localpane > unhandled DeviceControlMode::Data 7a z
14:08:22.520  WARN   wezterm_term::terminalstate::performer > unknown unspecified CSI: "0%m"
14:08:22.520  WARN   wezterm_term::terminalstate::performer > unknown unspecified CSI: "?4m"

Anything else?

Interestingly showkeys -s does not show differing behavior with how wezterm and other terminals are handling this keypress so I don't really know what is going on here.

@miversen33 miversen33 added the bug Something isn't working label Mar 1, 2023
@wez wez added the keyboard Keyboard mapping/handling label Mar 2, 2023
@miversen33
Copy link
Author

Some quick notes here. I tested this on a windows machine this morning and wezterm performs as expected (passing the correct keycode into vim).

So this may be something related to how key codes are handled in wezterm in relation to linux (if that helps narrow anything at all down)

@wez
Copy link
Owner

wez commented Mar 2, 2023

Things to try:

@miversen33
Copy link
Author

I will try that tonight when I get home!

If you are using a non-latin or otherwise "exotic" keyboard layout, does changing it to eg: standard US English change behavior?

I am using the standard US English keyset

@miversen33
Copy link
Author

use_ime=false did not help unfortunately.

Here is the debug_key_events logs

16:35:09.768  INFO   wezterm_gui::termwindow::keyevent     > key_event RawKeyEvent { key: Physical(LeftControl), modifiers: NONE, phys_code: Some(LeftControl), raw_code: 37, repeat_count: 1, key_is_down: true, handled: Handled(false) }
16:35:09.768  INFO   wezterm_gui::termwindow::keyevent     > key_event KeyEvent { key: Control, modifiers: NONE, repeat_count: 1, key_is_down: true, raw: Some(RawKeyEvent { key: Physical(LeftControl), modifiers: NONE, phys_code: Some(LeftControl), raw_code: 37, repeat_count: 1, key_is_down: true, handled: Handled(false) }) }
16:35:09.768  INFO   wezterm_gui::termwindow::keyevent     > send to pane DOWN key=Control mods=NONE
16:35:10.172  INFO   wezterm_gui::termwindow::keyevent     > key_event RawKeyEvent { key: Physical(Slash), modifiers: CTRL, phys_code: Some(Slash), raw_code: 61, repeat_count: 1, key_is_down: true, handled: Handled(false) }
16:35:10.172  INFO   wezterm_gui::termwindow::keyevent     > key_event KeyEvent { key: Char('/'), modifiers: CTRL, repeat_count: 1, key_is_down: true, raw: Some(RawKeyEvent { key: Physical(Slash), modifiers: CTRL, phys_code: Some(Slash), raw_code: 61, repeat_count: 1, key_is_down: true, handled: Handled(false) }) }
16:35:10.172  INFO   wezterm_gui::termwindow::keyevent     > send to pane DOWN key=Char('/') mods=CTRL
16:35:10.172  INFO   wezterm_term::terminalstate::keyboard > key_down: sending "\u{1b}[27;5;47~", Char('/') CTRL
16:35:10.241  INFO   wezterm_gui::termwindow::keyevent     > key_event KeyEvent { key: Char('/'), modifiers: CTRL, repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Physical(Slash), modifiers: CTRL, phys_code: Some(Slash), raw_code: 61, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
16:35:10.241  INFO   wezterm_gui::termwindow::keyevent     > send to pane UP key=Char('/') mods=CTRL
16:35:10.361  INFO   wezterm_gui::termwindow::keyevent     > key_event KeyEvent { key: Control, modifiers: CTRL, repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Physical(LeftControl), modifiers: CTRL, phys_code: Some(LeftControl), raw_code: 37, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
16:35:10.362  INFO   wezterm_gui::termwindow::keyevent     > send to pane UP key=Control mods=CTRL

@miversen33
Copy link
Author

Another quick update, this also happens in an Ubuntu 20.04 virtual machine (running on a different host). I suspect this is related to linux in general :(

@miversen33
Copy link
Author

More interesting behavior. If I launch tmux inside of wezterm, CTRL + / behaves correctly...

Don't know if that means anything but its interesting

@winter-again
Copy link

I'm currently encountering what I think is the same issue (running Pop OS and latest nightly wezterm: wezterm 20230329-193410-2c9fd0ef). In Neovim I have a keymap for 'Ctrl-/' getting registered as '/'. Tried the workaround from this previous issue and it seems to resolve things. Attaching the logs from debug_key_events in case it helps:

04:41:32.104  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(LeftControl), modifiers: CTRL, phys_code: Some(LeftControl), raw_code: 37, repeat_count: 1, key_is_down: true, handled: Handled(false) }
04:41:32.104  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: Control, modifiers: CTRL, repeat_count: 1, key_is_down: true, raw: Some(RawKeyEvent { key: Physical(LeftControl), modifiers: CTRL, phys_code: Some(LeftControl), raw_code: 37, repeat_count: 1, key_is_down: true, handled: Handled(false) }) }
04:41:32.105  INFO   wezterm_gui::termwindow::keyevent > send to pane DOWN key=Control mods=Modifiers(NONE | CTRL)
04:41:32.289  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(Slash), modifiers: CTRL, phys_code: Some(Slash), raw_code: 61, repeat_count: 1, key_is_down: true, handled: Handled(false) }
04:41:32.289  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: Char('/'), modifiers: CTRL, repeat_count: 1, key_is_down: true, raw: Some(RawKeyEvent { key: Physical(Slash), modifiers: CTRL, phys_code: Some(Slash), raw_code: 61, repeat_count: 1, key_is_down: true, handled: Handled(false) }) }
04:41:32.289  INFO   wezterm_gui::termwindow::keyevent > send to pane DOWN key=Char('/') mods=Modifiers(NONE | CTRL)
04:41:32.289  INFO   wezterm_term::terminalstate::keyboard > key_down: sending "\u{1f}", Char('/') Modifiers(NONE | CTRL)
04:41:32.359  INFO   wezterm_gui::termwindow::keyevent     > key_event KeyEvent { key: Char('/'), modifiers: CTRL, repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Physical(Slash), modifiers: CTRL, phys_code: Some(Slash), raw_code: 61, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
04:41:32.359  INFO   wezterm_gui::termwindow::keyevent     > send to pane UP key=Char('/') mods=Modifiers(NONE | CTRL)
04:41:32.483  INFO   wezterm_gui::termwindow::keyevent     > key_event KeyEvent { key: Control, modifiers: NONE, repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Physical(LeftControl), modifiers: NONE, phys_code: Some(LeftControl), raw_code: 37, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
04:41:32.483  INFO   wezterm_gui::termwindow::keyevent     > send to pane UP key=Control mods=Modifiers(0x0)

@miversen33
Copy link
Author

Well how about that, that work around

  keys = {
    {key="/", mods="CTRL", action=wezterm.action{SendString="\x1f"}},
  }

Worked :) I assume this will break down when running this on windows?

@miversen33
Copy link
Author

A bit more weirdness I discovered. CTRL+/ acts funny in windows cmd

Below is a screenshot of after I pressed CTRL+/ 4 times in wezterm (running a command prompt) and 4 times in windows command prompt.
image
Notice that wezterm is inserting ^_ whereas windows does nothing.

This is with using the following configuration

return {}

So there does seem to be some key map fuckery going on under the hood. I don't know that this specific instance matters (I won't be using cmd, I will be using powershell most likely) but still worth pointing out. Something is causing the key codes that are being passed to the underlying shell to be mangled slightly when mods are applied, regardless of the host OS. Though it appears to not matter most times.

@wez
Copy link
Owner

wez commented Mar 30, 2023

I haven't had bandwidth to look at this in depth, but wanted to note that keyboard behavior can vary based on the encoding, and that Windows has a special win32 input mode that complicates things
https://wezfurlong.org/wezterm/config/key-encoding.html has more information about encodings.

"\u{1b}[27;5;47~" sounds like a modifyOtherKeys style encoding. It's possible that wezterm is incorrect in using that for that key combination.

Windows: likely a completely unrelated issue, and one that might be resolved by #2235 which I haven't had bandwidth to follow up on either.

@wez
Copy link
Owner

wez commented Apr 6, 2023

OK, I checked into this and wezterm behaves like xterm here, which is the intended behavior.

The background is:

  • nvim sends ESC [ > 4 ; 2 m, the XTMODKEYS sequence that requests modifyOtherKeys mode 2.

https://github.com/neovim/neovim/blob/fd32a987520cb132455d61301467182cb58cddf2/runtime/doc/term.txt#L153-L156

  • That causes CTRL-/ to generate ESC [ 27 ; 5 ; 47 ~ as described in the xterm documentation. There's even an explicit excerpt from an email in that page:
Based on that I have added these key bindings to emacs with a note
that they will be available in xterm-214 or later:
\e[27;5;9~  control-TAB
\e[27;5;44~ control-,
\e[27;5;46~ control-.
\e[27;5;47~ control-/
\e[27;5;92~ control-\

You can replicate the behavior yourself in xterm:

$ printf "\e[>4;2m"
$ od -c

Then if you press CTRL-/, the output is:

^[[27;5;47~

image

So... what should you do?

I think this might be either an nvim configuration issue, or possibly an nvim bug, if it doesn't see through that encoding.

I saw this:

which sounds sort of similar, although kitty doesn't appear to encode CTRL-/ the same way as xterm on my mac.

If you open nvim in xterm, what behavior do you see?

@wez wez added the waiting-on-op Waiting for more information from the original poster label Apr 6, 2023
@winter-again
Copy link

So just to clarify, my Linux machine is running Pop OS which I believe uses gnome-terminal (mentioning this because I think it's similar to xterm, but I'm not 100% sure). In Neovim on gnome-terminal Ctrl-/ works fine for me.

@wez
Copy link
Owner

wez commented Apr 6, 2023

Can you try with xterm? wezterm is modeled after xterm, not gnome-terminal

@winter-again
Copy link

Sure. Tried it with xterm and Neovim is again only registering the / just like I observed previously in Wezterm.

@wez
Copy link
Owner

wez commented Apr 6, 2023

in nvim:
Enter insert mode, then press: CTRL-V CTRL-/. It renders as <C-/>

Do the same in regular vim, it renders as /. But in your vim config you can map <C-/> to have it do something else.

I think this is a vim default mapping problem rather than a problem with anything else.

@winter-again
Copy link

I tried what the OP did in that Neovim issue you linked (changing the <C-_> mapping to actually be <C-/> and it works fine on Wezterm and Xterm in Linux. On Windows, I still need to keep the mapping as <C-_> for it to work. Hope this is helpful.

@github-actions
Copy link
Contributor

This issue has been automatically closed because there has been no response to our request for more information from the original author. With only the information that is currently in the issue, we don't have enough information to take action. Please reach out if you have or find the answers we need so that we can investigate further.

@miversen33
Copy link
Author

@wez IMO this shouldn't be closed as there is no resolution for this yet. We do have a workaround for it, but the issue still persists without the workaround.

@github-actions github-actions bot removed the waiting-on-op Waiting for more information from the original poster label Apr 20, 2023
@github-actions github-actions bot reopened this Apr 20, 2023
@wez
Copy link
Owner

wez commented Apr 20, 2023

I don't believe that there is anything to change in wezterm. It is working the same way as xterm, which is the intent.

@miversen33
Copy link
Author

Hmm. I suppose if that is the goal (to emulate how xterm works), that makes sense. However from an end user perspective this still feels "wrong" if that makes sense. Sometimes the 2 don't meet though I suspect this kind of expectation vs reality mismatch (in relation to key chords) will occur more frequently as wezterm becomes more popular. Maybe worth putting some sort of FAQ doc somewhere to indicate how to address these kinds of "new comer" issues? That might actually exist on the wezterm doc somewhere, I don't know.

@wez
Copy link
Owner

wez commented Apr 20, 2023

The way I see it:

  • xterm defined modifyOtherKeys encoding
  • Other terminal(s) partially implemented it and incorrectly do not use it for CTRL-/
  • vim doesn't map the modifyOtherKeys encoded form of CTRL-/ to CTRL-/, leaving it with a surprising default

I'm open to having something get added to the FAQ to explain to folks how they can configure vim for this case; would you like to draft that? I don't use that key combination in vim and I don't really know what a good concrete example of its use might be.

@miversen33
Copy link
Author

Nifty! I figured that was somewhere. Ya I can slap something together. I'll add a comment on this thread with it when I get it done. Probably tomorrow, its getting late here tonight

@miversen33
Copy link
Author

miversen33 commented Apr 21, 2023

@wez

How's this?


CTRL+/ doesn't work in my vim editor!

Some terminals interpret or mangle chorded keys such as CTRL+/, causing them to be interpretted in a particular way by the underlying programs.
Wezterm does not do this and thus some programs such as vim and its variants may experience weirdness with interpreting the key codes.

A way to address this is to add the following to your wezterm keymap

config.keys = {
    { key = '/', mods = 'CTRL', action=wezterm.action.SendString("\x1f") }
}

This performs the aformentioned interception and "mangling" of the CTRL+/ key chord and emits a keycode that vim will understand to be CTRL+/.


Also, where do I submit this to get it added to the FAQ (once we decide its good)

@wez
Copy link
Owner

wez commented Apr 21, 2023

There's some nuance missing, and I think the solution is at the wrong layer; you don't (and shouldn't!) need to override the encoding in wezterm if the issue is that vim doesn't do anything with that key press.

Try this in vim:

:map <C-/> :echo "hello"<CR>

Pressing CTRL-/ will echo "hello"

What do you typically assign CTRL-/ in vim? Do you just need to explicitly map that?

@miversen33
Copy link
Author

miversen33 commented Apr 21, 2023

I was so very confused for a moment. Initially I was like "Wait Wez, we can't do what you are asking, that is literally what this issue is about". But then I tried it and it worked.

Digging into my neovim config, I find this

vim.keymap.set('n', '<C-_>', ':lua require("Comment.api").toggle.linewise()<CR>', {silent = true})
vim.keymap.set('i', '<C-_>', '<ESC>:lua require("Comment.api").toggle.linewise()<CR>i', {silent = true})
vim.keymap.set('x', '<C-_>', '<ESC>:lua require("Comment.api").toggle.linewise(vim.fn.visualmode())<CR>', {silent = true})

So I am (finally) now understanding what is going on here. Yes, this can be rectified in a vim config, though <C-/> is not recognized by other terminals (which is why I had to do <C-_> I guess?). Your map command for example will not work in alacritty or konsole or whatever. It does however work in xterm (and subsequently wezterm).

So you are correct that the fix is something that can be done in vim land based on the terminal (working through how to figure that out right now).

I will add a new comment to this thread with an updated set of FAQ text (probably with both vimscript (vim) and lua (neovim) solutions to the problem)

@wez
Copy link
Owner

wez commented Apr 21, 2023

The heart of this issue is that certain key combinations are, in the default terminal encoding scheme, ambiguous and low-fidelity. CTRL-/ is one example where that scheme resulted in it being encoded the same way as CTRL-_.

When a terminal fully implements modifyOtherKeys (or kitty keyboard encoding) that key press is then encoded unambiguously.

If you had configured an application to use CTRL-_ then you will need to also add a binding for CTRL-/ so that it will work in both environments.

@winter-again
Copy link

winter-again commented Apr 21, 2023

I could be missing something, but wanted to say that I agree that the solution is probably just a disclaimer to Vim/Neovim users that have a keymapping for CTRL-/ (i.e., they want to physically press CTRL-/ to do something)--so nothing to tweak in the Wezterm config itself.

Looks like @miversen33 had set CTRL-_ to target CTRL-/, which I also set before I used Wezterm. So it looks like the warning just has to be that

  • On Windows, target CTRL-/ with CTRL-_
  • On Linux, target CTRL-/ with CTRL-/

Is that right?

@wez
Copy link
Owner

wez commented Apr 21, 2023

It's more complex than Linux vs Windows. On Windows you may be using win32 input mode which is also capable of encoding CTRL-/ in high fidelity. But you may also be using kitty or modifyOtherKeys on that platform.

If you must collapse this to a simple rule where you don't want to understand the reasons behind it, I would summarize it as:

For legacy reasons, some terminals encode the CTRL-/ key press the same way as CTRL-_. For the widest compatibility it is recommended that you map both CTRL-/ and CTRL-_ to the same action so that your vim configuration will work in many different terminals.

@wez wez added docs Primarily or only affects documentation and removed bug Something isn't working labels Jul 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Primarily or only affects documentation keyboard Keyboard mapping/handling
Projects
None yet
Development

No branches or pull requests

3 participants