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

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!



CCR.VirtualKeying – virtual keystroke interface for Windows and OS X

$
0
0

I’ve just added to GitHub a little virtual keystroke interface for Windows and OS X – on the former it wraps the SendInput API, on the latter the CGEvent functions:

https://github.com/chrisrolliston/CCR.VirtualKeying

Virtually typing some text into the active window is a one-liner:

TVirtualKeySequence.Execute('¡Hola!');

Alternatively, you can build up a sequence of keystrokes to perform by working with an explicit IVirtualKeySequence instance:

var
  Sequence: IVirtualKeySequence;
begin
  Sequence := TVirtualKeySequence.Create;
  Sequence.AddKeyPresses('Привет!');
  {$IFDEF MACOS}
  Sequence.Add(vkA, [ssCommand], [keDown, keUp]);
  {$ELSE}
  Sequence.Add(vkA, [ssCtrl], [keDown, keUp]);
  {$ENDIF}
  Sequence.Execute;

For more on the available methods, check out the readme at the above link. The repository also includes a simple demo in FMX and VCL forms (code is essentially the same).


Viewing all 62 articles
Browse latest View live