AutoHotkeyでSandS


概要

AutoHotkey を用いて、SandSしてみようという試みです。

前の記事から切り出しました。
AutoHotkeyでどこでもVimっぽくカーソル移動したい(モードレス版)

環境

  • windows10 Home 1909
  • AutHotkey v.1.1.33.02

SandS とは

スペースバーにスペースバー以外の働きを持たせようという考え方です。

スペースバーを単体で押して離した場合は、単なるスペースバーとして作用するようにしておくため、スペースを入力することができなくなってしまうわけではありません。

スペースバーを押し下げている間に、他のキーを同時に押した場合、異なった作用をさせよう。という趣旨です。
元々は SandS (Space and Shift) の名の通り、スペースバーにシフトキー(小文字→大文字)の機能を持たせる物です。

具体的に説明をすると・・・

  • キーボードの「a」を打つと画面には「a」と出る。コレは当たり前です。。

  • シフトキーを押し下げても何も起こりません。
    シフトキーを押したまま、キー「a」を打つと、画面には「A」と出る。
    その後、シフトキーを離しても何も起きない。コレもまだ当たり前です。

  • キーボードのスペースバーを押し下げると、空白文字がキーリピートによりドバーと入り始めます。
    スペースバーを押したまま、キー「a」を打つと、空白文字のリピートが止まり、画面には「a」と出ます。
    その後、スペースバーを離しても何も起きません。コレもまだまだ当たり前です。

ここまでが、いつもの当たり前の世界です。
それが、SandS では以下のようになります。

  • スペースバーを押し下げても何も起こりません。(普通じゃない!)
    スペースバーを押したまま「a」を打つと、「A」と出る。(何それ便利!?)
    ちなみに、何もせずにスペースバーを離したときには1文字分だけの空白文字が画面に出力されます。

代償として、空白文字のキーリピートによる連続入力が行えなくなります。

SKK、とか、新JISカナ入力、とか、英文タイプといった方面などでは、重宝する人もいるとかいないとか。
ちなみに、元SKK使いですが、確かに便利でした。さらに、元新JISカナ使いでもありますが、確かに便利でした。

日本語入力をしている上では、スペースバーは仮名漢字変換の機能に用いることが多いと思います。
スペースバーを押し下げて変換を開始、そのまま次の文章の入力を続けたつもりが、スペースバーから指が離れる前に文字の入力をしてしまっていて、変なところに大文字アルファベットが?とかいうこともあると聞き及んでいます。

個人的には、「、」「。」を入力するときに、その直前の文章を変換した時のスペースが残ってしまって「>」や「<」が入力される事がありました。

AutoHotkey で SandS

修飾キーと同時にスペースが状態で押された場合は、素直に「修飾キー+スペース」として働いてほしいため、*Space::ではなく、Space::を対象に実装しています。

Sands.ahk
  #InstallKeybdHook
  $Space::
      if SandS_guard = True           ;スペースキーガード
          return
      SandS_guard = True              ;スペースキーにガードをかける
      Send,{Shift Down}               ;シフトキーを仮想的に押し下げる
      ifNotEqual SandS_key            ;既に入力済みの場合は抜ける
          return
      SandS_key=
      Input,SandS_key,L1 V            ;1文字入力を受け付け(入力有無判定用)
      return

  $Space up::                         ;スペース解放時
      input                           ;既存のInputコマンドの終了
      if SandS_guard = False          ;ガードがかかってなかった場合(修飾キー+Spaceのリリース)
          return
      SandS_guard = False             ;スペースキーガードを外す
      Send,{Shift Up}                 ;シフトキー解放
      ifEqual SandS_key               ;SandS文字入力なし
          Send,{Space}                ;スペースを発射
      SandS_key=
      return

解説

修飾キー同時の押しについて

修飾キーを優先させたいため、あえて*Space::ではなくSpace::を使用しています。
そのため Shif+Space によるスペースの入力はキーリピートが効くという利点(?)もあります。

また、<^Space::>+Space::等のように、個別に定義しなおすこともできます。

以下、失敗例

修飾キー同時押し時も含めて SandS にしたいとき(失敗例)

修飾キーと Space 同時押しした時にも、Space を Shift キーとして使いたい、という場合―――あまり考えられない状況ですが、Shift 以外の修飾キー、例えば Ctrl+Space を Ctrl+Shift として扱いたい、と言う感じでしょうか?―――もし、上記スクリプトを単純に*Space::に置き換えてしまうと、ALT+Space や Shift+Space や Ctrl+Space Win+Space 等もすべて該当ルーチン内で処理されてしまい、シフト押し下げ相当の事しかしてくれなくなってしまいます。

コントロールメニューにフォーカスを移すことも、Excel で行選択や列選択をすることも、できなくなってしまいます。
(Win+Space による IME の切り替えもできなくなりますが、それはあまり使わないので問題ない。)

そこで出てくるのが Send コマンドの 「{Blind}」というキーワードです。
通常、Send コマンドでは、修飾キーは仮想的に離された状態として処理されますが、「{Blind}」をキー名の前につけることで、修飾キーの自動復元を行ってくれます。

