マウスOnタイトルバーチェック関数(テスト版)

マウスの下にウィンドウキャプションがあるかどうかを判定する関数
qdirもどき実現のためFunction実装前からsubでチョロチョロ作ってたもの。微妙な判定位置ズレとかアイコン検出とか調整してたらかなり冗長に。もうちょい推考するつもりだったけど時間取れないので、とりあえず動くものを置いときます。

2ちゃんのAhkスレではSendMessageでもっと簡単にできそうな雰囲気なのでちょっと期待

#Persistent

auto:
    settimer,test
return

test:
     r := CheckOnMouseTitleBarEx(rhWnd,1)
     tooltip,%r%
return

CheckOnMouseTitleBarEX(byref rhWnd, MdiChild=0, def_cmode=1)
;-----------------------------------------------------------------
;  マウスがタイトルバー上の何処にあるかチェックして返す
;   対象: AHK v1.0.34以降          作成 : 2005.10.25
;
;       out rhWnd       マウス下ウィンドウハンドル
;       in  MdiChild    1:MDI子ウィンドウを対象に含める
;           def_cmode   元のマウスモード 1:Relative(デフォルト) 0:Screen
;
;   戻り値
;       0 : タイトルバー上ではない
;       1 : タイトルバー
;       2 : 右上アイコン
;       3 : 最小化ボタン [_]
;       4 : 最大化ボタン [□]
;       5 : ヘルプボタン [?]
;       6 : 閉じるボタン [X]
;-----------------------------------------------------------------
{
    ;--- マウス座標値直下のコントロールハンドル取得 ---
    CoordMode,Mouse,Screen
    MouseGetPos,ScreenX,ScreenY,hWnd
    if (MdiChild)
        hWnd := DllCall("WindowFromPoint",Int,ScreenX, Int,ScreenY, UInt)
    WinGetPos  ,WinL,WinT,WinW,,ahk_id %hWnd%
    WinGet, WinStyle,  Style,   ahk_id %hWnd%
    WinGet, WinExStyle,ExStyle, ahk_id %hWnd%
    ifEqual def_cmode,1,    CoordMode,Mouse,Relative ;座標モードを戻しとく

    ;--- マウスがタイトルバー上にあるかチェック ---
    if (WinStyle & 0x00C00000 <> 0x00C00000)    ;WS_CAPTION
        return 0                                ;マウス下:タイトルなし
    if (WinExStyle & 0x00000080)        ;WS_EX_TOOLWINDOW
    {   ;小さいツールバー
         SysGet, barH,     51           ;SM_CYSMCAPTION :タイトル高さ
         SysGet, BtnWidth, 52           ;SM_CXSMSIZE    :[_][?][□][X]ボタン幅
    }
    else
    {
        SysGet, barH,    4              ;SM_CYCAPTION   :タイトル高さ
        SysGet, BtnWidth,30             ;SM_CXSIZE      :[_][?][□][X]ボタン幅
    }
    if (WinT + barH < ScreenY)
        return 0                        ;タイトルバー高さ < マウスY

    rhWnd := hWnd
    if (!(WinStyle & 0x00080000))       ;WS_SYSMENU
        return 1

    ;--- タイトルバー上のどの位置にあるかをチェック ---
    if (WinStyle & 0x00040000 = 0x00040000) ;WS_THICKFRAME
         SysGet, frameW,32                  ;SM_CXSIZEFRAME  可変窓  枠幅
    else SysGet, frameW,7                   ;SM_CXFIXEDFRAME 不可変窓
    title_R := WinL + WinW - frameW

    if (ScreenX > title_R - BtnWidth)
        return 6                            ;[x]

    ; 右から2つ目ボタンチェック (最大化 or ToolHelpボタン)
    else if (ScreenX > title_R - (BtnWidth * 2))
    {
        if (WinStyle & 0x00010000)          ;WS_MAXIMIZEBOX [□]
            return 4
        else if (WinExStyle & 0x00000400)   ;WS_EX_CONTEXTHELP [?]
            return 5
    }

    ; 右から3つ目ボタンチェック (最小化)
    else if (ScreenX > title_R - (BtnWidth * 3))
    {
        if (WinStyle & 0x00020000) ;WS_MINIMIZEBOX [_]
            return 3
    }


/* ※※※※アイコン存在確認法テスト用 ※※※※※

    ;WNDCLASSEX 構造体にセットされたアイコン
    GCL_HICON := DllCall("GetClassLong", Uint,hWnd, Int,-14)    ;GCL_HICON
    GCL_HICONSM := DllCall("GetClassLong", Uint,hWnd, Int,-34)  ;GCL_HICONSM

    ;WM_SETICON メッセージによってセットされたアイコンを取得
    SendMessage,0x007F,0,0,,ahk_id %hWnd%   ;ICON_SMALL
    ICON_SMALL := ErrorLevel
    SendMessage,0x007F,1,0,,ahk_id %hWnd%   ;ICON_BIG
    ICON_BIG := ErrorLevel
    SendMessage,0x007F,2,0,,ahk_id %hWnd%   ;ICON_SMALL2(XP)
    ICON_SMALL2 := ErrorLevel
    OutputDebug, GCL_HICON=%GCL_HICON%  GCL_HICONSM=%GCL_HICONSM%   ICON_BIG=%ICON_BIG%  ICON_SMALL=%ICON_SMALL%  ICON_SMALL2=%ICON_SMALL2%

※※※※※※※※※※※※※※※※※※※※※※※※
 */

    ; --- 左上アイコンチェック ---  
    ;大きいアイコンチェック
    iTemp := DllCall("GetClassLong", Uint,hWnd, Int,-14)    ;GCL_HICON
    if (!iTemp)
    {
        SendMessage,0x007F,1,0,,ahk_id %hWnd%   ;ICON_BIG
        iTemp := ErrorLevel
    }

/* 
    ;小さいアイコンチェック
    if (!iTemp)
        iTemp := DllCall("GetClassLong", Uint,hWnd, Int,-34)    ;GCL_HICONSM
    if (!iTemp)
    {
        SendMessage,0x007F,0,0,,ahk_id %hWnd%   ;ICON_SMALL
        iTemp := ErrorLevel
    }
    if (!iTemp)
    {
        SendMessage,0x007F,2,0,,ahk_id %hWnd%   ;ICON_SMALL2(XP)
        iTemp := ErrorLevel
    }
 */
    ifEqual iTemp,0,            return 1
    SysGet, work, 49            ;SM_CXSMICON
    SysGet, work2,45            ;SM_CXEDGE
    if (ScreenX < WinL + work + work2 + frameW)
         return 2
    else return 1
}

