Quantcast
Channel: Delphi Haven
Viewing all articles
Browse latest Browse all 62

Sending virtual keystrokes on OS X

$
0
0

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,

  1. Call CGEventSourceCreate to allocate a CGEventSourceRef.
  2. 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.
  3. 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.
  4. Actually perform the event by passing the CGEventRef to CGEventPost, using kCGHIDEventTap for the first parameter.
  5. 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!



Viewing all articles
Browse latest Browse all 62

Trending Articles