+;; Normal terminal mouse click reporting: expect three bytes, of the
+;; form <BUTTON+32> <X+32> <Y+32>. Return a list (EVENT-TYPE X Y).
+(defun xterm-mouse--read-event-sequence-1000 ()
+ (list (let ((code (- (xterm-mouse-event-read) 32)))
+ (intern
+ ;; For buttons > 3, the release-event looks differently
+ ;; (see xc/programs/xterm/button.c, function EditorButton),
+ ;; and come in a release-event only, no down-event.
+ (cond ((>= code 64)
+ (format "mouse-%d" (- code 60)))
+ ((memq code '(8 9 10))
+ (setq xterm-mouse-last code)
+ (format "M-down-mouse-%d" (- code 7)))
+ ((= code 11)
+ (format "M-mouse-%d" (- xterm-mouse-last 7)))
+ ((= code 3)
+ ;; For buttons > 5 xterm only reports a
+ ;; button-release event. Avoid error by mapping
+ ;; them all to mouse-1.
+ (format "mouse-%d" (+ 1 (or xterm-mouse-last 0))))
+ (t
+ (setq xterm-mouse-last code)
+ (format "down-mouse-%d" (+ 1 code))))))
+ ;; x and y coordinates
+ (- (xterm-mouse-event-read) 33)
+ (- (xterm-mouse-event-read) 33)))
+
+;; XTerm's 1006-mode terminal mouse click reporting has the form
+;; <BUTTON> ; <X> ; <Y> <M or m>, where the button and ordinates are
+;; in encoded (decimal) form. Return a list (EVENT-TYPE X Y).
+(defun xterm-mouse--read-event-sequence-1006 ()
+ (let (button-bytes x-bytes y-bytes c)
+ (while (not (eq (setq c (xterm-mouse-event-read)) ?\;))
+ (push c button-bytes))
+ (while (not (eq (setq c (xterm-mouse-event-read)) ?\;))
+ (push c x-bytes))
+ (while (not (memq (setq c (xterm-mouse-event-read)) '(?m ?M)))
+ (push c y-bytes))
+ (list (let* ((code (string-to-number
+ (apply 'string (nreverse button-bytes))))
+ (wheel (>= code 64))
+ (down (and (not wheel)
+ (eq c ?M))))
+ (intern (format "%s%smouse-%d"
+ (cond (wheel "")
+ ((< code 4) "")
+ ((< code 8) "S-")
+ ((< code 12) "M-")
+ ((< code 16) "M-S-")
+ ((< code 20) "C-")
+ ((< code 24) "C-S-")
+ ((< code 28) "C-M-")
+ ((< code 32) "C-M-S-")
+ (t
+ (error "Unexpected escape sequence from XTerm")))
+ (if down "down-" "")
+ (if wheel
+ (- code 60)
+ (1+ (setq xterm-mouse-last (mod code 4)))))))
+ (1- (string-to-number (apply 'string (nreverse x-bytes))))
+ (1- (string-to-number (apply 'string (nreverse y-bytes)))))))
+
+(defun xterm-mouse-event (&optional extension)
+ "Convert XTerm mouse event to Emacs mouse event.
+EXTENSION, if non-nil, means to use an extension to the usual
+terminal mouse protocol; we currently support the value 1006,
+which is the \"1006\" extension implemented in Xterm >= 277."
+ (let* ((click (cond ((null extension)
+ (xterm-mouse--read-event-sequence-1000))
+ ((eq extension 1006)
+ (xterm-mouse--read-event-sequence-1006))
+ (t
+ (error "Unsupported XTerm mouse protocol"))))
+ (type (nth 0 click))
+ (x (nth 1 click))
+ (y (nth 2 click))