キーバインディング - 環境設定のための Emacs Lisp 入門
Emacs Lisp 入門の第 6 回です。
今回はこのキーバインディングの設定について説明します。
キー設定の方針
Emacs ではアルファベットの意味でキーを割り当てているため、 デフォルトのキー配置は人間工学的に押しづらいことが多いです。 しかも、英語キーボードで考えられているため、 "指つるだろ" とツッコミたくなる配置もあります。 キーを自分好みに設定すれば、 Emacs は格段に使いやすくなります。また、押しづらいキーを変更するだけでなく、 compile, eshell などよく使うけど 割り当てのないコマンドに新たに割り当てたり、 自分で作ったコマンド(関数)を割り当てたりといった場合にもキー設定は必要です。
しかし、 Emacs ではほとんどのキーは割り当て済みです。 新たに割り当てるキーは次の内のどちらかになると思います。
- あまり使わなそうなコマンドのキー
- 特殊キーなどで割り当てのないキー
キー | 機能 |
---|---|
C-o | 空行の挿入 |
C-t | カーソル位置の文字の入れ替え |
C-z | フレームの最小化 |
コマンド割り当てのない特殊キーには次のようなものがあります。
- 機能キー
- F1 - F12 など
- GUI でしか使えないキー
- C-;, C-: やキーパッドの数字など
Emacs 共通でのキー設定
Emacs の共通して使うキー設定は global-set-key で行います。(global-set-key KEY COMMAND)
(global-set-key "\C-z" 'undo)引数としてはキー(KEY)と呼び出すコマンド(COMMAND)を渡します。
KEY の設定方法はいろいろあるのですが、基本的に文字列で指定します。 "z" のようにも指定できるのですが、通常は "\C-", "\M-" と組み合わせます。
キー | 意味 |
---|---|
"\C-z" | Ctrl キーを押しながら z を押す。 |
"\M-z" | [Esc] キーを押した後に z を押す。 または Alt キーを押しながら z を押す。 |
COMMAND は呼び出されるコマンドでシンボルとして渡すので、クオートしています。
なお、 この global-set-key は以下の記述の簡易記法です。
(define-key global-map "\C-z" 'undo)
キーの割り当てはキーマップで管理されていて、 define-key でキーマップに割り当てを定義します。
global-map というのが Emacs で基本的に使われているキーマップです。global-map に格納されたキーマップの方を関数に渡すので、キーマップはクオートはしません。
lambda 式
自作のコマンド(関数)を作るのは少し難しそうに感じるかもしれませんが、 簡単なコードでも作れるコマンドはあります。例えば、 compile は引数として文字列を渡すとその文字列を問い合わせることなく、 コンパイルとして実行します。 いつも同じコンパイルをやる場合には便利なのではないでしょうか。
ただ、簡単な関数をいちいち名前を付けて作るのは面倒でもあります。 キーに割り当てるコマンドには無名関数(ラムダ式)で指定することもできます。
(global-set-key "\C-o" '(lambda () (interactive) (compile "MsBuild.exe")))ただし、前回のホックの場合と違い、キーに設定する場合は (interactive) をつけて インタラクティブな関数にしておくのを忘れないようにして下さい。
モードごとのキー設定
前回、ホックを使ったモードごとの設定を説明しました。 モード用のコマンドに対してキー設定する場合には、ホックで呼ぶ関数内で設定します。モードのキーマップは global-map をベースとして各モードで用意されています。 global-set-key では設定できませんし、 define-key で指定するにしても名前は調べないとわかりません。
しかし、 local-set-key を使えば、 呼び出した際に使われているキーマップに対してキーを設定することができます。
(defun my-csharp-mode-init () (local-set-key "{" 'c-electric-brace) ) (add-hook 'csharp-mode-hook 'my-csharp-mode-init)
連続するキー
C-x, C-c キーは特殊で、この後にキーを続けます。 こういったキーはキー指定でも文字列を続けて記述します。(global-set-key "\C-xc" 'compile) (global-set-key "\C-x\C-a" 'tags-search)ただし、 最初のキーがコマンドに割り当てられていると連続しているキーは呼ばれません。 キー割り当てをなくす場合には nil をコマンドとして指定します。
(global-set-key "\C-t" nil) (global-set-key "\C-t\C-c" 'compile)C-xの場合は C-x 後のキーは ctl-x-map というキーマップに割り当てられています。 このため、先ほどの例は次のようにも書けます。
(define-key ctl-x-map "c" 'compile) (define-key ctl-x-map "\C-a" 'tags-search)逆にコマンド指定の部分に ctl-x-map を指定することによって、 C-x を他のキーに割り当てることができます。
以下の例のようにするとC-x C-sで保存だったのが、 C-o C-c でも保存となります。
(global-set-key "\C-o" ctl-x-map)
このようにC-xを別のコマンドにしたい場合は他のキーよりも若干面倒です。
C-c はモードごとに割り当てられるのでもっと面倒です。その割にC-x, C-c は Windows ではカット、コピーでよく使われるので、 割り当てを変えたいことは多いかもしれません。 私は使ったことがないので、あまりお勧めはしませんが、 Windows 風のカット&ペーストのキーに設定する機能(CUA)があります。 これはメニューの [Options] から設定することができます。
キーマップの作成
連続するキーは自分でキーマップを使って、設定することもできます。;; キーマップ作成 (setq my-semicoron-map (make-keymap)) (global-set-key (kbd "C-;") my-semicoron-map) ;; 作成したキーマップへの割り当て (define-key my-semicoron-map "\C-k" 'kill-line) (define-key my-semicoron-map "j" 'goto-line)キーマップの作成は (make-keymap) 関数を使って行います。
連続するキーを指定するとき、 キーマップを作っておいた方が 最初のキーを変えたいという場合などには簡単に変えることができます。
キーの指定
最初の方針で特殊キーや C-: などのキーが空いていると書きました。 しかし、 この特殊キーや Ctrl キーと記号の組み合わせのキーの場合、 文字列では設定できないことがあります。こういった場合には別のキー指定方法を取ります。
ベクター表記
[] を使ったベクター表記で特殊キーや Ctrl + 記号のキー設定ができます。(global-set-key [f7] 'compile) ; F7 (global-set-key [kp-9] 'tags-query-replace) ; キーパットの 9 (global-set-key [?\C-,] 'tags-search) ; Ctrl + ,[] の中に記述する文字は若干わかりづらいです。
"\C-," の前についた ? は文字列にするためのものです。 ?e は C, C++ で言えば 'e' となります。
また、 特殊キーの場合は名前を指定します。 名前は C-h k で推測することができます。
ただし、 C-h k で表示される名前とは少し違います。 ベクター表記よりもキータイプは増えますが、 慣れないうちは次節の kbd を使った方がわかりやすいでしょう。
因みに elisp にはリストだけでなくベクター(配列)もあります。 この [] はベクターにアクセスするための表記です。 ただ、キー指定以外ではほとんど使わないので、 あまり気にする必要はないとは思います。
kbd
kbd を使うと文字列を Emacs のキーの内部表記に変換してくれます。(global-set-key (kbd "<f7>") 'compile) (global-set-key (kbd "<kp-9>") 'tags-query-replace) (global-set-key (kbd "C-,") 'tags-search)この kbd で指定する文字列は C-h k で表示される文字 と同じです。
C-h k でキーの表示文字を調べて設定すれば、大抵のキーには割り当てることができます。
kbd を使って連続するキーを指定する場合には間に空白を入れて続けて書きます。
(global-set-key (kbd "C-; C-k") 'kill-line) (global-set-key (kbd "C-; j") 'goto-line)
マウスの設定
キーの設定ではマウスの挙動の設定もできます。マウスの場合も C-h k の後にマウスの操作をすれば、指定する文字を見ることができます。
;; シフトを押しながらホイールするとゆっくりスクロール (global-set-key (kbd "<S-wheel-down>") '(lambda () (interactive) (scroll-up 1))) (global-set-key (kbd "<S-wheel-up>") '(lambda () (interactive) (scroll-up -1)))
既存の割り当てキーの変更
remap
キーの指定として あるコマンドに割り当てられているキーを指定することができます。 ちょっと拡張したコマンドを既存のキーに割り当てる場合などに使います。
(add-hook 'c++-mode-hook '(lambda ()
(local-set-key [remap newline] 'newline-and-indent)))
上記の例では改行(newline)に割り当てられたキー(<return>)
に改行してインデントするコマンド(newline-and-indent)を割り当てています。
キーマクロ
キー設定関数でコマンドを渡す部分(COMMAND)にキーを指定することもできます。(global-set-key "\C-l" "\C-f")前節の remap では指定したコマンドの割り当てられたキーを探し、そこに別コマンドを割り当てていました。 それに対してこちらはキーマクロです。 C-l を押すと C-f のキーが押されたことをなります。
キー変換
keyboard-translate を使うとモードに関係なく、キー変換を行うことができます。 引数として渡すのはベクター表記の中の文字です。(keyboard-translate ?\C-l ?\C-f) (keyboard-translate ?\C-f ?\C-l)この関数は Emacs の低次元層に働く関数なので、結構強力です。
私のキー設定
私が elisp を調べ始めたのは、 デフォルトのキー配列が使いづらく、自分好みのキー配置にしたいためでした。 ここで参考までに私のキーバインディングを紹介します。まずカーソル移動では、上下は C-p、C-n のままですが、 左右の移動は C-k、C-lにしています。 これでダイヤモンドキー配列とまで行きませんが、なんとなくイメージしやすい形になっています。
ちょっと変わっている点は使わないキーを一つ潰して、コマンドを実行できるようにしている点です。
使わないキーとして "@" にしています。 この @ の後の組み合わせでコマンドを実行します。 例えば、 @ k で kill-line(C-k)、 @ s で保存という感じです。
個人的にはモードの変更無しで、 vi のような操作性を実現できているのではないかと思います。
私のキー配列が使いやすいかどうかはさておき、 言いたかったことはこういったトリッキーなキー操作であろうと自分好みのキー設定が実現できる点です。
そもそもベストなキー配置というのは人それぞれだと思います。 ベストな配置にしたければ、設定を変更する必要があります。 その点、 Emacs のキーカスタマイズの能力は他のエディターの比ではありません。
私のようにあまりやり過ぎると他の Emacs を触れなくなりますが、 Emacs を快適に操作できるように、ぜひ自分なりのキー設定を工夫してみてください。
なお、今回説明した内容だけでは変更できないキー設定もでてくることがあります。 その場合は今回の入門では説明していませんが、マイナーモードの作り方を覚えて下さい。 マイナーモードを使えば大抵のキー設定は可能です。 途中で紹介した CUA の機能もマイナーモードを利用して実現されています。
- 関連記事
-
- リストと連想配列 - 環境設定のための Emacs Lisp 入門
- ファイルのロードとホック - 環境設定のための Emacs Lisp 入門
- キーバインディング - 環境設定のための Emacs Lisp 入門
- 設定に役立つ基本関数 - 環境設定のための Emacs Lisp 入門
- 条件分岐 - 環境設定のための Emacs Lisp 入門
Facebook コメント
コメント