键盘挂钩问题
我正在开发一个使用按键通话键的语音聊天应用程序。我已经做了一个钩子,因此它也会在应用程序外部注册一键通。
HHOOK hHook = SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)pushtotalk,0,0);
LRESULT CALLBACK pushtotalk(int key, WPARAM wParam,LPARAM lParam) {
if (key < 0) {
return (CallNextHookEx(hook,key,wParam,lParam));
}
else if (connected) {
KBDLLHOOKSTRUCT* kbdll = (KBDLLHOOKSTRUCT*)lParam;
if (kbdll ->vkCode == 75 && wParam == WM_KEYDOWN) {
MessageBox(mainhWnd,"KEYSTART","KEYSTART",0);
}
else if (kbdll ->vkCode == 75 && wParam == WM_KEYUP) {
MessageBox(mainhWnd,"KEYSTOP","KEYSTOP",0);
}
}
return (CallNextHookEx(hook,key,wParam,lParam));
}
问题;
1) 有时,(例如应用程序中 proc 的第一次执行),proc 在继续之前会导致 5 秒的系统冻结。为什么?
2)该钩子仅适用于在我的应用程序启动之前启动的进程,如果我在启动应用程序后启动文本程序,则钩子将不会注册。有解决办法吗?
3)如果我按住该键大约3秒,会明显显示很多消息框,但之后,过程将永远不会注册另一个被按下的键,所以我想我不知何故与钩子链断开了?
干杯
编辑:这是应用程序的主消息循环
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch(message) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case ID_MENU_EXIT:
SendMessage(hWnd,WM_CLOSE,0,0);
break;
case ID_MENU_PREFERENCES:
voiceManager->send((void*) "1");
break;
case ID_BUTTON_CONNECT:
onConnect(hWnd);
break;
case ID_BUTTON_DISCONNECT:
onDisconnect(hWnd);
break;
case ID_BUTTON_SEND:
onSendText(hWnd);
break;
default:
break;
}
break;
case SOCKET_TCP:
switch (lParam) {
case FD_READ:
{
// Disable repeated FD_READ call while we process message
WSAAsyncSelect(wParam,hWnd,SOCKET_TCP, FD_WRITE | FD_ACCEPT | FD_CLOSE);
// first four bytes is packet size
// second four bytes are used to identify type of msg
char* psize = (char*)malloc(5);
char* ptype = (char*)malloc(5);
psize[4] = '\0';
ptype[4] = '\0';
recv(wParam,psize,4,0);
recv(wParam,ptype,4,0);
// allocate memory for the buffer
int size_to_recv = atoi(psize);
char* textbuff = (char*)malloc(size_to_recv);
// receive
int i = size_to_recv;
while (i > 0) {
int read = recv(wParam,textbuff,i,0);
i = i - read;
}
// handle msg depending on type
switch(identifyMsg(ptype)) {
case 1:
// handle 'text' msg
onReadText(hWnd,textbuff);
break;
case 2:
// handle 'name' msg
onReadName(hWnd,textbuff);
break;
case 3:
// handle 'list' msg
onReadList(hWnd,textbuff);
break;
case 4:
// handle 'remv' msg
onReadRemv(hWnd,textbuff,size_to_recv);
break;
case 5:
// handle 'ipad' msg -- add ip
voiceManager->addParticipant(inet_addr(textbuff));
break;
case 6:
// handle 'iprm' msg -- remove ip
voiceManager->removeParticipant(inet_addr(textbuff));
break;
default:
break;
}
// re-enable FD_READ
WSAAsyncSelect(wParam,hWnd,SOCKET_TCP, FD_WRITE | FD_ACCEPT | FD_READ | FD_CLOSE);
// free resources
free(psize);
free(ptype);
free(textbuff);
break;
}
case FD_WRITE:
break;
case FD_CONNECT:
break;
case FD_CLOSE:
onDisconnect(hWnd);
break;
default:
break;
}
break;
case WM_PAINT:
paintText(hWnd);
break;
case WM_DESTROY:
shutdownConnection(hWnd);
// reset window procs
SetWindowLong(GetDlgItem(hWnd,ID_EDIT_SEND), GWL_WNDPROC,(LONG) OriginalEditProc);
SetWindowLong(GetDlgItem(hWnd,ID_EDIT_IP), GWL_WNDPROC,(LONG) OriginalEditProc);
PostQuitMessage(0);
return 0;
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
default:
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK sendEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_CHAR) {
if (wParam == VK_RETURN) {
onSendText(GetParent(hWnd));
return 0;
}
}
if (message == WM_KEYUP || message == WM_KEYDOWN) {
if (wParam == VK_RETURN) {
return 0;
}
}
return CallWindowProc(OriginalEditProc, hWnd, message, wParam,lParam);
}
,其中 sendEditProc 是一个子/超类,旨在在编辑控件“发送”内部时拦截“输入”键 这有帮助吗?
这是消息循环;这是标准,所以没有什么花哨的可能会出错的afaik:)
while (GetMessage(&msg, NULL,0,0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您调用 CallNextHookEx 的次数太多了。如果
key < 0 返回 CallNextHookEx
,否则返回 0
。您看到的问题与键盘重复和 MessageBox 或 MessageBeep 方法的调用非常非常昂贵有关。尝试此测试:
您可以通过在调试器下运行应用程序来监视调试字符串(检查“输出”窗口),或者您可以获得 DebugView 并观看。
请注意,我没有像您那样检查
connected
。您不想在挂钩中执行该检查,而是在挂钩外部执行该检查,并且仅使用挂钩来确定按键是否被按下。You're calling CallNextHookEx one too many times. If
key < 0 return CallNextHookEx
, otherwisereturn 0
.The problem you're seeing has to do with keyboard repeats and the MessageBox or MessageBeep methods being very, very expensive calls. Try this test:
You can monitor the debug strings by running the app under the debugger (check the Output window), or you can get DebugView and watch that.
Notice that I do not check for
connected
as you did. You don't want to perform that check in the hook, do that outside the hook and only use the hook to determain if the key is pressed or not pressed.