Next: , Previous: , Up: キーマップ   [Contents][Index]


23.12 キーバインディングの変更

キーのリバインド(rebind: 再バインド、再束縛)は、キーマップ内でそのキーのバインディングエントリーを変更することによって行われます。グローバルキーマップ内のバインディングを変更すると、その変更は(たとえローカルバインディングによりグローバルバインディングをshadowしているバッファーでは直接影響しないとしても)すべてのバッファーに影響します。カレントバッファーのローカルマップを変更すると、通常は同じメジャーモードを使用するすべてのバッファーに影響します。関数keymap-global-setkeymap-local-setは、これらの操作のための使いやすいインターフェイスです(キーのバインドのためのコマンドを参照)。より汎用的な関数keymap-setを使用することもできます。その場合には変更するマップを明示的に指定しなければなりません。

Lispプログラムでリバインドするキーシーケンスを選択するときは、さまざまなキーの使用についてのEmacsの慣習にしたがってください(キーバインディング規約を参照)。

以下の関数はkeymapがキーマップではない、あるいはkeyが有効なキーでなければエラーをシグナルします。

keyは単一のキーを表す文字列、あるいは一連のキーストロークであり、key-valid-pを満足しなければなりません。キーストロークは1つのスペース文字によって区切られています。

キーストロークはそれぞれ単一の文字、あるいは山カッコ(angle brackets)で括られたイベント名です。更にすべてのキーストロークにたいして1つ以上の修飾キーが前置されているかもしれません。最後に数は限られますが特別な短縮構文をもつ文字があります。以下に例としてキーシーケンスの例を示します:

f

キーのf

S o m

Somの3文字からなるキーシーケンス。

C-c o

controlで修飾されたキーc、その後にキーo

H-<left>

hyperで修飾されたleftという名前のキー。

M-RET

metaで修飾されたreturnキー。

C-M-<space>

controlとmetaで修飾されたspaceキー。

特別な短縮構文をもつキーはNULRETTABLFDESCSPCDELだけです。

修飾キーは‘Alt-Control-Hyper-Meta-Shift-super’、すなわち‘A-C-H-M-S-s’のアルファベット順に指定する必要があります。

Function: keymap-set keymap key binding

この関数はkeymap内でkeyにたいするバインディングをセットする(keyが長さ2以上のイベントなら、その変更は実際はkeymapから辿られる他のキーマップで行なわれる)。引数bindingには任意のLispオブジェクトを指定できるが、意味があるのは特定のオブジェクトだけである(意味のある型のリストはキーの照合を参照)。keymap-setのリターン値はbindingである。

key<t>なら、それはkeymap内でデフォルトバインディングをセットする。イベントが自身のバインディングをもたないとき、そのキーマップ内にデフォルトバインディングが存在すればEmacsコマンドループはそれを使用する。

keyのすべてのプレフィクスはプレフィクスキー(キーマップにバインドされる)か未定義のいずれかでなけらばならず、それ以外ならエラーがシグナルされる。keyのいくつかのプレフィクスが未定義ならkeymap-setはそれをプレフィクスキーとして定義するので、残りのkeyは指定されたように定義できる。

前にkeymap内でkeyにたいするバインディングが存在しなければ、新たなバインディングがkeymapの先頭に追加される。キーマップ内のバインディングの順序はキーボード入力にたいし影響を与えないが、メニューキーマップにたいしては問題となる(メニューキーアップを参照)。

Function: keymap-unset keymap key &optional remove

これはkeymap-setの逆バージョンの関数。keymap内のkeyのバインディングを解除(unset)する(nilにセットするのと同じ)。バインディングを完全に削除する場合には、removeに非nilを指定すればよい。これに違いが生じるのは、keymapに親キーマップがある場合のみ。子マップでキーのバインディングを解除しただけでは、依然としてそれが親マップの同じキーをシャドーし続けるだろう。removeを使うことによって、親キーマップのキーが用いられることになる。

注意: removeに非nilを指定してのkeymap-unsetの使用は、ユーザーがinitファイルに記述する場合を想定したものです。Emacsパッケージは他のパッケージのキーマップを変更するべきではなく、いずれにせよ自身のキーマップにたいして完全な制御を有しているので、可能であれば使用を避けてください。

以下はsparseキーマップを作成してその中にバインディングをいくつか作成する例:

(setq map (make-sparse-keymap))
    ⇒ (keymap)
