Toffee/Mercury: Carbon InstallEventHandler accepts EventHandlerUPP, but the callback is never invoked

Hi.
I am building a macOS Cocoa application with RemObjects Elements Mercury
(Toffee target). I am trying to register a Carbon global hot key using
RegisterEventHotKey and receive kEventHotKeyPressed through
InstallEventHandler.

Both calls return noErr, and the hot-key registration remains alive. However,
pressing Option+Command+Z never enters the event handler: even the first
NSLog in the callback is not printed.

This is the relevant Mercury code:

Imports Carbon.HIToolbox
Imports Foundation
Imports RemObjects.Elements.System

Public Function handleMacGlobalHotKeyEvent(
  nextHandler As EventHandlerCallRef,
  eventReference As EventRef,
  context As Ptr(Of Void)) As OSStatus

  NSLog("Carbon hot-key callback entered")
  MacGlobalHotKey.dispatchHotKeyEvent()
  Return noErr
End Function

Private _eventHandler As EventHandlerRef
Private _eventHandlerCallback As EventHandlerUPP
Private _hotKey As EventHotKeyRef

Public Function registerHotKey() As Boolean
  Dim eventType As EventTypeSpec
  eventType.eventClass = kEventClassKeyboard
  eventType.eventKind = kEventHotKeyPressed

  Dim eventTarget As EventTargetRef = GetApplicationEventTarget()

  _eventHandlerCallback = AddressOf Global.MacApp.handleMacGlobalHotKeyEvent

  Dim installStatus As OSStatus = InstallEventHandler(
    eventTarget,
    _eventHandlerCallback,
    1,
    AddressOf eventType,
    Null,
    AddressOf _eventHandler)

  NSLog("InstallEventHandler status %d", installStatus)

  Dim identifier As EventHotKeyID
  identifier.signature = &H5A4D524B
  identifier.id = 1

  Dim registerStatus As OSStatus = RegisterEventHotKey(
    6, ' Z
    optionKey Or cmdKey,
    identifier,
    eventTarget,
    0,
    AddressOf _hotKey)

  NSLog("RegisterEventHotKey status %d", registerStatus)
  Return installStatus = noErr AndAlso registerStatus = noErr
End Function

The native Carbon declaration is:

typedef OSStatus (*EventHandlerProcPtr)(
    EventHandlerCallRef, EventRef, void *);
typedef EventHandlerProcPtr EventHandlerUPP;

On modern macOS, NewEventHandlerUPP(proc) is only a cast macro and
DisposeEventHandlerUPP is a no-op. Therefore I expected assigning
AddressOf directly to the imported EventHandlerUPP type to be equivalent
to the C usage.

Could someone confirm the correct Mercury/Toffee pattern for this API?

Specifically:

  1. Is EventHandlerUPP imported as a raw C function-pointer type?
  2. Does AddressOf for a Mercury top-level function produce an ABI-compatible,
    stable C callback pointer for InstallEventHandler?
  3. If not, should I declare a <FunctionPointer> delegate explicitly, use a
    different attribute/calling convention, or add a custom bridge?
  4. Is there a recommended way to inspect the generated Objective-C/C output
    for this conversion?

I keep both the returned EventHandlerRef and the callback value alive until
I call RemoveEventHandler, so this should not be a lifetime issue.

Environment:

  • Elements version: Fire(with Elements:13.0.0.3095)
  • macOS version / CPU architecture: 26.0+

Thank you.

Update: After further investigation, it may not be an issue with FunctionPointer itself, and we currently believe the likelihood is relatively low. More precisely, the immediate problem I encountered is that Carbon events are not being received, so the keyboard callback is never triggered.

Thanks for the detailed report.

Your EventHandlerUPP / AddressOf reasoning is broadly the direction we would expect on current macOS: EventHandlerUPP is effectively a C callback pointer, and keeping both the handler reference and callback alive is the right thing to do.

Given the update, though, it sounds more likely that the immediate problem is that the Carbon event is never reaching the application event target, rather than that the Mercury callback conversion itself is failing.

A useful next isolation step would be to test the same registration with a minimal native Objective-C/C Cocoa application using the same:

  • GetApplicationEventTarget()
  • InstallEventHandler
  • RegisterEventHotKey
  • key code/modifier combination

