Next: , Previous: , Up: フレーム   [Contents][Index]


30.10 入力のフォーカス

どんなときでもEmacs内のただ1つのフレームが選択されたフレーム(selected frame)です。選択されたウィンドウ(ウィンドウの選択を参照)は常に選択されたフレーム上にあります。

Emacsがフレームを複数端末(複数の端末を参照)上に表示する際には、各端末は自身の選択されたフレームをもちます。しかしそれらのうち1つだけが、いわゆる選択されたフレームであり、それはもっとも最近に入力があった端末に属すフレームです。つまり特定の端末からのコマンドをEmacsが実行する際には、その端末上の1つが選択されたフレームです。Emacsが実行するコマンドは常に1つだけなので、選択されたフレームは常に1つだけだと考える必要があります。このフレームこそが、このマニュアルで選択されたフレームと呼ぶフレームです。選択されたフレームを表示するディスプレイは、選択されたフレームのディスプレイ(selected frame’s display)です。

Function: selected-frame

この関数は選択されたフレームをリターンする。

いくつかのウィンドウシステムおよびウィンドウマネージャーは、マウスがあるウィンドウオブジェクトにキーボード入力をダイレクトします。それ以外は、さまざまなウィンドウオブジェクトにフォーカスをシフト(shift the focus)するために、明示的なクリックやコマンドを要求します。どちらの方法でもEmacsはフォーカスをもつフレーム(複数形のframes)を自動的に追跡します。Lisp関数から別フレームに明示的に切り替えるためには、select-frame-set-input-focusを呼び出します。

前のパラグラフ中の“複数形のframes”は意図したものです。Emacs自身は選択されたフレームを1つしかもたないのにたいして、Emacsは多くの異なる端末上にフレームをもつことができ(ウィンドウシステムへの接続は端末とみなされることを思い出してほしい)、各端末は入力フォーカスをもつフレームにたいして独自のアイデアをもっています。Xウィンドウシステムの下ではユーザー入力は個別に入力の“指定席”に組織化されていて、それらの指定席それぞれが独自に特定の入力フォーカスを順に得ることができるのです。あるフレームに入力フォーカスをセットすると、Emacsが最後に相互作用を行った指定席のフレームの端末にフォーカスがセットされますが、他の端末上のフレームや指定席に依然としてフォーカスが残るかもしれません。

入力フォーカスをセットする前に指定された端末上でユーザーと何らかの相互作用が発生した場合には、Xサーバーが指定席をランダムに選んで(通常はもっとも小さい番号の指定席)、そこに入力フォーカスをセットします。

関数select-frameを呼び出すことにより、Lispプログラムが一時的にフレームを切り替えることができます。これはそのウィンドウシステムのフォーカス概念を変更はしません。変更ではなく何らかの方法により制御が再確認(reasserted)されるまで、ウィンドウマネージャーの制御から抜け出す(escape)のです。

テキスト端末使用時はその端末上で一度に表示できるフレームは1つだけなので、select-frame呼び出し後に次回の再表示で新たに選択されたフレームが実際に表示されます。このフレームは次のselect-frame呼び出しまで選択されたままです。テキスト端末上の各フレームはバッファー名の前に表示される番号をもちます(モードラインで使用される変数を参照)。

Function: select-frame-set-input-focus frame &optional norecord

この関数はframeを選択して、(他のフレームのせいで不明瞭な場合には)それを前面に移動(raise)してウィンドウシステムのフォーカス授与を試みる。テキスト端末上では、次回再表示時に端末スクリーン全体に新たにフレームが表示される。オプション引数norecordselect-frame(下記参照)のときと同じ意味をもつ。この関数のリターン値に意味はない。

以下で説明する関数は理想的には他のフレームを前面にレイズすることなくフレームにフォーカスするべきです。残念ながらウィンドウシステムやウィンドウマネージャーの多くはこの要求を拒絶するかもしれません。

Function: x-focus-frame frame &optional noactivate

この関数はframeのレイズを要さずにframeにXサーバーのフォーカスを与える。framenilなら選択されたフレームを意味する。Xの配下ではオプション引数noactivateが非nilなら、frameのウィンドウシステムのウィンドウが“アクティブ”なウィンドウになることを防ぐことを意味する。これはframeが他のフレームの前面にならないようさらに強く主張する。

