Linux/X11上でLibreOfficeやokular(PDF viewer)など、すべてのアプリケーションをEmacs的なキーバインドで操作したい!という要求を満たすためのツールです。
XKeymacs や emacs.ahk のLinux/X11用の簡易的な代替品ができないか、proof-of-conceptとして作ったものと考えてください。ソースコードは1,000行程度の簡単なものとなっており、比較的読みやすいと思います。(このコードの処理を参考に、より実用的なキーバインド設定ツールを作れると良いんじゃないかな、と思っています。)
普通に 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サーバの起動時に自動的に本ツールを起動するようにして使っています:
takeshi ALL=(ALL) ALL, SETENV:NOPASSWD:/usr/local/bin/x11keymacs
$HOME/.xinitrc
から x11keymacs を起動するように書き換えます。
cp $HOME/.xinitrc.template $HOME/.xinitrc
後、以下のような行を追加:
#
# Add your own lines here...
#
if test -e $HOME/.x11keymacs_excludes; then
xhost +
sudo -b DISPLAY="$DISPLAY" /usr/local/bin/x11keymacs \
--exclude $HOME/.x11keymacs_excludes \
/dev/input/by-id/usb-PFU_Limited_HHKB_Professional_JP-event-kbd
fi
上記の設定で、少なくとも職場でも常用できる程度には問題なく動作しているようです。(なお、私自身は公開しているコードに個人的な変更を加えて利用しています。)
diff --git a/emacs.cpp b/emacs.cpp
index 7e17802..d32bdca 100644
--- a/emacs.cpp
+++ b/emacs.cpp
@@ -73,7 +73,7 @@ void EmacsConverter::typeKey(__u16 code, int metaKeys)
BIT_LEFTALT, BIT_RIGHTALT,
};
static const __u16 keys[] = {
- KEY_LEFTCTRL, KEY_RIGHTCTRL,
+ KEY_CAPSLOCK, KEY_RIGHTCTRL,
KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
KEY_LEFTALT, KEY_RIGHTALT,
};
@@ -139,7 +139,7 @@ void EmacsConverter::typeKey(__u16 code, int metaKeys)
bool EmacsConverter::handleKeyInput(struct input_event* input)
{
switch (input->code) {
- case KEY_LEFTCTRL:
+ case KEY_CAPSLOCK:
return handleMetaKeyInput(input, BIT_LEFTCTRL);
case KEY_RIGHTCTRL:
return handleMetaKeyInput(input, BIT_RIGHTCTRL);
似たようなツールを作りたい人の参考になるかもしれないので、試行錯誤した際の情報をまとめておきます。
初期化の際、ioctl(m_keyfd, EVIOCGRAB, 1);
をする前に KeyboardDevice::releaseAllKeys(m_keyfd);
を呼び出して、すべてのキートップコードに対して release イベントを送っています。
これを行っておかないと grab した瞬間にキーが押下状態にあった場合、そのキーの release イベントは本ツールで grab されてしまい、Input Subsystemに入力されないため、押しっぱなしの状態になってしまいます。
現在アクティブなウィンドウのタイトルを入手する方法ですが、正しい方法がわからなかったので試行錯誤で作りました。window.cpp の WindowSystem::getFocusedWindowTitle()
がそれですが、とりあえず以下のような仕組みで動いています:
この部分については、もっと正しい方法があるのではないかと思います。よりよい方法をご存知でしたらご教示いただければ嬉しいです。(そのうち xprop のソースコードを読んでみるつもりです。)
[ 戻る ]
Yashiro Takeshi <yashiromann@gmail.com>