aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Stephani2016-03-25 13:17:38 +0300
committerEli Zaretskii2016-03-25 13:17:38 +0300
commit90fb9b38dd4a386a71cdf7c3bf6b42292db43c42 (patch)
tree4ebbe0a89215012e8519b5ec580a014d293ac920
parentf14d463661f46f614125f88b56d73106fab9ece6 (diff)
downloademacs-90fb9b38dd4a386a71cdf7c3bf6b42292db43c42.tar.gz
emacs-90fb9b38dd4a386a71cdf7c3bf6b42292db43c42.zip
Add customization option for using UTF-8 coordinates in xt-mouse
* lisp/xt-mouse.el (xterm-mouse-utf-8): New customization option. (xterm-mouse--read-coordinate): New function to replace `xterm-mouse--read-utf8-char'; uses UTF-8 only if enabled. (xterm-mouse--read-number-from-terminal): Adapt to new name. (xterm-mouse-tracking-enable-sequence) (xterm-mouse-tracking-disable-sequence): Replace constants with functions, mark constants as obsolete. (xterm-mouse--tracking-sequence): New helper function. (turn-on-xterm-mouse-tracking-on-terminal): Use new functions; enable UTF-8 only if customization option says so; store UTF-8 flag in terminal parameter. (Bug#23009) * test/automated/xt-mouse-tests.el: Add tests for xt-mouse.el.
-rw-r--r--lisp/xt-mouse.el128
-rw-r--r--test/automated/xt-mouse-tests.el110
2 files changed, 208 insertions, 30 deletions
diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
index 5975e60272f..b6738b21cb0 100644
--- a/lisp/xt-mouse.el
+++ b/lisp/xt-mouse.el
@@ -134,23 +134,34 @@ http://invisible-island.net/xterm/ctlseqs/ctlseqs.html)."
134 (fdiff (- f (* 1.0 maxwrap dbig)))) 134 (fdiff (- f (* 1.0 maxwrap dbig))))
135 (+ (truncate fdiff) (* maxwrap dbig)))))) 135 (+ (truncate fdiff) (* maxwrap dbig))))))
136 136
137(defun xterm-mouse--read-utf8-char (&optional prompt seconds) 137(defcustom xterm-mouse-utf-8 nil
138 "Read an utf-8 encoded character from the current terminal. 138 "Non-nil if UTF-8 coordinates should be used to read mouse coordinates.
139This function reads and returns an utf-8 encoded character of 139Set this to non-nil if you are sure that your terminal
140command input. If the user generates an event which is not a 140understands UTF-8 coordinates, but not SGR coordinates."
141character (i.e., a mouse click or function key event), read-char 141 :type 'boolean
142signals an error. 142 :risky t
143 143 :group 'xterm)
144The returned event may come directly from the user, or from a 144
145keyboard macro. It is not decoded by the keyboard's input coding 145(defun xterm-mouse--read-coordinate ()
146system and always treated with an utf-8 input encoding. 146 "Read a mouse coordinate from the current terminal.
147 147If `xterm-mouse-utf-8' was non-nil when
148The optional arguments PROMPT and SECONDS work like in 148`turn-on-xterm-mouse-tracking-on-terminal' was called, reads the
149`read-event'." 149coordinate as an UTF-8 code unit sequence; otherwise, reads a
150 (let ((tmp (keyboard-coding-system))) 150single byte."
151 (set-keyboard-coding-system 'utf-8) 151 (let ((previous-keyboard-coding-system (keyboard-coding-system)))
152 (prog1 (read-event prompt t seconds) 152 (unwind-protect
153 (set-keyboard-coding-system tmp)))) 153 (progn
154 (set-keyboard-coding-system
155 (if (terminal-parameter nil 'xterm-mouse-utf-8)
156 'utf-8-unix
157 ;; Use Latin-1 instead of no-conversion to avoid flicker
158 ;; due to `set-keyboard-coding-system' changing the meta
159 ;; mode.
160 'latin-1))
161 ;; Wait only a little; we assume that the entire escape sequence
162 ;; has already been sent when this function is called.
163 (read-char nil nil 0.1))
164 (set-keyboard-coding-system previous-keyboard-coding-system))))
154 165
155;; In default mode, each numeric parameter of XTerm's mouse report is 166;; In default mode, each numeric parameter of XTerm's mouse report is
156;; a single char, possibly encoded as utf-8. The actual numeric 167;; a single char, possibly encoded as utf-8. The actual numeric
@@ -170,7 +181,7 @@ The optional arguments PROMPT and SECONDS work like in
170 (<= ?0 c ?9)) 181 (<= ?0 c ?9))
171 (setq n (+ (* 10 n) c (- ?0)))) 182 (setq n (+ (* 10 n) c (- ?0))))
172 (cons n c)) 183 (cons n c))
173 (cons (- (setq c (xterm-mouse--read-utf8-char)) 32) c)))) 184 (cons (- (setq c (xterm-mouse--read-coordinate)) 32) c))))
174 185
175;; XTerm reports mouse events as 186;; XTerm reports mouse events as
176;; <EVENT-CODE> <X> <Y> in default mode, and 187;; <EVENT-CODE> <X> <Y> in default mode, and
@@ -314,6 +325,38 @@ down the SHIFT key while pressing the mouse button."
314 (mapc #'turn-off-xterm-mouse-tracking-on-terminal (terminal-list)) 325 (mapc #'turn-off-xterm-mouse-tracking-on-terminal (terminal-list))
315 (setq mouse-position-function nil))) 326 (setq mouse-position-function nil)))
316 327
328(defun xterm-mouse-tracking-enable-sequence ()
329 "Return a control sequence to enable XTerm mouse tracking.
330The returned control sequence enables basic mouse tracking, mouse
331motion events and finally extended tracking on terminals that
332support it. The following escape sequences are understood by
333modern xterms:
334
335\"\\e[?1000h\" \"Basic mouse mode\": Enables reports for mouse
336 clicks. There is a limit to the maximum row/column
337 position (<= 223), which can be reported in this
338 basic mode.
339
340\"\\e[?1002h\" \"Mouse motion mode\": Enables reports for mouse
341 motion events during dragging operations.
342
343\"\\e[?1005h\" \"UTF-8 coordinate extension\": Enables an
344 extension to the basic mouse mode, which uses UTF-8
345 characters to overcome the 223 row/column limit.
346 This extension may conflict with non UTF-8
347 applications or non UTF-8 locales. It is only
348 enabled when the option `xterm-mouse-utf-8' is
349 non-nil.
350
351\"\\e[?1006h\" \"SGR coordinate extension\": Enables a newer
352 alternative extension to the basic mouse mode, which
353 overcomes the 223 row/column limit without the
354 drawbacks of the UTF-8 coordinate extension.
355
356The two extension modes are mutually exclusive, where the last
357given escape sequence takes precedence over the former."
358 (apply #'concat (xterm-mouse--tracking-sequence ?h)))
359
317(defconst xterm-mouse-tracking-enable-sequence 360(defconst xterm-mouse-tracking-enable-sequence
318 "\e[?1000h\e[?1002h\e[?1005h\e[?1006h" 361 "\e[?1000h\e[?1002h\e[?1005h\e[?1006h"
319 "Control sequence to enable xterm mouse tracking. 362 "Control sequence to enable xterm mouse tracking.
@@ -343,10 +386,34 @@ escape sequences are understood by modern xterms:
343The two extension modes are mutually exclusive, where the last 386The two extension modes are mutually exclusive, where the last
344given escape sequence takes precedence over the former.") 387given escape sequence takes precedence over the former.")
345 388
389(make-obsolete-variable
390 'xterm-mouse-tracking-enable-sequence
391 "use the function `xterm-mouse-tracking-enable-sequence' instead."
392 "25.1")
393
394(defun xterm-mouse-tracking-disable-sequence ()
395 "Return a control sequence to disable XTerm mouse tracking.
396The control sequence resets the modes set by
397`xterm-mouse-tracking-enable-sequence'."
398 (apply #'concat (nreverse (xterm-mouse--tracking-sequence ?l))))
399
346(defconst xterm-mouse-tracking-disable-sequence 400(defconst xterm-mouse-tracking-disable-sequence
347 "\e[?1006l\e[?1005l\e[?1002l\e[?1000l" 401 "\e[?1006l\e[?1005l\e[?1002l\e[?1000l"
348 "Reset the modes set by `xterm-mouse-tracking-enable-sequence'.") 402 "Reset the modes set by `xterm-mouse-tracking-enable-sequence'.")
349 403
404(make-obsolete-variable
405 'xterm-mouse-tracking-disable-sequence
406 "use the function `xterm-mouse-tracking-disable-sequence' instead."
407 "25.1")
408
409(defun xterm-mouse--tracking-sequence (suffix)
410 "Return a control sequence to enable or disable mouse tracking.
411SUFFIX is the last character of each escape sequence (?h to
412enable, ?l to disable)."
413 (mapcar
414 (lambda (code) (format "\e[?%d%c" code suffix))
415 `(1000 1002 ,@(when xterm-mouse-utf-8 '(1005)) 1006)))
416
350(defun turn-on-xterm-mouse-tracking-on-terminal (&optional terminal) 417(defun turn-on-xterm-mouse-tracking-on-terminal (&optional terminal)
351 "Enable xterm mouse tracking on TERMINAL." 418 "Enable xterm mouse tracking on TERMINAL."
352 (when (and xterm-mouse-mode (eq t (terminal-live-p terminal)) 419 (when (and xterm-mouse-mode (eq t (terminal-live-p terminal))
@@ -360,18 +427,19 @@ given escape sequence takes precedence over the former.")
360 (with-selected-frame (car (frames-on-display-list terminal)) 427 (with-selected-frame (car (frames-on-display-list terminal))
361 (define-key input-decode-map "\e[M" 'xterm-mouse-translate) 428 (define-key input-decode-map "\e[M" 'xterm-mouse-translate)
362 (define-key input-decode-map "\e[<" 'xterm-mouse-translate-extended)) 429 (define-key input-decode-map "\e[<" 'xterm-mouse-translate-extended))
363 (condition-case err 430 (let ((enable (xterm-mouse-tracking-enable-sequence))
364 (send-string-to-terminal xterm-mouse-tracking-enable-sequence 431 (disable (xterm-mouse-tracking-disable-sequence)))
365 terminal) 432 (condition-case err
366 ;; FIXME: This should use a dedicated error signal. 433 (send-string-to-terminal enable terminal)
367 (error (if (equal (cadr err) "Terminal is currently suspended") 434 ;; FIXME: This should use a dedicated error signal.
368 nil ;The sequence will be sent upon resume. 435 (error (if (equal (cadr err) "Terminal is currently suspended")
369 (signal (car err) (cdr err))))) 436 nil ; The sequence will be sent upon resume.
370 (push xterm-mouse-tracking-enable-sequence 437 (signal (car err) (cdr err)))))
371 (terminal-parameter nil 'tty-mode-set-strings)) 438 (push enable (terminal-parameter nil 'tty-mode-set-strings))
372 (push xterm-mouse-tracking-disable-sequence 439 (push disable (terminal-parameter nil 'tty-mode-reset-strings))
373 (terminal-parameter nil 'tty-mode-reset-strings)) 440 (set-terminal-parameter terminal 'xterm-mouse-mode t)
374 (set-terminal-parameter terminal 'xterm-mouse-mode t)))) 441 (set-terminal-parameter terminal 'xterm-mouse-utf-8
442 xterm-mouse-utf-8)))))
375 443
376(defun turn-off-xterm-mouse-tracking-on-terminal (terminal) 444(defun turn-off-xterm-mouse-tracking-on-terminal (terminal)
377 "Disable xterm mouse tracking on TERMINAL." 445 "Disable xterm mouse tracking on TERMINAL."
diff --git a/test/automated/xt-mouse-tests.el b/test/automated/xt-mouse-tests.el
new file mode 100644
index 00000000000..c7e835c0311
--- /dev/null
+++ b/test/automated/xt-mouse-tests.el
@@ -0,0 +1,110 @@
1;;; xt-mouse-tests.el --- Test suite for xt-mouse. -*- lexical-binding: t; -*-
2
3;; Copyright (C) 2016 Free Software Foundation, Inc.
4
5;; Author: Philipp Stephani <phst@google.com>
6
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software: you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation, either version 3 of the License, or
12;; (at your option) any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
21
22;;; Commentary:
23
24;;; Code:
25
26(require 'xt-mouse)
27
28(defmacro with-xterm-mouse-mode (&rest body)
29 "Run BODY with `xterm-mouse-mode' temporarily enabled."
30 (declare (indent 0))
31 ;; Make the frame huge so that the test input events below don't hit
32 ;; the menu bar.
33 `(cl-letf (((frame-width nil) 2000)
34 ((frame-height nil) 2000)
35 ;; Reset XTerm parameters so that the tests don't get
36 ;; confused.
37 ((terminal-parameter nil 'xterm-mouse-x) nil)
38 ((terminal-parameter nil 'xterm-mouse-y) nil)
39 ((terminal-parameter nil 'xterm-mouse-last-down) nil)
40 ((terminal-parameter nil 'xterm-mouse-last-click) nil))
41 (if xterm-mouse-mode
42 (progn ,@body)
43 (unwind-protect
44 (progn
45 ;; `xterm-mouse-mode' doesn't work in the initial
46 ;; terminal. Since we can't create a second terminal in
47 ;; batch mode, fake it temporarily.
48 (cl-letf (((symbol-function 'terminal-name)
49 (lambda (&optional _terminal) "fake-terminal")))
50 (xterm-mouse-mode))
51 ,@body)
52 (xterm-mouse-mode 0)))))
53
54(ert-deftest xt-mouse-tracking-basic ()
55 (should (equal (xterm-mouse-tracking-enable-sequence)
56 "\e[?1000h\e[?1002h\e[?1006h"))
57 (should (equal (xterm-mouse-tracking-disable-sequence)
58 "\e[?1006l\e[?1002l\e[?1000l"))
59 (with-xterm-mouse-mode
60 (should xterm-mouse-mode)
61 (should (terminal-parameter nil 'xterm-mouse-mode))
62 (should-not (terminal-parameter nil 'xterm-mouse-utf-8))
63 (let* ((unread-command-events (append "\e[M%\xD9\x81"
64 "\e[M'\xD9\x81" nil))
65 (key (read-key)))
66 (should (consp key))
67 (cl-destructuring-bind (event-type position . rest) key
68 (should (equal event-type 'S-mouse-2))
69 (should (consp position))
70 (cl-destructuring-bind (_ _ xy . rest) position
71 (should (equal xy '(184 . 95))))))))
72
73(ert-deftest xt-mouse-tracking-utf-8 ()
74 (let ((xterm-mouse-utf-8 t))
75 (should (equal (xterm-mouse-tracking-enable-sequence)
76 "\e[?1000h\e[?1002h\e[?1005h\e[?1006h"))
77 (should (equal (xterm-mouse-tracking-disable-sequence)
78 "\e[?1006l\e[?1005l\e[?1002l\e[?1000l"))
79 (with-xterm-mouse-mode
80 (should xterm-mouse-mode)
81 (should (terminal-parameter nil 'xterm-mouse-mode))
82 (should (terminal-parameter nil 'xterm-mouse-utf-8))
83 ;; The keyboard driver doesn't decode bytes in
84 ;; `unread-command-events'.
85 (let* ((unread-command-events (append "\e[M%\u0640\u0131"
86 "\e[M'\u0640\u0131" nil))
87 (key (read-key)))
88 (should (consp key))
89 (cl-destructuring-bind (event-type position . rest) key
90 (should (equal event-type 'S-mouse-2))
91 (should (consp position))
92 (cl-destructuring-bind (_ _ xy . rest) position
93 (should (equal xy '(1567 . 271)))))))))
94
95(ert-deftest xt-mouse-tracking-sgr ()
96 (with-xterm-mouse-mode
97 (should xterm-mouse-mode)
98 (should (terminal-parameter nil 'xterm-mouse-mode))
99 (should-not (terminal-parameter nil 'xterm-mouse-utf-8))
100 (let* ((unread-command-events (append "\e[<5;1569;273;M"
101 "\e[<5;1569;273;m" nil))
102 (key (read-key)))
103 (should (consp key))
104 (cl-destructuring-bind (event-type position . rest) key
105 (should (equal event-type 'S-mouse-2))
106 (should (consp position))
107 (cl-destructuring-bind (_ _ xy . rest) position
108 (should (equal xy '(1568 . 271))))))))
109
110;;; xt-mouse-tests.el ends here