2011-01-19 14 views
6

Estoy haciendo una aplicación de chat de voz que usa una tecla de pulsar para hablar. He hecho un gancho para que también registre la aplicación exterior de pulsar para hablar.Problemas de Keyboard Hook

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

Problemas;

1) A veces, (por ejemplo, la primera ejecución del proceso en la aplicación), el proceso provoca una congelación del sistema de 5 segundos antes de continuar. ¿Por qué?

2) El gancho solo funciona en el proceso que se inició antes de que se iniciara mi aplicación, si empiezo un programa de texto después de iniciar mi aplicación, los ganchos no se registrarán. ¿Hay una solución para esto?

3) Si mantengo presionada la tecla durante ~ 3 segundos, obviamente, muchos MessageBoxes muestran, pero después de eso, el proceso nunca registrará otra tecla presionada, ¿así que supongo que de alguna manera me desconectaré de la cadena de enlace?

Saludos

EDIT: Aquí está el bucle principal de mensajes para la aplicación

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

Dónde sendEditProc es una sub/superclase diseñado para interceptar 'enter' teclas cuando dentro de un control de edición 'enviar' ¿El esta ayuda?

Aquí está el ciclo del mensaje; es el estándar así que nada de lujos que podría ir mal afaik :)

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

¿Esto está en una DLL? – soulseekah

+0

No, como utilicé WH_KEYBOARD_LL coloqué el proceso dentro de la aplicación principal. – KaiserJohaan

+0

Si comenta las llamadas de MessageBox (o lo reemplaza con algo como MessageBeep), ¿todavía tiene los mismos problemas? – Tadmas

Respuesta

3

Llamas a CallNextHookEx demasiadas veces. Si key < 0 return CallNextHookEx, de lo contrario return 0.

El problema que está viendo tiene que ver con repeticiones de teclado y los métodos MessageBox o MessageBeep son llamadas muy, muy costosas. Haga esta prueba:

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

Puede supervisar las cadenas de depuración mediante la ejecución de la aplicación en el depurador (marque la ventana de resultados), o puede obtener DebugView y ver eso.

Tenga en cuenta que no compruebo el connected como lo hizo. No desea realizar esa verificación en el gancho, haga eso fuera del gancho y solo use el gancho para determinar si se presiona o no se presiona la tecla.

+0

¿Cómo puedo verificar 'conectado' y no usar el gancho si su conjunto es falso? ¿Quiere crear el gancho en Conectado y eliminarlo en Desconectado, por ejemplo? Además, si devuelvo 0 como lo hizo al final del proceso, ¿no es eso 'interceptar' la tecla presionar mensajes y dificultar que se envíen a la aplicación que actualmente tenía foco? Por ejemplo, si escribo "k" en un editor de texto mientras mi programa estaba en ejecución, quiero capturar la "k", pero tampoco quiero interferir con la salida del texteado. CallNextHook le pasa el mensaje al hombre real para quien estaba destinado, ¿verdad? – KaiserJohaan

+0

Necesita saber el estado de la tecla Pulsar para hablar (hacia abajo o hacia arriba). Haz eso en el controlador como lo he hecho aquí. Es probable que desee hacer algo diferente de 'OutputDebugString' en respuesta y ese código puede verificar el estado conectado. – Tergiver

+0

En cuanto a 'CallNextHookEx', tiene razón. Tengo mis manipuladores de gancho confundidos. Lo has corregido la primera vez. http://msdn.microsoft.com/en-us/library/ms644985.aspx – Tergiver