ひらがなカタカナキーをF21キーに変更
AutoHotkeyのスクリプトを書いていると、ひらがなカタカナキーがDownされたっきりUpされないという事態に。そこで、「ChangeKeyを使用してWindowsキーをF13キーに変更する方法」を利用して、ひらがなカタカナキーをF21キーにして問題解決。
ちなみに、キーの履歴を見ると、ひらがなカタカナキーとして「vkF0sc070」と「vkF2sc070」が表示されており、UpとDownで異なる表示がされていました。ここらへんが何か関係あるのかも。
このキーと同じように、CapsLock、半角/全角も扱いにくいキーですが、ChangeKeyで他のキーと置き換えてからカスタマイズする分にはそれほど問題にならない、はず。
AutoHotkeyで、ちょっと高機能な「行頭へカーソルを移動」を作ってみる
インデントされている文章を編集しているときに、Homeキーなどで単純に行頭へカーソルを移すと、本当に編集したい"行頭"までTabやスペースの分だけ右に移動しなければなりません。今回は、インデントのTabやスペースを認識して、その手前まで移動するホットキー「行頭へカーソルを移動」を、AutoHotkeyを利用して作成します。また、それを通して、AutoHotkeyを利用するときのコツを紹介します。
文字列の内容を知るためには、コピーするしかない
今回は、Tabや半角スペースの存在をAutoHotkeyScriptが認識しなくてはいけません。このように、カーソル付近の文章を認識するためにはその内容をクリップボードにコピーして、それを読み込む必要があります。
このとき、現在のクリップボードの内容を一時的に退避して、作業が終わったら戻す必要があります。実は、この作業には、いくつかの注意すべきポイントがあります。
選択範囲の内容を読み取る方法
行頭へ移動するホットキーを作る前段階として、選択した文字を変数に格納してみます。
カーソルの一文字左を読み取るコードは次のようになります。
^j:: ; クリップボードの内容を退避 clipboard_backup = %ClipboardAll% : 選択 Send +{Left} ; コピー Clipboard = ; クリップボードを空にする Send ^c ; 実際のコピーコマンド ClipWait, 1 ; コピー完了まで待機 ; 変数へクリップボードの内容を格納 selected := Clipboard ; 表示 msgbox, %selected% ; クリップボードの内容を復元 Clipboard := clipboard_backup Return
見ての通り、結構長くなります。ただ、この中に注意すべき点がたくさんあるのです。以下、注意点を一つ一つ説明しておきます。
クリップボードの内容を退避と復元で利用する変数が違う
ClipboardAll変数は、退避のために利用する変数です。このコードのように「ClipboardAll」変数を利用して、バックアップ先の変数に退避してクリップボードを使う作業を終えたら、今度は「Clipboard」変数にその内容を代入します。ここで、ClipboardAllに代入しても無意味です。ClipboardAll変数は、退避専用の変数です。
ClipWaitを利用するために、コピーの前にClipboardを空にする
「Send ^c」の前に、「Clipboard =」でClipboard変数の中身を空にしています。これをしないと、次に紹介するClipWaitコマンドが意図した動作をしてくれません。かならずコピーの前にはClipboard変数をクリアしておきましょう。
コピーの完了をClipWaitで確認する
選択範囲のコピーの実際は、単なる「Send ^c」です。つまり、このキー入力を受け取ったアプリケーションがクリップボードに選択範囲の文字列を格納してくれるということを意味します。つまり、「Send ^c」をした直後、すぐクリップボードの内容が更新されているわけではなく、コピーの完了を待たなければならないということです。そこで利用するのが「ClipWait」コマンドです。
「ClipWait, 1」では、最大1秒、クリップボードの更新を待ちます。このとき、実際には、テキストとして読み取れる内容になることを待つので、あらかじめ内容をクリアしておく必要があるわけです。
クリップボードの内容を利用するときはClipboard変数
クリップボードの内容を利用するときは、「ClipboardAll変数」ではなく、「Clipboard変数」を利用してください。ClipboardAllを使って読み出しても、テキストとして利用できません。
行頭へ移動ホットキー(低速版)
では、選択範囲の読み出し方法が分かったところで、実際に目的のホットキーの実装を行います。今回は、とりあえず行頭までジャンプして、右隣がTabか半角スペースだったらひとつ移動するようにしてみます。
実際のコードは次のようになります。
^j:: ; 退避 clipboard_backup = %ClipboardAll% ; 先頭へ移動 Send {Home} ; カーソル位置の修正用ループ Loop { ; カーソルの一つ右の文字を読み取る Send +{Right} Clipboard := Send ^c ClipWait, 1 selected := Clipboard ; インデント文字かどうかで分岐 If (selected = " " || selected = "`t") { Send {Right} ; 次の文字へ } Else { ; 選択を解除して抜ける Send {Left} Break } } ; 復元 Clipboard := clipboard_backup Return
このコードは、とりあえず目的のとおり動きます環境、特にアプリケーション次第でうまくいかないかもしれません。今はとりあえずTeraPadで試しています。ただ、半角スペース8つなどのインデントで試しに実行してみると、まるでスローモーションです。
この原因のひとつは、コピー回数が多いことです。
行頭へ移動ホットキー(中速版)
次に紹介するコードは、コピー回数を減らしたバージョンです。
^j:: ; 退避 clipboard_backup = %ClipboardAll% ; 先頭まで選択 Send +{Home} ; 選択範囲を読み取る Clipboard := Send ^c ClipWait, 1 selected := Clipboard ; クリップボードの内容を復元 Clipboard := clipboard_backup ; 選択範囲一文字ずつに対してループ Loop % StrLen(selected) { ; 左から順番に一文字取り出す c := SubStr(selected, A_Index, 1) ; インデント文字かどうかで分岐 If (c = " " || c = "`t") { Send +{Right} ; 選択範囲を狭めて次の文字へ } Else { Break ; 終了 } } ; 選択を解除 Send {Left} Return
これでも十分遅いのですが、前のバージョンよりは速くなっています。このように、できるだけClipWaitで待つ時間を小さくした方がよいと思われます。ちなみに、今回のバージョンで最後の「Send {Left}」をコメントアウトすると、「先頭まで選択」ができます。
もっと速くするためには
実は、遅い原因の大部分はカーソル移動時間です。一文字ずつカーソルを移動させる限り、カーソル移動にかかる時間がどうしても削れません。そこで、「Ctrl+→」などを使って移動すればもっと高速化できるのですが、アプリケーションの依存度が高く、アプリケーションごとにどこまで移動するかが変わってしまうため、ちょっと微妙です。参考として、少し動作が変わってしまいますが(メモ帳ですら不適合で、TeraPadでわりと意図したとおり動いたという程度)、その一例を載せておきます。
^j:: ; 退避 clipboard_backup = %ClipboardAll% ; 先頭まで選択 Send +{Home} ; 選択範囲を読み取る Clipboard := Send ^c ClipWait, 1 selected := Clipboard ; クリップボードの内容を復元 Clipboard := clipboard_backup ; 先頭の一文字を取り出す c := SubStr(selected, 1, 1) ; インデント文字かどうかで分岐 If (c = " " || c = "`t") { Send ^+{Right} ; 単語単位の移動を利用して移動 } ; 選択を解除 Send {Left} Return
これは、「先頭までを選択」が行いやすいバージョンで、次は、行全体の選択を避けたバージョンです。
^j:: ; 退避 clipboard_backup = %ClipboardAll% ; カーソルが先頭になるように、 ; 先頭一文字を選択 Send {Home}{Right}+{Home} ; 選択範囲を読み取る Clipboard := Send ^c ClipWait, 1 selected := Clipboard ; クリップボードの内容を復元 Clipboard := clipboard_backup ; 先頭の一文字を取得 c := selected ; インデント文字かどうかで分岐 If (c = " " || c = "`t") { Send ^{Right} ; 単語単位の移動を利用して移動 } Else { Send {Left} } Return
まとめ
AutoHotkeyを使うとこんな感じで作業を自動化できますよ、という紹介にはなったと思います。ただ、そんなことより重要なのは、Clipboardの使い方です。いろいろ注意点が多いので、気を付けてください。
AutoHotkeyにおけるラベルの優先度と3キー同時押しの定義
AutoHotkey(Version v1.0.48.05.L61)のホットキーの定義方法だと、どのラベルの内容が実行されるのか迷うときがあります。その優先度についてのまとめです。
後に書いた方が優先される(コンビネーションキー)
次のコンビネーションキー二つから成るコードを実行します。
a & z::msgbox, "a&z"
b & z::msgbox, "b&z"
このときに、「a,b,z」を同時押し(正確にはaとbを押した状態でz)すると、「b&z」と表示され、二つの行を入れ替えて、
b & z::msgbox, "b&z"
a & z::msgbox, "a&z"
としたときは「a&z」が表示されます。 このことから、後ろに書いた方が優先的に実行されると考えられます。
コンビネーションキーが優先される(通常ホットキーラベルとコンビネーションキー)
続いて、「Ctrl+z」と「a+z」のホットキーを定義してみます。
^z::msgbox, "^z"
a & z::msgbox, "a & z"
このときに、「Ctrl,a,z」を同時押し(Ctrlとaを押した状態でz)すると、今度は行を入れ替えたとしても必ず「a & z」と表示されます。
このことから、コンビネーションキーに書いたことが優先的に実行されると考えられます。
3キー同時押しのホットキーを定義するときに注意
つまり、たとえばCtrlと無変換を修飾キー(prefix key)として利用し、「Ctrl+k」「無変換+k」、「Ctrl+無変換+k」をそれぞれ別々に独立して制御したい場合、「^k::」と「vk1Dsc07B & k::」を書いて二つ同時押し(「Ctrl+k」と「無変換+k」)、どちらかの中で三つ同時押しの動作を定義することになります。これは、Ctrl、Alt、Shift、Win以外のキーを二つ以上含む三つ同時押しを直接定義する方法がAutoHotkeyには存在しないからです。
つまり、「^k::」側に書く方式
^k:: If GetKeyState("vk1Dsc07B", "P") msgbox, "Ctrl+無変換+k" Else msgbox, "Ctrl+k" Return vk1Dsc07B & k::msgbox, "無変換+k"
と、「vk1Dsc07B & k::」側に書く方式
^k::msgbox, "Ctrl+k" vk1Dsc07B & k:: If GetKeyState("Ctrl", "P") msgbox, "Ctrl+無変換+k" Else msgbox, "無変換+k" Return
が考えられるのですが、どちらにせよ、3つのキー(Ctrl,無変換,k)を同時押ししたときに実行されるのは「^k::」ではなく「vk1Dsc07B & k::」なのです。つまり、後者が正解で、前者は間違いとなります(前者を実行して三つ同時押しをしても、「無変換+k」が表示されてしまいます)
まとめ
AutoHotkeyには、このような優先順序があるようです。例に挙げたように、特に3キー同時押しを細かく制御しようとする場合には注意が必要です。ちなみに、ここで細かく、と言っているのは、
vk1Dsc07B & k:: Send, {Blind}{Left}
のように、CtrlキーなどのUp/Downを素通ししてしまうことで3キー同時押しを行うことも出来るからです。ただし、これでは制限が非常にきついので、本文中で紹介したような方法が必要になると思います。
3キー同時押しのうまいやり方が本当にこれなのかは分かりません。もっといい3キー同時押し方法があるのかもしれません。ただ、とりあえずこういうことが起こるということに気がついて、実際にはまってしまったのでメモしておきました。落とし穴うめうめ。
Windowsダンプの極意 エラーが発生したら、まずダンプ解析!Advanced Windows 第5版 上 (マイクロソフト公式解説書)
インサイド Microsoft Windows 第4版〈上〉 (マイクロソフト公式解説書)
APIで学ぶWindows徹底理解
gdi++.exe Helium版でWindows Live Messengerからログアウトしてしまう
gdi++.exe Helium版を使っていると、
Windows Live Communications Platform は動作を停止しました
問題イベント名:AppHang
(問題イベント名:BEX のこともある)
アプリケーション名 01:wlcomm.exe
障害モジュールの名前:gdi++.dll_unloaded
例外コード:c0000005
というエラーメッセージが出て、Windows Live Messengerからログアウトしてしまいました。なので、gdi++.exeの.iniファイルの[DenyModule]にwlcomm.exeと書いて対策。ここまではっきりと原因が分かると対策も簡単。
追記
全然直ってないかもしれない。
MS Office用のAutoHotkeyスクリプトを書くときの注意
MS Office、ExcelやWord、OneNoteなどを利用する人には、専用AutoHotkeyスクリプトの作成をおすすめします。作業効率を大きく上げることが可能です。
しかし、設定したはずのホットキーがうまく働かないことがあります。
たとえば、Excelでホットキーから「Send {Home}」や「Send ^+`;」をしたり、OneNoteでホットキーから「Send {Down}」や「Send {Up}」をしようとすると、うまく動きません。