アクセラレータキー

アクセラレータキーというのは、マウスを使わずにアプリケーションの機能を呼び出すためのいわゆるショートカットキーです。例えば、Ctrl-S(保存)やCtrl-Z(元に戻す)などのことです。curlアクセラレータキーを実装するには、MenuBarに組み込むMenuActionにkey-accel-stringを指定します。以下の例は、FileメニューのOpenという項目に、Ctrl-Oのアクセラレータキーを設定しています。

{MenuBar
    {SubMenu
        label = "&File",
        {MenuAction label = "&Open",
            key-accel-string = "Ctrl-O",
            {on Action do
                {choose-file}
            }
        }
    }
}


MenuBarがないアプリケーションでショートカットキーを実現する場合はどのようにすればよいでしょうか?
実は、アクセラレータキーはFocusManagerというクラスによって実現されています。FocusManagerは、各View(ウィンドウ)毎に存在するオブジェクトで、Visual.get-focus-managerというメソッドを使ってアクセスできます。このFocusManagerを使ってアクセラレータキーを手動で設定することができます。

{if-non-null fm={(画面上の任意のVisualオブジェクト).get-focus-manager} then
    ||ESCキーで呼び出す機能の定義
    let esc-accel:KeyAccel =
        {KeyAccel
            key-accel-string = "esc",
            {on Action do
                {popup-message "ESCが押されました"}
            }
        }
    {fm.add-key-accel esc-accel}
}

get-focus-managerは、画面上に存在する任意のグラフィカルオブジェクトで呼び出して構いません。どのオブジェクトを使用しても同じView内のオブジェクトであれば、そのViewに関連付けられた同一のFocusManagerインスタンスが取得できます。
アクセラレータキーおよびそれによって呼び出される機能は、MenuActionの代わりにKeyAccelというクラスを使って定義します。このKeyAccelを、FocusManagerに追加すれば完了です。

気をつけなければならないのは、画面に表示されているオブジェクト*1でなければget-focus-managerでFocusManagerインスタンスを取得できないことです。そのため、上記の処理は大抵AttachEventのイベントハンドラ内で行うのが適当になります。

{on AttachEvent at v:Visual do
    {if-non-null fm={v.get-focus-manager} then
        {fm.add-key-accel xxx-key-accel}
    }
}

*1:正確には、View上のグラフィカル階層にattachされているオブジェクト