凄いお世話になっているMr.XRAYさんのコードに、多分、一部の誤字があると思い、私なりに訂正してみた。
04_WH_MOUSE_LL と WH_KEYBOARD_LL
mrxray.on.coocan.jp
とはいえ、ほぼ、引用先のソースコードそのままです。これが書ける人って、凄いな。
ちなみに、「 //この条件を削除すれば,全てのウィンドウでのマウス操作を検出することになる」
という記述以降の条件をコメントアウトすると、本当に全てのウインドウでのマウス操作を検出します。
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls, ShellAPI; type TForm1 = class(TForm) ListView1: TListView; Panel3: TPanel; Button1: TButton; Button2: TButton; Panel4: TPanel; Panel1: TPanel; Panel2: TPanel; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private 宣言 } procedure DisplayKeyCodeMousePos(h: HWND; MsgStr: String; Int1,Int2: Integer); function GetWindowTextStr(hWindow:HWND):String; protected procedure WMApp100(var Message: TMessage); message WM_APP+100; procedure WMApp110(var Message: TMessage); message WM_APP+110; public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.DFM} //----------------------------------------------------------------------------- // 低レベルキーフックの情報構造体と定数 // LLMHF_INJECTEDはマウスフックで使用 // // Microsoft Windows SDK 7.1の記述(構造体もSDKからのもの) // Low level hook flags // // #define LLKHF_EXTENDED (KF_EXTENDED >> 8) // #define LLKHF_INJECTED 0x00000010 // #define LLKHF_ALTDOWN (KF_ALTDOWN >> 8) // #define LLKHF_UP (KF_UP >> 8) // #define LLMHF_INJECTED 0x00000001 //----------------------------------------------------------------------------- const LLKHF_EXTENDED = KF_EXTENDED shr 8; LLKHF_INJECTED = $00000010; LLKHF_ALTDOWN = KF_ALTDOWN shr 8; LLKHF_UP = KF_UP shr 8; LLMHF_INJECTED = $00000001; type LPKBDLLHOOKSTRUCT = ^KBDLLHOOKSTRUCT; tagKBDLLHOOKSTRUCT = record vkCode : DWORD; scanCode : DWORD; flags : DWORD; time : DWORD; dwExtraInfo : ULONG_PTR; end; KBDLLHOOKSTRUCT = tagKBDLLHOOKSTRUCT; TKbDllHookStruct = KBDLLHOOKSTRUCT; PKbDllHookStruct = LPKBDLLHOOKSTRUCT; //----------------------------------------------------------------------------- // 低レベルマウスフックのキー情報構造体 //----------------------------------------------------------------------------- LPMSLLHOOKSTRUCT = ^MSLLHOOKSTRUCT; tagMSLLHOOKSTRUCT = record pt: TPOINT; mouseData: DWORD; flags: DWORD; time: DWORD; dwExtraInfo: ULONG_PTR; end; MSLLHOOKSTRUCT = tagMSLLHOOKSTRUCT; TMsllHookStruct = MSLLHOOKSTRUCT; PMsllHookStruct = LPMSLLHOOKSTRUCT; var KeyHookHandle : HHOOK; MouseHookHandle : HHOOK; TargetWnd : HWND; //----------------------------------------------------------------------------- // マウスフックのコールバック関数 //----------------------------------------------------------------------------- function LowLevelMouseProc(Code:integer; wPar: WPARAM; lPar: LPARAM): LRESULT; stdcall; begin if Code < 0 then begin Result := CallNextHookEx(MouseHookHandle, Code, wPar, lPar); exit; end; if Code = HC_ACTION then begin PostMessage(Form1.Handle, WM_APP+100, wPar, 0); end; Result := CallNextHookEx(MouseHookHandle, Code, wPar, lPar); end; //----------------------------------------------------------------------------- // キーフックのコールバック関数 //----------------------------------------------------------------------------- function LowLevelKeyProc(Code: Integer; wPar: WPARAM; lPar: LPARAM): LRESULT; stdcall; var Lkbdll : PKBDLLHOOKSTRUCT; LScanCode : Integer; begin if Code < 0 then begin Result := CallNextHookEx(KeyHookHandle, Code, wPar, lPar); exit; end; Lkbdll := PKBDLLHOOKSTRUCT(lPar); if Code = HC_ACTION then begin if wPar = WM_KEYDOWN then begin LScanCode := Lkbdll.scanCode; PostMessage(Form1.Handle, WM_APP+110, LScanCode, Lkbdll.vkCode); end; end; Result := CallNextHookEx(KeyHookHandle, Code, wPar, lPar); end; //============================================================================= // フォーム生成時の処理 // ListViewの各カラムを設定 //============================================================================= procedure TForm1.FormCreate(Sender: TObject); begin ListView1.ViewStyle:=vsReport; ListView1.Columns.Add; ListView1.Columns[0].Caption := ' TITLE'; ListView1.Columns[0].Width := 130; ListView1.Columns.Add; ListView1.Columns[1].Caption := ' HANDLE '; ListView1.Columns[1].Width := 66; ListView1.Columns.Add; ListView1.Columns[2].Caption := ' EVENT'; ListView1.Columns[2].Width := 85; end; //============================================================================= // アプリ終了時はフック関数をアンインストール(登録解除)して対象アプリを終了 // WH_MOUSE,WH_KEYBORDと違いアンインストールに時間がかかるような気がする //============================================================================= procedure TForm1.FormDestroy(Sender: TObject); begin if MouseHookHandle <> 0 then UnhookWindowsHookEx(MouseHookHandle); if KeyHookHandle <> 0 then UnhookWindowsHookEx(KeyHookHandle); if TargetWnd <> 0 then begin SendMessage(TargetWnd, WM_CLOSE, 0, 0); end; end; //============================================================================= // [StartHook]ボタン // フック開始 // イベントの発生を記録する対象としてメモ帳を起動 // フック関数をインストール(登録) // // TargetWndは起動したメモ帳のウィンドウハンドルでグローバル変数 //============================================================================= procedure TForm1.Button1Click(Sender: TObject); begin TargetWnd := FindWindow('NotePad', nil); if TargetWnd = 0 then begin ShellExecute(Self.Handle,'open', PChar('Notepad.exe'), nil, nil,SW_SHOW); while True do begin TargetWnd := FindWindow('NotePad', nil); if TargetWnd <> 0 then break; Application.ProcessMessages; end; end; //マウスとキーのグローバルフック開始 if MouseHookHandle = 0 then MouseHookHandle := SetWindowsHookEx(WH_MOUSE_LL, @LowLevelMouseProc, hInstance, 0); if KeyHookHandle = 0 then KeyHookHandle := SetWindowsHookEx(WH_KEYBOARD_LL, @LowLevelKeyProc, hInstance, 0); end; //============================================================================= // [StopHook]ボタン // フック終了 // フック関数をアンインストール(登録解除) //============================================================================= procedure TForm1.Button2Click(Sender: TObject); begin if MouseHookHandle <> 0 then begin UnhookWindowsHookEx(MouseHookHandle); MouseHookHandle := 0; end; if KeyHookHandle <> 0 then begin UnhookWindowsHookEx(KeyHookHandle); KeyHookHandle := 0; end; end; //----------------------------------------------------------------------------- // フックしたマウス情報を受取る //----------------------------------------------------------------------------- procedure TForm1.WMApp100(var Message: TMessage); var LhTarget : HWND; LMsgStr : String; LMousePos : TPoint; begin case Message.WParam of WM_NCMOUSEMOVE : LMsgStr := 'NC_MouseMove'; WM_NCLBUTTONDOWN : LMsgStr := 'NC_LButtonDown'; WM_NCLBUTTONUP : LMsgStr := 'NC_LButtonUp'; WM_NCLBUTTONDBLCLK : LMsgStr := 'NC_LButtonDBLClick'; WM_NCRBUTTONDOWN : LMsgStr := 'NC_RButtonDown'; WM_NCRBUTTONUP : LMsgStr := 'NC_RButtonUp'; WM_NCRBUTTONDBLCLK : LMsgStr := 'NC_RButtonDBLClick'; WM_NCMBUTTONDOWN : LMsgStr := 'NC_MButtonDown'; WM_NCMBUTTONUP : LMsgStr := 'NC_MButtonUp'; WM_NCMBUTTONDBLCLK : LMsgStr := 'NC_MButtonDBLClick'; WM_MOUSEMOVE : LMsgStr := 'MouseMove'; WM_LBUTTONDOWN : LMsgStr := 'LButtonDown'; WM_LBUTTONUP : LMsgStr := 'LButtonUp'; WM_LBUTTONDBLCLK : LMsgStr := 'LButtonDBLClick'; WM_RBUTTONDOWN : LMsgStr := 'RButtonDown'; WM_RBUTTONUP : LMsgStr := 'RButtonUp'; WM_RBUTTONDBLCLK : LMsgStr := 'RButtonDBLClick'; WM_MBUTTONDOWN : LMsgStr := 'MButtonDown'; WM_MBUTTONUP : LMsgStr := 'MButtonUp'; WM_MBUTTONDBLCLK : LMsgStr := 'MButtonDBLClick'; WM_MOUSEWHEEL : LMsgStr := 'MouseWheel'; WM_MOUSEHWHEEL : LMsgStr := 'MouseHWheel'; end; //最前面のウィンドウのハンドルがTargetWndと同じだったら処理 //この条件を削除すれば,全てのウィンドウでのマウス操作を検出することになる LhTarget := GetForegroundWindow; if LhTarget = TargetWnd then begin GetCursorPos(LMousePos); //アクティブウィンドウのタイトルと操作内容をListViewに表示 Form1.DisplayKeyCodeMousePos(LhTarget, LMsgStr, LMousePos.X, LMousePos.Y); end; end; //----------------------------------------------------------------------------- // フックしたキーボード情報を受取る // KEYDOWNで送られてくる //----------------------------------------------------------------------------- procedure TForm1.WMApp110(var Message: TMessage); var LKey : WORD; LMsgKind : WORD; LhTarget : HWND; LMsgStr : String; begin LKey := Message.LParam; LMsgKind := Message.WParam; LMsgStr := 'KeyDown'; //最前面のウィンドウのハンドルがTargetWndと同じだったら処理 //この条件を削除すれば,全てのウィンドウでのキー操作を検出することになる LhTarget := GetForegroundWindow; if LhTarget = TargetWnd then begin //アクティブウィンドウのタイトルと操作内容をListViewに表示 Form1.DisplayKeyCodeMousePos(LhTarget, LMsgStr, LKey, LMsgKind); end; end; //----------------------------------------------------------------------------- // ウィンドウのタイトルとハンドル番号,操作内容をListViewに表示 // また,押下したキー文字と仮想キーコード,マウス座標値を表示 //----------------------------------------------------------------------------- procedure TForm1.DisplayKeyCodeMousePos(h: HWND; MsgStr: String; Int1, Int2: Integer); var LItem : TListItem; LCode : Integer; begin LItem := ListView1.Items.Add; LItem.Caption := GetWindowTextStr(h); LItem.SubItems.Add(IntToStr(h)); LItem.SubItems.Add(MsgStr); //ListViewの一番最後を表示 ListView1.Items[ListView1.Items.Count-1].Selected := True; ListView1.Items[ListView1.Items.Count-1].Focused := True; ListView1.Items[ListView1.Items.Count-1].MakeVisible(True); if MsgStr = 'KeyDown' then begin LCode := Int1 and $FF; Panel1.Caption := Chr(LCode) + Format(' %.2d ($%.2x)', [LCode,LCode]); end; if MsgStr = 'LButtonDown' then begin Panel2.Caption := Format('[ X=%.4d Y=%.4d ]', [Int1, Int2]); end; end; //----------------------------------------------------------------------------- // 対象のウィンドウハンドルhWindowからそのタイトル(キャプション)を取得 //----------------------------------------------------------------------------- function TForm1.GetWindowTextStr(hWindow: HWND): String; var Buff : array [0..MAX_PATH-1] of Char; begin FillChar(Buff[0], MAX_PATH, #0); GetWindowText(hWindow, Buff, GetWindowTextLength(hWindow) + 1); Result := String(Buff); end; end.