(define-key function-key-map "\e[M" 'xterm-mouse-translate)
(defvar xterm-mouse-last)
(defun xterm-mouse-translate (event)
"Read a click and release event from XTerm."
(save-excursion
(save-window-excursion
(deactivate-mark)
(let* ((xterm-mouse-last)
(down (xterm-mouse-event))
(down-command (nth 0 down))
(down-data (nth 1 down))
(down-where (nth 1 down-data))
(down-binding (key-binding (if (symbolp down-where)
(vector down-where down-command)
(vector down-command))))
(is-click (string-match "^mouse" (symbol-name (car down)))))
(unless is-click
(unless (and (eq (read-char) ?\e)
(eq (read-char) ?\[)
(eq (read-char) ?M))
(error "Unexpected escape sequence from XTerm")))
(let* ((click (if is-click down (xterm-mouse-event)))
(click-command (nth 0 click))
(click-data (nth 1 click))
(click-where (nth 1 click-data)))
(if (memq down-binding '(nil ignore))
(if (and (symbolp click-where)
(not (eq 'menu-bar click-where)))
(vector (list click-where click-data) click)
(vector click))
(setq unread-command-events
(if (eq down-where click-where)
(list click)
(list
(list 'mouse-movement click-data)
(if (symbolp down-where)
0
(list (intern (format "drag-mouse-%d"
(+ 1 xterm-mouse-last)))
down-data click-data))
)))
(if (and (symbolp down-where)
(not (eq 'menu-bar down-where)))
(vector (list down-where down-data) down)
(vector down))))))))
(defvar xterm-mouse-x 0
"Position of last xterm mouse event relative to the frame.")
(defvar xterm-mouse-y 0
"Position of last xterm mouse event relative to the frame.")
(defvar xterm-mouse-mode nil)
(defun xterm-mouse-position-function (pos)
"Bound to `mouse-position-function' in XTerm mouse mode."
(setcdr pos (cons xterm-mouse-x xterm-mouse-y))
pos)
(defun xterm-mouse-event ()
"Convert XTerm mouse event to Emacs mouse event."
(let* ((type (- (read-char) #o40))
(x (- (read-char) #o40 1))
(y (- (read-char) #o40 1))
(point (cons x y))
(window (window-at x y))
(where (if window
(coordinates-in-window-p point window)
'menu-bar))
(pos (if (consp where)
(progn
(select-window window)
(goto-char (window-start window))
(move-to-window-line (-
(cdr where)
(if (or header-line-format
default-header-line-format)
1
0)))
(move-to-column (+ (car where) (current-column)
(if (string-match "\\` \\*Minibuf"
(buffer-name))
(- (minibuffer-prompt-width))
0)
(max 0 (1- (window-hscroll)))))
(point))
where))
(mouse (intern
(cond ((>= type 64)
(format "mouse-%d" (- type 60)))
((= type 3)
(format "mouse-%d" (+ 1 xterm-mouse-last)))
(t
(setq xterm-mouse-last type)
(format "down-mouse-%d" (+ 1 type)))))))
(setq xterm-mouse-x x
xterm-mouse-y y)
(list mouse
(list window pos point
(/ (nth 2 (current-time)) 1000)))))
(or (assq 'xterm-mouse-mode minor-mode-alist)
(setq minor-mode-alist
(cons '(xterm-mouse-mode (" Mouse")) minor-mode-alist)))
(defun xterm-mouse-mode (arg)
"Toggle XTerm mouse mode.
With prefix arg, turn XTerm mouse mode on iff arg is positive.
Turn it on to use emacs mouse commands, and off to use xterm mouse commands."
(interactive "P")
(if (or (and (null arg) xterm-mouse-mode)
(<= (prefix-numeric-value arg) 0))
(if xterm-mouse-mode
(progn
(turn-off-xterm-mouse-tracking)
(setq xterm-mouse-mode nil
mouse-position-function nil)
(set-buffer-modified-p (buffer-modified-p))))
(unless (or window-system xterm-mouse-mode)
(setq xterm-mouse-mode t
mouse-position-function #'xterm-mouse-position-function)
(turn-on-xterm-mouse-tracking)
(set-buffer-modified-p (buffer-modified-p)))))
(defun turn-on-xterm-mouse-tracking ()
"Enable Emacs mouse tracking in xterm."
(if xterm-mouse-mode
(send-string-to-terminal "\e[?1000h")))
(defun turn-off-xterm-mouse-tracking ()
"Disable disable Emacs mouse tracking in xterm."
(if xterm-mouse-mode
(send-string-to-terminal "\e[?1000l")))
(add-hook 'suspend-hook 'turn-off-xterm-mouse-tracking)
(add-hook 'suspend-resume-hook 'turn-on-xterm-mouse-tracking)
(add-hook 'kill-emacs-hook 'turn-off-xterm-mouse-tracking)
(provide 'xt-mouse)