2011-01-19 105 views
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是子/超類,旨在攔截「ENTER」鍵,當一個編輯控件中「發送」 不主消息循環這有幫助嗎?

這裏是消息循環;這是標準,所以沒有什麼幻想,可能會出錯afaik :)

while (GetMessage(&msg, NULL,0,0)) { 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 
+0

這是在DLL中嗎? – soulseekah 2011-01-19 04:41:05

+0

不,因爲我使用了WH_KEYBOARD_LL,我將proc放置在主應用程序中。 – KaiserJohaan 2011-01-19 11:54:22

回答

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。您不想在鉤子中執行該檢查,在鉤子之外執行該檢查,並且只使用鉤子來確定是否按下該鍵。