Search code examples
objective-cxcodemacoskeyboardcgeventtap

CGEventRef KeyHandler - Xcode - Mac


So I have an app that when you press the numbers on your keyboard on top, it normally types the symbols. But with the app it types the numbers.

But if I run it in xcode, everything works fine, but when i open the app outside of xcode it doesn't work.

I have the newest update of mac os x and xcode.

Video:

https://youtu.be/67hRybEmJJY

Can anybody help me please?

CGEventRef KeyHandler(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{
    UniCharCount actualStringLength;
    UniCharCount maxStringLength = 1;
    UniChar chars[3];

CGEventKeyboardGetUnicodeString(event, maxStringLength, &actualStringLength, chars);


NSString *rusLetters1 = @"&";
if (chars[0] == [rusLetters1 characterAtIndex:0]) {
    chars[0] = '1';
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters2 = @"é";
if (chars[0] == [rusLetters2 characterAtIndex:0]) {
    chars[0] = '2';
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters3 = @"\"";
if (chars[0] == [rusLetters3 characterAtIndex:0]) {
    chars[0] = '3';
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters4 = @"'";
if (chars[0] == [rusLetters4 characterAtIndex:0]) {
    chars[0] = '4';
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters5 = @"(";
if (chars[0] == [rusLetters5 characterAtIndex:0]) {
    chars[0] = '5';
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters6 = @"§";
if (chars[0] == [rusLetters6 characterAtIndex:0]) {
    chars[0] = '6';
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters7 = @"è";
if (chars[0] == [rusLetters7 characterAtIndex:0]) {
    chars[0] = '7';
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters8 = @"!";
if (chars[0] == [rusLetters8 characterAtIndex:0]) {
    chars[0] = '8';
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters9 = @"ç";
if (chars[0] == [rusLetters9 characterAtIndex:0]) {
    chars[0] = '9';
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters0 = @"à";
if (chars[0] == [rusLetters0 characterAtIndex:0]) {
    chars[0] = '0';
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}

//_________________________________________________________________________________________________________________

NSString *rusLetters11 = @"&";
if (chars[0] == '1') {
    chars[0] = [rusLetters11 characterAtIndex:0];
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters12 = @"é";
if (chars[0] == '2') {
    chars[0] = [rusLetters12 characterAtIndex:0];
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters13 = @"\"";
if (chars[0] == '3') {
    chars[0] = [rusLetters13 characterAtIndex:0];
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters14 = @"'";
if (chars[0] == '4') {
    chars[0] = [rusLetters14 characterAtIndex:0];
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters15 = @"(";
if (chars[0] == '5') {
    chars[0] = [rusLetters15 characterAtIndex:0];
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters16 = @"§";
if (chars[0] == '6') {
    chars[0] = [rusLetters16 characterAtIndex:0];
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters17 = @"è";
if (chars[0] == '7') {
    chars[0] = [rusLetters17 characterAtIndex:0];
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters18 = @"!";
if (chars[0] == '8') {
    chars[0] = [rusLetters18 characterAtIndex:0];
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters19 = @"ç";
if (chars[0] == '9') {
    chars[0] = [rusLetters19 characterAtIndex:0];
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}
NSString *rusLetters10 = @"à";
if (chars[0] == '0') {
    chars[0] = [rusLetters10 characterAtIndex:0];
    CGEventKeyboardSetUnicodeString(event, 1, chars);
    return event;
}

return event;
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    CFMachPortRef      eventTap;
    CGEventMask        eventMask;
    CFRunLoopSourceRef runLoopSource;

    eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, eventMask, KeyHandler, NULL);

    if (!eventTap) {
        exit(1);
    }

    runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
    CGEventTapEnable(eventTap, true);
    CFRunLoopRun();
}

Solution

  • Here's what I would do. There are many ways to calculate the modified character, this is one of them.

    #import "AppDelegate.h"
    
    @interface AppDelegate ()
    
    @property (assign) CFMachPortRef myEventTap;
    @property (assign) CFRunLoopSourceRef myRunLoopSource;
    
    @end
    
    @implementation AppDelegate
    
    CGEventRef KeyHandler(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
    {
        // don't modify keys on the numeric keypad
        CGEventFlags flags = CGEventGetFlags(event);
        if (flags & kCGEventFlagMaskNumericPad)
            return event;
    
        // get the typed character
        UniCharCount actualStringLength;
        UniChar chars[3];
        CGEventKeyboardGetUnicodeString(event, 3, &actualStringLength, chars);
    
        // uncomment this line to log the typed character, the modifier flags (Shift, Option, etc.) and the key code (number of the key on the keyboard)
        NSLog(@"%C %llX %lld", chars[0], flags, CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode));
    
        if (actualStringLength == 1) {
            // map the character from string1 to string2 and vice versa
            NSString *string1 = @"&é\"'(§è!çà";
            NSString *string2 = @"1234567890";
            NSString *typedString = [NSString stringWithCharacters:chars length:1];
            // find the index of the typed character in string1
            NSRange range = [string1 rangeOfString:typedString];
            if (range.location != NSNotFound)
                // get the character in string2 at the same index
                chars[0] = [string2 characterAtIndex:range.location];
            else {
                // find the index of the typed character in string2
                range = [string2 rangeOfString:typedString];
                if (range.location != NSNotFound)
                    // get the character in string1 at the same index
                    chars[0] = [string1 characterAtIndex:range.location];
            }
            // if the character was found, replace the character in the event
            if (range.location != NSNotFound)
                CGEventKeyboardSetUnicodeString(event, 1, chars);
        }
        return event;
    }
    
    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
        // create an event tap, we want the key down and key up events
        CGEventMask eventMask = CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp);
        self.myEventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, eventMask, KeyHandler, NULL);
        if (self.myEventTap) {
            // create a runloop source
            self.myRunLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.myEventTap, 0);
            // add it to the current run loop
            CFRunLoopAddSource(CFRunLoopGetCurrent(), self.myRunLoopSource, kCFRunLoopCommonModes);
        }
    }
    
    - (void)applicationWillTerminate:(NSNotification *)aNotification {
        // remove the event tap
        if (self.myRunLoopSource) {
            CFRunLoopSourceInvalidate(self.myRunLoopSource);
            CFRelease(self.myRunLoopSource);
        }
        if (self.myEventTap)
            CFRelease(self.myEventTap);
    }
    
    @end