msgProc: System Messages

Reference for system and utility msgProc events including container resizing, focus tracking, and reactive data change notifications.

Size Changed (MSG_SIZE)

MSG_SIZE fires when the container element is resized. Use this to recalculate layouts, adjust canvas dimensions, or update any size-dependent state. This event uses ResizeObserver internally and fires for both programmatic and user-driven size changes.

Message Parameters

Parameter Type Description
wParam number Resize type constant: SIZE_RESTORED (0), SIZE_HIDDEN (1), SIZE_FULLSCREEN (2). SIZE_HIDDEN fires when both width and height drop to zero; SIZE_FULLSCREEN fires when the container enters fullscreen mode.
lParam number Packed dimensions: low 16 bits = width, high 16 bits = height (in pixels). Extract using LOWORD() and HIWORD()

Detail Properties

Property Type Description
width number New container width in pixels (same as LOWORD(lParam))
height number New container height in pixels (same as HIWORD(lParam))
contentRect DOMRect Full ResizeObserver content rectangle with x, y, width, height, top, right, bottom, left properties
borderBoxSize ResizeObserverSize[] Array of ResizeObserverSize objects with inlineSize and blockSize properties representing the full element dimensions including padding and border. Writing-mode aware (inline=horizontal in LTR, vertical in vertical writing modes). Use for calculations needing complete box size or for internationalization with vertical text layouts
contentBoxSize ResizeObserverSize[] Array of ResizeObserverSize objects with inlineSize and blockSize properties representing the content area dimensions excluding padding and border. Writing-mode aware. Use when sizing child elements to fit exactly within the padding, or when you need the actual drawable/usable content space
Performance Note: MSG_SIZE fires immediately during resize operations for responsive UI updates. Keep resize handlers lightweight. Only debounce expensive operations that don't need real-time feedback (heavy calculations, network requests, complex re-renders). Most resize handlers (canvas sizing, layout updates) should run immediately without debouncing.

Example: Canvas Resize

msgProc(event) {
    if (event.message === wakaPAC.MSG_SIZE) {
        const width = wakaPAC.LOWORD(event.lParam);
        const height = wakaPAC.HIWORD(event.lParam);
        this.updateLayout();
    }
}

Set Focus (MSG_SETFOCUS)

MSG_SETFOCUS fires when an element within the container receives focus. Use this to track focus state, enable keyboard shortcuts, or update UI to reflect focused state.

Message Parameters

Parameter Type Description
wParam number Reserved (always 0)
lParam number Reserved (always 0)
target HTMLElement The element that received focus

Example: Enable Keyboard Shortcuts

msgProc(event) {
    if (event.message === wakaPAC.MSG_SETFOCUS) {
        this.keyboardShortcutsEnabled = true;
        return false;
    }

    if (event.message === wakaPAC.MSG_KILLFOCUS) {
        this.keyboardShortcutsEnabled = false;
        return false;
    }

    // Handle shortcuts only when focused
    if (event.message === wakaPAC.MSG_KEYDOWN && this.keyboardShortcutsEnabled) {
        if (event.wParam === wakaPAC.VK_S && (event.lParam & wakaPAC.KM_CONTROL)) {
            this.save();
            return false;
        }
    }
}

Kill Focus (MSG_KILLFOCUS)

MSG_KILLFOCUS fires when an element within the container loses focus. Use this to clean up focus-dependent state, disable keyboard shortcuts, or trigger validation.

Message Parameters

Parameter Type Description
wParam number Reserved (always 0)
lParam number Reserved (always 0)
target HTMLElement The element that lost focus

Example: Save Draft on Focus Loss

msgProc(event) {
    if (event.message === wakaPAC.MSG_KILLFOCUS) {
        // Auto-save when editor loses focus
        if (this.isDirty) {
            this.saveDraft();
        }
        return false;
    }
}

Device Pixel Ratio Changed (MSG_DPR_CHANGE)

MSG_DPR_CHANGE fires when the display's device pixel ratio changes. This happens when the user moves the browser window to a monitor with a different pixel density, or changes the OS display scaling setting. The updated ratio is available on this.browserDevicePixelRatio when the message arrives.

Message Parameters

Parameter Type Description
wParam number New device pixel ratio multiplied by 100 and rounded to the nearest integer (e.g. 150 for a DPR of 1.5, 200 for 2.0). Divide by 100 to recover the float value
lParam number Reserved (always 0)
Two ways to read the ratio: Use event.wParam / 100 for a self-contained handler, or read this.browserDevicePixelRatio directly — the abstraction property is updated before the message is dispatched.

Example: Resize Canvas for HiDPI

msgProc(event) {
    switch (event.message) {
        case wakaPAC.MSG_SIZE:
        case wakaPAC.MSG_DPR_CHANGE: {
            const dpr = this.browserDevicePixelRatio;
            wakaPAC.resizeCanvas(this.pacId, this.containerWidth * dpr, this.containerHeight * dpr);
            wakaPAC.invalidateRect(this.pacId);
            return;
        }

        case wakaPAC.MSG_PAINT: {
            const hdc = wakaPAC.getDC(this.pacId);
            const dpr = this.browserDevicePixelRatio;

            hdc.save();
            hdc.scale(dpr, dpr);

            // Draw using CSS pixel coordinates as normal
            hdc.clearRect(0, 0, this.containerWidth, this.containerHeight);
            // ... drawing code ...

            hdc.restore();
            return;
        }
    }
}

