After my adventures in faking iOS touch events, I assumed I was looking at more of the same slow process of reverse-engineering the right values to pass into a GSEvent object.
A curious thing happened, though.
GSEvent.h defines a GSKeyInfo object, and there are even functions with helpful-sounding names like
GSEventCreateKeyEvent(), but actually tapping a letter on the on-screen keyboard doesn’t cause your application to receive a GraphicsServices keyboard event. It just receives normal touch events, which get directed to the application’s UIKeyboard object. From there, something inside the black box of UIKeyboard causes the actual keypress to happen.
(As an aside, I’d be willing to wager that the key event objects referenced in
GSEvent.h are generated when you have a hardware keyboard attached to your iOS device.)
After diving into the UIKeyboard private headers, I found something interesting.
Bingo! If you want to create a synthetic keypress when there is already a keyboard visible on-screen, all you need to do is call a few private methods on it. I opened up a category interface to expose the necessary methods.
Using those two guys, it’s easy to get a pointer to the currently-visible keyboard and tell it to do its thing.
Worth noting: you would expect
_typeCharacter:(...) to take in a single character. However, you’ll notice it accepts an NSString rather than a char or a UniChar. It does in fact expect the string you give it to match up to a single keyboard key. There’s probably a good reason for this, but for now we’ll just have to write it off as an oddity of the private API.
And there you have it, programmatically-created keypress events!
The standard disclaimer applies: if you want to submit your app to Apple for release on the App Store, don’t do this. It’ll get rejected.