2.11. Input¶
Teleport has a dynamic input model: the server tells the client which inputs it expects, and the client reports their values each frame. Inputs are not hard-coded into the protocol – the server can declare anything from a single boolean button up to dozens of named axes per session.
Reference implementations:
Wire enums —
teleport::core::InputType, typedefInputId(TeleportCore/InputTypes.h).Server declaration —
teleport::core::SetupInputsCommand,teleport::core::InputDefinitionNetPacket.Client mapping —
teleport::client::OpenXR(OpenXR::OnInputsSetupChanged).Client messages —
teleport::core::InputStatesMessage,teleport::core::InputEventsMessage.
2.11.1. Negotiation: SetupInputsCommand¶
SetupInputsCommand is a server-to-client command on the reliable channel. It replaces any previous input definitions wholesale; the new set takes effect immediately. The packet layout is:
[ 1 CommandPayloadType::SetupInputs ]
[ 2 uint16 numInputs ]
repeat numInputs times:
[ 2 InputId inputId ]
[ 1 InputType inputType ]
[ 2 uint16 pathLength ]
[ pathLength bytes UTF-8 path ]
InputIdis a session-unique 16-bit identifier the client must echo in every state and event message.InputTypeis a one-byte bitfield (see below).pathis a regular expression matched against the client-side control path (e.g."/user/hand/left/input/trigger/value"on OpenXR). The client decides which physical control satisfies each regex; multiple controls may match, in which case the client picks one.
Receipt of SetupInputsCommand invalidates all earlier InputId values. Clients should re-bind their controls before sending the next InputStatesMessage.
2.11.2. InputType bitfield¶
InputType is one byte, made of the following flags:
Bit |
Flag |
Meaning |
|---|---|---|
0 |
|
The input fires events, not per-frame state. |
1 |
|
Use only with |
2 |
|
The value is integer (in practice a single bit – pressed / not). |
3 |
|
The value is a normalised float. |
The combinations the protocol uses:
Combination |
Wire meaning |
|---|---|
|
Per-frame boolean reported in |
|
Per-frame float reported in |
|
Edge-triggered boolean reported in |
|
Edge-triggered boolean that also fires on release. |
|
Float-valued event reported in |
Motion events (2D vector, e.g. thumbstick) are encoded as a separate InputEventMotion array on InputEventsMessage. They share the InputId namespace and are matched by id rather than by type bit.
2.11.3. Reporting: InputStatesMessage¶
Sent every frame on the unreliable channel. The header counts how many state inputs the message carries; the order matches the order of declaration in the most recent SetupInputsCommand. The binary bitfield is little-endian and zero-padded to a whole number of bytes.
See Messages from Client to Server for the byte layout.
2.11.4. Reporting: InputEventsMessage¶
Sent on the unreliable channel only when at least one event has fired since the last frame. Carries three independent arrays — binary, analogue, motion — each prefixed by its own uint16 count. eventID is a per-client monotonically-increasing 32-bit identifier the server uses to deduplicate retries.
For ReleaseEvent inputs the client emits two binary events: one with activated == true on press and one with activated == false on release.
2.11.5. Pose stream¶
Controller / head poses are not part of the input system. They are sent through the dedicated ControllerPoses (id 3) and OriginPose (id 8) client messages on the unreliable channel. See Messages from Client to Server for details. SetupInputsCommand need not declare them; the protocol assumes the client has at least a head pose and zero or more controller poses, all expressed in the session’s origin space.
2.11.6. Sequence¶
2.11.7. Operational notes for implementers¶
Servers should send
SetupInputsCommandbefore expecting any state/event traffic; the client otherwise has no way to interpret the bit/float arrays.Clients with no matching control for a declared input must still emit a slot for it –
falsefor binary states,0.0for analogue states. Otherwise the indices in the bitfield/array will not line up with the server’s expectations.InputIdvalues are not stable across sessions; do not cache them.The regex path syntax is implementation-defined. The reference client uses
std::regexagainst OpenXR component paths; non-OpenXR clients should expose an analogous canonical path tree.