🐷

Wayland/Sway 環境向けの Key Remapper を作った

2021/12/10に公開

Wayland/Sway 環境で動作する Key Remapper を作りました。

https://github.com/acro5piano/wayremap

動機

Wayland/Sway は素晴らしいですが、ネイティブな ​Wayland 上で動作する Key Remapper が無いのが
つらみでした。

X11 時代は xremap という神ツールがあり、特定のアプリケーション(ブラウザとか)のみに対して Emacs 風のキーバインドを設定していました。 xremap はもう4年以上使っていて、これが無かったら仕事できてないです。まじでありがとうございました。

https://github.com/k0kubun/xremap

この特定のアプリケーションでのみ動作させる、というのがポイントで、この点を考慮しなければ下記のようなツールは存在します。

ただ、ターミナルなどそもそも Remap が必要ないアプリケーションにまで設定されると困るので、その辺を解消してくれるものを作りました。

なぜ xremap や keysnail では駄目なのか

今の所 Chromium など XWayland を介して動くソフトウェアでは xremap は動いていますが、将来的に動かなくなるだろうというのと、 Firefox などでも動作させたかったです。

また xremap や keysnail にプルリクを出すことも考えましたが、むずそうなのと、 X11 と Wayland ではキー入力に対する考え方が違うので、新しく自分で作ることにしました。

Wayland のキー入出力モデル

レイヤー的に、Wayland の下にあるので、 Linux の話ですが...

Wayland は X11 よりもコンパクトに設計されていて、キー入力をフックするには Linux カーネルに働きかける必要があります。なので root 権限が必要です。

キーの入力を司っているのは evdev というカーネルで、デバイスは /dev/input/event20 などのファイルとして表現されています。また、 uinput というものを使うと、擬似的にキー入力を再現できます。

Rust で実装しようとして諦めた

勉強がてら Rust で実装しようとしたのですが、むずすぎて諦めましたw

https://github.com/acro5piano/sway-remap

自分の Rust 力が足りなさすぎたというのと、 Python の方が uinput でコンボ入力がハンドルできたので、そちらでやりました。いつか Rust で書き直したい。

インストール

pip で簡単にできます。 root が読み込めるよう、 sudo でインストールします。

sudo pip install wayremap

Run

あとは、下記のようなスクリプトを作り、実行するだけです。

# /opt/wayremap.py

from wayremap.config import WayremapConfig, Binding
from wayremap.main import run
import uinput as k

wayremap_config = WayremapConfig(# Filter applications which remap will be applied
   ​applications=['Chromium','Brave-browser','Leafpad','firefoxdeveloperedition',],
   ​bindings=[# Emacs-like key binding
       ​Binding('ctrl.alt.a', [[k.KEY_LEFTCTRL, k.KEY_HOME]]),
       ​Binding('ctrl.alt.e', [[k.KEY_LEFTCTRL, k.KEY_END]]),
       ​Binding('ctrl.alt.h', [[k.KEY_LEFTCTRL, k.KEY_BACKSPACE]]),
       ​Binding('ctrl.f', [[k.KEY_RIGHT]]),
       ​Binding('ctrl.b', [[k.KEY_LEFT]]),
       ​Binding('ctrl.p', [[k.KEY_UP]]),
       ​Binding('ctrl.n', [[k.KEY_DOWN]]),
       ​Binding('ctrl.k',[[k.KEY_LEFTSHIFT, k.KEY_END], [k.KEY_LEFTCTRL, k.KEY_X]]),
       ​Binding('ctrl.a', [[k.KEY_HOME]]),
       ​Binding('ctrl.e', [[k.KEY_END]]),
       ​Binding('ctrl.y', [[k.KEY_LEFTCTRL, k.KEY_V]]),
       ​Binding('alt.f', [[k.KEY_LEFTCTRL, k.KEY_RIGHT]]),
       ​Binding('alt.b', [[k.KEY_LEFTCTRL, k.KEY_LEFT]]),
       ​Binding('alt.d', [[k.KEY_LEFTCTRL, k.KEY_DELETE]]),
       ​Binding('ctrl.h', [[k.KEY_BACKSPACE]]),
       ​Binding('ctrl.s', [[k.KEY_LEFTCTRL, k.KEY_F]]),# OSX-like key binding
       ​Binding('alt.a', [[k.KEY_LEFTCTRL, k.KEY_A]]),
       ​Binding('alt.c', [[k.KEY_LEFTCTRL, k.KEY_C]]),
       ​Binding('alt.v', [[k.KEY_LEFTCTRL, k.KEY_V]]),
       ​Binding('alt.x', [[k.KEY_LEFTCTRL, k.KEY_X]]),# Slack helm!
       ​Binding('alt.x', [[k.KEY_LEFTCTRL, k.KEY_K]]),])

run(wayremap_config, '/dev/input/event4')

実行:

sudo modprobe uinput
sudo python /opt/wayremap.py

'/dev/input/event4' は PC によって変わるので、注意してください。

既知のバグ

  • 3 is pressed when changing focused window
  • Key repeating become slow while switching focused windowd

Roadmap

  • Enable to run wihtout Sway
  • Packaging for Arch Linux, Debian, Fedora, etc.
  • Enable to load per-application config.
  • Re-write in Rust for better performance.

Discussion