Delphi - Globális egérkezelés, avagy Hook

forráskód letöltése
Mellékelt példában arra láthatunk megoldást, hogy miként kaphat a saját alkalmazásunk információt az egér eseményeiről, függetlenül attól, hogy melyik program az aktív. Ennek megvalósítására az ún. Hook technikát alkalmazzuk. Mellékelt példában arra láthatunk megoldást, hogy miként kaphat a saját alkalmazásunk információt az egér eseményeiről, függetlenül attól, hogy melyik program az aktív. Ennek megvalósítására az ún. Hook technikát alkalmazzuk.


Ezt a technikát általában úgy lehet megvalósítani, hogy készítünk egy Dll-t, melyben elhelyezzük azokat a funkciókat, amelyek megvalósítják - jelen esetben - az egér kezelését, majd egy másik alkalmazásból meghívjuk a Dll inicializáló függvényét, amikor szükségünk van rá.

Kezdjük a Dll elkészítésével.

Létrehozunk egy SetHook, illetve egy UnHook nevű függvényt, melyeket elérhetővé teszünk más alkalmazások számára is. A SetHook hívásával indíthatjuk majd el az egér figyelését, míg az UnHook hívásával leállíthatjuk azt.

Mellékelt példában azt valósítjuk meg, hogy bármely alkalmazás is legyen az aktív, ahol lenyomja a felhasználó az egér bal gombját, oda teszünk egy kis piros kört és egy számot, hogy ez hányadik kattintás volt.


Mikor meghívjuk a SetHook függvényünket, az a SetWindowsHookEx Windows függvény hívásával elvégzi a regisztrációt. Mivel az egér üzeneteit szeretnénk elcsípni, így a WH_MOUSE konstanst használjuk. Második paraméterként egy függvénynevet kell megadnunk, amely az egér üzeneteit kezeli le. Ezek után már csak a Dll-ünk példány azonosítóját kell megadnunk a sikeres regisztráció érdekében.

Visszatérési értékként egy HHook típusú változóban kapjuk meg a létrehozott Hook azonosítóját.

Ezt az azonosítót felhasználva tudjuk az UnHook függvényünkben megszüntetni az egér események figyelését a UnHookWindowsHookEx Windows függvény hívásával.

Mivel regisztráláskor megadtunk a Windows-nak egy függvénynevet, így ha bekövetkezik bármilyen egérrel kapcsolatos esemény, ezt a függvényt automatikusan meghívja.

A mellékelt példában ez a HookProc nevű függvény. Itt valósítjuk meg azt, hogy ha a felhasználó kattint a bal gombbal, akkor arra a pozícióra kerüljön egy kis grafikai objektum.

Miután ellenőrizzük, hogy a bal gomb lett-e lenyomva, lekérdezzük az egér aktuális pozícióját, majd létrehozunk egy TCanvas típusú változót a rajzolás elvégzéséhez. Ennek az azonosítóját a teljes képernyőhöz rendeljük /GetDC(0)/, mivel a kattintás bárhol, bármilyen alkalmazáson történhetett, így a rajzolást is ott kell elvégeznünk.

Ezek után következhet a kis piros kör kirajzolása és egy sorszám kiírása, melyet folyamatosan növelünk egyesével minden kattintásnál.

Ha megfigyeljük a sorszám kiírásánál kapott eredményeket, akkor egy érdekes dolgot vehetünk észre: minden futó alkalmazásra való kattintásnál ez a sorszámozás nullától indul. Ezt úgy kell elképzelnünk, hogy ez a Dll minden egyes alkalmazáskor meghívásra kerül. Így a Dll-ben lévő globális FI változó, ahol a soron következő számot tároljuk, alkalmazásonként lokálisan viselkedik.

A rajzolás végeztével nem szabad megfeledkezni a ReleaseDC hívásáról, mivel csak ekkor fog felszabadulni a GetDC által lefoglalt memória tartomány.

Végső lépésként pedig meg kell hívnunk a CallNextHookEx Windows függvényt. Ez azért fontos, mert ha más alkalmazás is használ Hook-ot az egér kezelés figyelésére, akkor csak így biztosítható, hogy szép sorban az összes ilyen alkalmazás megkapja a szükséges paramétereket.

A rajzolással kapcsolatban van egy fontos tudnivalónk: mivel mi csak kirajzolást végzünk, így nem vesszük figyelembe azt az esetet, amikor a Windows érvénytelenít egy adott alkalmazás adott területét, melyet ezek után újra kellene rajzolni. Ilyenkor ez az adott alkalmazás újra rajzolja a szükséges területet, de egyúttal ezzel törli az általunk kirajzolt kis piros kört. Mivel mi nem végzünk újra rajzolást, így a kör véglegesen eltűnik. Bizonyos esetekben ez az újra rajzolás azonnal megtörténik. Ilyen eset lehet például, ha egy tetszőleges alkalmazásban a menüt használjuk vagy akár a nyomógombokat. Ekkor úgy látjuk, hogy a kis kör nem is jelent meg. Valójában megjelent, de mivel azonnal le is lett törölve ezért úgy láthatjuk, hogy hibásan működik a program, de inkább csak túl gyorsan.


Nézzük most az EXE készítését.

Itt elég egyszerű a helyzetünk, csupán deklarálnunk kell a Dll-ben található két függvényt, majd ezek hívását egy nyomógomb lenyomásának eseményéhez kell kötnünk.


Természetesen a Hook funkciókat komolyabb alkalmazási területeken szokás felhasználni, mint a mellékelt példa. Ebben csak azt szerettük volna látványosan bemutatni, hogy miként is működik ez a funkció. Sokkal hasznosabb eljárás lehet például egy olyan alkalmazás készítése, ahol az adott program például "megjegyzi", hogy merre jár és mit csinál az egér és ezt képes utána reprodukálni.
De például a komponenseknél található Hint property-ben tárolt szöveg megjelenítése is ennek segítségével történik.