Foreach Rebuilt (MSG_FOREACH_REBUILT)

MSG_FOREACH_REBUILT fires after a foreach binding finishes rendering its items. It fires once per foreach binding, so a component with multiple foreach bindings receives a separate message for each one. Use this to update any non-reactive content that depends on the rendered DOM — such as drawing sparklines onto canvas elements inside foreach items.

Message Parameters

Parameter Type Description
wParam number Number of items rendered
lParam number Reserved (always 0)

Detail Properties

Property Type Description
arrayName string The foreach expression string (e.g. 'products'). Use to retrieve the source data via this[event.detail.arrayName]
marker string | null The value of the data-pac-marker attribute on the foreach element, or null if not set. Use to distinguish between multiple foreach bindings that share the same source array
Distinguishing multiple foreachs: If the same array is bound in more than one foreach, or if you simply want explicit identification, add data-pac-marker="myMarker" to the foreach element and check event.detail.marker in the handler.

Child Destroyed (MSG_DESTROYED)

MSG_DESTROYED fires on a parent component when one of its direct child components is removed from the DOM. Use this to react to dynamic child removal — for example, to update a counter, clean up cross-component state, or log activity.

The message is dispatched asynchronously after the child has fully cleaned up and deregistered, so by the time the parent handles it the child's pacId is no longer present in the registry.

Message Parameters

Parameter Type Description
wParam number Reserved (always 0)
lParam number Reserved (always 0)

Detail Properties

Property Type Description
childPacId string The pacId of the destroyed child component

Example: Track Active Children

msgProc(event) {
    if (event.message === wakaPAC.MSG_DESTROYED) {
        const childId = event.detail.childPacId;
        this.activeChildren = this.activeChildren.filter(id => id !== childId);
    }
}

Command Notification (MSG_COMMAND)

MSG_COMMAND is the standard way for a child component to notify its parent that the user performed an action. Rather than sending an arbitrary MSG_USER message, child components send MSG_COMMAND with a defined command identifier, and the parent routes on that identifier. This mirrors the Win32 WM_COMMAND pattern where a control sends a command to its parent window.

The command identifier sits in LOWORD(wParam). Application-defined identifiers should start at 0x1000 or higher — values below that are reserved for framework use. The optional notification code in HIWORD(wParam) lets a control distinguish between different types of notification from the same control (e.g. selection changed vs. item activated); use 0 for plain commands.

Message Parameters

Parameter Type Description
wParam number Application-defined. Win32 uses LOWORD for the command identifier and HIWORD for an optional notification code — use that layout if it fits, or pack wParam however suits your needs. Extract with wakaPAC.LOWORD(event.wParam) and wakaPAC.HIWORD(event.wParam).
lParam number Reserved (always 0). The sending component's identity is carried in event.detail.sender instead.

Detail Properties

Property Type Description
sender string | undefined The pacId of the child component that sent the command. Present when the child passes { sender: this.pacId } as the extended argument. Omit for commands that do not originate from a specific control.
Define command IDs as constants: Declare command identifiers as named constants shared between the parent and child rather than using magic numbers.

Example: Child Sends, Parent Handles

// Shared command identifiers (define once, import in both components)
const CMD_SAVE   = 0x1001;
const CMD_DELETE = 0x1002;
const CMD_CANCEL = 0x1003;

// Child component — sends a command to its parent
msgProc(event) {
    if (event.message === wakaPAC.MSG_LCLICK) {
        wakaPAC.sendMessageToParent(
            this.pacId,
            wakaPAC.MSG_COMMAND,
            CMD_SAVE,
            0,
            { sender: this.pacId }
        );
    }
}

// Parent component — routes on the command identifier
msgProc(event) {
    if (event.message === wakaPAC.MSG_COMMAND) {
        switch (wakaPAC.LOWORD(event.wParam)) {
            case CMD_SAVE:
                this.save();
                break;
            case CMD_DELETE:
                this.confirmDelete();
                break;
            case CMD_CANCEL:
                this.reset();
                break;
        }
    }
}

Best Practices

  • Keep resize handlers lightweight: MSG_SIZE fires frequently during resizing - avoid expensive calculations
  • Handle DPR alongside resize: MSG_DPR_CHANGE and MSG_SIZE often need the same canvas resize logic — fall through both cases to a shared handler
  • Track focus state: Use MSG_SETFOCUS/KILLFOCUS to enable/disable keyboard shortcuts appropriately
  • Validate on blur: MSG_KILLFOCUS is a good trigger for field validation
  • Consider focus scope: MSG_SETFOCUS/KILLFOCUS fire for any element within the container receiving/losing focus
  • Use markers for multiple foreachs: If a component has more than one foreach binding, add data-pac-marker to each and check event.detail.marker to route MSG_FOREACH_REBUILT to the right handler
  • Don't message destroyed children: When handling MSG_DESTROYED, the child is already deregistered — sending a message to childPacId will be silently dropped
  • Prefer MSG_COMMAND over MSG_USER for child notifications: MSG_COMMAND communicates intent — any parent reading the code immediately understands it is a child-to-parent notification. Reserve MSG_USER for messages that don't fit the command pattern
  • Define command IDs as named constants: Magic numbers in a switch statement are hard to maintain. Define constants once in a shared location and use them in both the sending child and the receiving parent