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

20. コマンドループ

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Command%20Loop"
"elisp/コマンドループ"へのコメント(無し)

読者がEmacsを起動すると、Emacsはほぼただちにエディタコマンドループ (editor command loop)に入ります。 このループは、キー列を読み取り、それらの定義を実行し、結果を表示します。 本章では、これがどのように行われるのか、および、 Lispプログラムからこれを行うためのサブルーティンについて述べます。



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

20.1 コマンドループの概要

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Command%20Overview"
"elisp/コマンドループの概要"へのコメント(無し)

コマンドループがまず始めに行うことはキー列、 つまり、コマンドへ変換されるイベント列を読むことです。 これには関数read-key-sequenceを呼び出します。 読者のLispコードでもこの関数を呼び出せます(see 節 20.6.1 キー列の入力)。 Lispプログラムでは、read-event(see 節 20.6.2 単一イベントの読み取り)で 低レベルの入力を行ったり、 discard-input(see 節 20.6.4 その他のイベント入力機能)で 処理待ち中の入力を破棄できます。

キー列は現在活性なキーマップを介してコマンドに変換されます。 この処理方法についてはSee 節 21.7 キー探索。 この結果は、キーボードマクロであるか、 対話的に呼び出し可能な関数であるはずです。 キーがM-xであると、別のコマンドの名前を読み取り、 そのコマンドを呼び出します。 これはコマンドexecute-extended-command(see 節 20.3 対話的呼び出し)で 処理されます。

コマンドを実行するには、まず、その引数を読む必要があります。 これは、command-execute(see 節 20.3 対話的呼び出し)を呼び出して 行います。 Lispで書かれたコマンドでは、 interactive指定が引数の読み方を指示します。 前置引数(see 節 20.10 前置コマンド引数)を使ったり、 プロンプトを表示してミニバッファ(see 節 19. ミニバッファ)から読みます。 たとえば、コマンドfind-fileには、 ミニバッファからファイル名を読むことを指示した interactive指定があります。 コマンドの関数本体ではミニバッファを使いません。 このコマンドをLispコードから関数として呼び出す場合、 通常のLisp関数の引数としてファイル名文字列を指定する必要があります。

コマンドが文字列やベクトル(つまり、キーボードマクロ)である場合、 execute-kbd-macroを用いてそれらを実行します。 読者自身がこの関数を呼び出してもかまいません(see 節 20.14 キーボードマクロ)。

動作中のコマンドの実行を止めるには、C-gを打ちます。 この文字は中断(quitting)を引き起こします(see 節 20.9 中断)。

Variable: pre-command-hook
エディタコマンドループは、各コマンドのまえにこのノーマルフックを実行する。 その際、this-commandにはこれから実行するコマンドが保持され、 last-commandには直前のコマンドがある。 see 節 22.6 フック

Variable: post-command-hook
エディタコマンドループは、 (中断やエラーのために完了しなかったコマンドを含めて) 各コマンドのあとにこのノーマルフックを実行する。 初めてコマンドループに入ったときにも実行する。 その際、this-commandには実行し終えたばかりのコマンドがあり、 last-commandにはその前のコマンドがある。 see 節 22.6 フック

pre-command-hookpost-command-hookの実行中は、 中断を禁止します。 これらのフックの1つを実行中にエラーが起きると、 エラーの無限ループを防ぐために、 フックの実行を終了しフック変数をnilにします。



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

20.2 コマンドの定義

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Defining%20Commands"
"elisp/コマンドの定義"へのコメント(無し)

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.



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

20.2.1 interactiveの使い方

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Using%20Interactive"
"elisp/interactiveの使い方"へのコメント(無し)

本節では、Lisp関数を対話的に呼び出し可能なコマンドにするフォーム interactiveの書き方について述べます。

Special Form: interactive arg-descriptor
このスペシャルフォームは、これを含む関数がコマンドであり、 (M-xや当該関数にバインドしたキー列を入力することで) 対話的に呼び出せることを宣言する。 引数arg-descriptorは、コマンドを対話的に呼び出したときに コマンドに対する引数の計算方法を宣言する。

他の関数と同様に、コマンドはLispプログラムからも呼び出せるが、 その場合、呼び出し側が引数を渡し、arg-descriptorにはなんの効果もない。

フォームinteractiveが効果を発揮するのは、 コマンドループ(実際にはサブルーティンcall-interactively)が 関数を呼び出すまえに関数定義を走査してこのフォームを探すからである。 関数が呼び出されると、フォームinteractiveを含めて その本体のフォームが実行されるが、そのとき、 interactiveは引数を評価せずに単にnilを返す。

引数arg-descriptorには3つの可能性があります。



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

20.2.2 interactiveのコード文字

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Interactive%20Codes"
"elisp/interactiveのコード文字"へのコメント(無し)

以下に述べるコード文字の説明では、 つぎに定義するいくつかのキーワードを含みます。

「補完」
補完を使える。 completing-readを使って引数を読むため、 TABSPCRETは名前を補完する (see 節 19.5 補完)。 ?は補完候補のリストを表示する。

「既存」
既存オブジェクトの名前を必要とする。 不正な名前は受け付けない。 現在の入力が正しくないとミニバッファから抜けるコマンドは動作しない。

「デフォルト」
ミニバッファにユーザーがなにもテキストを入力しないときに 使われるなんらかのデフォルト値。 デフォルトはコード文字に依存する。

「入出力なし」
このコード文字は、入力をまったく読まずに引数を計算する。 したがって、プロンプト文字列を使わず、 読者が指定したプロンプト文字列は無視する。

コード文字はプロンプト文字列を使わないが、 この文字が文字列の最後の文字でない場合には改行を続けること。

「プロンプト」
コード文字の直後にプロンプトが続く。 プロンプトは文字列の終りか改行で終る。

「スペシャル」
このコード文字は、対話指定文字列の先頭でのみ意味を持ち、 プロンプトや改行を必要としない。 これは1つの孤立した文字である。

以下に、interactiveに使うコード文字を説明します。

`*'
カレントバッファが読み出し専用であるとエラーを通知する。 「スペシャル」。

`@'
このコマンドを起動したキー列の最初のマウスイベントが表すウィンドウを選択する。 「スペシャル」。

`a'
関数名(つまり、fboundpを満たすシンボル)。 「既存」、「補完」、「プロンプト」。

`b'
既存バッファの名前。 デフォルトでは、カレントバッファ(see 節 26. バッファ)の名前を使う。 「既存」、「補完」、「デフォルト」、「プロンプト」。

`B'
バッファ名。 バッファが既存である必要はない。 デフォルトでは、カレントバッファ以外の最近使ったバッファの名前を使う。 「補完」、「デフォルト」、「プロンプト」。

`c'
文字。 カーソルはエコー領域には移動しない。 「プロンプト」。

`C'
コマンド名(つまり、commandpを満たすシンボル)。 「既存」、「補完」、「プロンプト」。

`d'
整数としてのポイント位置(see 節 29.1 ポイント)。 「入出力なし」。

`D'
ディレクトリ名。 デフォルトは、カレントバッファのカレントデフォルトディレクトリ default-directory(see 節 37.3 オペレーティングシステム環境)。 「既存」、「補完」、「デフォルト」、「プロンプト」。

`e'
コマンドを起動したキー列の最初やつぎのマウスイベント。 より正確には、`e'はリストであるイベントを取得するので、 読者はリスト内のデータを調べられる。 see 節 20.5 入力イベント。 「入出力なし」。

1つのコマンドの対話指定で複数回`e'を使える。 コマンドを起動したキー列がn個のリストであるイベントである場合、 n番目の`e'は、n番目のそのようなイベントを与える。 `e'では、 ファンクションキーやASCII文字などのリストでないイベントは数えない。

`f'
既存ファイルの名前(see 節 24.8 ファイル名)。 デフォルトディレクトリはdefault-directory。 「既存」、「補完」、「デフォルト」、「プロンプト」。

`F'
ファイル名。 ファイルが既存である必要はない。 「補完」、「デフォルト」、「プロンプト」。

`i'
無関係な引数。 このコードは、引数の値につねにnilを与える。 「入出力なし」。

`k'
キー列(see 節 21.1 キーマップの用語)。 現在のキーマップにおいてコマンドがみつかる(あるいは未定義コマンド)まで イベントを読み続ける。 キー列引数は、文字列かベクトルとして表現される。 カーソルはエコー領域には移動しない。 「プロンプト」。

この種の入力は、describe-keyglobal-set-keyなどの コマンドで使われる。

`K'
キー列であり、読者がその定義を変更することを意図している。 これは`k'と同様に動作するが、 キー列の最後の入力イベントに対しては、 未定義キーを定義済みのものに変換するために(必要なときに)普通使われる 変換処理を抑制する。

`m'
整数としてのマーク位置。 「入出力なし」。

`M'
カレントバッファの入力方式を用いてミニバッファで読んだ任意のテキスト。 文字列として返す (see 節 `入力方式' in
GNU Emacs マニュアル
)。 「プロンプト」。

`n'
ミニバッファで読んだ数。 入力が数でないと、ユーザーに再入力を促す。 もし前置引数があってもそれは使わない。 「プロンプト」。

`N'
数値前置引数。 前置引数がなければ、nで数を読む。 数を必要とする。 see 節 20.10 前置コマンド引数。 「プロンプト」。

`p'
数値前置引数。 (この`p'は小文字。) 「入出力なし」。

`P'
生の前置引数。 (この`P'は大文字。) 「入出力なし」。

