とにかく書く

日々の雑感や知り得たことを、とにかく書いています

x11keymacs を Arch Linux で使ってみる

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;