# Retained widget foundations -- named-retail pseudocode **Date:** 2026-07-10 **Scope:** Wave 0 oracle for `UIElement_Text`, `UIElement_Button`, raw edge layout, UI time delivery, tooltip cancellation, and focus ordering. This note changes no runtime behavior. ## Sources and confidence Primary evidence: - `docs/research/named-retail/acclient_2013_pseudo_c.txt`, the Sept 2013 EoR PDB-named client decompilation. - `docs/research/named-retail/acclient.h`, especially `UIElement_Text::UIText_Flag`, `UIElement_Text`, `UIElement_Button`, `UIElementManager`, `ElementDesc`, and `Box2D`. - Static x86 disassembly of the matching `C:\Turbine\Asheron's Call\acclient.exe` for the expressions that both Binary Ninja and Ghidra lost around x87 `_ftol2` calls in `UIElement::UpdateForParentSizeChange`. Cross-checks: - `docs/research/2026-06-15-layoutdesc-format.md` and the production LayoutDesc data it records. Its property observations agree with the named code, but its `AnchorEdges` reduction is intentionally lossy and its text-property table has two margin fields transposed; the corrections are listed below. - `docs/research/retail-ui/02-class-hierarchy.md` and `docs/research/retail-ui/04-input-events.md`, the older `FUN_xxx` research. These are useful as provenance but are superseded where they conflict with the PDB-named client. In particular, the named client contains the full `UIElement*` hierarchy and does **not** implement the inferred generic `Device::RegisterTimerEvent` queue described there. - The only vendored reference tree present in this worktree is WorldBuilder; it does not implement the retail retained-widget system. No independent ACE, AC2D, ACViewer, or holtburger UI implementation was available here to corroborate these client-internal mechanics. Confidence is **high** for every branch below unless it is explicitly marked uncertain. Addresses were checked against `symbols.json` or the named function header in the pseudo-C. ## Corrections that affect the implementation plan 1. Retail text interactivity is **two orthogonal capabilities**, not a three-value exclusive mode. `Editable` (`0x16`) and `Selectable` (`0x27`) can be independently false/true. An editable, non-selectable field accepts edits but does not begin drag selection. The modern representation should therefore be flags or two booleans; `Display` means both are false. 2. A newly constructed Type-12 text starts with `m_bitField = 0x300` (`DIRTY | CURSOR_VISIBLE`), not editable and not selectable. Imported labels must not be made interactive merely because their resolved type is 12. 3. There is no evidence for the old generic Device timer queue in this build. Retail time-driven UI is a per-frame global message (`3`) plus explicit deadline polling by `UIElementManager::CheckTooltip`. The unpumped `UiRoot.RegisterTimerEvent` list is not a faithful retail mechanism. 4. Raw edge modes `3` and `4` cannot be reduced to `AnchorEdges`: `3` performs exact inclusive-pixel centering and `4` proportionally scales the individual edge coordinate with truncation toward zero. 5. In the older LayoutDesc note, the exact text margins should be `0x23=left`, `0x24=right`, `0x25=upper`, `0x26=lower`, as shown by `UIElement_Text::OnSetAttribute @ 0x0046A640`. --- ## 1. `UIElement_Text` ### 1.1 Flag model and defaults `acclient.h` defines the exact flags: | Flag | Value | Meaning | |---|---:|---| | `UITF_EDITABLE` | `0x0001` | Editing/input capability | | `UITF_ONE_LINE` | `0x0002` | One-line layout | | `UITF_SELECTABLE` | `0x0004` | Selection/copy capability | | `UITF_NO_IME` | `0x0008` | Do not enable IME | | `UITF_OUTLINE` | `0x0010` | Outline glyphs | | `UITF_DROPSHADOW` | `0x0020` | Drop shadow glyphs | | `UITF_MOUSE_SELECTING` | `0x0040` | Pointer drag is active | | `UITF_SELECTING` | `0x0080` | Selection anchor/end are active | | `UITF_DIRTY` | `0x0100` | Glyph/layout cache dirty | | `UITF_CURSOR_VISIBLE` | `0x0200` | Caret blink phase visible | | `UITF_FIT_TO_TEXT` | `0x0400` | Resize element to paper | | `UITF_TRUNCATE_TEXT_TO_FIT` | `0x0800` | Trailer/truncation path | | `UITF_LOSE_FOCUS_ON_ESCAPE` | `0x1000` | Escape relinquishes focus | | `UITF_LOSE_FOCUS_ON_ACCEPT_INPUT` | `0x2000` | Accept-input action relinquishes focus | `UIElement_Text::UIElement_Text @ 0x00468570` initializes the flag word to `0x300`, selection/cursor positions to zero, horizontal justification to `2`, vertical justification to `4`, margins to zero, and cursor/flash timestamps to `-1.0`. Thus the retail default is a display-only label. ### 1.2 Interaction-relevant property IDs `UIElement_Text::OnSetAttribute @ 0x0046A640` first delegates to `UIElement_Scrollable::OnSetAttribute`, then handles these properties: | Property | Value kind | Exact effect | |---:|---|---| | `0x14` | enum | Horizontal justification | | `0x15` | enum | Vertical justification | | `0x16` | bool | `SetEditable`; then recompute mouse visibility | | `0x17` | `StringInfo` | Set contents, or clear when invalid | | `0x1A` | array/data-id | Re-resolve current font | | `0x1B` | array/color | Re-resolve current font color | | `0x1D` | array/color | Re-resolve tag font color | | `0x1E` | integer | Maximum characters | | `0x1F` | bool | `SetNoIme` | | `0x20` | bool | `SetOneLine` | | `0x21` | bool | `SetOutline` | | `0x22` | color | Outline color; then font reset | | `0x23` | integer | Left margin | | `0x24` | integer | Right margin | | `0x25` | integer | Upper margin | | `0x26` | integer | Lower margin | | `0x27` | bool | `SetSelectable`; then recompute mouse visibility | | `0x28` | bool | Glyph list `TrimFromTop` | | `0x29` | bool | `SetFitToText` | | `0xC7` | `StringInfo` | Enable/define truncation trailer; invalid disables it | | `0xCB` | bool | Lose focus on Escape | | `0xCC` | bool | Lose focus on accept-input | ### 1.3 Capability setters Sources: `SetEditable @ 0x004680D0`, `SetOneLine @ 0x00468170`, and `SetSelectable @ 0x004681C0`. ```text SetEditable(value): if value == current Editable: return if value is false: if this has global focus AND Selectable is false: RelinquishFocus() else if TruncateTextToFit is true: clear TruncateTextToFit mark dirty and dirty the root set Editable = value SetSelectable(value): if value == current Selectable: return if value is false: if this has global focus AND Editable is false: RelinquishFocus() else if TruncateTextToFit is true: clear TruncateTextToFit mark dirty and dirty the root set Selectable = value if the internal selection-direction marker is active: clear selecting/mouse-selecting and zero both selection endpoints SetOneLine(value): if value differs: set OneLine = value mark dirty and dirty the root ``` The high internal selection-direction bit checked by `SetSelectable` and `SetCursorPosition` is not named in `UIText_Flag`; it is deliberately not given a speculative public name here. `SetTruncateTextToFit @ 0x00467480` refuses to enable truncation whenever either `Editable` or `Selectable` is set. ### 1.4 Mouse visibility Sources: `UIElement_Text::GetShouldBeMouseVisible @ 0x00467460` and `UIElement::GetShouldBeMouseVisible @ 0x004601B0`. ```text Text.GetShouldBeMouseVisible(): if Editable OR Selectable: return true return base.GetShouldBeMouseVisible() Base.GetShouldBeMouseVisible(): return explicit mouse-visible/interaction flag OR valid tooltip text ``` Consequently, a plain imported label does not claim the mouse unless another base property (for example a tooltip/explicit mouse role) says it should. ### 1.5 Mouse down, selection, and activation Sources: `MouseDown @ 0x00469370`, `MouseUp @ 0x004694F0`, and `MouseMove @ 0x004695F0`. ```text MouseDown(screenX, screenY, mouseAction): remember whether this already had focus call Scrollable.MouseDown(...) if hidden/blocked base flags reject input: return if mouseAction is not one of the accepted text actions (5, 6, 7): return if the base action-enable bit is false: return local = screen point - screen origin - margins if mouseAction == 7 AND (Editable OR Selectable): read bool property 0xD1 if this did not previously have focus AND property 0xD1 is true: SelectAll() return hitPos = DeterminePositionFromXY(local) previousAnchor = selectionStart when the internal selection direction is active, otherwise current cursor SetCursorPosition(hitPos, DontSelectText) Activate() // activate the owning root if Selectable: set Selecting and MouseSelecting if Shift is down: selectionStart = previousAnchor selectionEnd = cursor else: selectionStart = cursor MouseMove(screenX, screenY): if not MouseSelecting: call base MouseMove and return local = screen point - screen origin - margins SetCursorPosition(DeterminePositionFromXY(local), Default) MouseUp(screenX, screenY, mouseAction): remember whether a glyph callback is registered for mouseAction call base MouseUp(...) if MouseSelecting: set cursor from release point using Default clear MouseSelecting if a glyph callback was registered: glyph = glyph at release point if glyph has a callback: invoke it with mouseAction ``` Important boundary: `Editable` alone allows caret placement and root activation, but only `Selectable` starts pointer selection. The method calls `Activate`, not `TakeFocus`, so the focus transition remains governed by the root's remembered focus element and explicit `TakeFocus` requests. ### 1.6 Focus registration and key capabilities Sources: `RegisterInputMaps @ 0x00467350`, `UnregisterInputMaps @ 0x004673D0`, `ListenToElementMessage @ 0x004687C0`, and `OnAction @ 0x0046A260`. ```text RegisterInputMaps(priority): unregister this callback first result = Scrollable.RegisterInputMaps(priority) if Editable: register input map 1 at priority - 10 register input map 7 at priority if Editable OR Selectable: register input map 8 at priority return OR of registration results On focus message 0x2F for this element: if neither Editable nor Selectable: delegate to base if Editable: on gain: register as ICIDM input handler turn IME on unless disabled ask Keystone to lose its external focus on loss: unregister ICIDM input handler on gain: ICIDM.SetTextMode(true) subscribe to global message 3 on loss: Deselect() ICIDM.SetTextMode(false) unsubscribe from global message 3 delegate to Scrollable.ListenToElementMessage ``` Map 8 exposes cursor movement, line/document home/end, up/down/page movement, and Copy for both editable and selectable text. Editable-only maps add character editing. `Cut`, `Paste`, and deletion helpers independently guard on `UITF_EDITABLE`, so merely selectable text cannot mutate its contents. The action at `0x25` relinquishes focus when `0xCC` is set; the action at `0x27` relinquishes focus when `0xCB` is set. Actions `0x26` and `0x28` are forward-delete and backspace behavior respectively, deleting the active selection first. ### 1.7 Per-frame caret work `UIElement_Text::Global_Loop @ 0x00469FC0` runs on global message `3`. It checks asynchronous string downloads, then, only while `(Editable || Selectable) && HasFocus`, uses `GetCaretBlinkTime()` converted from milliseconds to seconds to flip `UITF_CURSOR_VISIBLE` and dirty the last caret rectangle. This is subscription-driven; it is not a registered timer object. --- ## 2. `UIElement_Button` ### 2.1 State inputs and numeric states Source: `UIElement_Button::UpdateState_ @ 0x00471CF0`, verified against the matching x86 instructions. The method reads these bool properties: - `0x0D`: ghosted/disabled role; - `0x0E`: selected/toggled role; - `0x13`: allow rollover-state change role. It combines them with `mousePressedOnButton` and the inherited `mouseOverTop` bit. The standard state IDs are: | Visual phase | Unselected | Selected | |---|---:|---:| | Normal | `1` | `6` | | Rollover / pressed outside | `2` | `7` | | Pressed while pointer is over | `3` | `8` | | Ghosted | `13` | `13` | ```text UpdateState_(): disabled = bool property 0x0D if disabled: requested = 13 else: selected = bool property 0x0E rolloverEnabled = bool property 0x13 requested = selected ? 6 : 1 if mousePressedOnButton OR (rolloverEnabled AND mouseOverTop): requested = selected ? 7 : 2 if mousePressedOnButton AND mouseOverTop: requested = selected ? 8 : 3 if ElementDesc contains requested state: virtual SetState(requested) else: leave the current state unchanged ``` That last test is the exact fallback rule. There is no search for a nearest standard state. A custom semantic state survives only when the newly requested standard state is absent from the element's DAT state table. ### 2.2 `SetState` synchronization Source: `UIElement_Button::SetState @ 0x00471DA0`. ```text SetState(requested): if bool property 0x0B is true: // toggle behavior selected = bool property 0x0E if requested == 6 AND not selected: set property 0x0E = true return true if requested == 1 AND selected: set property 0x0E = false return true wantsDisabled = requested == 13 disabled = bool property 0x0D if wantsDisabled != disabled: set property 0x0D = wantsDisabled return true return UIElement.SetState(requested) ``` Thus programmatic `SetState(1/6)` is also the selected-property API for a toggle button, and `SetState(13)` is the disabled-property API. Property changes call `UpdateState_` through `OnSetAttribute`. ### 2.3 Mouse state machine Sources: `MouseDown @ 0x00471FF0`, `MouseUp @ 0x004720E0`, and `MouseOverTop @ 0x004721F0`. ```text MouseOverTop(isOver): base.MouseOverTop(isOver) UpdateState_() MouseDown(x, y, mouseAction): Text.MouseDown(...) if inherited visibility/input gates reject: return if mouseAction is neither 7 nor accepted alternate action 0x0A: return mousePressedOnButton = true UpdateState_() disabled = bool property 0x0D allowHotClickWhileDisabled = bool property 0x0C if disabled AND not allowHotClickWhileDisabled: return if bool property 0x0F: // hot-click/auto-repeat BroadcastElementMessage(2, mouseAction, 0) // immediate activation hotClickingInProgress = true subscribe to global message 3 nextHotClickTime = Timer.cur_time + float property 0x10 MouseUp(x, y, mouseAction): Text.MouseUp(...) disabled = bool property 0x0D if mousePressedOnButton AND mouseAction is 7 or 0x0A: emitClick = false if mouseOverTop AND not disabled: if bool property 0x0B: // toggle property 0x0E = !property 0x0E if not hotClickingInProgress: emitClick = true mousePressedOnButton = false if hotClickingInProgress: hotClickingInProgress = false unsubscribe from global message 3 UpdateState_() if emitClick: BroadcastElementMessage(1, 7, 0) ``` Release outside never emits message `1`. During a captured press, moving outside changes state `3/8 -> 2/7`; moving back inside restores `3/8`. A hot-click press emits message `2` immediately and suppresses the ordinary release click. ### 2.4 Hot-click deadline delivery and cancellation Sources: `ListenToGlobalMessage @ 0x00471C60`, `OnSetAttribute @ 0x00471F40`, and the button destructor at `0x00471BC0`. ```text On global message 3 while hotClickingInProgress: now = Timer.cur_time if not mouseOverTop AND now >= nextHotClickTime: nextHotClickTime = now if mouseOverTop AND now >= nextHotClickTime: BroadcastElementMessage(2, 0, 0) nextHotClickTime += float property 0x11 ``` Cancellation is explicit and idempotent at all three owner transitions: - mouse up clears `hotClickingInProgress` and unsubscribes from global `3`; - changing bool property `0x0F` to false does the same; - destruction does the same if a hot click is active. `OnSetAttribute` recalculates visual state for `0x0D`, `0x0E`, and `0x13`; `0x0D` also recomputes mouse visibility. The descriptive names for button properties `0x0B..0x13` are not present in the recovered headers. Their behavioral roles above are exact; do not bake the descriptive labels into a wire/DAT enum until the master property-name table is recovered. --- ## 3. `UIElement::UpdateForParentSizeChange` **Oracle:** `UIElement::UpdateForParentSizeChange @ 0x00462640`. `Box2D` is inclusive: width is `x1 - x0 + 1`, height is `y1 - y0 + 1`. For a root/no-parent element (or the relevant root-sizing flag), the original parent box is `[0,0,layout.displayWidth-1,layout.displayHeight-1]` and the current parent box is `[0,0,displayWidth-1,displayHeight-1]`. Otherwise, both boxes come from the parent. ```text orig = this.GetOriginalPosition() origParent = parent.GetOriginalPosition() or layout display box curParent = parent.GetCurrentPosition() or current display box origParentWidth = origParent.x1 - origParent.x0 + 1 origParentHeight = origParent.y1 - origParent.y0 + 1 curParentWidth = curParent.x1 - curParent.x0 + 1 curParentHeight = curParent.y1 - curParent.y0 + 1 deltaX = curParentWidth - origParentWidth deltaY = curParentHeight - origParentHeight scaleX = origParentWidth != 0 ? curParentWidth / origParentWidth : 0.0 scaleY = origParentHeight != 0 ? curParentHeight / origParentHeight : 0.0 ``` All ratios are floating point. Mode-4 conversion uses MSVC `_ftol2`, i.e. truncate toward zero, not floor and not round-to-nearest. Define `halfTowardZero(n) = truncate(n / 2)` for signed integers. ```text newX0 = orig.x0 switch LeftEdge: 2: newX0 = orig.x0 + deltaX 3: newX0 = halfTowardZero(curParentWidth) - halfTowardZero(orig.width) 4: newX0 = truncateTowardZero(orig.x0 * scaleX) 0,1: leave orig.x0 for now newX1 = orig.x1 switch RightEdge: 1: newX1 = orig.x1 + deltaX 3: newX1 = halfTowardZero(curParentWidth) + halfTowardZero(orig.width) - 1 4: newX1 = truncateTowardZero(orig.x1 * scaleX) 0,2: leave orig.x1 for now newY0 = orig.y0 switch TopEdge: 2: newY0 = orig.y0 + deltaY 3: newY0 = halfTowardZero(curParentHeight) - halfTowardZero(orig.height) 4: newY0 = truncateTowardZero(orig.y0 * scaleY) 0,1: leave orig.y0 for now newY1 = orig.y1 switch BottomEdge: 1: newY1 = orig.y1 + deltaY 3: newY1 = halfTowardZero(curParentHeight) + halfTowardZero(orig.height) - 1 4: newY1 = truncateTowardZero(orig.y1 * scaleY) 0,2: leave orig.y1 for now ``` Then retail applies mode `0` as a preservation policy: ```text if current width != 0 OR current height != 0 OR preserve-current flag is set: if LeftEdge == 0: newX0 = current.x0 if TopEdge == 0: newY0 = current.y0 if RightEdge == 0: newX1 = current.x1 if BottomEdge == 0: newY1 = current.y1 ``` Finally: ```text MoveTo(newX0, newY0) ResizeTo(newX1 - newX0 + 1, newY1 - newY0 + 1) if original z-level differs from current z-level: restore original z-level ask parent to remove/reinsert this child in z-order return true ``` ### Raw-mode summary | Raw mode | Near edge (`Left`/`Top`) | Far edge (`Right`/`Bottom`) | |---:|---|---| | `0` | Preserve current edge after initialization | Preserve current edge after initialization | | `1` | Keep original near edge | Add parent size delta (stretch) | | `2` | Add parent size delta (move with far side) | Keep original far edge | | `3` | Recompute centered near edge | Recompute centered far edge | | `4` | Proportionally scale original coordinate | Proportionally scale original coordinate | Mode `4` does **not** mean “both anchors.” That description in the earlier LayoutDesc note was only an approximation of the resulting resize for common assets and must not survive in the imported layout policy. --- ## 4. Time delivery, tooltip cancellation, and focus ordering ### 4.1 No generic Device timer queue in the named client The old `04-input-events.md` inferred a Device vtable timer API from unnamed calls. The recovered `UIElementManager` fields in `acclient.h` contain tooltip timestamps but no timer collection, and the named execution path is explicit. The exact per-frame method is `UIElementManager::UseTime @ 0x0045CFD0`: ```text UseTime(): CleanDeleteQueue() ProcessUIMessageRemovalData() if mouse hit-test requested: DoMouseUpdate() CheckTooltip() BroadcastGlobalMessage(3, 0) if ICIDM exists: ICIDM.UseTime() DrawDirtyRegions() ``` Global message `3` is the shared time pulse used by text caret/download work and button hot-click repeat. Subscription and unsubscription are the cancellation mechanism. Deletions and deferred listener removals are processed **before** the time pulse. ### 4.2 Tooltip deadlines Sources: manager constructor `0x0045F5D0`, `CheckTooltip @ 0x0045B6E0`, `StartHover @ 0x00459250`, `StopHover @ 0x00459280`, `SwitchMouseOver @ 0x0045B560`, `MouseMoveHandler @ 0x0045E710`, and `ReleaseMouseCapture @ 0x0045D2B0`. Defaults are **0.25 seconds** delay and **10 seconds** duration. The delay is a user preference (`Misc.TooltipDelay`, allowed range 0..10 seconds); per-element float property `0x50` overrides it. ```text MouseMoveHandler(...): lastMouseMoveTime = Timer.local_time refresh the element under the pointer and call SwitchMouseOver continue drag processing ReleaseMouseCapture(owner): if owner holds capture: lastMouseMoveTime = Timer.local_time decrement/release capture CheckTooltip(): now = Timer.local_time if hover has not started AND mouse is inside the window: if no element has mouse capture AND lastEntered exists: delay = lastEntered.floatProperty(0x50) or manager default if now >= lastMouseMoveTime + delay: StartHover(currentMouseX, currentMouseY) if tooltip element exists: if now - tooltipStart >= tooltipDuration: queue tooltip element for deletion tooltipElement = null SwitchMouseOver(null) StartHover(x, y): if hover has not started: hoverStarted = lastEntered.MouseHover(x, y) StopHover(): if hoverStarted: hoverStarted = false lastEntered?.MouseUnhover() if tooltipElement exists: queue it for deletion tooltipElement = null ``` `SwitchMouseOver(old -> new)` calls `StopHover` before sending `old.MouseOverTop(false)`, then sends `new.MouseOverTop(true)`. Capture prevents a new tooltip deadline from starting. `UIElementManager::DeletingElement @ 0x0045E520` also clears capture/hover/drag/tooltip ownership and removes queued element messages that target the deleted element. There is therefore no “remove a due timer before callback” retail rule to port for tooltips. The faithful rule is owner-state cancellation plus subscription teardown before the global time pulse. ### 4.3 Focus transfer order Sources: `UIElementManager::SetFocusElement @ 0x0045B890`, `UIElement::TakeFocus @ 0x004601E0`, `UIElement::RelinquishFocus @ 0x00461DE0`, and `UIElementManager::BroadcastElementMessage @ 0x0045AB40`. ```text SetFocusElement(newFocus): oldFocus = focusElement if oldFocus == newFocus: return if oldFocus exists: BroadcastElementMessage(oldFocus, 0x2F, param1=0, param2=0) oldFocus.UnregisterInputMaps() focusElement = newFocus if newFocus exists: BroadcastElementMessage(newFocus, 0x2F, param1=1, param2=0) newFocus.RegisterInputMaps(priority=0x0BB8) // 3000 TakeFocus(element): root = element.GetRootElement() if root is null: return false set element's owns-focus marker if root is active: SetFocusElement(element) becameGlobal = true root.rememberedFocusDescendant = element return becameGlobal RelinquishFocus(element): root = element.GetRootElement() if root exists: root.rememberedFocusDescendant = null clear element's owns-focus marker if manager.focusElement == element: SetFocusElement(null) return true ``` Focus messages are synchronous. If a handler broadcasts another element message while one is already broadcasting, `BroadcastElementMessage` appends it to a FIFO list and drains that list before clearing the broadcasting flag. This prevents recursive listener traversal while retaining deterministic order. Active-root changes are separate from text focus. `UIElement::Activate @ 0x00461C80` activates/registers the root and restores its remembered focus descendant through `SetFocusElement`; `Deactivate @ 0x00461D50` broadcasts root deactivation and clears global focus when the root owned it. ### 4.4 Keyboard routing relative to focus `UIElementManager::KeyPressEvent @ 0x0045C300` uses this order when the debug console is not intercepting input: ```text target = focusElement if present else activeElement if target exists: consumed = target.KeyDown(action, extent) if not consumed: BroadcastGlobalMessage(1, action) else: BroadcastGlobalMessage(1, action) DoVisibilityToggleAction(action) // still runs after the route above ``` That final visibility-toggle call is unconditional within the normal input path; it is not gated by whether the focus/active target consumed `KeyDown`. --- ## 5. Conformance vectors to carry into Wave 1 1. **Text defaults:** construct Type 12 with no interaction properties; assert editable=false, selectable=false, and no mouse claim absent tooltip/base role. 2. **Orthogonal capabilities:** cover all four `(editable, selectable)` pairs. Editable-only places the caret but does not drag-select; selectable-only selects/copies but cut/paste/delete do not mutate. 3. **Focus teardown:** disabling the last active text capability while focused relinquishes focus; disabling one while the other remains does not. 4. **Button states:** golden table for states `1/2/3/6/7/8/13`, captured release outside, re-entry, toggle on/off, and missing-state fallback. 5. **Hot click:** immediate message `2`, initial delay `0x10`, repeat interval `0x11`, pause/reset while pointer is outside, and cancellation on mouse-up, property disable, and destruction. 6. **Layout:** one vector per raw mode on each individual edge; include odd and even parent/child sizes, negative intermediate centered values, a zero-sized original parent, mode-0 preservation after initialization, and nested parents. 7. **Time order:** deletion/removal before global tick `3`; tooltip check before tick `3`; capture release restarts the tooltip idle deadline. 8. **Focus order:** old loss message -> old map removal -> pointer assignment -> new gain message -> new map registration; nested focus messages drain FIFO. ## Remaining uncertainties - The recovered symbols do not name button properties `0x0B..0x13`; this note records exact observed behavior but intentionally does not assert canonical property names for all of them. - Mouse action `7` is the normal primary-button path in these methods. Alternate action `0x0A` is accepted by `UIElement_Button`; its user-facing input name was not recovered in this bounded pass. - The high text selection-direction bit used in `SetCursorPosition` is outside `UIText_Flag` and remains unnamed. - This pass did not reconstruct every `ICIDM` input action name, only the exact routing and behavior needed to separate display/selectable/editable text.