Terminality
Terminality

Reputation: 819

Cocoa/Objective-C on macOS - handle accented characters via keyDown:

I have an application that processes keystrokes via keyDown:. This works well so far, with the exception of two problems (the other one is here).

The problem in this question is about accented characters, i.e. letters that are combined with a dead char, e.g. á

I'm handling keyDown: fine so far (accessing the characters through [nsevent characters]). It's just that I never get accented characters.

I get a keyDown: event for the accent ´ where [nsevent characters] is zero length, but essentially I guess I don't know what to do with it.

The next characters in keyDown: is the unaccented version, e.g. an /a/.

I also know about selectNextKeyView: but ideally I am looking for a way to get the system to pass the combination to keyDown: for normal handling (incidentally keyUp: is called correctly for it).

So essentially my question is: Why does my handleKeyEvent: never get an á through [nsevent characters], only an /a/?

Or how should I access the characters otherwise?

        -(void)keyDown:(NSEvent *)nsevent
        {
            BOOL didit= [self handleKeyEvent:nsevent isRaw:FALSE isUp:FALSE];
            if (!didit)
                [super keyDown:nsevent];
        }


        -(void)keyUp:(NSEvent *)nsevent
        {
            BOOL didit= [self handleKeyEvent:nsevent isRaw:FALSE isUp:TRUE];
            if (!didit)
                [super keyUp:nsevent];
        }

Upvotes: 1

Views: 559

Answers (1)

Terminality
Terminality

Reputation: 819

Answering my own question.

Courtesy of questions already answered (see the two links near the top of the code), I was aböle to solve this via unicode routines UCKeyTranslate().

The function below requires a persistent UInt32 to store the deadKeyState across calls, but that's all it took.

//-------------------------------------------------------------------------
//  translate keyDown to true unichar via inputlayout
//-------------------------------------------------------------------------
NSString *
translateInputForKeyDown(NSEvent *event, UInt32 *deadKeyState) const
{
    // http://stackoverflow.com/questions/12547007/convert-key-code-into-key-equivalent-string
    // http://stackoverflow.com/questions/8263618/convert-virtual-key-code-to-unicode-string

    const size_t unicodeStringLength = 4;
    UniChar unicodeString[unicodeStringLength]= { 0, };
    UniCharCount reallength= 0;
    NSString *nsstring= nil;

    TISInputSourceRef fkis= TISCopyCurrentKeyboardInputSource();
    if (fkis) {
        CFDataRef cflayoutdata= (CFDataRef)TISGetInputSourceProperty(fkis, kTISPropertyUnicodeKeyLayoutData);
        const UCKeyboardLayout *keyboardlayout= (const UCKeyboardLayout *)CFDataGetBytePtr(cflayoutdata);
        CGEventFlags flags = [event modifierFlags];
        UInt32 keymodifiers = (flags >> 16) & 0xFF;

        UCKeyTranslate(keyboardlayout,
                            [event keyCode], kUCKeyActionDown, keymodifiers,
                            LMGetKbdType(), 0,
                            deadKeyState,
                            unicodeStringLength, &reallength, unicodeString);
        ::CFRelease(fkis);
    }


    if (reallength>0) {
        nsstring= (NSString *)CFStringCreateWithCharacters(kCFAllocatorDefault, unicodeString, reallength);
    }

    return nsstring;
}

Upvotes: 2

Related Questions