简短版:使用emacs的xterm-mouse-mode时,某个东西(emacs?bash?xterm?)拦截了xterm的控制序列,并将它们替换为\0。在宽屏幕上这很麻烦,因为只有前223列具有鼠标功能。
罪魁祸首是什么,我该如何解决?
据我所知,这与Unicode / UTF-8支持有关,因为5-6年前我上次使用大型显示器时这不是问题。
详细信息如下...
谢谢!
Emacs xterm-mouse-mode处理从x=95开始的鼠标点击存在已知的弱点。一个解决方法,被最新版本的emacs采用,将问题推迟到x=223处。
几年前,我发现xterm在7位八进制中编码位置。给定要编码的位置“x”,其中X=x-96,发送:
\40+x (x < 96)
\300+X/64 \200+X%64 (otherwise)
我们需要在emacs中给定的x位置上加1,因为xterm中的位置从1开始,而不是从0开始。因此,魔术数字x=95就出现了,因为它被编码为“\300\200”——第一个转义数字。某个人(emacs?bash?xterm?)将它们视为ISO 2022中的“C0”控制序列。从x=159开始,我们切换到“C1”序列(\301\200),这也是ISO 2022的一部分。\302序列出现问题,对应当前的x=223限制。几年前,我能够手动扩展这个hack以拦截\302和\303序列,从而解决了这个问题。快进几年,今天我发现我又卡在x=223处,因为某个人正在用\0替换那些序列。
因此,当我期望点击第1行,第250列时会产生什么:
ESC [ M SPC \303\207 ! ESC [ M # \303\207 !
但是对于任何列数大于223的情况,emacs报告如下:
ESC [ M SPC C-@ ! ESC [ M # C-@ !
我怀疑是Unicode/UTF-8支持造成的问题。一些调查显示,Unicode标准在2000年11月之前允许C0和C1序列作为UTF-8的一部分,我猜某人没有收到这个备忘录(幸运的是)。然而,\302\200-\302\237是Unicode控制序列,因此某些人将它们吞掉了(不知道要做什么!)并返回\0。更详细的问题如下:
- 谁是拦截代码并防止其进入emacs失效缓冲区的那个人?
- 如果真的只涉及控制序列,为什么在\302\237之后的字符(它们是可打印Unicode的UTF-8编码)也会返回\0?
- 是什么决定了emacs是以Unicode字符还是八进制转义序列来显示失效信息,并且为什么两者不匹配?例如,我的自制cygwin emacs 23.2.1(xterm 229)报告161列的\301\202,但我的rhel5.5附带的emacs 22.3.1(xterm 215)报告“”(带抑扬符的拉丁字母A),实际上是UTF-8的\ 303\202! 更新: 这是针对xterm-261的补丁,使其以utf-8格式发出鼠标位置:
diff -r button.c button.utf-8-fix.c
--- a/button.c Sat Aug 14 08:23:00 2010 +0200
+++ b/button.c Thu Aug 26 16:16:48 2010 +0200
@@ -3994,1 +3994,27 @@
-#define MOUSE_LIMIT (255 - 32)
+#define MOUSE_LIMIT (2047 - 32)
+#define MOUSE_UTF_8_START (127 - 32)
+
+static unsigned
+EmitMousePosition(Char line[], unsigned count, int value)
+{
+ /* Add pointer position to key sequence
+ *
+ * Encode large positions as two-byte UTF-8
+ *
+ * NOTE: historically, it was possible to emit 256, which became
+ * zero by truncation to 8 bits. While this was arguably a bug,
+ * it's also somewhat useful as a past-end marker so we keep it.
+ */
+ if(value == MOUSE_LIMIT) {
+ line[count++] = CharOf(0);
+ }
+ else if(value < MOUSE_UTF_8_START) {
+ line[count++] = CharOf(' ' + value + 1);
+ }
+ else {
+ value += ' ' + 1;
+ line[count++] = CharOf(0xC0 + (value >> 6));
+ line[count++] = CharOf(0x80 + (value & 0x3F));
+ }
+ return count;
+}
@@ -4001,1 +4027,1 @@
- Char line[6];
+ Char line[9]; /* \e [ > M Pb Pxh Pxl Pyh Pyl */
@@ -4021,2 +4047,0 @@
- else if (row > MOUSE_LIMIT)
- row = MOUSE_LIMIT;
@@ -4028,1 +4052,5 @@
- else if (col > MOUSE_LIMIT)
+
+ /* Limit to representable mouse dimensions */
+ if (row > MOUSE_LIMIT)
+ row = MOUSE_LIMIT;
+ if (col > MOUSE_LIMIT)
@@ -4090,2 +4118,2 @@
- line[count++] = CharOf(' ' + col + 1);
- line[count++] = CharOf(' ' + row + 1);
+ count = EmitMousePosition(line, count, col);
+ count = EmitMousePosition(line, count, row);
希望这个补丁(或类似的补丁)将出现在未来版本的xterm中……该补丁使xterm可以直接与emacs-23配合使用(它假定为utf-8输入),并且还修复了xt-mouse.el的现有问题。要在emacs-22中使用它,需要重新定义用于解码鼠标位置的函数(新定义也可在emacs-23中正常使用):(defadvice xterm-mouse-event-read (around utf-8 compile activate)
(setq ad-return-value
(let ((c (read-char)))
(cond
;; mouse clicks outside the encodable range produce 0
((= c 0) #x800)
;; must convert UTF-8 to unicode ourselves
((and (>= c #xC2) (< emacs-major-version 23))
(logior (lsh (logand c #x1F) 6) (logand (read-char) #x3F)))
;; normal case
(c) ) )))
将defun作为.emacs的一部分在您登录的所有计算机上进行分发,并在任何您工作的计算机上打补丁xterm。大功告成!
警告:使用xterm鼠标模式但不把其输入视为utf-8的应用程序会因此补丁而混乱,因为鼠标转义序列变得更长了。但是,这些应用程序在当前的xterm中也会因x > 95的鼠标位置看起来像utf-8代码而导致糟糕的错误。我会为xterm创建一个新的鼠标模式,但某些应用程序(gnu screen!)会过滤未知的转义序列。Emacs是我使用的唯一终端鼠标应用程序,所以我认为该补丁是净赢家,但您的情况可能有所不同。