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ウィンドウのハンドルがその一覧に無ければ、そのウィンドウは新たに作られたものであると判断するようにした。2005-10-08。