If that also does not receive kEventHotKeyPressed on the affected macOS version, the issue is outside the Mercury callback conversion. If the native test works but the Mercury version does not, we can then focus specifically on the generated callback bridge and calling convention.

We will also review the imported Carbon declarations and the generated output for this case. In particular, we want to confirm that EventHandlerUPP is imported as the expected raw C function-pointer type and that the generated callback uses the correct ABI.

For newer code, a Quartz event tap may also be a more supportable long-term approach than Carbon Event Manager APIs, but first we should establish whether this is a Carbon event-delivery issue or an Elements interop issue.

Thanks. I have now performed some additional isolation tests.

The current findings are:

  1. The generated callback pointer is most likely valid. So far, the tests do not indicate that the EventHandlerUPP value itself, or the conversion from AddressOf, is the problem.

  2. In the failing Elements implementation, the Carbon event does not appear to reach the application at all. In other words, the callback is not merely failing when invoked—the event does not seem to be delivered to it in the first place.

  3. An equivalent native Objective-C implementation works correctly on the same system.

  4. An equivalent .NET (not hydrogene) implementation using Objective-C/Swift interop also works correctly.

  5. This does not appear to be Mercury-specific. I tested an equivalent Silver/Toffee implementation, and it seems to exhibit the same behavior.

Based on these results, the issue is probably not specific to Mercury’s AddressOf syntax or callback conversion. It appears more likely to be somewhere in the Toffee/Elements interop or code-generation path shared by multiple Elements languages.

Thank you — that is an excellent isolation result.

Since the native Objective-C version works on the same system, while both Mercury/Toffee and Silver/Toffee exhibit the failure, this no longer looks like a Mercury AddressOf or EventHandlerUPP conversion issue.

It appears more likely to be in the shared Toffee runtime/code-generation path — for example, how the application event target or Carbon event delivery is integrated into a generated Cocoa application.

We will investigate this as an Elements/Toffee issue.

If you can provide a complete small test case, that would help us reproduce and investigate this much faster. Ideally, please include the exact target type and the smallest project that demonstrates:

  • InstallEventHandler returns noErr
  • RegisterEventHotKey returns noErr
  • the native equivalent receives kEventHotKeyPressed
  • the Toffee build does not

Thank you again for testing this across both Mercury and Silver; that comparison is especially useful.

Quick Q: is this Toffee or Island/Toffeev2?

Reproduced.

Fixed. Unfortrunately this needs new SDK imports; i’ll see if i can reimport Xcode 26.6 and Xcode 27 SDKs today or tomorrow.

Once thpre are ut, yu mighy need to delete the relevant old SDKs from ‘~/Library/Application Support/RemObjects Software/EBuild/SDKs/Island/Darwin’ to force a redownload.

If you’re uisng Xcode odler that 26.5, lmk, but the best option would be to use the workarund, i that case.


Description of what happened:

This is not an EventHandlerUPP, AddressOf, callback-lifetime, or Mercury-specific problem.

The SDK HeaderImporter imported Carbon’s C multi-character constant:

kEventClassKeyboard = 'keyb'

as 0x6279656B, while the correct native value is 0x6B657962. As a result, the handler was installed for the wrong event class, so the real Carbon keyboard event never matched it.

We have fixed the importer. Until a build ships with regenerated macOS SDK metadata, the workaround is to use the explicit FourCC value:

Dim eventType As EventTypeSpec
eventType.eventClass = &H6B657962 ' keyb
eventType.eventKind = kEventHotKeyPressed

The rest of the original code—including EventHandlerUPP, AddressOf, InstallEventHandler, and RegisterEventHotKey—can remain unchanged. Any other use of the imported kEventClassKeyboard constant should use the explicit value as well.

Xcode 27.0 Beta 4 SDKs are up, imported with the fix. If you’re using Xcode 27, delete the old SDKs from ~/Library/Application Support/RemObjects Software/EBuild/SDKs/Island/Darwin, and they should redownload on the next build.

Update: Xcode 26.6 reimport is also up.

thx, I will upgrade and try it

I tried the manual workaround, and it works

Happy to hear!