`r'
2つの数値引数としてのポイントとマーク。 小さいほうが先にくる。 これは、1つではなく2つの連続した引数を指定する唯一のコード文字。 「入出力なし」。

`s'
ミニバッファで読んだ任意のテキスト。 文字列として返す(see 節 19.2 ミニバッファでのテキスト文字列の読み取り)。 C-jRETで入力を終える。 (これらの文字を入力に含めるにはC-qを使う。) 「プロンプト」。

`S'
ミニバッファで読んだ名前をインターンしたシンボル。 白文字で入力を終える。 (文字列に白文字を含めるにはC-qを使う。) (丸括弧や角括弧などの)通常はシンボルを終える他の文字は、 ここではシンボルを終端しない。 「プロンプト」。

`v'
ユーザーオプションと宣言された変数 (つまり、述語user-variable-pを満たす)。 see 節 19.5.4 高レベルの補完関数。 「既存」、「補完」、「プロンプト」。

`x'
入力構文で表されたLispオブジェクト。 C-jRETで終える。 オブジェクトは評価しない。 see 節 19.3 ミニバッファでのLispオブジェクトの読み取り。 「プロンプト」。

`X'
xのようにLispフォームを読むが、評価しその値がコマンドの引数になる。 「プロンプト」。

`z'
コーディングシステム名(シンボル)。 ユーザーの入力が空であると、引数の値はnil。 see 節 32.10 コーディングシステム。 「補完」、「既存」、「プロンプト」。

`Z'
このコマンドに前置引数を指定した場合にのみ、 コーディングシステム名(シンボル)。 前置引数がないと、`Z'は引数の値にnilを与える。 「補完」、「既存」、「プロンプト」。



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

20.2.3 interactiveの使用例

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Interactive%20Examples"
"elisp/interactiveの使用例"へのコメント(無し)

ここではinteractiveの例を示します。

 
(defun foo1 ()              ; foo1は引数なし
    (interactive)           ; 2単語分先へ進める
    (forward-word 2))
     => foo1

(defun foo2 (n)             ; foo2は1引数
    (interactive "p")       ; 数値前置引数
    (forward-word (* 2 n)))
     => foo2

(defun foo3 (n)             ; foo3は1引数
    (interactive "nCount:") ; ミニバッファで読む
    (forward-word (* 2 n)))
     => foo3

(defun three-b (b1 b2 b3)
  "Select three existing buffers.
Put them into three windows, selecting the last one."
    (interactive "bBuffer1:\nbBuffer2:\nbBuffer3:")
    (delete-other-windows)
    (split-window (selected-window) 8)
    (switch-to-buffer b1)
    (other-window 1)
    (split-window (selected-window) 8)
    (switch-to-buffer b2)
    (other-window 1)
    (switch-to-buffer b3))
     => three-b
(three-b "*scratch*" "declarations.texi" "*mail*")
     => nil



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

20.3 対話的呼び出し

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Interactive%20Call"
"elisp/対話的呼び出し"へのコメント(無し)

コマンドループでは、キー列をコマンドへ変換し終えると、 関数command-executeを用いてそのコマンドを起動します。 コマンドが関数であれば、command-executeは引数を読み取り、 コマンドを呼び出すcall-interactivelyを呼びます。 読者自身がこれらの関数を呼び出してもかまいません。

Function: commandp object
objectが対話的呼び出しに適していれば、 つまり、objectがコマンドであればtを返す。 さもなければnilを返す。

対話的呼び出しが可能なオブジェクトには、 (キーボードマクロとして扱われる)文字列やベクトル、 トップレベルでinteractiveを呼び出しているラムダ式、 そのようなラムダ式をコンパイルしたバイトコード関数オブジェクト、 対話的(autoloadの4番目の引数がnil以外) と宣言された自動ロードオブジェクト、 一部の基本関数が含まれる。

シンボルの関数定義がcommandpを満たせば、 シンボルもcommandpを満たす。

キーやキーマップはコマンドではない。 それらはコマンドを探すために使われる(see 節 21. キーマップ)。

commandpの実用的な使用例については、 23.2 説明文字列の参照documentationを参照。

Function: call-interactively command &optional record-flag keys
この関数は、対話的呼び出し可能な関数commandを その対話指定に従って引数を読み取り呼び出す。 commandが関数でなかったり、 対話的に呼び出せない(つまり、コマンドでない)場合には、 エラーを通知する。 キーボードマクロ(文字列やベクトル)はコマンドとみなすが、 それらは関数でないため、この関数はキーボードマクロを受け付けない。

record-flagnil以外であると、 コマンドとその引数を無条件にリストcommand-historyに追加する。 さもなければ、引数を読むために コマンドがミニバッファを使った場合にのみ追加する。 see 節 20.13 コマンド履歴

もし引数keysを指定すると、コマンドがそれを起動したイベントを 問い合わせたときに与えるイベント列を指定する。

Function: command-execute command &optional record-flag keys
この関数はcommandを実行する。 引数commandcommandpを満たすこと。 つまり、対話的呼び出し可能な関数かキーボードマクロであること。

commandが文字列やベクトルであると、 execute-kbd-macroで実行される。 関数であると、省略可能なrecord-flagとともに関数を call-interactivelyに渡す。

シンボルは、その関数定義を使って処理する。 autoloadで定義されたシンボルは、 対話的呼び出し可能な関数と宣言されていればコマンドとみなす。 そのような定義では、指定されたライブラリをロードしてから シンボルの定義を再検査して処理する。

もし引数keysを指定すると、コマンドがそれを起動したイベントを 問い合わせたときに与えるイベント列を指定する。

コマンド: execute-extended-command prefix-argument
この関数はcompleting-read(see 節 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

Function: interactive-p
この関数は、これ(interactive-pの呼び出し)を含んだ関数が call-interactivelyで対話的に呼び出されるとtを返す。 (Lispからcall-interactivelyが呼び出されても、 エディタコマンドループが直接呼び出しても違いはない。) これを含んだ関数がLispの評価(あるいはapplyfuncall)で 呼び出された場合は、対話的呼び出しではない。

interactive-pのもっとも一般的な用途は、 情報メッセージを表示するかどうか決めることです。 特別な例外として、キーボードマクロを実行中にはいつでも、 interactive-pnilを返します。 これは情報メッセージを省いてマクロの実行を速くするためです。

つぎのように使います。

 
(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になりません。



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

20.4 コマンドループからの情報

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Command%20Loop%20Info"
"elisp/コマンドループからの情報"へのコメント(無し)

エディタコマンドループは、自身や実行中のコマンドのために 状態記録を数個のLisp変数に設定します。

Variable: last-command
この変数は、コマンドループが(現在のコマンドの)まえに実行したコマンドの 名前を記録する。 通常、この値は関数定義を持つシンボルであるが、保証はしない。

コマンドが後続のコマンドに対する前置引数を指定する場合を除いて、 コマンドからコマンドループへ戻るとthis-commandから値をコピーする。

この変数は現在の端末に対してつねにローカルであり、 バッファに対してローカルにはならない。 see 節 28.2 複数ディスプレイ

Variable: real-last-command
last-commandと同様にEmacsがこの変数に設定するが、 Lispプログラムではけっして変更しない。

Variable: this-command
この変数は、エディタコマンドループが いま実行しているコマンドの名前を記録する。 last-commandと同様に、通常は関数定義を持つシンボルである。

コマンドループは、コマンドを実行する直前にこの変数に設定し、 コマンドが終了すると(コマンドが後続のコマンドに対する 前置引数を指定する場合を除いて) この値をlast-commandにコピーする。

後続のコマンドに対するフラグとして 実行中にこの変数に設定するコマンドもある。 特に、テキストをキルする関数群はthis-commandkill-regionを 設定して、直後に続くキルコマンドでは キルしたテキストをまえのキルに追加するようにする。

特定のコマンドがエラーを起こした場合に 直前のコマンドとは認識されたくない場合には、 読者はそのコマンドがそれを防ぐように書く必要があります。 1つの方法は、以下に示すように、 コマンドの始めでthis-commandtを設定し、 コマンドの終りで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)))

letthis-commandを束縛しません。 というのは、エラーがあるとletは古い値を復元するからです。 これこそがここでは避けたいletの機能です。

Function: this-command-keys
この関数は、現在のコマンドに対して直前のコマンドが生成した前置引数を含めて、 現在のコマンドを起動したキー列を含んだ文字列かベクトルを返す。 すべてのイベントが文字であれば、値は文字列である。 see 節 20.5 入力イベント

 
(this-command-keys)
;; C-u C-x C-eを使ってこの式を評価する
     => "^U^X^E"

Function: this-command-keys-vector
this-command-keysと同様だが、つねにベクトルでイベントを返すため、 文字列に入力イベントを保持する際の複雑さを扱う必要がない (see 節 20.5.14 キーボードイベントを文字列で保持する)。

Variable: last-nonmenu-event
この変数は、マウスメニューによるイベントを考慮せずに、 キー列として読んだ最後の入力イベントを保持する。

この変数の1つの用途は、 メニューをポップアップする位置をx-popup-menuに指示することである。 y-or-n-p(see 節 19.6 Yes/Noの問い合わせ)も内部的に使っている。

Variable: last-command-event
Variable: last-command-char
この変数には、コマンドの一部としてコマンドループが 読んだ最後の入力イベントが設定される。 この変数の主な用途は、どの文字を挿入すべきかを決定するために self-insert-commandが使うことである。

 
last-command-event
;; C-u C-x C-eを使ってこの式を評価する
     => 5

C-eのASCIIコードは5なので、値は5である。

Emacs 18版との互換性のために別名last-command-charがある。

Variable: last-event-frame
この変数は、最後の入力イベントを振り向けたフレームを記録する。 通常これは、イベントが生成されたときに選択されていたフレームであるが、 そのフレームが入力フォーカスを別のフレームに振り向けていると、 この値はイベントを振り向けた先のフレームである。 see 節 28.9 入力フォーカス



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

20.5 入力イベント

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Input%20Events"
"elisp/入力イベント"へのコメント(無し)

Emacsのコマンドループは、キーボードやマウスのユーザーの操作を表す 入力イベント(input event)列を読みます。 キーボード操作に対するイベントは、文字かシンボルです。 マウスイベントはつねにリストです。 本節では、入力イベントの表現方法やその意味を詳しく説明します。

Function: eventp object
この関数は、objectが入力イベントであるかイベント型であると nil以外を返す。

任意のシンボルがイベントやイベント型として使われることに注意。 eventpは、Lispのプログラムコードがシンボルを イベントとして使うかどうか区別できない。 そのかわりに、シンボルが、Emacsの現在のセッションにおいて入力として読まれた イベントに使われたことがあるかどうかを区別する。 シンボルがそのように使われたことがなければ、 eventpnilを返す。

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.



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

20.5.1 キーボードイベント

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Keyboard%20Events"
"elisp/キーボードイベント"へのコメント(無し)

キーボードからは2種類の入力があります。 普通のキーとファンクションキーです。 普通のキーは文字に対応します。 それらが生成するイベントは、Lispでは文字として表現されます。 文字イベントのイベント型は文字自身(整数)です。 20.5.12 イベントの分類を参照してください。

入力文字イベントは、0から524287までの基本コード(basic code)と 以下の修飾ビット(modifier bit)の任意の組み合わせです。

meta
文字コードのビット 2**27 は、メタキーを押し下げながら文字を打ったことを表す。

control
文字コードのビット 2**26 は非ASCII文字のコントロール文字を表す。

C-aなどのASCIIコントロール文字には 独自の特別な基本コードがあるため、 Emacsはそれを表すための特別なビットを必要としない。 つまり、C-aのコードは単に1である。

しかし、コントロールキーを使った%などの ASCIIにないコントロールとの組み合わせを打った場合、 得られる数値は%のコードに 2**26 を加えたものである (端末で非ASCIIのコントロール文字を扱えるとして)。

shift
文字コードのビット 2**25 は、シフトキーを押し下げながら ASCIIコントロール文字を打ったことを表す。

英文字では、基本コードそのものが大文字か小文字かを表す。 数字文字と区切り文字では、 シフトキーは異なる基本コードのまったく異なる文字を選ぶ。 可能な限りASCII文字集合ですませるために、 これらの文字に対しては、Emacsはビット 2**25 を使わない。

しかし、ASCIIではC-AC-aを区別できないため、 Emacsは、C-Aではビット 2**25 を使うが、C-aではこのビットを使わない。

hyper
文字コードのビット 2**24 は、ハイパーキーを押し下げながら文字を打ったことを表す。

super
文字コードのビット 2**23 は、スーパーキーを押し下げながら文字を打ったことを表す。

alt
文字コードのビット 2**22 は、アルトキーを押し下げながら文字を打ったことを表す。 (ALTとラベルされたキーが実際にはメタキーである端末も存在する。)

読者のプログラム内では、 特定の修飾ビットの値を明示することは避けるのが最良です。 文字の修飾ビットを検査するには、 関数event-modifiers(see 節 20.5.12 イベントの分類)を使います。 キーバインディングを作るときには、 (`\C-'、`\M-'などの)修飾ビットを伴う文字の 入力表現を使います。 define-keyでキーバインディングを作るときには、 文字の指定には(control hyper ?x)のようなリストを使います (see 節 21.9 キーバインディングの変更)。 関数event-convert-listは、そのようなリストを イベント型に変換します(see 節 20.5.12 イベントの分類)。



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

