Эквивалент подтипа NSEvent для CGEvent?

NSEvent имеет метод для получения события subtype:

Получение информации о пользовательских событиях
– data1
– data2
– подтип

Можно ли получить доступ к этому же subtype из CGEvent без предварительного преобразования его в NSEvent?

CGEventRef eventCG = ...;
NSEvent *eventNS = [NSEvent eventWithCGEvent:eventCG];

short subtypeNS = eventNS.subtype;
short subtypeCG = ???;

В документах CGEvent упоминается событие мыши. подтипы, которые, кажется, соответствуют подтипам мыши из IOLLEvent.h. Однако меня особенно интересует поиск подтипов для системных CGEvents.

Это будут NX_SUBTYPE_AUX_CONTROL_BUTTONS и т. д. ниже или альтернативы компьютерной графики.

/* sub types for mouse and move events */

#define NX_SUBTYPE_DEFAULT                  0
#define NX_SUBTYPE_TABLET_POINT             1
#define NX_SUBTYPE_TABLET_PROXIMITY         2
#define NX_SUBTYPE_MOUSE_TOUCH              3

/* sub types for system defined events */

#define NX_SUBTYPE_POWER_KEY                1
#define NX_SUBTYPE_AUX_MOUSE_BUTTONS        7

/* 
 * NX_SUBTYPE_AUX_CONTROL_BUTTONS usage
 *
 * The incoming NXEvent for other mouse button down/up has event.type 
 * NX_SYSDEFINED and event.data.compound.subtype NX_SUBTYPE_AUX_MOUSE_BUTTONS.
 * Within the event.data.compound.misc.L[0] contains bits for all the buttons 
 * that have changed state, and event.data.compound.misc.L[1] contains the 
 * current button state as a bitmask, with 1 representing down, and 0
 * representing up.  Bit 0 is the left button, bit one is the right button, 
 * bit 2 is the center button and so forth.
 */
#define NX_SUBTYPE_AUX_CONTROL_BUTTONS      8

#define NX_SUBTYPE_EJECT_KEY                10
#define NX_SUBTYPE_SLEEP_EVENT              11
#define NX_SUBTYPE_RESTART_EVENT            12
#define NX_SUBTYPE_SHUTDOWN_EVENT           13

#define NX_SUBTYPE_STICKYKEYS_ON            100
#define NX_SUBTYPE_STICKYKEYS_OFF           101
#define NX_SUBTYPE_STICKYKEYS_SHIFT         102
#define NX_SUBTYPE_STICKYKEYS_CONTROL           103
#define NX_SUBTYPE_STICKYKEYS_ALTERNATE         104
#define NX_SUBTYPE_STICKYKEYS_COMMAND           105
#define NX_SUBTYPE_STICKYKEYS_RELEASE           106
#define NX_SUBTYPE_STICKYKEYS_TOGGLEMOUSEDRIVING    107

person pkamb    schedule 01.01.2014    source источник


Ответы (2)


Для событий мыши вы можете использовать CGEventGetIntegerValueField, чтобы получить свойство kCGMouseEventSubtype события.

Системные события сложнее. CGEvents, похоже, не раскрывает этого.

Легкая часть соответствует событиям. Пока CGEvent использует те же номера типов событий, что и NSEvent и IOLLEvent, и пока маски событий представляют собой просто комбинации 1 << eventType, вы сможете использовать некоторые варианты CGEventMaskBit(NSSystemDefined) для регистрации и CGEventGetType(event) == NSSystemDefined для тестирования.

Сложность заключается в том, чтобы определить подтип системного события, не проходя через NSEvent.

Одной из возможностей было бы сделать то же самое, что и для события мыши (использовать kCGMouseEventSubtype), но поскольку макет NXEventData отличается для событий мыши и «составных» (включая системные) событий, я бы не стал рассчитывать на то, что это сработает. .

Скорее всего, нет никакого способа получить системный подтип события из CGEvent, поэтому вам придется создать NSEvent.

