Краткая версия: при использовании режима emters xterm-mouse, Somebody (emacs? bash? xterm?) перехватывает управляющие последовательности xterm и заменяет их на \0. Это боль на широких мониторах, потому что только первые 223 столбца имеют мышь.
Каков виновник и как я могу его обойти?
Из того, что я могу сказать, это связано с поддержкой Unicode/UTF-8, потому что это была не проблема 5-6 лет назад, когда у меня в последний раз был большой монитор.
Подробности Gory следуют...
Спасибо!
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)
Мы должны добавить одно к заданной x позиции из emacs, потому что позиции в xterm начинаются с одного, а не с нуля. Следовательно, появляется магия x = 95, потому что она кодируется как "\ 300\200" - первое экранированное число. Кто-то (emacs? bash? Xterm?) Относится к тем, кто использует контрольные последовательности "C0" из ISO 2022. Начиная с x = 159, мы переходим к последовательностям "C1" (\ 301\200), которые также являются частью ISO 2022.
Тревога попадает с \302 последовательностями, что соответствует текущему пределу x = 223. Несколько лет назад я смог расшифровать хак для перехвата \302 и\303 последовательностей вручную, которые прошли мимо проблемы. Ускорьте вперед несколько лет, и сегодня я нахожу, что я застрял в x = 223, потому что Somebody заменяет эти последовательности на \0.
Итак, где бы я ожидал нажатия на строку 1, col 250 для создания
ESC [ M SPC \303\207 ! ESC [ M # \303\207 !
Вместо сообщений emacs (для любого col > 223)
ESC [ M SPC [email protected] ! ESC [ M # [email protected] !
Я подозреваю, что поддержка Unicode/UTF-8 является виновником. Некоторые копания показывают, что стандарт Unicode разрешил C0 и C1 последовательности как часть UTF-8 до ноября 2000 года, и я думаю, что кто-то не получил записка (к счастью). Тем не менее, \302\200 -\302\237 Unicode управляющие последовательности, так что кто-то их разрывает (кто-то знает, что с ними! ) и вместо этого возвращает \0.
Некоторые более подробные вопросы:
- Кто это Кто-то, кто перехватывает коды, прежде чем они достигнут буфера потери emacs?
- Если это действительно касается контрольных последовательностей, то почему символы после \302\237, которые являются кодировками UTF-8 печатаемого Юникода, также возвращаются как \0?
- Что заставляет emacs решать, отображать ли потери как символы Unicode или восьмеричные escape-последовательности, и почему не совпадают эти два? Например, мой встроенный cygwin emacs 23.2.1 (xterm 229) сообщает \301\202 для столбца 161, но мои данные, предоставленные мной rhel5.5, 22.3.1 (xterm 215) сообщают "Â" (латинский A с обводным), что на самом деле \303\202 в UTF-8!
Update:
Здесь патч против 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 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, будут путаться этим патчем, потому что escape-последовательности мыши увеличиваются. Тем не менее, эти приложения ломаются ужасно с текущим xterm, потому что позиции мыши с x > 95 выглядят как коды utf-8, но не являются. Я бы создал новый режим мыши для xterm, но некоторые приложения (gnu screen!) Отфильтровывают неизвестные escape-последовательности. Emacs - единственное приложение для мыши-терминала, которое я использую, поэтому считаю патч чистым выигрышем, но YMMV.