13

简短版:当使用 emacs 的 xterm-mouse-mode 时,Somebody (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 位置加一,因为 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 !

取而代之的是 emacs 报告(对于任何 col > 223)

ESC [ M SPC C-@ ! ESC [ M # C-@ !

我怀疑 Unicode/UTF-8 支持是罪魁祸首。一些挖掘表明,Unicode 标准允许 C0 和 C1 序列作为 UTF-8 的一部分,直到 Nov 2000,我猜有人没有得到备忘录(幸运的是)。但是,\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 的现有问题。埃尔也。要将它与 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 屏幕!)会过滤掉未知的转义序列。Emacs 是我使用的唯一终端鼠标应用程序,因此我认为该补丁是净胜,但 YMMV。

4

4 回答 4

5

xterm-262添加了上面内联的补丁,但是,这个补丁完全被设计破坏了。Rxvt-unicode的开发人员意识到了这一点,并添加了另一个更好的扩展来报告鼠标坐标。

现在,我正在努力获得对此的广泛支持。Rxvt-unicode并且iTerm2已经支持这两个扩展。xterm我为(以支持urxvt扩展)和为和gnome-terminal为新的扩展创建了补丁。至于应用程序,我添加了对.konsoleputtyurxvtMidnight Commander

请和我一起努力,并尝试说服更多的终端开发人员和应用程序实现这些扩展(至少urxvt一个,因为另一个不能被应用程序正确自动识别)。

请参阅http://www.midnight-commander.org/ticket/2662了解技术细节和进一步的指示。

于 2011-11-08T08:38:57.120 回答
4

好的,想通了。其实有两个问题。

首先,一些源代码显示 xterm 将窗口的鼠标启用区域剪辑为 223x223 个字符,并为所有其他位置发送 0x0。

其次,emacs-23 支持 UTF-8,并且会被 x>160 和 y>94 的鼠标事件弄糊涂;在这些情况下,xterm 对 x 和 y 的编码看起来像一个两字节的 UTF-8 字符(例如 0xC2 0x80),因此鼠标序列似乎短了一个字符。

我正在为 xterm 开发一个补丁,以使鼠标事件发出 UTF-8(这既可以使 emacs-23 混淆,也可以允许终端最大为 2047x2047),但我还不确定结果如何。

于 2010-08-16T10:09:46.367 回答
2

我认为导致您的解决方法(以及 v22 版本之一中包含的上游修复)在 23.2 中停止工作的问题是 Emacs 本身。23.1 可以使用 urxvt、gnu screen、putty 或 iTerm 处理第 95 列之后的鼠标点击,但 23.2 不能。将所有内容设置为 latin-1 没有任何区别。23.1 在 xt-mouse.el 中有相同的代码。然而, src/lread.c 和 src/character.h 发生了变化,乍一看我猜这个错误就在某个地方。至于第 223 列之后会发生什么,我不知道。

为了其他对 23.2 中的 xt-mouse 回归感到恼火的人的利益,这里是 xterm-mouse-event-read 的修改版本,它适用于高达 222 列的鼠标点击(感谢 Ryan 的 >222 溢出处理,我原来的缺少修复)。这可能不适用于 23.1 或更早版本。

(defun xterm-mouse-event-read ()
  (let ((c (read-char)))
    (cond ((= c 0) #x100)  
       ; for positions past col 222 emacs just delivers
       ; 0x0, best we can do is stay at eol 
      ((= 0 (logand c (- #x100))) c) 
      ((logand c #xff))))) 

...编辑:这是 Emacs 24 的版本(bzr head)。它在 23.2 到 col 222 中再次工作,但缺少 >222 溢出 eol 处理 Ryan 建议:

(defun xterm-mouse-event-read ()
  (let ((c (read-char)))
    (if (> c #x3FFF80)
        (+ 128 (- c #x3FFF80))
      c)))
于 2010-08-12T19:48:13.137 回答
1

虽然 xterm 现在在带有补丁的 utf-8 模式下工作,但这个 utf-8 hack 将在任何其他语言环境中以最糟糕的方式破坏,因为除非可表示,否则 unicode 字符将被丢弃。

rxvt-unicode(在 9.09 之后的版本中)具有 1015 模式,使用十进制数发送格式为“ESC [ code ; x ; y M”的回复。这样做的好处是不需要应用程序进行任何探测,并且也可以在非 utf-8 语言环境中工作。

于 2010-11-25T02:45:46.017 回答