The UI Toolkit event system listens to events, coming from the operating system or scripts, and dispatches these events to visual elements using the EventDispatcher
. The event dispatcher determines an appropriate dispatching strategy for each event it sends. Once determined, the dispatcher executes the strategy.
Visual elements, and other supporting classes, implement default behaviors for several events. Sometimes, this involves creating and sending additional events. For example, a MouseMoveEvent
could generate an additional MouseEnterEvent
and a MouseLeaveEvent
. These additional events are placed in a queue and are processed after the current event is completed. For example, the MouseMoveEvent
is completed before processing the MouseEnterEvent
and MouseLeaveEvent
events.
The first task of EventDispatcher.DispatchEvent()
is to find the target of the event.
This is sometimes easy because the event target
property has already been set. However, this is not the case for most events that originate from the operating system.
The target of an event depends on the event type. For mouse events, the target is usually the topmost pickable element, directly under the mouse. For keyboard events, the target is the currently focused element.
When the target is found, it is stored in EventBase.target
which does not change for the duration of the dispatch process. The property Event.currentTarget
is updated to the element that is currently handling the event.
Most mouse events use the picking mode to determine their target. The VisualElement
class has a pickingMode
property which supports the following values:
PickingMode.Position
(default): performs picking based on the position rectangle.PickingMode.Ignore
: prevents picking as the result of a mouse event.You can override the VisualElement.ContainsPoint()
method to perform custom intersection logic.
Sometimes, after a mouse down, an element must capture the mouse position to ensure that all subsequent mouse events are sent exclusively to itself, even when the pointer is no longer hovering over the element. This is typical for a control that reacts to a mouse down and mouse up sequence where a mouse move might occur between the mouse down and the mouse up events. For example, when you click on a button, slider, or a scroll bar.
To capture the mouse, call element.CaptureMouse()
or MouseCaptureController.CaptureMouse()
.
To release the mouse, call MouseCaptureController.ReleaseMouse()
. If another element is already capturing the mouse when you call CaptureMouse()
, the element receives a MouseCaptureOutEvent
and loses the capture.
Only one element in the application can have the capture at any moment. While an element has the capture, it is the target of all subsequent mouse events except mouse wheel events.
Note: This only applies to mouse events that do not have their target already set.
Each UIElement panel has a focus ring that defines the focus order of elements. By default, the focus order of elements is determined by performing a depth-first search (DFS) on the visual element tree. For example, the focus order for the tree depicted below would be F, B, A, D, C, E, G, I, H.
Some events use the focus order to determine which element holds the focus. For example, the target for a keyboard event is the element currently holding the focus.
Use the the focusable
property to control the focusability of element. By default, VisualElements
are not focusable, but some subclasses, such as TextField
, might be focusable by default.
Use the the tabIndex
property to control the focus order as follows (tabIndex
default value of 0) :
tabIndex
is negative, the element is not tabable.tabIndex
is zero, the element keeps its default tab order, as determined by the focus ring algorithm.tabIndex
is positive, the element is placed in front of other elements that either have a zero tabIndex
(tabIndex = 0
) or a higher tabIndex
.After selecting the event target, the dispatcher computes the propagation path of the event. The propagation path is an ordered list of visual elements which receive the event.
The list of elements are obtained by starting at the root of the visual element tree, descending towards the target, and then ascending the tree towards the root.
The first phase of the propagation path descends from the root to the target parent. This is called the trickle down phase.
The last phase of the propagation path ascends from the target parent to the root. This is referred to as the bubble-up phase.
The event target is in the middle of the propagation path.
Most event types are sent to all of the elements along the propagation path. However, some event types skip the bubble-up phase. In addition, some event types are only sent to the event target.
If an element is hidden or disabled, it will not receive events. Events are still propagated to the ancestors and descendants of a hidden or disabled element.
As an event is sent along the propagation path, Event.currentTarget
is updated to the element currently handling the event. This means that within an event callback function, Event.currentTarget
is the element on which the callback was registered and Event.target
is the element on which the event occured.
Each event type has its own dispatch behavior. The following table summarizes the behavior of each event type into three columns:
Trickles down | Bubbles up | Cancellable | |
---|---|---|---|
MouseCaptureOutEvent | ✔ | ✔ | |
MouseCaptureEvent | ✔ | ✔ | |
ChangeEvent | ✔ | ✔ | |
ValidateCommandEvent | ✔ | ✔ | ✔ |
ExecuteCommandEvent | ✔ | ✔ | ✔ |
DragExitedEvent | ✔ | ✔ | |
DragUpdatedEvent | ✔ | ✔ | ✔ |
DragPerformEvent | ✔ | ✔ | ✔ |
DragEnterEvent | ✔ | ||
DragLeaveEvent | ✔ | ||
FocusOutEvent | ✔ | ✔ | |
BlurEvent | ✔ | ||
FocusInEvent | ✔ | ✔ | |
FocusEvent | ✔ | ||
InputEvent | ✔ | ✔ | |
KeyDownEvent | ✔ | ✔ | ✔ |
KeyUpEvent | ✔ | ✔ | ✔ |
GeometryChangedEvent | |||
MouseDownEvent | ✔ | ✔ | ✔ |
MouseUpEvent | ✔ | ✔ | ✔ |
MouseMoveEvent | ✔ | ✔ | ✔ |
ContextClickEvent | ✔ | ✔ | ✔ |
WheelEvent | ✔ | ✔ | ✔ |
MouseEnterEvent | ✔ | ✔ | |
MouseLeaveEvent | ✔ | ✔ | |
MouseEnterWindowEvent | ✔ | ||
MouseLeaveWindowEvent | ✔ | ||
MouseOverEvent | ✔ | ✔ | ✔ |
MouseOutEvent | ✔ | ✔ | ✔ |
ContextualMenuPopulateEvent | ✔ | ✔ | ✔ |
AttachToPanelEvent | |||
DetachFromPanelEvent | |||
TooltipEvent | ✔ | ✔ | |
IMGUIEvent | ✔ | ✔ | ✔ |