wez / wezterm

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

alt key coming through? #3668

Closed bheadwhite closed 1 year ago

bheadwhite commented 1 year ago

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

macOS

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

No response

WezTerm version

20230408-112425-69ae8472

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

Im getting a weird behavior when using my keyboard shortcuts.

In NVIM v0.9.0 im using a "move line" plugin. the default for moving a line up and down is using the alt+j/k shortcuts. im using karabiner elements to remap my caps lock key to be escape AND ctrl if held down in conjunction with another key.

the problem comes up when im mashing the escape key and then hit a hjkl key to move my cursor right after. the plugin registers what seems like a alt+movement key event. and my line moves, ahhh! after hours of researching this and really wanting to use wezterm, ive remapped that move line feature to a different keymapping and wanted some closure...

in my attempts to resolve this i've tried disabling karabiner and using a different karabiner-like product called hammerspoon using this spoon and i still got the same behavior.

this setup works fine in other terminal/terminal emulators.. (specifically kitty and iterm)

in my debugging efforts i used the debug_key_events config option and found that i was only passing through escape and j/k key events.

To Reproduce

deps:

nvim 0.9.0 karabiner 14.12.0 gomove plugin

neovim install 0.9.0 install the gomove plugin, i used the packer plugin manager to install.

karabiner install ~/.config/karabiner/karabiner.json:

{
  "profiles": [
    {
      "complex_modifications": {
        "parameters": {
          "basic.simultaneous_threshold_milliseconds": 0,
          "basic.to_delayed_action_delay_milliseconds": 0,
          "basic.to_if_alone_timeout_milliseconds": 100,
          "basic.to_if_held_down_threshold_milliseconds": 1000,
          "mouse_motion_to_scroll.speed": 100
        },
        "rules": [
          {
            "description": "caps lock -> hyper key (held) / escape (alone)",
            "manipulators": [
              {
                "from": {
                  "key_code": "caps_lock",
                  "modifiers": {
                    "optional": ["any"]
                  }
                },
                "to": [
                  {
                    "key_code": "right_control",
                    "modifiers": ["right_alt"],
                    "lazy": true
                  }
                ],
                "to_if_alone": [
                  {
                    "key_code": "escape"
                  }
                ],
                "type": "basic"
              }
            ]
          }
        ]
      },
      "name": "test",
      "parameters": {
        "delay_milliseconds_before_open_device": 1000
      },
      "selected": true,
      "simple_modifications": [],
      "virtual_hid_keyboard": {
        "country_code": 0,
        "indicate_sticky_modifier_keys_state": true,
        "mouse_key_xy_scale": 100
      }
    }
  ]
}

open up nvim, edit a file. mash on the caps lock key and j/k alternating between the two fairly quickly and you should see the behavior.

Configuration

-- Pull in the wezterm API local wezterm = require("wezterm")

-- This table will hold the configuration. local config = {}

-- In newer versions of wezterm, use the config_builder which will if wezterm.config_builder then -- help provide clearer error messages config = wezterm.config_builder() end

-- and finally, return the configuration to wezterm return config

Expected Behavior

i expect the plugin gomove shouldnt move a line if im only sending wezterm an escape and j/k key events.

Logs