一応書いてみると、こんな感じになりますか。

ついでに、up::時のinputの空打ちがないと、%SandS_key% に半角空白が入ってきてしまうので、%A_Space%との比較が必要になってしまうという例も盛り込んでおきます。

Sands_Blind.ahk
  #InstallKeybdHook

  $*Space::                       ;スペース押下時

      if SandS_guard = True       ;スペースキーガード
          Return
      SandS_guard = True          ;スペースキーにガードをかける

      Send,{Shift Down}           ;シフトキーを仮想的に押し下げる

      ifNotEqual SandS_key        ;文字入力済みの場合は終わり
          return
      SandS_key=
      Input,SandS_key,L1 V        ;1文字入力を受け付け(入力有無判定用)


      Return


  $*Space up::                    ;スペース解放時
      ;input                       ;既存のInputコマンドの終了
      SandS_guard = False         ;スペースキーガードを外す
      Send,{Shift Up}             ;シフトキー解放

      ifEqual SandS_key           ;SandS文字入力なし
          Send,{Blind}{Space}     ;修飾を復元しながらスペースを発射
      ifEqual SandS_key,%A_Space% ;空白文字(Inputに、Sendした{Space}が詰まるため)
          Send,{Blind}{Space}     ;修飾を復元しながらスペースを発射

      SandS_key=
      Return

Shift+Space を入力してもリピートもされないのは良いとしても、Ctrl+Space を入力すると、私の環境ではなぜか、IME の切り替えが暴発したりしますね。謎です。

IME の切り替えが暴発する時点でお話になりませんが、もう一つ、使い物にならない理由があります。

IME が全角入力になっている最中に、 Shift → Space の順で押下します。その後、Shift → Space という順番で指を離してみてください。半角空白を期待していたのに、全角空白が入ってしまうのです。

Shift → Space と押された時点で*Space::が動き出しますが、Space を離すまで空白文字はまだ入力されません。Shift → Space と離された時点で*Space up::が動き出しますが、この時点ではもうShiftは押されておらず、Send コマンドの Blind 指定もむなしく、IME の状態に従って全角空白が入力されてしまうのです。嗚呼、残念無念。

修飾キー同時押し時も含めて SandS にしたいとき(押下、解放の順序問題へ対応)

上記の失敗を回避するために、*Space::の中で、Space が押された瞬間に、どの修飾キーが押されていたのか覚えておけば良いじゃん!というアプローチもあります。

もはや、あまりする必要の無い苦労ですが、どうしても Shift+Space がリピートしてしまうのが嫌だ! とか、Ctrl+Space+a の場合には Ctrl+A として振舞ってほしいんだ! いう場合にはもう少し迷走してみるのもよいでしょう。

こうなりました。

SandS_Modif.ahk
  #InstallKeybdHook

  $*Space::                           ;スペース押下時
      ;tooltip,"%SandS_mod%" "%SandS_key%" %SandS_guard%  ;debug

      if SandS_guard = True           ;スペースキーガード
          Return
      SandS_guard = True              ;スペースキーにガードをかける

      Send,{Shift Down}               ;シフトキーを仮想的に押し下げる

      SandS_mod=                      ;装飾キー退避
      GetKeyState, state, Shift,P
      if state=D
          SandS_mod=%SandS_mod%+
      GetKeyState, state, Ctrl,P
      if state=D
          SandS_mod=%SandS_mod%^
      GetKeyState, state, Alt,P
      if state=D
          SandS_mod=%SandS_mod%!

      GetKeyState, state, LWin,P
      if state=D
          SandS_mod=%SandS_mod%#
      GetKeyState, state, RWin,P
      if state=D
          SandS_mod=%SandS_mod%#

      ifNotEqual SandS_key            ;文字入力済みの場合は終わり
          return
      SandS_key=
      Input,SandS_key,L1 V            ;1文字入力を受け付け(入力有無判定用)



      Return


  $*Space up::                        ;スペース解放時
      ;tooltip,"%SandS_mod%" "%SandS_key%" %SandS_guard%  ;debug

      input                           ;既存のInputコマンドの終了
      SandS_guard = False             ;スペースキーガードを外す
      Send,{Shift Up}                 ;シフトキー解放

      ifNotEqual SandS_mod            ;修飾キーありの場合
          Send,%SandS_mod%{Space}     ;自前で修飾しながらスペースを発射!
      else                            ;修飾キー同時押しではなかった場合
          ifEqual SandS_key           ;SandS文字入力なし
              Send,{Space}            ;単打のスペースを発射

      SandS_key=
      Return

Shift+Spaceを長押ししても、Spaceを離すまで何も入力されず、キーリピートも抑止されています。

問題だった、Shift → Space の順で押し下げて、Shift → Space の順で離してみても、全角空白は出ませんね!成功です。

でも 私の端末では、相変わらず Ctrl 同時押し時の IME 切り替えが暴発するので、結局、一番最初のコードを使っています。