Yashiro Takeshi氏のプログラムで、キー入力を変換してくれるソフトウェアである x11keymacs を Arch Linux で使えるようにしてみた。Libre Office のキーバインドがどうしても我慢できなかったから。
ソースコードの編集
ターミナルでエコーをやめる設定を実行するところで suspended になってしまうので main.cpp 内の1行をコメントアウトした。なんで suspend するのか分かんない…。
// tcsetattr(STDIN_FILENO, TCSADRAIN, &term);
コンパイルとインストール
ソースコードをコンパイルすると、emacs.h が boost/regex.hpp を見つけられずコンパイルエラーになった。boost/regex.hpp は extra/boost パッケージをインストールすればOK。
$ sudo pacman -S boost $ make $ sudo make install
/usr/local/bin にインストールされる。
uinput モジュールのロード
/dev/uinput へアクセスするため, uinputモジュールをロードした。
$ sudo vi /etc/udev/rules.d/98-x11keymacs.rules
$ sudo reboot
98-x11keymacs.rules は以下のように記述。
# for x11keymacs KERNEL=="uinput", MODE="0660", GROUP="input", OPTIONS+="static_node=uinput"
ユーザを input グループへ追加
/dev/input/event* とか /dev/uinput へアクセスするため、ユーザを input グループに追加した。
$ sudo gpasswd -a user_name input
テスト
ちょっと試してみる。& を付けないとキーバインドを奪われて悲惨なことになるらしい。キーボードは /dev/input/by-id/ にソフトリンクがあるので探しやすい
$ x11keymacs /dev/input/by-id/usb-Topre_Corporation_Realforce_106-event-kbd &
LibreOfficeを起動して、試してみると無事にEmacsキーバインディングになっている!
X起動時に実行されるよう設定
.xinitrc に以下を追加。
x11keymacs -e ~/.config/x11keymacs_exclude /dev/input/by-id/usb-Topre_Corporation_Realforce_106-event-kbd &
細かい調整
- 修飾キーの切り替え
emacs.cpp の bool EmacsConverter::handleKeyInput(struct input_event* input)メソッド冒頭に追記。
bool EmacsConverter::handleKeyInput(struct input_event* input) { /* modifier keys */ /* CapsLock <--> LeftCtrl * RightAlt ---> Application * Muhenkan ---> LeftAlt * Henkan ---> ZenkakuHankaku */ switch (input->code) { case KEY_CAPSLOCK: input->code = KEY_LEFTCTRL; break; case KEY_LEFTCTRL: input->code = KEY_CAPSLOCK; break; case KEY_RIGHTALT: break; case KEY_MUHENKAN: input->code = KEY_LEFTALT; break; case KEY_HENKAN: input->code = KEY_ZENKAKUHANKAKU; default: break; }
- C-o の挙動を変えた。END→Enter→UP から Enter→UP→ENDへ。
- M-% で置換を追加。emacs.cpp の bool EmacsConverter::handleKeyInput(struct input_event* input)メソッドの適当なところに以下を追加。
case KEY_5: if (!exclude() && input->value > 0) { if (!IS_CTRL_ON() && IS_SHIFT_ON() && IS_ALT_ON()) { // M-% DP(("M-%%\n")); typeKey(KEY_H, BIT_LEFTCTRL); m_state_ctrlx = false; m_state_ctrlk = false; return true; } } handleKeyDefault(input); return true;
- キーボードとして106キーボードを使っているのに入力が109配列になっていたので、記号類を上記関数内で全部置き換えた。多分別のところに本質的な原因があると思う…。
case 41: input->code = KEY_ZENKAKUHANKAKU; handleKeyDefault(input); return true; case KEY_2: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { typeKey(KEY_APOSTROPHE, BIT_LEFTSHIFT); // " return true; } } handleKeyDefault(input); return true; case KEY_6: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { typeKey(KEY_7, BIT_LEFTSHIFT); // & return true; } } handleKeyDefault(input); return true; case KEY_7: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { typeKey(KEY_APOSTROPHE, 0); // ' return true; } } handleKeyDefault(input); return true; case KEY_8: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { typeKey(KEY_9, BIT_LEFTSHIFT); return true; } } handleKeyDefault(input); return true; case KEY_9: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { typeKey(KEY_0, BIT_LEFTSHIFT); return true; } } handleKeyDefault(input); return true; case KEY_0: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { return true;; // nothing } } handleKeyDefault(input); return true; case KEY_MINUS: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { typeKey(KEY_EQUAL, 0); return true; } } handleKeyDefault(input); return true; case KEY_EQUAL: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { // ~ typeKey(KEY_GRAVE, BIT_LEFTSHIFT); return true; } else { // ^ typeKey(KEY_6, BIT_LEFTSHIFT); return true; } } handleKeyDefault(input); return true; case KEY_YEN: if (input->value > 0) { // release key typeKey(KEY_BACKSLASH, 0); return true; } handleKeyDefault(input); return true; case KEY_LEFTBRACE: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { // ` typeKey(KEY_GRAVE, 0); return true; } else { // @ typeKey(KEY_2, BIT_LEFTSHIFT); return true; } } handleKeyDefault(input); return true; case KEY_RIGHTBRACE: input->code = KEY_LEFTBRACE; handleKeyDefault(input); return true; case KEY_SEMICOLON: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { typeKey(KEY_EQUAL, BIT_LEFTSHIFT); return true; } } handleKeyDefault(input); return true; case KEY_APOSTROPHE: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { // * typeKey(KEY_8, BIT_LEFTSHIFT); return true; } else { // : typeKey(KEY_SEMICOLON, BIT_LEFTSHIFT); return true; } } handleKeyDefault(input); return true; case KEY_BACKSLASH: input->code = KEY_RIGHTBRACE; handleKeyDefault(input); return true; case KEY_RO: if (input->value > 0) { // release key if (IS_SHIFT_ON()) { // _ typeKey(KEY_MINUS, BIT_LEFTSHIFT); return true; } else { /* \ */ typeKey(KEY_BACKSLASH, 0); return true; } } handleKeyDefault(input); return true;