20.5.2 ファンクションキー

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Function%20Keys"
"elisp/ファンクションキー"へのコメント(無し)

ほとんどのキーボードには、ファンクションキー(function key)、 つまり、文字ではない名前や記号のキーがあります。 Emacs Lispでは、ファンクションキーはシンボルで表現されます。 シンボルの(小文字の)名前がファンクションキーのラベルです。 たとえば、F1というラベルのキーを押すと、 入力ストリームにはシンボルf1が置かれます。

ファンクションキーイベントのイベント型は、イベントシンボルそれ自身です。 See 節 20.5.12 イベントの分類

ファンクションキーに対するシンボル命名慣習の特例を以下に示します。

backspace, tab, newline, return, delete
これらのキーは、ほとんどのキーボードにある特別なキーを持つ 一般的なASCIIコントロール文字に対応する。

ASCIIでは、C-iTABは同じ文字である。 これらを区別できる端末では、前者を整数9、後者をシンボルtabと 表現することで、EmacsはLispプログラムに区別を伝える。

ほとんどの場面では、これら2つを区別しても有用ではない。 そのため、通常、function-key-map(see 節 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
キーパッドのPFキー
kp-home, kp-left, kp-up, kp-right, kp-down
キーパッドの矢印キー。 Emacsは、通常、これらを対応するキーパッドのものではない homeleft...のキーに変換する。
kp-prior, kp-next, kp-end, kp-begin, kp-insert, kp-delete
普通のキーに対応するキーパッドのキー。 Emacsは、通常、同じ名前のキーパッドのものではないキーに変換する。

ファンクションキーにもALTCTRLHYPERMETASHIFTSUPERの修飾キーを使えます。 それらを表現するには、シンボル名に接頭辞を付けます。

`A-'
アルト修飾。
`C-'
コントロール修飾。
`H-'
ハイパー修飾。
`M-'
メタ修飾。
`S-'
シフト修飾。
`s-'
スーパー修飾。

したがって、METAを押し下げたF3キーのシンボルはM-f3です。 複数の接頭辞を使うときには、アルファベット順に書くことを勧めますが、 キーバインディングの探索関数や修飾関数の引数では関係ありません。



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

20.5.3 マウスイベント

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Mouse%20Events"
"elisp/マウスイベント"へのコメント(無し)

Emacsでは4種類のマウスイベント、つまり、クリックイベント、ドラッグイベント、 ボタン押し下げイベント、モーションイベントを扱えます。 すべてのマウスイベントは、リストで表現します。 リストのCARはイベント型であり、 どの修飾キーとともにどのマウスボタンを使ったかを表します。 イベント型では、ダブル(連続2回)/トリプル(連続3回)の 押し下げも区別できます(see 節 20.5.7 繰り返しイベント)。 リストの残りの要素は、位置情報と時間情報です。

キーの探索では、イベント型のみが意味を持ちます。 型が同じであれば、異なるイベントでも同じコマンドを実行します。 コマンドでは、対話指定コード`e'を用いてイベントの完全な値を参照できます。 See 節 20.2.2 interactiveのコード文字

マウスイベントで始まるキー列は、カレントバッファのキーマップではなく、 マウスが入っているウィンドウのバッファのキーマップを用いて読まれます。 つまり、あるウィンドウ内でクリックしても、 当該ウィンドウやバッファを選択するとは限らず、 その動作はキー列のコマンドバインディングで完全に制御されます。



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

20.5.4 クリックイベント

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Click%20Events"
"elisp/クリックイベント"へのコメント(無し)

ユーザーがマウスのボタンを同じ場所で押し下げてから離すと、 クリック(click)イベントが生成されます。 マウスクリックイベントはつぎの形式です。

 
(event-type
 (window buffer-pos (x . y) timestamp)
 click-count)

通常の各要素の意味はつぎのとおりです。

event-type
どのマウスボタンが使われたかを表すシンボル。 ボタンを左から右へ番号を付けて、 シンボルmouse-1mouse-2...の1つである。

ファンクションキーの場合と同様に、 アルト、コントロール、ハイパー、メタ、シフト、スーパーの 修飾キーを表す接頭辞`A-'、`C-'、`H-'、`M-'、 `S-'、`s-'も使える。

このシンボルはイベントのイベント型としての役割も果たす。 キーバインディングはイベント型でイベントを指定する。 したがって、mouse-1に対するキーバインディングは、 イベント型event-typemouse-1であるすべてのイベントに適用される。

window
クリックを行ったウィンドウ。

x, y
ウィンドウwindowの左上端を(0 . 0)とした クリック位置のピクセル単位の座標。

buffer-pos
クリックした文字のバッファ内位置。

timestamp
イベントが発生したときのミリ秒単位の時刻。 (この値は、Emacs Lispの整数の範囲では約5時間で一周するので、 時間的に近傍のイベントを関連付ける場合にのみ有用である。)

click-count
同じマウスボタンを素早く押し下げた繰り返し回数。 see 節 20.5.7 繰り返しイベント

モード行やスクロールバーなどのスクリーンの特別な部分で発生したイベントでは、 buffer-posxyの意味は少々異なります。

スクロールバーの内側でのクリックでは、 buffer-posはシンボルvertical-scroll-barhorizontal-scroll-barであり、 (x . y)(portion . whole)に 置き換えられます。 ここで、portionはスクロールバーの先頭や左端からのクリック位置、 wholeはスクロールバー全体の長さです。

モード行やウィンドウwindowを右隣のものと区切る 縦方向の区切り行の内側では、 buffer-posはシンボルmode-linevertical-lineです。 モード行では、yは意味のあるデータではありません。 縦方向の区切り行では、xは意味のあるデータではありません。

1つの特別な場面では、 buffer-posは単一のシンボルではなく(上に述べた1つの)シンボルを 含んだリストになります。 イベントに対する仮想的なプレフィックスキーを入力ストリームに挿入すると このようになります。 See 節 20.6.1 キー列の入力



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

20.5.5 ドラッグイベント

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Drag%20Events"
"elisp/ドラッグイベント"へのコメント(無し)

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 節 20.5.4 クリックイベント)。 ドラッグイベントかどうかを区別せずに、 マウスの任意のイベントの2番目の要素は同じ方法で参照できます。

接頭辞`drag-'は、 `C-'や`M-'のような修飾キー接頭辞に続きます。

read-key-sequenceが、 キーバインディングを持たないドラッグイベントを受け取り、かつ、 それに対応するクリックイベントにはバインディングがある場合、 ドラッグイベントの開始位置をクリック位置とするクリックイベントに変換します。 つまり、望まなければ、読者はクリックイベントとドラッグイベントを区別する 必要がありません。



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

20.5.6 ボタン押し下げイベント

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Button-Down%20Events"
"elisp/ボタン押し下げイベント"へのコメント(無し)

クリックイベントとドラッグイベントは、 ユーザーがマウスボタンを離したときに発生します。 ボタンを離すまではクリックとドラッグを区別する方法がないため、 ボタンを離すまで発生しえません。

ボタンを押し下げたらただちに動作を始めたい場合には、 読者はボタン押し下げ(button-down)イベントを処理する必要があります。 (8) ボタンを押し下げるとただちに発生します。 それらは、シンボルevent-typeの名前に 接頭辞`down-'があることを除けば、 クリックイベント(see 節 20.5.4 クリックイベント)とまったく同じリストで表現されます。 接頭辞`down-'は、`C-'や`M-'のような修飾キー接頭辞に続きます。

関数read-key-sequenceは、 コマンドバインディングを持たないボタン押し下げイベントを無視します。 したがって、Emacsのコマンドループもそれらを無視します。 つまり、読者がボタン押し下げイベントでなにかをしたいのでなければ、 読者はボタン押し下げイベントを定義する必要はありません。 ボタン押し下げイベントを定義する理由は、 ボタンが離されるまで(モーションイベントを読んで)マウスの動きを 追跡するためです。 See 節 20.5.8 モーションイベント



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

20.5.7 繰り返しイベント

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Repeat%20Events"
"elisp/繰り返しイベント"へのコメント(無し)

マウスを動かさずに同一のマウスボタンを素早く連続して押し下げると、 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回)、…などの イベントは生成しません。 しかし、イベントリストを調べれば、ボタンを何回押したか正確にわかります。

