情報科学屋さんを目指す人のメモ

方法・手順・解説を書き残すブログ。私と同じことを繰り返さずに済むように。

【AutoHotkey】キーが押しっぱなしになる現象の対策メモ(2024年6月最新版)

AutoHotkey (28) AutoHotkey v2 (4) Windows 10 (262)

AutoHotkey(現在v2)にて、キーが押されたままになってしまい、誤動作が発生してしまうことが以前より多発していました。例えばCtrlキーが押されたままになってしまうと、「s」キーを押しただけで「Ctrl+s」を押したこととなってしまい、急に保存ダイアログが表示されてしまう等の現象が発生します。

この修飾キーの押しっぱなし現象については、かなり長期間に渡って苦しめられてきており、以前にも対策についての試行錯誤記事を書いたのですが、その後も「押しっぱなし」現象は解消しないまま、騙し騙しAutoHotkeyの利用を継続しつつ、たまに対策について調べたり、実験的なAHKスクリプトの書き換えを行っていました。

AutoHotkey v2へのメジャーアップデートに伴う移行作業も行いつつ、その後も「押しっぱなし」となってしまい誤動作が発生する状態が続いていましたが、2024年6月、改めて対処をしていたところ、「押しっぱなし」になりにくくなったと思われる対策があったため、ここでシェアしておきます。

※ここ1年、2年程度、どういうわけか、押しっぱなし現象の発生頻度が悪化しており、対策しなければ、という度合いが上昇していた、というのもあります。

※「AutoHotkey v2.0.16」+ 「Windows バージョン 22H2 (OS ビルド 19045.4412)」+「キーボード:HHKB Professional HYBRID(日本語配列)」。

対策:SendEventを使用する

今回、色々と試した中で有力だった対策は、いくつかある「Send」の種類の中で、「SendEvent」を使用する、という方法です。

SendInput/SendPlayのほうが信頼性が高いと書かれているけれど、、、な対策

キーを送信する方法(モード)としては、「Event(SendEvent)」以外に「Input(SendInput)」や「InputThenPlay」、「Play(SendPlay)」があるのですが、それらの違いに関して、次のような記述があります。

SendInput and SendPlay: SendInput and SendPlay use the same syntax as SendEvent but are generally faster and more reliable. 引用元

日本語で言えば、「SendInputやSendPlayは、SendEventと文法は同じだが、速度や信頼性に優れる」と書かれています。

つまり、「押しっぱなし」のような不安定な現象を避けようと思うと、「SendEventよりも、SendInputやSendPlayを使用しよう」となるような記述です。

まさに従来、「SendはInputやPlayを試そう」と思っていたわけですが、あえてそこに逆らってSendEventを使用してみたわけです。

そうすると、突然、安定し始めたように思えています(今のところ)。

Sendを使用しつつ、SendModeで「Event」を指定

実際の書き換えとしては、SendInputと書かれていたコードを「Send」に書き換えた上で、「SendMode "Event"」を最初に書くようにしました。

検証している最中は「SendEvent」と書きましたが、より書き換えの効率を良くするために、無指定の「Send」を使用しつつ、デフォルト値を書き換える「SendMode」を使用して、「SendMode "Event"」を指定したかたちです。

検証内容

今回この対策に至った実験内容について書き残しておきます。

押っぱなし現象を繰り返し再現できるコンパクトな操作を特定

もともと、「sc079 & a::SendInput("#{Tab}")」という指定を行っていました。

「sc079(変換キー)」を押しながら「a」キーを押すと、「WIn+Tab」が送信される、というホットキー定義文です。

私の環境では、この定義を書いている状態で、無変換キーを押して、離しきる直前のタイミングで「a」キーを押すと、無変換キーが押したままになってしまうことが分かりました。

普通に無変換キーを押しながらaを押す、というだけなら大丈夫なのですが、無変換キーを離す直前に(Up完了判定の直前に)「a」キーを押すと、無変換キーが押しっぱなしに高確率である、という、押しっぱなし現象を再現できる手順が分かったため、そこを実験材料にしました。

SendEvent化で改善の兆し

そこで、様々な書き換えを行いました。

Sleepを末尾に加えたり、Criticalを使ってみたり。

しかしいろいろと、ある意味しらみつぶしに試してみた結果、「SendEvent」を指定することで、突然その再現手順が発動しなく(発動できなく)なり、有力な対策では?と思えたわけです

書き換えを実施してさらに検証を継続

そうした小さい実験で「改善されるかもしれない」という仮説が立ったため、すべてのSendを「SendEvent」に書き換えることとしました

とはいえ、先ほども説明したとおり、直接すべての箇所を「SendEvent」に書き換えるのではなく、すべてを「Send」に書き換えつつ、「Send」時に「SendEvent」が発動するように、「SendMode "Event"」を最初に書いておいた、という形です(もちろん、すべてをSendEventで書き換えても良かったと思います)。

ホットキー定義によっては、意味があって明示的に「SendInput」や「SendPlay」と書いていたような気もするのですが、そこをSendEvent化したことが原因で問題が発生するようであれば元に戻せば良く、押しっぱなしによるホットキーの暴発のほうが深刻だと考えたため、特に区別せず、すべて「SendEvent」に変更してみたのが今回試している書き換えです。

完璧ではないものの手元の環境では激減

それから2週間程度継続してみました。

完全に解消しているわけではないものの、1日に何度も発生していた「押しっぱなし」になる現象が、1日に1回発動するかしないかといった具合に激減しました。

そのわずかな発生も、従来の発生タイミングとは異なる箇所・操作で発動するようになったことで影響が小さくなり、押しっぱなし状態の影響を受けて思わぬショートカットキーが発動してしまう問題の煩わしさは激減しました。

引き続き、この「SendEventを使用する」方法で利用を継続してみようと思います。

関連

コメント(0)

新しいコメントを投稿