【发布时间】: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
这是我的两难选择,我目前正在考虑几种替代方案:
让终端发送控制字符而不是转义序列。始终支持控制字符。我希望存在一个无所事事的字符,并希望 Control-@(NUL 或 ASCII 0),但该字符由 shell 回显,并且在 vim 的插入模式中具有显着影响。如果不存在这样的字符,请参阅#3。也许我可以使用一个不常见的控制字符,但它也必须配置为在所有层上什么都不做:xterm、bash、readline、vim 等。
让终端发送一个未使用或什么都不做的转义序列,而不是 Control-Shift-c 固定词序列。该序列需要在所有层被忽略:被 shell(bash,...)忽略,被行编辑器(readline,...)忽略,并且被所有应用程序(vim,less,mutt,...)忽略.见#3。
根据 [10],修改终端的 terminfo 条目,以确保在所有层中至少忽略上述之一(控制代码、标准转义序列或 fixterms 转义序列)。然后,在 tmux 中绑定这个修改后的序列。
调用 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 特有的。
- https://stackoverflow.com/a/14876639
- https://unix.stackexchange.com/a/116630
- http://www.leonerd.org.uk/hacks/fixterms/
- https://github.com/tmux/tmux/blob/master/xterm-keys.c
- http://www.leonerd.org.uk/code/libtermkey/
- https://stackoverflow.com/a/2179779
- http://man7.org/linux/man-pages/man3/tcgetpgrp.3.html
- https://github.com/tmux/tmux/blob/master/osdep-linux.c
- https://invisible-island.net/xterm/manpage/xterm.html#h2-KEY-BINDINGS
- Bind Ctrl+Tab and Ctrl+Shift+Tab in tmux
- https://man.openbsd.org/ssh#ESCAPE_CHARACTERS
编辑,新想法: SSH 提供了自己的终端仿真器,或者至少连接到pts 对[11]。这是否意味着它可以处理传入的转义序列,并可能运行外部远程命令,例如使用tcgetpgrp 的命令?或者那会是一种不安全感?与其配置一系列可能无穷无尽的终端应用程序来忽略转义序列,我更愿意像 tmux 一样只配置 SSH。
【问题讨论】:
-
所有
0x80+ 字符。 -
那些回声——不管
XTerm*vt100.metaSendsEscape和XTerm*vt100.eightBitInput。顺便说一句,这些 C1 控制字符[1] 还是仅用于编码 Meta 的第八位,如 Control-Meta-key 中的? [1]vt100.net/docs/vt510-rm/chapter4#S4.1
标签: linux architecture keyboard keyboard-shortcuts tmux