2011-01-19 3 views
6

Я использую приложение голосовой чат, в котором используется клавиша push-to-talk. Я сделал крючок, так что он будет регистрировать приложение «нажимать на разговор» тоже.Проблемы с клавиатурой Ключ

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 в приложении), процесс заставляет замораживание системы за 5 секунд до продолжения. Зачем?

2) Крючок работает только с процессом, который был запущен до запуска моего приложения, если я запускаю текстовую программу после запуска приложения, перехватчики не регистрируются. Это можно как-то исправить?

3) Если я удерживаю клавишу в течение ~ 3 секунд, многие из сообщений MessageBoxes показывают, очевидно, но после этого proc никогда не зарегистрирует другой нажатый ключ, так что, полагаю, я каким-то образом отключается от цепочки крючков?

Приветствия

EDIT: Вот основной цикл обработки сообщений для приложения

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 является суб/суперкласс предназначен для перехвата «введите» клавиши, когда внутри элемента управления редактирования «отправить» ли эта помощь?

Вот цикл сообщений; это стандарт, так что ничего фантастического, что может пойти не так, афайка :)

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

Это в DLL? – soulseekah

+0

Нет, поскольку я использовал WH_KEYBOARD_LL Я поместил proc внутри основного приложения. – KaiserJohaan

+0

Если вы закомментируете вызовы MessageBox (или замените его чем-то вроде MessageBeep), у вас все еще есть те же проблемы? – Tadmas

ответ

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

Вы можете отслеживать строки отладки, запустив приложение под отладчиком (проверьте окно Output), или вы можете получить DebugView и следить за тем.

Обратите внимание, что я не проверяю connected, как и вы. Вы не хотите выполнять эту проверку на крючке, делайте это за крючком и используйте только крючок, чтобы определить, нажата ли клавиша или не нажата.

+0

Как я могу проверить 'connected' и не использовать hook, если его значение false? Вы хотите создать hook on Connected и удалить его при отключенном, например? Кроме того, если я вернусь 0 так же, как вы делали в конце proc, не перехватывайте ключевые сообщения для печати и не мешайте им отправлять в приложение, которое в настоящее время имеет фокус? Например, если я пишу «k» в текстовом редакторе во время работы моей программы, я хочу поймать «k», но я также не хочу вмешиваться в вывод текстового редактора. CallNextHook передает сообщение вместе с актуалом, которому он предназначался для права? – KaiserJohaan

+0

Вам нужно знать состояние клавиши push-to-talk (вниз или вверх). Сделайте это в обработчике, как я это сделал. Вероятно, вы захотите сделать что-то другое, кроме 'OutputDebugString', и этот код может проверить состояние подключения. – Tergiver

+0

Что касается 'CallNextHookEx', вы правы. Я перепутал своих обработчиков. У вас было это правильно в первый раз. http://msdn.microsoft.com/en-us/library/ms644985.aspx – Tergiver

Смежные вопросы