Function: event-click-count event
この関数は、イベントeventにおいてボタンが連続して押された回数を返す。 eventが、ダブルダウンイベント、ダブルクリックイベント、 ダブルドラッグイベントであると、値は2である。 eventがトリプルのイベントであると、値は3かそれ以上である。 eventが(繰り返しイベントではない)普通のマウスイベントであると、 値は1である。

Variable: double-click-time
繰り返しイベントが生成されるためには、 同じスクリーン位置において連続してマウスボタンを押し下げ、しかも、 各押し下げの間隔はdouble-click-timeの値未満(ミリ秒)である必要がある。 double-click-timenilを設定すると、 連続したクリックの検出を禁止する。 tを設定すると時間制限をなくし、 Emacsは連続したクリックの検出を位置だけで行う。



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

20.5.8 モーションイベント

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Motion%20Events"
"elisp/モーションイベント"へのコメント(無し)

Emacsは、ボタン操作を伴わないマウスの移動を表す マウスモーション(mouse motion)イベントを生成することがあります。 マウスモーションイベントはつぎのようなリストで表現されます。

 
(mouse-movement (window buffer-pos (x . y) timestamp))

リストの2番目の要素は、クリックイベント(see 節 20.5.4 クリックイベント)と同様に、 マウスの現在位置を表します。

スペシャルフォームtrack-mouseにより、 その本体の内側ではモーションイベントの生成を可能にできます。 フォームtrack-mouseの外側では、 Emacsはマウスの移動のみに対するイベントを生成しないので、 それらのイベントは現れません。 See 節 28.13 マウスの追跡



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

20.5.9 フォーカスイベント

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Focus%20Events"
"elisp/フォーカスイベント"へのコメント(無し)

ウィンドウシステムは、どのウィンドウにキーボード入力を与えるかを ユーザーが制御するための一般的な方法を提供します。 ウィンドウを選ぶことをフォーカス(focus)と呼びます。 ユーザーがEmacsのフレームを切り替える操作を行うと、 フォーカスイベント(focus event)が生成されます。 グローバルキーマップにあるフォーカスイベントの普通の定義は、 Emcasの新たなフレームを選択するようになっていて、 これはユーザーが期待することです。 See 節 28.9 入力フォーカス

Lispでは、フォーカスイベントはつぎのようなリストで表現されます。

 
(switch-frame new-frame)

ここで、new-frameは切り替え先のフレームです。

Xのほとんどのウィンドウマネージャは、 マウスをウィンドウへ入れるだけで当該ウィンドウにフォーカスが設定される ようになっています。 フレームにマウスが入るとカーソルの形状を変更するので、 Emacsでもそのようにします。 しかし、Lispプログラムにとっては、 なんらかの入力が到着するまではフォーカスの変更について知る必要がありません。 そのため、ユーザーが実際にキーボードのキーを打つか 新たなフレームでマウスボタンを押し下げたときだけ、 Emacsはフォーカスイベントを生成します。 フレーム間でマウスを動かしただけでは、フォーカスイベントは生成されません。

キー列の途中にフォーカスイベントが現れると、キー列を乱します。 そのため、Emacsはキー列の途中にはフォーカスイベントを生成しません。 ユーザーがキー列の途中で、つまり、 プレフィックスキーのあとでフォーカスを変更すると、 複数イベントのキー列のまえかうしろにフォーカスイベントを移動し、 途中には現れないようにEmacsはイベントの順序を並び替えます。



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

20.5.10 ウィンドウシステムのその他のイベント

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Misc%20Events"
"elisp/ウィンドウシステムのその他のイベント"へのコメント(無し)

ウィンドウシステム内で起きたことを表す他のイベントもあります。

(delete-frame (frame))
この種のイベントは、 Emacsのフレームであるウィンドウを削除するコマンドを ユーザーがウィンドウマネージャに与えたことを表す。

イベントdelete-frameの標準定義はフレームframeの削除である。

(iconify-frame (frame))
この種のイベントは、 ウィンドウマネージャを用いてユーザーがフレームframeを アイコン化したことを表す。 これに対する標準定義はignoreである。 というのは、フレームはすでにアイコンになっているので、 Emacsが行うことはなにもないからである。 このイベント型の目的は、 必要ならばその種のイベントを読者が追跡できるようにしておくことである。

(make-frame-visible (frame))
この種のイベントは、 ウィンドウマネージャを用いてユーザーがアイコン化したフレームframeを 開いたことを表す。 これに対する標準定義はignoreである。 というのは、フレームはすでに見えるようになっているので、 Emacsが行うことはなにもないからである。

(mouse-wheel position delta)
この種のイベントは、 (MSインテリマウスなどの)マウスのホイールを動かすと生成される。 その典型的な効果はスクロールやズーミングである。

要素deltaはホイールの回転方向と回転量である。 その絶対値はホイールを回すごとに増加する数である。 負のdeltaは、逆転、つまり、ユーザーへ近付く方向への回転を表し、 正のdeltaは、順転、つまり、ユーザーから遠ざかる方向への回転を表す。

要素positionはイベントの発生位置を表し、 マウスクリックイベントで使われる形式と同じである。

この種のイベントは、ある種のシステムでのみ生成される。

(drag-n-drop position files)
この種のイベントは、 Emacsの外側のアプリケーションで一群のファイルを選択し、 それらをEmacsのフレームにドラッグ&ドロップしたときに生成される。

要素positionはイベントの発生位置を表し、 マウスクリックイベントで使われる形式と同じであり、 要素filesはドラッグ&ドロップされたファイル名のリストである。 このイベントを扱う通常の処理は、それらのファイルを訪問することである。

現状では、この種のイベントは、ある種のシステムでのみ生成される。

これらのイベントがキー列の途中、つまり、 プレフィックスキーのうしろに現れると、 複数イベントのキー列のまえかうしろに当該イベントを移動し、 途中には現れないようにEmacsはイベントの順序を並び替えます。



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

20.5.11 イベントの例

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Event%20Examples"
"elisp/イベントの例"へのコメント(無し)

