14

I'm writing an app where I need to simulate key press events on a Mac, given a code that represents each key. It seems I need to use the CGEventCreateKeyboardEvent function to create the event. The problem is that this function needs a Mac keycode, and what I have is a code that represents the specific key. So, for example, I receive:

KEY_CODE_SHIFT or KEY_CODE_A - these are both numeric constants defined somewhere.

I need to take these constants and turn them into CGKeyCode values.

My current attempt uses code similar to this SO question. The problem is that it only works for printable characters. If all else fails, I'm not above hard coding the conversion, but that would mean that I'd need a table of possible CGKeyCode values, which I have not yet been able to find.

Any ideas?

Community
  • 1
  • 1
Thomi
  • 11,647
  • 13
  • 72
  • 110

2 Answers2

26

Here's code to simulate a Cmd-S action:

CGKeyCode inputKeyCode = kVK_ANSI_S;
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
CGEventRef saveCommandDown = CGEventCreateKeyboardEvent(source, inputKeyCode, YES);
CGEventSetFlags(saveCommandDown, kCGEventFlagMaskCommand);
CGEventRef saveCommandUp = CGEventCreateKeyboardEvent(source, inputKeyCode, NO);

CGEventPost(kCGAnnotatedSessionEventTap, saveCommandDown);
CGEventPost(kCGAnnotatedSessionEventTap, saveCommandUp);

CFRelease(saveCommandUp);
CFRelease(saveCommandDown);
CFRelease(source);

A CGKeyCode is nothing more than an unsigned integer:

typedef uint16_t CGKeyCode;  //From CGRemoteOperation.h

Your real issue will be turning a character (probably an NSString) into a keycode. Fortunately, the Shortcut Recorder project has code that will do just that in the SRKeyCodeTransformer.m file. It's great for transforming a string to a keycode and back again.

pkamb
  • 33,281
  • 23
  • 160
  • 191
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • So in this example then, the `CGKeyCode` of `1` is the code for S? Also, would this work for just a foreground app, or if it was running in the background, would it work across the entire session? Thanks – joec Jul 08 '10 at 17:30
  • So, say my app was running in the background (just as a service) and i had Photoshop in front, i could simulate a key press, and it would be seen in Photoshop? Thanks – joec Jul 08 '10 at 20:10
  • @joec yes, that's what would happen – Dave DeLong Jul 08 '10 at 20:34
  • @Dave, do you have code that utilises SRKeyCodeTransformer? I have added the ShortcutRecorder framework to my project, but unsure really where to go from here. Thanks. – joec Jul 09 '10 at 12:28
  • @Dave. Thx for your code. I use your code and it seems to work perfect on most of apps except finder. From this [link](http://stackoverflow.com/questions/6186317/why-copy-and-paste-in-finder-doesnt-work-when-i-use-registereventhotkey-cocoa), I try your code and it doesn't work on finder. Let's say I press cmd+C and finder does not copy selected files. – Chanok Jun 02 '11 at 09:16
  • 3
    You can use the kVK_??? constants instead of plain numbers. Thanks for the snippet. It really helped. – Gonzalo Larralde Jul 04 '11 at 15:34
  • Anyone have any examples which use ARC? I can't get the shortcut recorder code to compile in a ARC project. – Gourneau Oct 26 '12 at 05:35
  • Instead of using 1 use **kVK_ANSI_S** and replace S with any key you want – Josh Bernfeld Sep 02 '15 at 20:39
5

Just in case some one needs a Swift version:

XCode 7.3 and Swift 2.2:

let event1 = CGEventCreateKeyboardEvent(nil, 0x09, true); // cmd-v down
CGEventSetFlags(event1, CGEventFlags.MaskCommand);
CGEventPost(CGEventTapLocation.CGHIDEventTap, event1);

let event2 = CGEventCreateKeyboardEvent(nil, 0x09, false); // cmd-v up
CGEventSetFlags(event2, CGEventFlags.MaskCommand);
CGEventPost(CGEventTapLocation.CGHIDEventTap, event2);

Code above simulates CMD-V pressed then released(AKA: paste).

Tyler Liu
  • 19,552
  • 11
  • 100
  • 84