(keymap-set map "C-f" 'forward-char)
    ⇒ forward-char
map
    ⇒ (keymap (6 . forward-char))

;; C-xにたいしsparseサブマップを作成して
;; その中でfをバインドする
(keymap-set map "C-x f" 'forward-word)
    ⇒ forward-word
map
⇒ (keymap
    (24 keymap                ; C-x
        (102 . forward-word)) ;      f
    (6 . forward-char))       ; C-f

;; C-pctl-x-mapにバインド
(keymap-set map "C-p" ctl-x-map)
;; ctl-x-map
⇒ [nil … find-file … backward-kill-sentence]

;; ctl-x-map内でC-ffooにバインド
(keymap-set map "C-p C-f" 'foo)
⇒ 'foo
map
⇒ (keymap     ; ctl-x-map内のfooに注目
    (16 keymap [nil … foo … backward-kill-sentence])
    (24 keymap
        (102 . forward-word))
    (6 . forward-char))

C-p C-fにたいする新たなバインディングの格納は、実際にはctl-x-map内のエントリーを変更することによって機能し、これはデフォルトグローバルマップ内のC-p C-fC-x C-fの両方のバインディングを変更する効果をもつことに注意。

一般的にキーマップ内でキーを定義する際に主に作業を担うのがkeymap-setです。ただしモードを記述する際には一度に大量のキーのバインドを要することが多々あり、それらすべてにたいしてkeymap-setを使うのは煩雑ですし、エラーも起こりやすくなります。かわりにdefine-keymapを使えばキーマップを作成して複数のキーのバインドを行うことができます。詳細についてははキーマップの作成を参照してください。

関数substitute-key-definitionはキーマップから特定のバインディングをもつキーをスキャンして、それらを異なるバインディングにリバインドする。より明快かつ多くの場合には同じ結果を生成できる他の機能として、あるコマンドから別のコマンドへのリマップがある(コマンドのリマップを参照)。

Function: substitute-key-definition olddef newdef keymap &optional oldmap

この関数はkeymap内でolddefにバインドされるすべてのキーについてolddefnewdefに置き換える。言い換えるとolddefが出現する箇所のすべてをnewdefに置き換える。この関数はnilをリターンする。

たとえば以下をEmacsの標準バインディングで行うとC-x C-fを再定義する:

(substitute-key-definition
 'find-file 'find-file-read-only (current-global-map))

oldmapが非nilなら、どのキーをリバインドするかをoldmap内のバインディングが決定するようにsubstitute-key-definitionの動作を変更する。リバインディングは依然としてoldmapではなくkeymapで発生する。したがって他のマップ内のバインディングの制御下でマップを変更することができる。たとえば、

(substitute-key-definition
  'delete-backward-char 'my-funny-delete
  my-map global-map)

これは標準的な削除コマンドにグローバルにバインドされたキーにたいしてmy-map内の特別な削除コマンドを設定する。

以下はキーマップの置き換え(substitution)の前後を示した例:

(setq map (list 'keymap
                (cons ?1 olddef-1)
                (cons ?2 olddef-2)
                (cons ?3 olddef-1)))
⇒ (keymap (49 . olddef-1) (50 . olddef-2) (51 . olddef-1))

(substitute-key-definition 'olddef-1 'newdef map)
⇒ nil
map
⇒ (keymap (49 . newdef) (50 . olddef-2) (51 . newdef))
Function: suppress-keymap keymap &optional nodigits

この関数はself-insert-commandをコマンドundefinedにリマップ(コマンドのリマップを参照)することによってfullキーマップのコンテンツを変更する。これはすべてのプリント文字を未定義にする効果をもつので、通常のテキスト挿入は不可能になる。suppress-keymapnilをリターンする。

nodigitsnilなら、suppress-keymapは数字がdigit-argument-negative-argumentを実行するように定義する。それ以外は残りのプリント文字と同じように、それらの文字も未定義にする。

suppress-keymap関数はyankquoted-insertのようなコマンドを抑制(suppress)しないのでバッファーの変更は可能。バッファーの変更を防ぐには、バッファーを読み取り専用(read-only)にすること(読み取り専用のバッファーを参照)。

この関数はkeymapを変更するので、通常は新たに作成したキーマップにたいして使用するだろう。他の目的のために使用されている既存のキーマップに操作を行うと恐らくトラブルの原因となる。たとえばglobal-mapの抑制はEmacsをほとんど使用不可能にするだろう。

この関数はテキストの挿入が望ましくないメジャーモードの、ローカルキーマップ初期化に使用され得る。しかしそのようなモードは通常はspecial-mode (基本的なメジャーモードを参照)から継承される。この場合にはそのモードのキーマップは既に抑制済みのspecial-mode-mapから自動的に受け継がれる。以下にspecial-mode-mapが定義される方法を示す:

(defvar special-mode-map
  (let ((map (make-sparse-keymap)))
    (suppress-keymap map)
    (keymap-set map "q" 'quit-window)
    …
    map))

Next: 低レベルなキーバインディング, Previous: キー照合のための関数, Up: キーマップ   [Contents][Index]