wez / wezterm

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

Pasting from Windows clipboard manager adds extra ``^[[200~`` #3510

Open SuperSandro2000 opened 1 year ago

SuperSandro2000 commented 1 year ago

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

Windows

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?

No, and I'll explain why below

Describe the bug

When directly pasting after copying something from the windows clipboard (Meta+V,Ctrl+Shift+V) I always get an extra ^[[200~ in the beginning.

To Reproduce

Configuration

local wezterm = require("wezterm")

local is_windows = wezterm.target_triple == "x86_64-pc-windows-msvc"
local wsl_domains = nil

if is_windows then
  wsl_domains = is_windows and wezterm.default_wsl_domains()
end

local gruvxbox_dark = wezterm.get_builtin_color_schemes()["GruvboxDark"]
gruvxbox_dark.scrollbar_thumb = "#e6d4a3"

return {
  audible_bell = "Disabled",
  color_scheme = "Gruvbox Dark",
  color_schemes = {
    ["Gruvbox Dark"] = gruvxbox_dark,
  },
  default_domain = is_windows and "WSL:NixOS" or nil,
  default_prog = is_windows and { "wsl.exe" } or nil,
  -- debug_key_events = true,
  enable_scroll_bar = true,
  enable_kitty_keyboard = true,
  -- exit_behavior = "Close",
  font = wezterm.font_with_fallback({
    "JetBrains Mono",
    "Symbols Nerd Font",
  }),
  font_size = 12.15,
  hide_mouse_cursor_when_typing = false,
  hide_tab_bar_if_only_one_tab = false,
  keys = {
    -- because of some bug Tab is detect as i
    {
      key = "phys:I",
      mods = "CTRL|SHIFT",
      action = wezterm.action({ ActivateTabRelative = -1 }),
    },
    {
      key = "phys:I",
      mods = "CTRL",
      action = wezterm.action({ ActivateTabRelative = 1 }),
    },
    -- scroll between prompts with Shift+Arrow up/down
    {
      key = "UpArrow",
      mods = "SHIFT",
      action = wezterm.action({ ScrollToPrompt = -1 }),
    },
    {
      key = "DownArrow",
      mods = "SHIFT",
      action = wezterm.action({ ScrollToPrompt = 1 }),
    },
    -- split current pane vertical
    {
      key = '"',
      mods = "CTRL|SHIFT|ALT",
      action = wezterm.action({
        SplitVertical = { domain = "CurrentPaneDomain" },
      }),
    },
    -- split current pane horizontal
    {
      key = "%",
      mods = "CTRL|SHIFT|ALT",
      action = wezterm.action({
        SplitHorizontal = { domain = "CurrentPaneDomain" },
      }),
    },
    -- CTRL-SHIFT-l activates the debug overlay
    {
      key = 'L',
      mods = 'CTRL',
      action = wezterm.action.ShowDebugOverlay,
    },
  },
  launch_menu = is_windows and { { args = { "cmd.exe" }, domain = { DomainName = "local" } } } or nil,
  scrollback_lines = 40000,
  set_environment_variables = {
    -- TERMINFO_DIRS = "/home/" .. (os.getenv("USERNAME") or os.getenv("USER")) .. "/.nix-profile/share/terminfo",
    WSLENV = is_windows and "TERMINFO_DIRS" or nil,
    prompt = is_windows and "$E]7;file://localhost/$P$E\\$E[32m$T$E[0m $E[35m$P$E[36m$_$G$E[0m " or nil,
  },
  term = "wezterm",
  text_background_opacity = 1.0,
  warn_about_missing_glyphs = false,
  wsl_domains = wsl_domains,
  window_background_opacity = 0.9
}

Expected Behavior

Just the text should be copied

Logs

Debug Overlay
wezterm version: 20230408-112425-69ae8472 x86_64-pc-windows-msvc
Window Environment: Windows
OpenGL version: Intel(R) UHD Graphics 4.5.0 - Build 30.0.101.1122
Enter lua statements or expressions and hit Enter.
Press ESC or CTRL-D to exit
14:37:47.475 ERROR window::os::windows::window > unexpected dead key expansion: modifiers=NONE vk=9 res=2 releasing=true [94, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Anything else?

No response

michaelrommel commented 1 year ago

I don't think this is an error. I observe this in other terminals as well, if you prefix your paste with Ctrl-V I tried a simple operation: select a text in Windows' Notepad, then press Ctrl-C, switch to wezterm and do a Ctrl-Shift-V and it pastes without a problem. If I press Ctrl-V Ctrl-Shit-V, I get a ^[[200~ prefix and the last character is uppercase.

wez commented 1 year ago

FWIW, wezterm doesn't explicitly know anything about the windows clipboard manager. Please set debug_key_events=true and share the log from pressing that key sequence.

SuperSandro2000 commented 1 year ago

This happens with any program (cat, vim, shell). It also does not happen with windows terminal where the result is immediately pasted.

I tried pasting debug_key_events=true from my cliboard

17:05:54.545  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(LeftWindows), modifiers: SUPER | ENHANCED_KEY, phys_code: Some(LeftWindows), raw_code: 91, scan_code: 91, repeat_count: 1, key_is_down: true, handled: Handled(false) }
17:05:54.547  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: LeftWindows, modifiers: SUPER | ENHANCED_KEY, repeat_count: 1, key_is_down: true, raw: Some(RawKeyEvent {
key: Physical(LeftWindows), modifiers: SUPER | ENHANCED_KEY, phys_code: Some(LeftWindows), raw_code: 91, scan_code: 91, repeat_count: 1, key_is_down: true, handled: Handled(false) }) }
17:05:54.549  INFO   wezterm_gui::termwindow::keyevent > send to pane DOWN key=LeftWindows mods=Modifiers(NONE | SUPER)
17:05:54.550  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[91;91;0;1;256;1_"
17:05:54.552  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(LeftWindows), modifiers: ENHANCED_KEY, phys_code: Some(LeftWindows), raw_code: 91, scan_code:
91, repeat_count: 1, key_is_down: false, handled: Handled(false) }
17:05:54.552  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: LeftWindows, modifiers: ENHANCED_KEY, repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Physical(LeftWindows), modifiers: ENHANCED_KEY, phys_code: Some(LeftWindows), raw_code: 91, scan_code: 91, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
17:05:54.553  INFO   wezterm_gui::termwindow::keyevent > send to pane UP key=LeftWindows mods=Modifiers(0x0)
17:05:54.554  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[91;91;0;0;256;1_"
17:05:54.556  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(V), modifiers: NONE, phys_code: Some(V), raw_code: 86, scan_code: 47, repeat_count: 1, key_is_down: false, handled: Handled(false) }
17:05:54.556  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: Char('v'), modifiers: NONE, repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Physical(V), modifiers: NONE, phys_code: Some(V), raw_code: 86, scan_code: 47, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
17:05:54.557  INFO   wezterm_gui::termwindow::keyevent > send to pane UP key=Char('v') mods=Modifiers(0x0)
17:05:54.558  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[86;47;118;0;0;1_"
17:05:55.504  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(LeftControl), modifiers: CTRL | LEFT_CTRL, phys_code: Some(LeftControl), raw_code: 17, scan_code: 0, repeat_count: 1, key_is_down: true, handled: Handled(false) }
17:05:55.505  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: LeftControl, modifiers: CTRL | LEFT_CTRL, repeat_count: 1, key_is_down: true, raw: Some(RawKeyEvent { key: Physical(LeftControl), modifiers: CTRL | LEFT_CTRL, phys_code: Some(LeftControl), raw_code: 17, scan_code: 0, repeat_count: 1, key_is_down: true, handled: Handled(false) }) }
17:05:55.506  INFO   wezterm_gui::termwindow::keyevent > send to pane DOWN key=LeftControl mods=Modifiers(NONE | CTRL)
17:05:55.507  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[17;0;0;1;8;1_"
17:05:55.539  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(V), modifiers: CTRL | LEFT_CTRL, phys_code: Some(V), raw_code: 86, scan_code: 0, repeat_count: 1, key_is_down: true, handled: Handled(false) }
17:05:55.541  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: Char('v'), modifiers: CTRL | LEFT_CTRL, repeat_count: 1, key_is_down: true, raw: Some(RawKeyEvent { key: Physical(V), modifiers: CTRL | LEFT_CTRL, phys_code: Some(V), raw_code: 86, scan_code: 0, repeat_count: 1, key_is_down: true, handled: Handled(false) }) }
17:05:55.542  INFO   wezterm_gui::termwindow::keyevent > send to pane DOWN key=Char('v') mods=Modifiers(NONE | CTRL)
17:05:55.543  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[86;0;22;1;8;1_"
17:05:55.551  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(V), modifiers: CTRL | LEFT_CTRL, phys_code: Some(V), raw_code: 86, scan_code: 0, repeat_count: 1, key_is_down: false, handled: Handled(false) }
17:05:55.553  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: Char('v'), modifiers: CTRL | LEFT_CTRL, repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key:
Physical(V), modifiers: CTRL | LEFT_CTRL, phys_code: Some(V), raw_code: 86, scan_code: 0, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
17:05:55.554  INFO   wezterm_gui::termwindow::keyevent > send to pane UP key=Char('v') mods=Modifiers(NONE | CTRL)
17:05:55.555  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[86;0;22;0;8;1_"
17:05:55.573  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(LeftControl), modifiers: NONE, phys_code: Some(LeftControl), raw_code: 17, scan_code: 0, repeat_count: 1, key_is_down: false, handled: Handled(false) }
17:05:55.574  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: LeftControl, modifiers: NONE, repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Physical(LeftControl), modifiers: NONE, phys_code: Some(LeftControl), raw_code: 17, scan_code: 0, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
17:05:55.575  INFO   wezterm_gui::termwindow::keyevent > send to pane UP key=LeftControl mods=Modifiers(0x0)
17:05:55.576  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[17;0;0;0;0;1_"
17:05:56.552  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(LeftControl), modifiers: CTRL | LEFT_CTRL, phys_code: Some(LeftControl), raw_code: 17, scan_code: 29, repeat_count: 1, key_is_down: true, handled: Handled(false) }
17:05:56.553  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: LeftControl, modifiers: CTRL | LEFT_CTRL, repeat_count: 1, key_is_down: true, raw: Some(RawKeyEvent { key: Physical(LeftControl), modifiers: CTRL | LEFT_CTRL, phys_code: Some(LeftControl), raw_code: 17, scan_code: 29, repeat_count: 1, key_is_down: true, handled: Handled(false) }) }
17:05:56.554  INFO   wezterm_gui::termwindow::keyevent > send to pane DOWN key=LeftControl mods=Modifiers(NONE | CTRL)
17:05:56.555  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[17;29;0;1;8;1_"
17:05:56.557  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(LeftShift), modifiers: SHIFT | CTRL | LEFT_CTRL | LEFT_SHIFT, phys_code: Some(LeftShift), raw_code: 16, scan_code: 42, repeat_count: 1, key_is_down: true, handled: Handled(false) }
17:05:56.558  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: LeftShift, modifiers: SHIFT | CTRL | LEFT_CTRL | LEFT_SHIFT, repeat_count: 1, key_is_down: true, raw: Some(RawKeyEvent { key: Physical(LeftShift), modifiers: SHIFT | CTRL | LEFT_CTRL | LEFT_SHIFT, phys_code: Some(LeftShift), raw_code: 16, scan_code: 42, repeat_count: 1, key_is_down: true, handled: Handled(false) }) }
17:05:56.559  INFO   wezterm_gui::termwindow::keyevent > send to pane DOWN key=LeftShift mods=Modifiers(NONE | SHIFT | CTRL)
17:05:56.560  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[16;42;0;1;24;1_"
17:05:56.642  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(V), modifiers: SHIFT | CTRL | LEFT_CTRL | LEFT_SHIFT, phys_code: Some(V), raw_code: 86, scan_code: 47, repeat_count: 1, key_is_down: true, handled: Handled(false) }
17:05:56.643  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: Char('V'), modifiers: CTRL | LEFT_CTRL | LEFT_SHIFT, repeat_count: 1, key_is_down: true, raw: Some(RawKeyEvent { key: Physical(V), modifiers: SHIFT | CTRL | LEFT_CTRL | LEFT_SHIFT, phys_code: Some(V), raw_code: 86, scan_code: 47, repeat_count: 1, key_is_down: true, handled: Handled(false) }) }
17:05:56.644  INFO   wezterm_gui::termwindow::keyevent > Char('V') CTRL | LEFT_CTRL | LEFT_SHIFT -> perform PasteFrom(Clipboard)
17:05:56.741  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(V), modifiers: SHIFT | CTRL | LEFT_CTRL | LEFT_SHIFT, phys_code: Some(V), raw_code: 86, scan_code: 47, repeat_count: 1, key_is_down: false, handled: Handled(false) }
17:05:56.742  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: Char('V'), modifiers: CTRL | LEFT_CTRL | LEFT_SHIFT, repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Physical(V), modifiers: SHIFT | CTRL | LEFT_CTRL | LEFT_SHIFT, phys_code: Some(V), raw_code: 86, scan_code: 47, repeat_count: 1, key_is_down: false, handled: Handled(false) })
}
17:05:56.743  INFO   wezterm_gui::termwindow::keyevent > send to pane UP key=Char('V') mods=Modifiers(NONE | CTRL)
17:05:56.744  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[86;47;22;0;8;1_"
17:05:56.781  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(LeftControl), modifiers: SHIFT | LEFT_SHIFT, phys_code: Some(LeftControl), raw_code: 17, scan_code: 29, repeat_count: 1, key_is_down: false, handled: Handled(false) }
17:05:56.782  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: LeftControl, modifiers: SHIFT | LEFT_SHIFT, repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Physical(LeftControl), modifiers: SHIFT | LEFT_SHIFT, phys_code: Some(LeftControl), raw_code: 17, scan_code: 29, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
17:05:56.783  INFO   wezterm_gui::termwindow::keyevent > send to pane UP key=LeftControl mods=Modifiers(NONE | SHIFT)
17:05:56.785  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[17;29;0;0;16;1_"
17:05:56.786  INFO   wezterm_gui::termwindow::keyevent > key_event RawKeyEvent { key: Physical(LeftShift), modifiers: NONE, phys_code: Some(LeftShift), raw_code: 16, scan_code: 42, repeat_count: 1, key_is_down: false, handled: Handled(false) }
17:05:56.787  INFO   wezterm_gui::termwindow::keyevent > key_event KeyEvent { key: LeftShift, modifiers: NONE, repeat_count: 1, key_is_down: false, raw: Some(RawKeyEvent { key: Physical(LeftShift), modifiers: NONE, phys_code: Some(LeftShift), raw_code: 16, scan_code: 42, repeat_count: 1, key_is_down: false, handled: Handled(false) }) }
17:05:56.788  INFO   wezterm_gui::termwindow::keyevent > send to pane UP key=LeftShift mods=Modifiers(0x0)
17:05:56.790  INFO   wezterm_gui::termwindow::keyevent > Encoded input as "\u{1b}[16;42;0;0;0;1_"

I don't think this is an error. I observe this in other terminals as well, if you prefix your paste with Ctrl-V I tried a simple operation: select a text in Windows' Notepad, then press Ctrl-C, switch to wezterm and do a Ctrl-Shift-V and it pastes without a problem. If I press Ctrl-V Ctrl-Shit-V, I get a ^[[200~ prefix and the last character is uppercase.

Interesting. Ctrl+V produces the same extra character as Meta+V does. That could be the point where Windows tries to paste the selected clipboard entry

wez commented 1 year ago

I've never used this feature of windows before. Looking at it now, it seems like Win+V pops up a history dialog, but you're not talking about that.

What are these Meta-V and CTRL-SHIFT-V sequences you're referring to supposed to do? From wezterm's perspective, Meta-V doesn't do anything, and CTRL-SHIFT-V is a regular paste operation.

wez commented 1 year ago

Clicking on the clipboard manager, it looks like windows sends CTRL-v to paste. That UI does nothing with the default bindings. But if I add:

 {key='v', mods='CTRL', action=act.PasteFrom 'Clipboard' },

to make CTRL-v paste, then I see stuff pasted. Since CTRL-v is meaningful to a lot of terminal programs, I don't want to make that a default binding.

I still don't understand this Meta-V sequence you're referring to. How does that relate to this?

SuperSandro2000 commented 1 year ago

it seems like Win+V pops up a history dialog, but you're not talking about that.

I am talking about that :) Meta is the Windows key.

bew commented 1 year ago

If mapping Ctrl-v does work for you, I'd suggest making a dedicated keytable in your config (or using leader/..) where you have Ctrl-v to paste. This way you can not have it normally and when you want to paste something, activate your keytable and Win-v to paste something :) (could even use some AutoHotKey to trigger them both on Win-v)

SuperSandro2000 commented 1 year ago

Couldn't we make wezterm recognize Win+V and only after that Ctrl+V?

bestia-dev commented 11 months ago

I have the same annoyance. First to clarify: We don't want to mess with Ctrl+V. It is not usable for paste in terminals. We always use Shift+Ctrl+V for paste and it works fine.

I use Win+V a lot. It opens the Clipboard Manager in Win10. It is great to have multiple items in the clipboard and choose what you want to paste. It does not paste it immediately to the terminal when I choose it. Nothing visual happens, but that is okay and consistent with how the Windows terminal works. Then I can press Shift+Ctrl+V to really paste the chosen item. I am happy with that. The Windows terminal then pastes the item correctly, but WezTerm adds the ^[[200~ and it makes it unusable.

It looks like WezTerm starts the "bracketed paste mode".

https://en.wikipedia.org/wiki/ANSI_escape_code CSI ? 2004 h Turn on bracketed paste mode. In bracketed paste mode, text pasted into the terminal will be surrounded by ESC [200~ and ESC [201~; programs running in the terminal should not treat characters bracketed by those sequences as commands.

https://cirw.in/blog/bracketed-paste One of the least well-known, and therefore least used, features of many terminal emulators is [bracketed paste mode. When you are in bracketed paste mode and you paste into your terminal the content will be wrapped by the sequences \e[200~ and \e[201~.

How could we disable this feature in WezTerm, so it does not start the "bracketed paste mode"?

bew commented 11 months ago

Normally bracketed paste mode is not enabled until the running application enabled it. If the program can't handle the bracketed chars that's really an issue with that program.

bestia-dev commented 11 months ago

I am using WezTerm on Win10 and then I use Debian12 on WSL with BASH_VERSION 5.2.15(1)-release. As I understand, "bracketed-paste" is on by default from bash 5.1. I also tried bind 'set enable-bracketed-paste on', but it didn't change anything.

Maybe the pasted item is not correctly escaped? If I paste "test" from the Clipboard manager I got:

^[[200~test~

This is not complete. It should end with ^[[201~ like this:

^[[200~test^[[201~

I read that the pasted string should be sanitized from some malicious ansi codes before bracketed-pasting. Maybe it strips away the ending for bracketed-paste somehow? The most important sanitizing is to erase the "end bracketed paste ^[[201~" code if it is maliciously not at the end of the string.

ninjalj commented 11 months ago

Ctrl-V is usually used in shells to input the next character literally without interpreting it, e.g. if you press Ctrl-V and Enter in bash, you get ^M.

When bracketed paste is enabled, this would show the initial ESC character as ^[, and the shell would not interpret it as starting a bracketed paste control sequence.

See also: https://superuser.com/questions/1532688/pasting-required-text-into-terminal-emulator-results-in-200required-text

bestia-dev commented 11 months ago

Now I understand. The Clipboard Manager is sending ctrl+v under the hood. That key combination means "the next character will be taken literally". Then shift-ctrl-v pastes the "bracketed paste" that starts with ^[[200~. But unfortunately the first character is not understood as a special code, but as a normal character "literally".
I added to my $HOME\.config\wezterm\wezterm.lua to ignore the ctrl+v key binding:

config.keys = {
    -- Turn off the default ctrl+v "input the next character literally",
    -- because it works badly with the Windows Clipboard Manager Win+v.
    { key = 'v', mods = 'CTRL', action = wezterm.action.Nop },
}

Now it works okay for my needs.
I never needed "the next character will be taken literally" and I hope I will not regret this change one day.
Thanks.

SuperSandro2000 commented 3 months ago

I found a nice workaround and just replaced my windows clipboard with https://github.com/hluk/CopyQ which does not have that problem and also you can search in the history&paste dialog.