Autor Beitrag
Bergmann89
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Mi 06.07.11 20:54 
Hey,

ich versuch mich grad an meinem ersten Keyhook. Ich möchte eine Art MacroTool für Maus- und Tastatureingaben schreiben. Mit den gedrückten Tasten der Tastatur funktioniert das auch alles 1a, aber die Tasten die ich auf der Maus drück fängt er irgendwie nicht ab. Ich hab mit auch schon WH_MOUSE angesehen, aber da ist auch keine Rede von Maustasten. Hier ma noch mein bisheriger Code:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
library KeyHook;

uses
  Windows,
  Messages;

{$R *.res}

const
  WM_KEYHOOK = WM_USER + 1;

type
  TFNHookProc = function (code: Integer; wparam: WPARAM; lparam: LPARAM):  LRESULT stdcall;

var
  HookHandle: Cardinal = 0;
  WindowHandle: Cardinal = 0;

function KeyboardHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
  Result := CallNextHookEx(HookHandle, nCode, wParam, lParam);
  if nCode >= 0 then begin
    SendMessage(WindowHandle, WM_KEYHOOK, wParam, lParam);
  end;
end;

function InstallHook(Hwnd: Cardinal): Boolean; stdcall;
begin
  Result := False;
  if HookHandle = 0 then begin
    HookHandle := SetWindowsHookEx(WH_KEYBOARD_LL, @KeyboardHookProc, HInstance, 0);
    WindowHandle := Hwnd;
    Result := TRUE;
  end;
end;

function UninstallHook: Boolean; stdcall;
begin
  Result := UnhookWindowsHookEx(HookHandle);
  HookHandle := 0;
end;

exports
  InstallHook,
  UninstallHook;

end.


ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

const
  WM_KEYHOOK = WM_USER + 1;

type
  TInstallHook = function(Hwnd: THandle): Boolean; stdcall;
  TUninstallHook = function: Boolean; stdcall;

  TForm1 = class(TForm)
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    fInstallHook: TInstallHook;
    fUninstallHook: TUninstallHook;
    fKeyHookLib: Cardinal;
    procedure KeyHookMsg(var Msg: TMessage); message WM_KEYHOOK;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Form1/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRI//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Message-Handler der auf WM_KEYHOOK reagiert
//@Msg: Message die geschickt wurde
procedure TForm1.KeyHookMsg(var Msg: TMessage);
begin
  ListBox1.Items.Add(IntToStr(Msg.WParam));
  ListBox1.ItemIndex := ListBox1.Count-1;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBL//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Event-Handler von TForm1.OnCreate
//@Sender: Objekt, dass das Event auslöst;
procedure TForm1.FormCreate(Sender: TObject);
begin
  fKeyHookLib := LoadLibrary('Hook\KeyHook.dll');
  if fKeyHookLib <> INVALID_HANDLE_VALUE then begin
    fInstallHook := GetProcAddress(fKeyHookLib, 'InstallHook');
    fUnInstallHook := GetProcAddress(fKeyHookLib, 'UninstallHook');
    fInstallHook(Handle);
  end else begin
    ShowMessage('Can''t load "Hook\KeyHook.dll". Programm will terminate.');
    Application.Terminate;
  end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Event-Handler von TForm1.OnDestroy
//@Sender: Objekt, dass das Event auslöst;
procedure TForm1.FormDestroy(Sender: TObject);
begin
  fUnInstallHook;
  FreeLibrary(fKeyHookLib);
end;

end.
Wie komm ich da jetzt an die gedrückten Maustasten ran?!


MfG Bergmann

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 06.07.11 21:30 
Ich würde dir raten nicht über den Fenstermanager (sprich WH_MOUSE) zu gehen, es sei denn du musst innerhalb der Hookbehandlung eine kurze Behandlung durchführen bevor du das Event weitergibst. Dann wäre es natürlich ungünstig, das bereits auf unterster Ebene zu machen, aber das sollte man ohnehin nie machen...

Deshalb rate ich dir dazu WH_MOUSE_LL zu benutzen, dann kannst du dir die DLL auch sparen...
msdn.microsoft.com/e...ibrary/ms644986.aspx
Um was für ein Event (Taste runter, hoch, Bewegung, ...) es sich handelt bekommst du direkt übergeben, siehe Doku.
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Mi 06.07.11 21:41 
Hey,

er findet die WH_MOUSE_LL-Konstante nicht. Is die nich mit in der Windows-Unit? Ich hab folgende Werte für die Konstanten gefunden:
ausblenden Delphi-Quelltext
1:
2:
3:
const
  WH_KEYBOARD_LL = 13// define for Delphi 6 and older Versions
  WH_MOUSE_LL = 14;

aber da steht ja D6 und älter, also müsste die ja bei meinem D7 irgendwo mit dabei sein. Also wo genau find ich die?!

€: noch ne Frage. Wieso kann ich mir die DLL sparen? in der Doku steht folgendes:
Zitat:
lpfn [in]
Type: HOOKPROC
A pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a DLL.

dwThreadId [in]
Type: DWORD
The identifier of the thread with which the hook procedure is to be associated. If this parameter is zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread.

also muss es ne DLL sein, sobald ich Threads hookn will, die nich zu meinem Prozess gehören. Oder hab ich was falsch verstanden?!

