Extended key mapper to include modifiers as well

This commit is contained in:
michael starke
2017-01-18 18:30:10 +01:00
parent 334e92d1b4
commit c9b3637c24
7 changed files with 108 additions and 30 deletions

View File

@@ -17,7 +17,7 @@
}
- (void)execute {
CGKeyCode keyCode = [MPKeyMapper keyCodeForCharacter:@"A"];
CGKeyCode keyCode = [MPKeyMapper keyCodeForCharacter:@"a" modifier:NULL];
if(keyCode == kMPUnknownKeyCode) {
NSLog(@"Unable to generate key code for 'A'");
return;

View File

@@ -234,7 +234,7 @@ static CGKeyCode kMPFunctionKeyCodes[] = { kVK_F1, kVK_F2, kVK_F3, kVK_F4, kVK_F
NSUInteger part = random() % 2;
unichar key = [pasteContent characterAtIndex:i];
CGKeyCode keyCode = [MPKeyMapper keyCodeForCharacter:[NSString stringWithFormat:@"%c", key]];
CGKeyCode keyCode = [MPKeyMapper keyCodeForCharacter:[NSString stringWithFormat:@"%c", key] modifier:NULL];
/* append unknown keycodes to the paste since we can't type them */
if (part == 0 || keyCode == kMPUnknownKeyCode) {
@@ -394,7 +394,7 @@ static CGKeyCode kMPFunctionKeyCodes[] = { kVK_F1, kVK_F2, kVK_F3, kVK_F4, kVK_F
}
- (void)sendPasteKeyCode {
CGKeyCode keyCode = [MPKeyMapper keyCodeForCharacter:@"V"];
CGKeyCode keyCode = [MPKeyMapper keyCodeForCharacter:@"v" modifier:NULL];
if(keyCode == kMPUnknownKeyCode) {
return; // We did not find a mapping for "V"
}

View File

@@ -32,11 +32,15 @@ static CGEventFlags _updateModifierMaskForCurrentDefaults(CGEventFlags modifiers
}
- (instancetype)initWithModifierMask:(CGEventFlags)modiferMask character:(NSString *)character {
CGKeyCode mappedKey = [MPKeyMapper keyCodeForCharacter:character];
CGEventFlags modifiers;
CGKeyCode mappedKey = [MPKeyMapper keyCodeForCharacter:character modifier:&modifiers];
if(mappedKey == kMPUnknownKeyCode) {
self = nil;
}
else {
if(modifiers && (modiferMask != modifiers)) {
NSLog(@"Supplied modifiers for character %@ do not match required modifiers", character);
}
self = [self initWithModifierMask:modiferMask keyCode:mappedKey];
}
return self;
@@ -60,9 +64,4 @@ static CGEventFlags _updateModifierMaskForCurrentDefaults(CGEventFlags modifiers
//return ([self _transformKeyCode] != kMPUnknownKeyCode);
}
- (CGKeyCode)_transformKeyCode {
NSString *key = [MPKeyMapper stringForKey:self.keyCode];
return [MPKeyMapper keyCodeForCharacter:key];
}
@end

View File

@@ -16,16 +16,19 @@ FOUNDATION_EXTERN uint16_t const kMPUnknownKeyCode;
* Retrieves the string representation with the current keyboard mapping for the keycode
*
* @param keyCode The virtual keycode to be pressed
* @param modifier State of modifier flags being pressed with the key
* @return NSString containing the current mapping for the keyCode
*/
+ (NSString *)stringForKey:(CGKeyCode)keyCode modifier:(CGEventFlags)modifier;
+ (NSString *)stringForKey:(CGKeyCode)keyCode;
/**
* Determines the keyCode (if possible) for the character
* Determines the keyCode (if possible) for the character. Modifiers might be needed
*
* @param character NSString with a single character to be transformed
* @param modifier pointer to a modifer structure to return the modifer to use with the key code for the character
* @return virtual Keycode for the supplied string. If none is found, kMPUnkonwKeyCode is returned
*/
+ (CGKeyCode)keyCodeForCharacter:(NSString *)character;
+ (CGKeyCode)keyCodeForCharacter:(NSString *)character modifier:(CGEventFlags *)modifer;
@end

View File

@@ -28,9 +28,13 @@ uint16_t const kMPUnknownKeyCode = UINT16_MAX;
@implementation MPKeyMapper
+ (NSString *)stringForKey:(CGKeyCode)keyCode {
return [self stringForKey:keyCode modifier:0];
}
+ (NSString *)stringForKey:(CGKeyCode)keyCode modifier:(CGEventFlags)modifier {
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef layoutData = TISGetInputSourceProperty(currentKeyboard,kTISPropertyUnicodeKeyLayoutData);
if(!layoutData) {
currentKeyboard = TISCopyCurrentASCIICapableKeyboardLayoutInputSource();
layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
@@ -43,21 +47,36 @@ uint16_t const kMPUnknownKeyCode = UINT16_MAX;
UniChar chars[4];
UniCharCount realLength;
UCKeyTranslate(keyboardLayout,
keyCode,
kUCKeyActionDisplay,
0,
LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit,
&keysDown,
sizeof(chars) / sizeof(chars[0]),
&realLength,
chars);
uint32_t modifierKeyState = 0;
if(modifier & kCGEventFlagMaskCommand) {
modifierKeyState |= ((cmdKey >> 8 ) & 0xFF);
}
if(modifier & kCGEventFlagMaskShift) {
modifierKeyState |= ((shiftKey >> 8) & 0xFF);
}
if(modifier & kCGEventFlagMaskAlternate) {
modifierKeyState |= ((optionKey >> 8) & 0xFF);
}
if(modifier & kCGEventFlagMaskControl) {
modifierKeyState |= ((controlKey >> 8) & 0xFF);
}
OSStatus success = 0;
success = UCKeyTranslate(keyboardLayout,
keyCode,
kUCKeyActionDisplay,
modifierKeyState,
LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit,
&keysDown,
sizeof(chars) / sizeof(chars[0]),
&realLength,
chars);
return CFBridgingRelease(CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1));
}
+ (CGKeyCode)keyCodeForCharacter:(NSString *)character {
+ (CGKeyCode)keyCodeForCharacter:(NSString *)character modifier:(CGEventFlags *)modifer {
static NSMutableDictionary *keyboardCodeDictionary;
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
@@ -70,26 +89,38 @@ uint16_t const kMPUnknownKeyCode = UINT16_MAX;
keyboardCodeDictionary = [[NSMutableDictionary alloc] initWithCapacity:2];
}
/* search for current character mapping */
NSDictionary<NSString *, NSNumber *> *charToCodeDict = keyboardCodeDictionary[localizedName];
NSDictionary<NSString *, NSArray<NSNumber *> *> *charToCodeDict = keyboardCodeDictionary[localizedName];
if(nil == charToCodeDict) {
/* Add mapping */
NSMutableDictionary *tempCharToCodeDict = [[NSMutableDictionary alloc] initWithCapacity:128];
/* Generate table of keycodes and characters. */
/* Loop through every keycode (0 - 127) to find its current mapping. */
/* Loop throuhg every control key compbination for every virutal key */
for(CGKeyCode keyCode = 0; keyCode < 128; ++keyCode) {
NSString *string = [self stringForKey:keyCode];
if(string != nil) {
tempCharToCodeDict[string] = @(keyCode);
uint64_t modifiers[] = { 0, kCGEventFlagMaskShift, kCGEventFlagMaskAlternate, kCGEventFlagMaskControl, kCGEventFlagMaskShift | kCGEventFlagMaskAlternate, kCGEventFlagMaskShift | kCGEventFlagMaskControl, kCGEventFlagMaskShift | kCGEventFlagMaskAlternate | kCGEventFlagMaskControl };
for(int modifierIndex = 0; modifierIndex < sizeof(modifiers); modifierIndex++) {
NSString *string = [self stringForKey:keyCode modifier:modifiers[modifierIndex]];
if(string != nil && string.length > 0 && nil == tempCharToCodeDict[string]) {
tempCharToCodeDict[string] = @[@(keyCode), @(modifiers[modifierIndex])];
}
}
}
charToCodeDict = [[NSDictionary alloc] initWithDictionary:tempCharToCodeDict];
keyboardCodeDictionary[localizedName] = charToCodeDict;
}
NSString *singleCharacter = [character substringToIndex:1].lowercaseString;
if(charToCodeDict[singleCharacter]) {
return charToCodeDict[singleCharacter].integerValue;
NSArray<NSNumber *> *result = charToCodeDict[singleCharacter];
if(result) {
if(modifer) {
*modifer = result[1].unsignedIntegerValue;
}
/* false positive when no modifier was supplied! */
return result[0].integerValue;
}
if(modifer) {
*modifer = 0;
}
return kMPUnknownKeyCode;
}