DDirectorWikiDirector & Lingo Encyclopedia

Input: Mouse, Keyboard, and Hit Testing

Mouse and keyboard events, hit testing rules, focus, rollover, double-click, and the input state properties.

Mouse events

EventFires whenDelivered to
mouseDownButton pressedHit sprite's chain; frame/movie scripts if no sprite hit
mouseUpButton releasedThe sprite that received the matching mouseDown, if release is over it
mouseUpOutsideRelease happens off the mouse-down spriteThe mouse-down sprite
mouseEnterPointer enters the sprite's hit areaThat sprite
mouseWithinRepeatedly while insideThat sprite (keep it cheap)
mouseLeavePointer exitsThat sprite
rightMouseDown / rightMouseUpRight 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

lingo
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 since

Notes:

  • the clickOn reports 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 doubleClick is a state flag readable during a mouseDown/mouseUp handler; Director itself has no separate doubleClick event, so games implement double-click via the doubleClick or click timing (the lastClick).

Hit testing rules

Which sprite is "under" the pointer:

  1. Candidate sprites are tested front-to-back: descending locZ, ties by descending channel.
  2. Invisible sprites (visible = FALSE) and empty channels are skipped.
  3. The hit area depends on member type and ink:
SpriteHit area
Bitmap, non-Matte inkBounding box (the sprite rect)
Bitmap, Matte ink (8)Visible (matte-covered) pixels only
32-bit bitmap with useAlphaAlpha-gated by alphaThreshold (0 disables gating)
Shape (unfilled)Border only vs filled area for filled shapes
Field/TextThe text box rect
Flash / vectorMember-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

EventFires
keyDownKey pressed (auto-repeat generates repeats)
keyUpKey released
lingo
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 keypress

Facts:

  • the keyCode uses 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 keyDown handlers pass (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

lingo
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

lingo
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 members

Text-under-pointer utilities

For fields/text members, Lingo exposes hit-to-text mapping used by hyperlink and console UIs:

lingo
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 mouseDown polled 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/mouseLeave derive 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.