X Window Systemで動作するキーリマッパー「xremap」を作った
- 2017/1/9追記: xkremap→xremapにリネームしました
- 2021/12/21: Rust化に伴いアーキテクチャを刷新し、より多くの機能と環境がサポートされました: Linux用キーリマッパーxremapをRustで書き直した - k0kubun's blog
僕はKarabiner用のRuby DSLを作ったりそれを使って大量の設定を既述する程度にはKarabinerのヘビーユーザーなんだけど、デスクトップ環境にLinuxを使い始めてからもう1年以上経つ今でもLinux環境で使えるKarabiner並にリッチなキーリマッパーを見つけられずずっと不便していたので、ユースケースを満たす最低限のものを自分で作った。
ちなみにX用であって別にLinuxの何かに依存しているわけではないので、タイトルは釣りである。
これは何
RubyのDSLかつシンプルなキーの指定方法によりキーリマップを設定することができる。例えば、以下の設定ファイルを書いてxremapに渡す*1とターミナルやEmacsの外でもEmacsライクなキーバインドが使えるようになる。
remap 'C-b', to: 'Left' remap 'C-f', to: 'Right' remap 'C-p', to: 'Up' remap 'C-n', to: 'Down' remap 'C-a', to: 'Home' remap 'C-e', to: 'End' remap 'C-k', to: ['Shift-End', 'Ctrl-x']
また、xbindkeys等のツールより優れている点はアプリケーション*2ごとのキーバインドを設定できるところにある。普段Emacsバインディングを使っていると、Slackが割りあてるC-k
とコンフリクトするわけだけど、例えば以下のように書くとSlackでのみ下記の設定を適用し問題を回避することができる。
window class_only: 'slack' do remap 'Alt-n', to: 'Ctrl-k' end
あと、任意のキーからシェルを起動することができるので、ランチャーとしても使える。
remap 'C-o', to: execute('nocturn') remap 'C-u', to: execute('google-chrome-stable') remap 'C-h', to: execute('urxvt')
補足だけど、ある単一のキーを別のキーにリマップするみたいなことはXmodmapとかでやったほうがいいと思う。その方が多分速いので。僕はErgoDoxのファームウェアでそういうリマップはできるので不要なんだけど、xremapはEmacsバインディングみたいな何らかのキーの組み合わせをキーの組み合わせやシーケンスに変換したい時に使う。
なぜ作ったのか
GitHub等でキーバインドが奪われるし、その度にJavaScriptを読みたくない
GitHubというサイトはC-k
, C-b
を奪ってくる。社員は誰もEmacsを使ったことがないに違いない。
僕はいままでEmacsバインディングはinclude "/usr/share/themes/Emacs/gtk-2.0-key/gtkrc"
によって設定していたんだけど、これだと普通にブラウザに奪われるため、user.jsを書く必要があって面倒だった。
xremapを使うとXのルートウィンドウレベルでキー入力イベントをフックしてリマップするので、例えばGitHubのコメント欄とかでブラウザにキーバインドが奪われない点が便利。
rbindkeysがRuby >= 2.2で動かない & wineを使うとSEGVする
類似のツールにrbindkeysというものがあり、というかほぼ要件を満たしていたので長い間使っていた。が、上述したようなランチャーの用途には使えず別のツールで解決していたのとか、単純に不安定なのとか、DSLが複雑などの理由でずっと自分向けの奴を作りたいと思っていた。仕様も内部実装も仕組みも全て僕の好みに変えたrbindkeysがxremapといえる。いままでお世話になりました。
rbindkeysと比較して、xremapは下記のような違いがある。
- キーイベントの取得やリマップにLinux Input Subsystemを使わないので、Linuxじゃなくても(多分)動く & rootじゃなくても実行できる
- キーボードを抜き差ししてもそのまま使える
- DSLの違いにより、キーの指定がシンプルに書ける
C-k
とかのリマップの挙動が安定している
あと、この場合別にRubyでもmrubyでもどっちでもいいなあとは思ったんだけど、最近慣れてきたmrubyを採用している点も異なる。
macOSと違ってCommandキーがないから色々コンフリクトするのを解決したい
コピーやペーストがC-c
, C-v
などControlに割りあてられているため、例えばEmacsのC-f
とブラウザの検索のC-f
が被ってしまっていた*3。
アプリケーションごとにキーバインドを変えられる程度にはリッチかつ十分に安定したキーリマッパーがあると、macOSみたいにCommandキー相当のキーを作ることができる。会社で貸与されてるノートPCがMacBookなので今でもmacOSは使うのだけど、できれば複数の環境の差異をなくしたいというのがあった。
気持ち
デスクトップ環境でLinuxを使っている人はNocturnとxremapをよろしくお願いします。
*1:systemdとかで起動するのがよい xremap/xremap.service at 6e8e1f21285ecedfa7ac88d703ad80d25a2699dd · k0kubun/xremap · GitHub
*2:正確にはウィンドウのclass
*3:gtkrcによる設定だと、テキスト入力欄かどうかで挙動が変わっていたが、検索とかは常に使えて欲しかった