MfG Bergmann

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 06.07.11 22:08 
Vielleicht wusste es derjenige nicht, dass das auch für Delphi 7 gilt. In aktuellen Versionen ist die Konstante in der Unit Windows mit drin.

user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
Wieso kann ich mir die DLL sparen? in der Doku steht folgendes:
Das ist dort nicht ganz korrekt. Lowlevel-Hooks gehen auch ohne DLL, da die vom System selbst kommen.

Alle anderen, z.B. die normalen Tastatur- und Maushooks, brauchen in der Tat eine DLL, da sie (im Falle von Tastatur und Maus) über den Fenstermanager und damit ein zusätzliches Programm laufen.
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Mi 06.07.11 22:27 
Gut, also mit der DLL gehts jetzt schonma. Ich bau das ganze jetzt grad in meine Anwendung ein. Ich hät es gern das die HockProcedure eine Membermethode von TMainForm ist. Da meckert er jetzt aber rum, weil er ja einen normalen Prozedurzeiger erwartet. Ist es überhaupt möglich oder sollte ich das ganze lieber als normale Methode implementieren und dann über eine extra Methode an die Form weitergeben?
Wenn ich mir das so recht überleg geht das mit der Membermethode glaub ich nicht, weil ich ja nur eine Methode mit SetWindowsHookEx regestrieren kann, aber man kann ja unter Umständen mehrere Objekte von ein und der selben Klasse anlegen. Also ist der Umweg über die normale Methode der einzige Weg. Korrigiert mich wenn ich falsch liege ^^

MfG Bergmann

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
glotzer
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 393
Erhaltene Danke: 49

Win 7
Lazarus
BeitragVerfasst: Mi 06.07.11 22:52 
da schreib ich zurzeit an einer Klasse: (ist "work in progress" also noch nicht fertig. aber das wesentliche geht)

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
unit Hook;

interface

uses
  Windows, Dialogs, SysUtils, classes;

type
  TCallbackThunk = packed record
    POPEDX: Byte;
    MOVEAX: Byte;
    SelfPtr: Pointer;
    PUSHEAX: Byte;
    PUSHEDX: Byte;
    JMP: Byte;
    JmpOffset: Integer;
  end;

type
  TKeyboardHookError = class(Exception);
  TKeyboardCallback = procedure(code: Integer; wparam: WPARAM; lparam: LPARAM) of object;

type
  TKeyboardHook = class(TObject)
    private
      FOnCallback: TKeyboardCallBack;
      FOnKeyDown: TKeyEvent;
      FOnKeyUp: TKeyEvent;
      procedure SetOnCallback(const Value: TKeyboardCallBack);
      procedure RaiseSysError;
      procedure RaiseError(msg:String);
    protected
      Handle: HHook;
      FThunk: TCallbackThunk;
    protected
      function CallBack(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT; stdcall;
    public
      constructor Create;
      destructor Destroy; override;
    public
      procedure UnHook;
      procedure Hook;
    published
      property OnCallback: TKeyboardCallBack read FOnCallback write SetOnCallback;
      property OnKeyDown: TKeyEvent read FOnKeyDown write FOnKeyDown;
      property OnKeyUp: TKeyEvent read FOnKeyUp write FOnKeyUp;
  end;

const
  WH_KEYBOARD_LL = 13;
  WH_MOUSE_LL = 14;

implementation

constructor TKeyboardHook.Create;
begin
  Handle := 0;
  FThunk.POPEDX:= $5A;
  FThunk.MOVEAX:= $B8;
  FThunk.SelfPtr:= Self;
  FThunk.PUSHEAX:= $50;
  FThunk.PUSHEDX:= $52;
  FThunk.JMP:= $E9;
  FThunk.JmpOffset:= Integer(@TKeyboardHook.CallBack)-Integer(@FThunk.JMP)-5;
  inherited;
end;

destructor TKeyboardHook.Destroy;
begin
  if Handle <> 0 then UnHook;
  inherited;
end;

procedure TKeyboardHook.RaiseSysError;
var
  Error: Integer;
begin
  Error := GetLastError;
  if Error = 0 then exit;
  raise TKeyboardHookError.Create(SysErrorMessage(Error));
end;

procedure TKeyboardHook.RaiseError(msg:String);
begin
  raise TKeyboardHookError.Create(msg);
end;

procedure TKeyboardHook.SetOnCallback(const Value: TKeyboardCallBack);
begin
  FOnCallback := Value;
end

function TKeyboardHook.CallBack(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT;
begin
  if Code < 0 then
  begin
    Result:= CallNextHookEx(Handle, Code, wparam, lparam);
  end else
  begin
    if Assigned(FOnCallback) then
    begin
      FOnCallback(Code, wParam, lParam);
    end;

    Result:= 0;
  end;
end;

procedure TKeyboardHook.UnHook;
begin
  UnhookWindowsHookEx(Handle); 
end;

procedure TKeyboardHook.Hook;
begin
  Handle := SetWindowsHookEx(WH_KEYBOARD_LL, TFNHookProc(@FThunk), HInstance, 0);
  if Handle = 0 then RaiseSysError
end;

end.


"TCallbackThunk" ist dabei am wichtigsten.

_________________
ja, ich schreibe grundsätzlich alles klein und meine rechtschreibfehler sind absicht