前座
ここで述べるソフトウェアが一体どんなモノなのかというと、マウスやキーボードのマクロ操作を行うためのスクリプト言語の事である。
この手のソフトウェアで一番有名なものはWindowsの「AutoHotkey」である。
例えば、ブラウザ上の画像の上にマウスカーソルがある時に、「Pause/Break」キーを押すと自動的に保存するAutoHotKeyのスクリプトは以下のようになる。
- マウスの右ボタンをエミュレートしてコンテクストメニューを開く
- ショートカットの「V」(名前を付けて保存)を送信し保存ウインドウを呼び出す
- 「画像を保存」のウインドウが開くのを待つ
- クリップボードを通して日付時刻のファイル名を「CTRL-V」で張り付ける
- 「ENTER」を送信して保存する
#HotIf WinActive("ahk_class MozillaWindowClass")
|| WinActive("ahk_class Chrome_WidgetWin_1")
Pause:: {
MouseGetPos(,, &gwin)
SendInput("{RBUTTON}")
Sleep(100)
SendInput("V")
id := WinWait("画像を保存")
While (WinExist("画像を保存")) {
WinActivate(id)
keep := A_Clipboard
A_Clipboard := ""
Send("^C")
ClipWait
ts := Format("{1:d}{2:02d}{3:02d}{4:02d}{5:02d}{6:02d}{7:03d}",
A_YYYY, A_MM, A_DD, A_Hour, A_Min, A_Sec, A_MSec)
fn := RegExReplace(A_Clipboard, ".*\.([^.]+)$", ts . ".$1")
A_Clipboard := ""
A_Clipboard := fn
ClipWait
Send("^V")
Sleep(150)
A_Clipboard := keep
SendInput("{ENTER}")
Sleep(400)
}
}
#HotIf
日付時刻のファイル名を生成するのは「上書きしますか?」のダイアログの発動防止のため、重複しない名前を付ける目的である。また、正規表現でやってることはデフォルトの名前の拡張子を取り出し生成したファイル名にくっつけることである。
プロローグ
以前からWindowsマシンを捨てて、Linuxに移行しようと思っていた。というか別にLinuxマシンは持っていて、移行しても日常生活ではそれほど困らないことは分かっていた。
ただ、課金コンテンツとADFスキャナー(ScanSnap)の縛りでWindowsマシンを捨てられずにいた。
しかし、今となってはDMM.TVなどの動画サービスはLinxuで動くし、もう書類はPDFで配られ、紙の本は買わないので紙のスキャンもしない。
それでも最後に残ったネックがある。
AutoHotKeyというGUIアプリの操作の自動化ソフトだ。
OSとアプリケーションの通信路のルーターのように働き、
キーボードやマウスの操作と、その宛先のウインドウの情報を元に内容をフィルタリングし通信内容を置き換え、ボタン一つで様々な処理を自動実行できるようにする。
2025年秋現在、これに完全に置き換わるLinuxのソフトは無い。
だが、それに近いものはある。
そのソフトウェアとは「Kanata」である。
Kantaについて
AutoHotKeyはOSとアプリケーションの通信に介入し、OSから送信されるキーボードやマウスイベントの内容、及びその宛先のウインドウの情報を見て、それを元に動作を制御する。
一方、Kantaの設計図はここ。
Kanataは宛先のウインドウが見えない事以外は、似たり寄ったりの動作をする。
Kanatのライブラリ構成を見ると、GUIライブラリへの参照が現れない。
実際にログインに先立ってデスクトップ環境が立ち上がっていない状態で起動しても動作する。そして、Linux Mint22.2(X.org)でもUbunt 22(Wayland環境)でも動作する。Xlibを参照していないのだからそりゃあそうなるだろう。
linux-vdso.so.1 (0x00007fff9fda5000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ed284fd2000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ed285226000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ed285221000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ed284c00000)
/lib64/ld-linux-x86-64.so.2 (0x00007ed285240000)
これではウインドウ情報にアクセスできないので、機能の制限が出てくる。
だが、設計図にはTCP/IPの通信路を通して動作切り替えの命令を外から受け取ることができる(TCP/IPインターフェースの例)ので、ウインドウのアクティベートを補足してKanataに送信するプログラムを用意できればAutoHotkeyと同じ動作ができるようになる。
一方、Kanataの方がキーボードの制御に関しては優位な点がある。タップ/ホールド/タップダンスという機能があり、キーの短押しと長押し、ダブルクリック、トリプルクリックを識別して制御を変えることができる。
Kanataの実装状況(ver 1.9)
Linux版に関してはマウスもキーボードもおおむね問題なく動作する。
Windows版はキーボードはおおむね問題なく動作し、マウスの動作のエミュレーションはできるが、まだマウス関係のイベントを取れないので完成度は高くない。
また、Windows版(の推奨できるバリアント)はコンソールアプリなので、コンソールを透明化するツールを別に用意する必要がある
(WIN32APIのCreateProcessのパラメーターをいじってKanataを起動するようにすればよい)。
JPキーボードの対応状況は九割方OKで、大部分は問題ないが、一部のキーのイベントは拾えず(半角/全角と[英数])、またキーシンボルと一致しないコードを使う必要があるキーがある。
そして、今のところはcapslock/scrolllockなどのトグルスイッチのステータスは見れないので、必要ならば外部のプログラムで工夫するなどの処置が要る(押した/離したの判別はできるがON/OFF状態が見えない)。
Kanataのインストール
特筆すべきことだが、KanataはWindowsにおいてもLinuxにおいてもインストール不要で、単体の実行ファイルをダウンロードしてそのまま起動するだけで動く(MINT22.2とUbuntu22で確認)。もちろんスクリプト言語としての性格があるため、スクリプトを書いて渡す必要はあるが。
Windows: Githubのリリースのアセットから「kanata_cmd_allowd.exe」をダウンロード。
Linux: Githubのリリースのアセットから「kanata_cmd_allowd」をダウンロード。
Kanataのスクリプトはどんな感じ?
試しにキーボードとマウスホイールによるボリュームコントロールを書いてみる。
これはたったの四行で完成する。
動作内容
ファンクションキーのF10、F11、F12を右側のWINキーと同時押しすると、
マルチメディアキーの mute/volume-/volume+に置き換える。
ついでにマウスの上下回転でもボリュームを上下できるようにする。
動作環境
これはOSがマルチメディアキーに対応していればそのまま動作する。
Linux MINT 22.2ならパネルにPlusAudioPluginを追加し、そのプロパティ設定でショートカットを有効化すると動作するようになる。
スクリプトの中身
最初の一行目のdefcfgはHTML文における「」のようなお約束の定型文。
二行目のdefsrcは使用するキーの定義(F10, F11, F12, ホイールの上回転, 下回転)
deflayerはキーが押された場合の動作をdefsrcでの定義順に対応させて列挙する。最初は一つ目のlayerが有効。
三行目のmain-mapで右WINキー(rmet)が押されたら、(rmetが)離されるまで二つ目のrmet-mapを有効にする。他のキーだったら何もしない(_)。
四行目で押されたキーをマルチメディアキーに変換してOSへ送り返す。
(defcfg)
(defsrc rmet F10 F11 F12 mwd mwu);; R-WIN, F10, F11, F12, wheel-up, wheel-down
(deflayer main-map (layer-while-held rmet-map) _ _ _ _ _)
(deflayer rmet-map _ mute vold volu vold volu)
だいたいこんな感じ。
このように取り扱うキーの数が少ない場合は非常に簡単に使える。
増えてくると面倒になる。
詳しい解説は設定ガイドを参照。
扱えるキーの一覧
基本的に、kanataは使いたいキーだけ最小限定義すればよくて、全てを調べ尽くして正確に並べる必要は全くない。物理的に存在しないキーがスクリプト中にあってもイベントが発生しないだけでエラーになるわけではない。単に使いたいキーの名前がプログラム上適切であれば問題ない。そこは気楽に考えて良い。
一応、JPキーボードの対応状況を調べるために一覧は作ったが、このような長い定義を必ず使う義務はない。
扱えるキーの一覧は、プログラム中の定義とkanataのデバッグログを比較すると得られる。
日本語キーボードの場合
(defsrc
esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12
1 2 3 4 5 6 7 8 9 0 - apo \ bspc
tab q w e r t y u i o p grv [ ent
caps a s d f g h j k l eql ; ]
lsft z c v b n m , . / nubs rsft
lctl lmet lalt mhnk spc hnk kana ralt rmet menu rctl
;; edit keys tenkey pad
prtsc slck nlk brk kp/ kp* kp-
ins home pgup kp7 kp8 kp9 kp+
del end pgdn kp4 kp5 kp6
up kp1 kp2 kp3
lft down rght kp0 kp. kprt ;; kprt: ENTER
;; mouse
;;mltp mrtp mmtp mbtp mftp ;; mouse 5 buttons(tap) 未実装(?)
mlft mrgt mmid mbck mfwd ;; mouse 5 buttons(hold)
mwu mwd mwl mwr ;; mouse wheel
)
物理的なキーの刻印と一致しないもの:
^~→apo, @`→grv, ;+→eql, :*→;, \ ロ→nubs
全角/半角は×,caps(capslock)はSHIFTキー同時押しだけ認識
(この辺の問題はAutoHotKeyなど他のソフトでも難儀する所なのでしょうがない)
また、リリースアセットのwinterceptおよびWinIOv2と付けられたものは「カナ」キーと「Pause/Break」の取り扱いに不具合がある(ver 1.9)
結論
現時点ではAutoHotKeyの代用にはならないが、既に必要最低限な機能を持っていて、外部プログラムとの連携による発展の余地が大きいのでこれを使う方向にしようと思う。