¿Cómo monitorear el estado global de la clave modificadora (en cualquier aplicación)?

StackOverflow https://stackoverflow.com/questions/1603030

  •  05-07-2019
  •  | 
  •  

Pregunta

Estoy usando un código de carbono en mi proyecto Cocoa para manejar eventos clave globales (accesos directos) desde otras aplicaciones. Actualmente he configurado un controlador de eventos kEventHotKeyReleased y puedo obtener exitosamente teclas de acceso rápido cuando mi aplicación no está activa. Eso activa alguna operación en mi aplicación.

El problema que tengo con el comportamiento de kEventHotKeyReleased es:

Digamos, por ejemplo, presiono la combinación de teclas Cmd-Shift-P. Tan pronto como suelte el " P " tecla se activa el evento de tecla de acceso rápido. Necesito poder activar el evento (o activarlo manualmente) cuando se eliminan todas las teclas (es decir, también se sueltan las teclas Cmd y Shift).

Es fácil monitorear las teclas de acceso rápido, pero no he visto nada para monitorear las pulsaciones de teclas individuales. Si pudiera monitorear los estados de la tecla modificadora estaría en el negocio.

¿Alguna sugerencia sobre cómo hacer esto?

Gracias de antemano!


UPDATE:

He intentado usar kEventRawKeyUp y kEventRawKeyModifiersChanged pero mientras que kEventHotKeyReleased funciona, los dos no lo hacen aunque los haya configurado exactamente. de la misma manera que kEventHotKeyReleased .

EventTypeSpec eventTypes[] = {{kEventClassKeyboard, kEventHotKeyReleased}, {kEventClassKeyboard, kEventRawKeyUp}};
// Changing the order in the list does not help, nor does removing kEventHotKeyReleased
OSStatus err = InstallApplicationEventHandler(&globalHotkeyHandler, GetEventTypeCount(eventTypes), eventTypes, NULL, NULL);
// err == noErr after this line

El método globalHotKeyHandler se llama para kEventHotKeyReleased , pero no para kEventRawKeyUp por alguna razón que parece que no puedo entender. Esto es lo que mi método globalHotKeyHandler parece:

OSStatus globalHotkeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData) {
    NSLog(@"Something happened!");
}

¿Hay alguna llamada adicional que deba hacerse o algo más que haya olvidado?

N.B: A primera vista, parece que podría ser que el Acceso para dispositivos de asistencia esté desactivado, pero no lo está . Así que estoy bastante despistado.


ACTUALIZACIÓN 2:

Investigué un poco sobre el CGEventTap que sugirió Leibowitzn y se me ocurrió esta configuración:

CFMachPortRef keyUpEventTap = CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,kCGEventKeyUp,&keyUpCallback,NULL);
CFRunLoopSourceRef keyUpRunLoopSourceRef = CFMachPortCreateRunLoopSource(NULL, keyUpEventTap, 0);
CFRelease(keyUpEventTap);
CFRunLoopAddSource(CFRunLoopGetCurrent(), keyUpRunLoopSourceRef, kCFRunLoopDefaultMode);
CFRelease(keyUpRunLoopSourceRef);

... y la devolución de llamada:

CGEventRef keyUpCallback (CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
    NSLog(@"KeyUp event tapped!");
    return event;
}

Como puede ver, estoy usando kCGEventKeyUp como la máscara para el evento, pero de alguna manera estoy recibiendo eventos de mouse down . ?! ??


ACTUALIZACIÓN 3:

Ok, olvídalo, pasé por alto la línea en el documento que decía usar CGEventMaskBit (kCGEventKeyUp) para este parámetro, por lo que la llamada correcta es:

CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventKeyUp),&keyUpCallback,NULL);

Aunque todavía tengo un problema: las teclas modificadoras no activan el kCGEventKeyUp ...


ACTUALIZACIÓN 4:

Ok, olvídalo otra vez ... Estoy obligado a responder a mis propias preguntas 5 minutos después de hacerlas hoy, ¡eh!

Para interceptar claves modificadoras, use kCGEventFlagsChanged :

CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventFlagsChanged),&callbackFunction,NULL);

Entonces, en esencia, funcioné la detección del estado de la clave y la clave modificadora, pero todavía estoy interesado en saber por qué kEventRawKeyUp no funciona ...


N.B: También tenga en cuenta que estoy desarrollando Tiger con el objetivo de tener soporte para versiones nuevas y antiguas del sistema operativo tanto como sea posible. CGEventTap es 10.4+ solo, así que usaré esto por ahora, pero una solución compatible con versiones anteriores sería bienvenida.

¿Fue útil?

Solución

Una opción es usar EventTaps. Esto le permite controlar todos los eventos del teclado. Ver: http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/CGEventTapCreate

Desafortunadamente, los toques de eventos dejarán de funcionar si una aplicación solicita una entrada segura. Por ejemplo, Quicken.

Otros consejos

OSStatus err = InstallApplicationEventHandler(&globalHotkeyHandler, GetEventTypeCount(eventTypes), eventTypes, NULL, NULL);

Esto no es global. Esto instala el controlador solo cuando su propia aplicación está activa y (creo) después de los propios filtros de eventos de Carbon Event Manager.

Debe usar InstallEventHandler , que toma un objetivo de evento como primer parámetro ( InstallApplicationEventHandler es una macro que pasa el objetivo del evento de la aplicación).

Para los eventos que ocurren mientras su aplicación no está activa, el objetivo que desea es GetEventMonitorTarget () . Para los eventos que ocurren mientras su aplicación está activa, el destino que desea es GetEventDispatcherTarget () . Para detectar eventos sin importar qué aplicación esté activa, instale su controlador en ambos objetivos.

Sin embargo, hoy en día, solo uso CGEventTaps, como sugirió Leibowitzn.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top