便利に使う‎ > ‎

キー定義に関する件

体系立て書くのは苦手なので羅列。適当に追加・削除・編集をする予定。


ホットキーとリマップの違い

AutoHotkeyでキー定義を変更する方法として、以下の二つがある。

  • ホットキー
  • リマップ

どちらも結果としてキーを置き換えて何らかの機能に置換するものだが、決定的に異なる点がある。これをきちんと把握していないと、意図したとおりのキー定義ができなくなってしまう。両者の特徴は以下の表の通り。

名称 定義の及ぶ範囲 キー発行時の挙動
ホットキー 定義したもののみ 実際に押下されているキー状態に関係なくキー発行する
リマップ 修飾キー付きも影響する
(キー置換なため)
実際に押されている修飾キーを引き継いでキー発行する

リマップはその名の通り「キーの再配置」である、キー[A]とキー[B]を入れ替えるといったような用途するのが前提である。例を挙げるQWERTY配列でなく、DVORAK配列にしたいといった場合に使う。([Ctrl]+[A], [Shift]+[A], [Alt]+[A], [Ctrl]+[Shift]+[A]…といったように延々と定義をするのは冗長で面倒だという観点)

このようにリマップは単純なキー置換の用途に限って使うもので、特定のキー押下条件でキー発行したいという場合はホットキー定義を行い Sendコマンドでキー発行をすべきである。

これだけだと分かりにくいので、具体例を挙げてみる。

リマップを利用すると同時に押されているキーが影響する例

[Ctrl]+[1]に[Esc]を割り当てたいので、リマップ機能を利用して以下のように定義を行った。

^1::Esc

ところが、実際に[Ctrl]+[1]を押すとスタートメニューが表示されてしまう。これは以下のような機序で発生するためである。

  • [Ctrl]+[1] が押されたら、[Esc]を発行するようにする。ただし物理的に押下されている修飾キーを含めてキー発行を行う。
  • 実際に発行するキーは、[Ctrl]+[Esc]となる。
  • スタートメニューが表示される。

これを解決するには、ホットキーで定義を行えばよい。

^1::Send, {Esc}

現在のキー定義を動的に変更したい

方法としては以下の方法が考えられる。

  1. Hotkeyコマンドを利用してOn/Offや処理先のサブルーチンを切り替える
  2. AutoHotkey_Lの #If を利用して切り替える。

どのようなシーンで動的な変更をしたいかによるが、独断と偏見でケース別にどれを使ったらいいかを以下に述べる。

  • 予め定義されている処理があるが、どのホットキーに割り振るかは決めおらず、外部のINIファイルなどに記載されたキーをホットキーとして割り当てをしたい。
    → Hotkeyコマンドを利用してサブルーチンにホットキーを割り当てる。
  • 変数やどのようなキー定義をするかを管理して、変数が切り替わったらキー定義をゴロッと切り替えたい。
    →AutoHotkey_L の #If を利用する。

例) INIファイルに記述されたキーを基に決められた処理のホットキー定義を行う

方針として以下のようにする

  • キー指定はINIファイルから読み出す
  • キー割り当てはHotkeyコマンドを利用する

スクリプト例は以下の通り

IniRead, keyName, config.ini, config, Hotkey
If (keyName !="Error")
  Hotkey, %keyName%, HogeHoge, UseErrorLevel
Return
HogeHoge:
  ; 
Return

例) vi のように、文字入力モードと編集モードを切り替える

方針として以下のようにする

  • 編集モードと文字入力モードは変数でフラグ管理を行う
  • フラグはホットキーで切り替える
  • フラグに基づいてホットキー定義をする

スクリプト例は以下の通り

#IfWinActive, ahk_class Notepad
Esc::
  ViMode:=!ViMode
  Tooltip, モード=%ViMode%, A_CaretX, A_CaretY
  Sleep, 500
  Tooltip
  Return

#If WinActive("ahk_class Notepad") && (ViMode==1)
H::Send, {Left}
J::Send, {Down}
K::Send, {Up}
L::Send, {Right}

AutoHotkey_Lを使うとスクリプト量も少なく、見た目も必要以上に多くなくて済む。

例) 特定のキー押下中のみキー定義を切り替える

これは二通りのやり方が考えられる。

  • コンビネーションキーを使う
  • AutoHotkey_Lの  #If を利用する

[無変換] + [H] / [J] / [K] / [L] でカーソル移動を行う場合の例

コンビネーションキーでやる場合: 修飾キーの引き継ぎは {Blind} を利用する。

sc07B & H::Send, {Blind}{Left}
sc07B & J::Send, {Blind}{Down}
sc07B & K::Send, {Blind}{Up}
sc07B & L::Send, {Blind}{Right}

AutoHotkey_Lの #If を利用する場合: リマップの一時的適応なので修飾キーは自動的に引き継がれる。

sc07B::
  ViMove:=True
  KeyWait, sc07B
  ViMove:=False
  Return

#If (ViMove)
H::Left
J::Down
K::Up
L::Right

マウスボタンやジョイスティックにホットキー定義をしても連打にならない

これはキーボードやマウス・ジョイスティックの仕様と同じため。キーボードでキーを押しっぱなしにすると自動で連打になる仕組みが元々ある。一方、ジョイスティックやマウスボタンにはそれがない(もっともマウスボタンを勝手に連打されるようなものなら困りものだが)。

キーボード連打の信号をAHKは読み取ってアサインされた別キーを発行しているだけなので、特に特別なことはしていない。逆に、マウスボタンやジョイスティックの場合は、自前で連打機能を提供してやらなければならない。

連打を行うのは通常ボタン押下中なので、その間だけループして特定キーの発行をしてやればよい。

方針としては以下のようにする
  • キー発行をしたあとに、一定時間キーの解除が無ければ次のキー発行を行うようにする
  • 初回のキー発行後の間隔と、連打中の間隔は別途指定できるようにする(キーボードリピートと似た感じ)
  • キー押下中かどうかの判定と連打間隔を開けるための「待ち」はKeyWaitを利用する
  • 押下解除待ちキーはA_ThisHotkeyから自動で判定するようにする
  • 処理を再利用するために、関数化を行う

関数は以下のようにした。

SendWhileButtonPress(Keys, FirstDelay="0.7", RepeatDeley="0.01", WaitKey="") {
  KeyDelayBack:=A_KeyDelay
  If (!WaitKey) && RegExMatch(A_ThisHotkey, "i)^[\^!\+#<>\*\$~]*(?:(\w+)\s+&\s+)*(\w+)(?:\s+Up)*$", $)
    WaitKey:=$2
  If (!WaitKey && R)
  SetKeyDelay, 0
  Send, %Keys%
  KeyWait, %WaitKey%, T%FirstDelay%
  While (ErrorLevel) {
    Send, %Keys%
    KeyWait, %WaitKey%, T%RepeatDeley%
  }
  SetKeyDelay, %KeyDelayBack%
}

以下のように利用できる。

+RButton::SendWhileButtonPress("a")
Joy1::SendWhileButtnPress("x")

その他にもタイマーを利用したりする方法などがある。