2010-05-12 8 views
18

Estoy tratando de escribir algún código que descarte todos los eventos de teclado y mouse cuando está habilitado en Mac OSX 10.6. Mi código se ejecuta como el usuario raíz. El enfoque que estoy tomando es crear un toque de evento que descarte todos los eventos que se le pasen (mientras está habilitado). La función de devolución de llamada de eventos del grifo se ve así:El toque de evento de Mac solo retrasa los eventos descartados

CGEventRef MyTapCallback(CGEventTapProxy proxy, 
         CGEventType type, 
         CGEventRef event, 
         void *refcon) 
{ 
    return CKeyLocker::isEnabled() ? NULL : event; 
} 

Y el código que estoy usando para activar y desactivar el grifo evento es el siguiente:

void CKeyLocker::enable(bool bEnable) 
{ 
    if (bEnable == m_bEnabled) 
     return; 

    if (bEnable) 
    { 
     // which events are we interested in? 
     CGEventMask evMask = kCGEventMaskForAllEvents; 
     CFMachPortRef mp = CGEventTapCreate(kCGHIDEventTap, 
              kCGHeadInsertEventTap, 
              kCGEventTapOptionDefault, 
              evMask, 
              MyTapCallback, 
              NULL); 

     if (mp) 
     { 
      qDebug() << "Tap created and active. mp =" << mp; 
      m_enabledTap = mp; 
      m_bEnabled = true; 
     } 
    } 
    else 
    { 
     CGEventTapEnable(m_enabledTap, false); 
     CFRelease(m_enabledTap); 
     m_enabledTap =0; 
     m_bEnabled = false; 
     qDebug() << "Tap destroyed and inactive"; 
    } 
} 

Este enfoque funciona muy bien, mientras que el grifo evento está activo: puedo presionar el teclado y el mouse tanto como quiera y ningún evento lo hace a través del sistema. Sin embargo, cuando el tap está desactivado, todas las teclas que presioné mientras el tap estaba activo aparecen en la ventana actual. Es como el grifo evento es muy retrasar los eventos, en lugar de destruirlas, lo cual es extraño, ya que la documentación de Mac indica claramente:

Si el grifo evento es un filtro activo, la función de devolución de llamada debe devolver uno de los siguiente:

El evento (posiblemente modificado) que se transfiere. Este evento se devuelve al sistema de eventos.

Un evento de nueva construcción. Después de que el nuevo evento haya sido devuelto al sistema de eventos, el nuevo evento se lanzará junto con el evento original.

NULL si se debe eliminar el evento pasado.

Estoy devolviendo NULL, pero el evento no parece ser eliminado. ¿Algunas ideas?

+0

los solucionaron este problema? Acabo de encontrar exactamente el mismo comportamiento. – Dan

+0

no, desafortunadamente no. – Thomi

+0

Vea también http://stackoverflow.com/questions/4518559/consuming-osx-mouse-trackpad-events-with-an-event-tap – James

Respuesta

0

Puedo verificar que devolver NULL efectivamente elimina algunos eventos, pero también he visto ocasiones en las que no, exactamente cómo decide qué eliminaciones permitir no está claro, pero parece que las eliminaciones masivas parecen estar prevenidas, por ejemplo: cuando elimina más de 100 eventos más o menos en una fila.

1

El comentario vinculado no tiene una respuesta de lo que veo, así que voy a volcar algo de información de lo que he visto al hurgar con estas cosas.

Primero, tengo mucha mejor suerte con CGEventTapCreateForPSN. Es como si el sistema le diera un margen de maniobra para restringir el acceso. Sin embargo, de este ejemplo, parece que esto no es suficiente.

El siguiente paso - y esto/puede/ser todo lo que necesita ... En su llamada de vuelta, es probable que desee (y puede ser necesario) para comprobar los siguientes eventos:

switch (type) 
{ 
    case kCGEventTapDisabledByTimeout: 
    case kCGEventTapDisabledByUserInput: 
    { 
     CFMachPortRef *pTap = (CFMachPortRef*)refcon; 
     CGEventTapEnable(*pTap, true); 
     return NULL; 
    } 
    default: 
     break; 
} 

Independientemente de lo que el varios documentos dicen o no dicen, ha sido mi observación que el sistema operativo siente que está 'sondeando' las malas respuestas; básicamente deshabilitando devoluciones de llamadas de eventos que son eventos de alimentación universal. Si vuelve a registrarse en estos casos, el sistema operativo parece estar bien, como diciendo: OK, parece que sabe lo que está haciendo, pero probablemente lo vuelva a asomar un poco para estar seguro.

1

Es realmente extraño, utilizamos grifos de eventos para el mismo propósito (bloqueo de entrada en un escenario dado) y funciona perfectamente 10.4 - 10.8.2.excpet una cosa, no debe bloquear o recibir eventos de un diálogo de contraseña (que no es una gran sorpresa)

lo que puedo ver ahora es diferente en comparación con el que la muestra es:

  • utilizamos kCGTailAppendEventTap vez de kCGHeadInsertEventTap (esto no debería importar)
  • hacemos alguna registro de eventos en la devolución de llamada instalado
  • tenemos algunos datos de eventos de usuario en algunos eventos auto inyectado, que se filtraba a cabo, pero, aparte de esto, simplemente devuelva NULL para soltar un evento no deseado (como lo hace), puedo confirmar, no todos los eventos son ignorables!
  • que encender/apagar el evento gira esta manera:
 
bool SetInputFilter(bool bOn) 
{ 
    bool result = false; 
    CFRunLoopRef runLoopRef = CFRunLoopGetMain(); 

    if (bOn) { 
     // Create an event tap. 
     CGEventMask eventMask = kCGEventMaskForAllEvents; 
     if ((m_eventTapInput = CGEventTapCreate(kCGHIDEventTap, 
               kCGTailAppendEventTap, 
               kCGEventTapOptionDefault, 
               eventMask, CGInputEventCallback, this)) == NULL) { 
      Log(L"Failed to create event tap"); 
      return result; 
     } 

     // Create a run loop source. 
     m_runLoopEventTapSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTapInput, 0); 
     CFRelease(m_eventTapInput); // CFMachPortCreateRunLoopSource retains m_eventTapInput 
     if (m_runLoopEventTapSource == NULL) { 
      Log(L"Failed to create run loop source for event tap"); 
      return result; 
     } 

     // Add to the current run loop. 
     CFRunLoopAddSource(runLoopRef, m_runLoopEventTapSource, kCFRunLoopCommonModes);//kCFRunLoopDefaultMode); 
     CFRelease(m_runLoopEventTapSource); // CFRunLoopAddSource retains m_runLoopEventTapSource 
     result = true; 
    } 
    else { 
     // Disable the event tap. 
     if (m_eventTapInput) 
      CGEventTapEnable(m_eventTapInput, false); 

     // Remove our run loop source from the current run loop. 
     if (runLoopRef && m_runLoopEventTapSource) { 
      CFRunLoopRemoveSource(runLoopRef, m_runLoopEventTapSource, kCFRunLoopCommonModes);//kCFRunLoopDefaultMode); 
      m_runLoopEventTapSource = NULL; // removing m_runLoopEventTapSource releases last reference of m_runLoopEventTapSource too 
      m_eventTapInput = NULL;   // removing m_runLoopEventTapSource releases last reference of m_eventTapInput too 
     } 
    } 
    return result; 
} 
Cuestiones relacionadas