MS-Windowsではnoactivate引数に効果はない。しかしframeが子フレーム(子フレームを参照)なら、この関数は通常は他の子レームの前面にレイズすることなくframeにフォーカスする。

この関数はウィンドウシステムのサポートがなければ何もしない。

Command: select-frame frame &optional norecord

この関数はフレームframeを選択して、Xサーバーのフォーカスがあればそれを一時的に無視する。frameにたいする選択は次回ユーザーが別フレームに何かを行うか、この関数の次回呼び出しまで継続する(ウィンドウシステムを使用する場合には以前に選択されていたフレームに依然としてウィンドウシステムの入力フォーカスがあるかもしれないので、コマンドループからリターン後にそのフレームが選択されたフレームとしてリストアされるかもしれない)。

指定されたframeは選択されたフレームとなり、その端末が選択された端末になる。この関数はその後にframe内で選択されていたウィンドウを第1引数、norecordを第2引数にしてselect-windowをサブルーチンとして呼び出す(したがってnorecordが非nilなら、もっとも最近に選択されたウィンドウとバッファーリストの変更を避ける)。ウィンドウの選択を参照のこと。

この関数はframeframeが削除されていればnilをリターンする。

一般的には実行後に端末を戻すよう切り替えることなく、別の端末に切り替えるのが可能な手段としてselect-frameを決して使用しないこと。

Emacsは選択されたフレームをサーバーとしてアレンジしてウィンドウシステムに要求することによりウィンドウシステムと協調します。Emacsのいずれかのフレームが選択されたことをあるウィンドウシステムが通知すると、Emacsは内部的にfocus-inイベントを生成します。Emacsフレームをフォーカス変更イベントの通知をサポートするxtermのようなテキスト端末エミュレーター上で表示している際には、テキストモードのフレームでもfocus-inとfocus-outのイベントを利用できます。フォーカスイベントは通常はhandle-focus-inで処理されます。

Command: handle-focus-in event

この関数は明示的なフォーカス通知をサポートするウィンドウシステムと端末からのfocus-inイベントを処理する。これはframe-focus-stateが問い合わせてafter-focus-change-functionを呼び出すフレームごとのフォーカスフラグを更新する。加えてEmacsが認識する選択されたフレームを、いくつかの端末でもっとも最近フォーカスされたフレームに切り替えるためにswitch-frameイベントを生成する。Emacsの選択されたフレームをもっとも最近フォーカスされたフレームに切り替えることは、それぞれの端末にある他のフレームがフォーカスをもち続けることを意味しないことに注意することが大事。自分でこの関数を呼び出してはならない。かわりにロジックをafter-focus-change-functionにつけ加えること。

Command: handle-switch-frame frame

この関数はフォーカス通知や最後のイベントとは異なるフレームから到着した入力イベントを含むさまざまな状況においてEmacsが自身のために生成するswitch-frameイベントを処理する。自分でこの関数を呼び出してはならない。

Function: redirect-frame-focus frame &optional focus-frame

この関数はframeからfocus-frameにフォーカスをリダイレクトする。これはframeにかわってfocus-frameが以降のキーストロークとイベントを受け取るであろうことを意味する。そのようなイベント後にはlast-event-frameの値はfocus-frameになるだろう。またframeを指定したswitch-frameイベントも、かわりにfocus-frameを選択するだろう。

focus-frameが省略またはnilなら、frameにたいするすべての既存のリダイレクションがキャンセルされるので、frameが自身のイベントを再度受け取ることになる。

フォーカスリダイレクトの用途の1つは、ミニバッファーをもたないフレームにたいしてである。これらのフレームは別フレーム上のミニバッファーを使用する。別フレーム上のミニバッファーをアクティブにすることは、そのフレームにフォーカスをリダイレクトすることである。これはたとえマウスがミニバッファーをアクティブにしたフレーム内に留まっていても、ミニバッファーが属すフレームにフォーカスを置く。

フレーム選択はフォーカスリダイレクションの変更も可能にする。fooが選択されているときにフレームbarを選択することにより、fooを指すすべてのリダイレクションはかわりにbarを指す。これはユーザーがselect-windowを使用してあるフレームから別のフレームに切り替えた際に、フォーカスのリダイレクトが正しく機能することを可能にする。

