--- xt-mouse.new.el 2010-08-27 09:22:47.640625000 +0200 +++ xt-mouse.utf-8.el 2010-08-27 11:02:20.031250000 +0200 @@ -120,16 +120,36 @@ pos) ;; read xterm sequences above ascii 127 (#x7f) -(defun xterm-mouse-event-read () - (let ((c (read-char))) +(defun xterm-mouse-pos-read () + "Read positions from an xterm mouse escape sequence. + +This job is complicated because xterm can emit (px py) pairs +which look like (possibly invalid) UTF-8 sequences which emacs +dutifully decodes into unicode characters. + +UTF-8 sequencing can occur any time px and py are both greater +than #x80. For terminals smaller than 128x128, this function can +correct the problem because only px can trigger the +confusion. Terminals taller than 128 lines pose a more difficult +problem because the py can look like the start of a 2-byte UTF-8 +sequence, and xterm sends no sequence terminator which we could +use to detect the 'EOF'. This tends to leave emacs waiting for +input after mouse-up." + (let* ((c (read-char)) + (b (multibyte-char-to-unibyte c))) (cond ;; mouse clicks outside the encodable range produce 0 - ((= c 0) #x100) - ;; 8-bit control characters which don't pair up with the next - ;; char come back as "pseudo-negative", e.g. #x3fff?? - ((> c #x7ff) (logand c #xff)) + ((eq b 0) (cons #x100 (multibyte-char-to-unibyte (read-char)))) + ;; emacs treats some combinations of px py like utf-8 + ((or + ;; normal ("C2") sequences don't convert back to a single byte + (eq b -1) + ;; illegal ("C0") sequences convert back to one (legal) char + (not (eq c (unibyte-char-to-multibyte b)))) + ;; pick the char apart into two bytes + (cons (+ #xc0 (lsh c -6)) (+ #x80 (logand c #x3f)))) ;; normal case - (c)))) + ((cons b (multibyte-char-to-unibyte (read-char))))))) (defun xterm-mouse-truncate-wrap (f) "Truncate with wrap-around." @@ -148,9 +168,10 @@ (defun xterm-mouse-event () "Convert XTerm mouse event to Emacs mouse event." - (let* ((type (- (xterm-mouse-event-read) #o40)) - (x (- (xterm-mouse-event-read) #o40 1)) - (y (- (xterm-mouse-event-read) #o40 1)) + (let* ((type (- (read-char) #o40)) + (pos (xterm-mouse-pos-read)) + (x (- (car pos) #o40 1)) + (y (- (cdr pos) #o40 1)) ;; Emulate timestamp information. This is accurate enough ;; for default value of mouse-1-click-follows-link (450msec). (timestamp (xterm-mouse-truncate-wrap