Delphi Programming / Object Pascal
[掲載 2008年04月13日] [更新 2013年09月29日] Delphi サンプルプログラム集 |
261_マウスカーソル位置に画像を表示 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE Pro |
|
261_HookMouseEvent01.zip [1,717 KB] 2013年09月21日版 (EXE 同梱) |
- 2009年07月27日
- コールバックの戻り値 (Result) を CallNextHookEx の戻り値とした
- 2010年08月23日
- ポップアップメニューの後ろに画像が隠れてしまう現象を修正
- グローバルマウスフックとキーフックの DLL を使用するコードに変更
(WH_JOURNALRECORD が Windows Vista 以降では機能しないため)
- 2010年08月24日
- DLL を使用しない低レベルのマウスフックを利用したサンプルコードを追加
- 2013年09月21日
- サンプル [01] に,UIPI (ユーザーインターフェイス特権の分離) 対応コードを追加
- 複数のカーソルを定義して,切り替えて使用する方法のコードを追加
|
01_マウスカーソル位置に画像を表示 - WH_MOUSE フック使用 |
グローバルフックを使用して,マウスの位置に画像を表示するようにしたサンプルです.
このサンプルは,マウスとキーのグローバルフックのサンプルを変更修正して作成しました.
フックを開始すると,アクティブな,入力フォーカスがあるウィンドウのキャプションと,マウス位置の座標を表示します.マウスカーソル位置に画像を置いたフォームを表示します.このフォームは透明化していて,実行時には画像しか表示しません.
UIPI (ユーザーインターフェイス特権の分離) 対応コードについては,[ドラッグ・アンド・ドロップ機能の実装 (Vista 以降の UIPI 対応)] 記事も参考にしてください. |
[備考]
管理者権限で起動しているアプリのウインドウ内では,フックが無効になることがあります.その場合は,本サンプルを管理者権限で実行してください. |
|
図1
設計時画面 1
|
|
図2
設計時画面 2
|
|
図3
実行画面
|
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
Button2: TButton;
Panel2: TPanel;
Panel3: TPanel;
ListView1: TListView;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private 宣言 }
procedure DisplayKeyCodeMousePos(hWindow: HWND; MsgStr: String;
Int1,Int2: Integer);
function GetWindowTextStr(hWindow:HWND):String;
protected
procedure WMApp100(var Message: TMessage); message WM_APP+100;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses KaeruUnit;
{$R *.DFM}
function StartMouseHook(Wnd: HWND): HHOOK; stdcall; external 'PLMOUSEHOOK.DLL';
procedure StopMouseHook; stdcall; external 'PLMOUSEHOOK.DLL';
var
Hook : HHOOK;
//=============================================================================
// ListViewの各カラムを設定
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
ListView1.ViewStyle := vsReport;
ListView1.Columns.Add;
ListView1.Columns[0].Caption := ' アクティブウィンドのタイトル';
ListView1.Columns[0].Width := 218;
ListView1.Columns.Add;
ListView1.Columns[1].Caption := ' EVENT';
ListView1.Columns[1].Width := 90;
end;
//=============================================================================
// アプリ終了時はフック関数をアンインストール(登録解除)
//=============================================================================
procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeAndNil(KaeruForm);
UnhookWindowsHookEx(Hook);
end;
//=============================================================================
// フック関数をインストール(登録)
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
const
// Microsoft Windows SDK 7.1 より抜粋
// * Message Filter
// #define MSGFLT_ADD 1
// #define MSGFLT_REMOVE 2
MSGFLT_ADD = 1;
MSGFLT_REMOVE = 2;
var
DLLHandle : THandle;
FuncFilter : function (msg: Cardinal; dwFlag: DWORD): BOOL; stdcall;
begin
//UIPI(ユーザーインターフェイス特権の分離)対応処理
//このプログラムを管理者権限で実行してもWM_APP+100メッセージの受信を可能にする
if CheckWin32Version(6, 0) then begin
DLLHandle := loadLibrary('user32.dll');
try
if DLLHandle > 0 then begin
@FuncFilter := GetProcAddress(DLLHandle, 'ChangeWindowMessageFilter');
if @FuncFilter <> nil then begin
FuncFilter(WM_APP+100, MSGFLT_ADD);
end;
end;
finally
FreeLibrary(DLLHandle);
end;
end;
StartMouseHook(Handle);
if KaeruForm = nil then KaeruForm := TKaeruForm.Create(Self);
KaeruForm.Show;
ListView1.Items.Clear;
end;
//=============================================================================
// フック関数をアンインストール(登録解除)
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
Windows.BringWindowToTop(GetActiveWindow);
KaeruForm.Close;
StopMouseHook;
end;
//-----------------------------------------------------------------------------
// DLLからグローバルフックしたマウス情報を受取る
//-----------------------------------------------------------------------------
procedure TForm1.WMApp100(var Message: TMessage);
var
LhTarger : HWND;
LMsgStr : String;
LMousePos : TPoint;
begin
case Message.WParam of
WM_NCMOUSEMOVE: LMsgStr := 'NCMouseMove';
WM_NCLBUTTONDOWN: LMsgStr := 'NCLButtonDown';
WM_NCLBUTTONUP: LMsgStr := 'NCLButtonUp';
WM_NCRBUTTONDOWN: LMsgStr := 'NCRButtonDown';
WM_NCRBUTTONUP: LMsgStr := 'NCRButtonUp';
WM_MOUSEMOVE: LMsgStr := 'MouseMove';
WM_LBUTTONDOWN: LMsgStr := 'LButtonDown';
WM_LBUTTONUP: LMsgStr := 'LButtonUp';
WM_RBUTTONDOWN: LMsgStr := 'RButtonDown';
WM_RBUTTONUP: LMsgStr := 'RButtonUp';
end;
LhTarger := GetForegroundWindow;
if LhTarger <> 0 then begin
GetCursorPos(LMousePos);
//アクティブウィンドウのタイトルと操作内容をListViewに表示
Form1.DisplayKeyCodeMousePos(LhTarger, LMsgStr, LMousePos.X, LMousePos.Y);
end;
end;
//-----------------------------------------------------------------------------
// ウィンドウのタイトルと操作内容をListViewに表示
// また,マウス座標値を表示
//-----------------------------------------------------------------------------
procedure TForm1.DisplayKeyCodeMousePos(hWindow: HWND; MsgStr: String;
Int1, Int2: Integer);
var
LItem : TListItem;
LTargetWnd : HWND;
begin
if MsgStr = '' then exit;
LItem := ListView1.Items.Add;
//現在入力フォーカスのあるウィンドウ
LTargetWnd := Handle;
if (hWindow <> Handle) then begin
//マウスカーソルと共に表示する画像(フォーム)を最前面に
Windows.BringWindowToTop(KaeruForm.Handle);
LTargetWnd := hWindow;
end;
LItem.Caption := GetWindowTextStr(LTargetWnd);
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);
Panel2.Caption := Format('[ X=%.4d Y=%.4d ]',[Int1,Int2]);
//Int1はX座標値.Int2はY座標値
KaeruForm.Left := Int1 + 1;
KaeruForm.Top := Int2 + 1;
//ここでマウスの操作状態で画像を変更することも可能
//最初からアニメーション(gif画像)等を使用すれば面白いかも
end;
//-----------------------------------------------------------------------------
// 対象のウィンドウハンドルhWindowからそのタイトル(キャプション)を取得
//-----------------------------------------------------------------------------
function TForm1.GetWindowTextStr(hWindow: HWND): String;
var
Buff : array [0..MAX_PATH-1] of Char;
begin
FillChar(Buff, MAX_PATH, #0);
GetWindowText(hWindow, Buff, GetWindowTextLength(hWindow) + 1);
Result := String(Buff);
end;
end.
unit KaeruUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TKaeruForm = class(TForm)
Image1: TImage;
procedure FormCreate(Sender: TObject);
protected
procedure CreateParams(var Params: TCreateParams); override;
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
KaeruForm: TKaeruForm;
implementation
{$R *.dfm}
//=============================================================================
// ウィンドウスタイルの変更
//
// メインフォームのFormStyleはfsStayOnTop
// このフォームの設定は以下の通り
// FormStyle := fsNormal;
// BorderStyle := bsNone;
//=============================================================================
procedure TKaeruForm.CreateParams(var Params: TCreateParams);
begin
inherited;
//前面に表示
Params.ExStyle := Params.ExStyle or WS_EX_TOPMOST;
end;
//=============================================================================
// 以下はオブジェクト・インスペクタで設定するのが良
// TransparentColorはデフォルトのclBtnfaceでは無効なので他の色に変更
//=============================================================================
procedure TKaeruForm.FormCreate(Sender: TObject);
begin
Self.Color := clSkyBlue;
Self.TransparentColor := True;
Self.TransparentColorValue := Self.Color;
end;
end.
リスト3
マウスフックDLLのプロジェクトファイル |
library plMouseHook;
uses
plMouseHookUnit in 'plMouseHookUnit.pas';
//-----------------------------------------------------------------------------
// 外部からDLL内のメソッドを利用可能にするためのオマジナイ
//-----------------------------------------------------------------------------
exports
StartMouseHook,
StopMouseHook;
end.
unit plMouseHookUnit;
interface
uses
Windows, Messages, SysUtils;
//外部のアプリケーションから使用する関数類
function StartMouseHook(Wnd: HWND): Boolean; stdcall;
procedure StopMouseHook; stdcall;
implementation
//共有メモリの内容の構造体
type
PHookInfo = ^THookInfo;
THookInfo = record
HookHandle : HHOOK;
HostWnd : HWND;
end;
var
//メモリマップドファイルのハンドル
hMapFile : THandle;
const
//メモリマップドファイル名
MapFileName = 'plMouseHookDLL';
//-----------------------------------------------------------------------------
// 共有メモリアクセスのための準備
//
// 成功すると0を返す.失敗すると負数を返す.
// 負の値で処理を分岐できるようになっているが,このコードでは未使用.
//-----------------------------------------------------------------------------
function MapFileMemory(var hMap: THandle; var pMap: pointer): Integer;
begin
//メモリマップドファイルを開く
hMap := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, MapFileName);
if hMap = 0 then begin
Result := -1;
exit;
end;
//メモリマップドファイルの割り当て
pMap := MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if pMap = nil then begin
Result := -2;
CloseHandle(hMap);
exit;
end;
Result := 0;
end;
//-----------------------------------------------------------------------------
// 共有メモリアクセスの後始末
// 割当てたメモリがあればビューを解除
// ハンドルがあればクローズ
//-----------------------------------------------------------------------------
procedure UnMapFileMemory(hMap: THandle; pMap: Pointer);
begin
if pMap <> nil then UnmapViewOfFile(pMap);
if hMap <> 0 then CloseHandle(hMap);
end;
//-----------------------------------------------------------------------------
// フックのコールバック関数
// このDLLを使用したアプリにメッセージを送る
//-----------------------------------------------------------------------------
function MouseHookProc(nCode: Integer; wPar: WPARAM; lPar: LPARAM):
LRESULT; stdcall;
var
LpMap : Pointer;
LMapWnd : THANDLE;
begin
Result := 0;
if MapFileMemory(LMapWnd, LpMap) <> 0 then exit;
if nCode < 0 then begin
Result := CallNextHookEx(pHookInfo(LpMap)^.HookHandle, nCode, wPar, lPar);
end else begin
if nCode = HC_ACTION then begin
PostMessage(pHookInfo(LpMap)^.HostWnd, WM_APP+100, wPar, lPar);
end;
Result := CallNextHookEx(pHookInfo(LpMap)^.HookHandle, nCode, wPar, lPar);
end;
UnMapFileMemory(LMapWnd, LpMap);
end;
//-----------------------------------------------------------------------------
// フック関数の登録
//-----------------------------------------------------------------------------
function StartMouseHook(Wnd: HWND): Boolean; stdcall;
var
LpMap : Pointer;
LMapWnd : THandle;
begin
Result := False;
//メモリマップドファイル使用準備
MapFileMemory(LMapWnd, LpMap);
if LpMap = nil then begin
LMapWnd := 0;
exit;
end;
//フック情報構造体初期化とフック関数の登録
pHookInfo(LpMap)^.HostWnd := Wnd;
//フックをインストール
pHookInfo(LpMap)^.HookHandle := SetWindowsHookEx(WH_MOUSE,
Addr(MouseHookProc),
hInstance,
0);
//フック成功
if pHookInfo(LpMap)^.HookHandle > 0 then begin
Result := True;
end;
//メモリマップドファイル使用終了処理
UnMapFileMemory(LMapWnd, LpMap);
end;
//-----------------------------------------------------------------------------
// フックの解除
//-----------------------------------------------------------------------------
procedure StopMouseHook; stdcall;
var
LpMap : Pointer;
LMapWnd : THandle;
begin
//メモリマップドファイル使用準備
MapFileMemory(LMapWnd, LpMap);
if LpMap = nil then begin
LMapWnd := 0;
exit;
end;
//フック解除
if pHookInfo(LpMap)^.HookHandle > 0 then begin
UnhookWindowsHookEx(pHookInfo(LpMap)^.HookHandle);
end;
//メモリマップドファイル使用終了処理
UnMapFileMemory(LMapWnd, LpMap);
end;
//-----------------------------------------------------------------------------
// ユニット初期化部
// メモリマップドファイルの作成
//
// High(NativeUInt)の値は
// 32ビットアプリでは$FFFFFFFF
// 64ヒットアプリでは$FFFFFFFFFFFFFFFF
//-----------------------------------------------------------------------------
initialization
begin
hMapFile := CreateFileMapping(High(NativeUInt),
nil,
PAGE_READWRITE,
0,
SizeOf(THookInfo),
MapFileName);
end;
//-----------------------------------------------------------------------------
// ユニット終了処理部
// メモリマップドファイルのクローズ
//-----------------------------------------------------------------------------
finalization
begin
if hMapFile<>0 then CloseHandle(hMapFile);
end;
end.
02_WH_MOUSE フックにおけるマウスカーソル位置の取得 |
上のサンプルでは,マウスカーソルの位置を GetCursorPos 関数で取得しています.
フックのコールバック関数内でマウスカーソル位置を取得して,受信側で受け取るようにすることもできます.それには,マウスフックの情報を格納している構造体 (レコード型) からマウスカーソル位置を取得します.
次のコードでは,PostMessage の LParam パラメータの上位ワードと下位ワードにマウスカーソルの座標値を格納しています. |
//-----------------------------------------------------------------------------
// フックのコールバック関数
// このDLLを使用したアプリにメッセージを送る
//
// マウスカーソル位置をlParamの下位ワード,上位ワードに格納
//-----------------------------------------------------------------------------
function MouseHookProc(nCode: Integer; wPar: WPARAM; lPar: LPARAM):
LRESULT; stdcall;
var
LpMap : Pointer;
LMapWnd : THANDLE;
LMousePos : TPoint;
begin
Result := 0;
if MapFileMemory(LMapWnd, LpMap) <> 0 then exit;
if nCode < 0 then begin
Result := CallNextHookEx(pHookInfo(p)^.HookHandle, nCode, wPar, lPar);
end else begin
if nCode = HC_ACTION then begin
LMousePos := PMouseHookStruct(lPar)^.pt;
PostMessage(pHookInfo(p)^.HostWnd,
WM_APP+100,
wPar,
MakeLParam(LMousePos.X, LMousePos.Y));
end;
Result := CallNextHookEx(pHookInfo(p)^.HookHandle, nCode, wPar, lPar);
end;
UnMapFileMemory(LMapWnd, LpMap);
end;
受信側では,次のように,LParam の下位ワードから X 座標値,上位ワードから Y 座標値を取り出すことができます. |
LhTarget := GetForegroundWindow;
if LhTarget <> 0 then begin
//マウスカーソルのスクリーン座標値を取得
X := LOWORD(Message.LParam);
Y := HIWORD(Message.LParam);
//アクティブウィンドウのタイトルと操作内容をListViewに表示
Form1.DisplayKeyCodeMousePos(LhTarget, LMsgStr, X, Y);
end;
03_マウスカーソル位置に画像を表示 - WH_MOUSE_LL
フック使用 |
低レベルのマウスフックである WH_MOUSE_LL を使用したサンプルです.フック開始時に引数等を使用する必要がなければこの方法が利用できます.低レベルマウスフックは DLL にしなくてもグローバルフックを実現できます.構造体の説明は MSDN オンイランにあります.
前のサンプルとは,カエルの画像表示のタイミングが微妙に違います.ポップアップメニューを表示した直後,少しマウスを移動しないと表に表示されないようです.メッセージが,WH_MOUSE フックよりも前にこの低レベルのフックを通過するためと思われます. |
リスト5
WH_MOUSE_LL を使用したコード
このメインフォーム以外のコードは全て同じ |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
Button2: TButton;
Panel2: TPanel;
Panel3: TPanel;
ListView1: TListView;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private 宣言 }
procedure DisplayKeyCodeMousePos(hWindow: HWND; MsgStr: String;
Int1,Int2: Integer);
function GetWindowTextStr(hWindow:HWND):String;
protected
procedure WMApp100(var Message: TMessage); message WM_APP+100;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses KaeruUnit;
{$R *.DFM}
//-----------------------------------------------------------------------------
// 低レベルマウスフックの情報構造体と定数
// LLMHF_INJECTEDはマウスフックで使用
//-----------------------------------------------------------------------------
const
LLMHF_INJECTED = $00000001;
type
LPMSLLHOOKSTRUCT = ^MSLLHOOKSTRUCT;
tagMSLLHOOKSTRUCT = record
pt: TPOINT;
mouseData: DWORD;
flags: DWORD;
time: DWORD;
dwExtraInfo: ULONG_PTR;
end;
MSLLHOOKSTRUCT = tagMSLLHOOKSTRUCT;
TMsllHookStruct = MSLLHOOKSTRUCT;
PMsllHookStruct = LPMSLLHOOKSTRUCT;
var
MouseHookHandle : HHOOK;
//-----------------------------------------------------------------------------
// マウスフックのコールバック関数
//-----------------------------------------------------------------------------
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;
//=============================================================================
// ListViewの各カラムを設定
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
ListView1.ViewStyle := vsReport;
ListView1.Columns.Add;
ListView1.Columns[0].Caption := ' アクティブウィンドのタイトル';
ListView1.Columns[0].Width := 218;
ListView1.Columns.Add;
ListView1.Columns[1].Caption := ' EVENT';
ListView1.Columns[1].Width := 90;
end;
//=============================================================================
// アプリ終了時はフック関数をアンインストール(登録解除)
//=============================================================================
procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeAndNil(KaeruForm);
if MouseHookHandle <> 0 then begin
UnhookWindowsHookEx(MouseHookHandle);
MouseHookHandle := 0;
end;
end;
//=============================================================================
// フック関数をインストール(登録)
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
//マウスフック開始
if MouseHookHandle = 0 then
MouseHookHandle := SetWindowsHookEx(WH_MOUSE_LL,
@LowLevelMouseProc,
hInstance,
0);
if KaeruForm = nil then KaeruForm := TKaeruForm.Create(Self);
ListView1.Items.Clear;
end;
//=============================================================================
// フック関数をアンインストール(登録解除)
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
Windows.BringWindowToTop(GetActiveWindow);
KaeruForm.Close;
if MouseHookHandle <> 0 then begin
UnhookWindowsHookEx(MouseHookHandle);
MouseHookHandle := 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';
else
begin
LMsgStr := Format(' $%.2x', [Message.WParam]);
end;
end;
LhTarget := GetForegroundWindow;
if LhTarget <> 0 then begin
GetCursorPos(LMousePos);
//アクティブウィンドウのタイトルと操作内容をListViewに表示
Form1.DisplayKeyCodeMousePos(LhTarget, LMsgStr, LMousePos.X, LMousePos.Y);
end;
end;
//-----------------------------------------------------------------------------
// ウィンドウのタイトルと操作内容をListViewに表示
// また,マウス座標値を表示
//-----------------------------------------------------------------------------
procedure TForm1.DisplayKeyCodeMousePos(hWindow: HWND; MsgStr: String;
Int1, Int2: Integer);
var
LItem : TListItem;
LTargetWnd : HWND;
begin
if MsgStr = '' then exit;
LItem := ListView1.Items.Add;
if (hWindow = Handle) then begin
LTargetWnd := Handle;
end else begin
//マウスカーソルと共に表示する画像(フォーム)を最前面に
Windows.BringWindowToTop(KaeruForm.Handle);
LTargetWnd := hWindow;
end;
LItem.Caption := GetWindowTextStr(LTargetWnd);
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);
Panel2.Caption := Format('[ X=%.4d Y=%.4d ]',[Int1,Int2]);
//Int1はX座標値.Int2はY座標値
KaeruForm.Left := Int1 + 1;
KaeruForm.Top := Int2 + 1;
if KaeruForm.Visible = False then KaeruForm.Show;
end;
//-----------------------------------------------------------------------------
// 対象のウィンドウハンドルhWindowからそのタイトル(キャプション)を取得
//-----------------------------------------------------------------------------
function TForm1.GetWindowTextStr(hWindow: HWND): String;
var
Buff : array [0..MAX_PATH-1] of Char;
begin
FillChar(Buff, MAX_PATH, #0);
GetWindowText(hWindow, Buff, GetWindowTextLength(hWindow) + 1);
Result := String(Buff);
end;
end.
04_WH_MOUSE_LL フックにおけるマウスカーソル位置の取得 |
上のサンプルでは,マウスカーソルの位置を GetCursorPos 関数で取得しています.
フックのコールバック関数内でマウスカーソル位置を取得して,受信側で受け取るようにすることもできます.それには,マウスフックの情報を格納している構造体 (レコード型) からマウスカーソル位置を取得します.
次のコードでは,PostMessage の LParam パラメータの上位ワードと下位ワードにマウスカーソルの座標値を格納しています. |
//-----------------------------------------------------------------------------
// マウスフックのコールバック関数
//
// マウスカーソル位置をlParamの下位ワード,上位ワードに格納
//-----------------------------------------------------------------------------
function LowLevelMouseProc(Code: Integer; wPar: WPARAM; lPar: LPARAM):
LRESULT; stdcall;
var
LMousePos : TPoint;
begin
if Code < 0 then begin
Result := CallNextHookEx(MouseHookHandle, Code, wPar, lPar);
exit;
end;
if Code = HC_ACTION then begin
LMousePos := PMsllHookStruct(lPar)^.pt;
PostMessage(Form1.Handle, WM_APP+100, wPar, MakeLParam(MousePos.X, MousePos.Y));
end;
Result := CallNextHookEx(MouseHookHandle, Code, wPar, lPar);
end;
受信側では,次のように,LParam の下位ワードから X 座標値,上位ワードから Y 座標値を取り出すことができます. |
LhTarget := GetForegroundWindow;
if LhTarget <> 0 then begin
//マウスカーソルのスクリーン座標値を取得
X := LOWORD(Message.LParam);
Y := HIWORD(Message.LParam);
//アクティブウィンドウのタイトルと操作内容をListViewに表示
Form1.DisplayKeyCodeMousePos(LhTarget, LMsgStr, X, Y);
end;
もし,システム全体でマウスカーソルの形状を変更するのであれば,次のリストのようにカーソルの関数の API 関数,SetSystemCursor を使用します.[110_OnMouseMove イベントを使用したコントロールのドラッグ] のサンプルのように,独自のマウスカーソルを定義して使用することもできます.
本サンプルで使用している SyetemParametersInfo 関数は,特にユーザインターフェイス関係の設定や取得ができます. |
|
図4
変更前 |
|
図5
変更後のマウスカーソル |
リスト6
システムのマウスカーソル (ポインタ) 変更する例 |
unit ChangeMouseCursorUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// 元に戻しておかないと変更されたまま
//=============================================================================
procedure TForm1.FormDestroy(Sender: TObject);
begin
SystemParametersInfo(SPI_SETCURSORS, 0, nil, 0);
end;
//=============================================================================
// システム全体のマウスカーソル形状を変更
// マウスカーソルファイルから読出して設定
//
// SystemCursorの最後の引数に指定する元のマウスカーソルの値
//
// OCR_NORMAL 通常の選択カーソル
// OCR_IBEAM I型カーソル
// OCR_WAIT 大きい砂時計カーソル
// OCR_CROSS 十字カーソル
// OCR_UP 上向き矢印カーソル
// OCR_SIZE サイズ変更カーソル
// OCR_ICON アイコン カーソル
// OCR_SIZENWSE 左上から右下方向のサイズ変更カーソル
// OCR_SIZENESW 右上から左下方向のサイズ変更カーソル
// OCR_SIZEWE 水平方向サイズ変更カーソル
// OCR_SIZENS 垂直方向サイズ変更カーソル
// OCR_SIZEALL 水平および垂直方向サイズ変更カーソル
// OCR_SIZENO 各国対応の記号なしカーソル
// OCR_APPSTARTING 矢印付きの小さい砂時計カーソル
// OCR_HAND リンク選択カーソル
//
// Delphi ML 81301からのツリー参照
// http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=081320
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
CurPath1 : String;
CurPath2 : String;
CurPath3 : String;
begin
//各カーソル画像のパス名
CurPath1 := 'Cursor1.cur';
CurPath2 := 'C:\Windows\Cursors\metronom.ani';
CurPath3 := 'harrow.cur';
//通常の選択カーソルを変更
SetSystemCursor(LoadCursorFromFile(PChar(CurPath1)), OCR_NORMAL);
//矢印付きの小さい砂時計カーソルを変更
SetSystemCursor(LoadCursorFromFile(PChar(CurPath2)), OCR_APPSTARTING);
//ブラウザでリンク上にきた時のマウスを変更
SetSystemCursor(LoadCursorFromFile(PChar(CurPath3)), OCR_HAND);
//不要のようだ
//SystemParametersInfo(SPI_SETCURSORS,0,NULL,WM_SETTINGCHANGE);
end;
//=============================================================================
// まとめて元に戻す
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
SystemParametersInfo(SPI_SETCURSORS, 0, nil, 0);
end;
end.
マウスカーソルは,次のようにして,複数のカーソルを登録しておいて,実行時に切り替えて使用することもできます. |
procedure TForm1.Button1Click(Sender: TObject);
const
crMyCursor = 1;
begin
//Cursor1.curファイルのカーソルをcrMyCursorに割り当てる
Screen.Cursors[crMyCursor] := LoadCursorFromFile('Cursor1.cur');
//実際に利用
Screen.Cursor := crMyCursor;
end;
このページのサンプルで使用している「カエル」の画像はメタファイルです.
TImage の Picture プロパティに代入する際,wmf 形式は「メタファイルが不正です」のエラーが発生することがあります.または実行時にエラーが発生し,終了すると画像が消失することがあります.そのような場合は,以下のコードで拡張メタファイルに変換するとうまくいくことがあります. |
|
図6
メタファイルが不正です |
procedure TForm1.Button1Click(Sender: TObject);
var
MetaFile: TMetaFile;
begin
MetaFile := TMetaFile.Create;
MetaFile.LoadFromFile('E_frog.wmf');
MetaFile.Enhanced := True;
MetaFile.SaveToFile('E_frog.emf');
MetaFile.Free;
end;
|