"The strike that does nothing is the worst bug in a hotkey app — because the user blames the whole app, not the one chord."
Two Kinds of Collision
A chord can collide two ways. Internal: two of your own macros are assigned the same keys. External: the system, or another running app, already owns the chord. These are not the same problem, and the honest thing is to admit that one is easy to catch and the other is genuinely hard.
The Internal One Is Easy
Internal collisions you own completely. You hold the registry of every macro's chord, so before you register a new one you check whether any other macro already claims those exact keys. If so, refuse and tell the user which macro has it. This is a simple lookup in the map you already keep — there's no excuse for shipping two of your own macros that fight over one chord.
The External One Is Honest-Hard
External collisions are where you have to be truthful about the platform. RegisterEventHotKey does not reliably fail when another app already holds the chord — it can return noErr and simply never fire, or fire unpredictably, depending on who registered first. So you cannot fully detect an external collision from the return code alone. What you can do is check the chord against the known reserved system shortcuts, warn when a macro maps to one of those, and — because you can't promise a chord is free — make sure there is always another way to run the macro that doesn't depend on the chord firing at all.
RegisterEventHotKey returning success as 'the chord works.' It only means the OS accepted your registration — not that your handler will win when the keys are pressed. Design for the case where registration succeeds and the chord still never fires, because that case is real and undetectable from the status code.Never Swallow the Strike
The failure to design against is the silent one: a user assigns a chord, it quietly loses to another app, they press it, nothing happens, and they conclude Flint is broken. The fix is twofold — surface every collision you can detect on the specific macro, and give every macro a chord-independent path to run (the palette, next lesson). A user who can always fall back to the palette never experiences 'the app is broken,' only 'this particular chord is taken.'