Site cover image

Site icon imageGrizzly Storage Blog

新設されたゆうとんのブログです。メモぐらいの気持ちで書いていけたらと思っています。
更新日:2024-09-20

⌨️AutoHotkeyにて様々な文字で自動的に囲んでくれるスクリプトを作った

⚠️
こちらの記事はAutoHotkeyのv1.1対応です。v2には対応していません。
📎
IME.ahkが必要です。こちらからダウンロードしてください。

 カッコ、使っていらっしゃるでしょうか。もちろん()とかの話です。

 ()や「」なんかは使っても、それ以外はあんまり使わないですよね。といっても全く使わないわけではない。ごくたまに使いたいな……と思うことがあります。
 そういった時に囲むの面倒だと思いませんか?

 今回はそのような面倒事を避けるべく、スクリプトを作ってみました。

目次

機能

 まずは動画をご覧ください。

GUI起動

 無変換+Tabキーを押すことで起動します。

 入力したのち、Enterを押せば送信されてGUIも終了します。
 Escで送信せずやめることもできます。

選択文字を囲む

 動画全てがこちらの機能を使っています。

 文字列を選択した状態でGUIを起動し、囲み文字の先頭だけ入力すれば、文字列の最後に囲み文字の後尾を入れてくれます。

 この囲み文字はほぼどんな文字でも機能します。[{<など……。流石に全部は対応できていないとは思いますが、括弧の中で割と使える部類は大丈夫かと思います。

 ちなみに複数入力も可能です。「「「と打てば、「「「<選択された文字>」」」という感じに囲まれます。

この文字のみ使用

 GUIに出てくるこの文字のみ使用にチェックを入れれば、後尾に置かれる文字も先頭と同じ文字になります。などが使えるでしょうか。

 ちなみに、Tabからのスペースでチェックを入れることができます。

事前入力

 こちらは動画に映っていませんが、文字列を選択していない状態の機能です。

 ただのカーソルの時に入力すると、囲み文字が入力されたのちカーソルが囲み文字の真ん中に入ります。地味に便利な機能です。

 複数入力した場合は入力した分カーソルがずれていきます。

コード

 少し長めです。効率化もそこまでされていないし、他人のコードの流用も混じっていますが……。

EncloseStr := ""
IsSingle := 0
IsIMEOn := 0
sc07B & Tab::
  IsIMEOn := IME_Get()
  EncloseStr := ""
  Gui, Add, Text, , 囲み用文字
  Gui, Add, Edit, W200 vEncloseStr, %EncloseStr%
  Gui, Add, Checkbox, y+1 vIsSingle, この文字のみ使用
  Gui, Show,, WrapText
  Return

#IfWinActive WrapText
~Enter::
  if (IME_Get())
    Return
  Gui, Submit
  Gui, Destroy
  Sleep, 50
  reverseChrs := ""
  if(!IsSingle) {
    for index, chr in StrSplit(EncloseStr)
      reverseChrs := GetCloseStr(chr) . reverseChrs
    Enclose(EncloseStr, reverseChrs)
  }
  else {
    Enclose(EncloseStr, EncloseStr)
  }
  if (IsIMEOn)
    IME_Set(1)
  Return
#IfWinActive

GuiEscape:
GuiClose:
ButtonCancel:
  Gui, Destroy
Return

GetCloseStr(beginStr) {
  begin := Asc(beginStr)
  end := begin + 1
  if (42 <= begin && begin <= 128 || begin >= 65290) {
    end += 1
  }
  Return Chr(end)
}

Enclose(begin, end) {
  oldClipboard = %ClipboardAll%
  Clipboard =
  Send, ^c
  ClipWait, 0.1
  ; 選択時は囲む
  If (ErrorLevel == 0) {
    StringRight, LastChar, Clipboard, 1
    If (LastChar != "`n") {
      WinGetTitle, CurrentWinTitle
      Clipboard = %begin%%Clipboard%%end%
      ClipWait
      WinActivate, %CurrentWinTitle%
      Send, ^v
      Sleep 150
    }
    Clipboard = %oldClipboard%
    Return
  }
  ; 囲む記号を記述し、その中にカーソルを持っていく
  Else {
    WinGetTitle, CurrentWinTitle
    Clipboard = %begin%%end%
    WinActivate, %CurrentWinTitle%
    Send, ^v
    Sleep 50
    Send, {Ctrl Up}
    Loop % StrLen(end) {
      Send, {Left}
    }
    Sleep 100
    Clipboard = %oldClipboard%
    Return
  }
}

 今見たらめっちゃ汚い。でも普通に動くのでそのまま出します。

仕組み

 一部だけ解説します。そんなの要らないという方はスキップしてください。

~Enter::
  if (IME_Get())
    Return

 こちらのifが無いと変換完了時のEnterで反応してしまい、空文字列を送信してしまいます。

 そうならないようにIMEがONの時、すなわち日本語入力の時はEnterでの送信を阻止しています。

reverseChrs := ""
  if(!IsSingle) {
    for index, chr in StrSplit(EncloseStr)
      reverseChrs := GetCloseStr(chr) . reverseChrs
    Enclose(EncloseStr, reverseChrs)
  }
  else {
    Enclose(EncloseStr, EncloseStr)
  }

 入力された文字を1文字ずつ処理していきます。閉じ文字を探したのち結果文字列の前にくっつけることで、文字列反転を実現させています。

 ちなみにあのチェックボックスを付けていない場合はelseに飛びます。

GetCloseStr(beginStr) {
  begin := Asc(beginStr)
  end := begin + 1
  if (42 <= begin && begin <= 128 || begin >= 65290) {
    end += 1
  }
  Return Chr(end)
}

 今回の要となる関数です。こちらで閉じ文字をgetしています。

 まずどうやって開き文字を使って閉じ文字を得るかですが、文字コードを使用します。開き文字の文字コードの次に閉じ文字の文字コードがあるだろう、と最初は考えました。

 これで日本語記号の場合は上手くいったのですが、英記号は何故か上手くいかず。

 ちゃんと調べてみたところ、英記号の括弧の大半は2つ先にあることが分かりました。

 そのため42~128の文字コードの場合はもう一度+1をし、2つ先にある閉じ文字の文字コードを返しているわけです。

 なお英記号の全角も同じように並んでいるらしく、そちらも+1をしています。少し面倒ですね。

 ちなみにEnclose(begin, end)はほぼ受け売りです。一応変えている部分もあるので解説します。

Enclose(begin, end) {
  ...
  Else {
	  ...
	  Loop % StrLen(end) {
		  Send, {Left}
		}

 ここは入力された開き文字の数だけ←キーを送信するものです。

 実はSendコマンドには連続でn回入力させる方法があるのですが、こちらは静的な値を入力しなければならず、変数は置けないようです。

 なのでLoopコマンドで行う必要があります。地味にLoopコマンドで変数を渡すのにも苦労しました。

最後に

 初の技術紹介記事でしたが、書いていて楽しかったので良しとします。

 AHKのGUIの勉強として作ってみたのですが、意外と楽に実装できたので驚きました。Javaとかは結構辛かったので。まあ趣味開発であれば現在はPythonが一番いいんですかね。

 AHKはv2の方がさらに高度言語化していて使いたさはあるのですが、今絶賛使用中のMouseGestureLがv1.1なので留まり続けると思います。
 v2に対応されるか、自分で対応するかすれば話は変わってくるかもしれないですね。

それではまた~。