xt-mouse.el 6.03 KB
Newer Older
1
;;; xt-mouse.el --- support the mouse when emacs run in an xterm
Erik Naggum's avatar
Erik Naggum committed
2

3
;; Copyright (C) 1994, 2000, 2001, 2005 Free Software Foundation
Richard M. Stallman's avatar
Richard M. Stallman committed
4

Per Abrahamsen's avatar
Per Abrahamsen committed
5
;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
Richard M. Stallman's avatar
Richard M. Stallman committed
6 7
;; Keywords: mouse, terminals

Erik Naggum's avatar
Erik Naggum committed
8 9 10
;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
Richard M. Stallman's avatar
Richard M. Stallman committed
11 12 13
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
Erik Naggum's avatar
Erik Naggum committed
14 15

;; GNU Emacs is distributed in the hope that it will be useful,
Richard M. Stallman's avatar
Richard M. Stallman committed
16 17 18
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
Erik Naggum's avatar
Erik Naggum committed
19

Richard M. Stallman's avatar
Richard M. Stallman committed
20
;; You should have received a copy of the GNU General Public License
Erik Naggum's avatar
Erik Naggum committed
21 22 23
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
Richard M. Stallman's avatar
Richard M. Stallman committed
24

Dave Love's avatar
Dave Love committed
25
;;; Commentary:
Richard M. Stallman's avatar
Richard M. Stallman committed
26

27
;; Enable mouse support when running inside an xterm.
Richard M. Stallman's avatar
Richard M. Stallman committed
28 29 30 31 32 33 34

;; This is actually useful when you are running X11 locally, but is
;; working on remote machine over a modem line or through a gateway.

;; It works by translating xterm escape codes into generic emacs mouse
;; events so it should work with any package that uses the mouse.

Richard M. Stallman's avatar
Richard M. Stallman committed
35 36 37 38
;; You don't have to turn off xterm mode to use the normal xterm mouse
;; functionality, it is still available by holding down the SHIFT key
;; when you press the mouse button.

Richard M. Stallman's avatar
Richard M. Stallman committed
39 40
;;; Todo:

41 42 43
;; The xterm mouse escape codes are supposedly also supported by the
;; Linux console, but I have not been able to verify this.

Richard M. Stallman's avatar
Richard M. Stallman committed
44 45
;; Support multi-click -- somehow.

Dave Love's avatar
Dave Love committed
46
;;; Code:
Richard M. Stallman's avatar
Richard M. Stallman committed
47 48 49

(define-key function-key-map "\e[M" 'xterm-mouse-translate)

50 51
(defvar xterm-mouse-last)

52 53 54 55 56
;; Mouse events symbols must have an 'event-kind property with
;; the value 'mouse-click.
(dolist (event-type '(mouse-1 mouse-2 mouse-3))
  (put event-type 'event-kind 'mouse-click))

Richard M. Stallman's avatar
Richard M. Stallman committed
57
(defun xterm-mouse-translate (event)
Dave Love's avatar
Dave Love committed
58
  "Read a click and release event from XTerm."
Richard M. Stallman's avatar
Richard M. Stallman committed
59 60 61
  (save-excursion
    (save-window-excursion
      (deactivate-mark)
62
      (let* ((xterm-mouse-last)
63 64 65 66 67 68
	     (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)
69 70
					  (vector down-command))))
	     (is-click (string-match "^mouse" (symbol-name (car down)))))
71

72 73 74 75 76 77 78
	(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)))
79 80 81 82 83
	       (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)
84
		       (consp click-where))
