Skip to content
anmitsu edited this page Dec 2, 2012 · 3 revisions

キーバインド

1 はじめに

pyful のキーバインドは,例外なくすべて変更可能です。

キーバインドの実装は,ファイラー画面やコマンドラインを構成しているインターフェースを提供するウィジットで定義されている辞書構造のキーマップによって実現されています。キーバインドの設定は,このキーマップを設定ファイル rc.py で変更することで行います。デフォルトでは,Emacs風のキーバインドに設定されていますが,設定ファイルの編集しだいでは,Vim風のキーバインドを実現することも可能です。また,キーバインドを変更するだけでなく,新たにコマンド(外部コマンドも含む)をキーマップに登録し,キーバインドを追加することも可能です。メニュー機能 を利用することで,Emacsの C-x C-s ような階層化されたキーバインドを実現することも可能です。これにより,ユーザが望むコマンドを,ほぼ無制限にキーボードによって実行することできます。

2 キーバインドの変更

キーマップの書式は,以下のようになっています。

keymap = {
    "キーボード文字列1": 呼び出し可能オブジェクト,
    "キーボード文字列2": 呼び出し可能オブジェクト,
    .
    .
    .
    "キーボード文字列n": 呼び出し可能オブジェクト,
}

2.1 キーボード文字列

キーボード文字列は,以下のような形式で指定します。

キーボード文字列 説明
a “a” を入力
A Shift + a
C-a Ctrl + a
M-a Meta + a
M-A Meta + Shift + a
M-C-a Meta + Ctrl + Shift + a

なお,CtrlとShiftキーの組み合わせ C-A やMetaとCtrlとShiftキーの組み合わせ M-C-A の入力は, curses ライブラリで取得することができないため,キーボード文字列として指定することはできません。

カーソルキーやファンクションキーのような特殊なキー入力を表すキーボード文字列は,以下のような形式で指定します。

特殊キー 説明
<up> 上カーソルキー
<left> 左カーソルキー
<down> 下カーソルキー
<right> 右カーソルキー
<home> Homeキー
<end> Endキー
<ppage> PageUpキー
<npage> PageDownキー
<backspace> バックスペースキー
<dc> デリートキー
<f1>, <f2>, …, <f63> ファンクションキーF1 から F63
RET エンターキー,リターンキー
SPC スペースキー
ESC エスケープキー

なお,これらの特殊キーは,Metaキー,Shiftキー,Ctrlキーと組み合わせることはできません。ただし,エンターキーは例外で, M-C-j としてMetaキーとエンターキーの組み合わせは可能です。また,エンターキーと C-m のキーコードは同様に認識されるため,別々に割り当てることはできません。同様の理由から,TABキーは C-i として認識されます。ただし,これらの特殊キーの解釈は端末依存であるため,必ずしも上記のようにキーコードが解釈されるとは限りません。

キーボード文字列には,アルファベット以外にも “?” や “=” といった記号も指定できます。この場合も,アルファベットと同様にMetaキーやCtrlキーと組み合わせることが可能です。また,”あ” や “亜” といった日本語もキーボード文字列として指定できます。

2.2 キーマップの登録

キーマップの登録には,関数 pyful.widget.define_key を利用します。 pyful.widget.define_key は,第1引数にキーマップを登録するオブジェクト,第2引数に辞書形式のキーマップを取ります。

例として,コマンドラインにおける補完機能のキーバインドの変更を示します。補完機能のキーバインドは,デフォルトでEmacs風のキーマップが設定されています。ここでは,カーソルの上下左右移動をVim風に変更します。

pyful.widget.define_key(widgets.cmdline.completion, {
    "j"   : lambda: widgets.cmdline.completion.cursordown(),
    "k"   : lambda: widgets.cmdline.completion.cursorup(),
    "l"   : lambda: widgets.cmdline.completion.mvcursor(+1),
    "h"   : lambda: widgets.cmdline.completion.mvcursor(-1),
    "M-n" : lambda: widgets.cmdline.completion.mvscroll(+1),
    "M-p" : lambda: widgets.cmdline.completion.mvscroll(-1),
    "C-v" : lambda: widgets.cmdline.completion.pagedown(),
    "M-v" : lambda: widgets.cmdline.completion.pageup(),
    "C-g" : lambda: widgets.cmdline.completion.finish(),
    "C-c" : lambda: widgets.cmdline.completion.finish(),
    "ESC" : lambda: widgets.cmdline.completion.finish(),
    "RET" : lambda: widgets.cmdline.completion.insert(),
    "M-+" : lambda: widgets.cmdline.completion.zoombox(+5),
    "M--" : lambda: widgets.cmdline.completion.zoombox(-5),
    "M-=" : lambda: widgets.cmdline.completion.zoombox(0),
    })

