0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LinuxでもAutoHotKeyのようなものを使いたい

Posted at

前座

ここで述べるソフトウェアが一体どんなモノなのかというと、マウスやキーボードのマクロ操作を行うためのスクリプト言語の事である。
この手のソフトウェアで一番有名なものはWindowsの「AutoHotkey」である。

例えば、ブラウザ上の画像の上にマウスカーソルがある時に、「Pause/Break」キーを押すと自動的に保存するAutoHotKeyのスクリプトは以下のようになる。

  1. マウスの右ボタンをエミュレートしてコンテクストメニューを開く
  2. ショートカットの「V」(名前を付けて保存)を送信し保存ウインドウを呼び出す
  3. 「画像を保存」のウインドウが開くのを待つ
  4. クリップボードを通して日付時刻のファイル名を「CTRL-V」で張り付ける
  5. 「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で確認)。もちろんスクリプト言語としての性格があるため、スクリプトを書いて渡す必要はあるが。

Githubのリリースページ

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の代用にはならないが、既に必要最低限な機能を持っていて、外部プログラムとの連携による発展の余地が大きいのでこれを使う方向にしようと思う。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?