ユーザーが同じ場所でマウスの左ボタンを押し下げてから離すと、 つぎのようなイベント列が生成されます。

 
(down-mouse-1 (# 2613 (0 . 38) -864320))
(mouse-1      (# 2613 (0 . 38) -864180))

コントロールキーを押し下げた状態で、 ユーザーがマウスの2番目のボタンを押し下げ、 マウスをつぎの行へドラッグすると、つぎのような2つのイベントが生成されます。

 
(C-down-mouse-2 (# 3440 (0 . 27) -731219))
(C-drag-mouse-2 (# 3440 (0 . 27) -731219)
                (# 3510 (0 . 28) -729648))

メタキーとシフトキーを押し下げた状態で、 ユーザーがマウスの2番目のボタンをウィンドウのモード行で押し下げ、 マウスを別のウィンドウへドラッグすると、 つぎのような2つのイベントが生成されます。

 
(M-S-down-mouse-2 (# mode-line (33 . 31) -457844))
(M-S-drag-mouse-2 (# mode-line (33 . 31) -457844)
                  (# 161 (33 . 3)
                   -453816))



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

20.5.12 イベントの分類

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Classifying%20Events"
"elisp/イベントの分類"へのコメント(無し)

各イベントにはイベント型(event type)があって、 キーバインディング処理のためにイベントを分類します。 キーボードイベントでは、イベント型はイベントの値に等しいです。 したがって、文字に対するイベント型は文字であり、 ファンクションキーに対するイベント型はシンボルそのものです。 リストであるイベントでは、イベント型はリストのCARにあるシンボルです。 したがって、イベント型はつねにシンボルか文字です。

イベント型が同じであるイベントは、キーバインディングに関する限り同じです。 つまり、それらは同じコマンドを実行します。 しかし、これは、それらが必ずしも同じことを行うという意味ではありません。 イベント全体を調べてなにを行うかを決定するコマンドもあります。 たとえば、マウスイベントの生起位置を使って、 バッファのどの部分を処理するかを決めるコマンドもあります。

イベントをおおまかに分類すると有用な場合もあります。 たとえば、他の修飾キーやマウスボタンには関係なしに、 METAキーが使われているイベントかどうか調べたいことがあるでしょう。

関数event-modifiersevent-basic-typeは、 そのような情報を便利に与えるためのものです。

Function: event-modifiers event
この関数は、eventにある修飾子のリストを返す。 修飾子はシンボルであり、shiftcontrolmetaalthypersuperである。 さらに、マウスイベントシンボルの修飾子リストには、 必ず、clickdragdownの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'は含まれない。

Function: event-basic-type event
この関数は、eventにあるキーやマウスボタンを返す。 たとえばつぎのとおり。

 
(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

Function: mouse-movement-p object
この関数は、objectがマウス移動のイベントならばnil以外を返す。

Function: event-convert-list list
この関数は、修飾子名と基本イベント型のリストを それらが示すイベント型に変換する。 たとえばつぎのとおり。

 
(event-convert-list '(control ?a))
     => 1
(event-convert-list '(control meta ?a))
     => -134217727
(event-convert-list '(control super f1))
     => C-s-f1



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

20.5.13 イベントの参照

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Accessing%20Events"
"elisp/イベントの参照"へのコメント(無し)

本節では、マウスボタンイベントやモーションイベント内のデータを 参照するための便利な関数について述べます。

つぎの2つの関数は、以下の形式のリストであるマウスボタンイベントの 開始位置や終了位置を返します。

 
(window buffer-position (x . y) timestamp)

Function: event-start event
イベントeventの開始位置を返す。

eventがクリックイベントやボタン押し下げイベントであると、 イベントの位置を返す。 eventがドラッグイベントであると、ドラッグの開始位置を返す。

Function: event-end event
イベントeventの終了位置を返す。

eventがドラッグイベントであると、 ユーザーがマウスボタンを離したときの位置を返す。 eventがクリックイベントかボタン押し下げイベントであると、 実際の値は開始位置であり、 その種のイベントにある唯一の位置情報である。

つぎの5つの関数は、上に述べた位置情報のリストを引数として、 そのさまざまな部分を返す。

Function: posn-window position
position内のウィンドウを返す。

Function: posn-point position
positionのバッファ内位置を返す。 これは整数である。

Function: posn-x-y position
position内のピクセル単位のxy座標を コンスセル(x . y)として返す。

Function: posn-col-row position
positionの(文字単位の)行(row)とコラム(col)の座標を コンスセル(col . row)として返す。 これらは実際にはposition内のxyの値から計算される。

Function: posn-timestamp position
position内の時刻情報を返す。

つぎの関数はスクロールバーでのイベントを解読するのに便利です。

Function: scroll-bar-event-ratio event
スクロールバー内でのイベントから、スクロールバーに対する縦方向の位置を返す。 その値は2つの整数を含むコンスセル(portion . whole)であり、 その比は位置の割合を表す。

Function: scroll-bar-scale ratio total
この関数は(実質的には)ratiototalを掛け、 結果を整数に丸める。 引数ratioは数ではなく(num . denom)であり、 典型的にはscroll-bar-event-ratioが返す値である。

この関数はスクロールバー内での位置を バッファ内での位置へ換算するのに便利である。 つぎのように行う。

 
(+ (point-min)
   (scroll-bar-scale
      (posn-x-y (event-start event))
      (- (point-max) (point-min))))

スクロールバー内でのイベントには、 xy座標のかわりに比を表す2つの整数があることに注意。



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

20.5.14 キーボードイベントを文字列で保持する

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Strings%20of%20Events"
"elisp/キーボードイベントを文字列で保持する"へのコメント(無し)

文字列が使われるほとんどの場面では、 文字列にはテキスト文字、つまり、 バッファやファイルにある文字と同じ種類のものが入っていると考えています。 文字列にはキーボード文字が入っているとみなして使うLispプログラムもあります。 たとえば、文字列には、キー列やキーボードマクロの定義が入っているのです。 しかし、キーボード文字を文字列に保持するのは複雑であり、 それは歴史的な互換性を保つためにするのであり、 また、つねに可能とは限りません。

新しいプログラムでは、キーボードイベントを文字列に保持しないで、 このような複雑さを避けるように推奨します。 つぎのようにします。

複雑さの原因は、キーボード入力に含まれる修飾ビットにあります。 メタ修飾子以外の修飾ビットを文字列に入れることは不可能であり、 メタ修飾子は特別な場合として唯一許されているのです。

初期のGNU Emacsでは、メタ文字を128から255の範囲のコードで表現していました。 その当時、基本文字コードは0から127でしたから、 キーボード文字のすべてのコードは文字列に収まったのです。 多くのLispプログラムでメタ文字を表すために文字列定数内で`\M-'を使い、 特に、define-keyや類似の関数に対する引数に使われ、 キー列やイベント列はつねに文字列で表現されていました。

127を超える大きな基本文字コードと追加の修飾ビットを扱えるようにしたとき、 メタ文字の表現方法を変更せざるをえませんでした。 現在、メタ修飾子を表す文字内のビットは 2**27 であり、そのような数を文字列に入れることはできません。

文字列定数で`\M-'を使っているプログラムを扱えるように、 文字列にメタ文字を入れるための特別な規則があります。 以下は、文字列を入力文字の列として解釈するための規則です。

キーボード入力文字の文字列を作るread-key-sequenceなどの関数は つぎの規則に従います。 つまり、文字列に収まらないイベントであるときには、 文字列のかわりにベクトルを作ります。

読者が文字列で`\M-'の入力構文を使うと、 それらは128から255の範囲のコードになります。 対応するキーボードイベントを文字列に保存するように変更したときに得られる コードと同じです。 したがって、文字列内のメタイベントは、それらがどのように文字列に 収められたかに関わらず、整合性のある動作をします。

しかし、本節のはじめに述べた推奨方法に従ってこれらのことがらを避けるほうが、 ほとんどのプログラムはよりよく動作するでしょう。



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

20.6 入力の読み取り

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Reading%20Input"
"elisp/入力の読み取り"へのコメント(無し)

エディタコマンドループは、 関数read-key-sequenceを使ってキー列を読み取ります。 なお、関数read-key-sequenceは関数read-eventを使います。 これらやイベント入力を扱う他の関数は、Lispプログラムからも使えます。 38.7 一時的な表示momentary-string-display、 および、20.8 時間待ちと入力待ちsit-forを参照してください。 端末の入力モードの制御や端末入力のデバッグに関する関数や変数については、 See 節 37.8 端末入力。 入力イベントを読むときにそれらを変換したり修正する機能については、 See 節 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.



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

20.6.1 キー列の入力

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Key%20Sequence%20Input"
"elisp/キー列の入力"へのコメント(無し)

コマンドループは、read-key-sequenceを呼ぶことで キー列の入力を読み取ります。 Lispプログラムからこの関数を呼び出してもよく、 たとえば、describe-keyは、 説明対象とするキーを読むためにこの関数を使います。

Function: read-key-sequence prompt
この関数は、キー列を読み取り文字列かベクトルとして返す。 完全なキー列を収集し終えるまで、 つまり、現在活性なキーマップにおいて、非プレフィックスコマンドを 指定するのに十分になるまで、イベントを読み続ける。

イベントがすべて文字であり、かつ、それらが文字列に収まるならば、 read-key-sequenceは文字列(see 節 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 節 20.9 中断

Function: read-key-sequence-vector prompt
これはread-key-sequenceと同様であるが、 つねにベクトルとしてキー列を返し、文字列としてはけっして返さない。 see 節 20.5.14 キーボードイベントを文字列で保持する

入力文字が大文字であって、それらにキーバインディングがないとき、 対応する小文字にキーバインディングがあれば、 read-key-sequenceは文字を小文字に変換します。 lookup-keyはこのような変換を行わないことに注意してください。

関数read-key-sequenceは、ある種のマウスイベントも変換します。 バインディングのないドラッグイベントをクリックイベントに変換したり、 バインディングのないボタン押し下げイベントを完全に無視します。 さらに、フォーカスイベントとその他のウィンドウイベントを並び替えて、 それらが他のイベントのキー列の途中に現れないようにします。

マウスイベントが、モード行やスクロールバーなどのウィンドウの特別な部分で 生起しても、特別なイベント型はなく、マウスボタンや修飾キーの 組み合わせを普通どおりに表したシンボルです。 ウィンドウのどの部分かに関する情報は、 イベント内の別の部分、つまり、座標に入っています。 しかし、read-key-sequenceは、その情報を シンボルmode-linevertical-linehorizontal-scroll-barvertical-scroll-barを用いた仮想的な『プレフィックスキー』に変換します。 ウィンドウの特別な部分におけるマウスクリックの意味は、 これらの仮想的なプレフィックスキーを用いてキー列を定義することで 定義できます。

たとえば、read-key-sequenceを呼び出してから、 ウィンドウのモード行でクリックすると、 つぎのような2つのイベントを得ます。

 
(read-key-sequence "Click on the mode line: ")
     => [mode-line
         (mouse-1
          (# mode-line
           (40 . 63) 5959987))]

Variable: num-input-keys
この変数の値は、現在のEmacsセッションにおいて、 これまでに処理されたキー列の個数である。 これには、端末から読み取ったキー列、および、 実行したキーボードマクロから読み取ったキー列が含まれる。

Variable: num-nonmacro-input-events
この変数は、端末からこれまでに受け取った入力イベントの総個数を保持する。 キーボードマクロで生成されたものは含まない。



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

20.6.2 単一イベントの読み取り

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Reading%20One%20Event"
"elisp/単一イベントの読み取り"へのコメント(無し)

コマンド入力用の最低レベルの関数は、単一イベントを読み取る関数です。

Function: read-event &optional prompt suppress-input-method
この関数は、必要ならばイベントの到着を待って、 コマンド入力のつぎのイベントを読み取って返す。 イベントは、ユーザーか(実行中の)キーボードマクロから直接得る。

promptnil以外であると、 これはプロンプトとしてエコー領域に表示される文字列であること。 さもなければ、read-eventは 入力待ちであることを示すメッセージを表示せずに、 そのかわりに、現在のコマンドを実行するに至ったイベントや 現在のコマンドが読み取ったイベントをプロンプトとして表示する。 see 節 38.3 エコー領域

suppress-input-methodnil以外であると、 このイベントの読み取りに関しては現在の入力方式を使わない。 入力方式の処理をせずにイベントを読みたいときには、 つねにこのようにすること。 input-method-functionを束縛してはならない(下記参照)。

変数cursor-in-echo-areanil以外であると、 read-eventは、エコー領域に表示されたメッセージの末尾に カーソルを一時的に移動する。 さもなければ、read-eventはカーソルを移動しない。

read-eventがヘルプ文字と定義されたイベントを受け取ると、 それを返さずにread-eventがイベントを直接処理してしまう場合がある。 see 節 23.5 ヘルプ機能特殊イベント(special event)と呼ばれる他のイベントも read-eventが直接処理する(see 節 20.7 特殊イベント)。

read-eventを呼んで右矢印のファンクションキーを押すとつぎのようになる。

 
(read-event)
     => right

Function: read-char
この関数はコマンド入力の文字を読み取りそれを返す。 文字を得るまで、文字以外のイベントはすべて破棄する。

最初の例では、ユーザーは文字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-functionnil以外であれば、 それは関数であるはずです。 read-eventが修飾ビットのない(SPCを含む)印字文字を読み取ると、 引数としてイベントを渡してその関数を呼び出します。

Variable: input-method-function
これがnil以外であると、その値は現在の入力方式関数を指定する。

注意: この変数をletで束縛しないこと。 この変数はしばしばバッファローカルであり、 入力を読む周囲で束縛すると(読者がこれをもっとも束縛しそうなところ)、 Emacsが入力を待っているときにバッファが非同期に切り替わると、 誤ったバッファに値を復元してしまうことがある。

入力方式関数は、入力として使われるイベントのリストを返すべきです。 (リストがnilであると入力がなかったことを意味し、 read-eventは別のイベントを待つ。) これらのイベントは、 unread-command-events内のイベントよりまえに処理されます。 入力方式関数が返したイベントは、それらが修飾ビットがない印字文字であっても、 入力方式関数に再度渡されることはありません。

入力方式関数がread-eventread-key-sequenceを呼び出すときには、 input-method-functionnilに束縛して 再帰呼び出しを防ぐべきです。

キー列の2番目以降のイベントを読むときには、入力方式関数を呼び出しません。 したがって、それらの文字は、入力方式処理の対象ではありません。 入力方式の処理では、 overriding-local-mapoverriding-terminal-local-mapの値を 検査するのがよいです。 これらの変数のいずれかがnil以外であるときには、 入力方式ではその引数をリストに入れ、 それ以上処理せずにそのリストを返すべきです。



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

20.6.3 クォートした文字の入力

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Quoted%20Character%20Input"
"elisp/クォートした文字の入力"へのコメント(無し)

ユーザーに文字入力を促して、コントロール文字やメタ文字を 文字そのものや文字の8進数コードで手軽に入力できるようにするには、 関数read-quoted-charを使います。 コマンドquoted-insertは、この関数を使っています。

Function: read-quoted-char &optional prompt
この関数はread-charに似ているが、 最初に読んだ文字が8進数字文字(0-7)であると、 任意個数の8進数字文字を読み取り(8進数字文字以外が現れると止める)、 その数値の文字コードが表す文字を返す。

最初の文字を読むと中断を抑制するので、 ユーザーはC-gを入力できる。 see 節 20.9 中断

promptを与えると、それはユーザーへのプロンプトを表す文字列を指定する。 プロンプト文字列はつねにエコー領域に表示され、あとに`-'が続く。

つぎの例では、ユーザーは8進数177(10進数では127)を打つ。

 
(read-quoted-char "What character")

---------- Echo Area ----------
What character-177
---------- Echo Area ----------

     => 127



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

20.6.4 その他のイベント入力機能

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Event%20Input%20Misc"
"elisp/その他のイベント入力機能"へのコメント(無し)

本節では、イベントを処理せずに『まえもって覗き見』する方法、 処理待ちの入力の有無の検査方法、処理待ちの入力の破棄方法について述べます。 関数read-passwdも参照してください(see 節 19.8 パスワードの読み取り)。

Variable: unread-command-events
この変数は、コマンド入力として読まれることを 待っているイベントのリストを保持する。 イベントはリストに現れる順に使われ、使われると1つ1つ取り除かれる。

関数でイベントを読んだあとにそれを使わない場面があるため、 この変数が必要になる。 この変数にイベントを保存すると、 コマンドループやコマンド入力を読む関数によって通常どおり処理される。

たとえば、数値前置引数を実現する関数は、任意個数の数字文字を読み取る。 数字文字でないイベントをみつけたら、そのイベントを読み戻して、 コマンドループが通常どおりに読めるようにする必要がある。 同様に、インクリメンタルサーチでは、この機能を使って 探索においては意味を持たないイベントを読み戻す。 なぜなら、そのようなイベントは探索を終了させ、 通常どおり実行される必要があるからである。

unread-command-eventsに入れられるように キー列からイベントを確実に簡単に取り出す方法は listify-key-sequenceを使うことである(see 節 20.5.14 キーボードイベントを文字列で保持する)。

もっとも最近に読み戻したイベントが最初に再度読まれるように、 普通はこのリストの先頭にイベントを追加する。

Function: listify-key-sequence key
この関数は、文字列やベクトルであるkeyを個々のイベントのリストに変換する。 この結果はunread-command-eventsに入れられる。

Variable: unread-command-char
この変数は、コマンド入力として読まれる文字を保持する。 値「-1」は、『空』を意味する。

この変数はほとんど廃れており、 かわりにunread-command-eventsを使うべきである。 Emacs 18版以前向けに書かれたプログラムを扱うためだけに存在する。

Function: input-pending-p
この関数は、現在、コマンド入力があるかどうかを調べる。 ただちに返るが、入力があれば値tを、 さもなければnilを返す。 入力がないのにtを返すことが稀にある。

Variable: last-input-event
Variable: last-input-char
この変数は、コマンドの一部として、あるいは、Lispプログラムが明示的に 読み取った最後の端末入力イベントを記録する。

以下の例で、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が存在する。

Function: discard-input
この関数は端末入力バッファの内容を廃棄し、 定義中のキーボードマクロを取り消す。 これはnilを返す。

以下の例で、フォームを評価しはじめてから、ユーザーは何文字か打つ。 sleep-forが待機を終えると、 discard-inputは待機中に打たれた文字をすべて破棄する。

 
(progn (sleep-for 2)
       (discard-input))
     => nil



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

20.7 特殊イベント

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Special%20Events"
"elisp/特殊イベント"へのコメント(無し)

特殊イベントは、読まれるとただちに非常に低レベルで処理されます。 関数read-eventはこれらのイベントをそれ自身で処理してしまい、 それらを返すことはありません。

このように処理されるイベントは表示されることはなく、 キー列に組み込まれることもなく、 last-command-event(this-command-keys)の値に 現れることもありません。 特殊イベントが数値引数を破棄することはなく、 unread-command-eventsで読み戻すことはできません。 特殊イベントがキーボードマクロに現れることはなく、 読者がキーボードマクロを定義しているときに、 特殊イベントがキーボードマクロに記録されることはありません。

しかし、それらのイベントは、 読まれた直後にはlast-input-eventに現れますから、 これからイベントの定義で実際のイベントを見ることができます。

iconify-framemake-frame-visibledelete-frameの イベント型は、通常このように処理されます。 特殊イベントをどのように処理するか、 どのイベントが特殊イベントであるかを定義する キーマップは変数special-event-mapにあります(see 節 21.6 活性なキーマップ)。



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

20.8 時間待ちと入力待ち

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Waiting"
"elisp/時間待ちと入力待ち"へのコメント(無し)

待機関数は、指定時間経過するか入力がくるまで待つように設計してあります。 たとえば、ユーザーに表示を眺める時間を与えるために 計算途中で休止したいでしょう。 sit-forは、休止してスクリーンを更新し、 入力がくるとただちに戻ります。 一方、sleep-forはスクリーンを更新せずに休止します。

Function: sit-for seconds &optional millisec nodisp
この関数は(処理待ちのユーザーからの入力がなければ)再表示を行い、 seconds秒休止するか、入力がくるまで待つ。 入力がこずに(20.6.4 その他のイベント入力機能input-pending-pを参照) 指定時間だけ休止した場合は、戻り値はtである。 さもなければ、戻り値はnilである。

引数secondsは整数である必要はない。 それが浮動小数点数であると、sit-forは秒の小数も待つ。 秒単位しか扱えないシステムもあり、 そのようなシステムではsecondsを秒に切り下げる。

省略可能な引数millisecは、ミリ秒単位の追加待ち時間を指定する。 これはsecondsで指定した時間に加えられる。 秒未満を扱えないシステムでは、 millisecに0以外を指定するとエラーになる。

入力がくると再表示をつねに取り止め、 再表示開始まえに入力がくると、いっさい再表示しない。 したがって、処理待ちの入力があると、再表示を強制する方法はない。 しかし、処理待ちの入力がなければ、(sit-for 0)で再表示を強制できる。

nodispnil以外であると、 sit-forは再表示はしないが、 入力がくるとただちに(あるいは指定時間だけ経過すると)戻る。

フレームをアイコンにしたりアイコンにしたフレームを開くと イベントが生成されるため、sit-forは戻る。 see 節 20.5.10 ウィンドウシステムのその他のイベント

sit-forの普通の目的は、 読者が表示したテキストを読む時間をユーザーに与えることである。

Function: sleep-for seconds &optional millisec
この関数は表示を更新せずに単にseconds秒だけ休止する。 入力にはいっさい注意を払わない。 nilを返す。

引数secondsは整数である必要はない。 それが浮動小数点数であると、sleep-forは秒の小数も待つ。 秒単位しか扱えないシステムもあり、 そのようなシステムではsecondsを秒に切り下げる。

省略可能な引数millisecは、ミリ秒単位の追加待ち時間を指定する。 これはsecondsで指定した時間に加えられる。 秒未満を扱えないシステムでは、 millisecに0以外を指定するとエラーになる。

遅延を保証したい場合にsleep-forを使う。

現在時刻を取得する関数についてはSee 節 37.5 時刻



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

20.9 中断

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Quitting"
"elisp/中断"へのコメント(無し)

Lisp関数が動作中にC-gを打つと、 Emacsがなにを行っていても中断を引き起こします。 つまり、もっとも内側の活性なコマンドループに制御が戻ります。

コマンドループがキーボード入力を待っているときにC-gを打っても、 中断を引き起こさずに、普通の入力文字として動作します。 もっとも単純な場合、C-gはコマンドkeyboard-quitを実行しますが、 その効果は中断を引き起こすことですから、読者には区別できないはずです。 しかし、プレフィックスキーに続けてC-gを打つと、 それらは組み合わされて未定義キーになります。 その効果は、前置引数を含めてプレフィックスキーを取り消します。

ミニバッファでは、C-gには別の定義があって、 ミニバッファを強制終了させます。 つまり、ミニバッファから抜け出て中断します。 (単に中断したのでは、ミニバッファ内で コマンドループに戻るだけである。) コマンドループで入力を読んでいるときにC-gで直接中断しない理由は、 このようにミニバッファでその意味を再定義できるようにするためです。 ミニバッファでは、プレフィックスキーに続くC-gは再定義してなく、 プレフィックスキーと前置引数を取り消すという通常の効果を持ちます。 C-gがつねに直接中断するのでは、このようにすることさえ不可能です。

C-gが直接に中断するときには、 変数quit-flagtを設定します。 Emacsはこの変数を適切なときに検査しnilでないと中断します。 したがって、quit-flagnil以外を設定すると 中断を引き起こします。

Cのコードのレベルでは、どこでも中断できるわけではありません。 quit-flagを検査している特別な箇所だけです。 このようにするのは、それ以外の箇所で中断すると Emacsの内部状態に矛盾をきたす可能性があるからです。 中断は安全な場所まで延期されるので、 中断によってEmcasがクラッシュすることはありません。

read-key-sequenceread-quoted-charなどのある種の関数は、 入力を待っている場合であっても中断を完全に抑制します。 中断するかわりに、C-gは入力として働きます。 read-key-sequenceの場合、コマンドループにおいて C-gの特別なふるまいをもたらします。 read-quoted-charの場合、 C-qC-gをクォートできるようになります。

変数inhibit-quitnil以外の値を束縛することで Lisp関数のある部分において中断を抑制できます。 そうすると、C-gはそれでもいつもどおり quit-flagtにしますが、 その通常の結果である中断は抑制されます。 最終的にフォームletの終りで束縛が解除されるなどして inhibit-quitが再度nilになります。 その時点でもquit-flagnil以外であると 要求した中断がただちに起こります。 このふるまいは、プログラムの『臨界領域』では 中断が起こらないことを保証する理想的なものです。

read-quoted-charなどの)ある種の関数では、 C-gは特別に処理され中断を引き起こしません。 inhibit-quittを束縛して入力を読み取り、 inhibit-quitが再度nilになるまえに quit-flagnilにすることでそのようにします。 これを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)))
      ...変数codeに設定する...)
    code))

Variable: quit-flag
inhibit-quitnilであれば、 この変数がnil以外であるとEmacsはただちに中断する。 C-gは、inhibit-quitに関わらず、 通常、quit-flagnil以外を設定する。

Variable: inhibit-quit
この変数は、quit-flagnil以外の値に設定されたときに Emacsが中断すべきかどうかを決定する。 inhibit-quitnil以外であると、 quit-flagに特別な意味はない。

コマンド: keyboard-quit
この関数は(signal 'quit nil)quit条件を通知する。 これは中断と同じことを行う。 (9.5.3 エラーsignalを参照。)

中断として使うC-g以外の特殊文字を使えます。 37.8 端末入力の関数set-input-modeを参照してください。



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

20.10 前置コマンド引数

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Prefix%20Command%20Arguments"
"elisp/前置コマンド引数"へのコメント(無し)

Emacsのほとんどのコマンドは、前置引数(prefix argument)、 つまりコマンド自身のまえに指定された数を利用できます。 (前置引数とプレフィックスキーを混同しないこと。) 前置引数はつねに値で表現され、 nilであると現在は前置引数がないことを表します。 各コマンドは、前置引数を使ってもよいし、無視してもかまいません。

前置引数には2つの表現方法があります。 (raw)と数値(numeric)です。 エディタコマンドループでは、内部的には生の表現を使い、 その情報を保持するLisp変数もそのようにしますが、 コマンドではどちらの表現を要求してもかまいません。

生の前置引数の値にはつぎの可能性があります。

いろいろな前置引数でつぎの関数を呼び出す例を示します。

 
(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      ; (C-u 3と同じ)

C-u -   M-x display-prefix  -| -      

M--     M-x display-prefix  -| -      ; (C-u -と同じ)

C-u - 7 M-x display-prefix  -| -7     

M-- 7   M-x display-prefix  -| -7     ; (C-u -7と同じ)

Emacsは、前置引数を保持するために2つの変数、 prefix-argcurrent-prefix-argを使います。 他のコマンド向けに前置引数を設定するuniversal-argumentなどの コマンドは、前置引数をprefix-argに保持します。 対照的に、current-prefix-argには 現在のコマンドに対して前置引数を運ぶ役割があり、 この変数に設定しても以後のコマンドに対する前置引数には なんの効果もありません。

通常、コマンドは、interactive宣言により、 「生」か「数値」のいずれの表現の前置引数を使うか指定します。 (See 節 20.2.1 interactiveの使い方。) あるいは、変数current-prefix-argにある前置引数の値を 関数から直接見てもかまいませんが、 これは見通しのよい方法ではありません。

Function: prefix-numeric-value arg
この関数は、有効な生の前置引数の値argからそれに等価な数値を返す。 引数は、シンボル、数、リストのいずれかである。 それがnilであると、戻り値は1である。 -であると、戻り値は-1である。 数であると、その数を返す。 リストであると、リストの(数であるはずの)CARを返す。

Variable: current-prefix-arg
この変数は、現在のコマンドに対する生の前置引数を保持する。 コマンドが直接この変数を調べてもよいが、 前置引数を参照する普通の方法は(interactive "P")を使うことである。

Variable: prefix-arg
この変数の値は、つぎの編集コマンド向けの生の前置引数である。 後続のコマンド向けの前置引数を指定するuniversal-argumentなどの コマンドは、この変数に設定することで動作する。

Variable: last-prefix-arg
まえのコマンドで使われた生の前置引数の値。

つぎのコマンドは、後続のコマンド向けの前置引数を設定するためのものです。 それ以外の目的には呼ばないでください。

コマンド: universal-argument
このコマンドは入力を読み取り、後続のコマンド向けの前置引数を指定する。 なにをしているか理解していない限り、読者自身でこのコマンドを呼ばないこと。

コマンド: digit-argument arg
このコマンドは、後続のコマンド向けの前置引数に追加する。 引数argは、このコマンドが呼び出されるまえの生の前置引数であり、 前置引数を更新する計算に使われる。 なにをしているか理解していない限り、読者自身でこのコマンドを呼ばないこと。

コマンド: negative-argument arg
このコマンドは、後続のコマンド向けの数値前置引数に追加する。 引数argは、このコマンドが呼び出されるまえの生の前置引数であり、 その値の符号を変えて新たな前置引数とする。 なにをしているか理解していない限り、読者自身でこのコマンドを呼ばないこと。



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

20.11 再帰編集

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Recursive%20Editing"
"elisp/再帰編集"へのコメント(無し)

Emacsが動作を始めると、Emacsのコマンドループに自動的に入ります。 このトップレベルのコマンドループからはけっして抜けることはなく、 Emacsが動いている限り動作し続けます。 Lispプログラムからコマンドループを起動することもできます。 そうすると、活性なコマンドループが複数作られることになるので、 それを再帰編集(recursive editing)と呼びます。 再帰編集レベルには、それを起動したコマンドを一時休止させ、 当該コマンドを再開するまでユーザーにどんな編集でも許す効果があります。

再帰編集中に利用可能なコマンドは、トップレベルのコマンドループと 同じものでありキーマップで定義されます。 再帰編集を抜けるための数個の特別なコマンドがあり、 完了すると再帰編集レベルから抜ける別のコマンドもあります。 (再帰編集を抜けるコマンドはつねに利用可能であるが、 再帰編集中でないとなにも行わない。)

再帰編集を含むすべてのコマンドループでは、 コマンドループから実行したコマンドのエラーによって コマンドループから抜け出さないように汎用目的のエラーハンドラを設定します。

ミニバッファでの入力は、特別な種類の再帰編集です。 これには、ミニバッファやミニバッファ用ウィンドウを表示するなどの特別な 処理がありますが、読者が考えるよりは少ないのです。 ミニバッファでは特別なふるまいをするキーもありますが、 それらはミニバッファのローカルマップによるものです。 ウィンドウを切り替えると、Emacsの普通のコマンドを使えます。

再帰編集レベルを起動するには、関数recursive-editを呼び出します。 この関数にはコマンドループが含まれています。 さらに、exitを伴ったcatchの呼び出しもあり、 これにより、exitへ投げることで 再帰編集レベルから抜け出せるようになっています (see 節 9.5.1 明示的な非ローカル脱出: catchthrow)。 t以外の値を投げると、recursive-editは、 呼び出し側の関数へ普通に戻ります。 コマンドC-M-cexit-recursive-edit)は、これを行います。 値tを投げるとrecursive-editに中断を引き起こし、 1つ上のレベルのコマンドループへ制御を戻します。 これを強制終了(aborting)と呼び、 C-]abort-recursive-edit)で行えます。

ミニバッファを使う場合を除いて、ほとんどのアプリケーションでは 再帰編集を使うべきではありません。 カレントバッファのメジャーモードを 一時的な特別なメジャーモードに変更するほうが、 一般にはユーザーにとってより便利です。 ただし、当該メジャーモードには、 まえのモードに戻るコマンドを用意しておきます。 (rmailのコマンドeは、この方式を使っている。) あるいは、『再帰的に』編集する別のテキストをユーザーに与えたい場合には、 特別なモードの新たなバッファを作成してそれを選択します。 当該モードには、処理を終えてまえのバッファに戻るコマンドを 定義しておきます。 (rmailのコマンドmは、このようにする。)

再帰編集はデバッグに便利です。 ブレークポイントの一種として関数定義に debugの呼び出しを挿入しておくと、 その箇所に達したときにいろいろと調べられます。 debugは再帰編集を起動しますが、デバッガとしての機能も提供します。

query-replaceC-rを打ったり、 C-x qkbd-macro-query)を使ったときにも 再帰編集レベルが使われます。

Function: recursive-edit
この関数はエディタコマンドループを起動する。 Emacsの初期化過程で自動的に呼び出され、ユーザーが編集できるようにする。 Lispプログラムから呼ばれると、再帰編集レベルに入る。

以下の例では、関数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

コマンド: exit-recursive-edit
この関数は、(ミニバッファでの入力を含む)もっとも内側の再帰編集から抜ける。 その関数定義は実質的には(throw 'exit nil)である。

コマンド: abort-recursive-edit
この関数は、再帰編集から抜けたあとでquitを通知することで、 (ミニバッファでの入力を含む)もっとも内側の再帰編集を 要請したコマンドを強制終了する。 その関数定義は実質的には(throw 'exit t)である。 see 節 20.9 中断

コマンド: top-level
この関数は、すべての再帰編集を抜ける。 すべての計算を抜け出てメインのコマンドループへ直接戻るため、値は返さない。

Function: recursion-depth
この関数は再帰編集の現在の深さを返す。 活性な再帰編集がなければ0を返す。



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

20.12 コマンドを禁止する

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Disabling%20Commands"
"elisp/コマンドを禁止する"へのコメント(無し)

コマンドを禁止するとは、 コマンドを実行するまえにユーザーの確認を必要とするように コマンドに印を付けることです。 コマンドを禁止するのは、 初心者に混乱をもたらす可能性のあるコマンドに対してや、 コマンドの誤用を防ぐためです。

コマンドを禁止する低レベルの機構は、 コマンドの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 節 `使用禁止コマンド' in

GNU Emacs マニュアル
。 コマンドを禁止しても、Lispプログラムから関数として呼び出すことには なんの影響もありません。

コマンド: enable-command command
これ以降、特別な確認なしにcommandを実行可能にする。 さらに(ユーザーが了承すれば)ユーザーの`.emacs'ファイルを変更して、 将来のセッションでもそのようにする。

コマンド: disable-command command
これ以降、commandの実行には特別な確認を必要とするようにする。 さらに(ユーザーが了承すれば)ユーザーの`.emacs'ファイルを変更して、 将来のセッションでもそのようにする。

Variable: disabled-command-hook
禁止したコマンドをユーザーが対話的に起動したとき、 禁止したコマンドのかわりにこのノーマルフックを実行する。 フック関数では、this-command-keysを使って コマンドを実行するためにユーザーがなにを入力したかを調べ、 コマンドそのものを探し出せる。 see 節 22.6 フック

デフォルトでは、disabled-command-hookには、 ユーザーに処理を進めるかどうかを問い合わせる関数が入っている。



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

20.13 コマンド履歴

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Command%20History"
"elisp/コマンド履歴"へのコメント(無し)

コマンドループでは、実行した複雑なコマンドの履歴を管理していて、 それらのコマンドを簡単に繰り返せるようにしています。 複雑なコマンドとは、ミニバッファを使って引数を読むコマンドです。 これには、任意のM-xコマンド、任意のM-:コマンド、 ミニバッファから引数を読み取るinteractive指定を持つ任意のコマンドが 含まれます。 コマンド自身の実行中に明示的にミニバッファを使っても、 複雑なコマンドとはみなしません。

Variable: command-history
この変数の値は、最近使った複雑なコマンドのリストであり、 各要素は評価すべきフォームを表す。 編集セッション中は、すべての複雑なコマンドを集積するが、 (変数history-lengthで指定される)最大サイズに達すると 新しい要素を追加するたびに古い要素を削除する。

 
command-history
=> ((switch-to-buffer "chistory.texi")
    (describe-key "^X^[")
    (visit-tags-table "~/emacs/src/")
    (find-tag "repeat-complex-command"))

この履歴リストは、実際にはミニバッファ履歴(see 節 19.4 ミニバッファの履歴) の特別な場合です。 要素は文字列ではなく式なのです。

まえのコマンドを編集したり取り出すための専用コマンドがたくさんあります。 コマンドrepeat-complex-commandlist-command-historyは、 ユーザーマニュアル (see 節 `ミニバッファコマンドの繰り返し' in

GNU Emacs マニュアル
)に説明してあります。 ミニバッファ内では、通常のミニバッファ履歴コマンドを使えます。



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

20.14 キーボードマクロ

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp&node=Keyboard%20Macros"
"elisp/キーボードマクロ"へのコメント(無し)

キーボードマクロは、 コマンドとみなせる入力イベントのまとまった列であり、 キーの定義から構成されます。 Lispにおけるキーボードマクロの表現は、 イベントを含んだ文字列やベクトルです。 キーボードマクロとLispマクロ(see 節 12. マクロ)を混同しないでください。

Function: execute-kbd-macro kbdmacro &optional count
この関数はキーボードマクロkbdmacroをイベント列として実行する。 kbdmacroが文字列かベクトルであると、 その中のイベントをユーザーが入力した場合とまったく同様に実行する。 列は単一のキーイベントである必要はない。 通常、キーボードマクロの定義は、複数のキー列を連結したものである。

kbdmacroがシンボルであると、 kbdmacroのかわりにその関数定義を用いる。 それがさらに別のシンボルであると、この処理を繰り返す。 最終的な結果は、文字列かベクトルであること。 結果がシンボルでも文字列でもベクトルでもないと、 エラーを通知する。

引数countは繰り返し回数であり、 kbdmacroをその回数だけ実行する。 countを省略するかnilであると、kbdmacroを1回実行する。 countが0であると、 kbdmacroの実行をエラーに出会うか探索に失敗するまで繰り返す。

execute-kbd-macroを使った例についてはsee 節 20.6.2 単一イベントの読み取り

Variable: executing-macro
この変数は、現在実行中のキーボードマクロの定義である 文字列やベクトルを保持する。 これがnilであると、現在実行中のマクロはない。 コマンドでこの変数を検査することで、 マクロ実行で起動されたときのふるまいを変更できる。 読者自身はこの変数に設定しないこと。

Variable: defining-kbd-macro
この変数は、キーボードマクロを定義中かどうかを表す。 コマンドでこの変数を検査することで、マクロ定義中のふるまいを変更できる。 コマンドstart-kbd-macroend-kbd-macroがこの変数に設定する。 読者自身は設定しないこと。

この変数は現在の端末に対してつねにローカルであり、 バッファに対してローカルにはならない。 see 節 28.2 複数ディスプレイ

Variable: last-kbd-macro
この変数は、もっとも最近に定義されたキーボードマクロの定義である。 その値は、文字列かベクトル、あるいは、nilである。

この変数は現在の端末に対してつねにローカルであり、 バッファに対してローカルにはならない。 see 節 28.2 複数ディスプレイ


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