XREA.COM Logo XREA.COM Ad

旧雑記サルベージ

1管理人 ★:06/09/06 16:57 ID:???
前に雑記を書いていたサイトが完全に消滅してしまったので、AutoHotkey関連の記事をこちらに再掲載することにする。
内容は当時のままなので、現在のAutoHotkeyとは異なっている場合があるかも。
70管理人 ★:06/09/06 17:32 ID:???
2005年05月14日
■AutoHotkey(http://www.autohotkey.com/)1.0.33
DLL呼び出し機能が追加された模様。

とりあえず、引数を与えて返り値を得る基本的な機能は備わっている。
DMonkeyのDynaCallと違い、整数や浮動小数点値などの変数へのポインタを直接送ることができる。(DMonkeyの場合、要素が整数値一つのStructオブジェクトを作成して送ったりする必要があった)
構造体を扱うことはできない模様。
代わりに文字列としてメモリ領域を確保して、Transformコマンドなどでデータの書き換え・読み出しを行えば可能かと思ったが、文字列のヌル文字以降が削除されてしまったり、構造体メンバに文字列や構造体へのポインタが含まれる場合に対応できなかったりしてダメっぽい。


とりあえず、プロセスIDを指定して実行ファイルパスを得る関数を作った。
getLastError()
{
    return DllCall("GetLastError")
}
getProcessHandle(pid)
{
    return DllCall("OpenProcess","Int",0x001F0FFF,"Int",0,"Int",pid,"Int")
}
getProcessExeName(pid)
{
    hModule=0
    dwNeed=0
    l=0
    max:=VarSetCapacity(s,256)
    hProcess:=getProcessHandle(pid)
    if(DllCall("psapi\EnumProcessModules","Int",hProcess,"Int*",hModule,"Int",4,"UInt*",dwNeed,"Int")0)
    {
        l:=DllCall("psapi\GetModuleFileNameExA","Int",hProcess,"Int",hModule,"Str",s,"Int",max,"Int")
    }
    StringLeft,s,s,l
    DllCall("psapi\CloseProcess","Int",hProcess)
    return s
}


とりあえず説明を一部日本語化した。
DllCall()関数(http://lukewarm.s101.xrea.com/commands/DllCall.htm)
71管理人 ★:06/09/06 17:32 ID:???
2005年05月17日
■AutoHotkeyでプロセスメモリ書き換え
027.zip(http://lukewarm.s101.xrea.com/up/file/027.zip)
他のプロセスが所有するメモリを書き換える関数を作ってみた。
WriteProcessMemoryで割と簡単にできた。

ゲームなどの改造コードの実行に使える。
ホットキー割り当てやタイマー実行が柔軟に出来るのでそれなりに便利そうだ。
メモリ検索は作ってないので、改造コードを得るにはスペシャルねこまんま57号(http://www.vector.co.jp/soft/win95/hardware/se254476.html)などを使う。
72管理人 ★:06/09/06 17:33 ID:???
2005年05月26日
■AutoHotkey(http://www.autohotkey.com/)1.0.34

3番目の数字があがっているがマイナーバージョンアップらしい。
色々と修正されているらしい。
1.0.33.01とあわせた変更点。

・SuspendやHotkeyでジョイスティックホットキーのON/OFFがうまく行かないことがあるのを修正
・Transform,Derefで組み込み変数や環境変数を参照できないのを修正
・IE3以上がないWin95/NTでプログラムを起動できないのを修正
・ListLinesのなにやら正しく全部表示されない不具合が修正されたっぽい
・GUIの複数行エディットコントロールでESCを押したとき、GuiEscapeの割り当てられていないウィンドウは閉じないようにしたっぽい
・#LAltと#RAltでスタートメニューが出るのを修正
・GuiControlでデフォルトボタンなどに関連した不具合を修正
・GuiControlでTab上のPictureのリロード時の再描画を修正
・VarSetCapacity()を式の中で使ったときの動作を修正
・DllCallで関数名の後にAが付く関数のAをいつでも省略できるように修正
・DllCallで引数の型を引用符で囲まなくていいように修正(「*」つきのものは、代わりに「P」をつける)
・余りを無視した割り算を行う「//」演算子を追加
・組み込み関数を色々と追加

色々な言語で行コメントの開始に使われる「//」が割り算に使われるのはややこしい。
あと、割った余りを返す「%」のような演算子がないのも中途半端。

組み込み関数が色々と追加されたのは、いちいち自分で定義しなくて良くて楽。
73管理人 ★:06/09/06 17:33 ID:???
2005年06月01日
■AutoHotkey(http://www.autohotkey.com/)1.0.35

・SendコマンドでAltGr文字を送れないのを修正
AltGrってのがよくわからんが、こんな感じのものらしい(http://office.microsoft.com/ja-jp/assistance/HP052590631041.aspx)

・関数で省略可能引数を定義可能に
省略可能引数には、デフォルト値としてtrue,false,空文字列,数値のどれかを指定する模様。

・Tabコントロールの動作を修正

・Editコントロールで入力内容が変化したときにgラベルが実行されるように修正

・DateTimeコントロールとMonthCalコントロールを追加
1行入力欄型の日付時刻入力コントロールと、カレンダーコントロール。

・UpDownコントロールを追加
値を増減させる矢印ボタンの付いた数値入力用コントロール。

次はリストビューコントロールを追加する予定らしい。
ツリーは無いのか。
74管理人 ★:06/09/06 17:34 ID:???
2005年06月13日
■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)と違って、ラベルとして記述するらしい。
75管理人 ★:06/09/06 17:34 ID:???
2005年06月28日
■AutoHotkey v1.0.36(http://www.autohotkey.com/forum/viewtopic.php?t=4197&sid=1f65e2172fb5ad56d0fa3cb2b60a04aa)

GUIウィンドウに右クリックメニューをつけられるように
リストビューコントロールが追加
など
76管理人 ★:06/09/06 17:35 ID:???
2005年08月29日
■AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)を適当に更新した
4ヶ月くらい放置していた。
とりあえず、GUI関係以外の変更点を大体書いた。
77管理人 ★:06/09/06 17:35 ID:???
2005年08月30日
■AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)を適当に更新した
ListView以外のGUI関係の更新箇所に対応した。
78管理人 ★:06/09/06 17:35 ID:???
2005年09月01日
■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についての記述がある。
メモリリークがあるのではないかということらしい。
79管理人 ★:06/09/06 17:36 ID:???
2005年09月03日
■AutoHotkey v1.0.38(http://www.autohotkey.com/forum/viewtopic.php?t=5219&sid=0db1500df2a140e44c3a0e0506887e93)
なんか任意のウィンドウメッセージに応答する関数を設定する機能がついた模様。
これでGUI関連の対外のイベントは対応できそう。
とりあえず、こんな感じでウィンドウ全体をドラッグ可能なウィンドウの本物が作れる。

onLbuttonDown(wp,lp,msg,sender){
    SendMessage,0x0112,0xF011,0,,ahk_id %sender%
}
OnMessage(0x201,"onLbuttonDown")
Gui,add,text,,aaaaaaaaaaaaaaaaa`naaaaaaaaaaaaa
Gui,-Caption
Gui,Show
80管理人 ★:06/09/06 17:36 ID:???
2005年09月06日
■AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)を適当に更新した
OnMessageとかの説明を書いた。
更新処理スクリプトを実行するのを忘れてて、コマンド一覧などが更新されてなかったので更新した。

OnMessageだが、ウィンドウの閉じるボタンを押したときのWM_SYSCOMMANDなど、なぜか捕らえられないメッセージがある模様。
また、コントロールをクリックしたときなども、種類によってはコントロールではなくウィンドウに送られたものとして補足されることがある。

IsLabel関数でラベルが存在するかどうかを調べることができるようになった。

GuiCloseやOnClipboardChangeのように特別な名前のラベルとして記述するものと、SetTimerやOnExitのようにイベントにラベルを割り当てるもの、OnMessageのように関数を割り当てるものが混在していてややこしい。


ほかウィンドウへのメッセージの監視は、SetWindowsHookExを使って別途用意したDLLの関数を登録すればできなくはなさそう。
フックプロシージャが呼ばれたら、AutoHotkeyのメインウィンドウにSendMessageで通知して、必要なら関数で情報を取得するとか。
81管理人 ★:06/09/06 17:37 ID:???
2005年09月09日
■AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)を適当に更新した
とりあえず現行のバージョンに追いついた。

なにやら、仮想キーコードでホットキーを指定することができるようになった模様。
これで、なぜかIMEのOnとOffが別のキーイベントとして取得されるようになる。
こんな感じで、IMEの状態をキャレット位置に表示することもできなくはない。
~vkF3::ToolTip,直,%A_CaretX%,% A_CaretY+14
~vkF4::ToolTip,あ,%A_CaretX%,% A_CaretY+14

しかし、未確定文字列がある状態で半角/全角キーを押しても、この2つのホットキーが交互に実行されてしまう。
そして、未確定文字列を消してから半角/全角キーを押すと、一度だけ直前のホットキーではないほうが実行される。2度目からはまともになる。
そんなわけで、不完全すぎてあまり役には立たない。
82管理人 ★:06/09/06 17:37 ID:???
2005年10月03日
■音読み漢字一打鍵入力「色波弐〜いろはに〜」(http://iroha2.rona.nomaki.jp/)

よく分からんが特殊なかな入力方式を実現するAutoHotkeyスクリプトらしい。
83管理人 ★:06/09/06 17:37 ID:???
2005年10月12日
■AutoHotkey(http://www.autohotkey.com/)1.0.40

「a::b」のように記述することでキー割り当てを変更できる機能が追加された。
修飾キーとの組み合わせやキーリピートなども考慮された完全なリマップが簡単な記述で実現できるらしい。
まだ日本語環境では、CapsLockとCtrlの入れ替えはできない模様。
84管理人 ★:06/09/06 17:37 ID:???
2005年10月18日
■AutoHotkey メモ - Principia(http://principia.s54.xrea.com/index.php?AutoHotkey%20%A5%E1%A5%E2)

アクセスログより。
85管理人 ★:06/09/06 17:38 ID:???
2005年10月24日
■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を行うようにしたら、正常にアクセスできるようになった。
86管理人 ★:06/09/06 17:38 ID:???
2005年11月08日
■Shiftキーを短く押したときに動作するホットキー
Ctrlキーは元の位置とCapsLockの位置の両方にないと不便なので、AutoHotkeyでMS-IME95互換の英字入力トグルを実現しようと思って作ってみた。
なお、Sendで送信している{vkF2sc070}(ひらがな/カタカナ)キーにはATOKのカスタマイズで英字モードOn/Offを割り当てている。

試作一号
~LShift::return
~Lshift Up::
    if((A_PriorHotkey="~LShift")&&(A_TimeSincePriorHotkey
とりあえず作ってみた。
大文字を入力するときに押していたShiftを放したときにも誤作動すると困るので、短く押したときにだけ動作するようにした。
しかし、なぜか長く押したときにも発生する。
どうやら、ShiftキーのキーリピートでLShiftのイベントが繰り返し発生していたのが原因。
しかし、Shiftを押しながら他のキーを押したときには発生しない。
他のキーが押された時点でキーリピートが終了するための模様。
図らずも希望の動作に近いものができた。
    

試作二号
ls_state=0
~LShift::
    if ls_state=0
        ls_state=1
    else
        ls_state=2
return

~Lshift Up::
    if((ls_state=1)&&(A_TimeSincePriorHotkey
Shiftを長く押したときには発生しないようにしてみようと思い、キーリピートでのイベントを区別するようにしてみた。
Shiftを押してないときは0、最初にShiftを押すと1になり、キーリピートでのイベントでは2になる。
放すときに1なら動作を行い、0に戻す。


とりあえず大体うまくいった気がしたが、ATOKのShift+アルファベットキーで英字入力になる機能をShiftで解除する奴と重複して発生してしまうという問題が。
ATOKの方が通常入力に戻した後さらに切り替えを行って再び英字入力になってしまう。
仕方ないのでCtrlに割り当てることにした。
マウスジェスチャなどが生成するキーボードイベントで誤作動しないように、物理的な押し下げ状態をチェックするようにした。

最終版
ls_state=0
~LCtrl::
    if ((ls_state=0)&&GetKeyState("LCtrl","P"))
        ls_state=1
    else
        ls_state=2
return


~LCtrl Up::
    if((ls_state=1)&&(A_TimeSincePriorHotkey
87管理人 ★:06/09/06 17:39 ID:???
2005年11月21日
■AutoHotkeyでmigemo.dllを使用する(http://lukewarm.s101.xrea.com/myscripts/index.html#migemo)

なんとなく作ってみた。

migemoは正規表現を生成するだけなので、別途BREGEXP.DLLも使用する。
以前DMonkeyで作ったことがあるので特に苦労はしなかった。
BREGEXP.DLLを使用する関数は以前作ったが、新たに書き起こしてひとまとまりの関数群とした。

とりあえず、対象文字列がパターンに一致するかどうかを調べる関数だけ作った。
サンプルとして一覧をインクリメンタルサーチで絞り込むスクリプトを用意した。


■GetSystemPowerStatusでバッテリ容量を取得するAHK
036.zip(http://lukewarm.s101.xrea.com/up/file/036.zip)

以前作ったが忘れていた。
適当に実験的に作ったものなので、あまり実用性はない。
結果は適当に文字列として格納されるので、条件判断などに使いにくい。
88管理人 ★:06/09/06 17:39 ID:???
2005年12月05日
■色々

なまず日記(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解説らしい。
89管理人 ★:06/09/06 17:40 ID:???
2006年01月02日
■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自体に機能が搭載されることに期待する。
90管理人 ★:06/09/06 17:40 ID:???
2006年01月18日
■AutoHotkeyで一番手前のウィンドウを一番後ろに持って行く

Zオーダー順のウィンドウ切り替えを行いたい。
一番後ろのウィンドウを手前に持って来るには、WinActivateBottomを使用すればよいが、手前のウィンドウを後ろに送るのがうまくいかない。
WinSet,Bottom,,Aでアクティブウィンドウを後ろに送った後、WinActivateで一番手前のウィンドウをアクティブにすればいいはずだが、これでは常に最前面に居座っているタスクバーがアクティブ化されてしまう。
ExcludeTitleに「ahk_class Shell_TrayWnd」を設定してやれば、タスクバー以外で一番手前のウィンドウを対象にできるかと思ったが、どうしてもうまくいかない。
ExcludeTitleは「ahk_class」などが使えないという中途半端な仕様だったことを思い出した。
タスクバーにはタイトルがないので、ExcludeTitleでは除外できない。
仕方ないので、「WinSetTitle,ahk_class Shell_TrayWnd,,XABCDTrayWindowEFGH」のようにして無理矢理タイトルを設定してExcludeTitleで指定できるようにしてやった。
タスクバーにはタイトルバーがないので、タイトルを設定しても見た目に変化はない。
その他、特に副作用はない模様。
91管理人 ★:06/09/06 17:40 ID:???
2006年01月20日
■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/)は、とりあえず今回の変更部分の日本語説明を書いた。
#IfWinActive(http://lukewarm.s101.xrea.com/commands/_IfWinActive.htm)
92管理人 ★:06/09/06 17:40 ID:???
2006年01月21日
■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を調べる方法があるらしいが、取得できる場合とできない場合がある。
両方試して、それでも駄目なら大きいアイコンで代用するようにしたら、ほとんどのウィンドウのアイコンを取得できるようになった。

そんなわけで、とりあえず作ったもの。
ついでだからウィンドウスタイルなども表示し、プロセス名でソートするようにしてみた。
WinGet,w,List,,,joijpouhpoijjjjjjj
Gui,Margin,0,0
Gui,Font,s9
Gui,Add,ListView,w800 r%w% vLv gLvEvent AltSubmit,HWND|Title|Class|Pid|ProcessName|Style|ExStyle
himl:=IL_Create(w,w,0)
LV_SetImageList(himl,1)
cnt=0
Loop,%w%{
    id:=w%A_Index%
    SetFormat,Integer,H
    WinGet,s,Style,ahk_id %id%
    SetFormat,Integer,D
    if((!(s&0x08000000))&&((s&0x80)|| !(s&0x80000000))){
        cnt++
        WinGet,e,ExStyle,ahk_id %id%
        WinGet,pid,PID,ahk_id %id%
        WinGet,pn,ProcessName,ahk_id %id%
        WinGetClass,c,ahk_id %id%
        WinGetTitle,t,ahk_id %id%
        i:=DllCall("GetClassLong",UInt,id,Int,-34)
        if(i=0)
        {
            i:=DllCall("SendMessage",UInt,id,UInt,0x7F,UInt,0,UInt,0,UInt)
            if(i=0)
            {
                i:=DllCall("SendMessage",UInt,id,UInt,0x7F,UInt,1,UInt,0,UInt)
            }
        }
        icon:=DllCall("ImageList_AddIcon",Int,himl,Int,i,Int)+1
        LV_Add("Icon" . icon ,id,t ,c,pid,pn,s,e)
    }
}
LV_ModifyCol()
LV_ModifyCol(2,300)
LV_ModifyCol(3,120)
LV_ModifyCol(5,"Sort")
h:=20+cnt*13
GuiControl,Move,LV,h%h%

Gui,Show,AutoSize
return


LvEvent:
If(A_GuiEvent="Normal"){
    LV_GetText(id,A_EventInfo,1)
    WinActivate,ahk_id %id%
    ExitApp
}
return
93管理人 ★:06/09/06 17:41 ID:???
2006年01月23日
■AutoHotkeyでタイトルバーのクリックした場所によって分岐させる

AutoHotkeyのスレッドで話題に上がっていた奴。
WM_NCHITTESTという奴でどの座標がどんな部分かを調べられるらしい。
どうもAutoHotkeyのSendMessageは当てにならないので、DllCallで直に呼んでやったらうまくいった。
この間のアイコンの奴もそんな感じだった。
どっかの日本語マニュアルで座標はクライアント座標系で寄越せとか書いてあったが、手元の少し古いMSDNの英語リファレンスにはrelative to the upper-left corner of the screenとあったのでそのようにした。

返り値による分岐では、IsLabelとGoToで擬似的にswitch-caseのような感じにしてみた。


~MButton::
CoordMode,Mouse,Screen
MouseGetPos, x, y, id
a:=DllCall("SendMessage",UInt,id,UInt,0x84,UInt,0,UInt,x | y


以前、マウスクリックメッセージをOnMessageで処理してウィンドウの好きな場所をドラッグできるようにする方法を考えたが、これもWM_NCHITTESTを処理すれば数行で済むらしい。
しかし、WM_NCHITTESTはウィンドウ上をマウスカーソルが通過している間中送られてくるので、スクリプト側で処理すると無駄に重くなる気がする。
まあ、試したところCPU使用率は1%位にしかならなかったので、気にするほどではないか。

OnMessage(0x84,"OnHitTest")
Gui,add,Text,,aaaaaaaa`nbbbbbbb
Gui,Show
OnHitTest(w,l){
    return 2
}
94管理人 ★:06/09/06 17:41 ID:???
2006年01月26日
■AutoHotkeyで"タスクトレイに最小化"

AutoHotkeyでは、タスクトレイアイコンは通常一つだけしか持てない。
しかし、Shell_NotfyIconというAPI関数を使えばアイコンを作成できる。
作成したアイコンを操作すると、アイコン作成時に関連づけたウィンドウに指定した番号のメッセージが送られ、作成時に指定したアイコンIDと操作の内容が通知される。
これをOnMessageで捉えて、アイコンIDや操作に応じた動作を行えばよい。

とりあえず、このあいだのタイトルバーをホイールクリックする奴と、その前のウィンドウのアイコンを取得する奴と合わせて、タイトルバーをホイールクリックすると擬似的にタスクトレイに格納するというのを作ってみた。
格納したウィンドウは、トレイアイコンの何らかのクリック動作で復元される。
右クリックではメニューを出すようにしようかと思ったが、「復元」以外にコマンドが要らない気がするのでやめた。
プログラムが終了するときには自動的にすべてのアイコンを復元するようにした。

ホイールクリックのホットキーでは、MButtonをMButton upにし、カーソル下のウィンドウがアクティブかどうかをチェックする動作を加えた。
これにより、タイトルバー上でホイールを押し下げた後、タイトルバー外までカーソルを移動してから放すことで、キャンセルが行えるようになった。
クリック系の動作としてはこれが望ましい。

Shell_NotfyIconでは、いちいち構造体で情報を与えてやらないとならない。
Shell32.dllのバージョンによっては拡張機能が利用できるらしいが、とりあえず一番古くて簡単な奴を使うことにした。
なぜか操作を通知するメッセージの番号が指定できるようになっている。
AutoHotkeyのアイコンでは0x404が使われているようだが、標準アイコンの操作イベントはどうでもいいので、別の番号を指定して自分で作成したアイコンの分だけをOnMessageで捉えるようにした。

操作通知メッセージのlParamで通知される操作内容の番号の意味が載っている資料がなかった。
第1ビットがマウスボタンの押し上げフラグかと思ったが、違うらしい。
とりあえず、
0x200がカーソルが通過した
0x201:左ボタンを押した
0x202:左ボタンを放した
0x203:左ダブルクリック
0x204:右ボタンを押した
0x205:右ボタンを放した
0x206:右ダブルクリック
0x207:中ボタンを押した
0x208:中ボタンを放した
0x209:中ダブルクリック
までは調べた。
第4,5ボタンは利かないっぽい。
なんで0x200番からなのかはよくわからん。

CreateStruct(size)
{
    return DllCall("GlobalAlloc",UInt,0,UInt,size,UInt)
}
DestroyStruct(pStruct){
    DllCall("GlobalFree",UInt,pStruct,UInt)
}
StructSetInt(pStruct,offset,val){
    DllCall("RtlMoveMemory", UInt,pStruct+offset, UIntP,val, Int,4)
}
StructSetStr(pStruct,offset,val){
    DllCall("RtlMoveMemory", UInt,pStruct+offset, Str,val, Int,StrLen(val)+1)
}

numTrayIcon=0
Process,Exist
pid:=ErrorLevel
DetectHiddenWindows,On
WinGet,myhwnd,id,ahk_pid %pid% ahk_class AutoHotkey
DetectHiddenWindows,Off

OnMessage(0x405,"OnTrayIconEvent")
OnExit,RestoreFromTrayAll
return

GetWindowIcon(hwnd){
    i:=DllCall("GetClassLong",UInt,hwnd,Int,-34)
    if(i=0)
    {
        i:=DllCall("SendMessage",UInt,hwnd,UInt,0x7F,UInt,0,UInt,0,UInt)
        if(i=0)
        {
            i:=DllCall("SendMessage",UInt,hwnd,UInt,0x7F,UInt,1,UInt,0,UInt)
        }
    }
    return i
}

;引数にアイコンハンドルを指定
;自動的にIDが割り振られて返される
CreateTrayIcon(hicon,tooltip){
    global numTrayIcon,myhwnd
    ret=0
    StringLeft,tooltip,tooltip,63
    pnid:=CreateStruct(88)
    StructSetInt(pnid,0,88)
    StructSetInt(pnid,4,myhwnd)
    StructSetInt(pnid,8,11+numTrayIcon)
    StructSetInt(pnid,12,7)
    StructSetInt(pnid,16,0x405)
    StructSetInt(pnid,20,hicon)
    StructSetStr(pnid,24,tooltip)
    if(DllCall("Shell32.dll\Shell_NotifyIcon",UInt,0,UInt,pnid,UInt)){
        numTrayIcon++
        ret:=numTrayIcon
    }
    DestroyStruct(pnid)
    return ret
}
;引数にIDを指定
DeleteTrayIcon(id){
    global myhwnd
    pnid:=CreateStruct(88)
    StructSetInt(pnid,0,88)
    StructSetInt(pnid,4,myhwnd)
    StructSetInt(pnid,8,10+id)
    ret=0
    if(DllCall("Shell32.dll\Shell_NotifyIcon",UInt,2,UInt,pnid,UInt)){
        ret=1
    }
    DestroyStruct(pnid)
    return ret
}
MinimizeToTray(hwnd){
    global
    local t,ti
    WinGetTitle,t,ahk_id %hwnd%
    ti:=CreateTrayIcon(GetWindowIcon(hwnd),t)
    TrayIcon%ti%:=hwnd
    WinHide,ahk_id %hwnd%
}
RestoreFromTray(id,activate=1){
    global
    local hwnd
    hwnd:=TrayIcon%id%
    if(hwnd!=0){
        DeleteTrayIcon(id)
        WinShow,ahk_id %hwnd%
        if(activate){
            WinActivate,ahk_id %hwnd%
        }
        TrayIcon%id%:=0
    }
}
OnTrayIconEvent(w,l,m,h){
    ;マウスボタンが放されたとき解放
    if(l=0x202||l=0x205||l=0x20a){
        RestoreFromTray(w-10)
    }
}

RestoreFromTrayAll:
    Loop,%numTrayIcon%{
        RestoreFromTray(A_Index,0)
    }
    ExitApp
return

~MButton up::
    CoordMode,Mouse,Screen
    MouseGetPos, x, y, h
    If(WinActive("ahk_id " . h) && DllCall("SendMessage",UInt,h,UInt,0x84,UInt,0,UInt,x | y <<16,UInt)=2){
        MinimizeToTray(h)
    }
return
95管理人 ★:06/09/06 17:41 ID:???
2006年01月27日
■タスク切り替えの奴の改良
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で選択ウィンドウを閉じるという機能も付けた。
かなり便利な感じになった。
96管理人 ★:06/09/06 17:41 ID:???
2006年01月30日
■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で正しいエラーコードを知ることができない。
困ったもんだ。
97管理人 ★:06/09/06 17:43 ID:???
2006年02月02日
■AutoHotkeyスクリプトの高速化
SendMessageには、コマンドで送る方法とDllCallで送る方法がある。
どちらが速いのか。
コマンドの方では、「ahk_id %hwnd%」の解釈が行われるが、遅くならないのか?
以下のスクリプトで試してみた。
Process,Exist
pid:=ErrorLevel
DetectHiddenWindows,On
WinGet,myhwnd,id,ahk_pid %pid% ahk_class AutoHotkey
SetBatchLines,-1

tc:=A_TickCount
Loop,20000{
    DllCall("SendMessage",UInt,myhwnd,UInt,0x0,UInt,0,UInt,0,UInt)
}
l1:=A_TickCount-tc
tc:=A_TickCount
Loop,20000{
    SendMessage,0,0,0,,ahk_id %myhwnd%
}
l2:=A_TickCount-tc

結果は、1079対172でコマンドの方が圧倒的に速かった。

次に、コマンドの方でLastFoundWindowを利用したらどうなるかを調べた。
tc:=A_TickCount
Loop,200000{
    SendMessage,0,0,0,,ahk_id %myhwnd%
}
l1:=A_TickCount-tc
DetectHiddenWindows,On
IfWinExist,ahk_id %myhwnd%
{
DetectHiddenWindows,Off
    tc:=A_TickCount
    Loop,200000{
        SendMessage,0,0,0
    }
    l2:=A_TickCount-tc
}
234対125で、LastFoundWindowを使った方が高速なことがわかった。

しかし、わざわざIfWinExistを1行増やすと、その分遅くなるはずである。
以下のようにして、内側で何回ウィンドウ操作を行ったら、IfWinExistを使った分の元を取れるかを計測した。
tc:=A_TickCount
Loop,100000{
    SendMessage,0,0,0,,ahk_id %myhwnd%
    SendMessage,0,0,0,,ahk_id %myhwnd%
}
l1:=A_TickCount-tc
tc:=A_TickCount
Loop,100000{
    IfWinExist,ahk_id %myhwnd%
    {
        SendMessage,0,0,0
        SendMessage,0,0,0
    }
}
l2:=A_TickCount-tc
内側が1回の時、828対859で、IfWinExistを使った方が遅くなった。
しかし、2回にすると、1578対1375でIfWinExistを使った方が速くなる。

次に、DllCallの気になる部分を調べる。
引数の型は「Int」のようにするのと「"Int"」のようにするのがあるが、どっちが速いか。
tc:=A_TickCount
Loop,20000{
    DllCall("SendMessage",UInt,myhwnd,UInt,0x0,UInt,0,UInt,0,UInt)
}
l1:=A_TickCount-tc
tc:=A_TickCount
Loop,20000{
    DllCall("SendMessage","UInt",myhwnd,"UInt",0x0,"UInt",0,"UInt",0,"UInt")
}
l2:=A_TickCount-tc
1047対296で、文字列として渡した方が圧倒的に速くなる。

次に、モジュール名を省略しなかったらどうなるか。
tc:=A_TickCount
Loop,100000{
    DllCall("SendMessage","UInt",myhwnd,"UInt",0x0,"UInt",0,"UInt",0,"UInt")
}
l1:=A_TickCount-tc
tc:=A_TickCount
Loop,100000{
    DllCall("User32.dll\SendMessageA","UInt",myhwnd,"UInt",0x0,"UInt",0,"UInt",0,"UInt")
}
l2:=A_TickCount-tc
1500対1360で、できるだけ詳しく指定した方がほんの少し速くなる。

返り値を得ないとき、最後の返り値の型指定を省略したらどうなるか。
tc:=A_TickCount
Loop,100000{
    DllCall("User32.dll\SendMessageA","UInt",myhwnd,"UInt",0x0,"UInt",0,"UInt",0,"UInt")
}
l1:=A_TickCount-tc
tc:=A_TickCount
Loop,100000{
    DllCall("User32.dll\SendMessageA","UInt",myhwnd,"UInt",0x0,"UInt",0,"UInt",0)
}
l2:=A_TickCount-tc
1470対1359で、返り値の型を省略した方がほんの少し速かった。

高速化したDllCallと、SendMessageコマンドで、返り値を変数に格納する速度を計測する。
tc:=A_TickCount
Loop,10000{
    r:=DllCall("User32.dll\SendMessageA","UInt",myhwnd,"UInt",0x0,"UInt",0,"UInt",0)
}
l1:=A_TickCount-tc
tc:=A_TickCount
Loop,10000{
    SendMessage,0,0,0,,ahk_id %myhwnd%
    r=%ErrorLevel%
}
l2:=A_TickCount-tc
141対94で、やっぱりコマンドの方が速かった。

「var2:=var1」による代入と「var2=%var1%」による代入ではどっちが速いか。
tc:=A_TickCount
Loop,100000{
    SendMessage,0,0,0,,ahk_id %myhwnd%
    r=%ErrorLevel%
}
l1:=A_TickCount-tc
tc:=A_TickCount
Loop,100000{
    SendMessage,0,0,0,,ahk_id %myhwnd%
    r:=ErrorLevel
}
l2:=A_TickCount-tc
875対860で、:=の方がごくわずかに速かった。

定数を代入する場合はどうか。
tc:=A_TickCount
Loop,1000000{
    r=100
}
l1:=A_TickCount-tc
tc:=A_TickCount
Loop,1000000{
    r:=100
}
l2:=A_TickCount-tc
391対390で、ほとんど変わらない。

加算する場合はどうか。
r=0
tc:=A_TickCount
Loop,1000000{
    r+=1
}
l1:=A_TickCount-tc
r=0
tc:=A_TickCount
Loop,1000000{
    r:=r+1
}
l2:=A_TickCount-tc
937対1188で、「+=」の方が速い。

変数をいくつも足すような場合はどうか。
x=200
tc:=A_TickCount
Loop,100000{
    r=100
    r+=%x%
    r+=%x%
}
l1:=A_TickCount-tc
tc:=A_TickCount
Loop,100000{
    r:=100+x+x
}
l2:=A_TickCount-tc
足し算の場合、1回の時は985対1015で「:=」の方が遅かった。
しかし、2回足した場合、1547対1188で「:=」の方が速い。

文字列の連結はどうか。
VarSetCapacity(r,100000)
r=
tc:=A_TickCount
Loop,100000{
    r=%r%x
}
l1:=A_TickCount-tc
VarSetCapacity(r,100000)
r=
tc:=A_TickCount
Loop,100000{
    r:=r . "x"
}
l2:=A_TickCount-tc
47対13312で「=」の方が圧倒的に速い。

複雑な式の場合はどうか。
x=200
y=400
z=10
tc:=A_TickCount
Loop,100000{
    r=100
    r+=%x%
    r*=%y%
    r/=%z%
}
l1:=A_TickCount-tc
tc:=A_TickCount
Loop,100000{
    r:=(100+x)*y/z
}
l2:=A_TickCount-tc
266対468で、やはり「:=」は遅かった。

まとめると、
・SendMessageはDllCallでやるよりコマンドでやった方が速い
・同じウィンドウを2回以上操作する場合、毎回「ahk_id %hwnd%」で指定するより、IfWinExistを使ってLastFoundWindowに保持されるようにした方が速い
・DllCallは引数や返り値の型指定を「"」で囲んだ方が速い
・DllCallは関数名の後の「A」やモジュール名を省略しない方が若干速い
・返り値がIntやBoolだったり不要な場合は、返り値の型を省略した方が速い
・変数に変数を代入する場合、「var2=%var1%」による代入より「var2:=var1」による代入の方が速い
・変数に定数を加算する場合、「:=var+1」より「var+=1」の方が速い
・変数に定数+変数を代入する場合、「var=100」「var+=%x%」のようにする方が速い
・定数と2つ以上の変数を足す場合、「var:=100+x+y」の方が速い
・文字列の連結は「var:=var . "str"」より「var=%var%str」とする方が速い
・括弧などを使った複雑な式の場合、「:=式」とするより「var*=」等を使った方が速くなるときがある
98管理人 ★:06/09/06 17:44 ID:???
2006年02月03日
■AutoHotkeyのListViewをいじる

DllCallでImageList_Createを行えば、任意のサイズでアイコンを表示できる。
画像の縮小表示と組み合わせれば、任意のサイズの画像サムネイルが可能かと思って試してみたら、可能だった。

Gui,Add,ListView, w640 h480 r%w% vLv Icon,name
himl:=DllCall("ImageList_Create",Int,256,Int,256,UInt,0x21,Int,w,Int,w,UInt)
LV_SetImageList(himl,0)
n:=IL_Add(himl,"F:\pictures\cats\c22.jpg",0,1)
LV_Add("Icon" . n ,"aaaaaaaa")
Gui,Show


ExtractAssociatedIconAというAPIを使えば、ファイルやフォルダの関連づけアイコンを取得できるらしい。
このAPIにはなぜか呼び出し元プロセスのインスタンスハンドルが必要だが、GetModuleHandleというAPIで取得できるという。
とりあえず試してみたら、確かに関連づけアイコンが取得された。
hinst:=DllCall("GetModuleHandle",UInt,0,UInt)
Gui,Add,ListView, w640 h480 r%w% vLv Icon,name
himl:=DllCall("ImageList_Create",Int,32,Int,32,UInt,0x21,Int,w,Int,w,UInt)
LV_SetImageList(himl,0)
h:=DllCall("Shell32.dll\ExtractAssociatedIconA",UInt,hinst, Str,"F:\pictures\cats\c22.jpg", UShortP,0, UInt)
n:=DllCall("ImageList_AddIcon",Int,himl,Int,h, Int)+1
LV_Add("Icon" . n ,"aaaaaaaa")
Gui,Show,AutoSize

これをこのあいだのタスクリストの奴に組み込んで、何が何でもウィンドウのアイコンを取得できるようにしておくことに。
Alt+Tabの奴とはどうしても違ってしまうが、フォルダオプションのウィンドウなどもアイコンが表示されるようになった。
ALt+Tabの奴はどうやってアイコンを取得しているのだろうか?

■可能な限り正確にマウス下のコントロールを操作する
マウスホイールの操作をカーソル下のコントロールにリダイレクトするツールをAutoHotkeyで再現したい。
カーソル下のウィンドウとコントロールはMouseGetPosで取得できるが、タブブラウザのようなMDIコントロールの子ウィンドウが最大化されている場合などに誤認識が起こる模様。
いつ頃からかAltMethodというパラメータが追加され、MDI子ウィンドウに正確に対応できるようになったが、これを利用すると逆に誤認識を起こす場合がある。
たとえば、HTMLヘルプのウィンドウの「キーワード」ペインのリストなどがそうだった。

このあいだ使ったWM_NCHITTESTでカーソルがコントロール上かを判定して、おかしかったら非AltMethodで取得し直すようにしてみたら、MDIもHTMLヘルプも正確に操作できるようになった。
AltMethodと通常方式の順番を逆にすると、MDIで誤認識する。
*WheelDown::
    CoordMode,Mouse,Screen
    MouseGetPos,x,y,hwnd,ctrl,1
    IfWinExist,ahk_id %hwnd%
    {
        p:=y1
            MouseGetPos,,,,ctrl
    }
    PostMessage,0x020A,0xFF880000,%p%,%ctrl%,ahk_id %hwnd%
return

*WheelUp::
    CoordMode,Mouse,Screen
    MouseGetPos,x,y,hwnd,ctrl,1
    IfWinExist,ahk_id %hwnd%
    {
        p:=y1
            MouseGetPos,,,,ctrl
    }
    PostMessage,0x020A,0x00780000,%p%,%ctrl%,ahk_id %hwnd%
return色々と適当な感じだが、とりあえず大体のコントロールを操作できるようになった。
この例ではfwKeysの処理を省略してあるので、Shift+ホイールでIEコンポーネントの戻る・進むを行うなどの機能が利用できない。


このホイールリダイレクト機能では、正確にカーソルをコントロール上に合わせてやらないとならず、小さなコントロールを操作しづらい。
カーソルがどこにあってもアクティブなコントロールを操作できる通常の動作の方が好きだ。
99管理人 ★:06/09/06 17:44 ID:???
2006年02月06日
■もこ窓(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で処理して自前で再描画するようにした。

対象ウィンドウのフィルタリングとかは面倒くさいので、このあいだの「タスクトレイに最小化」のようにタイトルバーのホイールクリックで縮小するようにした。

その気になれば縮小ウィンドウを自由にリサイズしたりすることも実現できるが、面倒なんでやめた。
100管理人 ★:06/09/06 17:44 ID:???
2006年02月07日
■AutoHotkey虫眼鏡
041.zip(http://lukewarm.s101.xrea.com/up/file/041.zip)
昨日のStretchBltを応用すれば、画面を拡大することも可能なはずである。
そこで、「拡大鏡」のようなマウスカーソル周辺を拡大するツールを作ってみる。
デスクトップ全体を対象にしたいので、「GetDesktopWindow」でデスクトップ全体のハンドルを得る。
描画はタイマーで行うようにし、基本部分はあっさりできた。

透過ウィンドウのDCが特殊になっていたことを思い出し、自分のウィンドウをTrans,255にしてみたところ、自分のウィンドウが映らず、後ろの映像が拡大されるようになった。
透過ウィンドウは一般ウィンドウ群のDCからは隔離されていて、描画時に合成処理されるのだろう。
更に、拡張スタイルの0x00080000を指定することで、マウスクリックをカーソル下に透過させるようにし、ウィンドウがマウスカーソルに追従するようにしてみた。

AlwaysOnTopで常に最前面に表示されるようにしているが、新たに表示されたメニューなどの最前面ウィンドウに負けてしまう。
そこで、描画時にWinSet,Topで最前面に移動してやるようにした。
とりあえず、メニューより前に表示されるようになった。

そんな感じで、かなり虫眼鏡っぽくなったが、使いやすいかどうかは不明。
101管理人 ★:06/09/06 17:44 ID:???
2006年02月08日
■AutoHotkeyでGUIウィンドウの空いている番号を検索
AutoHotkeyのGUIでは、複数のウィンドウを番号で区別し、99個までのウィンドウを生成できる。
特に指定がなければ、1番のウィンドウが使われる。
複数のスクリプトを組み合わせて使う場合には、番号が衝突しないように修正しなければならない。

いちいち修正しなくていいように、空いている番号で新たにGUIウィンドウを作れるような仕組みを作ることに。
「その番号のウィンドウが存在しなければ、その番号は空いている」とみなすことを考えたが、GUIウィンドウが生成されているかを調べる機能はないし、「Gui,+LastFound」等を行うと、その時点でウィンドウが生成されてしまう。
そこで、あらかじめ自分のプロセスのGUIウィンドウのハンドルを列挙しておき、取得したGUIウィンドウのハンドルがその一覧に無ければ、そのウィンドウは新たに作られたものであると判断するようにした。

newGui(){
    Process,Exist
    mypid:=ErrorLevel
    DetectHiddenWindows,On
    WinGet,h,list,ahk_pid %mypid% ahk_class AutoHotkeyGUI
    DetectHiddenWindows,Off
    Loop,99{
        found=0
        Gui,%A_Index%:+LastFound
        WinGet,hwnd,id
        Loop,%h%{
            if(h%A_Index%=hwnd){
                found=1
                break
            }
        }
        if(found=0){
            return A_Index
        }
    }
    return 0
}

Gui,Add,text,,MyGUI
Gui,Show

w1:=newGui()
Gui,%w1%:Default
Gui,add,text,,DynamicGUI 1
Gui,Show

w2:=newGui()
Gui,%w2%:Default
Gui,add,text,,DynamicGUI 2
Gui,Show
102管理人 ★:06/09/06 17:44 ID:???
2006年02月11日
■AutoHotkey(http://www.autohotkey.com/)1.0.42
アクティブウィンドウなどの条件でホットキーの動作の有無を切り替える機能が改良され、同じホットキーに条件によって別の動作をさせることが可能になったらしい。
103管理人 ★:06/09/06 17:45 ID:???
2006年02月14日
■AutoHotkeyでプログラムファイルの説明などを取得
あまり使い道なさそうだが、とりあえず作ってみた。

/*
fn
ファイルパスを指定
type
以下の何れかを指定
CompanyName 会社名
FileDescription 説明
FileVersion ファイル・バージョン
InternalName 内部名
LegalCopyright 著作権
OriginalFileName 正式ファイル名
ProductName 製品名
ProductVersion 製品バージョン
Comments コメント
LegalTrademarks 商標
PrivateBuild プライベート・ビルド情報
SpecialBuild スペシャル・ビルド情報


MsgBox,% GetStringFileInfo("VERSION.dll","FileDescription")
*/
GetStringFileInfo(fn,type){
    len:=DllCall("VERSION.dll\GetFileVersionInfoSizeA",Str,fn, UIntP,h, UInt)
    vbuf:=DllCall("GlobalAlloc",UInt,0x40,UInt,len,UInt)
    DllCall("VERSION.dll\GetFileVersionInfoA",Str,fn, UInt,h, UInt,len, UInt,vbuf)

    DllCall("VERSION.dll\VerQueryValueA",UInt,vbuf, Str,"\VarFileInfo\Translation", UIntP,inf, UIntP,l)
    DllCall("RtlMoveMemory", UIntP,val, UInt,inf, Int,l, Int)
    SetFormat,Integer,H
    val+=0x100000000
    StringMid,l1,val,8,4
    StringMid,l2,val,4,4
    locale=%l1%%l2%
    StringUpper,locale,locale

    q=\StringFileInfo\%locale%\%type%
    DllCall("VERSION.dll\VerQueryValueA",UInt,vbuf, Str,q, UIntP,inf, UIntP,l)
    VarSetCapacity(buf,l)
    DllCall("RtlMoveMemory", Str,buf, UInt,inf, Int,l)
    DllCall("GlobalFree",UInt,vbuf)
    return buf
}
104管理人 ★:06/09/06 17:45 ID:???
2006年02月17日
■AutoHotkeyを流行らせるページ(http://lukewarm.s101.xrea.com/)更新

ウィンドウの条件ごとに別のホットキーアクションを割り当てられるようになったので、とりあえず#Ifwin...(http://lukewarm.s101.xrea.com/commands/_IfWinActive.htm)とHotkey(http://lukewarm.s101.xrea.com/commands/Hotkey.htm)の部分だけ更新した。
また、My Scripts(http://lukewarm.s101.xrea.com/myscripts/index.html)に今までに作ったスクリプトを適当に掲載した。
ホイールリダイレクトの奴は、fwKeysの部分をちゃんと作って、Ctrl+ホイールとかもリダイレクトされるようにした。
105管理人 ★:06/09/06 17:45 ID:???
2006年02月20日
■AutoHotkey(http://www.autohotkey.com/)1.0.42.03

DllCallを実行した後、「A_LastError」変数でGetLastErrorの値を参照できるようになったらしい。
内容はエラーコードの数値なので、エラーの内容を知るには以下のような感じにする。
なんか知らんが、エラーコードに対応するエラーメッセージをシステムから取り寄せているらしい。
GetError(){
    c:=A_LastError
    VarSetCapacity(buf,512)
    DllCall("FormatMessage", UInt,0x1000, UInt,0, UInt,c, UInt,0x400, Str,buf, UInt,512, UInt,0, UInt)
    return c . " " . buf
}



DllCallの最後に毎回GetLastErrorを行っているようだが、そもそもDllCallの時にLastErrorの値が変わってしまう部分を何とかしてくれればいいような気がするのだが。
106管理人 ★:06/09/06 17:46 ID:???
2006年02月23日
■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で使われている構造体とは構造が違うようだが、内部データ用の形式だろうか?
このような情報はどこで仕入れてくるのか。
typedef struct _TRAYNOTIFY{
    HWND    hWnd;
    UINT    uID;
    UINT    uCallbackMessage;
    DWORD    dwInfoFlags;
    DWORD    dwDammy;
    HICON    hIcon;
}TRAYNOTIFY;

これで、必要な情報と、ついでにアイコンのハンドルが得られそうだ。

他のプロセスからウィンドウメッセージなどで構造体のデータをやりとりするときは、VirtualAllocExで当該プロセスに共有メモリを確保し、そこにデータを受け取ってからReadProcessMemoryで読み取らなくてはならないらしい。
うっかりGlobalAllocで確保したメモリに受け取ろうとしたら、エクスプローラがメモリアクセスエラーで不正終了してしまった。


アイコンの数については、TB_BUTTONCOUNTメッセージで簡単に取得できる。

そんな感じで、任意のトレイアイコンの情報を取得する関数と、アイコンの数を取得する関数を作成した。
アイコンの数だけループして、条件に一致したときに指定の操作イベントを通知するようにすれば、TrayCommandのように指定したアプリケーションのトレイアイコンを操作することができるようになる。

プロセスの実行ファイルパスを取得する関数をコピーしてくるのが面倒だったので、サンプルでは「WinGet,pn,ProcessName」の結果のプロセス名を使用して判定するようにした。



TrayExpandのようにアイコンを隠す機能も作ろうと思ったが、TB_HIDEBUTTONで非表示にすると、消したアイコンの分のスペースが空いてしまう。
そこで、Shell_NotifyIconで状態を非表示に設定することにした。
これなら、スペースをちゃんと調節してくれる。
Shell_NotifyIconに与える情報は、先ほどの関数で取得したhWndやuIDを使用すればいい。
別のプロセスのアイコンの状態を勝手に変更できてしまうとは、結構いい加減なAPIだ。

ついでに、TB_MOVEBUTTONでアイコンの順番を入れ替える関数も作った。
スタートアップの実行タイミングやプログラムの再起動でアイコンの順番が変わってしまうのは鬱陶しいので便利かも。
107管理人 ★:06/09/06 17:46 ID:???
2006年02月26日
■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はあまり使っていないので、その他の細かい挙動の違いなどは不明。
108管理人 ★:06/09/06 17:46 ID:???
2006年03月01日
■fenrir風の奴の改良
045.zip(http://lukewarm.s101.xrea.com/up/file/045.zip)
・複数ファイルの選択に対応
Ctrl+上下やCtrl+Space、Shift+上下で複数選択ができるようにした。
AutoHotkeyのListBoxでは、なぜかCtrl+上下が利かない。
とりあえずLB_系のメッセージを使って実現することに。
しかし、入力欄にフォーカスがあると、リストボックスのフォーカスが見えない。
仕方ないので、移動しながら選択を反転するようにした。
通常の動作とは異なってしまうが、とりあえずどこを選択しているのかは分かるようになった。
その他、Ctrl+Aで全選択なども付けた。

コマンドなどの引数展開で、選択ファイルを半角スペース区切りで列挙した物や、改行区切りで列挙した物をセットするようにした。

・アイテムを登録する/aコマンドの追加
・アイテムを削除する/delコマンドの追加
・その他、内部コマンドの追加・修正
内部コマンドのスクリプトはかなりシンプルに書けるので、ユーザーが自分で追加することも簡単だろう。

・コマンドの引数を変数展開するようにした
これにより、「/c %Items%」でアイテムリストをクリップボードにコピーするなど、色々と可能になった。

・/で始まる入力時にコマンドモードに移行するように
・コマンド選択モードの仕様をコマンド名と引数を直接入力するように変更
コマンドモードを割と直感的に使えるようになった。
コマンドモードに移行しても、コマンドの一覧が表示されるだけで、直接入力するのとあまり変わらないが。

・引数付きで実行したコマンドはアイテムに自動登録されるようにした
「/c %Items%」などのコマンドを素早く再実行したいときに便利かも。
内容が短いので検索しにくいかもしれないが。

・入力を行うと絞り込みが行われなくても選択状態が解除されるのを修正
これにより、上下キーでリストから選択を行った後にコマンドを入力して実行できるようになった。

・ディレクトリ展開と他のモードを同時実行可能にした
・「*」と入力するとアイテムリストをリスト表示の上限まで表示する機能
・コマンドやアイテムのWorkingDirも変数展開されるようにした
・INIファイルで任意の変数の値を設定・保存できるようにした
・タスクトレイのメニューを改良
109管理人 ★:06/09/06 17:47 ID:???
2006年03月03日
■fenrir風の奴の改良
046.zip(http://lukewarm.s101.xrea.com/up/file/046.zip)

・Migemo使用時にスキップマッチングを利用できるようにした
Migemoには「改行やスペースの連続」にマッチする正規表現を指定することで改行をまたいだ検索が行われる正規表現を生成するという機能がある。
ここに「[^\\]*」などと指定すると、キーワード中の任意の部分を省略できるスキップマッチングが実現できる。
「ahk」で「AutoHotkey」にマッチしたりするようになる。
検索結果数が増えるため、多少遅くなっているような気がする。


・スキャンデータのリムーバブルドライブ対応
USBメモリなどのリムーバブルドライブや、CD-ROMなどの光学メディアなど、ドライブ文字が変わったりドライブに挿入されているメディアが変わったりする場合に対応できるようにした。
ドライブ文字の代わりにメディアのシリアルナンバーを保存し、実行時に当該メディアを検出してパスを生成する。


・固定ドライブとRAMディスク以外は存在しないファイルを自動削除しないように


・Migemoの辞書の問題のある項目を削除するスクリプトを同梱
面倒なんで正規表現オペレーター文字を含んでいる単語を片っ端から削除することに。
9割方顔文字などのゴミデータなので問題ないだろう。
ついでに、無駄に長い単語も削除するようにした。
「\\」で全角文字を誤検出するので、BREGEXP.DLLで検査するようにした。


・読み込み専用のサブインデックスファイルを指定する機能を追加
LAN上のフォルダなどをインデックス化しておいて、複数のPCから参照したりできるようにした。


・スキャン時に対象フォルダの古いインデックスを削除するようにした


・/scanallコマンドを実装し、scan.txtの仕様を変更した
フォルダごとに個別に正規表現フィルタなどを設定できるようにした。
ついでに、スキャンを行う最低間隔を指定する機能も付けてみた。


・検索を若干高速化
一時リストのメモリをVarSetCapacityであらかじめ確保するようにしたら高速化された気がする。


・フォルダ展開時の駄目文字問題を修正
なんかA_LoopFileNameは自前でパスを区切っているらしく、2バイト目が「\」の全角文字に誤反応しやがるので、スクリプト側で親ディレクトリパスの長さ分削除してファイル名部分を切り出すようにした。


・その他色々修正




色々と修正しようとスクリプトを弄っていたら、GUIウィンドウを表示した直後にメモリアクセス違反で不正終了するようになってしまった。
追加した行を削ると問題なくなり、別の場所に別のコードを追加しても駄目になる。
スクリプトが長くなりすぎた所為で不具合が起こっているのか。

とりあえず、同じ行を10000行ほど並べたスクリプトでGUIウィンドウを表示してみたが、不正終了はしなかった。
発生条件がはっきりしなくて困る。

エラーはGui,Showの中で起こっている模様。
問題のGui,Showのオプションを色々変更してみたところ、エラーが発生しなくなることがあった。
ひとまず表示動作に影響しないパターンを探して、とりあえずエラーはなくせた。
どのような原理でこんな気まぐれな不具合が発生するのか。
110管理人 ★:06/09/06 17:47 ID:???
2006年03月04日
■Visual C++ 2005 Express EditionでAutoHotkeyをビルドする

スクリプトが肥大化してきたら気まぐれで発生するようになった謎のエラーを何とかしたい。
エラー内容を見ると、「0x0000000f」というアドレスを参照しているらしい。
0x00000000ではないということは、構造体へのポインタがnullの時にメンバを参照しようとしているのだろう。

そんなわけで、ソースコードから問題の箇所を探そうとしたが、やたらと長大で挫折した。
デバッグ実行でエラーを発生させて問題の箇所を見つけてみることに。

どうやらVC7向けに作られているらしく、手持ちのVC6.0ではコンパイルできなかったので、無償提供されているVC2005EEを使うことに。
XPのSP2にしかインストールできないということで、サブマシンにインストールする。
DaemonToolsで配布isoイメージをマウントしてインストールを行い、AutoHotkeyのプロジェクトをインポートしてみたが、windows.hがないとか言われてビルドできない。
PlatformSDKがインストールされなかったらしい。
Visual Studio 2005 Express Editions_ Visual C++ 2005 Express Edition と Microsoft Platform SDK を一緒に使う(http://www.microsoft.com/japan/msdn/vstudio/express/visualc/usingpsdk/)というページに従ってインストールする。
合わせて50分くらいかかった。

とりあえずビルドを試みると、死ぬほど警告が表示された。
プロジェクトの設定で警告を切ると、いくつかのエラーが残った。
「for(char suffix」という宣言が利いていない問題は、言語の拡張設定で直った。
const char*をchar*に変換できないというエラーは、よく分からないので引数からconstを削除して黙らせた。
宣言の型が指定されていない部分がいくつかあったが、適当にintと書き足したら大人しくなった。

コンパイルは成功するようになったが、リンク時にリソースが重複しているとか言われてビルド完了できない。
設定で埋め込みマニフェストを無効にしたら、とりあえず回避できた。


そんなわけで、とりあえずビルドできたので、問題のあるスクリプトを実行させてデバッグしてみる。
GUIウィンドウが表示されてエラーが発生すると、実行中だった箇所や関数の呼び出し元、変数の内容などの情報が表示された。
思った通り、nullなオブジェクトの関数を呼び出している部分があった。
関数のローカル変数の情報を格納するオブジェクトのアドレスを格納する部分が、不正にnullになっているらしい。
通常は正しいアドレスが格納されていたので、どこかで上書きされてしまっているのだろう。

いつnullになってしまうのか調べるため、ブレークポイントを仕掛けてそのアドレスの変更を監視したところ、strlcpy関数で文字列のコピーを行っているときに上書きされてしまっているらしいことが分かった。
問題の箇所はscript.cppの以下の部分。
VarSizeType Script::GetFileDir(char *aBuf)
{
    char buf[MAX_PATH + 1]; // Uses +1 to append final backslash for AutoIt2 (.aut) scripts.
    char *target_buf = aBuf ? aBuf : buf;
    strlcpy(target_buf, mFileDir, MAX_PATH);    //!!!!!!!!!!!!!!!!!
aBufの指すアドレスにMAX_PATHを足すと、ちょうどnullになってしまった領域をまたいでいる。
aBufとして確保されている領域のサイズを考慮せずにMAX_PATH文字をコピーしてしまっているのが原因らしい。
呼び出し元を追跡すると、その変数の領域は64バイトしか確保されていないらしかった。

strlcpyが元の文字列の終端以降もコピーを行うのは妙な気がするが、Wikipediaの説明には指定されたサイズを超えないとしか書かれていないので、サイズ分丸ごとコピーされても文句は言えない。
と思ったら、よく見たらutil.hの中で自前で定義されていて、strncpyに丸投げされていた。
VCのstrncpyの説明にはコピー元の文字列が短かった場合は残りの部分を\0で埋めると書いてあったので、正しい動作らしい。

そんなわけで、原因はおおよそ特定できたが、改善策を考えるのが面倒なのであきらめた。
作者が適当に修正してくれることを祈る。


スクリプトの方は、適当にダミーの関数を追加したらとりあえず動くようになった。
いつ駄目になるか分からないので困る。
111管理人 ★:06/09/06 17:47 ID:???
2006年03月07日
■AutoHotkey(http://www.autohotkey.com/)1.0.42.06

がんばって英文を書いて公式のバグレポートに報告したところ、strncpyのバグが修正されたようで、問題のあったスクリプトが正常動作するようになった。
112管理人 ★:06/09/06 17:47 ID:???
2006年03月08日
■fenrir風の奴を修正
049.zip(http://lukewarm.s101.xrea.com/up/file/049.zip)

AutoHotkeyのバグが修正されて、エラーを気にせずに機能拡張できるようになったので、いくつか気になっていたところを改良した。

・上下キーでの移動の際、リストの上下をループするように
10個くらい候補があるときに下の方の項目を素早く選択したくなったので、一番上で↑キーを押したら一番下に行くようにした。

・IMEでEnterを押したときにIMEを無視して確定されてしまうのを修正
「/a」コマンドで日本語のタイトルを付けようと思ったら失敗したので気づいた。
ImmGetCompositionStringで変換中の文字列があったら、確定を行わないようにした。

・存在しないファイルを選択したとき、即座にインデックスから削除するようにした
ついでだから、上位フォルダのパスをチェックして、存在しない最上位階層からまとめて削除するようにした。


・「-」を付けると除外検索になるように
ノイズをまとめて消せるようにしたい。
1文字打つごとに前回の結果から絞り込む現在の方式では、「-t」と打った時点でtを含む全ての項目が消されてしまい、「-tx」になっても「tx」を含まずに「t」を含む項目が消えたままになってしまう。
除外検索があるときだけ、全候補から全キーワードで絞り込むようにすることも考えたが、打つたびに候補が増えていくというのは気にくわないのでやめた。
そこで、「-txt 」のようにスペースを打った時点で前の除外ワードによる絞り込みが行われるようにした。

・特殊記号を含むキーワードを検索する「+」記号を追加
「/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)のモジュールの方は、ツールチップテキストを取得する関数を追加した。
113管理人 ★:06/09/06 17:48 ID:???
2006年03月09日
■AutoHotkeyシステムモニタ用関数群(http://lukewarm.s101.xrea.com/myscripts/SystemMonitor.zip)

作った。
当初、RegQueryValueExでHKEY_PERFORMANCE_DATAから構造体を取得するという面倒くさそうな話を聞いていたが、PDH.DLLという物のAPIで簡略化できるらしい。
とりあえずサンプルを移植して動かしてみたが、システム全体のCPU使用率が取得できないし、なぜかカウンターを登録するときに以上に時間がかかるし、特定のプロセスIDの状態を監視するのも面倒くさそうで気に入らない。

その後、GetSystemTimes、GetProcessTimes、GlobalMemoryStatus、GetProcessMemoryInfo等を使えば普通に取得できることが分かる。
適当に作った関数でも、十分な速度で動作している模様。

PDH.DLLの存在意義が疑われる。
メモリとかCPU以外の色々な情報を取得したいときには役立つのだろうか?
114管理人 ★:06/09/06 17:49 ID:???
2006年03月10日
■AutoHotkey用システムモニタ用関数群(http://lukewarm.s101.xrea.com/myscripts/SystemMonitor.zip)更新

PDH.DLLのAPIでは様々な情報が取得できるが、.Netの奴の何かなど、訳の分からないものやどうでもいい物が大半だった。
しかし、ディスクのアクセス量なども取得できるらしいので、とりあえず関数を作ってみることに。

取得したい情報はパス文字列で指定しなければならない。
PdhBrowseCountersというAPIで項目を選択するダイアログが出せるとのことなので、それを呼び出す関数を作成した。

とりあえずディスクのアクセス率を取得してみると、それらしい物が取得できた。
アクセス率とアイドル率を足して100にならないなど怪しいところはあるが、気にしないことにする。

次に、ネットワークの使用率を取得してみる。
パス文字列にはネットワークインターフェイスの名前が含まれる。
ネットワークインターフェイスには「MS TCP Loopback interface」というのと、PCに接続されたNICらしき物の2つがある。
実際に必要なのはNICの方だが、PCによって違うので、何らかの方法で取得しなければならない。
PDHのAPIで自動取得できるようにするのは面倒だったので、以下のような方法で取得取得してもらうことにした。
RunWait,cmd /c route print > %tmp%\route.txt,,HIDE
FileReadLine,nic,%tmp%\route.txt,4
StringTrimLeft,nic,nic,32
FileDelete,%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を超えていて、あまり実用性はない。
115管理人 ★:06/09/06 17:50 ID:???
2006年03月12日
■AutoHotkey製コマンドラインランチャーの奴を更新
FileLaunch.zip(http://lukewarm.s101.xrea.com/myscripts/FileLaunch.zip)

飽きてきたので正式版っぽい感じにしてスクリプト公開ページに載せた。

検索機能を少し強化した。

・正規表現検索機能を追加
せっかくBREGEXP.DLLを使っているので、任意の正規表現で検索できるようにした。
or検索とか、任意の数字列を含むファイルを検索とか、たまに役立つかもしれない。

タイプの途中でマッチングが行われると困るので、除外検索の時と同じように後ろにスペースを打つまでは検索されないようにした。


・ファイルの名前部分のみから検索する機能を追加
AutoHotkey.exeを実行したいのにAutoHotkeyフォルダ内の全てのファイルが列挙されたりすると鬱陶しいので付けてみた。
パスを区切るのが面倒なんで、正規表現を生成して検索するように。

・デフォルトの検索モードを変数で指定するように
Migemoを頻繁に使う時でもいちいち「:」を付けるのは面倒なので、デフォルトの検索モードを変更できるようにした。
「/set SMode=:」のようなコマンドでも変更できる。

・短縮検索機能を追加
「@rm」で「readme.txt」を検索するなど、短縮ワードによる検索を可能にした。
正規表現検索モードなども割り当てられるので、「@ahk」で「AutoHotkey」か「.ahk」を含むアイテムを検索すると言ったことも可能。

検索モード指定文字は打ちやすいようにShiftと組み合わせないキーにしたかったが、ファイル名に使われない文字ではMigemoに割り当てている「:」しか無かったので、あまり使われなさそうで打ちやすい位置にある「@」を割り当てることにした。
116管理人 ★:06/09/06 17:50 ID:???
2006年03月13日
■AutoHotkey製コマンドラインランチャーの奴を更新
FileLaunch.zip(http://lukewarm.s101.xrea.com/myscripts/FileLaunch.zip)


・ドラッグ&ドロップでファイルを追加できるように
マウス操作はあまり必要ないだろうが、一応付けた。


・起動時や多重起動時に任意の動作を実行させる機能を追加
スクリプト中で番号にコマンドやサブルーチンを割り当てておいて、ウィンドウメッセージで実行させるように。
メッセージを送るウィンドウを検出するのが面倒だったので、スクリプト起動時にIniファイルに書き込んでおくようにした。
スクリプト以外のプログラムからも任意のコマンドを実行させられるように、Iniファイル経由でコマンドを指定する機能も付けた。


・内部コマンドをいくつか追加
上記の機能で使用するための物や、スキャンリストにフォルダを追加する物など、いくつか追加した。


・タイマーおよび拡張子判別実行を実現させる例を追加
拡張子ごとにファイルを開くプログラムを振り分けるようなコマンドを定義できるようにしようかと思ったが、面倒なんで内部コマンドとして記述してもらうことにした。
十分簡単な記述で実現できるので、わざわざ定義ファイルによる割り当て機能を付ける必要はないだろう。

定期的にスキャンなどを実行させる機能も、設定ファイルなどを用意するのは面倒なので、スクリプト中にSetTimer命令などで記述するようにした。



そんなわけで、今度こそ実現したかった機能は一通り作り終わった。
しばらく何も思いつかなかったら正式版ということにしよう。
いつの間にか配布ZIPファイルのサイズで21KBにもなってしまっていた。
117管理人 ★:06/09/06 17:50 ID:???
2006年03月27日
■AutoHotkey(http://www.autohotkey.com/)1.0.43.00

Sendコマンドに2つの別モードが用意されたらしい。
「SendInput」コマンドでは、同名のAPIを呼び出して一括して入力内容を流し込むらしい。
かなり高速らしいが、キーフックを使用していると利用できないらしく、あまり使い道はなさそう。

「SendPlay」では、ウィンドウメッセージのような仕組みで入力内容を送り込むらしい。
一部のゲームでは、通常のSendでは操作できないがSendPlayを使うことで操作できるようになるとのことだが、SendでもSendPlayでも操作できないゲームがあった。

これらの新しいモードは、従来のモードをSetKeyDelay,-1で使用した場合よりも高速に動作するとのことである。
試したところ、確かに多少高速になっていた。
また、一連の操作の間に外部から他の操作が割り込まれて動作がおかしくなるということも避けられるらしい。

また、新たにClickコマンドが追加された。
従来のMouseClickでは、コントロールパネルで左右のボタンを入れ替えていると、MouseClickが右クリックの動作に、MouseClick,Rが左クリックの動作になっていたが、Clickコマンドでは入れ替えがあってもなくても同じ動作が行われるらしい。
118管理人 ★:06/09/06 17:55 ID:???
以上。

2006年4月以降は
管理人の雑記(http://lukewarm.s101.xrea.com/test/read.cgi/bbs/1146398137/)

131KB
名前: E-mail:
ファイル:
0ch BBS 2005-10-08