2016-02-16 47 views
1

我正在发送键盘按键和按键释放事件,它们适用于所有键盘按键。在OSx中仿真/发送修改键(Cntrl,Alt,fn,Shift)

但修饰键仅在与修饰键相关的键是从应用程序发送而不是从真实硬件发送时才起作用。也就是说,如果我从应用程序发送 Shift和'a',它会打印'A'(大写字母A,这是预期的)。但如果我从应用程序发送'shift'键按下事件,并从物理键盘输入'a',它会打印出'a'(换档键似乎不适用于不同的设备)。这同样适用于其他修饰键,例如cmd,alt和fn键!

有没有办法将修改键发送给系统,以便我可以从我的应用程序中模拟修饰键? 具体来说,我想从应用程序中激活修饰键,然后从物理键盘中输入组合键。

这是我用来发送按键和发布事件的代码。

- (void)setADBKey:(uint32)key value:(int)value 
{ 
    if (!eventSource) 
    { 
     eventSource = CGEventSourceCreate(kCGEventSourceStatePrivate); 
    } 

    CGEventRef event = CGEventCreateKeyboardEvent(eventSource, key, value!=0); 
    CGEventPost(kCGHIDEventTap, event); 
    CFRelease(event); 
} 

我也曾尝试创建和发送系统事件,通过下面的代码

struct 
{ 

    CGKeyCode keyCode; 
    int flag; 
    int cgEventFlag; 

} modifiers[] = { 

    { 56, NX_DEVICELSHIFTKEYMASK, kCGEventFlagMaskShift }, 
    { 60, NX_DEVICERSHIFTKEYMASK, kCGEventFlagMaskShift }, 
    { 59, NX_DEVICELCTLKEYMASK, kCGEventFlagMaskControl }, 
    { 58, NX_DEVICELALTKEYMASK, kCGEventFlagMaskAlternate }, 
    { 61, NX_DEVICERALTKEYMASK, kCGEventFlagMaskAlternate }, 
    { 55, NX_DEVICELCMDKEYMASK, kCGEventFlagMaskCommand }, 
    { 54, NX_DEVICERCMDKEYMASK, kCGEventFlagMaskCommand } 

}; 

- (void)setAdbKey:(uint32)adbkey value:(int)value repeat:(BOOL)repeat 
{ 
    //int adbkey = def_usb_2_adb_keymap[hidkey]; 

    int modifier = 0; 

    for(int i=0; i< ARR_SIZE(modifiers); i++) 
    { 
     if (adbkey == modifiers[i].keyCode) 
     { 
      modifier = modifiers[i].cgEventFlag; 
      break; 
     } 
    } 

    if (value) 
    { 
     flags |= modifier; 
    }    
    else 
    { 
     flags &= ~modifier; 
    } 

    CGEventRef event = CGEventCreateKeyboardEvent(eventSource, adbkey, value!=0); 

    if (repeat) 
    { 
     CGEventSetIntegerValueField(event, kCGKeyboardEventAutorepeat, (int64_t)1); 
    } 

    // don't apply modifier flags to a modifier 
    if (!modifier) 
    { 
     CGEventSetFlags(event, flags); 
    } 

    CGEventPost(kCGHIDEventTap, event); 
    CFRelease(event); 
} 

这两种方法都工作时,修改键和组合键是由应用程序发送,而不是在修改键单独为从应用程序设置。

+0

而不是创造与'kCGEventSourceStatePrivate',你尝试过'kCGEventSourceStateCombinedSessionState'或'kCGEventSourceStateHIDSystemState'事件源? –

回答

1

您只需创建一个事件点击并设置蒙版。

样品:

@interface AppDelegate() 

@property (assign) CFMachPortRef myEventTap; 
@property (assign) CFRunLoopSourceRef myRunLoopSource; 

@end 

@implementation AppDelegate 

CGEventRef MyEventTapCallBack(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { 
    CGEventSetFlags(event, kCGEventFlagMaskShift); 
    return event; 
} 

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 
    self.myEventTap = CGEventTapCreate(kCGHIDEventTap, 
              kCGHeadInsertEventTap, 
              kCGEventTapOptionDefault, 
              CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventFlagsChanged), 
              MyEventTapCallBack, 
              (__bridge void *)self); 
    if (self.myEventTap) { 
     self.myRunLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.myEventTap, 0); 
     if (self.myRunLoopSource) 
      CFRunLoopAddSource(CFRunLoopGetMain(), self.myRunLoopSource, kCFRunLoopCommonModes); 
    } 
} 

- (void)applicationWillTerminate:(NSNotification *)aNotification { 
    if (self.myRunLoopSource) { 
     CFRunLoopSourceInvalidate(self.myRunLoopSource); 
     CFRelease(self.myRunLoopSource); 
    } 
    if (self.myEventTap) 
     CFRelease(self.myEventTap); 
} 

@end