【问题标题】:Terminal: send a do-nothing escape sequence or control character终端:发送无操作转义序列或控制字符
【发布时间】:2019-11-12 12:46:15
【问题描述】:

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


我希望 tmux 中的 Control-Shift-c 键和弦绑定到一个操作,该操作会将 tmux 选择复制到 X 剪贴板选择缓冲区中。当 tmux 未运行时,继续让 Control-Shift-c 将终端选择复制到 X 剪贴板选择缓冲区中。终端仿真器为 Control-Shift-key 和 Control-key 输入生成相同的输出,请参阅 [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 发送固定词序列。由于 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'"

所有其他不支持固定术语序列的应用程序都将收到输入垃圾。更糟糕的是,未知的转义序列可能会被误解并触发特定于应用程序的命令。最初我考虑使用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),但该字符由 shell 回显,并且在 vim 的插入模式中具有显着影响。如果不存在这样的字符,请参阅#3。也许我可以使用一个不常见的控制字符,但它也必须配置为在所有层上什么都不做:xterm、bash、readline、vim 等。

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

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

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

这个想法是像以前一样,将终端的选择复制到剪贴板缓冲区。然后插入&lt;STRING&gt;,就好像它已经被输入一样。当 tmux 收到&lt;STRING&gt; 时,它将用自己的选择覆盖剪贴板缓冲区。任何其他应用程序都会忽略它:包括并且特别是没有任何内容打印到终端。

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。

【问题讨论】:

标签: linux architecture keyboard keyboard-shortcuts tmux


【解决方案1】:

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

如果我是你,我只会发送 F20 或其他东西的转义序列,然后绑定该键以在你经常使用的其他应用程序中不执行任何操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-30
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 2015-05-09
    • 2013-11-02
    • 2013-10-04
    • 1970-01-01
    相关资源
    最近更新 更多