首页 文章

键盘挂钩问题

提问于
浏览
6

我正在做一个使用按键通话键的语音聊天应用程序 . 我已经做了一个钩子,所以它也会在外部应用程序中注册按键通话 .

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秒钟,很多MessageBoxes显然会显示,但在那之后,proc将永远不会注册另一个被按下的键,所以我想我不知道从钩链断开了?

干杯

编辑:这是应用程序的主要消息循环

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);
}

1 回答

  • 3

    你太多次调用CallNextHookEx了 . 如果 key < 0 return CallNextHookEx ,否则 return 0 .

    你看到的问题与键盘重复有关,MessageBox或MessageBeep方法是非常非常昂贵的调用 . 试试这个测试:

    HHOOK hHook;
    BOOL bTalkEnabled = FALSE;
    
    LRESULT CALLBACK pushtotalk(int key, WPARAM wParam, LPARAM lParam)
    {
        if (key < 0)
            return CallNextHookEx(hHook, key, wParam, lParam);
    
        KBDLLHOOKSTRUCT* kbdll  = (KBDLLHOOKSTRUCT*)lParam;
        if (kbdll->vkCode == VK_F11)
        {
            BOOL bStarted = FALSE;
            BOOL bStopped = FALSE;
    
            if (wParam == WM_KEYDOWN)
            {
                if (!bTalkEnabled)
                {
                    bStarted = TRUE;
                    bTalkEnabled = TRUE;
                }
            }
            else if (wParam == WM_KEYUP)
            {
                if (bTalkEnabled)
                {
                    bStopped = TRUE;
                    bTalkEnabled = FALSE;
                }
            }
    
            if (bStarted)
                OutputDebugString(L"Pushed\r\n");
            if (bStopped)
                OutputDebugString(L"Released\r\n");
        }
    
        return 0;
    }
    

    您可以通过在调试器下运行应用程序来监视调试字符串(检查“输出”窗口),或者您可以获得DebugView并观察它 .

    请注意,我没有像你那样检查 connected . 您不想在钩子中执行该检查,在挂钩外执行该操作,并且仅使用挂钩来阻止按下或未按下该键 .

相关问题