Entwickler-Ecke

Windows API - MouseHook - Ereignis komplett abfangen


netspy - Do 21.12.06 01:52
Titel: MouseHook - Ereignis komplett abfangen
Meine Anwendung [http://www.delphi-forum.de/topic_LingoPad+243+Woerterbuch_58314.html] möchte ich mittels eines Maus-Tastatur-Ereignis (bspw. Alt + rechte Maustaste) aktivieren. Dazu habe ich einen MouseHook gesetzt, der etwa so aussieht:


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:
function HookProc(nCode: Integer; MsgID: wParam; Data: LParam): LResult; stdcall;
var
  WindowHandle: THandle;

begin

  if (MsgID = WM_RBUTTONDOWN) and (GetKeyState(VK_MENU) < 0then
  begin

    WindowHandle := GetWindow(PMouseHookStruct(Data)^.HWND, GW_OWNER);

    if WindowHandle <= 0 then WindowHandle := PMouseHookStruct(Data)^.HWND;

    if nCode >= 0 then SendMessage(FindWindow(MouseHookWindow, nil), MouseHookMessage, MsgID, WindowHandle);

    Result := 0;

  end else
  begin

    Result := CallNextHookEx(Hook, nCode, MsgID, Data);

  end;

end;


Neben dem Aktivieren meines Programms will ich an die Anwendung, die beim Drücken der Maus aktiv war, noch ein Strg-C schicken, um einen markierten Text in die Zwischenablage zu holen. Leider funktioniert dies nicht. Das Handle des fremden Fenster stimmt aber meine Keybd_Event kommen nicht an. Da in der Anwendung auch ein Kontext-Menü (wegen der rechten Maustaste) aufgeht, ist klar, dass das Ereignis nicht abgefangen wird und vermutlich irgendwie mit meinen eigenen Keybd_Event kollidiert.

Frage: Wie kann ich das im MouseHook abgefangene Ereignis vor der eigentlich dafür bestimmten Anwendung verbergen? Result:=0 hilft nicht. Oder gibt es noch andere Wege nach Rom, die ich übersehen habe?

Mario


jaenicke - Do 21.12.06 11:59

Kannst du nicht mit RegisterHotkey [http://www.dsdt.info/tipps/?id=635] arbeiten?
(Zu deiner konkreten Frage kann ich im Moment nichts sagen, ich hab bisher immer damit gearbeitet.)

Die Frage ist nur: geht dabei auch die Mauseinbeziehung, aber ich denke eigentlich schon.
// EDIT: Ja, es gibt zum Beispiel VK_LBUTTON, und das sollte auch damit funktionieren. Alt und Strg und so kannst du direkt angeben.


netspy - Do 21.12.06 12:03

user profile iconjaenicke hat folgendes geschrieben:
Kannst du nicht mit RegisterHotkey [http://www.dsdt.info/tipps/?id=635] arbeiten?

Mache ich bisher schon und damit klappt es auch. Das funktioniert ja aber nur mit Tastaturereignissen und nicht mit der Maus, weshalb ich wohl nicht an einem MouseHook vorbeikomme.


jaenicke - Do 21.12.06 12:05

Wie bereits eben im Edit geschrieben: Es gibt doch einen virtuellen Keycode für die linke Maustaste, also würde ich jetzt denken, dass man den dort auch verwenden kann. (und natürlich gibts auch welche für die mittlere, etc.)
// EDIT:
Siehe hier: http://www.delphipraxis.net/topic7114_liste+der+virtuellen+tastencodes+vk.html


netspy - Do 21.12.06 12:11

user profile iconjaenicke hat folgendes geschrieben:
Wie bereits eben im Edit geschrieben: Es gibt doch einen virtuellen Keycode für die linke Maustaste, also würde ich jetzt denken, dass man den dort auch verwenden kann. (und natürlich gibts auch welche für die mittlere, etc.)

Nein, das geht leider nicht.


jaenicke - Do 21.12.06 12:49

Hmm, also AFAIK kannst bei einem Hook zwar durch Nichtaufrufen von CallNextHookEx dafür sorgen, dass die weiteren Hooks in der Hook-Kette das Ereignis nicht bekommen, aber da die Anwendung in diesem Fall (normalerweise) keine Hooks einsetzt, kann man wohl nicht so einfach verhindern, dass die das selbst bekommt.

Aber dafür kenne ich mich mit Hooks zuwenig aus um das definitiv zu sagen... Vielleicht kann dir da jemand anderes weiterhelfen.


netspy - Do 21.12.06 12:51

user profile iconjaenicke hat folgendes geschrieben:
... Vielleicht kann dir da jemand anderes weiterhelfen.

Das hoffe ich auch. :) :roll:


wulfskin - Do 21.12.06 13:37

Hallo,

wenn ich dich richtig verstanden habe, möchtest du den markierten Text in die Zwischenablage kopieren?! In welchem Control steht denn der Text?

Gruß Hape!


netspy - Do 21.12.06 14:08

user profile iconwulfskin hat folgendes geschrieben:
wenn ich dich richtig verstanden habe, möchtest du den markierten Text in die Zwischenablage kopieren?! In welchem Control steht denn der Text?

Ja, genau das ist mein Anliegen. In welchem Control der Text steht, ist mir prinzipiell egal, da so ziemlich alle Controls, die ein Markieren von Text erlauben, auch Strg+C oder Strg+Einfügen unterstützen.

Bisher machen ich das über eine mit RegisterHotKey registrierte Tastenkombination und das funktioniert auch ziemlich gut. Da ich aber auch auf Tasten+Maustasten-Ereignisse reagieren möchte, komme ich mit RegisterHotKey nicht weiter und hab es mit einem MouseHook versucht. Leider funktioniert beim Aktivieren meiner Anwendung durch den MouseHook das Senden von Strg+C nicht mehr. Da die Funktion dazu die gleiche wie bei der Aktivierung durch RegisterHotKey ist und das WindowHandle der fremnden Anwendung stimmt, vermute ich, dass sich da irgendwelche Meldungen in der MessageQueue blockieren oder kollidieren.


wulfskin - Do 21.12.06 14:56

Hallo,

damit dir klar ist warum ich frage: Wenn es ein einfaches Control ist, dann brauchst du nicht den Umweg über die Zwischenablage und den simulierten Tastendruck machen, sondern kannst ihn direkt auslegen.
Also: Um was für ein Controll handelt es sich?

Gruß Hape!


netspy - Do 21.12.06 15:19

user profile iconwulfskin hat folgendes geschrieben:
Also: Um was für ein Controll handelt es sich?

Das kann ich dir nicht sagen, da es beliebige Controls sein können. Die Anwendung ist ein Wörterbuch [http://www.ego4u.de/de/lingopad] und der Sinn ist, dass man in einer beliebigen Anwendung (bspw. ein Browser, Textverarbeitung, Mailprogramm, etc. pp) einen Text markiert, mit einem HotKey das Wörterbuch gestartet und der Text gesucht wird. Da es sich dabei um die unterschiedlichsten Anwendungen mit unterschiedlichen und meist sehr speziellen Controls handelt, macht das direkte Auslesen (soweit überhaupt möglich) IMO zu viel Arbeit. Ich lasse mich aber gerne korrigieren, falls es doch einen einfacheren Weg gibt.


jaenicke - Do 21.12.06 15:45

Es gibt ja auch die Message WM_GETTEXT. Da bekommst du wohl den kompletten Text, nicht nur den markierten. Aber vielleicht gibts ja sowas auch für den markierten. Mal sehen...
// EDIT: Hmm, wohl nicht...


netspy - Do 21.12.06 17:08

user profile iconjaenicke hat folgendes geschrieben:
Es gibt ja auch die Message WM_GETTEXT. Da bekommst du wohl den kompletten Text, nicht nur den markierten.

Eben, da gibt es leider nur den gesamten Text und was anderes habe ich auch nicht gefunden.


wulfskin - Do 21.12.06 18:27

Hallo,

ich würde an das Problem anders herangehen: Such nach einer Möglichkeit das Handle an der Mausposition zu bekommen. Dann überprüfe um was es sich für ein Fenstertyp handelt (Suche im MSDN GETCLASSNAME). Zum Schluss lies den Text entsprechend des Typs ein.
Für das erste fehlt mir noch der Ansatz, aber Motzis X-Spy findet ja auch die Klassen unter dem Mauszeiger, es geht also.

Gruß Hape!


netspy - Di 26.12.06 03:07
Titel: Lösung
Ich hab nun rausgefunden, warum ich bisher das Ereignis nicht abfangen konnte. Erstens brauche ich einen LowLevel-Hook (WH_MOUSE_LL) und zweitens hatte ich nur das MouseDown-Ereignis abgefangen. Zusätzlich muss natürlich auch noch das folgende MouseUp abgefangen werden.