Input: Mouse, Keyboard, and Hit Testing
Mouse and keyboard events, hit testing rules, focus, rollover, double-click, and the input state properties.
Mouse events
| Event | Fires when | Delivered to |
|---|---|---|
mouseDown | Button pressed | Hit sprite's chain; frame/movie scripts if no sprite hit |
mouseUp | Button released | The sprite that received the matching mouseDown, if release is over it |
mouseUpOutside | Release happens off the mouse-down sprite | The mouse-down sprite |
mouseEnter | Pointer enters the sprite's hit area | That sprite |
mouseWithin | Repeatedly while inside | That sprite (keep it cheap) |
mouseLeave | Pointer exits | That sprite |
rightMouseDown / rightMouseUp | Right button (Windows) / Ctrl-click (Mac, with the emulateMultibuttonMouse) | As mouseDown/Up |
Delivery follows the message hierarchy. Click-through: a sprite with no mouse handlers anywhere in its chain does not block the event; Director offers the click to the frame/movie level, but NOT to sprites underneath (topmost hit sprite owns the event; there is no spatial fall-through to lower sprites).
Mouse state properties
the mouseH, the mouseV, the mouseLoc -- current position (stage coords)
the clickLoc -- position of the last mouseDown
the clickOn -- sprite number last clicked (0 = stage)
the mouseDown, the mouseUp -- current button state (TRUE/FALSE)
the stillDown -- TRUE while held since last mouseDown
the doubleClick -- last click was a double-click
the mouseMember -- member under pointer (VOID if none)
the rollover / rollover(n) -- sprite under pointer / test sprite n
the lastClick, the lastRoll, the lastEvent -- ticks sinceNotes:
the clickOnreports only sprites with attached scripts (scriptless sprites are transparent to it): a documented quirk that navigation code exploits.rollover()is instantaneous hit testing independent of events.the doubleClickis a state flag readable during amouseDown/mouseUphandler; Director itself has no separate doubleClick event, so games implement double-click viathe doubleClickor click timing (the lastClick).
Hit testing rules
Which sprite is "under" the pointer:
- Candidate sprites are tested front-to-back: descending
locZ, ties by descending channel. - Invisible sprites (
visible = FALSE) and empty channels are skipped. - The hit area depends on member type and ink:
| Sprite | Hit area |
|---|---|
| Bitmap, non-Matte ink | Bounding box (the sprite rect) |
| Bitmap, Matte ink (8) | Visible (matte-covered) pixels only |
| 32-bit bitmap with useAlpha | Alpha-gated by alphaThreshold (0 disables gating) |
| Shape (unfilled) | Border only vs filled area for filled shapes |
| Field/Text | The text box rect |
| Flash / vector | Member-defined (hitTest for Flash exact mode) |
Do not infer click-through from rendered transparency: Background Transparent (36), Blend, and arithmetic-ink sprites hit on their full box despite transparent-looking pixels. (Native verification of edge cases is ongoing; see Native stage, input, and timing.)
Keyboard events and state
| Event | Fires |
|---|---|
keyDown | Key pressed (auto-repeat generates repeats) |
keyUp | Key released |
the key -- the character of the current event ("a", RETURN, ...)
the keyCode -- hardware key code (Mac virtual keycodes: 36 = Return, 48 = Tab, 123-126 = arrows)
the shiftDown, the controlDown, the optionDown, the commandDown
keyPressed(codeOrChar) -- poll a specific key right now
the keyPressed -- last key character (polling property)
the lastKey -- ticks since last keypressFacts:
the keyCodeuses Mac virtual key codes on both platforms (the Windows player translates), so arrow-key handling with 123-126 is portable; emulators must provide the Mac table.- Key events route: primary handler (
the keyDownScript) -> keyboard-focused sprite's behaviors (editable field/text) -> frame -> movie. Without an editable sprite focused, keys go to frame/movie scripts. - An editable field only receives typed characters if
keyDownhandlerspass(or don't exist). This is the number one broken-typing bug in ports. - ENTER (keypad) and RETURN are distinct characters (3 vs 13) from the Mac heritage.
Focus
the keyboardFocusSprite -- channel with keyboard focus; 0 = none, -1 = auto (click-to-focus)
sprite(n).editable -- editable text sprites can take focus
member(f).autoTab -- TAB advances focus to next editable sprite
the selStart, the selEnd -- selection within the focused field (char indexes)Click on an editable text/field sprite focuses it (auto mode); the keyboardFocusSprite = n forces focus; setting it to 0 releases. Selection and caret live on the member (selection(), hilite command for fields).
Cursors
cursor 4 -- watch cursor (system set: 0 arrow, 1 I-beam, 2 crosshair, 3 crossbar, 4 watch, 200 hide)
cursor -1 -- reset to default
sprite(5).cursor = 280 -- per-sprite cursor while over it
sprite(5).cursor = [member "handCur", member "handMask"] -- 1-bit member pair
cursor(member "animCur") -- animated cursor Xtra membersText-under-pointer utilities
For fields/text members, Lingo exposes hit-to-text mapping used by hyperlink and console UIs:
the mouseChar, the mouseWord, the mouseLine, the mouseItem -- index under pointer (-1 outside)
pointToChar(sprite 5, point) / pointToWord / pointToLine / pointToParagraph
charPosToLoc(member, i) / locToCharPos(member, point)Timing-sensitive behaviors
- Mouse events are queued and dispatched between frame events; a slow frame delays but never drops clicks (
flushInputEvents()discards the queue deliberately). the mouseDownpolled inside a repeat loop was the classic drag implementation (repeat while the stillDown); it works because polling reads live hardware state even though events wait for the loop to exit.- Double-click detection uses the OS double-click time.
mouseEnter/mouseLeavederive from hit-test transitions evaluated per event/frame pump, not from a continuous hover stream: entering and leaving within one long frame produces no events.