85 86 87 88 89 90 91 92 93 94 95
		  (vector (list click-where click-data) click)
		(vector click))
	    (setq unread-command-events
		  (if (eq down-where click-where)
		      (list click)
		    (list
		     ;; Cheat `mouse-drag-region' with move event.
		     (list 'mouse-movement click-data)
		     ;; Generate a drag event.
		     (if (symbolp down-where)
			 0
Dave Love's avatar
Dave Love committed
96 97
		       (list (intern (format "drag-mouse-%d"
					     (+ 1 xterm-mouse-last)))
98
			     down-data click-data)))))
99
	    (if (and (symbolp down-where)
100
		     (consp down-where))
101 102 103 104 105 106 107 108 109
		(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.")

110 111
;; Indicator for the xterm-mouse mode.

Dave Love's avatar
Dave Love committed
112 113 114 115
(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)
Richard M. Stallman's avatar
Richard M. Stallman committed
116

117 118 119 120 121 122 123
;; read xterm sequences above ascii 127 (#x7f)
(defun xterm-mouse-event-read ()
  (let ((c (read-char)))
    (if (< c 0)
        (+ c #x8000000 128)
      c)))

Richard M. Stallman's avatar
Richard M. Stallman committed
124
(defun xterm-mouse-event ()
Dave Love's avatar
Dave Love committed
125
  "Convert XTerm mouse event to Emacs mouse event."
126 127 128
  (let* ((type (- (xterm-mouse-event-read) #o40))
	 (x (- (xterm-mouse-event-read) #o40 1))
	 (y (- (xterm-mouse-event-read) #o40 1))
129
	 (mouse (intern
130 131 132 133 134 135 136 137 138 139
		 ;; For buttons > 3, the release-event looks
		 ;; differently (see xc/programs/xterm/button.c,
		 ;; function EditorButton), and there seems to come in
		 ;; a release-event only, no down-event.
		 (cond ((>= type 64)
			(format "mouse-%d" (- type 60)))
		       ((= type 3)
			(format "mouse-%d" (+ 1 xterm-mouse-last)))
		       (t
			(setq xterm-mouse-last type)
140
			(format "down-mouse-%d" (+ 1 type))))))
141 142 143 144 145
	 (w (window-at x y))
         (ltrb (window-edges w))
         (left (nth 0 ltrb))
         (top (nth 1 ltrb)))

146 147
    (setq xterm-mouse-x x
	  xterm-mouse-y y)
148
    (if w
149
	(list mouse (posn-at-x-y (- x left) (- y top) w t))
150
      (list mouse
151
	    (append (list nil 'menu-bar) (nthcdr 2 (posn-at-x-y x y w t)))))))
Richard M. Stallman's avatar
Richard M. Stallman committed
152 153

;;;###autoload
154
(define-minor-mode xterm-mouse-mode
Richard M. Stallman's avatar
Richard M. Stallman committed
155 156 157 158
  "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."
159
  nil " Mouse" nil :global t
160 161 162 163 164 165 166 167
  (if xterm-mouse-mode
      ;; Turn it on
      (unless window-system
	(setq mouse-position-function #'xterm-mouse-position-function)
	(turn-on-xterm-mouse-tracking))
    ;; Turn it off
    (turn-off-xterm-mouse-tracking 'force)
    (setq mouse-position-function nil)))
Richard M. Stallman's avatar
Richard M. Stallman committed
168 169

(defun turn-on-xterm-mouse-tracking ()
Dave Love's avatar
Dave Love committed
170
  "Enable Emacs mouse tracking in xterm."
Richard M. Stallman's avatar
Richard M. Stallman committed
171 172 173
  (if xterm-mouse-mode
      (send-string-to-terminal "\e[?1000h")))

174
(defun turn-off-xterm-mouse-tracking (&optional force)
175
  "Disable Emacs mouse tracking in xterm."
176
  (if (or force xterm-mouse-mode)
Richard M. Stallman's avatar
Richard M. Stallman committed
177 178 179 180 181 182 183 184 185
      (send-string-to-terminal "\e[?1000l")))

;; Restore normal mouse behaviour outside Emacs.
(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)

Miles Bader's avatar
Miles Bader committed
186
;;; arch-tag: 84962d4e-fae9-4c13-a9d7-ef4925a4ac03
Richard M. Stallman's avatar
Richard M. Stallman committed
187
;;; xt-mouse.el ends here