Clavier globaux crochet avec WH_KEYBOARD_LL et keybd_event (windows)
Je suis en train d'écrire un simple clavier crochet programme de rediriger certaines touches. Par exemple, lorsque le programme est exécuté, j'appuie sur " a "sur le clavier, le programme peut le désactiver et de simuler un "b", cliquez sur. Je n'ai pas besoin d'un graphique de l'interface utilisateur, juste une console est assez (le garder en cours d'exécution)
Mon plan est d'utiliser le crochet pour attraper la clé d'entrée, et ensuite utiliser keybd_event pour simuler le clavier. Mais j'ai quelques problèmes.
Le premier problème est que le programme peut correctement le bloc "A", mais si je frappe " A " sur le clavier une fois, le printf dans la fonction de rappel est exécutée deux fois, ainsi que le keybd_event. Donc, si j'ouvre un fichier txt, je clique sur " A " une fois, il y a deux 'B de l'entrée. pourquoi est-ce?
La deuxième question est que pourquoi le crochet à l'aide de WH_KEYBOARD_LL peut travailler sur d'autres processus sans une dll? J'ai pensé que nous avons dû utiliser une dll pour faire un hook global jusqu'à ce que j'ai écrit cet exemple...
#include "stdafx.h"
#include <Windows.h>
#define _WIN32_WINNT 0x050
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
BOOL fEatKeystroke = FALSE;
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (fEatKeystroke = (p->vkCode == 0x41)) { //redirect a to b
printf("Hello a\n");
keybd_event('B', 0, 0, 0);
keybd_event('B', 0, KEYEVENTF_KEYUP, 0);
break;
}
break;
}
}
return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam));
}
int main()
{
//Install the low-level keyboard & mouse hooks
HHOOK hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0);
//Keep this app running until we're told to stop
MSG msg;
while (!GetMessage(&msg, NULL, NULL, NULL)) { //this while loop keeps the hook
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhkLowLevelKybd);
return(0);
}
Merci beaucoup!
selon msdn.microsoft.com/en-us/library/windows/desktop/... - "...peut retourner une valeur différente de zéro pour éviter que le système de passer le message au reste de la chaîne de crochet ou de la procédure de fenêtre cible". Pour moi, empêchant le système de passer le message à la procédure de fenêtre cible ressemble exactement comme le blocage.
Pour ceux qui cherchent à obtenir que cela fonctionne, mais reçoit ERROR_HOOK_NEEDS_HMOD (1428): selon SetWindowsHookEx doc, "une erreur peut se produire si le hMod paramètre est NULL et le dwThreadId paramètre est égal à zéro". Par conséquent, vous devez spécifier
hMod
, mais dans ce cas, vous pouvez utiliser n'importe quelle valeur juridique, puisque aucune DLL est injecté de toute façon pour le bas niveau des crochets. Vous pouvez utiliser, par exemple, GetModuleHandle("kernel32.dll")
.
OriginalL'auteur user1722361 | 2014-04-09
Vous devez vous connecter pour publier un commentaire.
Premier est facile. Vous obtenez une clé et un autre pour les principaux. 🙂
Comme pour le pourquoi il peut fonctionner sans DLL - c'est parce que c'est un hook global. À la différence de thread spécifique de ceux qu'il est exécuté dans votre propre processus, non pas dans le processus où l'événement de clavier qui s'est passé. Il se fait via l'envoi d'un message pour le thread qui a installé le crochet - c'est précisément la raison pour laquelle vous avez besoin de boucle de message ici. Sans cela votre crochet ne peut pas être exécuté car il n'y aurait personne pour les écouter pour les messages entrants.
La DLL est nécessaire pour le thread spécifique crochets parce qu'ils sont appelés dans le cadre d'un autre processus. Pour que cela fonctionne, votre fichier DLL doit être injecté dans le processus. Il n'est pas le cas ici.
C'est tout faux. Globale de tous les crochets doivent être dans une DLL, sauf si c'est un hook de bas niveau. La documentation est incomplète sur ce point. La langue ici est le C++, mais C# peut utiliser des accroches de bas niveau, car ils n'ont pas besoin d'une DLL.
OriginalL'auteur Ivan Danilov
Votre fonction de rappel exécuter deux fois à cause de
WM_KEYDOWN
etWM_KEYUP
.Lorsque vous enfoncée une touche de votre clavier, windows appelle la fonction de rappel avec
WM_KEYDOWN
message et lorsque vous relâchez la touche, windows appelle la fonction de rappel avecWM_KEYUP
message. C'est pourquoi votre fonction de rappel exécuter deux fois.Vous devriez changer votre instruction switch pour cela:
À propos de votre deuxième question, je pense que vous avez déjà obtenu à partir de @Ivan Danilov réponse.
OriginalL'auteur Forhad Reza
OriginalL'auteur Hung Minh Tran