ぺんちゃん日記

食と歴史と IT と。 Web の旅人ぺんじろうが好奇心赴くままに彷徨います 。

【AutoHotkey】 入力キーを一定時間ごとにタイマー送信する

目次


キーのリピートを再現したい。

キーボードのキーを押しっぱなしにすると連続入力できるのですが、特定の入力環境ではできないことがあります。
私がはまっているのはスクリーンキーボードでの入力。
スクリーンキーボードではリピートできません。
そこで AutoHotkey でリピート機能をサポートしようと考えました。
まずは試しに小さいテストスクリプトを書きます。

今回やりたいこと。

小さくテストしたいのでシンプルに行きます。

前提条件はこんな感じ。

  • リピートできるのはエンターキーだけ。
  • ユーザーはマウス操作だけで物理キーボードは操作しない。
  • リピートのキャンセルはマウスポインタの移動で行う。

必要な処理はこんな感じでしょうか。

  • Enter キーの入力を hotkey で検知する。
  • タイマーをセットして 一定時間ごとにエンターキーを送信する処理を呼び出す。
  • タイマー処理内でエンターキーを送信する。
  • ただしマウスポインタの座標を取得して 一定量移動していたらタイマーを解除する。


実装した結果こんな感じになりました。

;エンターキー入力されたら一定時間の間隔でリピート送信。
;マウスポインタを移動させるとリピートを止められる。

    ;マウスキャンセルのため、マウスポインタの座標を保存する。
    mx := 0
    my := 0
;エンターキーのホットキーを定義する。
;自分自身を再送信で無限ループが発生しないように$をつけておくこと。
$Enter::
    ;念のためタイマーをリセット。
    SetTimer, RepeatTimer, off
    ;キャンセルのためのマウスポインタの座標を取得。
    MouseGetPos, mx, my
    ;エンターキー送信。
    send, {Enter}
    ;リピート送信用のタイマーをセット(リピート開始までの時間は少し長めに)。
    SetTimer, RepeatTimer, 800
    return

;タイマーで起動されるリピート送信処理。
RepeatTimer:
    ;タイマーオフ。
    SetTimer, RepeatTimer, off
    ;マウスポインタの座標を取得。
    MouseGetPos, cx, cy
    ;エンターキー入力された瞬間の座標から一定量移動していたら 終了。
    if (Abs(cx - mx) > 7 or Abs(cy - my) > 7)
    {
        return
    }
    ;キーを送信して新たにタイマー設定。次回のリピートへ。
    send, {Enter}
    SetTimer, RepeatTimer,300
    return


ちょっとだけハマったのがキー送信の無限ループ。
enter キーの送信を検知する hotkey の中でエンターキーを送信しているので無限に送信を続けるのです。
AutoHotkey が気を利かせてくれて中断した上で警告してくれるので操作不能に陥るほどではありませんが、期待した通りには動きません。
これを防ぐにはホットキーを定義する時に$をつけます。
例えばこんな感じ。

$Enter::

こうしておくと処理中にエンターキーを送信しても 新たなイベントが発生しません。
hotkey の検知を WindowsAPI ではなく AutoHotkey のフック機能に変更することで避けるようです。
フックを利用するか否かでどこがどう変わるのか正直わからない。
参考文献はこちら。

[[Hotkeys - Definition & Usage | AutoHotkey](https://www.autohotkey.com/docs/Hotkeys.htm):embed:cite]

この記事に登場するAutohotkey スクリプトについて

この記事の中で私が作成したプログラムは、全て自由に使うことができます。
詳しくはこちら