[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21. キーマップ

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Keymaps"
"texi/elisp21/キーマップ"へのコメント(無し)

入力イベントとコマンドとのバインディング(対応)は、 キーマップ(keymap)と呼ばれるデータ構造に記録されています。 キーマップの各バインディング(あるいはバインド(bind))は、 個々のイベント型を別のキーマップかコマンドに対応付けます。 イベント型のバインディングがキーマップであると、 後続の入力イベントを探すためにそのキーマップを使います。 コマンドがみつかるまで、これを繰り返します。 この処理全体をキー探索(key lookup)と呼びます。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.1 キーマップの用語

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Keymap%20Terminology"
"texi/elisp21/キーマップの用語"へのコメント(無し)

キーマップ(keymap)は、イベント型を定義に対応させる表です。 (この定義は任意のLispオブジェクトであるが、 コマンドループによる実行においては、特定の型のみが意味を持つ)。 与えられたイベント(あるいはイベント型)とキーマップから、 Emacsはイベントの定義を得ることができます。 イベントは、文字、ファンクションキー、マウス操作です (see 節 20.5 入力イベント)。

ある単位を構成する入力イベントの列をキー列(key sequence)、 あるいは、略してキー(key)と呼びます。 単一イベントから成る列はつねにキー列であり、複数イベント列もキー列です。

キーマップは、任意のキー列に対するバインディング、 つまり、定義を決定します。 キー列が単一イベントから成るとき、 そのバインディングはキーマップ内の当該イベントの定義です。 複数のイベントから成るキー列のバインディングは、 繰り返し処理で探します。 つまり、最初のイベントのバインディングを探すと、 それはキーマップであるはずです。 続いて、そのキーマップから2番目のイベントのバインディングを探します。 これをキー列のすべてのイベントを使い尽くすまで行います

キー列のバインディングがキーマップであると、 そのキー列をプレフィックスキー(prefix key)と呼びます。 さもなければ、(追加できるイベントがないので) 完全なキー(complete key)と呼びます。 バインディングがnilであると、キーは未定義であるといいます。 プレフィックスキーの例は、C-cC-xC-x 4です。 定義されている完全なキーの例は、XRETC-x 4 C-fです。 未定義な完全なキーの例は、C-x C-gC-c 3です。 詳しくは、See 節 21.5 プレフィックスキー

キー列のバインディングを探す際の規則では、 (最後のイベントのまえまでにみつかる)途中のバインディングは すべてキーマップであると仮定します。 これが満たされないと、イベントの列があるまとまりを構成せず、 1つのキー列になりません。 いいかえれば、有効なキー列の末尾からいくつかのイベントを取りさると、 つねにプレフィックスキーになる必要があります。 たとえば、C-f C-nはキー列ではありません。 C-fはプレフィックスキーではないので、 C-fで始まる列はキー列ではありません。

複数イベントから成るキー列の候補は、 プレフィックスキーのバインディングに依存します。 したがって、キーマップが異なればそれらは異なり、 バインディングを変更するとそれらは変わります。 しかし、単一イベントから成る列は、プレフィックスに依存しないので、 つねにキー列です。

ある時点には、複数個の主キーマップが活性です。 つまり、キーバインディングの探索に使われます。 それらは、 すべてのバッファが共有するグローバルマップ(global map)、 特定のメジャーモードに関連付けられたローカルマップ(local keymap)、 現在オンにしてあるマイナモードに属する マイナモードキーマップ(minor mode keymaps)です。 (すべてのマイナモードにキーマップがあるわけではない。) ローカルキーマップのバインディングは、 対応するグローバルなバインディングを隠します(つまり優先する)。 マイナモードキーマップは、ローカルとグローバルの両方のキーマップを隠します。 詳しくはSee 節 21.6 活性なキーマップ



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.2 キーマップの形式

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Format%20of%20Keymaps"
"texi/elisp21/キーマップの形式"へのコメント(無し)

キーマップは、そのCARがシンボルkeymapであるリストです。 リストの残りの要素がキーマップのキーバインディングを定義します。 オブジェクトがキーマップであるかどうか検査するには、 関数keymapp(下記参照)を使います。

キーマップでは、シンボルkeymapのうしろに、 さまざまな種類の要素が現れます。

(type . binding)
イベント型typeに対する1つのバインディングを指定する。 普通の各バインディングは、文字やシンボルである特定のイベント型に 適用される。 see 節 20.5.12 イベントの分類

(t . binding)
デフォルトのキーバインディングを指定する。 キーマップの他の要素に一致しない任意のイベントには、 そのバインディングとして指定したbindingを与える。 デフォルトのバインディングにより、 すべてを列挙せずに可能なすべてのイベントにバインドできる。 デフォルトのバインディングを有するキーマップは、 任意の低優先順位のキーマップを隠してしまう。

vector
キーマップの要素がベクトルであると、 当該ベクトルをASCII文字全体、つまり、コード0から127に対する バインディングとみなす。 ベクトルのn番目の要素は、コードnの文字に対する バインディングである。 これは、多くのバインディングを記録するコンパクトな方法である。 このようなベクトルのキーマップを完全なキーマップ(full keymap)と呼ぶ。 それ以外のキーマップを疎なキーマップ(sparse keymaps)と呼ぶ。

キーマップにベクトルがあると、ベクトルの要素がnilであっても ベクトルが各ASCII文字のバインディングをつねに定義する。 そのようなnilのバインディングは、 ASCII文字に対しては キーマップのデフォルトのキーバインディングを無効にする。 しかし、ASCII文字以外のイベントに対しては、 デフォルトのバインディングが意味を持つ。 nilのバインディングが 低優先順位のキーマップを隠すことはない。 つまり、ローカルマップがnilのバインディングを与えると、 Emacsはグローバルマップのバインディングを使う。

string
バインディングに加えて、 キーマップでは、要素として文字列を持つこともできる。 これを全面プロンプト文字列(overall prompt string)と呼び、 キーマップをメニューとして使うことを可能にする。 see 節 21.12 メニューキーマップ

キーマップは、メタ文字に対するバインディングを直接には記録していません。 そのかわりに、キー探索においては、メタ文字は2文字から成る列とみなし、 先頭文字はESC(あるいは、meta-prefix-charの現在値)です。 つまり、キーM-aは実際にはESC aと表現され、 そのグローバルなバインディングは esc-mapaでみつかります(see 節 21.5 プレフィックスキー)。

Lispモードに対するローカルキーマップの例を示します。 これは疎なキーマップです。 DELTABC-c C-lM-C-qM-C-xに対する バインディングを定義しています。

 
lisp-mode-map
=> 
(keymap 
 ;; TAB
 (9 . lisp-indent-line)                 
 ;; DEL
 (127 . backward-delete-char-untabify)  
 (3 keymap 
    ;; C-c C-l
    (12 . run-lisp))                    
 (27 keymap 
     ;; M-C-qESC C-qとみなされる
     (17 . indent-sexp)                 
     ;; M-C-xESC C-xとみなされる
     (24 . lisp-send-defun)))           

Function: keymapp object
この関数は、objectがキーマップであればtを返し、 さもなければnilを返す。 より正確には、この関数は、 そのCARがkeymapであるリストかどうかを検査する。

 
(keymapp '(keymap))
    => t
(keymapp (current-global-map))
    => t



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.3 キーマップの作成

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Creating%20Keymaps"
"texi/elisp21/キーマップの作成"へのコメント(無し)

ここでは、キーマップを作成するための関数について述べます。

Function: make-keymap &optional prompt
この関数は新たに完全なキーマップ (つまり、すべてのASCII文字に対する定義を収めた 長さ128のベクトル)を作成しそれを返す。 新たなキーマップでは、すべてのASCII文字に対するバインディングは nilであり、それ以外の種類のイベントに対するバインディングはない。

 
(make-keymap)
    => (keymap [nil nil nil ... nil nil])

promptを指定すると、 それはキーマップに対する全面プロンプト文字列になる。 全面プロンプト文字列はメニューキーマップ (see 節 21.12 メニューキーマップ)に有用である。

Function: make-sparse-keymap &optional prompt
この関数は、新たに空の疎なキーマップを作成しそれを返す。 新たなキーマップにはイベントに対するバインディングはいっさいない。 引数promptは、make-keymapの場合同様、 プロンプト文字列を指定する。

 
(make-sparse-keymap)
    => (keymap)

Function: copy-keymap keymap
この関数はkeymapのコピーを返す。 keymapにバインディングとして直接現れる任意のキーマップも 任意のレベルまで再帰的にコピーされる。 しかし、文字に対する定義が、その関数定義がキーマップであるような シンボルに出会うと再帰的なコピーを行わないため、 同じシンボルが新たなコピーにも現れる。

 
(setq map (copy-keymap (current-local-map)))
=> (keymap
     ;; (これはメタ文字を意味する)
     (27 keymap         
         (83 . center-paragraph)
         (115 . center-line))
     (9 . tab-to-tab-stop))

(eq map (current-local-map))
    => nil
(equal map (current-local-map))
    => t



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.4 継承とキーマップ

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Inheritance%20and%20Keymaps"
"texi/elisp21/継承とキーマップ"へのコメント(無し)

キーマップでは、親キーマップ(parent keymap)と呼ぶ別のキーマップの バインディングを継承できます。 そのようなキーマップはつぎのようになります。

 
(keymap bindings... . parent-keymap)

このキーマップは、キーを探索する時点において parent-keymapが有するすべてのバインディングを継承しますが、 それらにはbindingsが追加されたり優先します。

define-keyや他のキーバインディング関数でparent-keymapの バインディングを変更すると、それらの変更は、 bindingsで隠されない限り継承側のキーマップからも見えます。 その逆は真ではありません。 define-keyで継承側のキーマップを修正すると、 それはbindingsに影響するだけでparent-keymapには影響しません。

親キーマップを用いたキーマップを作成する正しい方法は、 set-keymap-parentを使うことです。 親キーマップを用いたキーマップを直接作成するようなコードがある場合には、 set-keymap-parentを用いるようにプログラムを変更してください。

Function: keymap-parent keymap
この関数は、キーマップkeymapの親キーマップを返す。 keymapに親がなければkeymap-parentnilを返す。

Function: set-keymap-parent keymap parent
キーマップkeymapの親キーマップとしてparentを設定し、 parentを返す。 parentnilであると、 この関数はkeymapに親キーマップをいっさい与えない。

keymapに(プレフィックスキー用のバインディングである) サブマップがあれば、それらもparentが指定するプレフィックスキーを 反映する新たな親マップを受け取る。

text-mode-mapからキーマップを継承する方法を示します。

 
(let ((map (make-sparse-keymap)))
  (set-keymap-parent map text-mode-map)
  map)



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.5 プレフィックスキー

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Prefix%20Keys"
"texi/elisp21/プレフィックスキー"へのコメント(無し)

プレフィックス(prefix key)とは、 そのバインディングがキーマップであるキー列のことです。 そのキーマップが、プレフィックスキー以降のキーでなにをするかを定義します。 たとえば、C-xはプレフィックスキーであり、 変数ctl-x-mapに保持されたキーマップを使います。 このキーマップは、C-xで始まるキー列に対するバインディングを定義します。

Emacsの標準プレフィックスキーのなかには、 Lisp変数にも保持されたキーマップを使うものがあります。

プレフィックスキーのキーマップバインディングは、 当該プレフィックスキーに続くイベントを探すために使われます。 (その関数定義がキーマップであるシンボルでもよい。 効果は同じであるが、シンボルはプレフィックスキーに対する名前として働く。) したがって、C-xのバインディングは シンボルControl-X-prefixであり、 その関数セルがコマンドC-x用のキーマップを保持している。 (ctl-x-mapの値も同じキーマップである。)

プレフィックスキーの定義は、任意の活性なキーマップにあってかまいません。 プレフィックスキーとしてのC-cC-xC-hESCの 定義はグローバルマップにあるので、これらのプレフィックスキーは つねに利用できます。 メジャーモードやマイナモードでは、 プレフィックスキーの定義をローカルキーマップや マイナモードキーマップに入れることで、 キーをプレフィックスとして再定義できます。 See 節 21.6 活性なキーマップ

複数の活性なキーマップにおいて、キーがプレフィックスと定義されていると、 さまざまな定義は実質的には併合されます。 マイナモードキーマップで定義されたコマンドが最優先で、 つぎにローカルマップのプレフィックス定義、 そしてグローバルマップのプレフィックス定義が続きます。

以下の例では、ローカルキーマップにおいて、 C-pC-xに等価なプレフィックスキーにします。 続いてC-p C-fのバインディングを C-x C-fのように関数find-fileにします。 キー列C-p 6はどの活性なキーマップでもみつかりません。

 
(use-local-map (make-sparse-keymap))
    => nil
(local-set-key "\C-p" ctl-x-map)
    => nil
(key-binding "\C-p\C-f")
    => find-file

(key-binding "\C-p6")
    => nil

Function: define-prefix-command symbol
この関数は、symbolをプレフィックスキーの バインディングとして使えるように準備する。 つまり、完全なキーマップを作成し、 symbolの関数定義にそのキーマップを保存する。 以後、symbolにキー列をバインドすると、 当該キー列をプレフィックスキーに入る。

この関数は、変数としてのsymbolにも値としてキーマップを設定する。 symbolを返す。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.6 活性なキーマップ

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Active%20Keymaps"
"texi/elisp21/活性なキーマップ"へのコメント(無し)

Emacsには、通常、たくさんのキーマップがあります。 ある時点では、それらの数個が活性になっていて、 ユーザー入力の解釈に関与します。 それらは、グローバルキーマップ、カレントバッファのローカルキーマップ、 オンになっているマイナモードのキーマップです。

グローバルキーマップ(global keymap)は、 C-fのようなカレントバッファに依存せずに 定義されたキーのバインディングを保持します。 変数global-mapはこのキーマップを保持していて、 このキーマップはつねに活性です。

各バッファには別のキーマップ、つまり、 バッファのローカルキーマップ(local keymap)があり、 キーに対する新しい定義や無効にする定義を保持しています。 カレントバッファのローカルキーマップは、 overriding-local-mapで無効にしない限り、つねに活性です。 テキスト属性により、バッファの特定部分に対する 代替ローカルマップを指定できます。 31.19.4 特別な意味を持つ属性を参照してください。

各マイナモードもキーマップを持てます。 その場合、マイナモードがオンであると当該キーマップは活性です。

変数overriding-local-mapnil以外であると、 バッファのローカルキーマップとそのすべてのマイナモードキーマップに 取ってかわるローカルキーマップを指定します。

キーが入力されるとどのコマンドを実行するかを決定するために、 すべての活性なキーマップを一緒に使います。 Emacsは、キーマップの1つでバインディングがみつかるまで、 優先順位が高いほうからこれらのキーマップを1つ1つ探索します。 1つのキーマップで探索する処理のことを キー探索(key lookup)といいます。 21.7 キー探索を参照してください。

通常、Emacsはまずminor-mode-map-alistで指定される順に マイナモードキーマップでキーを探します。 キーに対するバインディングがなければ、 Emacsはローカルキーマップで探します。 そこにもバインディングがなければ、 Emacsはグローバルキーマップで探します。 しかし、overriding-local-mapnil以外であれば、 Emacsはまずそのキーマップで探してから、 グローバルキーマップで探します。

同じメジャーモードを使う各バッファは、通常、同じローカルキーマップを 使うので、キーマップはモードにローカルであると考えることができます。 (たとえばlocal-set-keyを使って)バッファのローカルキーマップを 修正すると、当該キーマップを共有している別のバッファでも その修正が見えます。

Lispモードや他の数個のメジャーモードで使われるローカルキーマップは、 それらのモードがまだ使われていなくても存在します。 そのようなローカルキーマップは、lisp-mode-mapなどの変数の値です。 使用頻度の低いほとんどのメジャーモードでは、 セッションで始めてそのモードを使ったときに ローカルキーマップを作成します。

ミニバッファにもローカルキーマップがあります。 それにはさまざまな補完コマンドや脱出コマンドが含まれます。 See 節 19.1 ミニバッファの紹介

Emacsには、別の用途のキーマップもあります。 read-key-sequenceでイベントを変換するためのものです。 See 節 39.8.2 入力イベントの変換

標準的なキーマップの一覧についてはSee 節 F. 標準のキーマップ。

Variable: global-map
この変数は、Emacsがキーボード入力をコマンドに対応させるための デフォルトのグローバルキーマップを保持する。 グローバルキーマップは、通常、このキーマップである。 デフォルトのグローバルキーマップは、 すべての印字文字にself-insert-commandをバインドする 完全なキーマップである。

グローバルマップのバインディングを修正することは実用的ですが、 この変数には、動作開始時のキーマップ以外の値は設定しないこと。

Function: current-global-map
この関数は、現在のグローバルキーマップを返す。 global-mapを変更していなければ、 これはglobal-mapの値と同じである。

 
(current-global-map)
=> (keymap [set-mark-command beginning-of-line ... 
            delete-backward-char])

Function: current-local-map
この関数は、カレントバッファのローカルキーマップを返す。 なければnilを返す。 つぎの例では、(lisp対話モードを使っている)バッファ`*scratch*'の キーマップは疎なキーマップであり、 ASCIIコード27のESCに対する指定も別の疎なキーマップである。

 
(current-local-map)
=> (keymap 
    (10 . eval-print-last-sexp) 
    (9 . lisp-indent-line) 
    (127 . backward-delete-char-untabify) 
    (27 keymap 
        (24 . eval-defun) 
        (17 . indent-sexp)))

Function: current-minor-mode-maps
この関数は、現在オンになっているマイナモードのキーマップのリストを返す。

Function: use-global-map keymap
この関数は、キーマップkeymapを新たな現在のグローバルキーマップとする。 これはnilを返す。

グローバルキーマップを変更することは、とうてい普通のことではない。

Function: use-local-map keymap
この関数は、キーマップkeymapをカレントバッファの 新たなローカルキーマップとする。 keymapnilであると、 バッファにはローカルキーマップがなくなる。 use-local-mapnilを返す。 ほとんどのメジャーモードコマンドは、この関数を使う。

Variable: minor-mode-map-alist
この変数は、変数の値に応じて活性になっている/いないキーマップを 記述する連想リストである。 その要素はつぎの形である。

 
(variable . keymap)

変数variableの値がnil以外であれば、 キーマップkeymapは活性である。 典型的には、variableはマイナモードをオン/オフする変数である。 see 節 22.2.2 キーマップとマイナモード

minor-mode-map-alistの要素とminor-mode-alistの要素とは、 異なる構造であることに注意してほしい。 キーマップは要素のCDRである必要があり、 要素のCADRがキーマップであるようなリストではだめである。 CADRは、(リストの)キーマップであるか、 関数定義がキーマップであるシンボルである。

複数のマイナモードキーマップが活性な場合、 それらの優先順位は、minor-mode-map-alistでの順番である。 読者は、互いに干渉しないようにマイナモードを設計する必要がある。 正しくできていれば、順序は関係ないはずである。

マイナモードについて詳しくは22.2.2 キーマップとマイナモードを参照。 minor-mode-key-binding(see 節 21.8 キー探索関数)も参照のこと。

Variable: minor-mode-overriding-map-alist
この変数は、メジャーモードから特定のマイナモード向けのキーバインディングを 無効にするためのものである。 この連想リストの要素は、minor-mode-map-alistの要素と同じ形で、 (variable . keymap)である。

minor-mode-overriding-map-alistの要素として変数が現れると、 当該要素が指定するキーマップで、 minor-mode-map-alist内の同じ変数で指定したキーマップを 完全に置き換える。

minor-mode-overriding-map-alistは、すべてのバッファにおいて、 自動的にバッファにローカルになる。

Variable: overriding-local-map
nil以外の値であると、この変数は、 バッファのローカルキーマップ、ならびに、すべてのマイナモードキーマップの かわりに用いるキーマップを保持する。 このキーマップは、現在のグローバルキーマップを除く、 他のすべての活性なキーマップを無効にする。

Variable: overriding-terminal-local-map
nil以外であると、この変数は、 overriding-local-map、および、バッファのローカルキーマップと すべてのマイナモードキーマップのかわりに用いるキーマップを保持する。

この変数はつねに現在の端末に対してローカルであり、 バッファに対してローカルにはならない。 see 節 28.2 複数ディスプレイ。 これはインクリメンタルサーチモードの実装に使われている。

Variable: overriding-local-map-menu-flag
この変数がnil以外であれば、 overriding-local-mapoverriding-terminal-local-mapの値は、 メニューバーの表示に影響する。 デフォルト値はnilであり、 そのため、それらのマップはメニューバーには影響しない。

これら2つのキーマップ変数は、メニューバーの表示に影響しないときであっても、 メニューバーを用いて入力したキー列の実行には影響することに注意してほしい。 そのため、メニューバーのキー列が到着したら、 そのキー列を探索し実行するまえに、これらの変数をクリアすべきである。 これらの変数を使うモードでは、典型的にはつぎのようにする。 つまり、モードで処理できないイベントは『読み戻し』てモードから抜ける。

Variable: special-event-map
この変数は特殊イベント用のキーマップを保持する。 イベント型のバインディングがこのキーマップにあれば、 そのイベントは特殊イベントであり、 read-eventが当該イベントのバインディングを直接実行する。 see 節 20.7 特殊イベント



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.7 キー探索

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Key%20Lookup"
"texi/elisp21/キー探索"へのコメント(無し)

キー探索(key lookup)とは、 与えられたキーマップからキー列のバインディングを捜し出す処理です。 バインディングを実際に実行することは、キー探索ではありません。

キー探索では、キー列の各イベントのイベント型のみを使い、 イベントの他の部分は無視します。 実際、キー探索に使われるキー列では、 マウスイベント全体(リスト)ではなく そのイベント型(シンボル)のみを指定します。 See 節 20.5 入力イベント。 そのような『キー列』は、command-executeの動作には不十分ですが、 キーの探索や再バインディングには十分です。

キー列が複数のイベントから構成される場合、 キー探索ではイベントを順番に処理します。 先頭のイベントのバインディングを探しますが、 それはキーマップであるはずです。 続いて、そのキーマップから2番目のイベントのバインディングを探します。 これをキー列のすべてのイベントを使い尽くすまで行います。 (このように探した最後のイベントに対するバインディングは、 キーマップであたっりそうでないかもしれない。) つまり、キー探索処理は、 キーマップから単一イベントを探索するという単純な処理として定義できます。 これがどのように行われるかは、 キーマップ内のイベントに対応付けられたオブジェクトの型に依存します。

キーマップでイベント型を探してみつかった値のことを キーマップ項目(keymap entry)という単語で表します。 (これには、メニューキーバインディングにある 項目文字列や他の追加要素を含まない。 というのは、lookup-keyや他のキー探索関数は、 それらを戻り値として返さないからである。) キーマップ項目として任意のLispオブジェクトをキーマップに保存できますが、 キー探索においてそのすべてが意味を持つとは限りません。 意味のある種類のキー項目をつぎに示します。

nil
nilは、探索に使ったここまでのイベントが 未定義キーを構成することを意味する。 キーマップにイベント型が記載されてなく、かつ、 デフォルトのバインディングもない場合には、 そのイベント型に対しては、バインディングがnilであるのと等価。

command
探索に使ったここまでのイベントは完全なキーを構成し、 そのバインディングはコマンドcommandである。 see 節 11.1 関数とはなにか

array
配列(文字列やベクトル)は、キーボードマクロである。 探索に使ったここまでのイベントは完全なキーを構成し、 そのバインディングは配列arrayである。 詳しくは20.14 キーボードマクロを参照。

keymap
探索に使ったここまでのイベントはプレフィックスキーを構成する。 キー列のつぎのイベントはこのキーマップkeymapで探す。

list
リストの意味は、リストの要素の型に依存する。

symbol
シンボルsymbolのかわりにその関数定義を使う。 それがまたシンボルであると、この処理を何回でも繰り返す。 最終的にこれは、キーマップ、コマンド、キーボードマクロの いずれかのオブジェクトになるはずである。 キーマップやコマンドであるリストは許されるが、 シンボルを介しては間接項目は使えない。

キーマップやキーボードマクロ(文字列やベクトル)は正しい関数ではないので、 関数定義としてキーマップ、文字列、ベクトルを持つシンボルは、 正しい関数ではない。 しかし、キーバインディングとしては正しい。 定義がキーボードマクロである場合には、そのシンボルは command-executeの引数としても正しい (see 節 20.3 対話的呼び出し)。

シンボルundefinedについて特記しておく。 これは、キーを未定義として扱うことを意味する。 正確には、キーは定義されており、 そのバインディングはコマンドundefinedである。 しかし、そのコマンドは、未定義キーに対して自動的に行われることと 同じことを行う。 つまり、(dingを呼び出して)ベルを鳴らすが、 エラーは通知しない。

undefinedは、グローバルキーバインディングを無効にして キーをローカルに『未定義』にするためにローカルキーマップで使われる。 nilのローカルバインディングでは、 グローバルバインディングを無効にしないため、こうはならない。

その他
その他の型のオブジェクトであると、 探索に使ったここまでのイベントは完全なキーを構成し、 当該オブジェクトがそのバインディングであるが、 当該バインディングはコマンドとしては実行できない。

まとめると、キー項目は、キーマップ、コマンド、キーボードマクロ、 これら3つのいずれかになるシンボル、間接項目、nilです。 2つの文字をコマンドに、1つを別のキーマップに対応付ける 疎なキーマップの例を示します。 このキーマップは、emacs-lisp-mode-mapの通常の値です。 ここで、それぞれ、9はTAB、 127はDEL、27はESC、17はC-q、 24はC-xの文字コードであることに注意してください。

 
(keymap (9 . lisp-indent-line)
        (127 . backward-delete-char-untabify)
        (27 keymap (17 . indent-sexp) (24 . eval-defun)))



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.8 キー探索関数

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Functions%20for%20Key%20Lookup"
"texi/elisp21/キー探索関数"へのコメント(無し)

ここでは、キー探索に関わる関数や変数について述べます。

Function: lookup-key keymap key &optional accept-defaults
この関数はキーマップkeymapにおけるkeyの定義を返す。 本章で述べる他の関数は、lookup-keyを用いてキーを探す。 例を示す。

 
(lookup-key (current-global-map) "\C-x\C-f")
    => find-file
(lookup-key (current-global-map) "\C-x\C-f12345")
    => 2

文字列やベクトルであるkeyが、 keymapで指定されたプレフィックスキーに対して正しいキー列でなければ、 keyは『長すぎる』のであって、 1つのキー列に収まらない余分なイベントが末尾にある。 その場合、戻り値は数であり、 完全なキーを構成するkeyの先頭からのイベント数を表す。

accept-defaultsnil以外であると、 lookup-keyは、keyの特定のイベントに 対するバインディングだけでなく、 デフォルトのバインディングも考慮する。 さもなければ、lookup-keyは、 keyの特定のイベントに対するバインディングだけを報告し、 特に指定しない限りデフォルトのバインディングは無視する。 (それには、keyの要素としてtを与える。 21.2 キーマップの形式を参照。)

keyにメタ文字が含まれる場合、 当該文字は暗黙のうちに2文字の列、 つまり、meta-prefix-charの値と対応する非メタ文字 に置き換えられる。 したがって、つぎの最初の例は、2番目の例に変換して処理される。

 
(lookup-key (current-global-map) "\M-f")
    => forward-word
(lookup-key (current-global-map) "\ef")
    => forward-word

read-key-sequenceと異なり、 この関数は、情報を欠落するようには指定されたイベントを修正しない (see 節 20.6.1 キー列の入力)。 特に、文字を小文字に変換したり、 ドラッグイベントをクリックイベントに変換したりはしない。

コマンド: undefined
キーを未定義にするためにキーマップで使われる。 dingを呼び出すが、エラーにはならない。

Function: key-binding key &optional accept-defaults
この関数は、すべての活性なキーマップを試して keyに対するバインディングを返す。 キーマップでkeyが未定義であると結果はnil

引数accept-defaultsは、lookup-key(上記)と同様に、 デフォルトのバインディングを調べるかどうか制御する。

keyが文字列でもベクトルでもないとエラーを通知する。

 
(key-binding "\C-x\C-f")
    => find-file

Function: local-key-binding key &optional accept-defaults
この関数は、現在のローカルキーマップから keyに対するバインディングを返す。 未定義ならばnilを返す。

引数accept-defaultsは、lookup-key(上記)と同様に、 デフォルトのバインディングを調べるかどうか制御する。

Function: global-key-binding key &optional accept-defaults
この関数は、現在のグローバルキーマップから keyに対するバインディングを返す。 未定義ならばnilを返す。

引数accept-defaultsは、lookup-key(上記)と同様に、 デフォルトのバインディングを調べるかどうか制御する。

Function: minor-mode-key-binding key &optional accept-defaults
この関数は、すべてのオンになっているマイナモードにおける keyのバインディングのリストを返す。 より正確には、対(modename . binding)を要素とする 連想リストを返す。 ここで、modenameはマイナモードをオンにする変数であり、 bindingは当該モードにおけるkeyのバインディングである。 keyにマイナモードでのバインディングがなければ、 値はnilである。

最初にみつかったバインディングがプレフィックスの定義 (キーマップかキーマップとしてのシンボル)でなければ、 残りのマイナモードからのバインディングは完全に隠されてしまうので それらは省略する。 同様に、プレフィックスバインディングに 続く非プレフィックスバインディングも省略する。

引数accept-defaultsは、lookup-key(上記)と同様に、 デフォルトのバインディングを調べるかどうか制御する。

Variable: meta-prefix-char
この変数は、メタプレフィックス文字の文字コードである。 メタ文字をキーマップで探索するために2文字列に変換するときに使われる。 結果が有用であるためには、 この値はプレフィックスイベント(see 節 21.5 プレフィックスキー)であるべきである。 デフォルト値は27、ESCのASCIIコードである。

meta-prefix-charの値が27である限り、 キー探索ではM-bESC bに変換し、 通常、これはコマンドbackward-wordと定義されている。 しかし、meta-prefix-charC-xのコードである24を設定すると、 EmacsはM-bC-x bに変換し、 その標準のバインディングはコマンドswitch-to-bufferである。 これを以下に示す。

 
meta-prefix-char                    ; デフォルト値
     => 27
(key-binding "\M-b")
     => backward-word
?\C-x                               ; 文字の表示表現
     => 24
(setq meta-prefix-char 24)
     => 24      
(key-binding "\M-b")
    => switch-to-buffer            ; ここでM-bと打つと
                                    ; C-x bと打つのと同じ

(setq meta-prefix-char 27)          ; 混乱を避けるために
     => 27                         ; デフォルト値に戻す!



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

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

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Changing%20Key%20Bindings"
"texi/elisp21/キーバインディングの変更"へのコメント(無し)

キーを再バインドするには、キーマップにおける当該項目を変更します。 グローバルキーマップでバインディングを変更すると、 その変更はすべてのバッファで効果を発揮します (ただし、ローカルキーマップでグローバルバインディングを 隠しているバッファでは直接の効果はない)。 カレントバッファのローカルキーマップで変更すると、 通常、同じメジャーモードを使っているすべてのバッファに影響します。 関数global-set-keylocal-set-keyは、 これらの操作を行うための便利なインターフェイスです (see 節 21.10 キーをバインドするためのコマンド)。 より汎用の関数define-keyを使うこともできますが、 変更対象のキーマップを明示する必要があります。

キー列の再バインドを書くときには、 コントロール文字やメタ文字向けの 特別なエスケープシーケンスを使うのがよいです(see 節 2.3.8 文字列型)。 構文`\C-'は後続の文字がコントロール文字であること、 構文`\M-'は後続の文字がメタ文字であることを意味します。 したがって、文字列"\M-x"は単一のM-xを含むと読まれ、 "\C-f"は単一のC-fを含むと読まれ、 "\M-\C-x""\C-\M-x"はいずれも単一のC-M-xを 含むと読まれます。 同じエスケープシーケンスは、 ベクトルでも使え、文字列が許されない他の場面でも使えます。 たとえば、`[?\C-\H-x home]'です。 See 節 2.3.3 文字型

キーを定義したり探索する関数では、 ベクトルで表したキー列内のイベント型に対して別の構文、 つまり、修飾子名と1つの基本イベント(文字やファンクションキー名) から成るリストを受け付けます。 たとえば、(control ?a)?\C-aに等価であり、 (hyper control left)C-H-leftに等価です。 このようなリストの利点の1つは、 コンパイル済みのファイルに修飾ビットの数値が現れないことです。

以下の関数では、keymapがキーマップでなかったり、 keyがキー列を表す文字列やベクトルでないと、エラーを通知します。 リストであるイベントの省略形としてイベント型(シンボル)を使えます。

Function: define-key keymap key binding
この関数は、キーマップkeymapにおいて キーkeyに対するバインディングを設定する。 (keyが複数イベントの場合、 keymapから辿った別のキーマップが実際には変更される。) 引数bindingは任意のLispオブジェクトであるが、 ある種の型のものだけが意味を持つ。 (意味のある型の一覧については、21.7 キー探索を参照。) define-keyが返す値はbindingである。

keyのおのおののプレフィックスはプレフィックスキーである (キーマップにある)か未定義であること。 さもなければ、エラーを通知する。 keyのプレフィックスに未定義なものがあると、 define-keyは当該プレフィックスをプレフィックスキーと定義し、 keyの残りの部分を指定どおりに定義できるようにする。

keymapkeyのバインディングがなければ、 新たなバインディングをkeymapの先頭に追加する。 キーマップ内のバインディングの順序は多くの場合関係ないが、 メニューキーマップでは意味を持つ(see 節 21.12 メニューキーマップ)。

疎なキーマップを作成し、そこにバインディングを作る例を示します。

 
(setq map (make-sparse-keymap))
    => (keymap)
(define-key map "\C-f" 'forward-char)
    => forward-char
map
    => (keymap (6 . forward-char))

;; C-x用の疎なサブマップを作り、
;; そこにfのバインディングを入れる
(define-key map "\C-xf" 'forward-word)
    => forward-word
map
=> (keymap 
    (24 keymap                ; C-x
        (102 . forward-word)) ;      f
    (6 . forward-char))       ; C-f

;; C-pctl-x-mapにバインドする
(define-key map "\C-p" ctl-x-map)
;; ctl-x-map
=> [nil ... find-file ... backward-kill-sentence] 

;; ctl-x-mapで、C-ffooにバインドする
(define-key map "\C-p\C-f" 'foo)
=> 'foo
map
=> (keymap     ; fooctl-x-mapの中にある
    (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-fとデフォルトのグローバルキーマップ内の C-x C-fの両方のバインディングを変更する効果がある ことに注意してください。

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))

oldmapnil以外であると、 そのバインディングによってどのキーを再バインドするかを決定する。 再バインディングはkeymapで行い、oldmapではない。 つまり、別のキーマップ内のバインディングの制御のもとに、 キーマップを変更できる。 たとえば、

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

では、グローバルには標準の削除コマンドにバインドされているキーに対しては、 my-mapでは特別な削除コマンドにする。

変更前後のキーマップを以下に示す。

 
(setq map '(keymap 
            (?1 . olddef-1) 
            (?2 . olddef-2) 
            (?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
この関数は、完全なキーマップkeymapの内容を変更し、 すべての印字文字を未定義にする。 より正確には、それらにコマンドundefinedをバインドする。 これにより、通常のテキストの挿入を不可能にする。 suppress-keymapnilを返す。

nodigitsnilであると、 suppress-keymapは、 数字文字ではdigit-argumentを実行し、 -ではnegative-argumentを実行するように定義する。 さもなければ、それらも他の印字文字と同様に未定義にする。

関数suppress-keymapは、 yankquoted-insertなどのコマンドを抑制しないので、 バッファを変更不可能にするわけではない。 バッファの変更を禁止するには、バッファを読み出し専用にする (see 節 26.7 読み出し専用バッファ (2003/10/30))。

この関数はkeymapを変更するため、 読者は、通常、新たに作成したキーマップに対して使うであろう。 ある目的で使用中の既存のキーマップを操作すると、 問題を引き起こすことがある。 たとえば、global-mapに適用するとEmacsをほとんど使用不能にしてしまう。

多くの場合、テキストの挿入が必要なくバッファを読み出し専用で使う rmailやdiredなどのモードのローカルキーマップの初期化に suppress-keymapを使う。 ファイル`emacs/lisp/dired.el'から持ってきた例を示す。 これは、diredモード用のローカルキーマップの設定方法である。

 
(setq dired-mode-map (make-keymap))
(suppress-keymap dired-mode-map)
(define-key dired-mode-map "r" 'dired-rename-file)
(define-key dired-mode-map "\C-d" 'dired-flag-file-deleted)
(define-key dired-mode-map "d" 'dired-flag-file-deleted)
(define-key dired-mode-map "v" 'dired-view-file)
(define-key dired-mode-map "e" 'dired-find-file)
(define-key dired-mode-map "f" 'dired-find-file)
...



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.10 キーをバインドするためのコマンド

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Key%20Binding%20Commands"
"texi/elisp21/キーをバインドするためのコマンド"へのコメント(無し)

本節では、キーのバインディングを変更する 便利で対話的なインターフェイスについて述べます。 これらは、define-keyを呼び出して動作します。

単純なカスタマイズのために ファイル`.emacs'でglobal-set-keyをしばしば使います。 たとえば、

 
(global-set-key "\C-x\C-\\" 'next-line)

 
(global-set-key [?\C-x ?\C-\\] 'next-line)

 
(global-set-key [(control ?x) (control ?\\)] 'next-line)

は、1行下がるようにC-x C-\を再定義します。

 
(global-set-key [M-mouse-1] 'mouse-set-point)

は、メタキーを押し下げながらマウスの第1ボタン(左端)をクリックすると クリック位置にポイントを設定するように再定義します。

コマンド: global-set-key key definition
この関数は、現在のグローバルキーマップにおいて keyのバインディングをdefinitionと設定する。

 
(global-set-key key definition)
==
(define-key (current-global-map) key definition)

コマンド: global-unset-key key
この関数は、現在のグローバルキーマップから keyのバインディングを削除する。

この関数の1つの用途は、 keyに非プレフィックスのバインディングがあると再定義できないため、 keyをプレフィックスとして使う長いキーを定義する前準備である。 たとえば、つぎのとおり。

 
(global-unset-key "\C-l")
    => nil
(global-set-key "\C-l\C-l" 'redraw-display)
    => nil

この関数は単にdefine-keyを使って実装してある。

 
(global-unset-key key)
==
(define-key (current-global-map) key nil)

コマンド: local-set-key key definition
この関数は、現在のローカルキーマップにおいて keyのバインディングをdefinitionと設定する。

 
(local-set-key key definition)
==
(define-key (current-local-map) key definition)

コマンド: local-unset-key key
この関数は、現在のローカルキーマップから keyのバインディングを削除する。

 
(local-unset-key key)
==
(define-key (current-local-map) key nil)



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.11 キーマップの走査

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Scanning%20Keymaps"
"texi/elisp21/キーマップの走査"へのコメント(無し)

本節では、ヘルプ情報を表示するために 現在のキーマップをすべて走査する関数について述べます。

Function: accessible-keymaps keymap &optional prefix
この関数は、keymapから(0個以上のプレフィックスキーにより)辿れる すべてのキーマップのリストを返す。 その値は、(key . map)の形の要素から成る 連想リストである。 ここで、keyはプレフィックスキーであり、 keymap内でのその定義はmapである。

連想リスト内での要素の順番は、keyの長さが増える順である。 指定したキーマップkeymapはプレフィックスのイベントなしに参照できるので、 最初の要素はつねに("" . keymap)である。

prefixを与える場合、それはプレフィックスキー列であること。 すると、accessible-keymapsは、 prefixで始まるプレフィックスに対応したサブマップのみを含める。 それらの要素は、(accessible-keymaps)の値と同じに見えるが、 違いは、いくつかの要素が省略されることである。

つぎの例では、返された連想リストにおいては、 `^['と表示されたキーESCはプレフィックスキーであり、 その定義は疎なキーマップ (keymap (83 . center-paragraph) (115 . foo))であることを表す。

 
(accessible-keymaps (current-local-map))
=>(("" keymap 
      (27 keymap   ; Note this keymap for ESC is repeated below.
          (83 . center-paragraph)
          (115 . center-line))
      (9 . tab-to-tab-stop))

   ("^[" keymap 
    (83 . center-paragraph) 
    (115 . foo)))

つぎの例では、C-hは、 疎なキーマップ(keymap (118 . describe-variable)...)を 使うプレフィックスキーである。 別のプレフィックスC-x 4は、 変数ctl-x-4-mapの値でもあるキーマップを使う。 イベントmode-lineは、 ウィンドウの特別な箇所におけるマウス操作を表すための 疑似イベントの1つである。

 
(accessible-keymaps (current-global-map))
=> (("" keymap [set-mark-command beginning-of-line ... 
                   delete-backward-char])
    ("^H" keymap (118 . describe-variable) ...
     (8 . help-for-help))
    ("^X" keymap [x-flush-mouse-queue ...
     backward-kill-sentence])
    ("^[" keymap [mark-sexp backward-sexp ...
     backward-kill-word])
    ("^X4" keymap (15 . display-buffer) ...)
    ([mode-line] keymap
     (S-mouse-2 . mouse-split-window-horizontally) ...))

実際に表示されるキーマップはこれらだけとは限らない。

Function: where-is-internal command &optional keymap firstonly noindirect
この関数は、コマンドwhere-is (see GNU Emacs マニュアル)が使う サブルーティンである。 キーマップにおいてcommandにバインドされた (任意長の)キー列のリストを返す。

引数commandは任意のオブジェクトであり、 キーマップ項目とはeqで比較する。

keymapnilであると、 overriding-local-mapを無視 (つまり、その値はnilとみな)して、 現在活性なキーマップを使う。 keymapnil以外であると、 keymapとグローバルキーマップから辿れるキーマップを使う。

通常、keymapに対する式にはoverriding-local-mapを使うのが 最良である。 そうすると、where-is-internalは正確に活性なキーマップを走査する。 グローバルキーマップのみを走査するには、 keymapとして(keymap)(空のキーマップ)を渡す。

firstonlynon-asciiであると、 戻り値は、可能なキー列のリストではなく、 最初にみつかったキー列を表す1つの文字列である。 firstonlytであると、 値は最初のキー列であるが、 ASCII文字(あるいはASCII文字のメタ変種)のみから成るキー列が 他のキー列より優先される。

noindirectnil以外であると、 where-is-internalは間接項目を辿らない。 これにより、間接項目そのものを探すことができる。

 
(where-is-internal 'describe-function)
    => ("\^hf" "\^hd")

コマンド: describe-bindings &optional prefix
この関数は、現在のすべてのキーバインディングの一覧を作成し、 `*Help*'という名前のバッファに表示する。 テキストはモードごとにまとめられ、 マイナモード、メジャーモード、グローバルバインディングの順である。

prefixnil以外であると、それはプレフィックスキーであること。 そうすると、prefixで始まるキーのみの一覧を作る。

一覧では、メタ文字は、ESCに続けて対応する非メタ文字で表す。

連続したASCIIコードの一連の文字が同じ定義である場合には、 それらをまとめて`firstchar..lastchar'と表示する。 この場合、どの文字であるか理解するには、 ASCIIコードを知っている必要がある。 たとえば、デフォルトのグローバルキーマップでは、 `SPC.. ~'の文字が1行に表示される。 SPCはASCIIコード32、~はASCIIコード126であり、 そのあいだには普通の印字文字(英文字、数字文字、句読点文字など)が すべて含まれる。 これらの文字はすべてself-insert-commandにバインドされている。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.12 メニューキーマップ

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Menu%20Keymaps"
"texi/elisp21/メニューキーマップ"へのコメント(無し)

キーマップは、キーボードのキーやマウスボタンに対するバインディングに加えて メニューも定義できます。

21.12.1 メニューの定義    How to make a keymap that defines a menu.
21.12.2 メニューとマウス    How users actuate the menu with the mouse.
21.12.3 メニューとキーボード    How they actuate it with the keyboard.
21.12.4 メニューの例    Making a simple menu.
21.12.5 メニューバー    How to customize the menu bar.
21.12.6 メニューの修正    How to add new items to a menu.



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.12.1 メニューの定義

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Defining%20Menus"
"texi/elisp21/メニューの定義"へのコメント(無し)

キーマップに全面プロンプト文字列(overall prompt string)、 つまり、キーマップの要素として文字列が現れれば、 メニューとして使えます。 その文字列でメニューの目的を記述します。 プロンプト文字列を持ったキーマップを作成するもっとも簡単な方法は、 make-keymapmake-sparse-keymap(see 節 21.3 キーマップの作成)を 呼ぶときに、引数として文字列を指定します。

メニュー上での項目の順番は、 キーマップ内のバインディングの順番と同じです。 define-keyは、新たなバインディングを先頭に追加するので、 順番を気にするのならば、メニューの底の項目から始めて 上の項目へ向かってメニュー項目の定義を入れます。 既存のメニューに項目を追加する場合には、 define-key-after(see 節 21.12.6 メニューの修正)を使って メニュー内での位置を指定できます。

21.12.1.1 単純なメニュー項目    A simple kind of menu key binding, limited in capabilities.
21.12.1.3 メニュー項目の別名    Using command aliases in menu items.
21.12.1.2 拡張メニュー項目    More powerful menu item definitions let you specify keywords to enable various features.



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.12.1.1 単純なメニュー項目

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Simple%20Menu%20Items"
"texi/elisp21/単純なメニュー項目"へのコメント(無し)

メニューキーマップのバインディングを定義する単純で旧式の方法は つぎのとおりです。

 
(item-string . real-binding)

CARのitem-stringは、メニューに表示される文字列です。 3単語までの短いものにし、対応するコマンドの動作を記述します。

つぎのように、ヘルプ文字列となる2つめの文字列も指定できます。

 
(item-string help-string . real-binding)

現状では、Emacsは実際にはhelp-stringを使いません。 real-bindingを取り出すためにhelp-stringを無視する方法を 知っているだけです。 将来、ユーザーの要望に応じてメニュー項目に対する追加説明として help-stringを使うかもしれません。

define-keyに関する限り、 item-stringhelp-stringは イベントのバインディングの一部分です。 しかし、lookup-keyreal-bindingのみを返し、 キーの実行にはreal-bindingのみが使われます。

real-bindingnilであると、 item-stringはメニューに現れますが、それは選択できません。

real-bindingがシンボルであり、 その属性menu-enablenil以外であると、 当該属性は、メニュー項目を活性にするかどうかを制御する式です。 Emacsは、メニューを表示するためにキーマップを使うたびに、 その式を評価し、式の値がnil以外である場合に限り、 当該メニュー項目をオンにします。 メニュー項目がオフであると、『薄く』表示し、それは選択できません。

メニューバーでは、読者がメニューを見るたびにどの項目がオンであるかを 再計算しません。 Xツールキットがあらかじめメニューの木構造全体を必要とするからです。 メニューバーの再計算を強制するには、 force-mode-line-updateを呼び出します。 (see 節 22.3 モード行の書式)。

メニュー項目には、同じコマンドを起動する等価なキーボードのキー列が (あれば)表示されていることに気づいたと思います。 再計算の時間を節約するために、 メニューの表示では、この情報をつぎのように バインディングの部分リストに隠し持っています。

 
(item-string [help-string] (key-binding-data) . real-binding)

読者は、メニュー項目にこれらの部分リストを入れないでください。 それらはメニューの表示で自動的に計算されます。 冗長になるので、項目の文字列には、等価なキーボード入力を 含めないでください。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.12.1.2 拡張メニュー項目

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Extended%20Menu%20Items"
"texi/elisp21/拡張メニュー項目"へのコメント(無し)

拡張形式のメニュー項目は、より柔軟性があり、 単純な形式より見通しがよい代替方法です。 それらは、シンボルmenu-itemで始まるリストから成ります。 選択不可の文字列を定義するには、項目をつぎのようにします。

 
(menu-item item-name)

ここで、文字列item-nameは区切り行を表す複数個のダッシュから成ります。

選択可能な実際のメニュー項目を定義するには、 拡張形式の項目はつぎのようになります。

 
(menu-item item-name real-binding
    . item-property-list)

ここで、item-nameは、メニュー項目の文字列に評価される式です。 つまり、(項目の)文字列は定数である必要はありません。 3番目の要素item-property-listは実行すべきコマンドです。 リストの残りitem-property-listは、 他の情報を含んだ属性リストの形式です。 指定できる属性はつぎのとおりです。

:enable FORM
formの評価結果で、項目をオンにするかどうか決定する (nil以外だとオン)。

:visible FORM
formの評価結果で、項目をメニューに含めるかどうか決定する。 (nil以外だと含める)。 項目を含めない場合、当該項目が定義されていないかのようにメニューを表示する。

:help help
この属性の値helpは、拡張ヘルプ文字列 (現状ではEmacsは使わない)。

:button (type . selected)
この属性は、ラジオボタンとトグルボタンを定義する方法を提供する。 CARのtypeは、:toggle:radioであり、 どちらであるかを指定する。 CDRのselectedはフォームであること。 その評価結果が、現在ボタンが選択されているかどうかを決定する。

トグル(toggle)は、selectedの値に応じて 『on』か『off』と書かれるメニュー項目である。 コマンド自身では、selectednilならば selectedtを設定し、 tならばnilを設定すること。 以下は、debug-on-errorが定義されていれば debug-on-errorをオン/オフするメニュー項目の書き方である。

 
(menu-item "Debug on Error" toggle-debug-on-error
           :button (:toggle
                    . (and (boundp 'debug-on-error)
                           debug-on-error))

これは、変数debug-on-errorをオン/オフするコマンドとして toggle-debug-on-errorが定義されているので動作する。

ラジオボタン(radio button)はメニュー項目のグループであり、 ある時点ではそれらのうちの1つだけを『選択』できる。 どれを選択しているかを表す変数が必要である。 グループ内の各ラジオボタンに対するフォームselectedは、 当該変数の値が当該ボタンを選択している値かどうかを検査する。 ボタンをクリックすると、クリックしたボタンが選択されるように 当該変数に設定すること。

:key-sequence key-sequence
この属性は、このメニュー項目が起動するコマンドにバインド される可能性があるキー列を指定する。 正しいキー列を指定すると、メニュー表示の準備が素早くなる。

まちがったキー列を指定しても、その効果はない。 メニューにkey-sequenceを表示するまえに、 Emacsはkey-sequenceがこのメニュー項目に実際に等価かどうか調べる。

:key-sequence nil
この属性は、このメニュー項目に等価なキーバインディングが 普通はないことを示す。 この属性を使うとメニュー表示の準備時間を節約できる。 Emacsはこのメニュー項目に等価なキーボード入力をキーマップで 探す必要がないからである。

しかし、ユーザーがこの項目の定義に対してキー列を再バインドすると、 Emacsは属性:keysを無視して等価なキーボード入力を探す。

:keys string
この属性は、このメニュー項目に対する等価なキーボード入力として 表示する文字列stringを指定する。 stringでは説明文の`\\[...]'の書き方を使える。

:filter filter-fn
この属性は、動的にメニュー項目を計算する方法を与える。 属性値filter-fnは1引数の関数であること。 それが呼ばれるとき、引数はreal-bindingになる。 関数はかわりに使用するバインディングを返すこと。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.12.1.3 メニュー項目の別名

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Alias%20Menu%20Items"
"texi/elisp21/メニュー項目の別名"へのコメント(無し)

『同じ』コマンドを使いながらオン条件が異なるメニュー項目を 作れると便利なことがあります。 現状のEmacsでこれを行う最良の方法は、拡張メニュー項目を使うことです。 この機能がなかった頃には、コマンドの別名を定義し、 それをメニュー項目で使うことで可能でした。 異なるオン条件でtoggle-read-onlyを 使う2つの別名の作り方を以下に示します。

 
(defalias 'make-read-only 'toggle-read-only)
(put 'make-read-only 'menu-enable '(not buffer-read-only))
(defalias 'make-writable 'toggle-read-only)
(put 'make-writable 'menu-enable 'buffer-read-only)

メニューに別名を使うときには、 (典型的にはメニュー以外にはキーバインディングがない)別名ではなく 『本物の』コマンド名に対する等価なキーバインディングを 表示しするのがしばしば有用です。 これを行うには、別名のシンボルには nil以外の属性menu-aliasを与えます。

 
(put 'make-read-only 'menu-alias t)
(put 'make-writable 'menu-alias t)

こうすると、make-read-onlymake-writableのメニュー項目には toggle-read-onlyに対するキーバインディングが表示されます。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.12.2 メニューとマウス

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Mouse%20Menus"
"texi/elisp21/メニューとマウス"へのコメント(無し)

メニューキーマップがメニューを表示するようにする普通の方法は、 メニューキーマップをプレフィックスキーの定義にすることです。 (Lispプログラムから明示的にメニューをポップアップして、 ユーザーの選択を受け取れる。 28.15 ポップアップメニューを参照。)

プレフィックスキーがマウスイベントで終っていると、 Emacsはメニューをポップアップすることでメニューキーマップを扱います。 これで、ユーザーはマウスで選択できるようになります。 ユーザーがメニュー項目をクリックすると、 当該メニュー項目をバインディングとする文字やシンボルが イベントとして生成されます。 (メニューが複数レベルになっていたりメニューバーから開いたときには、 メニュー項目は一連のイベントを生成する。)

メニューの開始にはボタン押し下げイベントを使うのがしばしば最良です。 そうすると、ユーザーはボタンを離すことでメニュー項目を選べます。

明示的に配置すれば、1つのキーマップをメニューペインとして表示できます。 それには、各ペインに対するキーマップを作成し、 つぎに、メニューのメインのキーマップにおいて、 (各ペインの)各キーマップに対するバインディングを作ります。 なお、これらのバインディングには、 `@'で始まる項目文字列を指定します。 項目文字列の残りの部分がペインの名前になります。 この例についてはファイル`lisp/mouse.el'を参照してください。 `@'で始まらない項目文字列の他の普通のバインディングは 1つのペインにまとめられ、サブマップに対して明示的に作られた 他のペインとともに表示されます。

Xツールキットのメニューにはペインはありませんが、 そのかわりに、サブメニューがあります。 項目文字列が`@'で始まるかどうかに関わらず、 入れ子になった各キーマップがサブメニューになります。 Emacsのツールキット版では、項目文字列の先頭の`@'に関して特別なことは、 `@'がメニュー項目に表示されないことです。

個別のキーマップからも複数ペインやサブメニューを作成できます。 プレフィックスキーの完全な定義は、 さまざまな活性のキーマップ(マイナモード、ローカル、グローバル)が与える 定義を併合することで得られます。 これらのキーマップのうち複数個がメニューであるとき、 そのおのおのが別々のペイン(Xツールキットを使わないEmacs)や 別々のサブメニュー(Xツールキットを使ったEmacs)になります。 See 節 21.6 活性なキーマップ



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.12.3 メニューとキーボード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Keyboard%20Menus"
"texi/elisp21/メニューとキーボード"へのコメント(無し)

キーボードイベント(文字や関数)で終るプレフィックスキーに、 メニューキーマップであるような定義があると、 ユーザーはメニュー項目を選ぶためにキーボードを使えます。

Emacsはメニューの選択項目(バインディングの項目文字列)を エコー領域に表示します。 それらが1行に収まらなければ、 ユーザーはSPCを打つことで選択項目のつぎの行を見ることができます。 SPCを連続して使うと最終的にはメニューの最後に達し、 そうするとメニューの先頭に戻ります。 (変数menu-prompt-more-charに、このために用いる文字を指定する。 デフォルトはSPC。)

ユーザーは、メニューから望みの項目をみつけたら、 対応する文字、つまり、その項目のバインディングを持つ文字を打ちます。

Emacs類似エディタにおけるこのようなメニューの使い方は、 システムHierarkeyに触発されたからです。

Variable: menu-prompt-more-char
この変数は、メニューのつぎの行を見るために使う文字を指定する。 初期値は、SPCの文字コードの32である。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.12.4 メニューの例

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Menu%20Example"
"texi/elisp21/メニューの例"へのコメント(無し)

以下に、メニューキーマップの完全な定義の例を示します。 これは、メニューバーのメニュー`Tools'の サブメニュー`Print'の定義であり、 単純なメニュー項目を使います (see 節 21.12.1.1 単純なメニュー項目)。 まず、キーマップを作成し名前を与えます。

 
(defvar menu-bar-print-menu (make-sparse-keymap "Print"))

つぎに、メニュー項目を定義します。

 
(define-key menu-bar-print-menu [ps-print-region]
  '("Postscript Print Region" . ps-print-region-with-faces))
(define-key menu-bar-print-menu [ps-print-buffer]
  '("Postscript Print Buffer" . ps-print-buffer-with-faces))
(define-key menu-bar-print-menu [separator-ps-print]
  '("--"))
(define-key menu-bar-print-menu [print-region]
  '("Print Region" . print-region))
(define-key menu-bar-print-menu [print-buffer]
  '("Print Buffer" . print-buffer))

バインディングが『作られる対象』のシンボルに注意してください。 定義されるキー列の角括弧の内側に現れています。 そのシンボルはコマンド名に等しい場合もあればそうでない場合もあります。 これらのシンボルは『ファンクションキー』として扱われますが、 キーボード上の本物のファンクションキーではありません。 それらはメニュー項目の機能には影響ありませんが、 ユーザーがメニューから選ぶとそれらはエコー領域に『表示』され、 where-isaproposの出力にも現れます。

定義が("--")であるようなバインディングは区切り行です。 実際のメニュー項目のように、区切りにもキーシンボルがあり、 例ではseparator-ps-printです。 1つのメニューに複数の区切りがある場合、 それらはすべて異なるキーシンボルでなければなりません。

つぎには、メニュー内の2つのコマンドのオン条件を定義するコードです。

 
(put 'print-region 'menu-enable 'mark-active)
(put 'ps-print-region-with-faces 'menu-enable 'mark-active)

つぎは、このメニューを親メニューの項目に現れるようにする方法です。

 
(define-key menu-bar-tools-menu [print]
  (cons "Print" menu-bar-print-menu))

ここで使っているのは、サブメニューのキーマップ、つまり、 変数menu-bar-print-menuの値であって、 変数そのものではないことに注意してください。 menu-bar-print-menuはコマンドではないので、 このシンボルを親メニューの項目に使っても意味がありません。

同じ印刷メニューをマウスクリックに対応付けたければ、 つぎのようにしてできます。

 
(define-key global-map [C-S-down-mouse-1]
   menu-bar-print-menu)

つぎのようにして、print-regionに対して拡張メニュー項目 (see 節 21.12.1.2 拡張メニュー項目)を使うこともできます。

 
(define-key menu-bar-print-menu [print-region]
  '(menu-item "Print Region" print-region
              :enable (mark-active)))

拡張メニュー項目では、オン条件はメニュー項目自体の内側に指定します。 マークがないときにはメニューからこの項目が消えるようにするには つぎのようにします。

 
(define-key menu-bar-print-menu [print-region]
  '(menu-item "Print Region" print-region
              :visible (mark-active)))



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.12.5 メニューバー

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Menu%20Bar"
"texi/elisp21/メニューバー"へのコメント(無し)

ほとんどのウィンドウシステムでは、 各フレームにメニューバー(menu bar)、 つまり、フレームの先頭に水平方向に延びているメニューを恒久的に表示できます。 メニューバーの項目は、すべての活性なキーマップで定義された 疑似『ファンクションキー』menu-barのサブコマンドです。

メニューバーに項目を追加するには、 読者独自の疑似『ファンクションキー』を考え(これをkeyとする)、 キー列[menu-bar key]に対するバインディングを作ります。 多くの場合、バインディングはメニューキーマップであって、 メニューバーの項目上でボタンを押すと別のメニューへ至るようにします。

メニューバーに対する同じ疑似ファンクションキーを 複数の活性なキーマップで定義していても、1つの項目だけが表示されます。 ユーザーがメニューバーの当該項目をクリックすると、 当該項目のすべてのサブコマンド、つまり、 グローバルのサブコマンド、ローカルのサブコマンド、 マイナモードのサブコマンドを含む1つの複合メニューが表示されます。

メニューバーの内容を決定する際には、 通常、変数overriding-local-mapは無視されます。 つまり、overriding-local-mapnilであるときに 活性になるキーマップからメニューバーを計算します。 See 節 21.6 活性なキーマップ

フレームにメニューバーを表示するには、 フレームのパラメータmenu-bar-linesが0より大きい必要があります。 Emacsはメニューバーそのものには1行だけ使います。 読者が2行以上を指定すると、 残りの行はフレームのウィンドウとメニューバーを区切る行になります。 menu-bar-linesの値には1か2を勧めます。 See 節 28.3.3 ウィンドウフレームのパラメータ

メニューバーの項目の設定例を示します。

 
(modify-frame-parameters (selected-frame)
                         '((menu-bar-lines . 2)))

;; (プロンプト文字列を持つ)メニューキーマップを作り
;; それをメニューバーの項目の定義にする
(define-key global-map [menu-bar words]
  (cons "Words" (make-sparse-keymap "Words")))

;; このメニュー内のサブコマンドを定義する
(define-key global-map
  [menu-bar words forward]
  '("Forward word" . forward-word))
(define-key global-map
  [menu-bar words backward]
  '("Backward word" . backward-word))

グローバルキーマップに作ったメニューバー項目を ローカルキーマップで取り消すには、 ローカルキーマップの当該疑似ファンクションキーのバインディングを undefinedで再バインドします。 たとえば、つぎのようにしてdiredはメニューバーの項目`Edit'を抑制します。

 
(define-key dired-mode-map [menu-bar edit] 'undefined)

editは、メニューバー項目`Edit'に対して グローバルキーマップで使う疑似ファンクションキーです。 グローバルなメニューバー項目を抑制する主な理由は、 モード固有の項目向けに場所を確保するためです。

Variable: menu-bar-final-items
通常、メニューバーは、グローバルな項目に ローカルキーマップで定義された項目を続けて表示する。

この変数は、通常の順ではなくメニューバーの底に表示する項目に 対する疑似ファンクションキーのリストを保持する。 デフォルト値は(help-menu)であり、 したがって、ローカルのメニュー項目に続いて、 メニュー項目`Help'はメニューバーの最後に通常表示される。

Variable: menu-bar-update-hook
このノーマルフックは、 ユーザーがメニューバーをクリックするたびに、 サブメニューを表示するまえに実行される。 これを用いて、内容が変化するサブメニューを更新できる。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

21.12.6 メニューの修正

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Modifying%20Menus"
"texi/elisp21/メニューの修正"へのコメント(無し)

既存のメニューに新たな項目を挿入するとき、 メニューの既存の項目の特定の場所に挿入したいでしょう。 define-keyで項目を追加すると、通常、メニューの先頭に入ります。 メニューのそれ以外の場所に挿入するには、 define-key-afterを使います。

Function: define-key-after map key binding after
keyに対するバインディングbindingmap内に作る。 ただし、map内でのバインディングの位置は、 イベントafterに対するバインディングのあとにする。 引数keyは長さ1、つまり、1要素のみのベクトルか文字列であること。 しかし、afterは1つのイベント型、つまり、 シンボルか文字であり列ではないこと。 新たなバインディングはafterに対するバインディングのうしろに入る。 aftertであると、新たなバインディングは最後、 つまり、キーマップの末尾に入る。

例を示す。

 
(define-key-after my-menu [drink]
                  '("Drink" . drink-command) 'eat)

これは、疑似ファンクションキーDRINKに対するバインディングを作り、 EATに対するバインディングのあとに入れる。

shellモードのメニュー`Signals'において、 項目breakのあとに項目`Work'を入れる方法はつぎのとおりである。

 
(define-key-after
  (lookup-key shell-mode-map [menu-bar signals])
  [work] '("Work" . work-command) 'break)

[ << ] [ >> ]           [表紙] [目次] [索引] [検索] [上端 / 下端]