Emacsでマウスを有効活用する方法

Emacs使いというと、どうしてもキーボード操作に偏ってしまい、マウス操作がないがしろにされている気がします。 Emacsでもマウス操作はそこそこできるのです。 マウスを有効に使っていますか?

Emacsインクリメンタルサーチが強力なので、目についた場所へ一瞬でジャンプできます。 しかし、文章を読む場合に目についた単語や範囲についてコマンドを実行する場合はマウスが優勢です。

そこで、マウスにコマンドを割り当てる方法ついて少し解説してみます。

マウスイベントのシンボル

マウスイベントは「接頭辞-mouse-番号」という形のシンボルで表されます。 接頭辞はないこともあります。 たとえば、mouse-1は左クリックを、double-mouse-3は右ダブルクリックです。

マウスボタンの番号

マウスボタンと番号は以下のような対応になっています。 3以降は環境に依存するかもしれませんが、僕のところではこうなっています。

1
2
3ホイール、または左右同時
4ホイール上
5ホイール下
Emacsが認識できるマウスイベント

Emacsが認識できるマウスイベントは、クリック、ドラッグ、ボタン押し下げ、モーションがあります。 クリックイベントとは、ボタンを押し下げて、その場で離すときに発生します。 ボタンを押し下げてから移動したらドラッグイベントが発生します。 また、ボタンを押し下げた瞬間にボタン押し下げイベントが発生します。 モーションイベントは普段は使いませんのでここでは省略します。

イベント起きるとき左ボタンでのシンボル
クリックボタンを押して、その場で離すときmouse-1
ドラッグボタンを押してからマウスを移動するときdrag-mouse-1
ボタン押し下げボタンを押した瞬間down-mouse-1

また、ダブルクリックやトリプルクリック、ダブルドラッグやトリプルドラッグも扱うことができます。 それぞれ、double-やtriple-という接頭辞をつけます。

マウスを使うコマンドを作成する

マウスを使うコマンドを作成するのは、さほど難しくありません。 通常のコマンドを定義しキーに割り当てる知識の延長線上にあります。

コマンド定義時に(interactive "e")を指定する

マウスを使うコマンドを定義するには、次のような形になります。


(defun function (click)
(interactive "e")
...)

こうすることで、マウスイベントの情報をclickから得ることができます。

マウスでドラッグした範囲を得るには

マウスイベントで欲しい情報の典型は、ドラッグした範囲でしょう。 ドラッグは、ドラッグ開始とドラッグ終了のイベントから成ります。 それぞれ (event-start click) 、 (event-end click) で得られます。 そして、イベントから位置を得るには、posn-point関数を使います。

ドラッグ開始位置(posn-point (event-start click))
ドラッグ終了位置(posn-point (event-end click))
マウスに機能を割り当てる

マウス操作もキー操作同様 global-set-key 関数や define-key 関数で割り当てられます。


