docs
Systems
Infrastructure
InputSystem
Architecture and Design

Design patterns in use

  • Fluent builder: InputMessageBuilder extends the shared MessageBuilder base. Callers chain Create, AddParam, BuildMessage, and Send. The builder fixes the verb and subject at creation and adds the subject as a param automatically.
  • C# events: ClickDetector.OnClick and DoubleClickDetector.OnDoubleClick are plain Action events. InputManager subscribes to them in its constructor, so each detector stays unaware of the message system.
  • Flow controller registration: InputFlowController owns the Input domain. It registers its command handler with the command bus through its base class, and it registers InputManager with the update system.
  • Per-frame tick: InputManager implements IUpdateable. The update system calls OnUpdate every frame.
  • Compile-time platform selection: The UNITY_ANDROID define chooses between HandleTouch and HandleMouse. Only one input path is compiled per platform.

Connections to other systems

  • Update system: InputFlowController.Init creates InputManager and sends it through UpdateCommandFactory.RegisterUpdatable. The update system then calls OnUpdate each frame.
  • Flow and command system: InputFlowController derives from FlowController and returns Domain.Input. Commands addressed to that domain reach HandleCommand, which only logs a warning.
  • Message system: InputMessageBuilder creates an Event on Domain.Input. Send passes it to the shared message dispatch.
  • Params system: InputParamKeys uses the shared ParamKey<T> type. Each event stores its data in Params, read by listeners with Get or TryGet.
  • Contracts: Domain.Input identifies the domain. The verb and subject enums are local to this system.

Key terms

  • Verb: what happened, from InputEventVerb (for example Pressed, Clicked, Started).
  • Subject: what the event is about, from InputSubject: Pointer or Drag.
  • Press: a button-down (mouse) or TouchPhase.Began (touch).
  • Click: a press and release that finish within InputConstants.ClickThreshold seconds, with no drag in between.
  • Double-click: two presses within InputConstants.DoubleClickTime seconds.
  • Drag: a press whose pointer moves more than InputConstants.DragThreshold pixels from the press position.

Event and data flow

Each frame, InputManager.OnUpdate runs the platform path. For a mouse press, the code does the following, in order:

  1. Store the press position and clear the drag flag.
  2. Send a Pressed event with the subject Pointer.
  3. Call ClickDetector.OnPressed, which records the time.
  4. Raycast against the EventSystem. If the hit object or its parents have IInteractable components, call OnInteraction on each.
  5. Call DoubleClickDetector.RegisterClick with Time.time.

While the button is held, the code sends a Held event each frame. When the pointer moves past the drag threshold, the code sends Started with the subject Drag, then calls Reset on both detectors. Resetting the click detector prevents a click from being raised for a drag that ends quickly.

On release, the code calls ClickDetector.OnReleased, which raises Clicked only if the press was short enough and no drag cancelled it. Then the code sends Released. If a drag was active, it also sends Ended with the subject Drag.

Double-click detection runs on press, not release. The second press that falls inside the window raises DoubleClicked, which then resets. Click and double-click are independent, so a quick double tap can produce Clicked on each release and DoubleClicked on the second press.

Touch follows the same pattern, but it reads only touch index 0 and handles Began, Moved, Stationary, and Ended. Touch sends Held for Moved and Stationary, and it does not send Moved events. The touch path has no Canceled case, so a canceled touch leaves the press and drag state as it was.

Timing notes

ClickDetector and DoubleClickDetector use Time.time. Unity's Time.time is scaled time, so gesture timing stops advancing while Time.timeScale is zero.