macoslazarusfreepascal

OSX Keyboard Event Taps with Lazarus / FreePascal


I'm trying to create an OSX keyboard event tap using Lazarus / FreePascal. Lazarus is set to defaults from the install - 32bit and Carbon widget set.

The code setting the tap looks like:

eventMask := (1 shl kCGEventKeyDown) or (1 shl kCGEventKeyUp);

KeyboardTap := CGEventTapCreate( KCGSessionEventTap, kCGHeadInsertEventTap, 0, eventMask, @KeyboardEventTapCB, nil);
if KeyboardTap <> nil then
begin
   RunLoopSource := CFMachPortCreateRunLoopSource( kCFAllocatorDefault, KeyboardTap, 0);
   CFRunLoopAddSource(CFRunLoopGetCurrent(), RunLoopSource, kCFRunLoopCommonModes);
   CGEventTapEnable( KeyboardTap, 1);
   result := true;
end

And the callback looks like:

function KeyboardEventTapCB(proxy: CGEventTapProxy; eType: CGEventType; e: CGEventRef; userInfo: UnivPtr): CGEventRef;
var
   keycode: CGKeyCode;
begin
   keycode := CGEventGetIntegerValueField( e, kCGKeyboardEventKeycode);
   result := nil;
end;

I'm having two problems.

The first is that the CGEventRef being passed into the callback looks like its actually the CGEventType value. That is, the 'e' being passed into CGEventGetIntegerValue() holds the value that should be in eType, the CGEventType.

The other is that if I attempt to return the event in the callback, it causes and AV.

So the question is... am I creating the tap correctly (I am not terribly familiar with OSX's internals), and if so, are fpc's OSX units for this functionality correct?


Solution

  • Pascal and C have different calling conventions. Since you're passing your KeyboardEventTapCB into a function that's going to call it using C calling conventions, you need to make sure it is compiled to expect C calling conventions.

    Some web searching suggests that you can add cdecl; on the end of the function declaration. If not that, try surrounding KeyboardEventTapCB with:

    ${CALLING cdecl}
    

    and

    ${CALLING default}