PressIt! もどき

スクリプトフォルダ整理してきたら出てきた。前に2ちゃんのAutoHotKey Threadに貼った奴、の見た目改良版。もしくはCheckBoxをトグルボタンにするサンプルとでも。コントロール系のスタイルはほとんどノーチェックだったので最近までこういうのできるって知らなかったのよ。

 ;---- PressIt.Ahk ----
autoexecute:
    gui,add,checkbox,-Wrap GPressIt 0x00001000 X1  Y3 W60 H20 , SHIFT
    gui,add,checkbox,-Wrap GPressIt 0x00001000 X61 Y3 W60 H20 , CTRL
    gui,+AlwaysOnTop -MaximizeBox -MinimizeBox ToolWindow
    gui,show, w125 h25 ; , Status & Toggle
    settimer,keywatch,100
return

keywatch:  ;Shift,Ctrl押下監視
    GuiControl,,SHIFT,% GetKeyState("Shift")
    GuiControl,,CTRL, % GetKeyState("Ctrl")
return

PressIt:  ;ボタン押下で Shift or Ctrl ON/OFFトグル
    ToggleKey(A_GuiControl)
return

ToggleKey(keyname)  ;キーの押下状態を反転する関数
{
    if (GetKeyState(keyname))
        Send,{%keyname% Up}
    else
        Send,{%keyname% Down}
}

GuiClose:  ;押下状態にあるキーを解除してスクリプト終了
    if (!GetKeyState(Shift,"P"))
        Send,{Shift Up}
    if (!GetKeyState(Ctrl,"P"))
        Send,{Ctrl Up}
    exitapp

MDIアクティブウィンドウ取得関数

ついでに、面倒なことせんでもアクティブ子ウィンドウはSendMessageで取れるらしいのでそれも上げときます。

MdiGetActive(WinTitle="", MdiClientName="")
MDIにおいて現在アクティブなウィンドウのハンドルを取得する
MdiGetActive(WinTitle="", MdiClientName="")
;----------------------------------------------------------------------
;   MDIにおいて現在アクティブなウィンドウのハンドルを取得する
;       対象: AHK v1.0.34以降       作成 : 2005.11.21
;   in  WinTitle        対象親ウィンドウ (省略時:アクティブウィンドウ)
;       MdiClientName   MDIクライアント名(省略時:MdiClient1)
;   戻り値:MDI子ウィンドウハンドル
;----------------------------------------------------------------------
{
    ifEqual,WinTitle,,  SetEnv,WinTitle,A
    if (MdiClientName = "")
    {
        MdiClientName := "MdiClient1"
        WinGetClass,cls,%WinTitle%
        ifEqual cls,XLMAIN,     SetEnv,MdiClientName,XLDESK1
    }

    SendMessage, 0x229 , 0, 0, %MdiClientName%, %WinTitle%  ;WM_MDIGETACTIVE
    ifEqual ErrorLevel,FAIL,    return 0
    else                        return %ErrorLevel%
}

