AutoHotkey設定メモ　　　　　　　　　　　　　　　　　　

# Tips

基本的なことはこちらを参考に。
[AutoHotkey Wiki](http://ahkwiki.net/Top)

## エディタの変更
タスクトレイメニュー`EDIT THIS SCRIPT`で起動するエディタを変更するには、以下のレジストリを編集しましょう。

- キー値:
    - `HKEY_CLASSES_ROOT\AutoHotkeyScript\Shell\Edit\Command`
- 設定例:
    - VisualStudio Code
        - `"C:\Users\username\AppData\Local\Programs\Microsoft VS Code\Code.exe" "%1"`
    - Notepad++
        - `"C:\Program files\notepad++\notepad++.exe" "%1"`
    - サクラエディタ
        - `"C:\Program Files (x86)\sakura\sakura.exe" "%1"`

## デバッグ
デバッグ時の変数内容の確認などに`MsgBox`を使うことは多いと思います。
が、`MsgBox`は表示するとそこでスクリプトが停止してしまうため、それが困る場合(例えば`SetTimer`の内容をデバッグしたいけど、`MsgBox`が鬼表示される時など)は`SplashImage`を使うと幸せになれるかもしれません。
継続的に監視したい場合は、`SetTimer`で`SplashImage`を定期更新させるといいです。

```ini
/**
 * デバッグ用スプラッシュを表示
 *
 * @Hotkey [Ctrl]+[Alt]+[Shift]+[F12]
 * @Target デフォルト
 */
+^!F12::
    ;フラグのトグル
    vSplash := vSplash ? False : True

    If (vSplash)
    {
        ;フラグがオンだったらスプラッシュを表示し定期的にリロード
        SetTimer, DebugSplashReload, 0
    }
    Else
    {
        ;フラグがオフだったらスプラッシュを消去しリロードを解除
        SetTimer, DebugSplashReload, Off
        SplashImage, 10:Off
    }
Return

/**
 * デバッグ用スプラッシュを表示し、定期的にリロード
 */
DebugSplashReload:
    ;タイマーを2500ミリ秒に設定
    SetTimer, DebugSplashReload, 2500

    ;ウィンドウタイトル
    vDebugSplashTitle := "Debug"

    ;表示中スプラッシュの位置と大きさを取得
    WinGetPos, vDebugSplashX, vDebugSplashY, vDebugSplashWidth, vDebugSplashHeight, %vDebugSplashTitle% ahk_exe AutoHotkey.exe

    If (vDebugSplashX == "")
    {
        ;ウィンドウが存在しない場合、スプラッシュの横幅と位置を初期設定
        vDebugSplashWidth := 400
        vDebugSplashHeight := 186
        vDebugSplashX := A_ScreenWidth - vDebugSplashWidth
        vDebugSplashY := 0
    }
    Else
    {
        ;ウィンドウが存在する場合、マージン・タイトルバー分を調整
        vDebugSplashWidth := vDebugSplashWidth - 16
        vDebugSplashHeight := vDebugSplashHeight - 38
    }

    ;表示情報
    WinGetPos, vX, vY, vWidth, vHeight, A ;アクティブウィンドウ
    vIME := IME_GET() ? "ON" : "OFF" ;IME状態
    vIMEKana := IME_GetConvMode > 11 ? "KANAロック" : "" ;かなロック状態
    vIMEConvMode := IME_GetConvMode() == 0 || IME_GetConvMode() == 16 ? "半英数" : vIMEConvMode ;入力モード
    vIMEConvMode := IME_GetConvMode() == 3 || IME_GetConvMode() == 19  ? "半カナ" : vIMEConvMode ;入力モード
    vIMEConvMode := IME_GetConvMode() == 8 || IME_GetConvMode() == 24  ? "全英数" : vIMEConvMode ;入力モード
    vIMEConvMode := IME_GetConvMode() == 9 || IME_GetConvMode() == 25  ? "ひらがな" : vIMEConvMode ;入力モード
    vIMEConvMode := IME_GetConvMode() == 11 || IME_GetConvMode() == 27  ? "全カタカナ" : vIMEConvMode ;入力モード
    vIMESentenceMode := IME_GetSentenceMode() == 0 ? "無変換" : vIMESentenceMode ;変換モード
    vIMESentenceMode := IME_GetSentenceMode() == 1 ? "人名/地名" : vIMESentenceMode ;変換モード
    vIMESentenceMode := IME_GetSentenceMode() == 8 ? "一般" : vIMESentenceMode ;変換モード
    vIMESentenceMode := IME_GetSentenceMode() == 16 ? "話し言葉" : vIMESentenceMode ;変換モード
    vIMEConverting := IME_GetConverting() == 0 ? "その他" : vIMEConverting ;変換状態
    vIMEConverting := IME_GetConverting() == 1 ? "入力変換中" : vIMEConverting ;変換状態
    vIMEConverting := IME_GetConverting() == 2 ? "変換候補選択" : vIMEConverting ;変換状態

    ;スプラッシュ(10:デバッグ用)を表示
    SplashImage, 10:, FM12 FS10 M1 H%vDebugSplashHeight% W%vDebugSplashWidth% X%vDebugSplashX% Y%vDebugSplashY% C00,
    (LTrim
        ThisHotkey: %A_ThisHotkey% %A_TimeSinceThisHotkey% msec
        PriorHotkey: %A_PriorHotkey% %A_TimeSincePriorHotkey% msec
        PhysicalIdleTime: %A_TimeIdlePhysical%
        ErrorLevel: %ErrorLevel%
        Clipboard:%Clipboard%
        Caret: X=%A_CaretX% Y=%A_CaretY%
        WinPos: H=%vHeight% W=%vWidth% X=%vX% Y=%vY%
        Screen: H=%A_ScreenHeight% W=%A_ScreenWidth%
        IME: %vIME% %vIMEKana% %vIMEConvMode% %vIMESentenceMode% %vIMEConverting%
    ), , %vDebugSplashTitle%, Meiryo UI
Return
```

- [Progress / SplashImage \- AutoHotkey Wiki](http://ahkwiki.net/Progress_/_SplashImage)

# 設定内容

自分用メモ。
※随時更新中

スクリプト内でライブラリ[IME制御]を使用しています。
利用する際は下記リンクからダウンロードの上、展開した`IME.ahk`を`AutoHotkey.exe`と同階層の`Lib`フォルダか`MyDocuments\AutoHotkey\Lib`に格納する(関数ライブラリ)、`Include`コマンドを使用するなどしてライブラリを使用可能にしてください。

- [IME制御 \- eamat @Cabinet \- アットウィキ](https://www6.atwiki.jp/eamat/pages/17.html)

- [関数 \- AutoHotkey Wiki](http://ahkwiki.net/Function#.E9.96.A2.E6.95.B0.E3.83.A9.E3.82.A4.E3.83.96.E3.83.A9.E3.83.AA.E3.82.B9.E3.82.AF.E3.83.AA.E3.83.97.E3.83.88)
- [\#Include / \#IncludeAgain \- AutoHotkey Wiki](http://ahkwiki.net/-Include)

コーディングルールは可能な限り以下に従っています。

- 変数の命名規約
    - `vName`: ローカル変数
    - `gName`: グローバル変数
    - `cName`: 定数値
    - `pName`: 引数
- コマンド等はアッパーキャメルケース。
- 値の代入には`=`ではなく`:=`を使う。
- 論理演算子には`And`, `Or`ではなく`&&`, `||`を使う
- ブロックは省略可能でも`{}`で明示的に囲う。
- 式が利用可能な場合は極力式を使う。

など。

コメントについては、JsDoc風のコメントをホットキーとホットストリング、いちおう関数にも設定しています。
このコメントを読み込んで、[ヘルプウィンドウを表示する](https://qiita.com/draganmaistir/items/36bd90fa6c5a93736c70)のに使っています。

```ini
/**
 * ホットキー/ホットストリングの説明
 *
 * @hotkey [ホットキー]
 * @hotstr [ホットストリング]
 * @target [対象ウィンドウ]
 * @condition [発動条件]
 */

/**
 * 関数の説明
 *
 * @param {パラメータの型} [パラメータ名] パラメータの説明
 * @return {戻り値の型} [戻り値名] 戻り値の説明
 */
```

## Auto-Executeセクション
最初の`Return`までを起動時に実行。
AutoHotkeyの設定処理。

```ini
;[START]Auto-executeセクション開始

/**
 * AutoHotkey設定
 */
#Persistent ;スクリプトを常駐状態にする
#SingleInstance force ;同じスクリプトの複数プロセス実行を禁止
#NoEnv ;変数名を解釈する時環境変数を無視
#InstallKeybdHook ;ホットキーの設定に無条件でキーボードフックを適応
#UseHook ;ホットキーラベルの定義で常にフックを使用
SendMode, Input ;SendコマンドにWindowsAPIのSendInput関数を利用
SetKeyDelay, 30 ;Sendコマンドで1キーごとに挿入される間隔
SetTitleMatchMode, 2 ;対象ウィンドウ検索方法を中間一致に設定
CoordMode, Caret, Screen ;キャレットの取得座標をスクリーン上の絶対位置に指定
SetNumLockState, On ;[NumLock]をオン
SetScrollLockState, Off ;[ScrollLock]をオフ
OnClipboardChange("NoticeClipboard") ;クリップボード変更時に実行する関数

/**
 * プログラムグループ
 */
;テキストエディタ
GroupAdd, GroupTextEditor, ahk_exe notepad.exe ;メモ帳
GroupAdd, GroupTextEditor, ahk_exe notepad++.exe ;Notepad++
GroupAdd, GroupTextEditor, ahk_exe sakura.exe ;サクラエディタ
GroupAdd, GroupTextEditor, ahk_exe Code.exe ;Visual Studio Code

;ブラウザ
GroupAdd, GroupBrowser, ahk_exe Chrome.exe ;Google Chrome
GroupAdd, GroupBrowser, ahk_exe iexplore.exe ;Internet Explorer

;[F1]ヘルプ起動抑制
GroupAdd, GroupF1Help, ahk_class Progman ;エクスプローラ
GroupAdd, GroupF1Help, ahk_class CabinetWClass ;デスクトップ
GroupAdd, GroupF1Help, ahk_exe OUTLOOK.EXE ;Outlook
GroupAdd, GroupF1Help, ahk_exe WINWORD.EXE ;Word
GroupAdd, GroupF1Help, ahk_exe EXCEL.EXE ;Excel
GroupAdd, GroupF1Help, ahk_exe POWERPNT.EXE ;PowerPoint
GroupAdd, GroupF1Help, ahk_exe MSACCESS.EXE ;Access
GroupAdd, GroupF1Help, ahk_exe WINPROJ.EXE ;Project
GroupAdd, GroupF1Help, ahk_exe ONENOTE.EXE ;OneNote
GroupAdd, GroupF1Help, ahk_exe MSPUB.EXE ;Publisher
GroupAdd, GroupF1Help, ahk_exe INFOPATH.EXE ;InfoPath
GroupAdd, GroupF1Help, ahk_exe Chrome.exe ;Google Chrome
GroupAdd, GroupF1Help, ahk_exe iexplore.exe ;Internet Explorer

/**
 * グローバル変数
 */
;ブラウザパス
global cIEPath := "C:\Program Files\Internet Explorer\iexplore.exe"
global cChromePath := "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"

;クリップボード更新フラグ
Global gClipboardChange := False

;ContinueAction関数の実行継続フラグ
global gContinueAction := False

Return

;[END]Auto-executeセクション終了
```

### #Persistent
スクリプトの常駐。

- [\#Persistent \- AutoHotkey Wiki](http://ahkwiki.net/-Persistent)

### #SingleInstance force
同じスクリプトの複数プロセス実行の許可/禁止。

- [\#SingleInstance \- AutoHotkey Wiki](http://ahkwiki.net/-SingleInstance)

### #NoEnv
環境変数を変数として参照しない。
意図しない環境変数を参照しないように設定しておくこと推奨。
環境変数を参照したい場合は`EnvGet`コマンドで明示的に取得できます。

- [\#NoEnv \- AutoHotkey Wiki](http://ahkwiki.net/-NoEnv)
- [EnvGet \- AutoHotkey Wiki](http://ahkwiki.net/EnvGet)

### #InstallKeybdHook / #UseHook
常にキーボードフックを使う。
[Ctrl]キー押しっ放し病が発症したため投与。

- [\#InstallKeybdHook \- AutoHotkey Wiki](http://ahkwiki.net/-InstallKeybdHook)
- [\#UseHook \- AutoHotkey Wiki](http://ahkwiki.net/-UseHook)

### SendMode, Input
`Send`コマンドのデフォルトモード。
`InputThenPlay`にした場合、`SendEvent`を送らないと動かないスクリプトがいくつかあったので、`Input`推奨。

- [SendMode \- AutoHotkey Wiki](http://ahkwiki.net/SendMode)

### SetKeyDelay, 20
`Send`や`ControlSend`コマンド時のキー入力間隔(ms)。

- [SetKeyDelay \- AutoHotkey Wiki](http://ahkwiki.net/SetKeyDelay)

### SetTitleMatchMode, 2
ウィンドウ関連コマンドでの対象ウィンドウ検索方法。

- [SetTitleMatchMode \- AutoHotkey Wiki](http://ahkwiki.net/SetTitleMatchMode)

### CoordMode, Caret, Screen
キャレットの座標取得基準位置。

- [CoordMode \- AutoHotkey Wiki](http://ahkwiki.net/CoordMode)

### SetNumLockState / ScrollLockState, On / Off
[NumLock]/[ScrollLock]キーのロックの状態を指定。
ちなみに[CapsLock]の設定は`SetCapsLockState`。
`SetScrollLockState`は最初`AlwaysOff`にしていましたが、ホイールで横スクロールを発生させる際にオンにする必要が生じたため変更。
代わりに、ホットキーとして[ScrollLock]キーと[NumLock]キーを殺す設定を入れ、キーボードからは制御できないけどスクリプト内では制御可能となるようにしました。

- [Set\[Caps/Num/Scroll\]LockState \- AutoHotkey Wiki](http://ahkwiki.net/SetLockState)

### OnClipboardChange("NoticeClipboard")
クリップボードの更新を検知して動作する組み込み関数。
引数に指定した名前の関数を作成すると、クリップボードの中身が更新されるたびにその関数が実行されます。
以下の記事で詳細が載っています。

- [\[AutoHotKey\]OnClipboardChange\(\)関数でクリップボード監視 \- Qiita](https://qiita.com/catfist/items/cdb8300221b48667b155)
- [OnClipboardChange \- Syntax & Usage \| AutoHotkey](https://autohotkey.com/docs/commands/OnClipboardChange.htm)

以前からある組み込みラベル`onClipboardChange`サブルーチンについてはこちら。
- [OnClipboardChangeサブルーチン \- AutoHotkey Wiki](http://ahkwiki.net/Clipboard#OnClipboardChange)

## 全般設定
### クリップボード監視
上記`OnClipboardChange`で呼び出される関数の実体。
コピーされたテキストの最初50文字をツールチップに表示します。
なお、この設定によりホットキーのスクリプトでクリップボードを操作するものについて、発動と同時にツールチップが表示されるようになってしまいます。
これを回避するためには、クリップボード操作の直前直後に以下のスクリプトを追加する必要があります。

```ini
;onClipboardChangeの一時停止
    OnClipboardChange("NoticeClipboard", 0)

;onClipboardChangeの再開
    OnClipboardChange("NoticeClipboard", 1)
```
`onClipboardChange`関数の第一引数は設定した関数名、第二引数は`0`が停止、`1`が開始です。

```ini
/**
 * 組み込み関数OnClipboardChangeでクリップボードを監視し、クリップボードの内容をツールチップで表示する。
 *
 * @param {number} pType クリップボードの内容タイプ。0:空 1:テキストデータ 2:非テキストデータ
 * @return {boolean} gClipboardChange [Ctrl]+C/[Ctrl]+Xの場合のクリップボード変更フラグ。
 */
NoticeClipboard(pType) {
    cStrLen := 50

    ;ツールチップの表示位置
    vCaretX := A_CaretX + 20
    vCaretY := A_CaretY + 20

    If (A_ThisHotkey == "^c" || A_ThisHotkey == "^x")
    {
        ;[Ctrl]+C/[Ctrl]+Xの場合、クリップボード変更フラグをオン
        gClipboardChange := True
    }

    If (pType == 0)
    {
        ;クリップボードが空になった場合、メッセージのみ表示
        vStr := "クリップボードが空になりました。"
    }

    If (pType == 1)
    {
        ;クリップボード変数に文字が格納された場合、最初の50文字を追記
        vClipStr := SubStr(Clipboard, 1, cStrLen)
        StringLen, vStrLen, Clipboard

        If (vStrLen > cStrLen)
        {
            ;クリップボードの文字が50文字より多い場合、 省略文字数を追記
            vClipStr := vClipStr . "...`r`n(" . vStrLen - cStrLen . " 文字を省略しました)"
        }

        ;ツールチップに表示する文字列
        vStr := "クリップボードにコピーしました。"
        vStr := vStr . "`r`n`r`n" . vClipStr
    }

    ;ツールチップをキャレット位置に表示し、1200ミリ秒後に消去するタイマーをセット
    ToolTip, %vStr%, %vCaretX%, %vCaretY%,
    SetTimer, RemoveToolTip, 1200
}

/**
 * タイマーをオフにし、ツールチップを消去する。
 */
RemoveToolTip:
    SetTimer, RemoveToolTip, Off
    ToolTip
Return
```

後で出てくる未選択時[Ctrl]+C/[Ctrl]+Xでラインコピー/ラインカットのために、グローバル変数としてクリップボードが更新されたかを示すフラグを用意し、関数内で更新しています。

### [NumLock] / [ScrollLock]キー無効化

```ini
/**
 * 無効
 *
 * @Hotkey [NumLock]
 * @Hotkey [ScrollLock]
 * @Target デフォルト
 */
NumLock::
ScrollLock::
    ;バルーンメッセージを表示
    TrayTip, %A_ThisHotkey%, [%A_ThisHotkey%]の入力は無効化されています。, 10, 17
Return
```
### 上書きモード、CapsLockモード、[F1]ヘルプ起動の抑制
気付いたらなっている上書きモード([Insert]キー)、CapsLockモード([Shift]+[CapsLock])、と、主にExcelで[F2]編集時にヘルプが起動する怒りのデスロードを避けるため。
[F1]抑制の対象はAutoHotkeyセクションでプログラムグループとして指定しています。

```ini
/**
 * 上書きモード
 *
 * @hotkey [Insert]長押し
 * @target デフォルト
 */
Insert::
    ;[Insert]キーの押し下げ状態を300ミリ秒待機
    KeyWait, Insert, T0.3

    If (ErrorLevel)
    {
        ;指定時間が経過した場合、{Insert}キーを送信
        Send, {Insert}

        ;上書きモードの状態を取得
        If (GetKeyState("Insert", "T"))
        {
            ;上書きモードオンの場合
            TrayTip, 上書きモード, 上書きモードをオンにしました。, 10, 17
        }
        Else
        {
            ;上書きモードオフの場合
            TrayTip, 上書きモード, 上書きモードをオフにしました。, 10, 17
        }
    }
    Else
    {
        ;指定時間経過前にキーが離された場合、バルーンメッセージを表示
        TrayTip, 上書きモード, 上書きモードを有効にするには[Insert]キーを長押ししてください。, 10, 17
    }

    ;長押し後キーを離した時にホットキーを発動させないようにする
    KeyWait, Insert
Return

/**
 * CapsLockモード
 *
 * @hotkey [Shift]+[CapsLock]長押し
 * @target デフォルト
 */
+CapsLock::
    ;[Shift]+[CapsLock]キーの押し下げ状態を300ミリ秒待機
    KeyWait, Shift, T0.3
    KeyWait, CapsLock, T0.3

    If (ErrorLevel)
    {
        ;指定時間が経過した場合、CapsLockモードの状態を取得
        If (GetKeyState("CapsLock", "T"))
        {
            ;CapsLockモードがオンの場合、オフにしてバルーンメッセージを表示
            SetCapsLockState, Off
            TrayTip, CapsLockモード, CapsLockをオフにしました。, 10, 17
        }
        Else
        {
            ;CapsLockモードがオフの場合、オンにしてバルーンメッセージを表示
            SetCapsLockState, On
            TrayTip, CapsLockモード, CapsLockをオンにしました。, 10, 17
        }
    }
    Else
    {
        ;指定時間経過前にキーが離された場合、バルーンメッセージを表示
        TrayTip, CapsLockモード, CapsLockをオンにするには、[Shift]+[CapsLock]を長押ししてください。, 10, 17
    }

    ;長押し後キーを離した時にホットキーを発動させないようにする
    KeyWait, Shift
    KeyWait, CapsLock
Return

;[START] F1ヘルプ起動抑制
#IfWinActive, ahk_group GroupF1Help

/**
 * ヘルプを表示
 *
 * @hotkey [F1]長押し
 * @target F1ヘルプ起動抑制(エクスプローラ/デスクトップ/Microsoft Office)
 */
F1::
    ;[F1]キーの押し下げ状態を300ミリ秒待機
    KeyWait, F1, T0.3

    If (ErrorLevel)
    {
        ;指定時間が経過した場合、キーをそのまま送信
        Send, {F1}
    }
    Else
    {
        ;指定時間経過前にキーが離された場合、バルーンメッセージを表示
        TrayTip, ヘルプの表示, ヘルプを表示するには[F1]キーを長押ししてください。, 10, 17
    }
    KeyWait, F1
Return

#IfWinActive
;[END] F1ヘルプ起動抑制
```

### キー2連打でアプリケーション起動
左[Alt]2連打に[Rapture](http://www.geocities.jp/knystd/rapture.html)、右[Alt]2連打に[Everything](https://www.voidtools.com/)、[Ctrl]2連打に[Clibor](https://www.amunsnet.com/)というアプリを割り当てています。
ちなみにここで使っているCliborというアプリは、アプリ側の機能として[Ctrl]キー2連打で起動するという設定を持っていますが、それがAutoHotkeyからの[Ctrl]キー送信によって誤動作を起こしまくっていたので、アプリ側の設定を殺してAutoHotkey側に統一しました。
基本的にアプリ側にホットキー機能を持っていてもAutoHotkey側に統一した方が、誤動作は起こしにくいと思います。
チルダ`~`については以下を参照。

- [ホットキー \- AutoHotkeyJp](https://sites.google.com/site/autohotkeyjp/reference/Hotkeys)

```ini
/**
 * Raptureを起動
 *
 * @hotkey 左[Alt]キー2回
 * @target デフォルト
 */
~LAlt up::
    If (A_PriorHotKey == A_ThisHotKey && A_TimeSincePriorHotkey < 300)
    {
        ;直前のキーと今回のキーが同じで300ミリ秒以内の場合、アプリケーション起動
        Run, C:\Apps\Rapture\rapture.exe, C:\Apps\Rapture\Rapture\
    }
Return

/**
 * Everythingを起動
 *
 * @hotkey 右[Alt]キー2回
 * @target デフォルト
 */
~RAlt up::
    If (A_PriorHotKey == A_ThisHotKey && A_TimeSincePriorHotkey < 300)
    {
        ;直前のキーと今回のキーが同じで300ミリ秒以内の場合、アプリケーション起動
        Run, C:\Program Files\Everything\Everything.exe, C:\Program Files\Everything\
    }
Return

/**
 * Clibor(クリップボードタブ)を起動
 *
 * @hotkey 左[Ctrl]キー2回
 * @target デフォルト
 */
~LCtrl up::
    If (A_PriorHotKey == A_ThisHotKey && A_TimeSincePriorHotkey < 300)
    {
        ;直前のキーと今回のキーが同じで300ミリ秒以内の場合、アプリケーション起動
        Run, C:\Apps\clibor\Clibor.exe /vc 1, C:\Apps\clibor\
    }
Return

/**
 * Clibor(定型文タブ)を起動
 *
 * @hotkey 右[Ctrl]キー2回
 * @target デフォルト
 */
~RCtrl up::
    If (A_PriorHotKey == A_ThisHotKey && A_TimeSincePriorHotkey < 300)
    {
        ;直前のキーと今回のキーが同じで300ミリ秒以内の場合、アプリケーション起動
        Run, C:\Apps\clibor\Clibor.exe /vt 1, C:\Apps\clibor\
    }
Return
```

### AutoHotkey関連機能
スクリプトの編集や再読み込みなどを割り当てています。
スクリプト終了時の`OnExit`は、`OnExit`サブルーチンが設定されている場合に解除しないとスクリプトが終了できないため入れています。
今のところ`OnExit`は設定してませんが、この記述があっても問題はないので問答無用で書いておいて損はないと思います。

- [TrayTip \- AutoHotkey Wiki](http://ahkwiki.net/TrayTip)
- [OnExit \- AutoHotkey Wiki](http://ahkwiki.net/OnExit)

```ini
/**
 * スクリプトを編集
 *
 * @hotkey [Ctrl]+[Alt]+[Shift]+[F1]
 * @target デフォルト
 */
+^!F1::Run, Edit %A_ScriptFullPath%

/**
 * スクリプトを再読み込み
 *
 * @hotkey [Ctrl]+[Alt]+[Shift]+[F2]
 * @target デフォルト
 */
+^!F2::
    ;OnExitを無効化
    OnExit

    ;バルーンメッセージを表示
    TrayTip, AutoHotkey, %A_ScriptName% を更新しました。, 10, 17

    Reload
Return

/**
 * スクリプトディレクトリを開く
 *
 * @hotkey [Ctrl]+[Alt]+[Shift]+[F3]
 * @target デフォルト
 */
+^!F3::Run, %A_ScriptDir%

/**
 * スクリプトを終了
 *
 * @hotkey [Ctrl]+[Alt]+[Shift]+[F4]
 * @target デフォルト
 */
+^!F4::
    ;OnExitを無効化
    OnExit

    ;バルーンメッセージを表示
    TrayTip, AutoHotkey, %A_Scriptname% を終了しました。, 10, 17

    ExitApp
Return

/**
 * スクリプト実行履歴を表示
 *
 * @hotkey [Ctrl]+[Alt]+[Shift]+[F5]
 * @target デフォルト
 */
+^!F5::
    ListLines
Return

/**
 * 変数一覧を表示
 *
 * @hotkey [Ctrl]+[Alt]+[Shift]+[F6]
 * @target デフォルト
 */
+^!F6::
    ListVars
Return

/**
 * ホットキー一覧を表示
 *
 * @hotkey [Ctrl]+[Alt]+[Shift]+[F7]
 * @target デフォルト
 */
+^!F7::
    ListHotkeys
Return

/**
 * キーボード・マウス操作履歴を表示
 *
 * @hotkey [Ctrl]+[Alt]+[Shift]+[F8]
 * @target デフォルト
 */
+^!F8::
    KeyHistory
Return

/**
 * Window Spyを表示
 *
 * @hotkey [Ctrl]+[Alt]+[Shift]+[F9]
 * @target デフォルト
 */
+^!F9::
    ;AutoHotkey.exeのパスを取得
    SplitPath, A_AhkPath, vName, vDir, vExt, vNoExt, vDrive

    ;Window Spyを実行
    Run, %vDir%\WindowSpy.ahk
Return
```

### スクリプト編集後の上書き保存([Ctrl]+S)で自動的に再読み込み
のーとぱっどぷらすやらさくらえでぃたやら、そんなんよう使われへんわ、という人は`Window Spy`で`ahk_class`を調べて、AutoHotkeyセクションにあるプログラムグループに追加しましょう。
当然ですが、エディタの上書き保存ボタンなど、[Ctrl]+C以外で保存した場合はリロードされないので注意。

```ini
;[START] テキストエディタ
#IfWinActive, ahk_group GroupTextEditor

/**
 * スクリプトを再読み込み
 *
 * @hotkey [Ctrl]+S
 * @target テキストエディタ(メモ帳/notepad++/サクラエディタ/VS Code)
 */
~^s::
    IfWinActive, %A_ScriptName%
    {
        ;OnExitを無効化
        OnExit

        ;バルーンメッセージを表示
        TrayTip, AutoHotkey, %A_ScriptName% を更新しました。, 10, 17

        Reload
    }
Return
```

### 上部数字キーで半角数字入力
ノートパソコンだとテンキーがないため、上部数字キーを半角数字(テンキーの数字)に置き換えています。

```ini
/**
 * テンキーの数字(半角)
 *
 * @hotkey 数字キー
 * @target デフォルト
 */
1::Send, {Numpad1}
2::Send, {Numpad2}
3::Send, {Numpad3}
4::Send, {Numpad4}
5::Send, {Numpad5}
6::Send, {Numpad6}
7::Send, {Numpad7}
8::Send, {Numpad8}
9::Send, {Numpad9}
0::Send, {Numpad0}
```

### テンキーの入力追加
比較的数字と一緒に入力することの多い[:][,]をテンキーのみで入力可能にします。
[Shift]+テンキーの操作は別のキー操作に置き換わるものがあるので注意。
([Shift]+[NumPadDot]=[NumPadDel]など)

```ini
/**
 * [:]
 *
 * @hotkey [Shift]+[テンキー+]
 * @target デフォルト
 */
+NumpadAdd::Send, :

/**
 * [,]
 *
 * @hotkey [Shift]+[テンキー.]
 * @target デフォルト
 */
NumpadDel::Send, {Shift Up}`,{Shift Down}
```

### 右[Ctrl]+[方向キー]で[PageUp] / [PageDown] / [Home] / [End]
右手だけでページ移動するため。

```ini
/**
 * [PageUp]
 *
 * @hotkey 右[Ctrl]+[↑]
 * @target デフォルト
 */
>^Up::Send, {PgUp}
>^+Up::Send, +{PgUp}
<^>^Up::Send, ^{PgUp}
<^>^+Up::Send, +^{PgUp}

/**
 * [PageDown]
 *
 * @hotkey 右[Ctrl]+[↓]
 * @target デフォルト
 */
>^Down::Send, {PgDn}
>^+Down::Send, +{PgDn}
<^>^Down::Send, ^{PgDn}
<^>^+Down::Send, +^{PgDn}

/**
 * [Home]
 *
 * @hotkey 右[Ctrl]+[←]
 * @target デフォルト
 */
>^Left::Send, {Home}
>^+Left::Send, +{Home}
<^>^Left::Send, ^{Home}
<^>^+Left::Send, +^{Home}

/**
 * [End]
 *
 * @hotkey 右[Ctrl]+[→]
 * @target デフォルト
 */
>^Right::Send, {End}
>^+Right::Send, +{End}
<^>^Right::Send, ^{End}
<^>^+Right::Send, +^{End}
```

### マウス操作
キーボードでマウス操作を可能にします。
クリック操作については通常と`Up`を分けることでドラッグ操作も可能です。

```ini
/**
 * マウスカーソル移動
 *
 * @hotkey 右[Shift]+[↑][↓][←][→]
 * @target デフォルト
 */
>+Up::MouseMove, 0, -10, , R
>+Down::MouseMove, 0, 10, , R
>+Left::MouseMove, -10, 0, , R
>+Right::MouseMove, 10, 0, , R

/**
 * マウスカーソル高速移動
 *
 * @hotkey 右[Shift]+右[Shift]+[↑][↓][←][→]
 * @target デフォルト
 */
<+>+Up::MouseMove, 0, -50, , R
<+>+Down::MouseMove, 0, 50, , R
<+>+Left::MouseMove, -50, 0, , R
<+>+Right::MouseMove, 50, 0, , R

/**
 * マウス左クリック
 *
 * @hotkey 右[Shift]+[Space]
 * @target デフォルト
 */
>+Space::Send, {Click, Left, Down, 0, 0, 1, Relative}
<+>+Space::Send, +{Click, Left, Down, 0, 0, 1, Relative}
<^>+Space::Send, ^{Click, Left, Down, 0, 0, 1, Relative}
!>+Space::Send, !{Click, Left, Down, 0, 0, 1, Relative}
<^<+>+Space::Send, +^{Click, Left, Down, 0, 0, 1, Relative}
!<+>+Space::Send, +!{Click, Left, Down, 0, 0, 1, Relative}
<^!>+Space::Send, ^!{Click, Left, Down, 0, 0, 1, Relative}
<^!<+>+Space::Send, +^!{Click, Left, Down, 0, 0, 1, Relative}

>+Space Up::Send, {Click, Left, Up, 0, 0, 1, Relative}
<+>+Space Up::Send, +{Click, Left, Up, 0, 0, 1, Relative}
<^>+Space Up::Send, ^{Click, Left, Up, 0, 0, 1, Relative}
!>+Space Up::Send, !{Click, Left, Up, 0, 0, 1, Relative}
<^<+>+Space Up::Send, +^{Click, Left, Up, 0, 0, 1, Relative}
!<+>+Space Up::Send, +!{Click, Left, Up, 0, 0, 1, Relative}
<^!>+Space Up::Send, ^!{Click, Left, Up, 0, 0, 1, Relative}
<^!<+>+Space Up::Send, +^!{Click, Left, Up, 0, 0, 1, Relative}

/**
 * マウス右クリック
 *
 * @hotkey 右[Shift]+右[Ctrl][Space]
 * @target デフォルト
 */
>^>+Space::Send, {Click, Right, Down, 0, 0, 1, Relative}
<+>^>+Space::Send, +{Click, Right, Down, 0, 0, 1, Relative}
<^>^>+Space::Send, ^{Click, Right, Down, 0, 0, 1, Relative}
!>^>+Space::Send, !{Click, Right, Down, 0, 0, 1, Relative}
<^<+>^>+Space::Send, +^{Click, Right, Down, 0, 0, 1, Relative}
!<+>^>+Space::Send, +!{Click, Right, Down, 0, 0, 1, Relative}
<^!>^>+Space::Send, ^!{Click, Right, Down, 0, 0, 1, Relative}
<^!<+>^>+Space::Send, +^!{Click, Right, Down, 0, 0, 1, Relative}

>^>+Space Up::Send, {Click, Right, Up, 0, 0, 1, Relative}
<+>^>+Space Up::Send, +{Click, Right, Up, 0, 0, 1, Relative}
<^>^>+Space Up::Send, ^{Click, Right, Up, 0, 0, 1, Relative}
!>^>+Space Up::Send, !{Click, Right, Up, 0, 0, 1, Relative}
<^<+>^>+Space Up::Send, +^{Click, Right, Up, 0, 0, 1, Relative}
!<+>^>+Space Up::Send, +!{Click, Right, Up, 0, 0, 1, Relative}
<^!>^>+Space Up::Send, ^!{Click, Right, Up, 0, 0, 1, Relative}
<^!<+>^>+Space Up::Send, +^!{Click, Right, Up, 0, 0, 1, Relative}
```

### ホットストリング
基本的にはホットストリングに頼らない生活を心掛けていますが、これくらいは登録しておいていいかな、というものと、個人的に絶望的な多さを誇る「くだしあ」「nwe」の打ち間違いだけは自動訂正させたいので。

「くだしあ」「nwe」については、ライブラリ[IME制御]を使用して、IMEがそれぞれオン/オフの時だけ発動させています。
加えて、`*`オプションで終了文字なしで即発動、「くだしあ」の場合はIMEオンでそのままホットストリングを発動させると、平仮名4文字に対してローマ字7文字分が削除されてしまうため、`B0`オプションで入力文字の削除を抑制した上でホットストリング内で[BS]キーを4回送るという動作をさせました。
また、`C`オプションで全部小文字で入力した時のみ発動としています。

IMEオン/オフどちらでも同じように動作させたい場合は、`B0`オプションで入力文字の自動削除を解除した上で、文字数に応じて[BS]キーを送って入力したい文字をクリップボードからペーストするやり方が賢明です。
ただ、IMEオン時の文字数をいちいち数えるのも面倒くさいので、それ用の関数を作成しました。
#### `FormatLine(pStr)`
- 引数
    - `pstr`
        - カウント対象の文字列。
- 戻り値
    - `vStrLen`
        - 現在のIME状態に応じた文字数。

- [ホットストリング \- AutoHotkey Wiki](http://ahkwiki.net/Hotstrings)

```ini
/**
 * 文字列から現在のIME状態に応じた文字数をカウントする。
 *
 * @param {string} pStr カウント対象の文字列。
 * @return {number} vStrLen 現在のIME状態に応じた文字数。
 */
StrLenIME(pStr) {
    ;文字数
    vStrLen := 0

    If (!IME_Get() || IME_GetConvMode() == 0 || IME_GetConvMode() == 16)
    {
        ;IMEオフまたは英字入力モードの場合、引数の文字数をカウント
        vStrLen := StrLen(pStr)
    }
    Else
    {
        ;IMEオンの場合、1文字ずつパースして文字数をカウント
        vCurrentStr := ""

        Loop, Parse, pStr
        {
            vCurrentStr := vCurrentStr . A_LoopField

            If (RegExMatch(A_LoopField, "[\W\d_]"))
            {
                ;アルファベット以外は1文字としてカウント
                vStrLen := vStrLen + StrLen(vCurrentStr)
                vCurrentStr := ""
            }
            Else If (RegExMatch(A_LoopField, "[^aeiou]"))
            {
                ;子音だった場合、nn(ん)以外は現在の文字列を継続利用
                If (RegExMatch(vCurrentStr, "nn$"))
                {
                    ;nn(ん)の場合は1文字としてカウント
                    vStrLen := vStrLen + StrLen(vCurrentStr) - 1
                    vCurrentStr := ""
                }
            }
            Else
            {
                ;母音の場合
                If (strLen(vCurrentStr) == 1)
                {
                    ;母音のみの場合は1文字としてカウント
                    vStrLen := vStrLen + 1
                    vCurrentStr := ""
                }
                Else
                {
                    ;2文字以上の場合
                    If (RegExMatch(vCurrentStr, "ltsu$"))
                    {
                        ;ltsuの4文字は1文字としてカウント
                        vStrLen := vStrLen + StrLen(vCurrentStr) - 3
                        vCurrentStr := ""
                    }
                    Else If (RegExMatch(vCurrentStr, "ja|je|jo|ju$"))
                    {
                        ;ja/je/jo/juの2文字は2文字としてカウント
                        vStrLen := vStrLen + StrLen(vCurrentStr)
                        vCurrentStr := ""
                    }
                    Else If (RegExMatch(vCurrentStr, "chi|shi|tsu|whu|ltu|xtu|ly[aeiou]|xy[aeiou]$"))
                    {
                        ;リストの3文字は1文字としてカウント
                        vStrLen := vStrLen + StrLen(vCurrentStr) - 2
                        vCurrentStr := ""
                    }
                    Else If (RegExMatch(vCurrentStr, "[bcdghjkmnprstz]y[aeiou]|[cds]h[aeou]|dhi$"))
                    {
                        ;リストの3文字は2文字としてカウント
                        vStrLen := vStrLen + StrLen(vCurrentStr) - 1
                        vCurrentStr := ""
                    }
                    Else{
                        ;それ以外(通常の子音+母音)は2文字を1文字としてカウント
                        vStrLen := vStrLen + StrLen(vCurrentStr) - 1
                        vCurrentStr := ""
                    }
                }
            }
        }

        ;残った文字はそのままカウント
        vStrLen := vStrLen + StrLen(vCurrentStr)
    }

    Return vStrLen
}

/**
 * AutoHotkey
 *
 * @hotstr autohotkey
 * @target デフォルト
 */
:*B0K-1Z:autohotkey::
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll

    ;出力文字列を削除
    vStrLen := StrLenIME("autohotkey")
    Send, {BS %vStrLen%}

    ;置換文字列を出力
    Clipboard := "AutoHotkey"
    Send, +{Insert}
    Sleep, 150

    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
Return

/**
 * Debug.console();
 *
 * @hotstr Debug.
 * @target デフォルト
 */
:*B0K-1Z:Debug.::
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll

    ;出力文字列を削除
    vStrLen := StrLenIME("Debug.")
    Send, {BS %vStrLen%}

    ;置換文字列を出力
    Clipboard := "Debug.console();"
    Send, +{Insert}
    Sleep, 100

    ;キャレットを括弧の間に入れる
    Send, {Left 2}

    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
Return

/**
 * console.log();
 *
 * @hotstr console.
 * @target デフォルト
 */
:*B0K-1Z:console.::
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll

    ;出力文字列を削除
    vStrLen := StrLenIME("console.")
    Send, {BS %vStrLen%}

    ;置換文字列を出力
    Clipboard := "console.log();"
    Send, +{Insert}
    Sleep, 100

    ;キャレットを括弧の間に入れる
    Send, {Left 2}

    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
Return

;[START]IMEオン
#If, IME_Get()

/**
 * ください
 *
 * @hotstr kudasia
 * @target デフォルト
 * @condition IMEオン
 */
:*B0CK-1Z:kudasia::{BS 4}ください

#If
;[END]IMEオン

;[START]IMEオフまたは英字入力モード
#If, !IME_Get() || IME_GetConvMode() == 0 || IME_GetConvMode() == 16

/**
 * new
 *
 * @hotstr nwe
 * @target デフォルト
 * @condition IMEオフ/英字入力モード
 */
:*K-1Z:nwe::new

#If
;[END]IMEオフまたは英字入力モード
```

### 未選択状態[Ctrl]+C/[Ctrl]+Xでラインコピー/ラインカット
文字列が未選択の状態で[Ctrl]+C/[Ctrl]+Xを入力した時、その行全体をコピー/カットします。
コピー/カットの実行後、

- `ErrorLevel`が`1`(`ClipWait`がタイムアウト)
- クリップボードが更新されていない(`onClipboardChange`関数の中で判断している)
- キャレットが画面上に存在する**「と見做された」**、

以上3つの条件を全て満たす場合は未選択状態だったと判断しています。
組み込み変数`A_CaretX`/`A_CaretY`がキャレットがなくても数値になることがある(Microsoft Excelのオブジェクト選択時など)ため、完璧なチェックが難しいのが現状。
上記のチェックでだいぶ精度は上がってはいますが、それでも暴発の可能性は否定しきれないです。ダメな場合は別のキーに割り当てるなどして対処してください。

```ini
/**
 * ラインカット
 *
 * @hotkey [Ctrl]+X
 * @target デフォルト
 * @condition 文字列未選択
 */

/**
 * ラインコピー
 *
 * @hotkey [Ctrl]+C
 * @target デフォルト
 * @condition 文字列未選択
 */
^c::
^x::
    ;実行されたホットキーを記録
    vHotkey := A_ThisHotkey

    ;クリップボード変更フラグをFalseにする
    gClipboardChange := False

    ;クリップボードを空にする時にNoticeClipboard関数を動作させない
    OnClipboardChange("NoticeClipboard", 0)
    Clipboard := ""
    OnClipboardChange("NoticeClipboard", 1)

    ;コピー/カットを実行
    Send, %vHotkey%
    ClipWait, 0.2

    If (!gClipboardChange && ErrorLevel && A_CaretX != "" && A_CaretY != "")
    {
        ;クリップボード変更とテキストコピーがされず、かつキャレットが表示されている場合はラインコピー/ラインカット
        Send, {Home}+{End}
        Send, %vHotkey%
    }

    ;クリップボード変更フラグをFalseにする
    gClipboardChange := False
Return
```

### [Ctrl]+[Alt]/[Shift]+Vで選択した複数行を整形して貼り付け
[Ctrl]+[Alt]+Vで行頭に「> 」を付けて貼り付け、[Ctrl]+[Shift]+Vで行頭行末の全角半角スペースとタブをトリムして貼り付け、[Ctrl]+[Alt]+[Shift]+Vだとその両方。
`FormatLine`という関数を作り、各ショートカットから呼ぶようにしてあります。

#### `FormatLine(pText[, pBulletChar][, pTrim])`
- 引数
    - `pText`
        - 整形対象のテキスト。
    - `pBulletChar`
        - 行頭に付与する文字。
        - 省略時は何も付与しない。
    - `pTrim`
        - 行頭行末の空白をトリムするかどうか。
        - `True`/`False`、`0`以外/`0`で指定。
        - 省略時はトリムしない。
- 戻り値
    - なし

```ini
/**
 * 文字列をの左右トリムと行頭文字の付与して貼り付けを行う。
 *
 * @param {String} pText フォーマット対象テキスト。
 * @param {String} pBulletChar 行頭文字。省略時は付与しない。
 * @param {Boolean} pTrim 文字列の左右トリムを行うかどうか。省略時は行わない。
 */
FormatLine(pText, pBulletChar="", pTrim=False) {
    If (Clipboard != "")
    {
        ;クリップボードが空でない場合
        OnClipboardChange("NoticeClipboard", 0)
        vClipboardAll := ClipboardAll
        vResult := ""

        ;改行コード単位でループ
        Loop, Parse, pText, `n, `r
        {
            vLoopField := A_LoopField
            vLastLine := A_LoopField
            {
                If (pTrim)
                {
                    ;トリムフラグがTrueの場合、左右の空白とタブを削除
                    vLoopField := Trim(A_LoopField, " 　`t")
                }

                ;行頭文字を付与し、改行コードを設定
                vResult := vResult . pBulletChar . vLoopField . "`r`n"
            }
        }
        If (vResult != "")
        {
            ;改行コードがありループした場合
            If (vLastLine == "")
            {
                ;最終行が空白だった場合、最後の行頭文字と改行コードを削除
                vResult := SubStr(vResult, 1, -(StrLen(pBulletChar) + 2))
            }
        }
        Else
        {
            ;改行コードがなくループしなかった場合
            If (pTrim){
                ;トリムフラグがTrueの場合、左右の空白とタブを削除
                pText := Trim(pText, " 　`t")
            }

            ;行頭文字を付与
            vResult := pBulletChar . pText
        }

        ;貼り付けを実行
        Clipboard := vResult
        Send, +{Insert}
        Sleep, 100

        Clipboard := vClipboardAll
        OnClipboardChange("NoticeClipboard", 1)
    }
    Else
    {
        ;クリップボードが空だった場合、ホットキーをそのまま実行
        Send, %A_ThisHotKey%
    }
}

/**
 * 先頭に"> "を付けてペースト
 *
 * @hotkey [Ctrl]+[Shift]+V
 * @target デフォルト
 */
+^v::
    FormatLine(Clipboard, "> ", False)
Return

/**
 * 空白をトリムしてペースト
 *
 * @hotkey [Ctrl]+[Alt]+[Shift]+V
 * @target デフォルト
 */
^!v::
    FormatLine(Clipboard, "", True)
Return

/**
 * 空白をトリムし先頭に"> "を付けてペースト
 *
 * @hotkey [Ctrl]+[Alt]+[Shift]+V
 * @target デフォルト
 */
+^!v::
    FormatLine(Clipboard, "> ", True)
Return
```

### [変換]+[Space]でIMEオフで入力したアルファベットを再変換
カーソルの直前にあるアルファベットを再変換します。

```ini
/**
 * IMEオフで入力した直前の文字を再変換
 *
 * @hotkey [Ctrl]+[Space]
 * @target デフォルト
 */
^Space::
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll
    vClipboard := ""

    ;再変換実行フラグ
    vReConvFlg := True

    ;初回もしくはクリップボードが更新された場合は処理を継続
    While (vClipboard != Clipboard || vClipboard == "")
    {
        vClipboard := Clipboard
        Clipboard := ""

        ;キャレットの左1文字を追加取得
        Send, +{Left}
        Send, ^{Insert}
        ClipWait, 0.2

        vStrLen := StrLen(Clipboard)

        If (vStrLen == 0)
        {
            ;取得文字が0文字だった場合、再変換を実行しない
            vReConvFlg := False
            Break
        }
        Else If (RegExMatch(Clipboard, "[^0-9a-zA-Z\-\~]"))
        {
            ;取得した文字列に英数文字,-,~以外が含まれていた場合、この回でループを終了
            If (vStrLen == 1 || (vStrLen == 2 && RegExMatch(Clipboard, "[\r\n]")))
            {
                ;取得文字が1文字、または2文字で改行コード(CR+LF)だった場合、再変換を実行しない
                vReConvFlg := False

                ;キャレット位置を元に戻す
                Send, {Right}
            }
            Else
            {
                ;取得文字が3文字以上、または2文字で改行コード(CR+LF)以外だった場合、1文字前まで選択
                Send, +{Right}
                Clipboard := ""
                Send, ^{Insert}
                ClipWait, 0.2
            }
            Break
        }
        Else
        {
            ;取得した文字列が全て英数文字,-,~だった場合、左側を単語単位で取得してループを継続
            Send, +{Right}+^{Left}
        }

        ;クリップボードを取得範囲で更新してループを継続
        Clipboard := ""
        Send, ^{Insert}
        ClipWait, 0.2
    }

    If (vReConvFlg)
    {
        ;再変換実行フラグがTrueの場合、IMEをオンにして取得した範囲を入力
        IME_Set(1)
        Send, %Clipboard%
    }

    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
Return
```

### [Alt]+[変換]で文字種変換
e, é, è, ê, ëなど、[Alt]+[変換]キーを押す毎にキャレット直前の文字を変換します。
冒頭の変数`cCode`に、変換候補になる文字を変換前の文字挟んで設定しています。
(cf. **e**éèêë**e**)
注意点として、同じ変換候補を複数の変換前文字に設定することはできません。
2回目以降の[Alt]+[CapsLock]キー押下で見つかるのは必ず最初に設定された箇所になってしまうため、それ以降の変換は最初に設定された文字に移ってしまうからです。
(cf. **い**ゐ*井***い****イ**ヰ*井***イ**)
上記の例だと、「イ」で[Alt]+[変換]キーを押すと、「ヰ」→「井」と変換された後、「い」→「ゐ」→「井」→「い」……と、前の変換候補ループに入ってしまいます。

```ini
/**
 * 直前の文字を別種文字に変換
 *
 * @hotkey [Alt]+[変換]
 * @target デフォルト
 */
Alt & sc079::
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll
    Clipboard := ""

    ;変換対象文字(同じ文字で囲まれた間の文字をループして変換)
    cCode := ""
    cCode := cCode . "AÁÀÂÄÆÃÅAaáàâäæãåabßbCÇCcçcEÉÈÊËEeéèêëeIÏÍÌÎIiïîíìiNÑNnñnOÔŒÖÓÒÕOoôœöóòõoUÚÙÛÜUuúùûüu"
    cCode := cCode . "!¡!?¿?$€₣£$"
    cCode := cCode . "いイゐヰいえエゑヱえかカヵヶか"
    cCode := cCode . "-‐―－￣＿-<«<＜≦≪〈《＜>»>＞≧≫〉》＞[{[]}]「『【［｛〔「」』】］｝〕」"
    cCode := cCode . "0０零⑩Ⅹⅹ十拾⑳01１①Ⅰⅰ一壱⑪12２②Ⅱⅱ二弐⑫23３③Ⅲⅲ三参⑬34４④Ⅳⅳ四肆⑭45５⑤Ⅴⅴ五伍⑮56６⑥Ⅵⅵ六陸⑯67７⑦Ⅶⅶ七漆⑰78８⑧Ⅷⅷ八捌⑱89９⑨Ⅸⅸ九玖⑲9"

    If (A_CaretX != "" && A_CaretY != "")
    {
        ;キャレットが認識できた場合、ツールチップ表示位置をキャレットの下に設定
        vCaretX := A_CaretX
        vCaretY := A_CaretY + 20
    }
    Else
    {
        ;キャレットが認識できなかった場合、ツールチップ表示位置をウィンドウ左下に設定
        WinGetPos, vX, vY, , vHeight, A
        vCaretX := vX
        vCaretY := vY + vHeight - 58
    }

    ;1文字前をコピー
    Send, {Left}+{Right}^{Insert}
    ClipWait, 0.2

    ;選択を解除
    Send, {Left}{Right}

    ;取得した文字の変換対象文字内での位置を取得
    vCodeNum := InStr(cCode, Clipboard, True)

    If (vCodeNum != 0 && StrLen(Clipboard) == 1)
    {
        ;取得した文字が変換対象文字に存在しており、かつ取得文字数が1文字の場合、次の変換対象を取得
        vOutCode := SubStr(cCode, vCodeNum + 1, 1)
        vCodeNum := InStr(cCode, vOutCode, True)
        vNextCode := SubStr(cCode, vCodeNum + 1, 1)

        ;スプラッシュイメージをキャレット位置に表示し、1000ミリ秒後に消去するタイマーをセット
        SplashImage, , B FM20 FS12 W50 X%vCaretX% Y%vCaretY%, %vNextCode%, %vOutCode%
        SetTimer, RemoveSplashImage, 1000

        If (WinActive("ahk_class OpusApp"))
        {
            ;Microsoft Wordの場合
            ;IME状態を取得
            vIME := IME_Get()

            ;前の文字を削除して変換後文字をエスケープ後に出力
            vOutCode := EscapeSend(vOutCode)
            Send, {BS}%vOutCode%

            ;IME状態を復元
            IME_Set(vIME)
        }
        Else
        {
            ;Microsoft Word以外の場合、前の文字を削除して変換後文字を貼り付け
            Clipboard := vOutCode
            Send, {BS}+{Insert}
            Sleep, 100
        }
    }
    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
Return

/**
 * タイマーをオフにし、スプラッシュイメージを消去する。
 */
RemoveSplashImage:
    SetTimer, RemoveSplashImage, Off
    SplashImage, Off
Return
```

### 日付/時刻の入力
Microsoft Excelのショートカットにある`[Ctrl]+;`現在日付入力と`[Ctrl]+:`現在時刻入力を他でも使えるようにします。
最初は`yyyyMMdd`形式と`hh:MM:dd`のみにしていましたが、慾が出てきてホットキーを送るたびに`yyyyMMdd`→`yyyy/MM/dd`→`yyyy年MM月dd日`...みたいにフォーマットを変更していくように改良しました。`MMdd`形式にも対応。
アホみたいに長い日付の正規表現については、[yyyy\(\-mm\(\-dd\)?\)?形式の年月日文字列の正規表現 \- Qiita](https://qiita.com/plasma0713/items/6f1b8172080bbc13ebc4)を参考に。
ぶっちゃけ`[0-9]{4}(0[1-9]|1[0-2])(([0-2][0-9])|3[0-1])`程度でいいと思うよ。

- [RegExMatch\(\) \- AutoHotkey Wiki](http://ahkwiki.net/RegExMatch)
- [RegExReplace\(\) \- AutoHotkey Wiki](http://ahkwiki.net/RegExReplace)
- [正規表現 \- AutoHotkey Wiki](http://ahkwiki.net/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE)

なお、`:`はホットキーを表す記号に使われているので、ホットキーを設定する時に`:::`とは書けません。
`:`,`;`にホットキーを設定する場合はキーコード`sc028`,`sc027`を使い、`::sc028`,`sc027::`とします。

```ini
/**
 * 現在日付を入力
 *
 * @hotkey [Ctrl]+;
 * @target デフォルト
 */
^sc027::
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll
    Clipboard := ""

    vResult := ""

    ;選択文字列をコピー
    Send, ^{Insert}
    ClipWait

    If (Clipboard != "")
    {
        ;文字列が選択されている場合

        ;yyyyMMdd形式を表す正規表現
        cYYYYMMDD := "^(?!([02468][1235679]|[13579][01345789])000229)(([0-9]{4}(01|03|05|07|08|10|12)(0[1-9]|[12][0-9]|3[01]))|([0-9]{4}(04|06|09|11)(0[1-9]|[12][0-9]|30))|([0-9]{4}02(0[1-9]|1[0-9]|2[0-8]))|([0-9]{2}([02468][048]|[13579][26])0229))$"
        ;yyyy/MM/dd形式を表す正規表現
        cYYYYMMDDs := "^(?!([02468][1235679]|[13579][01345789])00\/02\/29)(([0-9]{4}\/(01|03|05|07|08|10|12)\/(0[1-9]|[12][0-9]|3[01]))|([0-9]{4}\/(04|06|09|11)\/(0[1-9]|[12][0-9]|30))|([0-9]{4}\/02\/(0[1-9]|1[0-9]|2[0-8]))|([0-9]{2}([02468][048]|[13579][26])\/02\/29))$"
        ;yyyy-MM-dd形式を表す正規表現
        cYYYYMMDDh := "^(?!([02468][1235679]|[13579][01345789])00-02-29)(([0-9]{4}-(01|03|05|07|08|10|12)-(0[1-9]|[12][0-9]|3[01]))|([0-9]{4}-(04|06|09|11)-(0[1-9]|[12][0-9]|30))|([0-9]{4}-02-(0[1-9]|1[0-9]|2[0-8]))|([0-9]{2}([02468][048]|[13579][26])-02-29))$"
        ;yyyy年MM月dd日形式を表す正規表現
        cYYYYMMDDj := "^(?!([02468][1235679]|[13579][01345789])00年02月29日)(([0-9]{4}年(01|03|05|07|08|10|12)月(0[1-9]|[12][0-9]|3[01])日)|([0-9]{4}年(04|06|09|11)月(0[1-9]|[12][0-9]|30)日)|([0-9]{4}年02月(0[1-9]|1[0-9]|2[0-8])日)|([0-9]{2}([02468][048]|[13579][26])年02月29日))$"
        ;yyyy年MM月dd日(ddd)形式を表す正規表現
        cYYYYMMDDd := "^(?!([02468][1235679]|[13579][01345789])00年02月29日)(([0-9]{4}年(01|03|05|07|08|10|12)月(0[1-9]|[12][0-9]|3[01])日)|([0-9]{4}年(04|06|09|11)月(0[1-9]|[12][0-9]|30)日)|([0-9]{4}年02月(0[1-9]|1[0-9]|2[0-8])日)|([0-9]{2}([02468][048]|[13579][26])年02月29日))\([日月火水木金土]\)$"
        ;MMdd形式を表す正規表現
        cMMDD := "((01|03|05|07|08|10|12)(0[1-9]|[12][0-9]|3[01])|(04|06|09|11)(0[1-9]|[12][0-9]|30)|(02)(0[1-9]|[12][0-9]))$"
        ;MM/dd,M/d形式を表す正規表現
        cMMDDs := "((0?1|0?3|0?5|0?7|0?8|10|12)\/(0?[1-9]|[12][0-9]|3[01])|(0?4|0?6|0?9|11)\/(0?[1-9]|[12][0-9]|30)|(0?2)\/(0?[1-9]|[12][0-9]))$"
        ;MM-dd,M-d形式を表す正規表現
        cMMDDh := "((0?1|0?3|0?5|0?7|0?8|10|12)-(0?[1-9]|[12][0-9]|3[01])|(0?4|0?6|0?9|11)-(0?[1-9]|[12][0-9]|30)|(0?2)-(0?[1-9]|[12][0-9]))$"
        ;MM月dd日,M月d日形式を表す正規表現
        cMMDDj := "((0?1|0?3|0?5|0?7|0?8|10|12)月(0?[1-9]|[12][0-9]|3[01])日|(0?4|0?6|0?9|11)月(0?[1-9]|[12][0-9]|30)日|(0?2)月(0?[1-9]|[12][0-9])日)$"
        ;MM月dd日(ddd),M月d日(ddd)形式を表す正規表現
        cMMDDd := "((0?1|0?3|0?5|0?7|0?8|10|12)月(0?[1-9]|[12][0-9]|3[01])日|(0?4|0?6|0?9|11)月(0?[1-9]|[12][0-9]|30)日|(0?2)月(0?[1-9]|[12][0-9])日)\([日月火水木金土]\)$"

        ;クリップボード文字列から数値以外を削除
        vResult := RegExReplace(Clipboard, "\D", "")

        If (RegExMatch(Clipboard, cYYYYMMDD))
        {
            ;クリップボード文字列がyyyyMMdd形式の場合、yyyy/MM/dd形式に変換
            FormatTime, vResult, %vResult%, yyyy/MM/dd
        }
        Else If (RegExMatch(Clipboard, cYYYYMMDDs))
        {
            ;クリップボード文字列がyyyy/MM/dd形式の場合、yyyy-MM-dd形式に変換
            FormatTime, vResult, %vResult%, yyyy-MM-dd
        }
        Else If (RegExMatch(Clipboard, cYYYYMMDDh))
        {
            ;クリップボード文字列がyyyy-MM-dd形式の場合、yyyy年MM月dd日形式に変換
            FormatTime, vResult, %vResult%, yyyy年MM月dd日
        }
        Else If (RegExMatch(Clipboard, cYYYYMMDDj))
        {
            ;クリップボード文字列がyyyy年MM月dd日形式の場合、yyyy年MM月dd日(ddd)形式に変換
            FormatTime, vResult, %vResult%, yyyy年MM月dd日(ddd)
        }
        Else If (RegExMatch(Clipboard, cYYYYMMDDd))
        {
            ;クリップボード文字列がyyyy年MM月dd日(ddd)形式の場合、yyyyMMdd形式に変換
            FormatTime, vResult, %vResult%, yyyyMMdd
        }
        Else If (RegExMatch(Clipboard, cMMDD))
        {
            ;クリップボード文字列がMMdd形式の場合MM/DD形式に変換
            FormatTime, vResult, 2000%vResult%, MM/dd
        }
        Else If (RegExMatch(Clipboard, cMMDDs))
        {
            ;クリップボード文字列がMM/dd形式の場合
            If (RegExMatch(vResult, "(0\d{3})|(\d{2}0\d)"))
            {
                ;月日のいずれかが1桁の場合、M/d形式に変換
                FormatTime, vResult, 2000%vResult%, M/d
            }
            Else
            {
                ;月日がどちらも2桁またはM/d形式の場合、MM-dd形式に変換
                vMonth := SubStr("0" . SubStr(Clipboard, 1, InStr(Clipboard, "/") - 1), -1, 2)
                vDay := SubStr("0" . SubStr(Clipboard, InStr(Clipboard, "/") + 1), -1, 2)
                FormatTime, vResult, 2000%vMonth%%vDay%, MM-dd
            }
        }
        Else If (RegExMatch(Clipboard, cMMDDh))
        {
            If (RegExMatch(vResult, "(0\d{3})|(\d{2}0\d)"))
            {
                ;月日のいずれかが1桁の場合、M-d形式に変換
                FormatTime, vResult, 2000%vResult%, M-d
            }
            Else
            {
                ;月日がどちらも2桁またはM-d形式の場合、MM月dd日形式に変換
                vMonth := SubStr("0" . SubStr(Clipboard, 1, InStr(Clipboard, "-") - 1), -1, 2)
                vDay := SubStr("0" . SubStr(Clipboard, InStr(Clipboard, "-") + 1), -1, 2)
                FormatTime, vResult, 2000%vMonth%%vDay%, MM月dd日
            }
        }
        Else If (RegExMatch(Clipboard, cMMDDj))
        {
            ;クリップボード文字列がMM月dd日形式の場合
            If (RegExMatch(vResult, "(0\d{3})|(\d{2}0\d)"))
            {
                ;月日のいずれかが1桁の場合、M月d日形式に変換
                FormatTime, vResult, 2000%vResult%, M月d日
            }
            Else
            {
                ;月日がどちらも2桁またはM月d日形式の場合、MM月dd日(ddd)形式に変換
                vMonth := SubStr("0" . SubStr(Clipboard, 1, InStr(Clipboard, "月") - 1), -1, 2)
                vDay := SubStr("0" . SubStr(Clipboard, InStr(Clipboard, "月") + 1, InStr(Clipboard, "日") - InStr(Clipboard, "月") - 1), -1, 2)
                FormatTime, vResult, 2000%vMonth%%vDay%, MM月dd日(ddd)
            }
        }
        Else If (RegExMatch(Clipboard, cMMDDd))
        {
            ;クリップボード文字列がMM月dd日(ddd)形式の場合
            If (RegExMatch(vResult, "(0\d{3})|(\d{2}0\d)"))
                ;月日のいずれかが1桁の場合、Md(ddd)形式に変換
                FormatTime, vResult, 2000%vResult%, M月d日(ddd)
            Else
            {
                ;月日がどちらも2桁またはM月d日(ddd)形式の場合、MMdd形式に変換
                vMonth := SubStr("0" . SubStr(Clipboard, 1, InStr(Clipboard, "月") - 1), -1, 2)
                vDay := SubStr("0" . SubStr(Clipboard, InStr(Clipboard, "月") + 1, InStr(Clipboard, "日") - InStr(Clipboard, "月") - 1), -1, 2)
                FormatTime, vResult, 2000%vMonth%%vDay%, MMdd
            }
        }
        Else
        {
            ;いずれのフォーマットでもない場合、本日日付をyyyyMMdd形式で出力
            FormatTime, vResult, ,yyyyMMdd
        }
    }
    Else
    {
        ;文字列が選択されていない場合、本日日付をyyyyMMdd形式で出力
        FormatTime, vResult, ,yyyyMMdd
    }

    ;出力文字列を貼り付けて選択状態にする
    vStrLen := StrLen(vResult)
    Clipboard := vResult
    Send, +{Insert}
    Sleep, 150
    Send, +{Left %vStrLen%}

    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
Return
```

### 括弧で括る
[無変換]キーとの組み合わせで、選択範囲を括弧で括るショートカットキーです。
`EncloseBrackets`という関数を作り、各ショートカットキーから呼ぶようにしました。
ホットキー押下時のIMEがオンで、`pOpenStrIME`/`pCloseStrIME`のどちらかが指定されている場合は引数`pOpenStrIME`と`pCloseStrIME`で、それ以外の場合は`pOpenStr`と`pCloseStr`で選択中の文字列を括ります。文字列が選択されていない場合は何もしません。
ついでに[無変換]+カンマには数値のみだったら3桁カンマ区切りにする機能も持たせました。こちらも連続ホットキーでカンマあり→カンマなしをトグルします。
なお、これらの設定のみだと[無変換]キー単独での使用ができなくなってしまうため、[無変換]キー単独のホットキーを用意し、[無変換]をそのまま送るように設定しておく必要があります。

#### `EncloseBrackets([pOpenStr][, pCloseStr][, pOpenStrIME][, pCloseStrIME])`
- 引数
    - `pOpenStr`
        - 開括弧に使用する文字。
        - 省略時は何も設定されない。
    - `pCloseStr`
        - 閉括弧に使用する文字。
        - 省略時は何も設定されない。
    - `pOpenStrIME`
        - IMEオンの時、開括弧に使用する文字。
        - 省略時は何も設定されない。
    - `pCloseStrIME`
        - IMEオンの時、閉括弧に使用する文字。
        - 省略時は何も設定されない。
- 戻り値
    - なし 

注意点として、サクラエディタなど一部アプリでは未選択状態での[Ctrl]+Cが行単位でのコピーとなっている場合があり、未選択時に`EncloseBracets`関数から[Ctrl]+Cを送信すると意図しない挙動になってしまいます。
その場合はアプリ側の設定を変更するなどして対応してください。
サクラエディタの場合、以下に設定があります。

- 設定 - 共通設定
   - [編集]タブ - [コピー]カテゴリ
      - 「選択なしでコピーを可能にする」チェックボックスをオフ

```ini
/**
 * 選択文字列を指定された括弧で括る。
 *
 * @param {String} pOpenStr IMEオフ、またはIMEオン時の設定がない場合の開括弧。
 * @param {String} pCloseStr IMEオフ、またはIMEオン時の設定がない場合の閉括弧。
 * @param {String} pOpenStrIME IMEオン時の開括弧。省略時は空白。
 * @param {String} pCloseStrIME IMEオン時の閉括弧。省略時は空白。
 */
EncloseBrackets(pOpenStr, pCloseStr, pOpenStrIME="", pCloseStrIME="") {
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll
    Clipboard := ""

    ;選択文字列をコピー
    Send, ^{Insert}
    ClipWait, 0.2

    If (Clipboard != "")
    {
        ;クリップボードが空でない場合
        If (IME_Get() && (pOpenStrIME != "" || pCloseStrIME != ""))
        {
            ;IMEがオン、かつpOpenStrIME,pCloseStrIMEのいずれかが設定されている場合、pOpenStrIME,pCloseStrIMEで括る
            Clipboard := pOpenStrIME . Clipboard . pCloseStrIME
        }
        Else
        {
            ;IMEがオフ、またはpOpenStrIME,pCloseStrIMEのいずれも設定されていない場合、pOpenStr,pCloseStrで括る
            Clipboard := pOpenStr . Clipboard . pCloseStr
        }

        ;出力文字列を貼り付け
        Send, +{Insert}
        Sleep, 100
    }

    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
}

;[無変換]のみの場合は[無変換]キーを送信
sc07B::
    Send, {sc07B}
Return

/**
 * 選択文字列を""で括る
 *
 * @hotkey [無変換]+2
 * @target デフォルト
 */
sc07B & 2::
    EncloseBrackets("""", """", "", "")
Return

/**
 * 選択文字列を$$で括る
 *
 * @hotkey [無変換]+4
 * @target デフォルト
 */
sc07B & 4::
    EncloseBrackets("$", "$", "", "")
Return

/**
 * 選択文字列を%%で括る
 *
 * @hotkey [無変換]+5
 * @target デフォルト
 */
sc07B & 5::
    EncloseBrackets("%", "%", "", "")
Return

/**
 * 選択文字列を''で括る
 *
 * @hotkey [無変換]+7
 * @target デフォルト
 */
sc07B & 7::
    EncloseBrackets("'", "'", "", "")
Return

/**
 * 選択文字列を()で括る
 *
 * @hotkey [無変換]+8
 * @target デフォルト
 */
sc07B & 8::
    EncloseBrackets("(", ")", "", "")
Return

/**
 * 選択文字列を()で括る
 *
 * @hotkey [無変換]+9
 * @target デフォルト
 * @condition IMEオフ
 */

/**
 * 選択文字列を（）で括る
 *
 * @hotkey [無変換]+9
 * @target デフォルト
 * @condition IMEオン
 */
sc07B & 9::
    EncloseBrackets("(", ")", "（", "）")
Return

/**
 * 選択文字列を``で括る
 *
 * @hotkey [無変換]+@
 * @target デフォルト
 */
sc07B & @::
    EncloseBrackets("``", "``", "", "")
Return

/**
 * 選択文字列を[]で括る
 *
 * @hotkey [無変換]+[
 * @target デフォルト
 * @condition IMEオフ
 */

/**
 * 選択文字列を「」で括る
 *
 * @hotkey [無変換]+[
 * @target デフォルト
 * @condition IMEオン
 */
sc07B & [::
    EncloseBrackets("[", "]", "「", "」")
Return

/**
 * 選択文字列を{}で括る
 *
 * @hotkey [無変換]+]
 * @target デフォルト
 * @condition IMEオフ
 */

/**
 * 選択文字列を『』で括る
 *
 * @hotkey [無変換]+]
 * @target デフォルト
 * @condition IMEオン
 */
sc07B & ]::
    EncloseBrackets("{", "}", "『", "』")
Return

;[無変換]+,で数値を3桁カンマ区切り、文字列を<>で括る(IME考慮)
/**
 * 選択文字列を3桁カンマ区切りにする
 *
 * @hotkey [無変換]+,
 * @target デフォルト
 * @condition 半角数値選択
 */

/**
 * 選択文字列を<>で括る
 *
 * @hotkey [無変換]+,
 * @target デフォルト
 * @condition IMEオフ
 */

/**
 * 選択文字列を＜＞で括る
 *
 * @hotkey [無変換]+,
 * @target デフォルト
 * @condition IMEオン
 */
sc07B & ,::
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll
    Clipboard := ""

    ;選択文字列をコピー
    Send, ^{Insert}
    ClipWait, 0.2

    If (RegExMatch(Clipboard, "^\d+$"))
    {
        ;選択文字列が半角数値のみの場合、3桁ずつ,で区切る
        Clipboard := RegExReplace(Clipboard, "\B(?=(\d{3})+(?!\d))", ",", ALL)
        vStrLen := StrLen(Clipboard)

        ;出力文字列を貼り付けて選択状態にする
        vStrLen := StrLen(Clipboard)
        Send, +{Insert}
        Send, +{Left %vStrLen%}
        Sleep, 100
    }
    Else If (RegExMatch(Clipboard, "(\d)(?=(,\d{3})+$)"))
    {
       ;選択文字列が3桁区切り半角数値の場合、,を除外して半角数値のみにする
        Clipboard := RegExReplace(Clipboard, ",", "", ALL)

        ;出力文字列を貼り付けて選択状態にする
        vStrLen := StrLen(Clipboard)
        Send, +{Insert}
        Send, +{Left %vStrLen%}
        Sleep, 100
    }
    Else
    {
        ;選択文字列が半角数値以外を含む場合、<>で括る(IME考慮)
        EncloseBrackets("<", ">", "＜", "＞")
        OnClipboardChange("NoticeClipboard", 0)
    }

    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
Return

/**
 * 選択文字列を<>で括る
 *
 * @hotkey [無変換]+.
 * @target デフォルト
 * @condition IMEオフ
 */

/**
 * 選択文字列を＜＞で括る
 *
 * @hotkey [無変換]+.
 * @target デフォルト
 * @condition IMEオン
 */
sc07B & .::
    EncloseBrackets("<", ">", "＜", "＞")
Return

/**
 * 選択文字列を\\で括る
 *
 * @hotkey [無変換]+\
 * @target デフォルト
 * @condition IMEオフ
 */

/**
 * 選択文字列を【】で括る
 *
 * @hotkey [無変換]+\
 * @target デフォルト
 * @condition IMEオン
 */
sc07B & sc073::
    EncloseBrackets("`\", "`\", "【", "】")
Return
```

### 括弧を自動で閉じる
対象となる文字は、ダブルクォート`""`、小括弧`()`、ブラケット`[]`、カーリーブラケット`{}`、およびその日本語入力文字。
アポストロフィ`''`、バッククォート``` `` ```、不等号`<>`は、括弧以外の用途で使うことも多いため対象外にしました。
関数`AutoCloseBracket`は、開括弧キーを押した後0.3秒以内に閉括弧が入力された場合はそのまま、それ以外の文字が入力されたり0.3秒を経過した場合は入力された文字を括弧で括って出力しています。
引数で渡された文字は、`EscapeStr`関数でエスケープして使用します。
エスケープの仕様については以下を参照してください。

- [\#EscapeChar \- AutoHotkey Wiki](http://ahkwiki.net/-EscapeChar)


#### `AutoCloseBracket(pOpenStr, pCloseStr)`
- 引数
    - `pOpenStr`
        - 開括弧に使用する文字
    - `pCloseStr`
        - 閉括弧に使用する文字
- 戻り値
    - なし 

#### `EscapeStr(pStr)`
- 引数
    - `pStr`
        - エスケープ対象文字
- 戻り値
    - エスケープ後の文字

Excelでは関数やセル範囲指定の編集時に暴発して邪魔になるため、`#IfWinNotActive`で条件を付けて除外しています。
`ahk_class`ではなく`ahk_exe`を指定しているのは、条件付き書式のダイアログボックスなどExcel内の各種サブウィンドウ上でも無効化したいためです。

- [IfWinActive / IfWinNotActive \- AutoHotkey Wiki](http://ahkwiki.net/IfWinActive_/_IfWinNotActive)
- [ディレクティブの基礎知識 \- AutoHotkey Wiki](http://ahkwiki.net/Directives)

そのままだと同じ文字を2回入力した時に、2回目の入力もホットキー受付として処理されてしまい、入力を取得できません。
このため、`Input`コマンドで2回目の入力を取得できるように、まず最初に`Hotkey`コマンドで一時的にホットキーをオフにすることで入力をキー入力として受け付け、最後に再びオンに戻すという方法を採っています。
ただ、`#IfWinActive`などで条件指定されたブロックにあるホットキーをオンにしようとすると何故か条件を満たしているのにエラーとなってしまうため、`Hotkey`コマンドのオプションで`UseErrorLevel`を指定し、エラー時にも処理が流れるようにしてあります。
`ErrorLevel`上はエラーが発生していても`Hotkey`コマンドは正しく処理されます。

- [Hotkey, KeyName \[, Label, Options\]](http://ahkwiki.net/Hotkey)

```ini
/**
 * 開括弧・閉括弧を自動的に入力する。
 *
 * @param {String} pOpenStr 開括弧。
 * @param {String} pCloseStr 閉括弧。
 */
AutoCloseBracket(pOpenStr, pCloseStr) {
    ;入力されたホットキーを一時的に停止する
    vHotkey := A_ThisHotKey
    Hotkey, %vHotkey%, Off, UseErrorLevel

    ;閉括弧の入力を300ミリ秒待機
    Input, vOutput, I T0.3 L1, %pCloseStr%

    ;開括弧・閉括弧をSendコマンド用にエスケープ
    pOpenStr := EscapeSend(pOpenStr)
    pCloseStr := EscapeSend(pCloseStr)

    If ErrorLevel In EndKey:%pCloseStr%,Timeout
    {
        ;入力されたキーが閉括弧またはタイムアウトした場合、開括弧・閉括弧を出力し、キャレットを括弧に入れる
        Send, %pOpenStr%%pCloseStr%
        Send, {Left}
    }
    Else
    {
        ;入力されたキーが閉括弧以外の場合、開括弧・閉括弧で括って出力し、キャレットを括弧に入れる
        Send, %pOpenStr%%vOutput%%pCloseStr%
        Send, {Left}
    }

    ;停止したホットキーを実行可能にする
    Hotkey, %vHotkey%, On, UseErrorLevel
}

/**
 * 対象文字列をSendコマンド用にエスケープする。
 *
 * @param {String} pStr エスケープ対象文字列。
 * @return {String} pStr エスケープ後の文字列。
 */
EscapeSend(pStr) {
    ;`でエスケープする文字(,%;`)
    pStr := RegExReplace(pStr, "([,%;`])", "`$1")
    ;{}で囲ってエスケープする文字({}+^!#)
    pStr := RegExReplace(pStr, "([\{\}+^!#])", "{$1}")

    Return pStr
}

;[START] Microsoft Excel以外
#IfWinNotActive, ahk_exe EXCEL.EXE

/**
 * ""を自動入力する
 *
 * @hotkey "
 * @target Microsoft Excel以外
 */
+2::
    AutoCloseBracket("""", """")
Return

/**
 * ()を自動入力する
 *
 * @hotkey (
 * @target Microsoft Excel以外
 */
+8::
    AutoCloseBracket("(", ")")
Return

/**
 * []を自動入力する
 *
 * @hotkey [
 * @target Microsoft Excel以外
 */
[::
    AutoCloseBracket("[", "]")
Return

/**
 * {}を自動入力する
 *
 * @hotkey {
 * @target Microsoft Excel以外
 */
+[::
    AutoCloseBracket("{", "}")
Return

#IfWinNotActive
;[End] Microsoft Excel以外
```

### [App]キー/[Win]キー
細かい説明は省略しますので、ソースをご覧ください。

```ini

/**
 * アプリケーションのインストールディレクトリを開く
 *
 * @hotkey [Apps]+D
 * @target デフォルト
 */
AppsKey & d::
    ;ファイラのパス(省略時はエクスプローラ)
    cFilerpath := ""

    ;アクティブウィンドウのフルパスからディレクトリを取得
    WinGet, vExeFullPath, ProcessPath, A
    vExeDir := RegExReplace(vExeFullPath, "[^\\]+$", "")

    ;ファイラで実行
    Run, %cFilerPath%%vExeDir%
Return

/**
 * アプリケーションの再起動
 *
 * @hotkey [Apps]+R
 * @target デフォルト
 */
AppsKey & r::
    ;アクティブウィンドウのフルパスを取得
    WinGet, vExeFullPath, ProcessPath, A

    ;プロセスIDを取得してウィンドウをクローズ
    WinGet, vPid, PID, A
    WinClose, ahk_pid %vPid%

    ;ウィンドウクローズまで60秒待機
    Process, WaitClose, %vPid%, 60

    If (ErrorLevel)
    {
        ;ウィンドウがクローズしなかった場合、バルーンメッセージを表示
        TrayTip, アプリケーション再起動, プロセスが終了できませんでした。, 10, 17
    }
    Else
    {
        ;ウィンドウがクローズした場合、再起動
        Run, %vExeFullPath%
    }
Return

/**
 * タスクマネージャ
 *
 * @hotkey [Apps]+T
 * @target デフォルト
 */
AppsKey & t::Send, +^{Esc}

/**
 * Windows Update
 *
 * @hotkey [LWin]2回
 * @target デフォルト
 */
LWin up::
    Input, vOutput, I T0.3 V L1, {LWin}
    If ErrorLevel In EndKey:LWin
    {
        Sleep, 100
        ;直前のキーと今回のキーがどちらも[LWin]キーで300ミリ秒以内の場合、Windows Updateを実行
        IfWinExist, Windows Update ahk_exe Explorer.EXE
        {
            ;Windows Updateが起動済の場合、アクティブにする
            WinActivate
        }
        Else
        {
            IfWinNotExist, スタート メニュー ahk_class DV2ControlHost
            {
                ;スタートメニューが表示されていない場合、[Win]キーを送信
                Send, {LWin}
            }

            ;スタートメニューの表示を10秒間待機
            WinWait, スタート メニュー ahk_class DV2ControlHost, , 10, ,
            If (ErrorLevel)
            {
                ;タイムアウトした場合、バルーンメッセージを表示して終了
                TrayTip, Windows Update, Windows Updateの起動に失敗しました。`r`nもう一度コマンドを実行してください。, 10, 17

                Return
            }

            ;スタートメニューが表示されたら「Windows Update」を送信
            Send, Windows update
            Send, {Enter}

            ;Windows Updateの表示を10秒間待機
            WinWait, Windows Update ahk_exe Explorer.EXE, , 10, ,
            If (ErrorLevel)
            {
                ;タイムアウトした場合、バルーンメッセージを表示して終了
                TrayTip, Windows Update, Windows Updateの起動に失敗しました。`r`nもう一度コマンドを実行してください。, 10, 17

                Return
            }
        }

        ;更新プログラムの確認をクリックする
        Send, !d
        Send, +{Tab}
        Send, {Enter}
    }
    Else
    {
        ;それ以外の場合、[LWin]キーを送信
        Send, {LWin}
    }
Return

/**
 * SEP LiveUpdate
 *
 * @hotkey [RWin]2回
 * @target デフォルト
 */
RWin up::
    Input, vOutput, I T0.3 V L1, {RWin}
    If ErrorLevel In EndKey:RWin
    {
        Sleep, 100
        ;直前のキーと今回のキーがどちらも[RWin]キーで300ミリ秒以内の場合、スタートメニューからLiveUpdateを実行
        IfWinNotExist, スタート メニュー ahk_class DV2ControlHost
        {
            ;スタートメニューが表示されていない場合、[Win]キーを送信
            Send, {RWin}
        }

        ;スタートメニューの表示を10秒間待機
        WinWait, スタート メニュー ahk_class DV2ControlHost, , 10, ,
        If (ErrorLevel)
        {
            ;タイムアウトした場合、バルーンメッセージを表示して終了
            TrayTip, SEP LiveUpdate, LiveUpdateの起動に失敗しました。`r`nもう一度コマンドを実行してください。, 10, 17

            Return
        }

        ;スタートメニューが表示されたらLiveUpdate実行コマンドを送信
        Send, C:\Program Files (x86)\Symantec\Symantec Endpoint Protection\SepLiveUpdate.exe
        Send, {Enter}
    }
    Else
    {
        ;それ以外の場合、[RWin]キーを送信
        Send, {RWin}
    }
Return
```

### プロキシ認証の自動入力
社内プロキシの認証がうざいのでショートカットキー一発で。
当たり前のように平文でパスワード保存してるので、セキュリティにはご注意ください。

```ini
/**
 * 認証プロキシログイン
 *
 * @hotkey [Apps]+P
 * @target デフォルト
 */
AppsKey & p::
    cProxyLoginID := userid
    cProxyPassword := password

    ;IMEをオフ
    IME_Set(0)

    ;ユーザ・パスワードを送信
    Send, %cProxyLoginID%{Tab}
    Send, %cProxyPassword%{Tab}
    Send, {Enter}
Return
```

## Microsoft Excel
主にコピー/ペースト系のショートカットキー。

```ini
;[START] Microsoft Excel
#IfWinActive, ahk_class XLMAIN

/**
 * 条件付き書式(ルールの管理)([Alt]→H→L→2→R)
 *
 * @hotkey [Ctrl]+I
 * @target Microsoft Excel
 */
^i::
    Send, !h
    Send, l2r
Return

/**
 * データの入力規則([Alt]→A→V→V)
 *
 * @hotkey [Ctrl]+J
 * @target Microsoft Excel
 */
^j::
    Send, !a
    Send, vv
Return

/**
 * 形式を選択して貼り付け([Ctrl]+[Alt]+V)
 *
 * @hotkey [Ctrl]+B
 * @target Microsoft Excel
 */
^b::
    Send, ^!v
Return

/**
 * 値を貼り付け([Ctrl]+[Alt]+V→V→[Enter])
 *
 * @hotkey [Ctrl]+Q
 * @target Microsoft Excel
 */
^q::
    Send, ^!v
    Send, v
    Send, {Enter}
Return

/**
 * 数式を貼り付け([Ctrl]+[Alt]+V→F→[Enter])
 *
 * @hotkey [Ctrl]+W
 * @target Microsoft Excel
 */
^w::
    Send, ^!v
    Send, f
    Send, {Enter}
Return

/**
 * 図として貼り付け([Alt]→H→V→U)
 *
 * @hotkey [Ctrl]+D
 * @target Microsoft Excel
 */
^d::
    Send, {Alt}
    Send, hvu
Return

/**
 * セル内の文字列をコピー
 *
 * @hotkey [Ctrl]+[Shift]+C
 * @target Microsoft Excel
 */
+^c::
    Clipboard := ""
    Send, {F2}
    Send, ^{Home}
    Send, +^{End}
    Send, ^{Insert}
    ClipWait, 0.2

    Send, {Esc}
Return

/**
 * セルを図としてコピー([Alt]→H→C→P)
 *
 * @hotkey [Ctrl]+[Alt]+C
 * @target Microsoft Excel
 */
^!c::
    Send, {Alt}
    Send, hcp
Return

/**
 * 編集モード([F2])
 *
 * @hotkey [Shift]2回
 * @target Microsoft Excel
 */
~LShift up::
~RShift up::
    Input, vOutput, I T0.3 V L1, {LShift}{RShift}
    If ErrorLevel In EndKey:LShift,EndKey:RShift
    {
        ;直前のキーと今回のキーがどちらも[Shift]キーで300ミリ秒以内の場合、[F2]を送信
        Send, {F2}
    }
Return

/**
 * シート切替([Ctrl]+[PageUp]/[PageDown])
 *
 * @hotkey [Ctrl]+[Alt]+Wheel
 * @target Microsoft Excel
 */
^!WheelUp::
    Send, ^{PgUp}
Return

^!WheelDown::
    Send, ^{PgDn}
Return

#IfWinActive
;[END] Microsoft Excel
```

## ブラウザ
別のブラウザで開いたり新規セッションで開いたり。

```ini
;[START] ブラウザ
#IfWinActive, ahk_group GroupBrowser

/**
 * 無効
 *
 * @hotkey [Ctrl]+S
 * @target ブラウザ(Google Chrome/Internet Explorer)
 */
^s::
    ;バルーンメッセージを表示
    TrayTip, [Ctrl]+S, ブラウザでの[Ctrl]+Sの入力は無効化されています。, 10, 17
Return

#IfWinActive
;[END] ブラウザ

;[START] Google Chrome
#IfWinActive, ahk_exe Chrome.exe

/**
 * Internet Explorerで開く
 *
 * @hotkey [Apps]+I
 * @target Google Chrome
 */
AppsKey & i::
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll
    Clipboard := ""

    ;アドレスバーにフォーカス
    Send, !d
    Sleep, 300

    ;アドレスバーのURLをコピー
    Send, ^{Insert}
    ClipWait, 0.2

    ;コピーしたURLでIEを起動
    Run, %cIEPath% %Clipboard%

    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
Return

#IfWinActive
;[END] Google Chrome

;[START] Internet Explorer
#IfWinActive, ahk_exe iexplore.exe

/**
 * Google Chromeで開く
 *
 * @hotkey [Apps]+C
 * @target Internet Explorer
 */
AppsKey & c::
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll
    Clipboard := ""

    ;アドレスバーにフォーカス
    Send, !d
    Sleep, 300

    ;アドレスバーのURLをコピー
    Send, ^{Insert}
    ClipWait, 0.2

    ;コピーしたURLでIEを起動
    Run, %cChromePath% %Clipboard%

    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
Return

/**
 * 新規セッション
 *
 * @hotkey [Ctrl]+[Alt]+N
 * @target Internet Explorer
 */
^!n::
    Send, !f
    Sleep, 100
    Send, i
Return

#IfWinActive
;[END] Internet Explorer
```

## コマンドプロンプト
コピー&ペーストの統一と、それによって使えなくなる[Ctrl]+Cの移動。

```ini
;[START] コマンドプロンプト
#IfWinActive, ahk_class ConsoleWindowClass

/**
 * コピー
 *
 * @hotkey [Ctrl]+C
 * @target コマンドプロンプト
 */
^c::
    Send, !{Space}
    Send, ey
Return

/**
 * ペースト
 *
 * @hotkey [Ctrl]+V
 * @target コマンドプロンプト
 */
^v::
    Send, !{Space}
    Send, ep
Return

/**
 * 中断
 *
 * @hotkey [Ctrl]+B
 * @target コマンドプロンプト
 */
^b::Send, ^c
```

## マウス
### 高速スクロール

```ini
/**
 * 高速スクロール
 *
 * @hotkey [Shift]+Wheel
 * @target デフォルト
 */
+WheelUp::
    Send, {WheelUp 10}
Return

+WheelDown::
    Send, {WheelDown 10}
Return

+WheelRight::
    Send, {WheelRight 10}
Return

+WheelLeft::
    Send, {WheelLeft 10}
Return
```

### 水平スクロール
Microsoft Excelは水平スクロールが効かなかったため、処理を別にしています。

```ini
/**
 * 水平スクロール
 *
 * @hotkey [Alt]+Wheel
 * @target デフォルト
 */
!WheelUp::
    IfWinActive, ahk_class XLMAIN
    {
        SetScrollLockState, On
        Send, {Left}
        SetScrollLockState, Off
    }
    Else
    {
        Send, {WheelLeft}
    }
Return

!WheelDown::
    IfWinActive, ahk_class XLMAIN
    {
        SetScrollLockState, On
        Send, {Right}
        SetScrollLockState, Off
    }
    Else
    {
        Send, {WheelRight}
    }
Return

/**
 * 高速水平スクロール
 *
 * @hotkey [Shift]+[Alt]+Wheel
 * @target デフォルト
 */
+!WheelUp::
    IfWinActive, ahk_class XLMAIN
    {
        SetScrollLockState, On
        Send, {Left 10}
        SetScrollLockState, Off
    }
    Else
    {
        Send, {WheelLeft 10}
    }
Return

+!WheelDown::
    IfWinActive, ahk_class XLMAIN
    {
        SetScrollLockState, On
        Send, {Right 10}
        SetScrollLockState, Off
    }
    Else
    {
        Send, {WheelRight 10}
    }
Return
```

### フライングスクロール
ELECOMのマウスには勢いよくホイールを回すと勝手にスクロールし続けてくれる「フライングスクロール」という機能があります。
ぶっちゃけ暴発し過ぎで使い物にならなかったので、`ContinueAction`という関数を作成して[無変換]+ホイールに割り当ててみました。
基本は、発動するとコマンドをループで実行し、実行中のホットキー以外から`ContinueAction`関数が呼ばれると前の実行がストップします。
仕組み的には、グローバル変数`gContinueAction`が`True`の間だけ引数`pInterval`で指定された間隔でコマンドを実行し続けるという単純なものですので、別のホットキーでグローバル変数`gContinueAction`を`False`に設定してやれば、ループがキャンセルされます。
今回は[無変換]+[Esc]の他、通常のホイール操作にもループキャンセルを設定しました。`~WheelUp`から`~WheelRight`の並びに同じようにキーを追加すれば、キャンセル用のキーを増やすことができます。
ちなみに、作成した`ContinueAction`関数はホイール回転以外のコマンドも継続実行できますので、使い方次第で連打スクリプトなどに応用できるかも。

#### `ContinueAction(pCommand[, pInterval][, pLimit])`
- 引数
    - `pCommand`
        - 継続実行するコマンド。
        - Hotkey形式で指定する。
    - `pInterval`
        - 実行間隔をミリ秒で指定する。
        - 省略時は100ミリ秒。
    - `pLimit`
        - 最大実行回数。
        - 省略時は300回。
- 戻り値
    - なし 

```ini
/**
 * グローバル変数gContinueActionがTrueの間、処理を継続実行する。
 *
 * @param {String} pCommand 継続実行するSendコマンド。
 * @param {Number} pInterval 実行間隔(ミリ秒)。省略時は100。
 * @param {Number} pLimit 最大実行回数。省略時は300。
 */
ContinueAction(pCommand, pInterval=100, pLimit=300) {
    If (gContinueAction)
    {
        ;開始時にgContinueActionがTrueだった場合、継続実行を終了
        gContinueAction := False
        Sleep, 100
    }
    Else
    {
        ;開始時にgContinueActionがFalseだった場合、継続実行を開始
        gContinueAction := True

        ;リミットを指定してループ
        Loop, %pLimit%
        {
            If (!gContinueAction)
            {
                ;gContinueActionがFalseに変化していたら、処理を終了
                Break
            }

            ;コマンドを実行して実行間隔を待機
            Send, %pCommand%
            Sleep, %pInterval%
        }

        ;リミットを超えた場合、gContinueActionをFalseにする
        gContinueAction := False
    }
}

/**
 * フライングスクロール
 *
 * @hotkey [無変換]+Wheel
 * @target デフォルト
 */
sc07B & WheelUp::
    ContinueAction("{WheelUp}", 50, 300)
Return

sc07B & WheelDown::
    ContinueAction("{WheelDown}", 50, 300)
Return

sc07B & WheelLeft::
    ContinueAction("{WheelLeft}", 50, 300)
Return

sc07B & WheelRight::
    ContinueAction("{WheelRight}", 50, 300)
Return

;連続実行時は通常のホイール操作でキャンセル
;[Start]gContinueAction == True
#If, gContinueAction

WheelUp::
WheelDown::
WheelLeft::
WheelRight::
    {
        gContinueAction := False
    }
Return

#If
;[End]gContinueAction == True

/**
 * 連続実行を中止
 *
 * @hotkey [無変換]+[Esc]
 * @target デフォルト
 */
sc07B & Esc::
    gContinueAction := False
Return
```
## Google便利機能
### 選択文字列をGoogle翻訳
選択した範囲をURIエンコードし、Google翻訳に引き渡すスクリプト。
英数記号のみの場合は英語→日本語、それ以外の場合は日本語→英語で翻訳します。
URIデコード関数は使っていませんが、折角エンコードを作ったのでセットで。いずれ役に立つ時が来る……かも？
エンコード・デコード部分はJavascriptを使用したかった(のとCOMオブジェクトを使ってみたかった)ため、スクリプトコントロールのCOMオブジェクトを利用しています。

- [ComObjCreate\(\) \- AutoHotkey Wiki](http://ahkwiki.net/ComObjCreate)

……が、64bit版Windowsにはスクリプトコントロールがない！
ので、32bit版で動かすか、[64ビット スクリプト コントロール・Tablacus Script Control 64](https://tablacus.github.io/scriptcontrol.html)をインストールしてください。

#### `URIEncode(pStr)`
- 引数
    - `pStr`
        - URIエンコードの対象となる文字列。
- 戻り値
    - URIエンコード後の文字列。 

#### `URIDecode(pStr)`
- 引数
    - `pStr`
        - URIデコードの対象となる文字列。
- 戻り値
    - URIデコード後の文字列。 

#### `EscapeJS(pStr)`
- 引数
    - `pStr`
        - JavaScriptのコマンド実行用にエスケープを行う文字列。
- 戻り値
    - エスケープ後の文字列。 

```ini
/**
 * 対象文字列をURIエンコードする。
 *
 * @param {String} pStr URIエンコード対象文字列。
 * @return {String} vResult URIエンコード後の文字列。
 */
URIEncode(pStr)
{
    ;JavaScriptのスクリプトコントロールCOMオブジェクトを作成
    oScriptControl := ComObjCreate("ScriptControl")
    oScriptControl.Language := "JScript"

    ;改行コード単位でループ
    Loop, Parse, pStr, `n, `r
    {
        ;JavaScriptコマンド文字列を作成し、実行
        vScript := "var encodedStr = encodeURIComponent(""" . EscapeJS(A_LoopField) . """);"
        oScriptControl.ExecuteStatement(vScript)

        ;実行結果を取得して改行コード"%0A"を付与
        vResult := vResult . oScriptControl.Eval("encodedStr") . "%0A"
    }

    Return vResult
}

/**
 * 対象文字列をURIデコードする。
 *
 * @param {String} pStr URIデコード対象文字列。
 * @return {String} vResult URIデコード後の文字列。
 */
URIDecode(pStr)
{
    ;JavaScriptのスクリプトコントロールCOMオブジェクトを作成
    oScriptControl := ComObjCreate("ScriptControl")
    oScriptControl.Language := "JScript"

    ;JavaScriptコマンド文字列を作成し、実行
    vScript := "var decodedStr = decodeURIComponent(""" . EscapeJS(pStr) . """);"
    oScriptControl.ExecuteStatement(vScript)

    ;実行結果を返却
    Return oScriptControl.Eval("decodedStr")
}

/**
 * 対象文字列をJavaScript実行用にエスケープする。
 *
 * @param {String} pStr エスケープ対象文字列。
 * @return {String} vResult エスケープ後の文字列。
 */
EscapeJS(pStr) {
    StringReplace, pStr, pStr, \, \\, All
    StringReplace, pStr, pStr, ', \', All
    StringReplace, pStr, pStr, ", \", All
    StringReplace, pStr, pStr, `b, \b, All
    StringReplace, pStr, pStr, `t, \t, All
    StringReplace, pStr, pStr, `v, \v, All
    StringReplace, pStr, pStr, `n, \n, All
    StringReplace, pStr, pStr, `r, \r, All
    StringReplace, pStr, pStr, `f, \f, All

    Return pStr
}

/**
 * 選択文字列をGoogle翻訳
 *
 * @hotkey [Win]+[変換]
 * @target デフォルト
 */
LWIN & sc079::
RWIN & sc079::
    ;Google翻訳URL
    cGoogleTranslateURL := "https://translate.google.co.jp/"
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll
    Clipboard := ""

    ;選択文字列をコピー
    Send, ^{Insert}
    ClipWait

    If (Clipboard != "") {
        ;文字列が選択されている場合、翻訳ページURLを作成
        vTranslateURL := cGoogleTranslateURL . "#view=home&op=translate"

        ;選択文字列が空でない場合
        If (RegExMatch(Clipboard, "[^\x01-\x7E]"))
        {
            ;選択文字列に1バイト文字以外が含まれる場合、日本語→英語翻訳
            vTranslateURL := vTranslateURL . "&sl=ja&tl=en"
        }
        Else
        {
            ;選択文字列が1バイト文字のみの場合、英語→日本語翻訳
            vTranslateURL := vTranslateURL . "&sl=en&tl=ja"
        }

        ;URIエンコーディングを行い、翻訳ページをChromeで起動
        Clipboard := URIEncode(Clipboard)
        vTranslateURL := vTranslateURL . "&text=" . Clipboard
        Run, %cChromePath% %vTranslateURL%
    }

    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
Return
```

### 選択文字列を開く / Google検索
[Ctrl]+ホイールボタン、または[Win]+Gで選択文字列を開きます。
選択文字列がURLの場合はブラウザで実行、ファイルパスの場合はエクスプローラで実行、それ以外の場合はGoogle検索となります。
[Win]+Gには未選択状態でGoogle検索キーワード入力ダイアログボックスを出すようにしました。

#### `OpenSelStr(pSelStr)`
- 引数
    - `pSelStr`
        - 開く対象の文字列。
- 戻り値
    - なし 

#### `ShowWebSearchDialog()`
- 引数
    - なし
- 戻り値
    - なし 

```ini
/**
 * 選択文字列がURIならChromeで、ファイルパスならエクスプローラで、それ以外ならGoogle検索で開く。
 *
 * @param {String} pStr 対象文字列。
 */
OpenSelStr(pStr) {
    ;Google検索URL
    cGoogleSearchURL := "http://www.google.co.jp/search?q="
    If (pStr != "")
    {
        ;対象文字列が空でない場合、パスに分割
        SplitPath, pStr, vName, vDir, vExt, vNoExt, vDrive
        If vDrive Contains http://,https://
        {
            ;URIの場合、Chromeで開く
            Run, %cChromePath% %pStr%
        }
        Else If (vDrive != "")
        {
            ;ファイルパスの場合、エクスプローラで開く
            Run, %vDir%, , UseErrorLevel
            If (ErrorLevel)
            {
                ;ファイルパスが開けなかった場合、バルーンメッセージを表示しGoogle検索で開く
                TrayTip, AutoHotkey, <%pStr%>`r`nはエクスプローラで開けませんでした。`r`nウェブ検索を実行します。, 1, 18
                pStr := RegExReplace(pStr, "\s+", "\+")
                Run, %cChromePath% %cGoogleSearchURL%%pStr%
            }
        }
        Else
        {
            ;それ以外の場合、Google検索で開く
            pStr := RegExReplace(pStr, "\s+", "\+")
            Run, %cChromePath% %cGoogleSearchURL%%pStr%
        }
    }
}

/**
 * Web検索ダイアログを表示する。
 */
ShowWebSearchDialog() {
    ;Google検索URL
    cGoogleSearchURL := "http://www.google.co.jp/search?q="

    ;検索ダイアログを表示
    InputBox, vSearchWord, Web検索, 検索したい語句を入力してください。, , , 130

    If (!ErrorLevel)
    {
        ;[OK]ボタンが押された場合、Google検索で開く
        vSearchWord := RegExReplace(vSearchWord, "\s+", "\+")
        Run, %cChromePath% %cGoogleSearchURL%%vSearchWord%
    }
}

/**
 * 選択文字列を開く
 *
 * @hotkey [Win]+G
 * @hotkey [Ctrl]+ホイールボタン
 * @target デフォルト
 * @condition 文字列選択
 */

/**
 * 検索ダイアログを表示
 *
 * @hotkey [Win]+G
 * @hotkey [Ctrl]+ホイールボタン
 * @target デフォルト
 * @condition 文字列未選択
 */
#g::
^Mbutton::
    OnClipboardChange("NoticeClipboard", 0)
    vClipboardAll := ClipboardAll
    Clipboard := ""

    ;選択文字列をコピー
    Send, ^{Insert}
    ClipWait, 0.2

    If (Clipboard != "") {
        ;選択文字列が空でない場合、選択文字列を開く
        OpenSelStr(Clipboard)
    }
    Else
    {
        ;選択文字列が空の場合、検索ダイアログを開く
        ShowWebSearchDialog()
    }

    Clipboard := vClipboardAll
    OnClipboardChange("NoticeClipboard", 1)
Return
```

## ホットキー/ホットストリング一覧
こちらの別記事を参照してください。
[AutoHotkeyのコメントからヘルプを作成する \- Qiita](https://qiita.com/draganmaistir/items/36bd90fa6c5a93736c70)

# 参考にさせていただいたページ
- [Microsoft Excel/Wordで、意図せずにF1キーを押しヘルプが暴発するのを防ぐ \- Qiita](https://qiita.com/rohinomiya/items/b655115b3ba3e1eaafbe)
- [Win10 AutoHotKeyで、右Ctrl\+矢印キーでPageUp/PageDown/Home/Endする \- Qiita](https://qiita.com/standard-software/items/6e4ad65da23041c075de)
- [作業効率を上げるかもしれない簡単スクリプトを見てほしい\(AutoHotkey\) \- Qiita](https://qiita.com/neokix/items/70256089ff343404db8d)
- [\[AutoHotKey\]OnClipboardChange\(\)関数でクリップボード監視 \- Qiita](https://qiita.com/catfist/items/cdb8300221b48667b155)
- [どこからでも google 検索 \- Qiita](https://qiita.com/_meki/items/34191154386d1137636e)
- [neue cc \- AutoHotKeyによるマウス/キーボード徹底カスタマイズ](http://neue.cc/2008/10/27_110.html)
- [誰かの役に立つかもしれない実験メモ AutoHotkey](https://yuruaki.blog.fc2.com/blog-category-4.html)
- [クリップボードにコピーしている文字の行頭に引用記号"&gt;"を挿入する \- 今日もスミマセン。](http://d.hatena.ne.jp/snaka72/20090205/1233815453)
- [AutoHotkeyのつぼの記事一覧 \| つぼログ。 \| 横浜で翻訳業務を行うシーブレインスタッフによる技術情報ブログ](http://tsubolog.c-brains.jp/autohotkey/)