WinMergeでの作業を効率化するスクリプトを作った。表示しているコマンドをAutoHotkey同梱のCHMヘルプで開いたり、エディタで対応ファイルを開いたり、ワンキーで保存して閉じたり、フォーカスを移動せずに差分表示を横スクロールできるようにしたりして快適になった。■AutoHotkey(http://www.autohotkey.com/)1.0.32なんか微妙に改良されてた。次はDLLの関数が呼べるようになるらしい。構造体のポインタ渡しとかがどうなるか。■AutoHotkey(http://www.autohotkey.com/)1.0.33DLL呼び出し機能が追加された模様。引数を与えて返り値を得る基本的な機能は備わっている。DMonkeyのDynaCallと違い、整数や浮動小数点値などの変数へのポインタを直接送ることができる。(DMonkeyの場合、要素が整数値一つのStructオブジェクトを作成して送ったりする必要があった)構造体を扱うことはできない模様。代わりに文字列としてメモリ領域を確保して、Transformコマンドなどでデータの書き換え・読み出しを行えば可能かと思ったが、文字列のヌル文字以降が削除されてしまったり、構造体メンバに文字列や構造体へのポインタが含まれる場合に対応できなかったりしてダメっぽい。プロセスIDを指定して実行ファイルパスを得る関数を作った。s}とりあえず説明を一部日本語化した。■AutoHotkeyでプロセスメモリ書き換え027.zip(http://lukewarm.s101.xrea.com/up/file/027.zip)他のプロセスが所有するメモリを書き換える関数を作ってみた。WriteProcessMemoryで割と簡単にできた。ゲームなどの改造コードの実行に使える。ホットキー割り当てやタイマー実行が柔軟に出来るのでそれなりに便利そうだ。メモリ検索は作ってないので、改造コードを得るにはスペシャルねこまんま57号(http://www.vector.co.jp/soft/win95/hardware/se254476.html)などを使う。■AutoHotkey(http://www.autohotkey.com/)1.0.343番目の数字があがっているがマイナーバージョンアップらしい。修正されているらしい。1.0.33.01とあわせた変更点。色々な言語で行コメントの開始に使われる「//」が割り算に使われるのはややこしい。あと、割った余りを返す「%」のような演算子がないのも中途半端。組み込み関数が色々と追加されたのは、いちいち自分で定義しなくて良くて楽。■AutoHotkey(http://www.autohotkey.com/)1.0.35・SendコマンドでAltGr文字を送れないのを修正AltGrってのがよくわからんが、こんな感じのものらしい(http://office.microsoft.com/ja-jp/assistance/HP052590631041.aspx)・関数で省略可能引数を定義可能に省略可能引数には、デフォルト値としてtrue,false,空文字列,数値のどれかを指定する模様。・DateTimeコントロールとMonthCalコントロールを追加1行入力欄型の日付時刻入力コントロールと、カレンダーコントロール。値を増減させる矢印ボタンの付いた数値入力用コントロール。次はリストビューコントロールを追加する予定らしい。■AutoHotkey(http://www.autohotkey.com/)1.0.35.10なんかクリップボードの内容が変更されたときに実行されるOnClipboardChange(http://www.autohotkey.com/docs/misc/Clipboard.htm#OnClipboardChange)サブルーチンを設定できるようになったらしい。コマンドでラベルを割り当てるOnExit(http://www.autohotkey.com/docs/commands/OnExit.htm)と違って、ラベルとして記述するらしい。■AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)を適当に更新した4ヶ月くらい放置していた。GUI関係以外の変更点を大体書いた。■AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)を適当に更新したListView以外のGUI関係の更新箇所に対応した。■AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)を適当に更新したとりあえず1.0.37.05分の変更点まで追いついた。ListViewがややこしくてしんどい。そのうちツリービューも出てくるのだろうか。■見つけたサイトなまず日記(http://www.tierra.ne.jp/~aki/diary/)AutoHotkeyについて書いてあった。ファンとか言われてるけど、実はあんまり使ってない。ファンというと塊魂の新しいほうを思い出す。eamatの日記(http://d.hatena.ne.jp/eamat/)AutoHotkeyについての記述がある。メモリリークがあるのではないかということらしい。v1.0.38(http://www.autohotkey.com/forum/viewtopic.php?t=5219&sid=0db1500df2a140e44c3a0e0506887e93)なんか任意のウィンドウメッセージに応答する関数を設定する機能がついた模様。これでGUI関連の対外のイベントは対応できそう。こんな感じでウィンドウ全体をドラッグ可能なウィンドウの本物が作れる。■AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)を適当に更新したOnMessageとかの説明を書いた。更新処理スクリプトを実行するのを忘れてて、コマンド一覧などが更新されてなかったので更新した。OnMessageだが、ウィンドウの閉じるボタンを押したときのWM_SYSCOMMANDなど、なぜか捕らえられないメッセージがある模様。コントロールをクリックしたときなども、種類によってはコントロールではなくウィンドウに送られたものとして補足されることがある。IsLabel関数でラベルが存在するかどうかを調べることができるようになった。GuiCloseやOnClipboardChangeのように特別な名前のラベルとして記述するものと、SetTimerやOnExitのようにイベントにラベルを割り当てるもの、OnMessageのように関数を割り当てるものが混在していてややこしい。ほかウィンドウへのメッセージの監視は、SetWindowsHookExを使って別途用意したDLLの関数を登録すればできなくはなさそう。フックプロシージャが呼ばれたら、AutoHotkeyのメインウィンドウにSendMessageで通知して、必要なら関数で情報を取得するとか。■AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)を適当に更新したとりあえず現行のバージョンに追いついた。なにやら、仮想キーコードでホットキーを指定することができるようになった模様。これで、なぜかIMEのOnとOffが別のキーイベントとして取得されるようになる。こんな感じで、IMEの状態をキャレット位置に表示することもできなくはない。A_CaretY+14しかし、未確定文字列がある状態で半角/全角キーを押しても、この2つのホットキーが交互に実行されてしまう。未確定文字列を消してから半角/全角キーを押すと、一度だけ直前のホットキーではないほうが実行される。2度目からはまともになる。そんなわけで、不完全すぎてあまり役には立たない。〜いろはに〜」(http://iroha2.rona.nomaki.jp/)よく分からんが特殊なかな入力方式を実現するAutoHotkeyスクリプトらしい。■AutoHotkey(http://www.autohotkey.com/)1.0.40「a::b」のように記述することでキー割り当てを変更できる機能が追加された。修飾キーとの組み合わせやキーリピートなども考慮された完全なリマップが簡単な記述で実現できるらしい。日本語環境では、CapsLockとCtrlの入れ替えはできない模様。Principia(http://principia.s54.xrea.com/index.php?AutoHotkey%20%A5%E1%A5%E2)アクセスログより。■AutoHotkeyでBREGEXP.DLLを使う作った。BREGEXP(http://lukewarm.s101.xrea.com/myscripts/index.html#bregexp)とりあえず、マッチした文字列とパターンの()内にマッチしたサブマッチ文字列を得る関数と、置換を行う関数を作った。マッチ結果は、グローバル変数の偽配列として格納することにした。全てのマッチ文字列を検索する関数も作った。マッチした文字列ではなく、マッチ部分の位置を得る機能も作ろうと思ったが、面倒なんでやめた。TransとかSplitも面倒なんで作っていない。BREGEXPでは、処理結果を構造体として保持する。AutoHotkeyでは構造体は使えないので、保持されたメモリ領域から値を取り出す処理を記述してやる必要がある。ヘルプにそれらしいコードがあったが、やけに冗長なのでRtlMoveMemoryというAPIを使って代用した。自前で確保した変数からの取り出しは上手くいったが、BREGEXPの構造体から値を取り出そうとすると0xC0000005番のエラー(メモリのアクセス違反)になる。AutoHotkeyが関数呼び出しのたびにBREGEXP.DLLを開放してしまっているのが悪いらしい。自前でLoadLibrary/FreeLibraryを行うようにしたら、正常にアクセスできるようになった。■Shiftキーを短く押したときに動作するホットキーCtrlキーは元の位置とCapsLockの位置の両方にないと不便なので、AutoHotkeyでMS-IME95互換の英字入力トグルを実現しようと思って作ってみた。Sendで送信している{vkF2sc070}(ひらがな/カタカナ)キーにはATOKのカスタマイズで英字モードOn/Offを割り当てている。Up::if((A_PriorHotkey="~LShift")&&(A_TimeSincePriorHotkeyとりあえず作ってみた。大文字を入力するときに押していたShiftを放したときにも誤作動すると困るので、短く押したときにだけ動作するようにした。長く押したときにも発生する。ShiftキーのキーリピートでLShiftのイベントが繰り返し発生していたのが原因。Shiftを押しながら他のキーを押したときには発生しない。他のキーが押された時点でキーリピートが終了するための模様。図らずも希望の動作に近いものができた。Up::if((ls_state=1)&&(A_TimeSincePriorHotkeyShiftを長く押したときには発生しないようにしてみようと思い、キーリピートでのイベントを区別するようにしてみた。Shiftを押してないときは0、最初にShiftを押すと1になり、キーリピートでのイベントでは2になる。放すときに1なら動作を行い、0に戻す。大体うまくいった気がしたが、ATOKのShift+アルファベットキーで英字入力になる機能をShiftで解除する奴と重複して発生してしまうという問題が。ATOKの方が通常入力に戻した後さらに切り替えを行って再び英字入力になってしまう。仕方ないのでCtrlに割り当てることにした。マウスジェスチャなどが生成するキーボードイベントで誤作動しないように、物理的な押し下げ状態をチェックするようにした。■AutoHotkeyでmigemo.dllを使用する(http://lukewarm.s101.xrea.com/myscripts/index.html#migemo)なんとなく作ってみた。migemoは正規表現を生成するだけなので、別途BREGEXP.DLLも使用する。以前DMonkeyで作ったことがあるので特に苦労はしなかった。BREGEXP.DLLを使用する関数は以前作ったが、新たに書き起こしてひとまとまりの関数群とした。対象文字列がパターンに一致するかどうかを調べる関数だけ作った。サンプルとして一覧をインクリメンタルサーチで絞り込むスクリプトを用意した。■GetSystemPowerStatusでバッテリ容量を取得するAHK036.zip(http://lukewarm.s101.xrea.com/up/file/036.zip)以前作ったが忘れていた。適当に実験的に作ったものなので、あまり実用性はない。結果は適当に文字列として格納されるので、条件判断などに使いにくい。■色々なまず日記(2005-12-04)(http://www.tierra.ne.jp/~aki/diary/?date=20051204#p01)IMEの状態を表示するAutoHotkeyスクリプト。なにやら細かいカスタマイズが可能になっているらしく凄いこだわりようだ。http://www5d.biglobe.ne.jp/~takirin/lineage/line_tips/tips_autohotkey.html(http://www5d.biglobe.ne.jp/~takirin/lineage/line_tips/tips_autohotkey.html)リネージュでマウスの第4,5ボタンを活用するためのAutoHotkey解説らしい。■AutoHotkeyでActiveXを利用しようと思ったけど面倒なんでやめたC言語でCOMクライアント(http://www.asahi-net.or.jp/~kv8s-yjm/another/yja001.htm)というページを見つけたので、DllCallでActiveXを呼び出せないかと思い立つ。内容を見たところ、COMインターフェイスを作成すると、メソッドに対応する関数へのポインタの配列が作成されるらしい。メソッドを呼び出すには、関数のポインタを元に関数として呼び出しを行う必要がある。C言語などなら普通にできることだが、AutoHotkeyにはDLL名と関数名を元に呼び出しを行うDllCallしかないので、ポインタだけわかっても何の役にも立たない。このようなスクリプト言語のために、関数のポインタと引数を与えて関数を呼び出すAPIが用意されていそうな気がするのだが、軽く調べた限りでは見つからない。同様の関数を自前で作ってDLLにすることも考えたが、面倒なんであきらめることにした。そのうちAutoHotkey自体に機能が搭載されることに期待する。■AutoHotkeyで一番手前のウィンドウを一番後ろに持って行くZオーダー順のウィンドウ切り替えを行いたい。後ろのウィンドウを手前に持って来るには、WinActivateBottomを使用すればよいが、手前のウィンドウを後ろに送るのがうまくいかない。WinSet,Bottom,,Aでアクティブウィンドウを後ろに送った後、WinActivateで一番手前のウィンドウをアクティブにすればいいはずだが、これでは常に最前面に居座っているタスクバーがアクティブ化されてしまう。Shell_TrayWnd」を設定してやれば、タスクバー以外で一番手前のウィンドウを対象にできるかと思ったが、どうしてもうまくいかない。ExcludeTitleは「ahk_class」などが使えないという中途半端な仕様だったことを思い出した。タスクバーにはタイトルがないので、ExcludeTitleでは除外できない。Shell_TrayWnd,,XABCDTrayWindowEFGH」のようにして無理矢理タイトルを設定してExcludeTitleで指定できるようにしてやった。タスクバーにはタイトルバーがないので、タイトルを設定しても見た目に変化はない。その他、特に副作用はない模様。■AutoHotkey(http://www.autohotkey.com/)1.0.41「{」や「}」をLoopやIf〜、else、関数定義の最初の行と同じ行に書けるようになった。Ifは「If(式)」のスタイルのみ、Loopは「Loop,回数」の奴のみ。JavaScript系などでは、一行にまとめて書くのが好きだったので、この変更はありがたい。A_AhkPathという変数でAutoHotkey.exeのパスを知ることができるようになった。時々必要になるので便利だ。#IfWinActive/Existという指令で、特定のウィンドウのアクティブ/存在時のみ有効になるホットキーを設定できるようになった。従来だと、IfWinActiveコマンドで分岐して除外したいウィンドウには元々のキーをSendするか、アクティブウィンドウを監視してホットキーの有効・無効を切り替えるなどの方法があったが、割り当てるキーが増えるといちいち記述するのが面倒だった。この指令を使用すれば、条件を1行書くだけで済む。あるソフトがアクティブの時は動作A、その他の場合は動作Bというように、同じホットキーに条件によって別の機能を割り当てるようなことには使えない。特定のソフト使用時のみ起動しておくスクリプトなどでは便利そう。AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)は、とりあえず今回の変更部分の日本語説明を書いた。■AutoHotkeyでタスク切り替えを作ってみた作ってみることに。Alt+Tabに表示するウィンドウをどう判定するかを考える。フォルダオプションなどのダイアログなど、タスクバーに表示されないのにAlt+Tabに表示されるウィンドウがあったり、色々と謎が多い。やっかいなのがDelphi製のソフトのTApplicationというクラス名のウィンドウ。可視ウィンドウ扱いで、タスクバーにはこのウィンドウのタイトルが表示されるが、実際には大きさがゼロで画面には表示されない。VxEditorなど、TApplicationが不可視になっているものもある。Alt+Tabのリストには、実際に見えているウィンドウが表示されるが、中にはTApplicationがAlt+Tabのリストに表示されているらしいものもあってややこしい。ウィンドウスタイルが条件になっているのだろうと思い、条件を調べることに。全てのウィンドウスタイルと拡張スタイルについて、そのスタイルを持つ可視ウィンドウの一覧を列挙するというスクリプトを作成し、Alt+Tabの表示と比較してみたところ、とりあえずWS_DISABLEDになっていると表示されないことがわかった。WS_EX_TOOLWINDOWはAlt+Tabに表示されないという説明があったが、WS_EX_TOOLWINDOWでもAlt+Tabに表示されるものがあるので当てにならない。結局よくわからないので、、適当にそれっぽい物を組み合わせることに。WS_POPUPを除外すれば大体正しくなるが、フォルダオプションのダイアログなどが表示されなくなってしまうので、WS_POPUPなウィンドウで除外したくないものに共通しているスタイルを探したところ、0x80(DS_MODALFRAME)がそれっぽかった。微妙にAlt+Tabとは違う気がするが、面倒なんでこれでいいことにする。リストの表示には、とりあえずリストビューを使ってみる。ウィンドウのアイコンを表示できるようにしてみる。AutoHotkeyの標準機能では、ファイルからアイコンを追加することしかできないが、ImageList_AddIconというAPIでアイコンハンドルを指定して追加することができるらしい。アイコンハンドルは、WM_GETICONメッセージで取得する方法と、GetClassLongというAPIでGCL_HICONを調べる方法があるらしいが、取得できる場合とできない場合がある。両方試して、それでも駄目なら大きいアイコンで代用するようにしたら、ほとんどのウィンドウのアイコンを取得できるようになった。そんなわけで、とりあえず作ったもの。ついでだからウィンドウスタイルなども表示し、プロセス名でソートするようにしてみた。■AutoHotkeyでタイトルバーのクリックした場所によって分岐させるAutoHotkeyのスレッドで話題に上がっていた奴。WM_NCHITTESTという奴でどの座標がどんな部分かを調べられるらしい。AutoHotkeyのSendMessageは当てにならないので、DllCallで直に呼んでやったらうまくいった。この間のアイコンの奴もそんな感じだった。screenとあったのでそのようにした。返り値による分岐では、IsLabelとGoToで擬似的にswitch-caseのような感じにしてみた。y以前、マウスクリックメッセージをOnMessageで処理してウィンドウの好きな場所をドラッグできるようにする方法を考えたが、これもWM_NCHITTESTを処理すれば数行で済むらしい。WM_NCHITTESTはウィンドウ上をマウスカーソルが通過している間中送られてくるので、スクリプト側で処理すると無駄に重くなる気がする。試したところCPU使用率は1%位にしかならなかったので、気にするほどではないか。■AutoHotkeyで"タスクトレイに最小化"AutoHotkeyでは、タスクトレイアイコンは通常一つだけしか持てない。Shell_NotfyIconというAPI関数を使えばアイコンを作成できる。作成したアイコンを操作すると、アイコン作成時に関連づけたウィンドウに指定した番号のメッセージが送られ、作成時に指定したアイコンIDと操作の内容が通知される。これをOnMessageで捉えて、アイコンIDや操作に応じた動作を行えばよい。このあいだのタイトルバーをホイールクリックする奴と、その前のウィンドウのアイコンを取得する奴と合わせて、タイトルバーをホイールクリックすると擬似的にタスクトレイに格納するというのを作ってみた。格納したウィンドウは、トレイアイコンの何らかのクリック動作で復元される。右クリックではメニューを出すようにしようかと思ったが、「復元」以外にコマンドが要らない気がするのでやめた。プログラムが終了するときには自動的にすべてのアイコンを復元するようにした。upにし、カーソル下のウィンドウがアクティブかどうかをチェックする動作を加えた。これにより、タイトルバー上でホイールを押し下げた後、タイトルバー外までカーソルを移動してから放すことで、キャンセルが行えるようになった。クリック系の動作としてはこれが望ましい。Shell_NotfyIconでは、いちいち構造体で情報を与えてやらないとならない。Shell32.dllのバージョンによっては拡張機能が利用できるらしいが、とりあえず一番古くて簡単な奴を使うことにした。操作を通知するメッセージの番号が指定できるようになっている。AutoHotkeyのアイコンでは0x404が使われているようだが、標準アイコンの操作イベントはどうでもいいので、別の番号を指定して自分で作成したアイコンの分だけをOnMessageで捉えるようにした。操作通知メッセージのlParamで通知される操作内容の番号の意味が載っている資料がなかった。第1ビットがマウスボタンの押し上げフラグかと思ったが、違うらしい。0x200がカーソルが通過した0x201:左ボタンを押した0x202:左ボタンを放した0x203:左ダブルクリック0x204:右ボタンを押した0x205:右ボタンを放した0x206:右ダブルクリック0x207:中ボタンを押した0x208:中ボタンを放した0x209:中ダブルクリックまでは調べた。第4,5ボタンは利かないっぽい。なんで0x200番からなのかはよくわからん。■タスク切り替えの奴の改良038.zip(http://lukewarm.s101.xrea.com/up/file/038.zip)色々と改良した。ウィンドウが非アクティブになったら終了するようにした。WM_ACTIVATEをOnMessageで捕らえて、非アクティブ化だったら終了する。ウィンドウのスタイルなどを色々と変更。タイトルバーを無くして、タスクバーに表示されなくし、常に最前面に表示するように。リストでは、一旦タイトルでソートしてからプロセス名でソートし、Z順位にかかわらず同じ並びになるようにした。リストビューをポイントして選択しクリックで決定する奴にした。決定時にAutoHotkeyのイベントが発生するのが遅いので、自前でリストビューの決定通知を受け取るようにした。リストビューの項目が決定された場合、WM_NOTIFYで情報が送られてくる。詳細は構造体に格納されているので、RtlMoveMemoryで取り出して判定することに。イメージリストは、アイコンのサイズがシステムに依存しているようなので、自前でImageList_Createを行ってフォントサイズに合わせたアイコンサイズにするようにした。ついでに、大きいアイコンとフォントのバージョンを作成した。大きい方がマウスで選択しやすくて良いが、表示速度や画面の専有面積などが気になる。常駐版では、2回目以降の表示の際、ウィンドウのZ順位が他のウィンドウの下になっていて、一旦可視状態になってから最前面に移動するのが鬱陶しいので、SetForegroundWindowでZ順位を一番上にしてから表示させるようにした。リストビューの項目の幅などはすべて固定にして、ウィンドウ表示時の処理をできるだけ削減したら、かなり一瞬で表示されるようになった。割り当てるホットキーは、せっかく5ボタンマウスを買ったのに未だ使い道の定まっていないXButton1に割り当ててみた。ついでに、XButton1を放したときにリスト上なら決定、リスト外ならキャンセルを行うようにした。MButtonで選択ウィンドウを閉じるという機能も付けた。■AutoHotkeyで起動したプロセスの標準入出力を読み書き039.zip(http://lukewarm.s101.xrea.com/up/file/039.zip)作ることに。CreatePipeでパイプを作って、それをセットしてCreateProcessしてやればいいらしい。見つけた資料に従って作成した。CreateProcessが失敗する。知らんが、STARTUP_INFOを0で埋めて作成するようにしたらうまくいった。資料のコードは0で初期化されることを前提に書かれていたようだ。CreateProcessで使うPROCESS_INFOにプロセスハンドルやIDが入るらしい。こちら側で使うためのパイプハンドルをどこに保持しておくかで迷ったので、とりあえずこいつの後ろに12バイト余計に確保して、そこに置いておくことにした。関数利用側は、このPROCESS_INFOのポインタだけを保持しておけばいいことになる。入力への書き込みは適当に作ったら動いた。sortのようなプログラムにテキストデータを与えるときは、入力の終わりを知らせてやらないと、出力を行ってくれない。入力のハンドルを閉じたら、出力を開始してくれたので、入力ハンドルだけを閉じる関数を用意した。パイプからデータが送られてくるときの動作がよくわからない。入力待ちで相手プロセスの出力が停止していることと、出力の最中でデータの途中までがパイプに入っていることをどうやって見分けるのか?とりあえず、PeekNamedPipeでパイプに残ったデータの量を調べて、50ミリ秒の間増加しなければ出力が停止しているとみなすことにした。これでcmd.exeとかと対話できるようになった。使う機会があるかは不明。pingのように小出しに出力を行うプログラムは、終了を待ってから一気に読みたいので、GetExitCodeProcessで終了まで待つ関数を用意した。作成途中、関数がエラーを返すことがあったので、GetLastErrorでエラーコードを調べようとしたが、常に127番になってしまう。調べてみたら「指定したプロシージャが見つかりません」と言うことらしい。DllCall自体は成功しているので不審に思い、「DllCall("kernel32.dll\GetLastError")」としてみたところ、エラーコードが変わった。モジュール名を指定してやらないと、デフォルトのモジュールを一つずつ調べて当該関数が呼び出せるかを試しているらしい。効率化したい場合は、必ずモジュール名を指定してやった方がいいようだ。モジュール名を指定してやってもなお、DllCall内で何らかのエラーが発生しているようで、GetLastErrorで正しいエラーコードを知ることができない。■AutoHotkeyスクリプトの高速化SendMessageには、コマンドで送る方法とDllCallで送る方法がある。%hwnd%」の解釈が行われるが、遅くならないのか?以下のスクリプトで試してみた。%myhwnd%}l2:=A_TickCount-tc結果は、1079対172でコマンドの方が圧倒的に速かった。次に、コマンドの方でLastFoundWindowを利用したらどうなるかを調べた。%myhwnd%{DetectHiddenWindows,Offtc:=A_TickCountLoop,200000{SendMessage,0,0,0}l2:=A_TickCount-tc}234対125で、LastFoundWindowを使った方が高速なことがわかった。IfWinExistを1行増やすと、その分遅くなるはずである。以下のようにして、内側で何回ウィンドウ操作を行ったら、IfWinExistを使った分の元を取れるかを計測した。%myhwnd%{SendMessage,0,0,0SendMessage,0,0,0}}l2:=A_TickCount-tc内側が1回の時、828対859で、IfWinExistを使った方が遅くなった。2回にすると、1578対1375でIfWinExistを使った方が速くなる。次に、DllCallの気になる部分を調べる。引数の型は「Int」のようにするのと「"Int"」のようにするのがあるが、どっちが速いか。tc:=A_TickCountLoop,20000{DllCall("SendMessage",UInt,myhwnd,UInt,0x0,UInt,0,UInt,0,UInt)}l1:=A_TickCount-tctc:=A_TickCountLoop,20000{DllCall("SendMessage","UInt",myhwnd,"UInt",0x0,"UInt",0,"UInt",0,"UInt")}l2:=A_TickCount-tc1047対296で、文字列として渡した方が圧倒的に速くなる。次に、モジュール名を省略しなかったらどうなるか。tc:=A_TickCountLoop,100000{DllCall("SendMessage","UInt",myhwnd,"UInt",0x0,"UInt",0,"UInt",0,"UInt")}l1:=A_TickCount-tctc:=A_TickCountLoop,100000{DllCall("User32.dll\SendMessageA","UInt",myhwnd,"UInt",0x0,"UInt",0,"UInt",0,"UInt")}l2:=A_TickCount-tc1500対1360で、できるだけ詳しく指定した方がほんの少し速くなる。返り値を得ないとき、最後の返り値の型指定を省略したらどうなるか。tc:=A_TickCountLoop,100000{DllCall("User32.dll\SendMessageA","UInt",myhwnd,"UInt",0x0,"UInt",0,"UInt",0,"UInt")}l1:=A_TickCount-tctc:=A_TickCountLoop,100000{DllCall("User32.dll\SendMessageA","UInt",myhwnd,"UInt",0x0,"UInt",0,"UInt",0)}l2:=A_TickCount-tc1470対1359で、返り値の型を省略した方がほんの少し速かった。高速化したDllCallと、SendMessageコマンドで、返り値を変数に格納する速度を計測する。%myhwnd%r=%ErrorLevel%}l2:=A_TickCount-tc141対94で、やっぱりコマンドの方が速かった。「var2:=var1」による代入と「var2=%var1%」による代入ではどっちが速いか。%myhwnd%r:=ErrorLevel}l2:=A_TickCount-tc875対860で、:=の方がごくわずかに速かった。定数を代入する場合はどうか。tc:=A_TickCountLoop,1000000{r=100}l1:=A_TickCount-tctc:=A_TickCountLoop,1000000{r:=100}l2:=A_TickCount-tc391対390で、ほとんど変わらない。加算する場合はどうか。r=0tc:=A_TickCountLoop,1000000{r+=1}l1:=A_TickCount-tcr=0tc:=A_TickCountLoop,1000000{r:=r+1}l2:=A_TickCount-tc937対1188で、「+=」の方が速い。変数をいくつも足すような場合はどうか。x=200tc:=A_TickCountLoop,100000{r=100r+=%x%r+=%x%}l1:=A_TickCount-tctc:=A_TickCountLoop,100000{r:=100+x+x}l2:=A_TickCount-tc足し算の場合、1回の時は985対1015で「:=」の方が遅かった。2回足した場合、1547対1188で「:=」の方が速い。文字列の連結はどうか。"x"}l2:=A_TickCount-tc47対13312で「=」の方が圧倒的に速い。複雑な式の場合はどうか。x=200y=400z=10tc:=A_TickCountLoop,100000{r=100r+=%x%r*=%y%r/=%z%}l1:=A_TickCount-tctc:=A_TickCountLoop,100000{r:=(100+x)*y/z}l2:=A_TickCount-tc266対468で、やはり「:=」は遅かった。■AutoHotkeyのListViewをいじるDllCallでImageList_Createを行えば、任意のサイズでアイコンを表示できる。画像の縮小表示と組み合わせれば、任意のサイズの画像サムネイルが可能かと思って試してみたら、可能だった。,"aaaaaaaa")Gui,ShowExtractAssociatedIconAというAPIを使えば、ファイルやフォルダの関連づけアイコンを取得できるらしい。このAPIにはなぜか呼び出し元プロセスのインスタンスハンドルが必要だが、GetModuleHandleというAPIで取得できるという。試してみたら、確かに関連づけアイコンが取得された。,"aaaaaaaa")Gui,Show,AutoSizeこれをこのあいだのタスクリストの奴に組み込んで、何が何でもウィンドウのアイコンを取得できるようにしておくことに。Alt+Tabの奴とはどうしても違ってしまうが、フォルダオプションのウィンドウなどもアイコンが表示されるようになった。ALt+Tabの奴はどうやってアイコンを取得しているのだろうか?■可能な限り正確にマウス下のコントロールを操作するマウスホイールの操作をカーソル下のコントロールにリダイレクトするツールをAutoHotkeyで再現したい。カーソル下のウィンドウとコントロールはMouseGetPosで取得できるが、タブブラウザのようなMDIコントロールの子ウィンドウが最大化されている場合などに誤認識が起こる模様。いつ頃からかAltMethodというパラメータが追加され、MDI子ウィンドウに正確に対応できるようになったが、これを利用すると逆に誤認識を起こす場合がある。HTMLヘルプのウィンドウの「キーワード」ペインのリストなどがそうだった。このあいだ使ったWM_NCHITTESTでカーソルがコントロール上かを判定して、おかしかったら非AltMethodで取得し直すようにしてみたら、MDIもHTMLヘルプも正確に操作できるようになった。AltMethodと通常方式の順番を逆にすると、MDIで誤認識する。%hwnd%return色々と適当な感じだが、とりあえず大体のコントロールを操作できるようになった。この例ではfwKeysの処理を省略してあるので、Shift+ホイールでIEコンポーネントの戻る・進むを行うなどの機能が利用できない。このホイールリダイレクト機能では、正確にカーソルをコントロール上に合わせてやらないとならず、小さなコントロールを操作しづらい。カーソルがどこにあってもアクティブなコントロールを操作できる通常の動作の方が好きだ。■もこ窓(http://tomo.panicode.com/)をAutoHotkeyでパクる040.zip(http://lukewarm.s101.xrea.com/up/file/040.zip)ウィンドウを縮小してしまう「もこ窓」のようなものをAutoHotkeyで実現する。ウィンドウの描画に使っているデバイスコンテキストを取得し、リサイズしながらコピー描画する「StretchBlt」APIを実行すればいいはずなのだが、これだと他のウィンドウに隠れている部分などが正しく描画されない。もこ窓のソースを見てみたところ、本来のウィンドウを非表示ではなく「完全に透明」にしていた。試しに真似してみたところ、なぜかウィンドウが見えなくても全体の画像がコピーされた。GetWindowDCの説明によると、ウィンドウの種類によって取得されるDCが違うらしい。半透明の時は全体のバッファが格納されたDCが得られるのだろう。DCへの直接描画は、そのままでは自動で再描画されないので、他のウィンドウに隠されたりすると、その部分が永久につぶれてしまう。WM_PAINTメッセージをOnMessageで処理して自前で再描画するようにした。対象ウィンドウのフィルタリングとかは面倒くさいので、このあいだの「タスクトレイに最小化」のようにタイトルバーのホイールクリックで縮小するようにした。その気になれば縮小ウィンドウを自由にリサイズしたりすることも実現できるが、面倒なんでやめた。■AutoHotkey虫眼鏡041.zip(http://lukewarm.s101.xrea.com/up/file/041.zip)昨日のStretchBltを応用すれば、画面を拡大することも可能なはずである。そこで、「拡大鏡」のようなマウスカーソル周辺を拡大するツールを作ってみる。デスクトップ全体を対象にしたいので、「GetDesktopWindow」でデスクトップ全体のハンドルを得る。描画はタイマーで行うようにし、基本部分はあっさりできた。透過ウィンドウのDCが特殊になっていたことを思い出し、自分のウィンドウをTrans,255にしてみたところ、自分のウィンドウが映らず、後ろの映像が拡大されるようになった。透過ウィンドウは一般ウィンドウ群のDCからは隔離されていて、描画時に合成処理されるのだろう。拡張スタイルの0x00080000を指定することで、マウスクリックをカーソル下に透過させるようにし、ウィンドウがマウスカーソルに追従するようにしてみた。AlwaysOnTopで常に最前面に表示されるようにしているが、新たに表示されたメニューなどの最前面ウィンドウに負けてしまう。そこで、描画時にWinSet,Topで最前面に移動してやるようにした。メニューより前に表示されるようになった。そんな感じで、かなり虫眼鏡っぽくなったが、使いやすいかどうかは不明。■AutoHotkeyでGUIウィンドウの空いている番号を検索AutoHotkeyのGUIでは、複数のウィンドウを番号で区別し、99個までのウィンドウを生成できる。指定がなければ、1番のウィンドウが使われる。複数のスクリプトを組み合わせて使う場合には、番号が衝突しないように修正しなければならない。いちいち修正しなくていいように、空いている番号で新たにGUIウィンドウを作れるような仕組みを作ることに。「その番号のウィンドウが存在しなければ、その番号は空いている」とみなすことを考えたが、GUIウィンドウが生成されているかを調べる機能はないし、「Gui,+LastFound」等を行うと、その時点でウィンドウが生成されてしまう。そこで、あらかじめ自分のプロセスのGUIウィンドウのハンドルを列挙しておき、取得したGUIウィンドウのハンドルがその一覧に無ければ、そのウィンドウは新たに作られたものであると判断するようにした。■AutoHotkey(http://www.autohotkey.com/)1.0.42アクティブウィンドウなどの条件でホットキーの動作の有無を切り替える機能が改良され、同じホットキーに条件によって別の動作をさせることが可能になったらしい。■AutoHotkeyでプログラムファイルの説明などを取得あまり使い道なさそうだが、とりあえず作ってみた。■AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)更新ウィンドウの条件ごとに別のホットキーアクションを割り当てられるようになったので、とりあえず#Ifwin...(http://lukewarm.s101.xrea.com/commands/_IfWinActive.htm)とHotkey(http://lukewarm.s101.xrea.com/commands/Hotkey.htm)の部分だけ更新した。Scripts(http://lukewarm.s101.xrea.com/myscripts/index.html)に今までに作ったスクリプトを適当に掲載した。ホイールリダイレクトの奴は、fwKeysの部分をちゃんと作って、Ctrl+ホイールとかもリダイレクトされるようにした。■AutoHotkey(http://www.autohotkey.com/)1.0.42.03DllCallを実行した後、「A_LastError」変数でGetLastErrorの値を参照できるようになったらしい。内容はエラーコードの数値なので、エラーの内容を知るには以下のような感じにする。なんか知らんが、エラーコードに対応するエラーメッセージをシステムから取り寄せているらしい。buf}DllCallの最後に毎回GetLastErrorを行っているようだが、そもそもDllCallの時にLastErrorの値が変わってしまう部分を何とかしてくれればいいような気がするのだが。■AutoHotkeyでタスクトレイアイコンを直接操作TaskTrayIcon.zip(http://lukewarm.s101.xrea.com/myscripts/TaskTrayIcon.zip)TrayCommand(http://hp.vector.co.jp/authors/VA026310/)のように擬似的にタスクトレイアイコンの操作イベントを発生させたりするために作ってみた。タスクトレイにアイコンを登録するとき、タスクトレイアイコンの操作イベントが発生したときに通知するウィンドウのハンドルと、そのときに送るウィンドウメッセージの番号、複数のアイコンがあるときに識別するための番号などが登録される。これらの情報が分かれば、スクリプトからタスクトレイアイコンの操作イベントを発生させることが可能になるはずである。TrayCommandの動作を見たところ、タスクトレイのアイコンが表示されているToolbarWindow32からTB_GETBUTTONメッセージで情報を取得しているらしい。TB_GETBUTTONでは、ツールバーの項目の情報を格納した構造体が得られるらしい。構造体にはdwDataというメンバがあり、アプリケーションが独自に何らかのデータを関連づけておけるようになっている。ここにウィンドウハンドルやアイコンの識別番号、メッセージなどが格納されているのだろう。構造体のデータ構造がよく分からなかったが、TrayExpandのソースを調べたら見つかった。Shell_NotifyIconで使われている構造体とは構造が違うようだが、内部データ用の形式だろうか?このような情報はどこで仕入れてくるのか。hIcon;}TRAYNOTIFY;これで、必要な情報と、ついでにアイコンのハンドルが得られそうだ。他のプロセスからウィンドウメッセージなどで構造体のデータをやりとりするときは、VirtualAllocExで当該プロセスに共有メモリを確保し、そこにデータを受け取ってからReadProcessMemoryで読み取らなくてはならないらしい。うっかりGlobalAllocで確保したメモリに受け取ろうとしたら、エクスプローラがメモリアクセスエラーで不正終了してしまった。アイコンの数については、TB_BUTTONCOUNTメッセージで簡単に取得できる。そんな感じで、任意のトレイアイコンの情報を取得する関数と、アイコンの数を取得する関数を作成した。アイコンの数だけループして、条件に一致したときに指定の操作イベントを通知するようにすれば、TrayCommandのように指定したアプリケーションのトレイアイコンを操作することができるようになる。プロセスの実行ファイルパスを取得する関数をコピーしてくるのが面倒だったので、サンプルでは「WinGet,pn,ProcessName」の結果のプロセス名を使用して判定するようにした。TrayExpandのようにアイコンを隠す機能も作ろうと思ったが、TB_HIDEBUTTONで非表示にすると、消したアイコンの分のスペースが空いてしまう。そこで、Shell_NotifyIconで状態を非表示に設定することにした。これなら、スペースをちゃんと調節してくれる。Shell_NotifyIconに与える情報は、先ほどの関数で取得したhWndやuIDを使用すればいい。別のプロセスのアイコンの状態を勝手に変更できてしまうとは、結構いい加減なAPIだ。ついでに、TB_MOVEBUTTONでアイコンの順番を入れ替える関数も作った。スタートアップの実行タイミングやプログラムの再起動でアイコンの順番が変わってしまうのは鬱陶しいので便利かも。■AutoHotkeyでfenrir風の物を作る042.zip(http://lukewarm.s101.xrea.com/up/file/042.zip)パフォーマンス的に可能かどうかを試すために作ってみた。フォルダをスキャンする部分は、Loopとかを適当に使ってできた。複数のファイルマスクを指定できるようにするのが面倒だったので、BREGEXP.DLLの正規表現で判別するようにした。スキャン結果の書き出しでは、FileAppendを使った。FileAppendは1回ごとに出力先ファイルを開き直すためパフォーマンスが悪いが、ファイルを1行ずつ読む「Loop,Read」でOutputFileを指定しておくと開きっぱなしにしてくれる。いちいち何かのファイルを開かないと利用できないので困る。スキャン対象のフォルダをテキストに列挙して、それをLoop,Readし、OutputFileにスキャン結果のファイルを指定するようにした。DllCallを使えば、開きっぱなしにしたファイルに追記していくこともできるが、DllCallの処理が遅いようなので、できるだけ標準の機能を使うことにした。スキャン速度は、とりあえずfenrirより劇的に遅いということはなかった。検索部分では、スペース区切りで列挙されたキーワードの部分一致検索のみを実装した。入力内容の末尾に文字が追加された場合だけ、前回の検索結果からの絞り込みを行うようにした。6000ファイルくらいある時でも、それなりの早さで検索できた。当初、試しにMigemoを付けてみたところ、やたらと遅くなった。絞り込み検索を行うようになっていなかったのと、入力文字が1文字だけでもMigemoで検索していたのが原因のような気がする。フォルダ内のファイルを候補として表示する機能も付けた。数百ファイル程度ならそれなりの速度で展開できる。一度実行したファイルは、スキャン結果ファイルとは別に書き出しておくようにした。このファイルでは、Tabで区切ってキーワードを記述できるようにした。最後のTabより後がファイルパスの本体になる。検索結果項目を実行するときは、単にRunに引数として与えているだけなので、コマンドライン引数を含めて記述することも可能な気がする。一通りの機能を付けてみた。起動速度なども、とりあえず実用的な速度になっているような気がする。fenrirはあまり使っていないので、その他の細かい挙動の違いなどは不明。■fenrir風の奴の改良045.zip(http://lukewarm.s101.xrea.com/up/file/045.zip)・複数ファイルの選択に対応Ctrl+上下やCtrl+Space、Shift+上下で複数選択ができるようにした。AutoHotkeyのListBoxでは、なぜかCtrl+上下が利かない。LB_系のメッセージを使って実現することに。入力欄にフォーカスがあると、リストボックスのフォーカスが見えない。仕方ないので、移動しながら選択を反転するようにした。通常の動作とは異なってしまうが、とりあえずどこを選択しているのかは分かるようになった。その他、Ctrl+Aで全選択なども付けた。コマンドなどの引数展開で、選択ファイルを半角スペース区切りで列挙した物や、改行区切りで列挙した物をセットするようにした。内部コマンドのスクリプトはかなりシンプルに書けるので、ユーザーが自分で追加することも簡単だろう。%Items%」でアイテムリストをクリップボードにコピーするなど、色々と可能になった。・/で始まる入力時にコマンドモードに移行するように・コマンド選択モードの仕様をコマンド名と引数を直接入力するように変更コマンドモードを割と直感的に使えるようになった。コマンドモードに移行しても、コマンドの一覧が表示されるだけで、直接入力するのとあまり変わらないが。%Items%」などのコマンドを素早く再実行したいときに便利かも。内容が短いので検索しにくいかもしれないが。・入力を行うと絞り込みが行われなくても選択状態が解除されるのを修正これにより、上下キーでリストから選択を行った後にコマンドを入力して実行できるようになった。■fenrir風の奴の改良046.zip(http://lukewarm.s101.xrea.com/up/file/046.zip)・Migemo使用時にスキップマッチングを利用できるようにしたMigemoには「改行やスペースの連続」にマッチする正規表現を指定することで改行をまたいだ検索が行われる正規表現を生成するという機能がある。ここに「[^\\]*」などと指定すると、キーワード中の任意の部分を省略できるスキップマッチングが実現できる。「ahk」で「AutoHotkey」にマッチしたりするようになる。検索結果数が増えるため、多少遅くなっているような気がする。・スキャンデータのリムーバブルドライブ対応USBメモリなどのリムーバブルドライブや、CD-ROMなどの光学メディアなど、ドライブ文字が変わったりドライブに挿入されているメディアが変わったりする場合に対応できるようにした。ドライブ文字の代わりにメディアのシリアルナンバーを保存し、実行時に当該メディアを検出してパスを生成する。面倒なんで正規表現オペレーター文字を含んでいる単語を片っ端から削除することに。9割方顔文字などのゴミデータなので問題ないだろう。ついでに、無駄に長い単語も削除するようにした。「\\」で全角文字を誤検出するので、BREGEXP.DLLで検査するようにした。・読み込み専用のサブインデックスファイルを指定する機能を追加LAN上のフォルダなどをインデックス化しておいて、複数のPCから参照したりできるようにした。・スキャン時に対象フォルダの古いインデックスを削除するようにした・/scanallコマンドを実装し、scan.txtの仕様を変更したフォルダごとに個別に正規表現フィルタなどを設定できるようにした。ついでに、スキャンを行う最低間隔を指定する機能も付けてみた。一時リストのメモリをVarSetCapacityであらかじめ確保するようにしたら高速化された気がする。・フォルダ展開時の駄目文字問題を修正なんかA_LoopFileNameは自前でパスを区切っているらしく、2バイト目が「\」の全角文字に誤反応しやがるので、スクリプト側で親ディレクトリパスの長さ分削除してファイル名部分を切り出すようにした。修正しようとスクリプトを弄っていたら、GUIウィンドウを表示した直後にメモリアクセス違反で不正終了するようになってしまった。追加した行を削ると問題なくなり、別の場所に別のコードを追加しても駄目になる。スクリプトが長くなりすぎた所為で不具合が起こっているのか。同じ行を10000行ほど並べたスクリプトでGUIウィンドウを表示してみたが、不正終了はしなかった。発生条件がはっきりしなくて困る。エラーはGui,Showの中で起こっている模様。問題のGui,Showのオプションを色々変更してみたところ、エラーが発生しなくなることがあった。表示動作に影響しないパターンを探して、とりあえずエラーはなくせた。どのような原理でこんな気まぐれな不具合が発生するのか。EditionでAutoHotkeyをビルドするスクリプトが肥大化してきたら気まぐれで発生するようになった謎のエラーを何とかしたい。エラー内容を見ると、「0x0000000f」というアドレスを参照しているらしい。0x00000000ではないということは、構造体へのポインタがnullの時にメンバを参照しようとしているのだろう。そんなわけで、ソースコードから問題の箇所を探そうとしたが、やたらと長大で挫折した。デバッグ実行でエラーを発生させて問題の箇所を見つけてみることに。VC7向けに作られているらしく、手持ちのVC6.0ではコンパイルできなかったので、無償提供されているVC2005EEを使うことに。XPのSP2にしかインストールできないということで、サブマシンにインストールする。DaemonToolsで配布isoイメージをマウントしてインストールを行い、AutoHotkeyのプロジェクトをインポートしてみたが、windows.hがないとか言われてビルドできない。PlatformSDKがインストールされなかったらしい。一緒に使う(http://www.microsoft.com/japan/msdn/vstudio/express/visualc/usingpsdk/)というページに従ってインストールする。合わせて50分くらいかかった。ビルドを試みると、死ぬほど警告が表示された。プロジェクトの設定で警告を切ると、いくつかのエラーが残った。suffix」という宣言が利いていない問題は、言語の拡張設定で直った。char*をchar*に変換できないというエラーは、よく分からないので引数からconstを削除して黙らせた。宣言の型が指定されていない部分がいくつかあったが、適当にintと書き足したら大人しくなった。コンパイルは成功するようになったが、リンク時にリソースが重複しているとか言われてビルド完了できない。設定で埋め込みマニフェストを無効にしたら、とりあえず回避できた。そんなわけで、とりあえずビルドできたので、問題のあるスクリプトを実行させてデバッグしてみる。GUIウィンドウが表示されてエラーが発生すると、実行中だった箇所や関数の呼び出し元、変数の内容などの情報が表示された。思った通り、nullなオブジェクトの関数を呼び出している部分があった。関数のローカル変数の情報を格納するオブジェクトのアドレスを格納する部分が、不正にnullになっているらしい。通常は正しいアドレスが格納されていたので、どこかで上書きされてしまっているのだろう。いつnullになってしまうのか調べるため、ブレークポイントを仕掛けてそのアドレスの変更を監視したところ、strlcpy関数で文字列のコピーを行っているときに上書きされてしまっているらしいことが分かった。問題の箇所はscript.cppの以下の部分。//!!!!!!!!!!!!!!!!!aBufの指すアドレスにMAX_PATHを足すと、ちょうどnullになってしまった領域をまたいでいる。aBufとして確保されている領域のサイズを考慮せずにMAX_PATH文字をコピーしてしまっているのが原因らしい。呼び出し元を追跡すると、その変数の領域は64バイトしか確保されていないらしかった。strlcpyが元の文字列の終端以降もコピーを行うのは妙な気がするが、Wikipediaの説明には指定されたサイズを超えないとしか書かれていないので、サイズ分丸ごとコピーされても文句は言えない。思ったら、よく見たらutil.hの中で自前で定義されていて、strncpyに丸投げされていた。VCのstrncpyの説明にはコピー元の文字列が短かった場合は残りの部分を\0で埋めると書いてあったので、正しい動作らしい。そんなわけで、原因はおおよそ特定できたが、改善策を考えるのが面倒なのであきらめた。作者が適当に修正してくれることを祈る。スクリプトの方は、適当にダミーの関数を追加したらとりあえず動くようになった。いつ駄目になるか分からないので困る。■AutoHotkey(http://www.autohotkey.com/)1.0.42.06がんばって英文を書いて公式のバグレポートに報告したところ、strncpyのバグが修正されたようで、問題のあったスクリプトが正常動作するようになった。■fenrir風の奴を修正049.zip(http://lukewarm.s101.xrea.com/up/file/049.zip)AutoHotkeyのバグが修正されて、エラーを気にせずに機能拡張できるようになったので、いくつか気になっていたところを改良した。・上下キーでの移動の際、リストの上下をループするように10個くらい候補があるときに下の方の項目を素早く選択したくなったので、一番上で↑キーを押したら一番下に行くようにした。「/a」コマンドで日本語のタイトルを付けようと思ったら失敗したので気づいた。ImmGetCompositionStringで変換中の文字列があったら、確定を行わないようにした。・存在しないファイルを選択したとき、即座にインデックスから削除するようにしたついでだから、上位フォルダのパスをチェックして、存在しない最上位階層からまとめて削除するようにした。・「-」を付けると除外検索になるようにノイズをまとめて消せるようにしたい。1文字打つごとに前回の結果から絞り込む現在の方式では、「-t」と打った時点でtを含む全ての項目が消されてしまい、「-tx」になっても「tx」を含まずに「t」を含む項目が消えたままになってしまう。除外検索があるときだけ、全候補から全キーワードで絞り込むようにすることも考えたが、打つたびに候補が増えていくというのは気にくわないのでやめた。」のようにスペースを打った時点で前の除外ワードによる絞り込みが行われるようにした。「/scan」とか「-dict」のように特殊なキーワードと解釈されてしまう場合に「+/scan」「+-dict」のようにすることで検索できるようにした。■タスクトレイアイコンをキーボードで操作するAutoHotkeyスクリプトTrayIconList.zip(http://lukewarm.s101.xrea.com/myscripts/TrayIconList.zip)ノートPCで使うために作った。プロセス名とツールチップテキストをリスト表示し、キー操作に応じてダブルクリックや右クリックなどの動作を行うように。左手だけで操作できるように、Tab/Shift+Tabにカーソル移動を、Ctrl+S/D/Rに各クリック操作を割り当てた。当初は、修飾キー無しのアルファベットキー単独で操作できるようにしようかと思ったが、リストビューの方でインクリメンタルサーチが提供されていることに気づいたので、そっちを生かすことに。一部のソフトでメニューにフォーカスが当たらなくて悩んだが、メニューの親ウィンドウにフォーカスをやればアクティブになるようだった。非常駐でできるだけ高速化することに。トレイアイコン情報取得は、このあいだ作ったモジュールを使わず、無駄な処理を省くようにした。タスクトレイアイコン操作(http://lukewarm.s101.xrea.com/myscripts/TaskTrayIcon.zip)のモジュールの方は、ツールチップテキストを取得する関数を追加した。■AutoHotkeyシステムモニタ用関数群(http://lukewarm.s101.xrea.com/myscripts/SystemMonitor.zip)作った。当初、RegQueryValueExでHKEY_PERFORMANCE_DATAから構造体を取得するという面倒くさそうな話を聞いていたが、PDH.DLLという物のAPIで簡略化できるらしい。サンプルを移植して動かしてみたが、システム全体のCPU使用率が取得できないし、なぜかカウンターを登録するときに以上に時間がかかるし、特定のプロセスIDの状態を監視するのも面倒くさそうで気に入らない。その後、GetSystemTimes、GetProcessTimes、GlobalMemoryStatus、GetProcessMemoryInfo等を使えば普通に取得できることが分かる。適当に作った関数でも、十分な速度で動作している模様。PDH.DLLの存在意義が疑われる。■AutoHotkey用システムモニタ用関数群(http://lukewarm.s101.xrea.com/myscripts/SystemMonitor.zip)更新PDH.DLLのAPIでは様々な情報が取得できるが、.Netの奴の何かなど、訳の分からないものやどうでもいい物が大半だった。ディスクのアクセス量なども取得できるらしいので、とりあえず関数を作ってみることに。取得したい情報はパス文字列で指定しなければならない。PdhBrowseCountersというAPIで項目を選択するダイアログが出せるとのことなので、それを呼び出す関数を作成した。ディスクのアクセス率を取得してみると、それらしい物が取得できた。アクセス率とアイドル率を足して100にならないなど怪しいところはあるが、気にしないことにする。次に、ネットワークの使用率を取得してみる。パス文字列にはネットワークインターフェイスの名前が含まれる。interface」というのと、PCに接続されたNICらしき物の2つがある。実際に必要なのはNICの方だが、PCによって違うので、何らかの方法で取得しなければならない。PDHのAPIで自動取得できるようにするのは面倒だったので、以下のような方法で取得取得してもらうことにした。%tmp%\route.txt,,HIDEFileReadLine,nic,%tmp%\route.txt,4StringTrimLeft,nic,nic,32FileDelete,%tmp%\route.txtとりあえずパス文字列ができたのでモニタリングしてみたが、なぜか値がおかしい。テストダウンロードを行っているIrvineの示している転送量の70%くらいの値になってしまう。Windowsの管理ツールにあるパフォーマンスモニタで監視しても同じなので仕様だろう。TClockのソースを見たら、ネットワーク転送量はiphlpapi.dllというDLLの関数で取得していることが分かったので、せっかくだから移植してみることに。データを受け取るのに必要なバッファが10KBくらいあって気持ち悪い。構造体の定義もややこしく、メンバのアドレスオフセットを計算するのが面倒なんで、VCで適当に「printf("%d\n",(int)(&(st.dwInOctets))-(int)(&st));」のようなコードを書いて実行して調べた。その他は、他のモニタリング関数と同じような感じで適当に作ったら動いた。サンプルスクリプトも作ることにした。ラベルとプログレスバーで情報を表示し、背景を透過して文字だけが浮かんでいる状態にし、最前面に表示するようにした。取得できる情報を片っ端から表示することに。HDDの情報は、ドライブの数だけ列挙する。ついでに、DriveSpaceFree命令などを利用してHDDの空き容量も表示できるようにした。フォントなどを工夫したら、それなりに見栄えのするシステムモニタができた。ドライブが7つもあると無闇に縦長になってしまって邪魔だが。スクリプトのメモリ使用量が15MBを超えていて、あまり実用性はない。■AutoHotkey製コマンドラインランチャーの奴を更新FileLaunch.zip(http://lukewarm.s101.xrea.com/myscripts/FileLaunch.zip)飽きてきたので正式版っぽい感じにしてスクリプト公開ページに載せた。追加せっかくBREGEXP.DLLを使っているので、任意の正規表現で検索できるようにした。or検索とか、任意の数字列を含むファイルを検索とか、たまに役立つかもしれない。タイプの途中でマッチングが行われると困るので、除外検索の時と同じように後ろにスペースを打つまでは検索されないようにした。・ファイルの名前部分のみから検索する機能を追加AutoHotkey.exeを実行したいのにAutoHotkeyフォルダ内の全てのファイルが列挙されたりすると鬱陶しいので付けてみた。パスを区切るのが面倒なんで、正規表現を生成して検索するように。・デフォルトの検索モードを変数で指定するようにMigemoを頻繁に使う時でもいちいち「:」を付けるのは面倒なので、デフォルトの検索モードを変更できるようにした。SMode=:」のようなコマンドでも変更できる。「@rm」で「readme.txt」を検索するなど、短縮ワードによる検索を可能にした。正規表現検索モードなども割り当てられるので、「@ahk」で「AutoHotkey」か「.ahk」を含むアイテムを検索すると言ったことも可能。検索モード指定文字は打ちやすいようにShiftと組み合わせないキーにしたかったが、ファイル名に使われない文字ではMigemoに割り当てている「:」しか無かったので、あまり使われなさそうで打ちやすい位置にある「@」を割り当てることにした。■AutoHotkey製コマンドラインランチャーの奴を更新FileLaunch.zip(http://lukewarm.s101.xrea.com/myscripts/FileLaunch.zip)・ドラッグ&ドロップでファイルを追加できるようにマウス操作はあまり必要ないだろうが、一応付けた。・起動時や多重起動時に任意の動作を実行させる機能を追加スクリプト中で番号にコマンドやサブルーチンを割り当てておいて、ウィンドウメッセージで実行させるように。メッセージを送るウィンドウを検出するのが面倒だったので、スクリプト起動時にIniファイルに書き込んでおくようにした。スクリプト以外のプログラムからも任意のコマンドを実行させられるように、Iniファイル経由でコマンドを指定する機能も付けた。上記の機能で使用するための物や、スキャンリストにフォルダを追加する物など、いくつか追加した。拡張子ごとにファイルを開くプログラムを振り分けるようなコマンドを定義できるようにしようかと思ったが、面倒なんで内部コマンドとして記述してもらうことにした。簡単な記述で実現できるので、わざわざ定義ファイルによる割り当て機能を付ける必要はないだろう。定期的にスキャンなどを実行させる機能も、設定ファイルなどを用意するのは面倒なので、スクリプト中にSetTimer命令などで記述するようにした。そんなわけで、今度こそ実現したかった機能は一通り作り終わった。何も思いつかなかったら正式版ということにしよう。いつの間にか配布ZIPファイルのサイズで21KBにもなってしまっていた。■AutoHotkey(http://www.autohotkey.com/)1.0.43.00Sendコマンドに2つの別モードが用意されたらしい。「SendInput」コマンドでは、同名のAPIを呼び出して一括して入力内容を流し込むらしい。高速らしいが、キーフックを使用していると利用できないらしく、あまり使い道はなさそう。「SendPlay」では、ウィンドウメッセージのような仕組みで入力内容を送り込むらしい。一部のゲームでは、通常のSendでは操作できないがSendPlayを使うことで操作できるようになるとのことだが、SendでもSendPlayでも操作できないゲームがあった。これらの新しいモードは、従来のモードをSetKeyDelay,-1で使用した場合よりも高速に動作するとのことである。試したところ、確かに多少高速になっていた。一連の操作の間に外部から他の操作が割り込まれて動作がおかしくなるということも避けられるらしい。新たにClickコマンドが追加された。従来のMouseClickでは、コントロールパネルで左右のボタンを入れ替えていると、MouseClickが右クリックの動作に、MouseClick,Rが左クリックの動作になっていたが、Clickコマンドでは入れ替えがあってもなくても同じ動作が行われるらしい。2005-10-08。