Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to tell the difference between a user-tapped keyboard event and a generated one?

I've installed a keyboard hook:

CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {

Basically I want to take the user's keyboard taps, eat the input, and post my own input instead.

So if he taps "g" I might want to post "foo" to the textfield.

I'm writing to the textfield with CGEventPost and CGEventSetUnicodeString as found here: http://www.mail-archive.com/[email protected]/msg23343.html

The problem is that each of my programmatically entered characters is hitting the keyboard hook. So I can't return NULL in the keyboard hook to block the user input... that blocks all the program's input as well!

I differentiated them on the Windows side in C# with the 'injected' flag, see my question a year ago here: How do I use low-level 8 bit flags as conditionals?

Looking for something similar in Objective-C.

like image 815
ck_ Avatar asked Apr 30 '11 09:04

ck_


1 Answers

Take a look at the comments in CGEventSource.h. It's a little bit easier to put the information together than using the Event Services Reference. The long, but more correct, way around looks like creating an event source (which is subject to memory management rules; you need to CFRelease it if you're done using it before program termination):

myEventSource = CGEventSourceCreate(kCGEventSourceStatePrivate);

This will create your own private event source with a unique ID; you then indicate that events you create came from there:

CGEventRef myKeyboardEvent = CGEventCreateKeyboardEvent(myEventSource, 
                                                        keyCode, true);

When an event comes in, check to see if it's from yourself:

 if( (CGEventGetType(newEvent) == kCGEventKeyDown) &&
     (CGEventGetIntegerValueField(newEvent, kCGEventSourceStateID) == CGEventSourceGetSourceStateID(myEventSource) ) {

There's also a user data field for the source that lets you pass around an arbitrary 64 bits, should you need to.

The quick and dirty way would be to try picking an event field that isn't likely to be a meaningful value for a keyboard event, like kCGMouseEventPressure and turn it into a signature:

CGEventSetIntegerValueField(myKeyboardEvent, 
                            kCGMouseEventPressure, 
                            0xFEEDFACE);
// The field is an int_64 so you could make the sig longer
like image 195
jscs Avatar answered Sep 19 '22 14:09

jscs