Linux/X11上のキーバインドをEmacs化する試み

[ 日本語 | English ]

概要

Linux/X11上でLibreOfficeやokular(PDF viewer)など、すべてのアプリケーションをEmacs的なキーバインドで操作したい!という要求を満たすためのツールです。

XKeymacs や emacs.ahk のLinux/X11用の簡易的な代替品ができないか、proof-of-conceptとして作ったものと考えてください。ソースコードは1,000行程度の簡単なものとなっており、比較的読みやすいと思います。(このコードの処理を参考に、より実用的なキーバインド設定ツールを作れると良いんじゃないかな、と思っています。)

動作環境
OpenSUSE 11.4/12.1 + KDE4 (※ 他のLinuxディストリビューションやウィンドウマネージャでも動かせると思いますが、手順等の読みかえが必要になるかもしれません。)
ダウンロード
x11keymacs.tar.gz (9KB)
ライセンス
MIT License としておきます

インストール方法

普通に make & make install すると、/usr/local/bin 以下に実行バイナリ(x11keymacs)がインストールされます。

$ cd x11keymacs/
$ make
$ sudo make install

使い方(概要)

x11keymacsの実行には、以下の権限が必要となります。

上記の2つの権限を持ったユーザから、以下のようなコマンドを実行することで、指定したキーボードからのEmacsキーバインド的な入力がWindows的な操作に変換されてシステムに入力されるようになります。
(なお、/dev/input/... の部分はお手持ちのキーボードに合わせて変更する必要があります。)

$ /usr/local/bin/x11keymacs /dev/input/by-id/usb-PFU_Limited_HHKB_Professional_JP-event-kbd &

例えば、Ctrl-P キーは キーに変換されるので、EmacsユーザがLibreOfficeを利用する際、うっかり印刷ダイアログをポップアップさせてしまう状況を避けることができます。

オプションとして --exclude filename を指定することで、キーバインドの変換の対象外とするウィンドウタイトルを正規表現で指定することが可能です。たとえば、--exclude $HOME/.x11keymacs_exclude として、$HOME/.x11keymacs_exclude として以下のような内容のファイルを用意しておくと、Emacs(Gtk+版)とVMware Playerをキーバインド変換の対象から外すことが可能です:

^emacs(-gtk)?@
(^|- )VMware Player$

利用方法の例

私の場合、以下のような設定を行ってXサーバの起動時に自動的に本ツールを起動するようにして使っています:

上記の設定で、少なくとも職場でも常用できる程度には問題なく動作しているようです。(なお、私自身は公開しているコードに個人的な変更を加えて利用しています。)

補足・注意事項

技術情報とか

似たようなツールを作りたい人の参考になるかもしれないので、試行錯誤した際の情報をまとめておきます。

キーボード入力

初期化の際、ioctl(m_keyfd, EVIOCGRAB, 1); をする前に KeyboardDevice::releaseAllKeys(m_keyfd); を呼び出して、すべてのキートップコードに対して release イベントを送っています。

これを行っておかないと grab した瞬間にキーが押下状態にあった場合、そのキーの release イベントは本ツールで grab されてしまい、Input Subsystemに入力されないため、押しっぱなしの状態になってしまいます。

アクティブウィンドウの情報取得

現在アクティブなウィンドウのタイトルを入手する方法ですが、正しい方法がわからなかったので試行錯誤で作りました。window.cpp の WindowSystem::getFocusedWindowTitle() がそれですが、とりあえず以下のような仕組みで動いています:

  1. XGetInputFocus() を用いて、まずは現在入力フォーカスのあるウィンドウを取得します。
  2. そのウィンドウを起点にして、XWMHintsを持ったウィンドウに到達するまで親ウィンドウをさかのぼって探索して行きます。XWMHintsを持っているということは、ウィンドウマネージャに扱ってもらう際の情報を持っているということで、(埋込みではなく)トップレベルのウィンドウである可能性が高いと思われます。いろいろ試した結果、大体の場合はこの方法でウィンドウタイトルを持ったトップレベルのウィンドウまで遡れるらしいことを確認しました。(もしかすると例外もあるかもしれません。)
  3. トップレベルウィンドウのタイトルをXGetWMName()で取り出します。x11keymacsではウィンドウクラス等には対応していませんが、同じような方法で取り出せるはずです。
  4. なお、ここまでのXGetInputFocus()〜XGetWMName() までを順次実行している間に、対象としているウィンドウがクローズされてしまい、うまく動作しなくなる可能性があります。これが原因でエラーとなった場合には、もう一度 XGetInputFocus() からすべてやり直しています。

この部分については、もっと正しい方法があるのではないかと思います。よりよい方法をご存知でしたらご教示いただければ嬉しいです。(そのうち xprop のソースコードを読んでみるつもりです。)

関連情報や謝辞など

Linux Input Subsystemの使い方
Linux Input Subsystemの利用方法が説明されているページです。本ツールはここに書いてある情報を参考に実装しました。とても有用な情報をありがとうございます。
WindowsでEmacsキーバインド
AutoHotKeyを用いてWindows上でEmacs風のキーバインドを実現するスクリプト(emacs.ahk)が公開されているページです。私もWindowsではこれを用いています。x11keymacsのemacs.cppはこのスクリプトを参考に記述しました。ありがとうございます。
xfumble
より汎用的なキーバインド設定ツールで、任意のキーバインドを設定することができる素晴らしいツールです。Emacsキーバインドの設定も含まれており、カスタマイズも容易なので、特にこだわりがなければそちらを用いるほうが良いでしょう。キー入力はX11の機能を使って処理しているようで、x11keymacsとはだいぶ雰囲気が違うようです。
窓使いの憂鬱 Linux & Mac (Darwin) 対応版
窓使いの憂鬱をLinuxにも対応させたものだそうです。ソースコードをざっと読んだ感じでは、キーボード処理は本ソフトとほとんど同じ方法を用いているようです。x11keymacsを作った後にページを発見してしまい、先に気づいていればこれをベースにウィンドウタイトル対応を追加するなどの方法もあったかな、…と後悔中です。

更新履歴


[ 戻る ]

Yashiro Takeshi <yashiromann@gmail.com>
Last modified: Fri Nov 25 06:55:59 2011
Valid XHTML 1.0!