msgProc: Hooks

Message hooks let you intercept PAC messages before they reach their target container's msgProc, making them the right tool for cross-cutting concerns like debugging, telemetry, and middleware-style message transformation.

Hooks vs msgProc

A message hook sits above the normal message routing layer: it intercepts messages before dispatch, regardless of which container they are heading to. Where msgProc has scope over a single container, a hook sees everything.

msgProc Message Hook
Scope Single container All containers on the page
Purpose Application logic Tooling, middleware, cross-cutting concerns
Fires After hook chain completes Before msgProc receives the message
Defined on The PAC component object The wakaPAC runtime via installMessageHook
Can suppress Yes — return false Yes — do not call callNextHook

installMessageHook

Registers a callback that fires for every dispatched PAC message, before the target container's msgProc is called:

const hhook = wakaPAC.installMessageHook((event, callNextHook) => {
    // inspect or transform the event here
    callNextHook(); // pass to the next hook and eventually to msgProc
});

The method returns a hook handle (hhook) that identifies the installed hook. Pass it to uninstallMessageHook to remove the hook later.

Callback Arguments

Argument Type Description
event CustomEvent The PAC message event — same structure as the event received by msgProc, including message, wParam, lParam, pacId, and target
callNextHook Function Passes the message to the next hook in the chain. When the last hook calls through, the message is delivered to msgProc. Must be called for the message to continue — omitting it swallows the message

uninstallMessageHook

Removes a previously installed hook. After this call the callback will no longer fire:

wakaPAC.uninstallMessageHook(hhook);

Passing an invalid or already-removed handle is a no-op.

The Hook Chain

Multiple hooks can be active simultaneously. They form a chain and are called in installation order. Each hook must explicitly call callNextHook to pass the message forward:

1. DOM event occurs
   ↓
2. Hook 1 fires
   ├─ Calls callNextHook? → continue
   └─ Does not call? → message swallowed, chain stops here
      ↓
3. Hook 2 fires
   └─ Calls callNextHook → continue
      ↓
4. msgProc of the target container fires
Spy hooks must always call through. A hook that does not call callNextHook suppresses the message for the target container and all subsequent hooks. Only omit the call if you intentionally want to block the message.

Examples

Logging all messages

const hhook = wakaPAC.installMessageHook((event, callNextHook) => {
    const hex = '0x' + event.message.toString(16).toUpperCase().padStart(4, '0');
    console.log('[' + event.pacId + '] ' + hex);
    callNextHook();
});

Filtering a message type globally

Suppress MSG_MOUSEMOVE for all containers while a modal is open:

let hhook = null;

function openModal() {
    hhook = wakaPAC.installMessageHook((event, callNextHook) => {
        if (event.message === wakaPAC.MSG_MOUSEMOVE) {
            return; // swallow — do not call callNextHook
        }

        callNextHook();
    });
}

function closeModal() {
    if (hhook !== null) {
        wakaPAC.uninstallMessageHook(hhook);
        hhook = null;
    }
}

Measuring message throughput

const counts = {};

const hhook = wakaPAC.installMessageHook((event, callNextHook) => {
    counts[event.message] = (counts[event.message] ?? 0) + 1;
    callNextHook();
});

// Later — remove the hook and print results
wakaPAC.uninstallMessageHook(hhook);
console.table(counts);

Best Practices

  • Always call through in spy hooks: Failing to call callNextHook silently breaks message delivery for the target container
  • Keep hook callbacks fast: Hooks run on every message across all containers — expensive operations will degrade responsiveness
  • Uninstall when done: Store the hhook handle and call uninstallMessageHook when the hook is no longer needed, especially inside components with a lifecycle