NSEvent`subtype`等价于CGEvent?

时间:2014-01-01 00:43:59

标签: macos cocoa macos-carbon nsevent cgeventtap

NSEvent有一种获取事件subtype的方法:

  

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

可以从CGEvent访问同一subtype而不先将其转换为NSEvent吗?

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

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

CGEvent docs提到鼠标事件子类型,似乎与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

2 个答案:

答案 0 :(得分:4)

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

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

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

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

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

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

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

答案 1 :(得分:2)

所以我对此进行了一些研究,看起来子类型data1和data2是可能的。

CFDataRef data = CGEventCreateData(kCFAllocatorDefault, cg_event_ref);
CFDataGetBytes(data, CFRangeMake(108, 16), buffer);

UInt32 subtype = CFSwapInt32BigToHost(*((UInt32 *) buffer));
UInt32 data1 = *((UInt32 *) buffer + 2);
// Data2 needs testing. It could be at + 4.
UInt32 data2 = *((UInt32 *) buffer + 3);

...

CFRelease(data);
free(buffer);

更新:所以这是获取上述信息的正确方法。它需要与-lobjc链接。

#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);
auto_release_pool = objc_msgSend(pool, sel_registerName("init"));

id event_data = objc_msgSend((id) objc_getClass("NSEvent"), sel_registerName("eventWithCGEvent:"), cg_event_ref);
int subtype = (int) objc_msgSend(event_data, sel_registerName("subtype"));
int data1 = (int) objc_msgSend(event_data, sel_registerName("data1"));
int data2 = (int) objc_msgSend(event_data, sel_registerName("data2"));
...
objc_msgSend(auto_release_pool, sel_registerName("release"));