これはフォーカスが自身にリダイレクトされたフレームが、フォーカスがリダイレクトされていないフレームとは異なる扱いを受けることを意味する。前者にたいしてselect-frameは影響するが、後者には影響がない。

このリダイレクションは、それを変更するためにredirect-frame-focusが呼び出されるまで継続する。

Function: frame-focus-state frame

この関数はframeの既知の最後のフォーカス状態を取得する。

フレームにフォーカスがないと解っていればnil、フォーカスがあると解っていればt、フレームのフォーカス状態をEmacsが知らなければunknownをリターンする(この最後の状態は明示的なフォーカス通知をサポートしない端末で実行中のTTYフレームで見ることがあるかもしれない)。

Variable: after-focus-change-function

これはEmacsがフレームへのフォーカスを取得あるいは喪失する可能性に気づいた際に引数なしで呼び出される関数である。フォーカスイベントの配信は非同期であり、期待する順に配信されないかもしれないので、フレームのフォーカス状態に応じて何かを行いたいコードはすべてのフレームをチェックする必要がある。

たとえばフレームへのフォーカス有無にもとづきバックグラウンドカラーをセットするシンプルな関数例を以下に示す:

(add-function :after after-focus-change-function
              #'my-change-background)
(defun my-change-background ()
  (dolist (frame (frame-list))
    (pcase (frame-focus-state frame)
      (`t (set-face-background 'default "black" frame))
      (`nil (set-face-background 'default "#404040" frame)))))

フォーカスイベント配信の差異や別の要因のせいで、複数フレームが入力イベントをもつように見える場合があるので、このような状況に直面しても大丈夫なように堅牢なコードを記述するべきである。

ウィンドウシステムによってはフォーカスイベントが繰り返し配信されて、期待した値にセットする前に異なるフォーカス状態が配信されるかもしれない。フォーカス通知にもとづくコードはおそらく再表示まで処理を遅延することにより、フォーカス変更から生じるユーザーに可視の更新を“デバウンス(debounce)”する必要がある。

この関数はread-eventの内部を含む任意のコンテキストで呼び出されるかもしれないので、プロセスフィルター記述時と同様の注意を払うこと。

User Option: focus-follows-mouse

このオプションはフレーム内にマウスポインターを移動した際にウィンドウマネージャーがフォーカスを転送するかどうかと、その方法についてEmacsに知らせる。意味がある値は以下の3つ:

nil

デフォルト値nilはウィンドウマネージャーが“click-to-focus(フレームがフォーカスを取得するためにフレーム内部でマウスをクリックする必要がある)”のポリシーにしたがう際に使用すること。

t

tはマウスポインターの位置にしたがってウィンドウマネージャーが自動的にフォーカスするが、フォーカスを得たフレームは自動的にレイズされず別のウィンドウシステムのウィンドウに隠されたままかもしれないときに使用すること。

auto-raise

auto-raiseはマウスポインターの位置にしたがってウィンドウマネージャーが自動的にフォーカスして、フォーカスを得たフレームは自動的にレイズされる際に使用すること。

このオプションが非nilなら、Emacsはselect-frame-set-input-focusが選択したフレームにマウスポインターを移動する。この関数はother-framepop-to-bufferなどいくつかのコマンドで使用される。

ウィンドウマネージャーは“通常”のフレームのレイズには通常は配慮するので、値tauto-raiseを区別する必要はない。これはmouse-autoselect-window (マウスによるウィンドウの自動選択を参照)を通じて子フレームをレイズするために有用。

このオオプションは“sloppy”なフォーカス(ウィンドウシステムの別ウィンドウにマウスポインターが移動しないかぎり以前にフォーカスのあったフレームがフォーカスを保持する)と“strict”なフォーカス(マウスポインターが去るとフレームは即座にフォーカスを失う)を区別しないことに注意。ウィンドウマネージャーがフォーカスや自動レイズの遅延をサポートしていなくても、新たなフレームがフォーカスを取得(あるいは自動レイズ)するまでの時間を明示的に指定できる。

変数mouse-autoselect-window (マウスによるウィンドウの自動選択を参照)をカスタマイズすることにより、個別のEmacsウィンドウにたいして“focus follows mouse”ポリシーを提供できる。