Autor |
Beitrag |
Bergmann89
      
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)
|
Verfasst: 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:
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. |
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 end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.KeyHookMsg(var Msg: TMessage); begin ListBox1.Items.Add(IntToStr(Msg.WParam)); ListBox1.ItemIndex := ListBox1.Count-1; end;
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;
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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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 
      
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)
|
Verfasst: 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:
Delphi-Quelltext 1: 2: 3:
| const WH_KEYBOARD_LL = 13; 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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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.
Bergmann89 hat folgendes geschrieben : | 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 
      
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)
|
Verfasst: 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
      
Beiträge: 393
Erhaltene Danke: 49
Win 7
Lazarus
|
Verfasst: 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)
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
|
|
|