Skip to content

macOS 27 beta: void-declared contact-frame callback suppresses system gestures (declare int32_t return, return 0) #13

Description

@bitvibelabs

Heads-up from another project using the same private framework, in case it saves someone a debugging day.

Symptom (macOS 27.0 developer beta, build 26A5388g, arm64): while an app streams contact frames via MTRegisterContactFrameCallback + MTDeviceStart(dev, 0) on the built-in trackpad, the system's own 3-finger and 4-finger swipe gestures (space switching, Mission Control, App Expose) stop firing. Quit the streaming app and they come back immediately. Verified A/B on real hardware several times.

Cause we landed on: the callback's declared return type. The oldest header lineage (steike/Karabiner/MiddleDrag) declares the contact callback as returning int, where 0 means "pass the frame through to the system recognizer" and non-zero means "consume". OpenMTInternal.h (like many gists) declares it void. A void-declared callback leaves whatever garbage is in the return register, and on macOS 27 the reworked gesture pipeline appears to honor that value. Garbage reads as "consume", so the system recognizer starves while streaming. Through Tahoe 26.x this appears to have been ignored, which would be why nobody has noticed.

Fix that worked: declare the callback as returning int32_t and explicitly return 0. With that one change, streaming and the system gestures coexist again on 27 beta. Details and the working Swift implementation are here: https://github.com/bitvibelabs/TicTap (App/TouchStream.swift).

Caveats, honestly: one machine, one beta build, and we reproduced it with our own dlsym-based registration rather than through OpenMultitouchSupport itself. But since OpenMTInternal.h declares the void-returning form, the same suppression seems likely to hit OMS-based apps once users are on 27. Might be worth declaring the int return proactively; returning 0 is compatible with existing behavior on older macOS.

Happy to provide more repro detail if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions