4

NSEvent有一个获取事件的方法subtype

获取自定义事件信息
——data1
——data2——
子类型

是否可以subtype在不先将其转换为 NSEvent 的情况下从 CGEvent 访问它?

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

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

CGEvent文档提到了鼠标事件子类型,似乎与来自IOLLEvent.h. 但是,我对查找系统定义的 CGEvents 的子类型特别感兴趣。

这些将是NX_SUBTYPE_AUX_CONTROL_BUTTONS下面的 等或 CG 替代品。

/* 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
4

2 回答 2

4

对于鼠标事件,可以使用CGEventGetIntegerValueField来获取事件的kCGMouseEventSubtype属性。

系统定义的事件比较棘手。CGEvents 似乎并没有真正暴露这一点。

最简单的部分是匹配事件。只要 CGEvent 使用与 NSEvent 和 IOLLEvent 相同的事件类型编号,并且只要事件掩码是 的简单组合1 << eventType,您就应该能够CGEventMaskBit(NSSystemDefined)在注册和CGEventGetType(event) == NSSystemDefined测试中使用一些变体。

困难的部分是在不通过 NSEvent 的情况下告诉系统定义事件的子类型是什么。

一种可能性是对鼠标事件(使用kCGMouseEventSubtype)执行相同的操作,但由于鼠标事件和“复合”(包括系统定义的)事件的布局NXEventData不同,我不会指望这种工作。

最有可能的是,没有办法从 CGEvent 中获取系统定义事件的子类型,因此您必须创建一个 NSEvent。

你考虑过使用 NSEvent 的事件监控 API 吗?如果您需要 10.6 或更高版本,您可以通过这种方式捕获事件,并且您已经将它们作为 NSEvents 获取,准备好询问它们的子类型。

于 2014-01-02T01:24:07.843 回答
2

所以我对此做了一些研究,看起来子类型、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"));
于 2015-07-03T17:38:45.400 回答