;;; 定義例
;; 左クリック
(global-set-key [mouse-1] 'test-click)
;; 左ドラッグ
(global-set-key [drag-mouse-1] 'test-drag-mouse)

デフォルトでは、次のように割り当てられています。

<mouse-1>mouse-set-point
<double-mouse-1>mouse-set-point
<triple-mouse-1>mouse-set-point
<down-mouse-1>mouse-drag-region
<drag-mouse-1>mouse-set-region
<mouse-2>mouse-yank-at-click
<mouse-3>mouse-save-then-kill
<mouse-4>mwheel-scroll
<mouse-5>mwheel-scroll

たとえば、 double-drag-mouse-1 等には割り当てられていません。 マウスで範囲選択をし、それに対応するコマンドを定義するには、 double-drag-mouse-1 等が適しています。

Ctrl、Meta、Shiftと併用することもできます。

<C-down-mouse-1>mouse-buffer-menu
<C-down-mouse-2>facemenu-menu
<C-mouse-4>mwheel-scroll
<C-mouse-5>mwheel-scroll
<M-down-mouse-1>mouse-drag-secondary
<M-drag-mouse-1>mouse-set-secondary
<M-mouse-1>mouse-start-secondary
<M-mouse-2>mouse-yank-secondary
<M-mouse-3>mouse-secondary-save-then-kill
<S-down-mouse-1>mouse-appearance-menu
<S-mouse-3>kmacro-end-call-mouse
<S-mouse-4>mwheel-scroll
<S-mouse-5>mwheel-scroll
マウスイベントテストプログラム

以下のコードは、マウスドラッグイベントのデモンストレーションです。 ドラッグ、ダブルドラッグ、トリプルドラッグを試してみてください。 範囲内のテキストが表示されます。

;; (save-window-excursion (shell-command (format "emacs-test -l test-minimum -l %s %s &" buffer-file-name buffer-file-name)))
(global-set-key [drag-mouse-1] 'test-drag-mouse)
(global-set-key [double-drag-mouse-1] 'test-double-drag-mouse)
(global-set-key [triple-drag-mouse-1] 'test-triple-drag-mouse)
(defun test-drag-mouse (click)
  (interactive "e")
  (mouse-message-region click "test-drag-mouse"))
(defun test-double-drag-mouse (click)
  (interactive "e")
  (mouse-message-region click "test-double-drag-mouse"))
(defun test-triple-drag-mouse (click)
  (interactive "e")
  (mouse-message-region click "test-triple-drag-mouse"))
(defun mouse-message-region (click comment)
  (interactive "e")
  (mouse-set-region click)
  (message "%s\n%s" comment
           (buffer-substring-no-properties
            (posn-point (event-start click)) (posn-point (event-end click)))))

auto-install.elを使うと、以下のコマンドですぐに試すことができます。


M-x install-elisp http://www.rubyist.net/~rubikitch/archive/2010-11-09-110928.mouse.drag.el
マウスで範囲選択した後で元のポイントに戻るには

通常は、マウスドラッグで範囲選択をしたら、その位置にまでカーソルが移動します。 しかし、カーソル位置を復元してほしいときもあります。

そのときは、以下の内容のmouse-excursion.elを利用します。

(eval-when-compile (require 'cl))
(lexical-let (start-point start-window)
  (defun mouse-drag-region-excursion (click)
    (interactive "e")
    (setq start-point (point))
    (setq start-window (selected-window))
    (mouse-drag-region click))
  (defun mouse-funcall-region-excursion (func click)
    (funcall func (posn-point (event-start click))
                  (posn-point (event-end click)))
    (select-window start-window)
    (goto-char start-point)))
(provide 'mouse-excursion)


M-x install-elisp http://www.rubyist.net/~rubikitch/archive/mouse-excursion.el

デモンストレーションは以下の内容です。

;; (save-window-excursion (shell-command (format "emacs-test -l test-minimum -l %s %s &" buffer-file-name buffer-file-name)))
(require 'mouse-excursion)
(global-set-key [down-mouse-1] 'mouse-drag-region-excursion)
(global-set-key [drag-mouse-1] 'test-drag-mouse-excursion)
(defun test-drag-mouse-excursion (click)
  (interactive "e")
  (mouse-message-region-excursion click "test-drag-mouse-excursion"))
(defun mouse-message-region-excursion (click comment)
  (interactive "e")
  (mouse-funcall-region-excursion
   (lambda (s e)
     (message "%s\n%s" comment (buffer-substring-no-properties s e)))
   click))


M-x install-elisp http://www.rubyist.net/~rubikitch/archive/2010-11-09-225132.mouse-excursion.el

左ドラッグで試してみてください。 範囲選択した後でカーソル位置が戻っていることに気付くでしょう。

なお、ダブルドラッグでは動きません。 なぜなら、ダブルドラッグするには一度マウスを離すため、左クリックイベントが発生するからです。 デフォルトでは左クリックイベントは mouse-set-point に割り当てられています。

僕の場合、この機能を使って、範囲内のテキストをメモに放り込みたいと思っています。