MDI子ウィンドウ列挙関数 修正

AutoHotkeyのバージョンを0.40.08にしてから エクセルの子ウィンドウアクティブ操作に失敗するようになった。なんでかと思って調べたら自作のExcel用MDI子ウィンドウ列挙関数(GetMdiChildWindowList)で WS_VISIBLEを見てないせいで不可視の Persnal.xlsやアドインコントロールなんかまで子ウィンドウ判定してしまってたのが原因だった。(1.0.40.05 で DetectHiddenWindows OFF状態でも 非可視ウィンドウのスタイルが取れるようになってたらしい。最近バージョンアップしてなかったので気がつかなかった。)

Styleの 0x10000000 が WS_VISIBLEなんだけど、ver 1.0.40.04では Style/ExStyle値は不定値だったっぽい。

--- ahk 1.0.40.04 (DetectHiddenWindows,ON) ---
hwnd = 263050
title = Personal.xls
Style = 0x46C40000
ExStyle= 0x00000300

--- ahk 1.0.40.04 (DetectHiddenWindows,OFF) ---
hwnd = 263050
title =
Style = 0x56C40000
ExStyle=
※ 上記ハンドルと同一のコントロールを抽出 Personal.xlsと推測

--- ahk 1.0.40.08 (DetectHiddenWindows,OFF) ---
hwnd = 263050
title = Personal.xls
Style = 0x46C40000
ExStyle= 0x00000300

てことでhttp://d.hatena.ne.jp/eamat/20050906/:Title=9/6の分をWS_VISIBLEのビットも見るよう修正しました

パソコンテレビ GyaOを試してみた。

CM収入による運営で視聴者の皆様には一切料金はかからない。普通のTVと違うのはお好きな時間に何度でも視聴できる、とのこと。試しに一番組視聴してみたが通常のTV番組と同じように番組の合間にCM動画が入る、録画のできないTVといった印象。*1思ったよりラインナップが多くないなーと思ってよく見たら、各番組には「12月10日まで」等のラベルが貼られてる。「お好きな時間に何度でも」という謳い文句で勘違いしたが実際は期間限定での提供らしい、まぁそりゃそうか。なんていうか映像の図書館みたいなのを想像していたのでちょっと(´・ω・`) 図書館で言うところの外部持ちだし禁止の書物みたいな感じで、録画、貸出しはできないけど図書館(サイト)内でなら半永久的にいつ行っても閲覧可能、みたいな。そういうんだったら利用しがいがあるんだけどなぁ。
自分の場合そんなに積極的にテレビ見るほうじゃないので放映期間中にGyaOを訪れなければ観られないのではあんまり意味がなさそうだ。むしろ録画できる分普通のテレビのがアレかもなぁ、何て思ってしまったりして。

*1:普通にブラウザから見てる分での話。技術的にどうにかできる方法があるかは知らない。

 v1.0.40.08 メモリリークバグ修正

関数の再帰コール時のメモリリークバグが修正されたっぽい。試しに再度テストしてみたが実行するごとにメモリ使用量が増えていく現象はなくなった。ただ、テストでは再帰関数とそうでない関数でメモリ使用量が倍近く変化する。

起動時 メモリ常駐: 3980kb 仮想メモリ: 2352kb
test1(通常)実行 メモリ常駐: 3988kb 仮想メモリ: 2364kb
test2(再帰)実行 メモリ常駐: 6568kb 仮想メモリ: 4972kb
test2(再帰)実行 メモリ常駐: 6572kb 仮想メモリ: 4972kb

再帰関数の方が普通よりメモリ食うってことですかね。テストの内容にもよるかもだけど

#1::    OutputDebug, % test1(2,100)
#2::    OutputDebug, % test2(2,100)

test1(add,cnt)
{
    result=0
    loop,%cnt%
        result := add + result
    return result
}
test2(add,cnt)
{
    result=0
    if (cnt > 0)
        result := add + test2(add,cnt-1)
    return result
}

廃人まっしぐら

えー、秋口に冬に備えてリクライニングベッドとベッドテーブルを購入してたんですがいざ寒くなってきたらやおら腰がヤヴァくなってリクライニングに堪えられない。結果枕元にLOOX置いて横寝でネットするはめに。その後峠は越したもののエアコンのリモコンは行方不明だしテーブルの上はジャンプでいっぱいだしーで横寝モバイルは継続中。なんかもーなんもかんもかったるくっていけない。これが噂の冬季鬱病というやつだろうか(違)