Рассматривали ли вы возможность использования API монитора событий NSEvent? Если вам может потребоваться 10.6 или более поздняя версия, вы можете перехватывать события таким образом, и вы уже получите их как NSEvents, готовые для запроса их подтипов.

person Peter Hosey    schedule 02.01.2014
comment
Спасибо. Я бы предпочел монитор NSEvent, но, к сожалению, CGEvents — единственный способ запустить глобальный хук. Идея заключалась в том, чтобы отфильтровать довольно распространенные события NX_SUBTYPE_AUX_MOUSE_BUTTONS перед созданием NSEvent. Многие из них попадают в мои события NSSystemDefined (в частности, ключ питания). Не самая плохая вещь в мире, но это было бы чем-то вроде оптимизации. - person pkamb; 03.01.2014
comment
@pkamb: Почему API глобального монитора событий NSEvent не делает то, что вам нужно? Вы хотите изменить или съесть определенные события? - person Peter Hosey; 03.01.2014
comment
Пометка как принятый ответ (спасибо!), Вероятно, нет способа получить подтип системного события. Изменится, хотя, если кто-то найдет способ. - person pkamb; 05.01.2014
comment
Попробуйте CGEventGetIntegerValueField(event, 110), который кажется подтипом. Протестировано на событиях жестов и прокрутки. - person Noah Nuebling; 19.06.2021

Итак, я провел небольшое исследование по этому вопросу, и похоже, что это возможно для подтипа data1 и data2. Возможно, вам не следует этого делать, см. обновление ниже.

CFDataRef data_ref = CGEventCreateData(kCFAllocatorDefault, event_ref);
if (data_ref == NULL) {
    return;
}

CFIndex len = CFDataGetLength(data_ref);
UInt8 *buffer = malloc(20);
if (buffer == NULL) {
    return;
}

CFDataGetBytes(data_ref, CFRangeMake(len - 68, 20), buffer);

...

int subtype = CFSwapInt32BigToHost(*((UInt32 *) buffer));

#ifdef __LP64__
long data1 = CFSwapInt64BigToHost(*((UInt64 *) (buffer + 4)));
#else
long data1 = CFSwapInt32BigToHost(*((UInt32 *) (buffer + 4)));
#endif
        
#ifdef __LP64__            
long data2 = CFSwapInt64BigToHost(*((UInt64 *) (buffer + 12)));
#else
long data2 = CFSwapInt32BigToHost(*((UInt32 *) (buffer + 8)));
#endif

...

CFRelease(data_ref);
free(buffer);

Обновление: Вот правильный способ получить приведенную выше информацию. Это потребует связывания с -framework AppKit.

#include <objc/objc.h>
#include <objc/objc-runtime.h>

static id auto_release_pool;

...

Class NSAutoreleasePool_class = (Class) objc_getClass("NSAutoreleasePool");
id pool = class_createInstance(NSAutoreleasePool_class, 0);
id (*eventWithoutCGEvent)(id, SEL) = (id (*)(id, SEL)) objc_msgSend;
auto_release_pool = eventWithoutCGEvent(pool, sel_registerName("init"));

...

id (*eventWithCGEvent)(id, SEL, CGEventRef) = (id (*)(id, SEL, CGEventRef)) objc_msgSend;
id event_data = eventWithCGEvent((id) objc_getClass("NSEvent"), sel_registerName("eventWithCGEvent:"), event_ref);

long (*eventWithoutCGEvent)(id, SEL) = (long (*)(id, SEL)) objc_msgSend;
int subtype = (int) eventWithoutCGEvent(event_data, sel_registerName("subtype"));

long data1 = eventWithoutCGEvent(event_data, sel_registerName("data1"));
long data2 = eventWithoutCGEvent(event_data, sel_registerName("data2"));

...

eventWithoutCGEvent(auto_release_pool, sel_registerName("release"));
person Alex Barker    schedule 03.07.2015