2016-02-16 3 views
1

Я посылаю нажатия клавиш клавиатуры и нажатия клавиш, которые работают для всех клавиш клавиатуры.Эмуляция/отправка ключа модификатора (Cntrl, Alt, fn, Shift) в OSx

Но ключи-модификаторы работают только тогда, когда ключ, связанный с ключом-модификатором, отправляется из приложения, а не из реального оборудования. То есть, если я отправлю Shift и «a» из приложения, он печатает «A» (капитал A, это то, что ожидается).

Но если я отправил событие «смена» из приложения и введите «a» с физической клавиатуры, он напечатает «a» (клавиша shift не работает на разных устройствах). То же самое относится к другим клавишам-модификаторам, таким как клавиши 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