c++ macos events quartz-graphics macos-carbon

c++ - El evento de Mac solo retrasa los eventos descartados



macos events (3)

Estoy intentando escribir un código que descarta todos los eventos del teclado y el mouse cuando está habilitado en Mac OSX 10.6. Mi código se ejecuta como usuario root. El enfoque que estoy tomando es crear un toque de evento que descarte todos los eventos pasados ​​(mientras esté habilitado). La función de devolución de llamada de toque de evento se ve así:

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

Y el código que estoy usando para habilitar y deshabilitar el toque del evento se ve así:

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 el toque del evento está activo. Puedo golpear el teclado y el mouse tanto como lo desee y ningún evento lo logra a través del sistema. Sin embargo, cuando el toque está deshabilitado, todas las teclas que presioné mientras el toque estaba activo aparecen en la ventana actual. Es como si el toque del evento simplemente retrasara los eventos, en lugar de destruirlos, lo cual es extraño, ya que la documentación de Mac establece claramente:

Si el evento tap es un filtro activo, su función de devolución de llamada debe devolver uno de los siguientes:

El evento (posiblemente modificado) que se pasa. Este evento se pasa de nuevo 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 va a eliminar el evento pasado.

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


El comentario vinculado no tiene una respuesta de lo que veo, así que daré un poco de información de lo que he visto al hurgarme con estas cosas.

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

A continuación, y esto / puede / ser todo lo que necesita ... En su devolución de llamada, probablemente desee (y quizás necesite) verificar los siguientes eventos:

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

Independientemente de lo que diga o no lo que diga la documentación, mi observación es que el sistema operativo se siente como si estuviera "sondeando" en busca de malas devoluciones de llamadas; Básicamente, se deshabilitan las devoluciones de llamada de toque de evento que son eventos que se comen universalmente Si vuelve a registrarse en estos casos, el sistema operativo parece estar bien con eso, como si dijera: está bien, parece que sabe lo que está haciendo, pero probablemente lo empuje de nuevo en un momento para asegurarme.


Es realmente extraño, usamos toques de eventos para el mismo propósito (bloqueo de entrada en un escenario determinado) y funciona perfectamente de 10.4 a 10.8.2. una cosa, no debe bloquear ni recibir eventos de un diálogo de contraseña (lo cual no es una gran sorpresa)

Lo que puedo ver ahora es diferente en comparación con su muestra:

  • usamos kCGTailAppendEventTap en lugar de kCGHeadInsertEventTap (esto no debería importar)
  • Hacemos algún registro de eventos en el callback instalado.
  • tenemos algunos datos de eventos de usuario en algunos eventos autoinyectados, que se filtran, pero aparte de esto, simplemente devolvemos NULL para eliminar un evento no deseado (como lo hace usted), puedo confirmar, ¡no todos los eventos son ignorables!
  • activamos / desactivamos el evento tocando de 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; }


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