Question

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.

Was it helpful?

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.

OTHER TIPS

This is how I send a string to the first responder ( foreground application )

// 1 - Get the string length in bytes.        
NSUInteger l = [string lengthOfBytesUsingEncoding:NSUTF16StringEncoding];

// 2 - Get bytes for unicode characters
UniChar *uc = malloc(l);
[string getBytes:uc maxLength:l usedLength:NULL encoding:NSUTF16StringEncoding options:0 range:NSMakeRange(0, l) remainingRange:NULL];

// 3 - create an empty tap event, and set unicode string
CGEventRef tap = CGEventCreateKeyboardEvent(NULL,0, YES);
CGEventKeyboardSetUnicodeString(tap, string.length, uc);

// 4 - Send event and tear down
CGEventPost(kCGSessionEventTap, tap);
CFRelease(tap);
free(uc);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top