| # Mozart Input system |
| |
| This document describes how the input system works inside Mozart. |
| |
| ## Devices |
| |
| Zircon provides access to devices through the file system under |
| `/dev/class/input`. Those are HID devices and there are associated ioctls to |
| retrieve the description report and simple reads on those devices will return |
| the event reports. |
| |
| ## HID Reports to `InputEvent`. |
| |
| When launching an application through the sysmgr process, |
| `src/root_presenter` is launched as a singleton to create the root of the |
| `Presentation`. When starting, root_presenter starts `src/input_reader` which |
| will monitor the `/dev/class/input` directory for new devices and discover |
| existing devices if they are already present. |
| |
| Any time a device is detected (or discovered the first time) `InputReader` reads |
| the HID description report and converts it into a DeviceDescriptor. |
| |
| That device is then registered through the `InputDeviceRegistry` which is |
| implemented by the root presenter `App` class. `App` then notifies any existing |
| `Presentation` of the new device. It also creates a channel for that device in |
| the form of an `InputDevice` which `InputReader` can keep a reference to, to |
| forward events. `Presentation` creates a `DeviceState` (found under `lib/input`) |
| which will be used later in the process. |
| |
| During the initialization of the device, `InputReader` will add the handle |
| corresponding to that device to the list of handles to monitor for activity in |
| its message loop. Whenever activity is detected, it reads the packet and the |
| `InputInterpreter` associated to this device, will convert the report into an |
| `InputReport`. |
| |
| The `InputReport` is forwarded through the `InputDevice` channel created during |
| the registration process to the root presenter `App` which dispatches it to the |
| different `Presentations`. |
| |
| The `DeviceState` held by a `Presentation` will convert the `InputReport` into |
| an `InputEvent`. |
| |
| ## The life of an `InputEvent`. |
| |
| Once an `InputEvent` has been generated by a `DeviceState`, it's forwarded to |
| `src/input_manager`, a `ViewAssociate` dedicated to process input events which |
| implements the `InputDispatcher` service. |
| |
| There is one `InputDispatcherImpl` per view tree. The view tree is owned by |
| `Presentation`. So the `InputEvent` is forwarded to each one of them. |
| |
| An `InputDispatcherImpl` will query the `ViewInspector` service to retrieve the |
| input focus chain. It will then dispatch those events through the chain. It |
| starts at the deepest view in that chain and propagates the event until the |
| `View` says it has handled the event though the |
| `InputConnection::InputListener::OnEvent` method. |
| |
| ## Input Focus. |
| |
| When the `InputEvent` is a touch or mouse down event, `InputDispatcherImpl`, |
| using the `ViewInspector`, runs the `HitTest` on the scene graph. The result |
| contains a tree of nodes that were hit. |
| |
| `InputDispatcherImpl` uses `ViewInspector` to convert this list of nodes into |
| `Views`, at which point it requests in parallel the different views whether they |
| are hit or not and which of their children should be considered for the hit. |
| This is done through the `InputConnection::ViewHitTester` interface. |
| |
| Once all views have responded, `InputDispatcherImpl` reconciles the results |
| walking down the tree from the top and using the answer to which subviews should |
| participate to build a tree of interested parties. For each leaf it will then |
| create focus chain, which is the branch that leads from that leaf to the root. |
| |
| For now `InputDispatcherImpl` picks one of the chain but this will be changed in |
| the future. It then tells the `ViewInspector` which chain is now in focus. |