终端:发送禁止执行的转义序列或控制字符

时间:2019-07-01 21:42:55

标签: linux architecture keyboard keyboard-shortcuts tmux

我需要我的终端发送一个未使用的控制字符或转义序列,该序列在所有层上均无效:被shell(bash,...)忽略,被行编辑器(readline,...)忽略,并被所有应用程序(vim,less,mutt等)忽略。然后,我将在tmux中绑定此密钥,并在必要时使用用户定义的密钥转义序列。 我使用什么控制字符或转义序列?下面的更多信息:


我希望tmux中的Control-Shift-c琴键绑定到一个动作,该动作会将tmux选择复制到X剪贴板选择缓冲区中。当tmux不运行时,并继续让Control-Shift-c将终端选择复制到X剪贴板选择缓冲区。终端仿真器为Control-Shift键和Control键输入生成相同的输出,请参见[1] [2]。第一步是更改此内容:

# Enable fixterms (I think) sequences for all keys:
xterm -xrm "XTerm.vt100.modifyOtherKeys: 2" -xrm "XTerm.vt100.formatOtherKeys: 1"

这指示xterm为由Control,Alt或Meta修改的所有键构造一个转义序列。据我所知,是使用原始xterm序列还是通过新的fixterms [3]规范格式化了这些转义序列。甚至tmux仅支持这些序列的一个子集[4],而不支持成熟的CSI序列解析器[5]。

最简单的解决方法是按照[6]的方法仅让Control-Shift-c发送一个fixterms序列。由于tmux不支持此序列,因此必须通过user-keys选项手动定义。它还必须绑定在tmux的根密钥表中,而不是复制模式表之一。否则,如果tmux不在复制模式下,则绑定将被忽略,并通过tmux传递给终端应用程序之一。

# Configure only Control-Shift-c to send a fixterms sequence:
xterm -xrm "XTerm*vt100.translations: #override \n\
    Ctrl Shift <Key>c: string(0x1b) string ([67;6u)"

# Recognize (but don't handle) the Control-Shift-c fixterms sequence:
tmux set-option -s user-keys[0] "\e[67;6u"

# Copy the selection to the clipboard buffer only when in copy-mode. If
# there is no selection, nothing will be copied:
tmux bind-key -T root User0 if-shell -Ft= "#{pane_in_mode}"
    "send-keys -X copy-pipe 'xsel -i -b'"

所有不支持fixterms序列的其他应用程序都将收到输入垃圾。更糟糕的是,未知的转义序列很可能会被误解并触发特定于应用程序的命令。最初,我考虑过使用tcgetpgrp(3) [7]来获取当前在终端中运行的命令的名称,就像tmux [8]中的#{pane_current_command}一样。

xterm <-> bash <-> command

Control-Shift-c的终端绑定将首先照常将终端的选择复制到剪贴板缓冲区;然后调用我的外部程序[9]。如果终端命令当前不是tmux,则什么也不会发生。否则,外部命令将Fixterms Control-Shift-c序列写入终端的pts。当tmux接收到该序列时,它将使用自己的选择覆盖剪贴板缓冲区。

xterm -xrm "XTerm*vt100.translations: #override \n\
    Ctrl Shift <Key>c: copy-selection(PRIMARY) \n\
                       exec-formatted("~/send_fixterms_sequence_if_tmux.py")

这无法处理嵌套的终端仿真器,就像在ssh上运行tmux一样-这很常见。

xterm <-> bash <-> ssh <-> bash <-> tmux <-> bash <-> command

这是我的两难选择,目前我正在考虑几种选择:

  1. 让终端发送控制字符而不是转义序列。始终支持控制字符。我希望那里有一个空字符,并希望Control-@(NUL或ASCII 0)有效,但是该字符会被外壳回显,并且在vim中的插入模式下具有重要作用。如果不存在这样的字符,请参阅#3。也许我可以使用一个不常见的控制字符,但也必须将其配置为在所有层上不执行任何操作:xterm,bash,readline,vim等。

  2. 让终端发送未使用的或什么都不做的转义序列,而不是Control-Shift-c固定术语序列。该序列在所有层都需要被忽略:shell(bash,...)忽略,行编辑器(readline,...)忽略,所有应用程序(vim,less,mutt,...)忽略。 。参见#3。

  3. 为我的终端修改terminfo条目,以确保根据[10]在所有层上都忽略至少上述项之一(控制代码,标准转义序列或fixterms转义序列)。然后,将修改后的序列绑定到tmux中。

  4. 调用readline做一些神奇的事情。长远来看,因为这不太可能对备用模式终端应用程序产生任何影响。

想法是像以前一样,将终端的选择复制到剪贴板缓冲区。然后插入<STRING>,就像已经键入一样。当tmux收到<STRING>时,它将使用自己的选择覆盖剪贴板缓冲区。任何其他应用程序都将忽略它:包括,尤其是没有任何内容打印到终端上。

xterm -xrm "XTerm*vt100.translations: #override \n\
    Ctrl Shift <Key>c: copy-selection(PRIMARY) string(<STRING>)

我还打算将其扩展到gnome-terminal,因此将转义序列或控制字符写入终端的pts的示例将不胜感激。我只使用xterm作为工作示例-这个问题绝对不是xterm特定的。


  1. https://stackoverflow.com/a/14876639
  2. https://unix.stackexchange.com/a/116630
  3. http://www.leonerd.org.uk/hacks/fixterms/
  4. https://github.com/tmux/tmux/blob/master/xterm-keys.c
  5. http://www.leonerd.org.uk/code/libtermkey/
  6. https://stackoverflow.com/a/2179779
  7. http://man7.org/linux/man-pages/man3/tcgetpgrp.3.html
  8. https://github.com/tmux/tmux/blob/master/osdep-linux.c
  9. https://invisible-island.net/xterm/manpage/xterm.html#h2-KEY-BINDINGS
  10. Bind Ctrl+Tab and Ctrl+Shift+Tab in tmux
  11. https://man.openbsd.org/ssh#ESCAPE_CHARACTERS

编辑,新思路: SSH提供了自己的终端仿真器,或者至少与pts对挂钩[11]。这是否意味着它可以处理传入的转义序列,并可能运行外部远程命令,例如使用tcgetpgrp的命令?还是那是一种不安全感?与其配置可能无休止的终端应用程序系列以忽略转义序列,不如像tmux那样仅配置SSH。

1 个答案:

答案 0 :(得分:0)

所有可用序列对于接收它的应用程序都可能看起来像某种密钥(例如0是C- @和C-Space),没有保证应用程序可以忽略的序列。

如果我是我,我只是发送F20或类似内容的转义序列,然后将该键绑定在您经常使用的其他应用程序中什么也不做。