3 ファイルの関連付け

キーマップは,ファイルの拡張子ごとにコマンドを割り当てることが可能です。これにより,拡張子 .jpg のファイルは画像ビューアで,拡張子が .txt のファイルはテキストエディタで開くといったファイルの関連付け機能を実現することができます。

ファイルの関連付けを考慮したキーマップの書式は,以下のようになります。

association_keymap = {
    ("キーボード文字列1", "拡張子1"): 呼び出し可能オブジェクト,
    ("キーボード文字列2", "拡張子2"): 呼び出し可能オブジェクト,
    .
    .
    .
    ("キーボード文字列n", "拡張子n"): 呼び出し可能オブジェクト,
}

ファイラー画面におけるエンターキーの入力を, Python や Ruby のようなスクリプトファイルやアーカイブなどに関連付けた場合の設定コードの例を以下に示します。

association = {
    ("RET", ".py"  ): lambda: widgets.cmdline.shell("python %f"),
    ("RET", ".rb"  ): lambda: widgets.cmdline.shell("ruby %f"),
    ("RET", ".sh"  ): lambda: widgets.cmdline.shell("sh %f"),
    ("RET", ".tar" ): lambda: command.run("untar"),
    ("RET", ".tgz" ): lambda: command.run("untar"),
    ("RET", ".gz"  ): lambda: command.run("untar"),
    ("RET", ".bz2" ): lambda: command.run("untar"),
    ("RET", ".zip" ): lambda: command.run("unzip"),
    }
pyful.widget.define_key(widgets.filer, association)

3.1 メニューを関連付ける

ファイルの関連付けでは,メニュー機能 と組み合わせると,拡張子ごとにグループ化されたコマンドを関連付けることができ非常に便利です。

設定ファイルにはデフォルトで,画像ファイル,音楽ファイルおよび動画ファイルを表す拡張子に対して,画像ビューアメニュー,音楽プレーヤーメニューおよび動画プレイヤーメニューを,ファイラー画面のキーマップにそれぞれ関連付けするための設定が記述されています。そのコードを以下に示します。

# Define a image file associate the menu item.
pyful.menu.define_menu("image", (
    ("(d)isplay"    , "d", lambda: process.spawn("display %f %&")),
    ("(g)imp"       , "g", lambda: process.spawn("gimp %f %&")),
    )

# Define a music file associate the menu item.
pyful.menu.define_menu("music", (
    ("(m)player"  , "m", lambda: process.spawn("mplayer %m")),
    ("(M)OC"      , "M", lambda: process.spawn("mocp -a %m %&")),
    ("(a)marok"   , "a", lambda: process.spawn("amarok %f %&")),
    )

# Define a video file associate the menu item.
pyful.menu.define_menu("video", (
    ("(m)player"  , "m", lambda: process.spawn("mplayer %f")),
    ("(v)lc"      , "v", lambda: process.spawn("vlc %f %&")),
    )

menu_association = {
    ("RET", ".jpg"  ): lambda: widgets.menu.show("image"),
    ("RET", ".gif"  ): lambda: widgets.menu.show("image"),
    ("RET", ".png"  ): lambda: widgets.menu.show("image"),
    ("RET", ".bmp"  ): lambda: widgets.menu.show("image"),
    ("RET", ".mp3"  ): lambda: widgets.menu.show("music"),
    ("RET", ".flac" ): lambda: widgets.menu.show("music"),
    ("RET", ".avi"  ): lambda: widgets.menu.show("video"),
    ("RET", ".mp4"  ): lambda: widgets.menu.show("video"),
    ("RET", ".flv"  ): lambda: widgets.menu.show("video"),
    }
pyful.widget.define_key(widgets.filer, menu_association)

この設定により,ファイラー画面においてエンターキーを入力すると,カーソル下のファイルの拡張子が jpg, gif, png, bmp の場合は image メニュー, mp3, flac の場合は music メニュー, avi, mp4, flv の場合は video メニューが呼び出されるようになります。

3.2 特殊な拡張子

ファイルの関連付けでは, ファイルの種類を判断するための pyful が独自に解釈する特殊な拡張子を利用できます。特殊な拡張子を以下に示します。

特殊な拡張子 説明
.dir ディレクトリ
.link シンボリックリンク
.exec 実行可能ファイル
.mark マークされたファイル

特殊な拡張子を利用した関連付けの設定コードを以下に示します。

special_ext_keymap = {
    ("RET", ".dir" ): command.query("enter_dir"),
    ("RET", ".mark"): command.query("enter_mark"),
    ("RET", ".link"): command.query("enter_link"),
    ("RET", ".exec"): command.query("enter_exec"),
    }
pyful.widget.define_key(widgets.filer, special_ext_keymap)