Reputation: 566
I am trying to hook mouse and keyboard events and log them to the Memo1 (for mouse) and Memo2 (for keyboard). The code i am trying to compile to:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, windows;
type
{ TForm1 }
TForm1 = class(TForm)
Memo1: TMemo;
Memo2: TMemo;
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
function LowLevelKeybdHookProc(nCode: LongInt; WPARAM: WPARAM; lParam : LPARAM) : LRESULT; stdcall;
function LowLevelMouseHookProc(nCode: LongInt; WPARAM: WPARAM; lParam : LPARAM) : LRESULT; stdcall;
{ public declarations }
end;
KeybdLLHookStruct = record
vkCode : cardinal;
scanCode : cardinal;
flags : cardinal;
time : cardinal;
dwExtraInfo : cardinal;
end;
MouseLLHookStruct = record
pt : TPoint;
mouseData : cardinal;
flags : cardinal;
time : cardinal;
dwExtraInfo : cardinal;
end;
var
Form1: TForm1;
mHook : cardinal;
kHook : cardinal;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
UnhookWindowsHookEx(kHook);
UnhookWindowsHookEx(mHook);
end;
procedure TForm1.FormCreate(Sender: TObject);
const
wh_keybd_ll = 13;
wh_mouse_ll = 14;
begin
kHook := SetWindowsHookEx(wh_keybd_ll, @LowLevelKeybdHookProc, hInstance, 0);
mHook := SetWindowsHookEx(wh_mouse_ll, @LowLevelMouseHookProc, hInstance, 0);
end;
function TForm1.LowLevelKeybdHookProc(nCode: LongInt; WPARAM: WPARAM; lParam : LPARAM) : LRESULT; stdcall;
// possible wParam values: WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP
var
info : ^KeybdLLHookStruct absolute lParam;
lpChar : word;
kState : TKeyboardState;
begin
result := CallNextHookEx(kHook, nCode, wParam, lParam);
with info^ do
case wParam of
wm_keydown : begin
GetKeyboardState(kState);
if ToAscii(vkCode, scanCode, kState, @lpChar, 0) > 0 then Form1.Memo2.Lines.Append(format('pressed key -- %s', [char(lpChar)]));
end;
end;
end;
function TForm1.LowLevelMouseHookProc(nCode: LongInt; WPARAM: WPARAM; lParam : LPARAM) : LRESULT; stdcall;
// possible wParam values: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_RBUTTONDOWN, WM_RBUTTONUP
var
info : ^MouseLLHookStruct absolute lParam;
begin
result := CallNextHookEx(mHook, nCode, wParam, lParam);
with info^ do
case wParam of
wm_lbuttondown : Form1.Memo1.Lines.Append(format('pressed left button (%d, %d)' , [pt.x, pt.y]));
wm_lbuttonup : Form1.Memo1.Lines.Append(format('released left button (%d, %d)' , [pt.x, pt.y]));
wm_mbuttondown : Form1.Memo1.Lines.Append(format('pressed middle button (%d, %d)' , [pt.x, pt.y]));
wm_mbuttonup : Form1.Memo1.Lines.Append(format('released middle button (%d, %d)' , [pt.x, pt.y]));
wm_rbuttondown : Form1.Memo1.Lines.Append(format('pressed right button (%d, %d)' , [pt.x, pt.y]));
wm_rbuttonup : Form1.Memo1.Lines.Append(format('released right button (%d, %d)' , [pt.x, pt.y]));
wm_mousewheel : begin
if smallInt(mouseData shr 16) > 0
then Form1.Memo1.Lines.Append('scrolled wheel (up)')
else Form1.Memo1.Lines.Append('scrolled wheel (down)');
end;
end;
end;
end.
But it returns these errors:
unit1.pas(64,62) Error: Incompatible type for arg no. 2: Got "<procedure variable type of function(LongInt,LongInt,LongInt):LongInt of object;StdCall>", expected "<procedure variable type of function(LongInt,LongInt,LongInt):LongInt;StdCall>"
unit1.pas(65,62) Error: Incompatible type for arg no. 2: Got "<procedure variable type of function(LongInt,LongInt,LongInt):LongInt of object;StdCall>", expected "<procedure variable type of function(LongInt,LongInt,LongInt):LongInt;StdCall>"
I can't understand what is "LongInt of object" and how to fix this.
Upvotes: 0
Views: 3617
Reputation: 613442
The of object
indicates that you have supplied a method pointer. That is an instance or a class method. In your case you are passing an instance method where a plain procedure is required.
Solve the problem by using procedures rather than methods. You'll need to get hold of the form by a means other than the Self
pointer, but then the code in the question wasn't using Self
anyway. As an aside, that in itself is a bad move. Always use Self
rather than a global variable that happens to have the same value as Self
.
Upvotes: 3