10:43:28.992  INFO   wezterm_gui::termwindow::keyevent     > key_event RawKeyEvent { key: Char('\u{1b}'), modifiers: NONE, leds: (empty), phys_code: Some(Escape), raw_code: 53, repeat_count: 1, key_is_down: true, handled: Handled(false) }
10:43:28.993  INFO   wezterm_gui::termwindow::keyevent     > key_event KeyEvent { key: Char('\u{1b}'), modifiers: NONE, leds: (empty), repeat_count: 1, key_is_down: true, raw: Some(RawKeyEvent { key: Char('\u{1b}'), modifiers: NONE, leds: (empty), phys_code: Some(Escape), raw_code: 53, repeat_count: 1, key_is_down: true, handled: Handled(false) }) }
10:43:28.993  INFO   wezterm_gui::termwindow::keyevent     > send to pane DOWN key=Escape mods=NONE
10:43:28.993  INFO   wezterm_term::terminalstate::keyboard > key_down: sending "\u{1b}", Escape NONE
10:43:28.994  INFO   wezterm_gui::termwindow::keyevent     > key_event RawKeyEvent { key: Char('\u{1b}'), modifiers: NONE, leds: (empty), phys_code: Some(Escape), raw_code: 53, repeat_count: 1, key_is_down: false, handled: Handled(false) }
10:43:28.994  INFO   wezterm_gui::termwindow::keyevent     > key_event KeyEvent { key: Char('\u{1b}'), modifiers: NONE, leds: (empty), repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Char('\u{1b}'), modifiers: NONE, leds: (empty), phys_code: Some(Escape), raw_code: 53, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
10:43:28.994  INFO   wezterm_gui::termwindow::keyevent     > send to pane UP key=Escape mods=NONE
10:43:29.005  INFO   wezterm_gui::termwindow::keyevent     > key_event RawKeyEvent { key: Char('j'), modifiers: NONE, leds: (empty), phys_code: Some(J), raw_code: 38, repeat_count: 1, key_is_down: true, handled: Handled(false) }
10:43:29.005  INFO   wezterm_gui::termwindow::keyevent     > key_event KeyEvent { key: Char('j'), modifiers: NONE, leds: (empty), repeat_count: 1, key_is_down: true, raw: None }
10:43:29.005  INFO   wezterm_gui::termwindow::keyevent     > send to pane DOWN key=Char('j') mods=NONE
10:43:29.005  INFO   wezterm_term::terminalstate::keyboard > key_down: sending "j", Char('j') NONE
10:43:29.038  INFO   wezterm_gui::termwindow::keyevent     > key_event RawKeyEvent { key: Char('j'), modifiers: NONE, leds: (empty), phys_code: Some(J), raw_code: 38, repeat_count: 1, key_is_down: false, handled: Handled(false) }
10:43:29.038  INFO   wezterm_gui::termwindow::keyevent     > key_event KeyEvent { key: Char('j'), modifiers: NONE, leds: (empty), repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Char('j'), modifiers: NONE, leds: (empty), phys_code: Some(J), raw_code: 38, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
10:43:29.038  INFO   wezterm_gui::termwindow::keyevent     > send to pane UP key=Char('j') mods=NONE

Anything else?

the debug key logs i've shared was all i needed to input to recreate the behavior..

thank you for your time. 🙇‍♂️

wez commented 1 year ago

In the standard terminal keyboard encoding, ALT+j is encoded as ESC j. This is ambiguous and hard to distinguish from someone pressing ESC followed by j.

Most programs that care to make a distinction do so by waiting a small amount of time when they receive an ESC to see if a following character is present to complete the ALT-j version of the key press or whether to consider the ESC as a standalone key.

https://unix.stackexchange.com/questions/23138/esc-key-causes-a-small-delay-in-terminal-due-to-its-alt-behavior discusses this in more detail in the context of tmux.

https://stackoverflow.com/questions/10855539/why-does-vim-incsearch-pause-when-cancelling-a-search-with-the-esc-key/10856095#10856095 discusses how you can adjust the timeout for vim; if nvim doesn't use the same setting, you should search to see if it has an equivalent.

wez commented 1 year ago

FWIW, I also use karabiner to make capslock be ESC when tapped or CTRL when held. I have my timeouts set this way:

image

I suspect that you may have yours set too aggressively, as I do not have this particular issue.

bheadwhite commented 1 year ago

I did play with those timeouts, looks like I left them in a funny spot. I believe changing them back to the default values didn't help fix my issue. I can verify later this evening.

bheadwhite commented 1 year ago

can confirm. karabiner default timeout values dont fix it. also, regarding the vim stack overflow article, i did play with the timeout settings in vim with no luck.

the tmux article hit home. i did feel that the tmux example was in a similar layer that we're working with here. Would their offered solution in that link also inspire a wezterm solution?

if i do load all my current settings in kitty, for example, it works fine.

wez commented 1 year ago

I don't think there is anything that should be changed in wezterm here; you are pressing escape and then j, wezterm is passing those on as soon as you press them, and it is vim/nvim interpreting the byte sequence that those key presses map to.

The only thing that wezterm could potentially do here is to artificially delay keys after escape is pressed, but that will be a source of bug reports from people that don't want there to be any additional latency, and it will be a complex PITA to implement--wezterm can't really block input key events except by hanging the GUI thread for whatever delay is desired.

re: kitty, it has its own keyboard encoding scheme that is intended to avoid ambiguous key representations. You can enable support for that protocol in wezterm; I recommend using the nightly builds as a number of fixes have been made to it recently. See:

https://wezfurlong.org/wezterm/config/key-encoding.html#kitty-keyboard-protocol

github-actions[bot] commented 1 year ago

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.