[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
読者がEmacsを起動すると、Emacsはほぼただちにエディタコマンドループ (editor command loop)に入ります。 このループは、キー列を読み取り、それらの定義を実行し、結果を表示します。 本章では、これがどのように行われるのか、および、 Lispプログラムからこれを行うためのサブルーティンについて述べます。
20.1 コマンドループの概要 | How the command loop reads commands. | |
20.2 コマンドの定義 | Specifying how a function should read arguments. | |
20.3 対話的呼び出し | Calling a command, so that it will read arguments. | |
20.4 コマンドループからの情報 | Variables set by the command loop for you to examine. | |
20.5 入力イベント | What input looks like when you read it. | |
20.6 入力の読み取り | How to read input events from the keyboard or mouse. | |
20.7 特殊イベント | Events processed immediately and individually. | |
20.8 時間待ちと入力待ち | Waiting for user input or elapsed time. | |
20.9 中断 | How C-g works. How to catch or defer quitting. | |
20.10 前置コマンド引数 | How the commands to set prefix args work. | |
20.11 再帰編集 | Entering a recursive edit, and why you usually shouldn't. | |
20.12 コマンドを禁止する | How the command loop handles disabled commands. | |
20.13 コマンド履歴 | How the command history is set up, and how accessed. | |
20.14 キーボードマクロ | How keyboard macros are implemented. |
コマンドループがまず始めに行うことはキー列、
つまり、コマンドへ変換されるイベント列を読むことです。
これには関数read-key-sequence
を呼び出します。
読者のLispコードでもこの関数を呼び出せます(see section 20.6.1 キー列の入力)。
Lispプログラムでは、read-event
(see section 20.6.2 単一イベントの読み取り)で
低レベルの入力を行ったり、
discard-input
(see section 20.6.4 その他のイベント入力機能)で
処理待ち中の入力を破棄できます。
キー列は現在活性なキーマップを介してコマンドに変換されます。
この処理方法についてはSee section 21.7 キー探索。
この結果は、キーボードマクロであるか、
対話的に呼び出し可能な関数であるはずです。
キーがM-xであると、別のコマンドの名前を読み取り、
そのコマンドを呼び出します。
これはコマンドexecute-extended-command
(see section 20.3 対話的呼び出し)で
処理されます。
コマンドを実行するには、まず、その引数を読む必要があります。
これは、command-execute
(see section 20.3 対話的呼び出し)を呼び出して
行います。
Lispで書かれたコマンドでは、
interactive
指定が引数の読み方を指示します。
前置引数(see section 20.10 前置コマンド引数)を使ったり、
プロンプトを表示してミニバッファ(see section 19. ミニバッファ)から読みます。
たとえば、コマンドfind-file
には、
ミニバッファからファイル名を読むことを指示した
interactive
指定があります。
コマンドの関数本体ではミニバッファを使いません。
このコマンドをLispコードから関数として呼び出す場合、
通常のLisp関数の引数としてファイル名文字列を指定する必要があります。
コマンドが文字列やベクトル(つまり、キーボードマクロ)である場合、
execute-kbd-macro
を用いてそれらを実行します。
読者自身がこの関数を呼び出してもかまいません(see section 20.14 キーボードマクロ)。
動作中のコマンドの実行を止めるには、C-gを打ちます。 この文字は中断(quitting)を引き起こします(see section 20.9 中断)。
this-command
にはこれから実行するコマンドが保持され、
last-command
には直前のコマンドがある。
see section 22.6 フック。
this-command
には実行し終えたばかりのコマンドがあり、
last-command
にはその前のコマンドがある。
see section 22.6 フック。
pre-command-hook
やpost-command-hook
の実行中は、
中断を禁止します。
これらのフックの1つを実行中にエラーが起きると、
エラーの無限ループを防ぐために、
フックの実行を終了しフック変数をnil
にします。
Lisp関数の本体に、スペシャルフォームinteractive
を呼び出す
フォームがトップレベルにあると、Lisp関数はコマンドになります。
このフォームは実際に呼び出されてもなにもしませんが、
このフォームがあることで、対話的に呼び出せることを表します。
その引数が、対話的呼び出しにおける引数の読み方を制御します。
20.2.1 interactive の使い方 | General rules for interactive . | |
20.2.2 interactive のコード文字 | The standard letter-codes for reading arguments in various ways. | |
20.2.3 interactive の使用例 | Examples of how to read interactive arguments. |
interactive
の使い方
本節では、Lisp関数を対話的に呼び出し可能なコマンドにするフォーム
interactive
の書き方について述べます。
他の関数と同様に、コマンドはLispプログラムからも呼び出せるが、 その場合、呼び出し側が引数を渡し、arg-descriptorにはなんの効果もない。
フォームinteractive
が効果を発揮するのは、
コマンドループ(実際にはサブルーティンcall-interactively
)が
関数を呼び出すまえに関数定義を走査してこのフォームを探すからである。
関数が呼び出されると、フォームinteractive
を含めて
その本体のフォームが実行されるが、そのとき、
interactive
は引数を評価せずに単にnil
を返す。
引数arg-descriptorには3つの可能性があります。
nil
。
この場合、コマンドは引数なしで呼ばれる。
コマンドが1つ以上の引数を必要とする場合、これはただちにエラーになる。
この式が(ミニバッファを使うことを含めて)キーボード入力を読む場合には、 入力を読むまえのポイントの整数値やマークは、 入力を読んだあとでは正しくない可能性があることに留意すること。 カレントバッファがサブプロセスの出力を受け取る可能性があるからである。 コマンドが入力を待っているあいだにサブプロセスの出力が到着すると、 ポイントやマークを再配置する可能性がある。
してはいけないことの例を示す。
(interactive (list (region-beginning) (region-end) (read-string "Foo: " nil 'my-history))) |
キーボード入力を読み終えてからポイントやマークを調べることで、 問題を回避する。
(interactive (let ((string (read-string "Foo: " nil 'my-history))) (list (region-beginning) (region-end) string))) |
(interactive "bFrobnicate buffer: ") |
コード文字`b'は、補完を用いて既存のバッファ名を読むことを指示する。 バッファ名は、コマンドに渡される唯一の引数である。 文字列の残りはプロンプトである。
文字列内に改行文字があると、それはプロンプトを終える。 その部分で文字列が終らないときには、 文字列の残りの部分には、別の引数を指定するコード文字やプロンプトがある。 このようにして、何個の引数でも指定できる。
プロンプトの文字列では、プロンプト内の(第1引数から始まる)
まえの引数値を含めるために`%'を使える。
これはformat
(see section 4.7 文字列の書式付け)を用いて行う。
たとえば、既存バッファの名前を読み、
続けてそのバッファに与える新たな名前を読むにはつぎのようにする。
(interactive "bBuffer to rename: \nsRename buffer %s to: ") |
文字列の最初の文字が`*'である場合、 バッファが読み出し専用であるとエラーを通知する。
文字列の最初の文字が`@'であり、 コマンドを起動したキー列にマウスイベントが含まれる場合、 コマンドを実行するまえに それらのイベントの最初のものに関連したウィンドウを選択する。
`*'と`@'は同時に使え、その順序は関係ない。 引数の実際の読み取りはプロンプトの (`*'でも`@'でもない最初の文字で始まる)残りの部分で制御される。
interactive
のコード文字 以下に述べるコード文字の説明では、 つぎに定義するいくつかのキーワードを含みます。
completing-read
を使って引数を読むため、
TAB、SPC、RETは名前を補完する
(see section 19.5 補完)。
?は補完候補のリストを表示する。
コード文字はプロンプト文字列を使わないが、 この文字が文字列の最後の文字でない場合には改行を続けること。
以下に、interactive
に使うコード文字を説明します。
fboundp
を満たすシンボル)。
「既存」、「補完」、「プロンプト」。
commandp
を満たすシンボル)。
「既存」、「補完」、「プロンプト」。
default-directory
(see section 37.3 オペレーティングシステム環境)。
「既存」、「補完」、「デフォルト」、「プロンプト」。
1つのコマンドの対話指定で複数回`e'を使える。 コマンドを起動したキー列がn個のリストであるイベントである場合、 n番目の`e'は、n番目のそのようなイベントを与える。 `e'では、 ファンクションキーやASCII文字などのリストでないイベントは数えない。
default-directory
。
「既存」、「補完」、「デフォルト」、「プロンプト」。
nil
を与える。
「入出力なし」。
この種の入力は、describe-key
やglobal-set-key
などの
コマンドで使われる。
user-variable-p
を満たす)。
see section 19.5.4 高レベルの補完関数。
「既存」、「補完」、「プロンプト」。
nil
。
see section 32.10 コーディングシステム。
「補完」、「既存」、「プロンプト」。
nil
を与える。
「補完」、「既存」、「プロンプト」。
interactive
の使用例
ここではinteractive
の例を示します。
(defun foo1 () ; |
コマンドループでは、キー列をコマンドへ変換し終えると、
関数command-execute
を用いてそのコマンドを起動します。
コマンドが関数であれば、command-execute
は引数を読み取り、
コマンドを呼び出すcall-interactively
を呼びます。
読者自身がこれらの関数を呼び出してもかまいません。
t
を返す。
さもなければnil
を返す。
対話的呼び出しが可能なオブジェクトには、
(キーボードマクロとして扱われる)文字列やベクトル、
トップレベルでinteractive
を呼び出しているラムダ式、
そのようなラムダ式をコンパイルしたバイトコード関数オブジェクト、
対話的(autoload
の4番目の引数がnil
以外)
と宣言された自動ロードオブジェクト、
一部の基本関数が含まれる。
シンボルの関数定義がcommandp
を満たせば、
シンボルもcommandp
を満たす。
キーやキーマップはコマンドではない。 それらはコマンドを探すために使われる(see section 21. キーマップ)。
commandp
の実用的な使用例については、
23.2 説明文字列の参照のdocumentation
を参照。
record-flagがnil
以外であると、
コマンドとその引数を無条件にリストcommand-history
に追加する。
さもなければ、引数を読むために
コマンドがミニバッファを使った場合にのみ追加する。
see section 20.13 コマンド履歴。
もし引数keysを指定すると、コマンドがそれを起動したイベントを 問い合わせたときに与えるイベント列を指定する。
commandp
を満たすこと。
つまり、対話的呼び出し可能な関数かキーボードマクロであること。
command
が文字列やベクトルであると、
execute-kbd-macro
で実行される。
関数であると、省略可能なrecord-flagとともに関数を
call-interactively
に渡す。
シンボルは、その関数定義を使って処理する。
autoload
で定義されたシンボルは、
対話的呼び出し可能な関数と宣言されていればコマンドとみなす。
そのような定義では、指定されたライブラリをロードしてから
シンボルの定義を再検査して処理する。
もし引数keysを指定すると、コマンドがそれを起動したイベントを 問い合わせたときに与えるイベント列を指定する。
completing-read
(see section 19.5 補完)を使って
ミニバッファでコマンド名を読む。
そしてcommand-execute
を使って指定されたコマンドを実行する。
コマンドが返した値がexecute-extended-command
の値になる。
コマンドが前置引数を必要とする場合、prefix-argumentの値を受け取る。
execute-extended-command
が対話的に呼ばれた場合、
現在の生の前置引数がprefix-argumentとして使われ、
それが実行するコマンドへ渡される。
execute-extended-command
は通常M-xに定義付けられ、
そのため、プロンプトとして文字列`M-x 'を使う。
(execute-extended-command
を起動するために使われた
イベントをプロンプトにするべきであるが、
それを実装するのは手間がかかる。)
もし前置引数を指定すると、その内容もプロンプトの一部になる。
(execute-extended-command 1) ---------- Buffer: Minibuffer ---------- 1 M-x forward-word RET ---------- Buffer: Minibuffer ---------- => t |
interactive-p
の呼び出し)を含んだ関数が
call-interactively
で対話的に呼び出されるとt
を返す。
(Lispからcall-interactively
が呼び出されても、
エディタコマンドループが直接呼び出しても違いはない。)
これを含んだ関数がLispの評価(あるいはapply
やfuncall
)で
呼び出された場合は、対話的呼び出しではない。
interactive-p
のもっとも一般的な用途は、
情報メッセージを表示するかどうか決めることです。
特別な例外として、キーボードマクロを実行中にはいつでも、
interactive-p
はnil
を返します。
これは情報メッセージを省いてマクロの実行を速くするためです。
つぎのように使います。
(defun foo () (interactive) (when (interactive-p) (message "foo"))) => foo (defun bar () (interactive) (setq foobar (list (foo) (interactive-p)))) => bar ;; M-x fooと打つ -| foo ;; M-x barと打つ ;; これはなにも表示しない foobar => (nil t) |
この種のことを行う別の方法は、コマンドを
対話的呼び出しではnil
以外の値になる引数print-message
を
取るようにし、その引数がnil
以外になるようなinteractive
指定を
使うことです。
つぎのようにします。
(defun foo (&optional print-message) (interactive "p") (when print-message (message "foo"))) |
`p'で与えられる数値前置引数はけっしてnil
になりません。
エディタコマンドループは、自身や実行中のコマンドのために 状態記録を数個のLisp変数に設定します。
コマンドが後続のコマンドに対する前置引数を指定する場合を除いて、
コマンドからコマンドループへ戻るとthis-command
から値をコピーする。
この変数は現在の端末に対してつねにローカルであり、 バッファに対してローカルにはならない。 see section 28.2 複数ディスプレイ。
last-command
と同様にEmacsがこの変数に設定するが、
Lispプログラムではけっして変更しない。
last-command
と同様に、通常は関数定義を持つシンボルである。
コマンドループは、コマンドを実行する直前にこの変数に設定し、
コマンドが終了すると(コマンドが後続のコマンドに対する
前置引数を指定する場合を除いて)
この値をlast-command
にコピーする。
後続のコマンドに対するフラグとして
実行中にこの変数に設定するコマンドもある。
特に、テキストをキルする関数群はthis-command
にkill-region
を
設定して、直後に続くキルコマンドでは
キルしたテキストをまえのキルに追加するようにする。
特定のコマンドがエラーを起こした場合に
直前のコマンドとは認識されたくない場合には、
読者はそのコマンドがそれを防ぐように書く必要があります。
1つの方法は、以下に示すように、
コマンドの始めでthis-command
にt
を設定し、
コマンドの終りでthis-command
に正しい値を戻します。
(defun foo (args...) (interactive ...) (let ((old-this-command this-command)) (setq this-command t) ...do the work... (setq this-command old-this-command))) |
let
でthis-command
を束縛しません。
というのは、エラーがあるとlet
は古い値を復元するからです。
これこそがここでは避けたいlet
の機能です。
(this-command-keys) ;; C-u C-x C-eを使ってこの式を評価する => "^U^X^E" |
this-command-keys
と同様だが、つねにベクトルでイベントを返すため、
文字列に入力イベントを保持する際の複雑さを扱う必要がない
(see section 20.5.14 キーボードイベントを文字列で保持する)。
この変数の1つの用途は、
メニューをポップアップする位置をx-popup-menu
に指示することである。
y-or-n-p
(see section 19.6 Yes/Noの問い合わせ)も内部的に使っている。
self-insert-command
が使うことである。
last-command-event ;; C-u C-x C-eを使ってこの式を評価する => 5 |
C-eのASCIIコードは5なので、値は5である。
Emacs 18版との互換性のために別名last-command-char
がある。
Emacsのコマンドループは、キーボードやマウスのユーザーの操作を表す 入力イベント(input event)列を読みます。 キーボード操作に対するイベントは、文字かシンボルです。 マウスイベントはつねにリストです。 本節では、入力イベントの表現方法やその意味を詳しく説明します。
nil
以外を返す。
任意のシンボルがイベントやイベント型として使われることに注意。
eventp
は、Lispのプログラムコードがシンボルを
イベントとして使うかどうか区別できない。
そのかわりに、シンボルが、Emacsの現在のセッションにおいて入力として読まれた
イベントに使われたことがあるかどうかを区別する。
シンボルがそのように使われたことがなければ、
eventp
はnil
を返す。
20.5.1 キーボードイベント | Ordinary characters--keys with symbols on them. | |
20.5.2 ファンクションキー | Function keys--keys with names, not symbols. | |
20.5.3 マウスイベント | Overview of mouse events. | |
20.5.4 クリックイベント | Pushing and releasing a mouse button. | |
20.5.5 ドラッグイベント | Moving the mouse before releasing the button. | |
20.5.6 ボタン押し下げイベント | A button was pushed and not yet released. | |
20.5.7 繰り返しイベント | Double and triple click (or drag, or down). | |
20.5.8 モーションイベント | Just moving the mouse, not pushing a button. | |
20.5.9 フォーカスイベント | Moving the mouse between frames. | |
20.5.10 ウィンドウシステムのその他のイベント | Other events window systems can generate. | |
20.5.11 イベントの例 | Examples of the lists for mouse events. | |
20.5.12 イベントの分類 | Finding the modifier keys in an event symbol. Event types. | |
20.5.13 イベントの参照 | Functions to extract info from events. | |
20.5.14 キーボードイベントを文字列で保持する | Special considerations for putting keyboard character events in a string. |
キーボードからは2種類の入力があります。 普通のキーとファンクションキーです。 普通のキーは文字に対応します。 それらが生成するイベントは、Lispでは文字として表現されます。 文字イベントのイベント型は文字自身(整数)です。 20.5.12 イベントの分類を参照してください。
入力文字イベントは、0から524287までの基本コード(basic code)と 以下の修飾ビット(modifier bit)の任意の組み合わせです。
C-aなどのASCIIコントロール文字には 独自の特別な基本コードがあるため、 Emacsはそれを表すための特別なビットを必要としない。 つまり、C-aのコードは単に1である。
しかし、コントロールキーを使った%などの ASCIIにないコントロールとの組み合わせを打った場合、 得られる数値は%のコードに 2**26 を加えたものである (端末で非ASCIIのコントロール文字を扱えるとして)。
英文字では、基本コードそのものが大文字か小文字かを表す。 数字文字と区切り文字では、 シフトキーは異なる基本コードのまったく異なる文字を選ぶ。 可能な限りASCII文字集合ですませるために、 これらの文字に対しては、Emacsはビット 2**25 を使わない。
しかし、ASCIIではC-AとC-aを区別できないため、 Emacsは、C-Aではビット 2**25 を使うが、C-aではこのビットを使わない。
読者のプログラム内では、
特定の修飾ビットの値を明示することは避けるのが最良です。
文字の修飾ビットを検査するには、
関数event-modifiers
(see section 20.5.12 イベントの分類)を使います。
キーバインディングを作るときには、
(`\C-'、`\M-'などの)修飾ビットを伴う文字の
入力表現を使います。
define-key
でキーバインディングを作るときには、
文字の指定には(control hyper ?x)
のようなリストを使います
(see section 21.9 キーバインディングの変更)。
関数event-convert-list
は、そのようなリストを
イベント型に変換します(see section 20.5.12 イベントの分類)。
ほとんどのキーボードには、ファンクションキー(function key)、
つまり、文字ではない名前や記号のキーがあります。
Emacs Lispでは、ファンクションキーはシンボルで表現されます。
シンボルの(小文字の)名前がファンクションキーのラベルです。
たとえば、F1というラベルのキーを押すと、
入力ストリームにはシンボルf1
が置かれます。
ファンクションキーイベントのイベント型は、イベントシンボルそれ自身です。 See section 20.5.12 イベントの分類。
ファンクションキーに対するシンボル命名慣習の特例を以下に示します。
backspace
, tab
, newline
, return
, delete
ASCIIでは、C-iとTABは同じ文字である。
これらを区別できる端末では、前者を整数9、後者をシンボルtab
と
表現することで、EmacsはLispプログラムに区別を伝える。
ほとんどの場面では、これら2つを区別しても有用ではない。
そのため、通常、function-key-map
(see section 37.8.2 入力イベントの変換)は、
tab
を9に対応付けるようには設定してある。
したがって、文字コード9(文字C-i)に対するキーバインディングは
tab
にも適用される。
この種の他のシンボルについても同様である。
関数read-char
も同様にこれらのイベントを文字に変換する。
ASCIIでは、BSは実際にはC-hである。
しかし、backspace
は文字コード127(DEL)に変換され、
文字コード8(BS)には変換されない。
ほとんどのユーザーはこれを好む。
left
, up
, right
, down
kp-add
, kp-decimal
, kp-divide
, ...
kp-0
, kp-1
, ...
kp-f1
, kp-f2
, kp-f3
, kp-f4
kp-home
, kp-left
, kp-up
, kp-right
, kp-down
home
、left
、...のキーに変換する。
kp-prior
, kp-next
, kp-end
, kp-begin
, kp-insert
, kp-delete
ファンクションキーにもALT、CTRL、HYPER、 META、SHIFT、SUPERの修飾キーを使えます。 それらを表現するには、シンボル名に接頭辞を付けます。
したがって、METAを押し下げたF3キーのシンボルはM-f3
です。
複数の接頭辞を使うときには、アルファベット順に書くことを勧めますが、
キーバインディングの探索関数や修飾関数の引数では関係ありません。
Emacsでは4種類のマウスイベント、つまり、クリックイベント、ドラッグイベント、 ボタン押し下げイベント、モーションイベントを扱えます。 すべてのマウスイベントは、リストで表現します。 リストのCARはイベント型であり、 どの修飾キーとともにどのマウスボタンを使ったかを表します。 イベント型では、ダブル(連続2回)/トリプル(連続3回)の 押し下げも区別できます(see section 20.5.7 繰り返しイベント)。 リストの残りの要素は、位置情報と時間情報です。
キーの探索では、イベント型のみが意味を持ちます。
型が同じであれば、異なるイベントでも同じコマンドを実行します。
コマンドでは、対話指定コード`e'を用いてイベントの完全な値を参照できます。
See section 20.2.2 interactive
のコード文字。
マウスイベントで始まるキー列は、カレントバッファのキーマップではなく、 マウスが入っているウィンドウのバッファのキーマップを用いて読まれます。 つまり、あるウィンドウ内でクリックしても、 当該ウィンドウやバッファを選択するとは限らず、 その動作はキー列のコマンドバインディングで完全に制御されます。
ユーザーがマウスのボタンを同じ場所で押し下げてから離すと、 クリック(click)イベントが生成されます。 マウスクリックイベントはつぎの形式です。
(event-type (window buffer-pos (x . y) timestamp) click-count) |
通常の各要素の意味はつぎのとおりです。
mouse-1
、mouse-2
、...の1つである。
ファンクションキーの場合と同様に、 アルト、コントロール、ハイパー、メタ、シフト、スーパーの 修飾キーを表す接頭辞`A-'、`C-'、`H-'、`M-'、 `S-'、`s-'も使える。
このシンボルはイベントのイベント型としての役割も果たす。
キーバインディングはイベント型でイベントを指定する。
したがって、mouse-1
に対するキーバインディングは、
イベント型event-typeがmouse-1
であるすべてのイベントに適用される。
(0 . 0)
とした
クリック位置のピクセル単位の座標。
モード行やスクロールバーなどのスクリーンの特別な部分で発生したイベントでは、 buffer-pos、xとyの意味は少々異なります。
スクロールバーの内側でのクリックでは、
buffer-posはシンボルvertical-scroll-bar
か
horizontal-scroll-bar
であり、
(x . y)
は(portion . whole)
に
置き換えられます。
ここで、portionはスクロールバーの先頭や左端からのクリック位置、
wholeはスクロールバー全体の長さです。
モード行やウィンドウwindowを右隣のものと区切る
縦方向の区切り行の内側では、
buffer-posはシンボルmode-line
かvertical-line
です。
モード行では、yは意味のあるデータではありません。
縦方向の区切り行では、xは意味のあるデータではありません。
1つの特別な場面では、 buffer-posは単一のシンボルではなく(上に述べた1つの)シンボルを 含んだリストになります。 イベントに対する仮想的なプレフィックスキーを入力ストリームに挿入すると このようになります。 See section 20.6.1 キー列の入力。
Emacsには、ドラッグイベントがあります。 ユーザーがマウスボタンを押し下げてから、 ボタンを離すまえに別の文字位置へマウスを動かすと ドラッグ(drag)イベントが発生します。 マウスのすべてのイベントのように、Lispではドラッグイベントは リストとして表現されます。 つぎのように、リストは開始マウス位置と終了位置を記録しています。
(event-type (window1 buffer-pos1 (x1 . y1) timestamp1) (window2 buffer-pos2 (x2 . y2) timestamp2) click-count) |
ドラッグイベントでは、シンボルevent-typeの名前には
接頭辞`drag-'が付きます。
たとえば、ボタン2を押し下げてマウスをドラッグすると
イベントdrag-mouse-2
が生成されます。
イベントの2番目と3番目の要素は、ドラッグの開始位置と終了位置を与えます。
なお、データにはクリックイベントと同じ意味があります(see section 20.5.4 クリックイベント)。
ドラッグイベントかどうかを区別せずに、
マウスの任意のイベントの2番目の要素は同じ方法で参照できます。
接頭辞`drag-'は、 `C-'や`M-'のような修飾キー接頭辞に続きます。
read-key-sequence
が、
キーバインディングを持たないドラッグイベントを受け取り、かつ、
それに対応するクリックイベントにはバインディングがある場合、
ドラッグイベントの開始位置をクリック位置とするクリックイベントに変換します。
つまり、望まなければ、読者はクリックイベントとドラッグイベントを区別する
必要がありません。
クリックイベントとドラッグイベントは、 ユーザーがマウスボタンを離したときに発生します。 ボタンを離すまではクリックとドラッグを区別する方法がないため、 ボタンを離すまで発生しえません。
ボタンを押し下げたらただちに動作を始めたい場合には、 読者はボタン押し下げ(button-down)イベントを処理する必要があります。 (8) ボタンを押し下げるとただちに発生します。 それらは、シンボルevent-typeの名前に 接頭辞`down-'があることを除けば、 クリックイベント(see section 20.5.4 クリックイベント)とまったく同じリストで表現されます。 接頭辞`down-'は、`C-'や`M-'のような修飾キー接頭辞に続きます。
関数read-key-sequence
は、
コマンドバインディングを持たないボタン押し下げイベントを無視します。
したがって、Emacsのコマンドループもそれらを無視します。
つまり、読者がボタン押し下げイベントでなにかをしたいのでなければ、
読者はボタン押し下げイベントを定義する必要はありません。
ボタン押し下げイベントを定義する理由は、
ボタンが離されるまで(モーションイベントを読んで)マウスの動きを
追跡するためです。
See section 20.5.8 モーションイベント。
マウスを動かさずに同一のマウスボタンを素早く連続して押し下げると、 Emacsは2回目以降の押し下げに対して 特別な繰り返し(repeat)マウスイベントを生成します。
もっとも一般的な繰り返しイベントはダブルクリック(double-click) イベントです。 ボタンを2回クリックすると、Emcasはダブルクリックイベントを生成します。 (他のすべてのクリックイベントのように)読者がボタンを離したときに イベントが生成されます。
ダブルクリックイベントのイベント型には、接頭辞`double-'が含まれます。
したがって、metaを押し下げて2番目のボタンをダブルクリックすると、
LispプログラムにはM-double-mouse-2
が送られます。
ダブルクリックイベントにバインディングがなければ、
対応する普通のクリックイベントを用いて実行します。
したがって、実際に利用したくない限りは、
読者はダブルクリック機能に注意する必要はありません。
ユーザーがダブルクリックすると、Emacsはまず普通のクリックイベントを生成し、 つぎにダブルクリックイベントを生成します。 したがって、ダブルクリックイベントのコマンドバインディングでは、 すでに普通のクリックコマンドが動作済みであると仮定して設計する必要があります。 普通のクリックの結果をもとに望みのダブルクリックの結果を得るようにします。
普通のクリックの意味にダブルクリックの意味を 『追加』するようにすると便利です。 ダブルクリックのユーザーインターフェイスはこのようにすることを勧めます。
ボタンをクリックして、ふたたびボタンを押し下げてそのままマウスを動かすと、 最終的にボタンを離した時点で、ダブルドラッグ(double-drag)イベントが 生成されます。 そのイベント型には`drag'のかわりに`double-drag'が含まれます。 ダブルドラッグイベントにバインディングがなければ、 Emacsは普通のドラッグイベントとしてバインディングを探します。
ダブルクリックイベントやダブルドラッグイベントを生成するまえに、 ユーザーがボタンを2回目に押し下げたとき、 Emacsはダブルダウン(double-down)イベントを生成します。 このイベント型には`down'のかわりに`double-down'が含まれます。 ダブルダウンイベントにバインディングがなければ、 Emacsは普通のボタン押し下げイベントとしてバインディングを探します。 どちらでもバインディングがみつからなければ、ダブルダウンイベントは無視します。
まとめると、ボタンをクリックしてただちに再度ボタンを押し下げると、 Emacsは、はじめのクリックに対してボタン押し下げイベントと クリックイベントを生成し、 再度ボタンを押し下げるとダブルダウンイベントを生成し、 最後にダブルクリックイベントかダブルドラッグイベントを生成します。
ボタンを2回クリックしてから再度押し下げる操作を素早く行うと、 Emacsは、トリプルダウン(triple-down)イベントに続けて トリプルクリック(triple-click)イベントか トリプルドラッグ(triple-drag)イベントを生成します。 これらのイベント型には`double'のかわりに`triple'が含まれます。 トリプルのイベントにバインディングがなければ、 Emacsは対応するダブルのイベントを使います。
ボタンを3回以上クリックしてから再度押し下げると、 3回目以降の押し下げに対するイベントはすべてトリプルのイベントです。 Emacsは、クアドラプル(4回)、クインタプル(5回)、…などの イベントは生成しません。 しかし、イベントリストを調べれば、ボタンを何回押したか正確にわかります。
double-click-time
の値未満(ミリ秒)である必要がある。
double-click-time
にnil
を設定すると、
連続したクリックの検出を禁止する。
t
を設定すると時間制限をなくし、
Emacsは連続したクリックの検出を位置だけで行う。
Emacsは、ボタン操作を伴わないマウスの移動を表す マウスモーション(mouse motion)イベントを生成することがあります。 マウスモーションイベントはつぎのようなリストで表現されます。
(mouse-movement (window buffer-pos (x . y) timestamp)) |
リストの2番目の要素は、クリックイベント(see section 20.5.4 クリックイベント)と同様に、 マウスの現在位置を表します。
スペシャルフォームtrack-mouse
により、
その本体の内側ではモーションイベントの生成を可能にできます。
フォームtrack-mouse
の外側では、
Emacsはマウスの移動のみに対するイベントを生成しないので、
それらのイベントは現れません。
See section 28.13 マウスの追跡。
ウィンドウシステムは、どのウィンドウにキーボード入力を与えるかを ユーザーが制御するための一般的な方法を提供します。 ウィンドウを選ぶことをフォーカス(focus)と呼びます。 ユーザーがEmacsのフレームを切り替える操作を行うと、 フォーカスイベント(focus event)が生成されます。 グローバルキーマップにあるフォーカスイベントの普通の定義は、 Emcasの新たなフレームを選択するようになっていて、 これはユーザーが期待することです。 See section 28.9 入力フォーカス。
Lispでは、フォーカスイベントはつぎのようなリストで表現されます。
(switch-frame new-frame) |
ここで、new-frameは切り替え先のフレームです。
Xのほとんどのウィンドウマネージャは、 マウスをウィンドウへ入れるだけで当該ウィンドウにフォーカスが設定される ようになっています。 フレームにマウスが入るとカーソルの形状を変更するので、 Emacsでもそのようにします。 しかし、Lispプログラムにとっては、 なんらかの入力が到着するまではフォーカスの変更について知る必要がありません。 そのため、ユーザーが実際にキーボードのキーを打つか 新たなフレームでマウスボタンを押し下げたときだけ、 Emacsはフォーカスイベントを生成します。 フレーム間でマウスを動かしただけでは、フォーカスイベントは生成されません。
キー列の途中にフォーカスイベントが現れると、キー列を乱します。 そのため、Emacsはキー列の途中にはフォーカスイベントを生成しません。 ユーザーがキー列の途中で、つまり、 プレフィックスキーのあとでフォーカスを変更すると、 複数イベントのキー列のまえかうしろにフォーカスイベントを移動し、 途中には現れないようにEmacsはイベントの順序を並び替えます。
ウィンドウシステム内で起きたことを表す他のイベントもあります。
(delete-frame (frame))
イベントdelete-frame
の標準定義はフレームframeの削除である。
(iconify-frame (frame))
ignore
である。
というのは、フレームはすでにアイコンになっているので、
Emacsが行うことはなにもないからである。
このイベント型の目的は、
必要ならばその種のイベントを読者が追跡できるようにしておくことである。
(make-frame-visible (frame))
ignore
である。
というのは、フレームはすでに見えるようになっているので、
Emacsが行うことはなにもないからである。
(mouse-wheel position delta)
要素deltaはホイールの回転方向と回転量である。 その絶対値はホイールを回すごとに増加する数である。 負のdeltaは、逆転、つまり、ユーザーへ近付く方向への回転を表し、 正のdeltaは、順転、つまり、ユーザーから遠ざかる方向への回転を表す。
要素positionはイベントの発生位置を表し、 マウスクリックイベントで使われる形式と同じである。
この種のイベントは、ある種のシステムでのみ生成される。
(drag-n-drop position files)
要素positionはイベントの発生位置を表し、 マウスクリックイベントで使われる形式と同じであり、 要素filesはドラッグ&ドロップされたファイル名のリストである。 このイベントを扱う通常の処理は、それらのファイルを訪問することである。
現状では、この種のイベントは、ある種のシステムでのみ生成される。
これらのイベントがキー列の途中、つまり、 プレフィックスキーのうしろに現れると、 複数イベントのキー列のまえかうしろに当該イベントを移動し、 途中には現れないようにEmacsはイベントの順序を並び替えます。
ユーザーが同じ場所でマウスの左ボタンを押し下げてから離すと、 つぎのようなイベント列が生成されます。
(down-mouse-1 (#<window 18 on NEWS> 2613 (0 . 38) -864320)) (mouse-1 (#<window 18 on NEWS> 2613 (0 . 38) -864180)) |
コントロールキーを押し下げた状態で、 ユーザーがマウスの2番目のボタンを押し下げ、 マウスをつぎの行へドラッグすると、つぎのような2つのイベントが生成されます。
(C-down-mouse-2 (#<window 18 on NEWS> 3440 (0 . 27) -731219)) (C-drag-mouse-2 (#<window 18 on NEWS> 3440 (0 . 27) -731219) (#<window 18 on NEWS> 3510 (0 . 28) -729648)) |
メタキーとシフトキーを押し下げた状態で、 ユーザーがマウスの2番目のボタンをウィンドウのモード行で押し下げ、 マウスを別のウィンドウへドラッグすると、 つぎのような2つのイベントが生成されます。
(M-S-down-mouse-2 (#<window 18 on NEWS> mode-line (33 . 31) -457844)) (M-S-drag-mouse-2 (#<window 18 on NEWS> mode-line (33 . 31) -457844) (#<window 20 on carlton-sanskrit.tex> 161 (33 . 3) -453816)) |
各イベントにはイベント型(event type)があって、 キーバインディング処理のためにイベントを分類します。 キーボードイベントでは、イベント型はイベントの値に等しいです。 したがって、文字に対するイベント型は文字であり、 ファンクションキーに対するイベント型はシンボルそのものです。 リストであるイベントでは、イベント型はリストのCARにあるシンボルです。 したがって、イベント型はつねにシンボルか文字です。
イベント型が同じであるイベントは、キーバインディングに関する限り同じです。 つまり、それらは同じコマンドを実行します。 しかし、これは、それらが必ずしも同じことを行うという意味ではありません。 イベント全体を調べてなにを行うかを決定するコマンドもあります。 たとえば、マウスイベントの生起位置を使って、 バッファのどの部分を処理するかを決めるコマンドもあります。
イベントをおおまかに分類すると有用な場合もあります。 たとえば、他の修飾キーやマウスボタンには関係なしに、 METAキーが使われているイベントかどうか調べたいことがあるでしょう。
関数event-modifiers
やevent-basic-type
は、
そのような情報を便利に与えるためのものです。
shift
、control
、
meta
、alt
、hyper
、super
である。
さらに、マウスイベントシンボルの修飾子リストには、
必ず、click
、drag
、down
の1つが含まれる。
引数eventは、イベントオブジェクト全体であるか、単なるイベント型である。
例を示す。
(event-modifiers ?a) => nil (event-modifiers ?\C-a) => (control) (event-modifiers ?\C-%) => (control) (event-modifiers ?\C-\S-a) => (control shift) (event-modifiers 'f5) => nil (event-modifiers 's-f5) => (super) (event-modifiers 'M-S-f5) => (meta shift) (event-modifiers 'mouse-1) => (click) (event-modifiers 'down-mouse-1) => (down) |
クリックイベントに対する修飾子リストにはclick
が明示的に含まれるが、
イベントシンボルの名前自体には`click'は含まれない。
(event-basic-type ?a) => 97 (event-basic-type ?A) => 97 (event-basic-type ?\C-a) => 97 (event-basic-type ?\C-\S-a) => 97 (event-basic-type 'f5) => f5 (event-basic-type 's-f5) => f5 (event-basic-type 'M-S-f5) => f5 (event-basic-type 'down-mouse-1) => mouse-1 |
nil
以外を返す。
(event-convert-list '(control ?a)) => 1 (event-convert-list '(control meta ?a)) => -134217727 (event-convert-list '(control super f1)) => C-s-f1 |
本節では、マウスボタンイベントやモーションイベント内のデータを 参照するための便利な関数について述べます。
つぎの2つの関数は、以下の形式のリストであるマウスボタンイベントの 開始位置や終了位置を返します。
(window buffer-position (x . y) timestamp) |
eventがクリックイベントやボタン押し下げイベントであると、 イベントの位置を返す。 eventがドラッグイベントであると、ドラッグの開始位置を返す。
eventがドラッグイベントであると、 ユーザーがマウスボタンを離したときの位置を返す。 eventがクリックイベントかボタン押し下げイベントであると、 実際の値は開始位置であり、 その種のイベントにある唯一の位置情報である。
つぎの5つの関数は、上に述べた位置情報のリストを引数として、 そのさまざまな部分を返す。
(x . y)
として返す。
(col . row)
として返す。
これらは実際にはposition内のxとyの値から計算される。
つぎの関数はスクロールバーでのイベントを解読するのに便利です。
(portion . whole)
であり、
その比は位置の割合を表す。
(num . denom)
であり、
典型的にはscroll-bar-event-ratio
が返す値である。
この関数はスクロールバー内での位置を バッファ内での位置へ換算するのに便利である。 つぎのように行う。
(+ (point-min) (scroll-bar-scale (posn-x-y (event-start event)) (- (point-max) (point-min)))) |
スクロールバー内でのイベントには、 xy座標のかわりに比を表す2つの整数があることに注意。
文字列が使われるほとんどの場面では、 文字列にはテキスト文字、つまり、 バッファやファイルにある文字と同じ種類のものが入っていると考えています。 文字列にはキーボード文字が入っているとみなして使うLispプログラムもあります。 たとえば、文字列には、キー列やキーボードマクロの定義が入っているのです。 しかし、キーボード文字を文字列に保持するのは複雑であり、 それは歴史的な互換性を保つためにするのであり、 また、つねに可能とは限りません。
新しいプログラムでは、キーボードイベントを文字列に保持しないで、 このような複雑さを避けるように推奨します。 つぎのようにします。
lookup-key
やdefine-key
に対する
引数以外にも使うつもりならば、文字列のかわりにベクトルを使う。
たとえば、read-key-sequence
のかわりにread-key-sequence-vector
を
this-command-keys
のかわりにthis-command-keys-vector
を使う。
define-key
に直接渡す場合であっても、ベクトルで書く。
listify-key-sequence
(see section 20.6.4 その他のイベント入力機能)を使って、
それをリストに変換しておく。
複雑さの原因は、キーボード入力に含まれる修飾ビットにあります。 メタ修飾子以外の修飾ビットを文字列に入れることは不可能であり、 メタ修飾子は特別な場合として唯一許されているのです。
初期のGNU Emacsでは、メタ文字を128から255の範囲のコードで表現していました。
その当時、基本文字コードは0から127でしたから、
キーボード文字のすべてのコードは文字列に収まったのです。
多くのLispプログラムでメタ文字を表すために文字列定数内で`\M-'を使い、
特に、define-key
や類似の関数に対する引数に使われ、
キー列やイベント列はつねに文字列で表現されていました。
127を超える大きな基本文字コードと追加の修飾ビットを扱えるようにしたとき、 メタ文字の表現方法を変更せざるをえませんでした。 現在、メタ修飾子を表す文字内のビットは 2**27 であり、そのような数を文字列に入れることはできません。
文字列定数で`\M-'を使っているプログラムを扱えるように、 文字列にメタ文字を入れるための特別な規則があります。 以下は、文字列を入力文字の列として解釈するための規則です。
キーボード入力文字の文字列を作るread-key-sequence
などの関数は
つぎの規則に従います。
つまり、文字列に収まらないイベントであるときには、
文字列のかわりにベクトルを作ります。
読者が文字列で`\M-'の入力構文を使うと、 それらは128から255の範囲のコードになります。 対応するキーボードイベントを文字列に保存するように変更したときに得られる コードと同じです。 したがって、文字列内のメタイベントは、それらがどのように文字列に 収められたかに関わらず、整合性のある動作をします。
しかし、本節のはじめに述べた推奨方法に従ってこれらのことがらを避けるほうが、 ほとんどのプログラムはよりよく動作するでしょう。
エディタコマンドループは、
関数read-key-sequence
を使ってキー列を読み取ります。
なお、関数read-key-sequence
は関数read-event
を使います。
これらやイベント入力を扱う他の関数は、Lispプログラムからも使えます。
38.7 一時的な表示のmomentary-string-display
、
および、20.8 時間待ちと入力待ちのsit-for
を参照してください。
端末の入力モードの制御や端末入力のデバッグに関する関数や変数については、
See section 37.8 端末入力。
入力イベントを読むときにそれらを変換したり修正する機能については、
See section 37.8.2 入力イベントの変換。
上位レベルの入力機能については、19. ミニバッファを参照してください。
20.6.1 キー列の入力 | How to read one key sequence. | |
20.6.2 単一イベントの読み取り | How to read just one event. | |
20.6.3 クォートした文字の入力 | Asking the user to specify a character. | |
20.6.4 その他のイベント入力機能 | How to reread or throw away input events. |
コマンドループは、read-key-sequence
を呼ぶことで
キー列の入力を読み取ります。
Lispプログラムからこの関数を呼び出してもよく、
たとえば、describe-key
は、
説明対象とするキーを読むためにこの関数を使います。
イベントがすべて文字であり、かつ、それらが文字列に収まるならば、
read-key-sequence
は文字列(see section 20.5.14 キーボードイベントを文字列で保持する)を返す。
さもなければ、ベクトルを返す。
ベクトルならば、任意の種類のイベント、つまり、
文字、シンボル、リストを保持できるからである。
文字列やベクトルの要素は、キー列のイベントである。
引数promptは、プロンプトとしてエコー領域に表示する文字列であるか、
あるいは、プロンプトを表示しないことを意味するnil
である。
以下の例では、プロンプト`?'がエコー領域に表示され、 ユーザーはC-x C-fと打つ。
(read-key-sequence "?") ---------- Echo Area ---------- ?C-x C-f ---------- Echo Area ---------- => "^X^F" |
関数read-key-sequence
は中断を抑止する。
この関数が動作中にC-gを打っても、他の文字と同様に扱い、
quit-flag
を設定しない。
see section 20.9 中断。
read-key-sequence
と同様であるが、
つねにベクトルとしてキー列を返し、文字列としてはけっして返さない。
see section 20.5.14 キーボードイベントを文字列で保持する。
入力文字が大文字であって、それらにキーバインディングがないとき、
対応する小文字にキーバインディングがあれば、
read-key-sequence
は文字を小文字に変換します。
lookup-key
はこのような変換を行わないことに注意してください。
関数read-key-sequence
は、ある種のマウスイベントも変換します。
バインディングのないドラッグイベントをクリックイベントに変換したり、
バインディングのないボタン押し下げイベントを完全に無視します。
さらに、フォーカスイベントとその他のウィンドウイベントを並び替えて、
それらが他のイベントのキー列の途中に現れないようにします。
マウスイベントが、モード行やスクロールバーなどのウィンドウの特別な部分で
生起しても、特別なイベント型はなく、マウスボタンや修飾キーの
組み合わせを普通どおりに表したシンボルです。
ウィンドウのどの部分かに関する情報は、
イベント内の別の部分、つまり、座標に入っています。
しかし、read-key-sequence
は、その情報を
シンボルmode-line
、vertical-line
、horizontal-scroll-bar
、
vertical-scroll-bar
を用いた仮想的な『プレフィックスキー』に変換します。
ウィンドウの特別な部分におけるマウスクリックの意味は、
これらの仮想的なプレフィックスキーを用いてキー列を定義することで
定義できます。
たとえば、read-key-sequence
を呼び出してから、
ウィンドウのモード行でクリックすると、
つぎのような2つのイベントを得ます。
(read-key-sequence "Click on the mode line: ") => [mode-line (mouse-1 (#<window 6 on NEWS> mode-line (40 . 63) 5959987))] |
コマンド入力用の最低レベルの関数は、単一イベントを読み取る関数です。
promptがnil
以外であると、
これはプロンプトとしてエコー領域に表示される文字列であること。
さもなければ、read-event
は
入力待ちであることを示すメッセージを表示せずに、
そのかわりに、現在のコマンドを実行するに至ったイベントや
現在のコマンドが読み取ったイベントをプロンプトとして表示する。
see section 38.3 エコー領域。
suppress-input-methodがnil
以外であると、
このイベントの読み取りに関しては現在の入力方式を使わない。
入力方式の処理をせずにイベントを読みたいときには、
つねにこのようにすること。
input-method-function
を束縛してはならない(下記参照)。
変数cursor-in-echo-area
がnil
以外であると、
read-event
は、エコー領域に表示されたメッセージの末尾に
カーソルを一時的に移動する。
さもなければ、read-event
はカーソルを移動しない。
read-event
がヘルプ文字と定義されたイベントを受け取ると、
それを返さずにread-event
がイベントを直接処理してしまう場合がある。
see section 23.5 ヘルプ機能。
特殊イベント(special event)と呼ばれる他のイベントも
read-event
が直接処理する(see section 20.7 特殊イベント)。
read-event
を呼んで右矢印のファンクションキーを押すとつぎのようになる。
(read-event) => right |
最初の例では、ユーザーは文字1(ASCIIコード49)を打つ。
2番目の例は、eval-expression
を使って
ミニバッファからread-char
を呼び出すキーボードマクロの定義である。
read-char
はキーボードマクロの直後の文字、つまり、1を読む。
そして、eval-expression
はその戻り値をエコー領域に表示する。
(read-char) => 49 ;; これを評価するために読者はM-:を使うと仮定する (symbol-function 'foo) => "^[:(read-char)^M1" (execute-kbd-macro 'foo) -| 49 => nil |
read-event
は、あれば現在の入力方式も起動します。
input-method-function
がnil
以外であれば、
それは関数であるはずです。
read-event
が修飾ビットのない(SPCを含む)印字文字を読み取ると、
引数としてイベントを渡してその関数を呼び出します。
nil
以外であると、その値は現在の入力方式関数を指定する。
注意:
この変数をlet
で束縛しないこと。
この変数はしばしばバッファローカルであり、
入力を読む周囲で束縛すると(読者がこれをもっとも束縛しそうなところ)、
Emacsが入力を待っているときにバッファが非同期に切り替わると、
誤ったバッファに値を復元してしまうことがある。
入力方式関数は、入力として使われるイベントのリストを返すべきです。
(リストがnil
であると入力がなかったことを意味し、
read-event
は別のイベントを待つ。)
これらのイベントは、
unread-command-events
内のイベントよりまえに処理されます。
入力方式関数が返したイベントは、それらが修飾ビットがない印字文字であっても、
入力方式関数に再度渡されることはありません。
入力方式関数がread-event
やread-key-sequence
を呼び出すときには、
input-method-function
をnil
に束縛して
再帰呼び出しを防ぐべきです。
キー列の2番目以降のイベントを読むときには、入力方式関数を呼び出しません。
したがって、それらの文字は、入力方式処理の対象ではありません。
入力方式の処理では、
overriding-local-map
とoverriding-terminal-local-map
の値を
検査するのがよいです。
これらの変数のいずれかがnil
以外であるときには、
入力方式ではその引数をリストに入れ、
それ以上処理せずにそのリストを返すべきです。
ユーザーに文字入力を促して、コントロール文字やメタ文字を
文字そのものや文字の8進数コードで手軽に入力できるようにするには、
関数read-quoted-char
を使います。
コマンドquoted-insert
は、この関数を使っています。
read-char
に似ているが、
最初に読んだ文字が8進数字文字(0-7)であると、
任意個数の8進数字文字を読み取り(8進数字文字以外が現れると止める)、
その数値の文字コードが表す文字を返す。
最初の文字を読むと中断を抑制するので、 ユーザーはC-gを入力できる。 see section 20.9 中断。
promptを与えると、それはユーザーへのプロンプトを表す文字列を指定する。 プロンプト文字列はつねにエコー領域に表示され、あとに`-'が続く。
つぎの例では、ユーザーは8進数177(10進数では127)を打つ。
(read-quoted-char "What character") ---------- Echo Area ---------- What character-177 ---------- Echo Area ---------- => 127 |
本節では、イベントを処理せずに『まえもって覗き見』する方法、
処理待ちの入力の有無の検査方法、処理待ちの入力の破棄方法について述べます。
関数read-passwd
も参照してください(see section 19.8 パスワードの読み取り)。
関数でイベントを読んだあとにそれを使わない場面があるため、 この変数が必要になる。 この変数にイベントを保存すると、 コマンドループやコマンド入力を読む関数によって通常どおり処理される。
たとえば、数値前置引数を実現する関数は、任意個数の数字文字を読み取る。 数字文字でないイベントをみつけたら、そのイベントを読み戻して、 コマンドループが通常どおりに読めるようにする必要がある。 同様に、インクリメンタルサーチでは、この機能を使って 探索においては意味を持たないイベントを読み戻す。 なぜなら、そのようなイベントは探索を終了させ、 通常どおり実行される必要があるからである。
unread-command-events
に入れられるように
キー列からイベントを確実に簡単に取り出す方法は
listify-key-sequence
を使うことである(see section 20.5.14 キーボードイベントを文字列で保持する)。
もっとも最近に読み戻したイベントが最初に再度読まれるように、 普通はこのリストの先頭にイベントを追加する。
unread-command-events
に入れられる。
この変数はほとんど廃れており、
かわりにunread-command-events
を使うべきである。
Emacs 18版以前向けに書かれたプログラムを扱うためだけに存在する。
t
を、
さもなければnil
を返す。
入力がないのにt
を返すことが稀にある。
以下の例で、Lispプログラムは文字1(ASCIIコード49)を読む。
それがlast-input-event
の値になるが、
(この式を評価するコマンドはC-x C-eと仮定するので)
last-command-event
の値はC-eのままである。
(progn (print (read-char)) (print last-command-event) last-input-event) -| 49 -| 5 => 49 |
Emacs 18版との互換性のために、別名last-input-char
が存在する。
nil
を返す。
以下の例で、フォームを評価しはじめてから、ユーザーは何文字か打つ。
sleep-for
が待機を終えると、
discard-input
は待機中に打たれた文字をすべて破棄する。
(progn (sleep-for 2) (discard-input)) => nil |
特殊イベントは、読まれるとただちに非常に低レベルで処理されます。
関数read-event
はこれらのイベントをそれ自身で処理してしまい、
それらを返すことはありません。
このように処理されるイベントは表示されることはなく、
キー列に組み込まれることもなく、
last-command-event
や(this-command-keys)
の値に
現れることもありません。
特殊イベントが数値引数を破棄することはなく、
unread-command-events
で読み戻すことはできません。
特殊イベントがキーボードマクロに現れることはなく、
読者がキーボードマクロを定義しているときに、
特殊イベントがキーボードマクロに記録されることはありません。
しかし、それらのイベントは、
読まれた直後にはlast-input-event
に現れますから、
これからイベントの定義で実際のイベントを見ることができます。
iconify-frame
、make-frame-visible
、delete-frame
の
イベント型は、通常このように処理されます。
特殊イベントをどのように処理するか、
どのイベントが特殊イベントであるかを定義する
キーマップは変数special-event-map
にあります(see section 21.6 活性なキーマップ)。
待機関数は、指定時間経過するか入力がくるまで待つように設計してあります。
たとえば、ユーザーに表示を眺める時間を与えるために
計算途中で休止したいでしょう。
sit-for
は、休止してスクリーンを更新し、
入力がくるとただちに戻ります。
一方、sleep-for
はスクリーンを更新せずに休止します。
input-pending-p
を参照)
指定時間だけ休止した場合は、戻り値はt
である。
さもなければ、戻り値はnil
である。
引数secondsは整数である必要はない。
それが浮動小数点数であると、sit-for
は秒の小数も待つ。
秒単位しか扱えないシステムもあり、
そのようなシステムではsecondsを秒に切り下げる。
省略可能な引数millisecは、ミリ秒単位の追加待ち時間を指定する。 これはsecondsで指定した時間に加えられる。 秒未満を扱えないシステムでは、 millisecに0以外を指定するとエラーになる。
入力がくると再表示をつねに取り止め、
再表示開始まえに入力がくると、いっさい再表示しない。
したがって、処理待ちの入力があると、再表示を強制する方法はない。
しかし、処理待ちの入力がなければ、(sit-for 0)
で再表示を強制できる。
nodispがnil
以外であると、
sit-for
は再表示はしないが、
入力がくるとただちに(あるいは指定時間だけ経過すると)戻る。
フレームをアイコンにしたりアイコンにしたフレームを開くと
イベントが生成されるため、sit-for
は戻る。
see section 20.5.10 ウィンドウシステムのその他のイベント。
sit-for
の普通の目的は、
読者が表示したテキストを読む時間をユーザーに与えることである。
nil
を返す。
引数secondsは整数である必要はない。
それが浮動小数点数であると、sleep-for
は秒の小数も待つ。
秒単位しか扱えないシステムもあり、
そのようなシステムではsecondsを秒に切り下げる。
省略可能な引数millisecは、ミリ秒単位の追加待ち時間を指定する。 これはsecondsで指定した時間に加えられる。 秒未満を扱えないシステムでは、 millisecに0以外を指定するとエラーになる。
遅延を保証したい場合にsleep-for
を使う。
現在時刻を取得する関数についてはSee section 37.5 時刻。
Lisp関数が動作中にC-gを打つと、 Emacsがなにを行っていても中断を引き起こします。 つまり、もっとも内側の活性なコマンドループに制御が戻ります。
コマンドループがキーボード入力を待っているときにC-gを打っても、
中断を引き起こさずに、普通の入力文字として動作します。
もっとも単純な場合、C-gはコマンドkeyboard-quit
を実行しますが、
その効果は中断を引き起こすことですから、読者には区別できないはずです。
しかし、プレフィックスキーに続けてC-gを打つと、
それらは組み合わされて未定義キーになります。
その効果は、前置引数を含めてプレフィックスキーを取り消します。
ミニバッファでは、C-gには別の定義があって、 ミニバッファを強制終了させます。 つまり、ミニバッファから抜け出て中断します。 (単に中断したのでは、ミニバッファ内で コマンドループに戻るだけである。) コマンドループで入力を読んでいるときにC-gで直接中断しない理由は、 このようにミニバッファでその意味を再定義できるようにするためです。 ミニバッファでは、プレフィックスキーに続くC-gは再定義してなく、 プレフィックスキーと前置引数を取り消すという通常の効果を持ちます。 C-gがつねに直接中断するのでは、このようにすることさえ不可能です。
C-gが直接に中断するときには、
変数quit-flag
にt
を設定します。
Emacsはこの変数を適切なときに検査しnil
でないと中断します。
したがって、quit-flag
にnil
以外を設定すると
中断を引き起こします。
Cのコードのレベルでは、どこでも中断できるわけではありません。
quit-flag
を検査している特別な箇所だけです。
このようにするのは、それ以外の箇所で中断すると
Emacsの内部状態に矛盾をきたす可能性があるからです。
中断は安全な場所まで延期されるので、
中断によってEmcasがクラッシュすることはありません。
read-key-sequence
やread-quoted-char
などのある種の関数は、
入力を待っている場合であっても中断を完全に抑制します。
中断するかわりに、C-gは入力として働きます。
read-key-sequence
の場合、コマンドループにおいて
C-gの特別なふるまいをもたらします。
read-quoted-char
の場合、
C-qでC-gをクォートできるようになります。
変数inhibit-quit
にnil
以外の値を束縛することで
Lisp関数のある部分において中断を抑制できます。
そうすると、C-gはそれでもいつもどおり
quit-flag
をt
にしますが、
その通常の結果である中断は抑制されます。
最終的にフォームlet
の終りで束縛が解除されるなどして
inhibit-quit
が再度nil
になります。
その時点でもquit-flag
がnil
以外であると
要求した中断がただちに起こります。
このふるまいは、プログラムの『臨界領域』では
中断が起こらないことを保証する理想的なものです。
(read-quoted-char
などの)ある種の関数では、
C-gは特別に処理され中断を引き起こしません。
inhibit-quit
にt
を束縛して入力を読み取り、
inhibit-quit
が再度nil
になるまえに
quit-flag
をnil
にすることでそのようにします。
これをread-quoted-char
の定義の以下の抜粋で示しましょう。
最初の入力文字のあとで通常の中断を許す方法も示しています。
(defun read-quoted-char (&optional prompt)
"...documentation..."
(let ((message-log-max nil) done (first t) (code 0) char)
(while (not done)
(let ((inhibit-quit first)
...)
(and prompt (message "%s-" prompt))
(setq char (read-event))
(if inhibit-quit (setq quit-flag nil)))
...変数 |
inhibit-quit
がnil
であれば、
この変数がnil
以外であるとEmacsはただちに中断する。
C-gは、inhibit-quit
に関わらず、
通常、quit-flag
にnil
以外を設定する。
quit-flag
がnil
以外の値に設定されたときに
Emacsが中断すべきかどうかを決定する。
inhibit-quit
がnil
以外であると、
quit-flag
に特別な意味はない。
(signal 'quit nil)
でquit
条件を通知する。
これは中断と同じことを行う。
(9.5.3 エラーのsignal
を参照。)
中断として使うC-g以外の特殊文字を使えます。
37.8 端末入力の関数set-input-mode
を参照してください。
Emacsのほとんどのコマンドは、前置引数(prefix argument)、
つまりコマンド自身のまえに指定された数を利用できます。
(前置引数とプレフィックスキーを混同しないこと。)
前置引数はつねに値で表現され、
nil
であると現在は前置引数がないことを表します。
各コマンドは、前置引数を使ってもよいし、無視してもかまいません。
前置引数には2つの表現方法があります。 生(raw)と数値(numeric)です。 エディタコマンドループでは、内部的には生の表現を使い、 その情報を保持するLisp変数もそのようにしますが、 コマンドではどちらの表現を要求してもかまいません。
生の前置引数の値にはつぎの可能性があります。
nil
。
その数値としての値は1であるが、
多くのコマンドではnil
と整数1を区別する。
-
。
数字文字なしにM--やC-u -を打ったことを表す。
これに等価な数値は-1であるが、
整数-1とシンボル-
を区別するコマンドもある。
いろいろな前置引数でつぎの関数を呼び出す例を示します。
(defun display-prefix (arg) "Display the value of the raw prefix arg." (interactive "P") (message "%s" arg)) |
以下は、生の前置引数でdisplay-prefix
を呼び出した結果です。
M-x display-prefix -| nil C-u M-x display-prefix -| (4) C-u C-u M-x display-prefix -| (16) C-u 3 M-x display-prefix -| 3 M-3 M-x display-prefix -| 3 ; ( |
Emacsは、前置引数を保持するために2つの変数、
prefix-arg
とcurrent-prefix-arg
を使います。
他のコマンド向けに前置引数を設定するuniversal-argument
などの
コマンドは、前置引数をprefix-arg
に保持します。
対照的に、current-prefix-arg
には
現在のコマンドに対して前置引数を運ぶ役割があり、
この変数に設定しても以後のコマンドに対する前置引数には
なんの効果もありません。
通常、コマンドは、interactive
宣言により、
「生」か「数値」のいずれの表現の前置引数を使うか指定します。
(See section 20.2.1 interactive
の使い方。)
あるいは、変数current-prefix-arg
にある前置引数の値を
関数から直接見てもかまいませんが、
これは見通しのよい方法ではありません。
nil
であると、戻り値は1である。
-
であると、戻り値は-1である。
数であると、その数を返す。
リストであると、リストの(数であるはずの)CARを返す。
(interactive "P")
を使うことである。
universal-argument
などの
コマンドは、この変数に設定することで動作する。
つぎのコマンドは、後続のコマンド向けの前置引数を設定するためのものです。 それ以外の目的には呼ばないでください。
Emacsが動作を始めると、Emacsのコマンドループに自動的に入ります。 このトップレベルのコマンドループからはけっして抜けることはなく、 Emacsが動いている限り動作し続けます。 Lispプログラムからコマンドループを起動することもできます。 そうすると、活性なコマンドループが複数作られることになるので、 それを再帰編集(recursive editing)と呼びます。 再帰編集レベルには、それを起動したコマンドを一時休止させ、 当該コマンドを再開するまでユーザーにどんな編集でも許す効果があります。
再帰編集中に利用可能なコマンドは、トップレベルのコマンドループと 同じものでありキーマップで定義されます。 再帰編集を抜けるための数個の特別なコマンドがあり、 完了すると再帰編集レベルから抜ける別のコマンドもあります。 (再帰編集を抜けるコマンドはつねに利用可能であるが、 再帰編集中でないとなにも行わない。)
再帰編集を含むすべてのコマンドループでは、 コマンドループから実行したコマンドのエラーによって コマンドループから抜け出さないように汎用目的のエラーハンドラを設定します。
ミニバッファでの入力は、特別な種類の再帰編集です。 これには、ミニバッファやミニバッファ用ウィンドウを表示するなどの特別な 処理がありますが、読者が考えるよりは少ないのです。 ミニバッファでは特別なふるまいをするキーもありますが、 それらはミニバッファのローカルマップによるものです。 ウィンドウを切り替えると、Emacsの普通のコマンドを使えます。
再帰編集レベルを起動するには、関数recursive-edit
を呼び出します。
この関数にはコマンドループが含まれています。
さらに、exit
を伴ったcatch
の呼び出しもあり、
これにより、exit
へ投げることで
再帰編集レベルから抜け出せるようになっています
(see section 9.5.1 明示的な非ローカル脱出:
catch
とthrow
)。
t
以外の値を投げると、recursive-edit
は、
呼び出し側の関数へ普通に戻ります。
コマンドC-M-c(exit-recursive-edit
)は、これを行います。
値t
を投げるとrecursive-edit
に中断を引き起こし、
1つ上のレベルのコマンドループへ制御を戻します。
これを強制終了(aborting)と呼び、
C-](abort-recursive-edit
)で行えます。
ミニバッファを使う場合を除いて、ほとんどのアプリケーションでは 再帰編集を使うべきではありません。 カレントバッファのメジャーモードを 一時的な特別なメジャーモードに変更するほうが、 一般にはユーザーにとってより便利です。 ただし、当該メジャーモードには、 まえのモードに戻るコマンドを用意しておきます。 (rmailのコマンドeは、この方式を使っている。) あるいは、『再帰的に』編集する別のテキストをユーザーに与えたい場合には、 特別なモードの新たなバッファを作成してそれを選択します。 当該モードには、処理を終えてまえのバッファに戻るコマンドを 定義しておきます。 (rmailのコマンドmは、このようにする。)
再帰編集はデバッグに便利です。
ブレークポイントの一種として関数定義に
debug
の呼び出しを挿入しておくと、
その箇所に達したときにいろいろと調べられます。
debug
は再帰編集を起動しますが、デバッガとしての機能も提供します。
query-replace
でC-rを打ったり、
C-x q(kbd-macro-query
)を使ったときにも
再帰編集レベルが使われます。
以下の例では、関数simple-rec
は、まず1単語分ポイントを進め、
エコー領域にメッセージを表示して再帰編集に入る。
そうすると、ユーザーは望むことはなんでもできるようになり、
(再帰編集を)抜けるためにC-M-cを打つと、
simple-rec
の実行を継続する。
(defun simple-rec () (forward-word 1) (message "Recursive edit in progress") (recursive-edit) (forward-word 1)) => simple-rec (simple-rec) => nil |
(throw 'exit nil)
である。
quit
を通知することで、
(ミニバッファでの入力を含む)もっとも内側の再帰編集を
要請したコマンドを強制終了する。
その関数定義は実質的には(throw 'exit t)
である。
see section 20.9 中断。
コマンドを禁止するとは、 コマンドを実行するまえにユーザーの確認を必要とするように コマンドに印を付けることです。 コマンドを禁止するのは、 初心者に混乱をもたらす可能性のあるコマンドに対してや、 コマンドの誤用を防ぐためです。
コマンドを禁止する低レベルの機構は、
コマンドのLispシンボルにnil
以外の属性disabled
を入れることです。
これらの属性は、通常、ユーザーの`.emacs'ファイルにて
つぎのようなLisp式で設定します。
(put 'upcase-region 'disabled t) |
数個のコマンドにはデフォルトでこれらの属性がありますから、 `.emacs'ファイルで属性を取り除きます。
属性disabled
の値は文字列であり、
コマンドを禁止したことを表すメッセージです。
たとえばつぎのとおりです。
(put 'delete-region 'disabled "Text deleted this way cannot be yanked back!\n") |
禁止したコマンドを対話的に起動するとどうなるかについて 詳しくはSee section `使用禁止コマンド' in GNU Emacs マニュアル。 コマンドを禁止しても、Lispプログラムから関数として呼び出すことには なんの影響もありません。
this-command-keys
を使って
コマンドを実行するためにユーザーがなにを入力したかを調べ、
コマンドそのものを探し出せる。
see section 22.6 フック。
デフォルトでは、disabled-command-hook
には、
ユーザーに処理を進めるかどうかを問い合わせる関数が入っている。
コマンドループでは、実行した複雑なコマンドの履歴を管理していて、
それらのコマンドを簡単に繰り返せるようにしています。
複雑なコマンドとは、ミニバッファを使って引数を読むコマンドです。
これには、任意のM-xコマンド、任意のM-:コマンド、
ミニバッファから引数を読み取るinteractive
指定を持つ任意のコマンドが
含まれます。
コマンド自身の実行中に明示的にミニバッファを使っても、
複雑なコマンドとはみなしません。
history-length
で指定される)最大サイズに達すると
新しい要素を追加するたびに古い要素を削除する。
command-history => ((switch-to-buffer "chistory.texi") (describe-key "^X^[") (visit-tags-table "~/emacs/src/") (find-tag "repeat-complex-command")) |
この履歴リストは、実際にはミニバッファ履歴(see section 19.4 ミニバッファの履歴) の特別な場合です。 要素は文字列ではなく式なのです。
まえのコマンドを編集したり取り出すための専用コマンドがたくさんあります。
コマンドrepeat-complex-command
とlist-command-history
は、
ユーザーマニュアル
(see section `ミニバッファコマンドの繰り返し' in GNU Emacs マニュアル)に説明してあります。
ミニバッファ内では、通常のミニバッファ履歴コマンドを使えます。
キーボードマクロは、 コマンドとみなせる入力イベントのまとまった列であり、 キーの定義から構成されます。 Lispにおけるキーボードマクロの表現は、 イベントを含んだ文字列やベクトルです。 キーボードマクロとLispマクロ(see section 12. マクロ)を混同しないでください。
kbdmacroがシンボルであると、 kbdmacroのかわりにその関数定義を用いる。 それがさらに別のシンボルであると、この処理を繰り返す。 最終的な結果は、文字列かベクトルであること。 結果がシンボルでも文字列でもベクトルでもないと、 エラーを通知する。
引数countは繰り返し回数であり、
kbdmacroをその回数だけ実行する。
countを省略するかnil
であると、kbdmacroを1回実行する。
countが0であると、
kbdmacroの実行をエラーに出会うか探索に失敗するまで繰り返す。
execute-kbd-macro
を使った例についてはsee section 20.6.2 単一イベントの読み取り。
nil
であると、現在実行中のマクロはない。
コマンドでこの変数を検査することで、
マクロ実行で起動されたときのふるまいを変更できる。
読者自身はこの変数に設定しないこと。
start-kbd-macro
とend-kbd-macro
がこの変数に設定する。
読者自身は設定しないこと。
この変数は現在の端末に対してつねにローカルであり、 バッファに対してローカルにはならない。 see section 28.2 複数ディスプレイ。
nil
である。
この変数は現在の端末に対してつねにローカルであり、 バッファに対してローカルにはならない。 see section 28.2 複数ディスプレイ。
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |