ぽよメモ

レガシーシステム考古学専攻

xmodmapとxcapeで消耗するのはもうやめよう

きっかけ

ひさしぶりにデスクトップでデュアルブートしていたUbuntu 16.04を開こうとしたらくたばっていて、仕方なく18.04を新規インストールしてセットアップしているとかつてキーマップをどういじっていたのか思っていた操作ができない…

xmodmapとxcapeでなにやらいろいろやっていた覚えがあったのでやってみるも、fcitxにぶっ壊されてしまうし、キーマップがうまく動作していないように感じ、セットアップに無限に時間が吸われていってしまう…

調べてみるとxkeysnailというツールがたいへんよさそう。

github.com

というわけで導入、設定してみました。

環境

  • Ubuntu 18.04 LTS
  • fcitx version: 4.2.9.6
  • Mozc-2.23.2815.102+24.2.oss
  • xkeysnail v0.1.0
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

xkeysnailとは

qiita.com

LinuxでうごくPython3で書かれたキーマッパです。Linux版Keyhacというところ。

xmodmapやxcapeがsudoなしに実行できるのに対し、xkeysnailはより低レイヤー(evdevおよびuinput)で動作するためにsudoを必要とします。
そのため、使用に際し、権限を持たないユーザは使用できません

また、X windowに依存するため、自動起動させる際にも注意が必要でしょう。今回はGnomeのautostart機能を利用しています。

  • メリット
    • fcitxと競合して設定が消し飛んだりしない
    • アプリケーションごとにキーマップを設定可能
    • multi strokeをサポート(C-x C-cC-qにしたりできる)
    • キーリマップするだけでなく、Pythonの関数などを割り当てたりもできる
    • いわゆるoneshot modifierが簡単にできる
    • 低レベルレイヤーで動作するため、ほとんどの場合においてキーマップが動作する
  • デメリット
    • 情報が少ない
    • sudoが必要

導入

xkeysnailのインストール

pipでインストールできます。

$ sudo apt install python3-pip
$ sudo pip3 install xkeysnail
$ which xkeysnail
/usr/local/bin/xkeysnail
$ xkeysnail -h

こうなります。

f:id:pudding_info:20180622230540p:plain

設定

基本的にここの2つの内容をそのまま踏襲させていただきました。

qiita.com

tmtms.hatenablog.com

自動起動

自動起動させる方法も上記サイトに載ってはいますが、Gnomeでのベストプラクティスがよくわからなかったので、~/.config/autostart/以下に.desktopファイルを配置することで起動スクリプトをログイン時に自動実行させることにしました。

まずは起動スクリプトです。

#!/usr/bin/env bash
if [ -x /usr/local/bin/xkeysnail ]; then
    xhost +SI:localuser:xkeysnail
    sudo -u xkeysnail DISPLAY=:1 /usr/local/bin/xkeysnail /etc/opt/xkeysnail/config.py &
fi

xhostコマンドでxkeysnailユーザにアクセスを許可し、バックグラウンドでxkeysnailを起動します。これを/etc/opt/xkeysnailに配置しておきます。

[Desktop Entry]
Type=Application
Version=1.0
Name=xkeysnail
GenericName=Keymapper
Exec=/etc/opt/xkeysnail/start-xkeysnail.sh
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true

あとは上記を適当にxkeysnail.desktopなどとして~/.config/autostart/以下に配置すれば自動起動の一覧に表示されます。

f:id:pudding_info:20180623011230p:plain

キーリマップ

注意
僕はHHKB ProfessionalのUS配列を使用しています。

config.py

configはPythonで記述します。つまり文法はPythonそのものになるので下手なものを書けば当然syntax errorで落ちます。詳細はgithubのREADMEやexampleを見ましょう。

雛形はこうです。

# -*- coding: utf-8 -*-

import re
from xkeysnail.transform import *

# something remap

Ctrl(またはCaps)単押しでEsc

まずはVimを使っている人には必須であろう(?)configを書きます。

# -*- coding: utf-8 -*-

import re
from xkeysnail.transform import *

define_multipurpose_modmap({
    Key.CAPSLOCK: [Key.ESC, Key.LEFT_CTRL],
    # CapsLockではなくCtrlの場合
    # Key.LEFT_CTRL: [Key.ESC, Key.LEFT_CTRL],
})

今までxmodmapとxcapeでごにょごにょやっていたのは何だったのか…

SandS

Space単押しでSpace、他のキーと組み合わせてShiftにします。

# -*- coding: utf-8 -*-

import re
from xkeysnail.transform import *

define_multipurpose_modmap({
    # SandS
    Key.SPACE: [Key.SPACE, Key.LEFT_SHIFT],
})

MacIME切り替え

Ctrl + Space使いづらいので…
スペースの両側にあるAltをそれぞれ変換、無変換キーに割り当て、fcitxでそれぞれIMEのオン/オフに使用します。

# -*- coding: utf-8 -*-

import re
from xkeysnail.transform import *

define_multipurpose_modmap({
    Key.LEFT_ALT: [Key.MUHENKAN, Key.LEFT_CTRL],
    Key.RIGHT_ALT: [Key.HENKAN, Key.RIGHT_CTRL]
})

fcitxの設定からそれぞれ入力メソッドのオン/オフに指定します。

f:id:pudding_info:20180623012955p:plain

Vim like cursor

Ctrl + hjklで矢印キーを入力します。

# -*- coding: utf-8 -*-

import re
from xkeysnail.transform import *

define_keymap(None, {
    K('C-h'): Key.LEFT,
    K('C-j'): Key.DOWN,
    K('C-k'): Key.UP,
    K('C-l'): Key.RIGHT,
}, "Vim-like cursor")

ログを見るとactive keymaps = [Vim-like cursor]が出力されていると思います。このキーマップはすべてのアプリケーションで動作することを示しています。

Escしたときに自動でIMEオフ

Vimを使っているときに入力モードから抜ける際、日本語入力のままになっていると毎回IMEをオフにしないといけないのが面倒です。
Vimを使っているかどうかを検知することはできませんが、ターミナルを触っている際にEscを押したら自動で無変換を送信し、IMEをオフにしましょう。

# -*- coding: utf-8 -*-

import re
from xkeysnail.transform import *

# 標準の端末ならGnome-terminal
define_keymap(re.compile('Terminator'), {
    K('esc'): [K('muhenkan'), K('esc')]
}, "Esc and IME off")

ターミナルにフォーカスがあたっているときだけログにactive keymaps = [Esc and IME off]が出力されることがわかるかと思います。

ansible-role-xkeysnail

勉強のためにansible-galaxyにroleを登録してみました。Ubuntu 18.04 LTSで検証しています。

galaxy.ansible.com

やっていることはセットアップの内容をそのまま記述しているだけです。

  • python3-pipのインストール
  • xkeysnailのインストール
  • xkeysnail実行用グループおよびユーザの設定
  • /etc/udev/rules.d/40-udev-xkeysnail.rulesの記述
  • /etc/modules-load.d/uinput.confの記述
  • /etc/sudoers.d/以下にxkeysnail用のNOPASSWD設定を記述
  • 起動スクリプトおよびconfig.pyの配置
  • ~/.config/autostart/以下に自動起動.desktopファイルの追記

まとめ

しばらく常用していますがめちゃくちゃ安定していて最高です。
頑張って~/.Xmodmapを書いたりするよりいいと思うのでおすすめです。