Comprendre le crochet de la souris et du clavier de bas niveau (win32)
Je suis en train de capture global de la souris et du clavier.
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0) {
if (wParam == WM_RBUTTONDOWN) printf("right mouse down\n");
if (wParam == WM_RBUTTONUP) printf("right mouse up\n");
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
HHOOK mousehook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0);
while(true) {
MSG msg;
if (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
printf("msg recvd\n");
TranslateMessage(&msg);
DispatchMessage(&msg);
}
#ifdef TEST
Sleep(50);
#endif
}
De sorte que tout fonctionne, sauf si je #define TEST
à mettre dans le Sleep
la souris devient incroyablement lent, comme si soudain j'ai autoriser uniquement la souris pour mettre à jour 20 fois par seconde. Et sans sommeil, je suis le rattachement de la CPU à 100%. Mais c'est bien pour l'instant (qui s'en va si j'utilise GetMessage
).
Maintenant que je le comprends, le faible niveau des crochets de travail par commutation de contexte le processus qui l'a installé, et l'envoi du processus d'une sorte de message à laisser exécuter le crochet de rappel. Ce qui me confond un peu, cependant, c'est pourquoi mon programme ne sera jamais imprimer "msg recvd", mais il imprime "droit de la souris vers le bas/haut" chaque fois que je clique sur le bouton droit de la souris. Ce qui m'amène à conclure que mon MouseHookProc
est invoquée au cours de la PeekMessage
appel. Il arrive juste à être une sorte de message spécial et PeekMessage
retourne 0. Mais j'ai toujours besoin d'appeler PeekMessage
ou l'équivalent.
Depuis mon programme doit faire un tas de choses, de toute évidence, je ne peux pas alourdir mon message boucle de pompage (celui qui appelle PeekMessage
) par l'appel d'une autre fonction qui prend, dire 50ms de retour. Comment pourrais-je multithread mon programme afin de maintenir la réactivité de la souris tout en faisant un peu lourd de levage? Dans un multithread programme win32, il est toujours juste l'un message de la file d'attente, non?
Mise à jour: Après avoir lu sur la MS de la documentation, je pense que je sais ce que la bonne chose à faire pour moi est. Je devrais juste frayer un thread dans mon application qui appelle SetWindowsHookEx
pour enregistrer le point de raccordement de souris, et puis s'asseoir autour dans son propre message en boucle, et le système se chargera de l'envoi de la souris mises à jour de ce thread. Il sera libre de faire ce qu'il veut au sein de la MouseHookProc
et le reste de mon application va fonctionner de façon indépendante.
source d'informationauteur Steven Lu
Vous devez vous connecter pour publier un commentaire.
Le problème, c'est votre boucle de message, il brûle 100% de CPU cycles parce que vous utilisez PeekMessage(). Windows sait comment garder le crochet en vie, même si vous n'avez pas de sondage pour les messages, l'utilisation GetMessage() pour résoudre votre problème. À l'aide de Sommeil(1) permettra de résoudre votre problème aussi, mais n'est pas nécessaire ici.
Pourquoi doit SetWindowsHookEx être utilisé avec windows file d'attente de messages
J'ai demandé si vous placez le lieu
MouseHookProc
dans la DLL, parce que les tentatives de le placer à l'intérieur d'un EXE c'est une erreur classique. Je l'ai fait aussi il y a plusieurs années.Tout d'abord, comment vous pouvez le lire dans http://msdn.microsoft.com/en-us/library/ms644990.aspx:
Sorte que vous devez placer dans une DLL. Pour être parfaitement si vous souhaitez soutenir à la fois 32 bits et 64 bits des plates-formes que vous avez à mettre en œuvre deux dll: un 32-bit et 64-bit DLL. Mais pourquoi? Et comment
SetWindowsHookEx
fonctionne?Si vous exécutez dans un fichier EXE le code comme suit
vous donner user32.dll demande d'injecter votre syshook.dll dans tous les autres processus sur le même poste windows (dll ne sera pas injecté pour les services et les processus des autres utilisateurs connectés à travers le changement rapide d'utilisateur). Puis user32.dll appel
LoadLibrary
à la syshook.dll dans des processus différents. Ensuite, si la fonctionMouseHookProc
sera appelé, sera appelé dans le contexte du processus qui proccess le message de souris. Si le processus n'est pas une application de console le code commene peuvent pas travailler.
Donc j'espère que maintenant, vous allez undestend pourquoi vous devez placer
MouseHookProc
dans une DLL.Au lieu de faire:
Commutateur:
Cela va permettre à votre application de continuer à traiter tous les messages dans la file d'attente jusqu'à ce qu'il est vide (pas de dormir), puis abandonner quelques temps CPU quand l'application est "inactif".
MouseHookProc
doit résider dans la dll, sinon vous ne pouvez pas capturer "global" d'entrée ( http://msdn.microsoft.com/en-us/library/ms997537.aspx )Sur la boucle - vous pouvez le modifier comme ceci: