Going through my comments backlog I found a question asking how to send virtual keystrokes on OS X. Short answer is to use the CGEvent functions in MacApi.CoreGraphics – in a nutshell,
- Call CGEventSourceCreate to allocate a CGEventSourceRef.
- For each keystroke, create a CGEventRef by calling CGEventCreateKeyboardEvent; this takes the CGEventSourceRef just allocated plus an OS X virtual key code. For possible values of the latter, see the MacApi.KeyCodes unit, assuming you have a recent Delphi version, otherwise scan the source for KEY_xxx values. Also, note that you will need separate events for first pressing a key down, then unpressing it.
- If required, call CGEventSetFlags on a given CGEventRef to assign a modifier key (alt/shift/ctrl/command); in the case of a character, you’ll typically want to call CGEventKeyboardSetUnicodeString as well rather than messing about trying to figure out the correct key code.
- Actually perform the event by passing the CGEventRef to CGEventPost, using kCGHIDEventTap for the first parameter.
- Clean up by passing each CGEventRef then the CGEventSourceRef to CFRelease.
The following follows these steps to generate key down and key up events for a Cmd+L shortcut:
uses System.SysUtils, MacApi.CocoaTypes, MacApi.CoreFoundation, MacApi.CoreGraphics, MacApi.KeyCodes; procedure PressCmdLShortcut; var EventSourceRef: CGEventSourceRef; KeyDownRef, KeyUpRef: CGEventRef; begin KeyDownRef := nil; KeyUpRef := nil; EventSourceRef := CGEventSourceCreate(kCGEventSourceStateHIDSystemState); if EventSourceRef = nil then RaiseLastOSError; try KeyDownRef := CGEventCreateKeyboardEvent(EventSourceRef, KEY_L, 1); //1 = key down if KeyDownRef = nil then RaiseLastOSError; CGEventSetFlags(KeyDownRef, kCGEventFlagMaskCommand); KeyUpRef := CGEventCreateKeyboardEvent(EventSourceRef, KEY_L, 0); //0 = key up if KeyUpRef = nil then RaiseLastOSError; CGEventSetFlags(KeyUpRef, kCGEventFlagMaskCommand); CGEventPost(kCGHIDEventTap, KeyDownRef); CGEventPost(kCGHIDEventTap, KeyUpRef); finally if KeyDownRef <> nil then CFRelease(KeyDownRef); if KeyUpRef <> nil then CFRelease(KeyUpRef); CFRelease(EventSourceRef); end; end;
Alternatively, you can use a little cross platform (Mac/Windows) wrapper interface I’ve written… more on which in my next post!
