Search code examples
macosquartz-graphicskeypresscgeventtap

How do I use CGEventKeyboardSetUnicodeString with multiple characters?


I'm trying to use event taps to create an OS X program that will listen for Yiddish typed in transliteration and post the result in Hebrew characters. I made a very short program to test one things I'd have to do: http://pastie.org/791398

As is, the program successfully replaces every typed 'q' with 'w':

if(inputString[0] == 'q') { inputString[0] = 'w'; }

But how does one post a string of more than one character? For instance, if someone types 'sh' you'd presumably have to post a backspace (to delete the character that was posted for 's' alone) and then post the character that corresponds to 'sh'. However, this code results in only a backspace being posted:

else if(inputString[0] == 'm') { inputString[0] = '\b'; inputString[1] = 'n'; }

I apologize if these are basic questions; I have read all the documentation I could find, but I might not have understood it all. It's also possible that I'm going about this entirely the wrong way.


Solution

  • Ideally you should be using an input method instead of a program with event taps, most likely using Input Method Kit if you don't need to support pre-10.5. Using event taps for this purpose is inherently a bad idea because the user can change where he/she is typing with the mouse as well as the keyboard. So if the user typed a "s" in one text field followed by a "h" in another, you wouldn't be able to tell the difference.

    That said, here's a direct answer to your question.

    The string is length-counted, so you can't just provide the incoming length (1); the second character will be ignored. However, most applications also don't like to get more than a single character per event, so they'll just discard the remaining characters. (Terminal is a notable exception.)

    So what you can do is simply post a second event with the second character in it.

    else if(inputString[0] == 'm') {
      inputString[0] = 'n';
      CGEventKeyboardSetUnicodeString(event, 1, inputString);
      CGEventPost(kCGSessionEventTap, event);
      inputString[0] = '\b';
    }
    

    In the general case (simulating > 2 keypresses) you'll need to create an event for each character you want to insert. This mailing list post includes a simple example.