AutoHotKey で SandS

検索したら既にあるっぽいけど、作ってみたらできたので晒す。

よく見かけるのは

Space Up:: Send, % "{Shift Up}" (A_TimeSincePriorHotkey < 200 ? " " : "")
+Space:: Send, +{Space}
Space:: RShift

というやつ(やそのバリエーション)とか。これは、Space 押し続けてたらキーリピートしてしまったり、Space 押す→他のキー→Space 離すっていうのを素早くやったらスペースも発射されてしまったりしてちょっと使い心地が悪い。

それから、使ったことないけどかなりちゃんとしてるっぽい、ここの 089.zip というやつもある。

でも

自分で作ることに意味があるんだということでペタリ。

使い勝手は MacKeyRemap4MacBook のものと同じにしたつもり。ツッコミ歓迎。

*Space::
  SendInput {RShift Down}
  If SandS_SpaceDown = 1
  {
    Return
  }
  SandS_SpaceDown := 1
  SandS_SpaceDownTime := A_TickCount ; milliseconds after computer is booted http://www.autohotkey.com/docs/Variables.htm
  SandS_AnyKeyPressed := 0
  ; watch for the next single key, http://www.autohotkey.com/docs/commands/Input.htm
  Input, SandS_AnyKey, L1 V,{LControl}{RControl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Up}{Down}{Home}{End}{PgUp}{PgDn}{Del}{Ins}{BS}{Capslock}{Numlock}{PrintScreen}{Pause} 
  SandS_AnyKeyPressed := 1
  Return


*Space Up:: 
  SendInput {RShift Up}
  SandS_SpaceDown := 0
  If SandS_AnyKeyPressed = 0
  {
    If A_TickCount - SandS_SpaceDownTime < 200
    {
      SendInput {Space}
    }
    ; Send EndKey of the "Input" command above
    ; You must use Send here since SendInput is ignored by "Input"
    Send {RShift}
  }
  Return

せっかくなので

コメントしながら上から見ていく。

*Space::

アスタリスクは、モディファイアが押されていても以下のことをやりますよという意味。

  SendInput {RShift Down}

とりあえず右 Shift を(仮想的に)押して、

  If SandS_SpaceDown = 1
  {
    Return
  }
  SandS_SpaceDown := 1
  SandS_SpaceDownTime := A_TickCount ; milliseconds after computer is booted http://www.autohotkey.com/docs/Variables.htm

SandS_SpaceDown というオレオレ変数が1だったらここで終了。そうじゃなかったら1にする。Space 離さずに押し続けてるときは、キーリピートでこの HotKey が何度も発火してしまうので、それのガード用。

それから現在の時間を SandS_SpaceDownTime として覚えておく。A_TickCount はパソコンを起動してからの経過時間がミリ秒で入ってるらしい。

  SandS_AnyKeyPressed := 0
  ; watch for the next single key, http://www.autohotkey.com/docs/commands/Input.htm
  Input, SandS_AnyKey, L1 V,{LControl}{RControl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Up}{Down}{Home}{End}{PgUp}{PgDn}{Del}{Ins}{BS}{Capslock}{Numlock}{PrintScreen}{Pause} 
  SandS_AnyKeyPressed := 1
  Return

ここではまず SandS_AnyKeyPressed というオレオレ変数をゼロにして、その後、Input 命令で何かひとつキーが押されるまで待機。SandS_AnyKey という変数に押されたキーが入るが、これは使わない。ここで取れるキーは「文字を出す」キーだけなので、それ以外の見えないキーも監視したいため、それらを待機状態を終了するためのキーとして後ろに列挙する。Input 命令の説明ページの例に出てくるとおり。L1 は入力待ちキーストロークの長さ。V は押されたキーをそのままアプリケーションに渡すという意味。

もし何もキーを押さなければ次の行には進まず、SandS_AnyKeyPressed はゼロのままになる。


次にスペースを離したとき。

*Space Up:: 
  SendInput {RShift Up}
  SandS_SpaceDown := 0

とりあえずさっき(仮想的に)押した右 Shift を離す。

  If SandS_AnyKeyPressed = 0
  {
    If A_TickCount - SandS_SpaceDownTime < 200
    {
      SendInput {Space}
    }
    ; Send EndKey of the "Input" command above
    ; You must use Send here since SendInput is ignored by "Input"
    Send {RShift}
  }
  Return

もし Space を押してからから離すまでの間に何もキーが押されていなければ、(ちょっと下に飛んで)とにかく右 Shift を一回出す。右 Shift である必要はまったくないんだけど、さっきの Input 命令の待機状態を終わらせるために適当なキー(見えないキー)を出しておく。

AutoHotKeyドキュメントには SendInput は Send と同じようなもので、最近のバージョンではこっちのほうが速くキーを発火するから推奨ね、って書いてあるけど、Input に食わせたい場合は SendInput だと無視されるから Send を使ってねとあるのでそれに従った。

で、さっき飛ばした部分。Space を押してから離すまでの時間差が200ミリ秒以内なら Space を出す、と。

これ調べながら書くのに数日かかった。大変だった。でも AutoHotKey はヘルプがとても充実してるのが素晴らしいですね。

おまけ

自分は、右 Ctrl を押しながら Space を離したときは IME の切り替えにしているので、SendInput {Space} の部分をこうしてる。

      If GetKeyState("RControl", "P")
      {
        SendInput {vkF3sc029}
      }
      Else
      {
        SendInput {Space}
      }

{vkF3sc029} は全角・半角キーみたい。自分のキーボードには付いてないのでよくわからない。


あと、右 Shfit を押しながら Space 長押しでスペースがリピートされるように、それから左 Shift を押しながら Space を長押しで Shift+Space がリピートされるようにした。{Blind} は「現在押しているモディファイア」を離さずにという意味。

;;; Right Shift + Space to send just space, Left Shift + Space to send Shift+Space
*>+Space:: SendInput {Space}
*<+Space:: SendInput {Blind}{Space}

これはそのうち消すかも。SandS の良いところのひとつは、左右の Shift を好きに割り当てられることだし。