TouchInjectionScope

Interface

Common
@JvmDefaultWithCompatibility
interface TouchInjectionScope : InjectionScope

The receiver scope of the touch input injection lambda from performTouchInput.

The functions in TouchInjectionScope can roughly be divided into two groups: full gestures and individual touch events. The individual touch events are: down, move and friends, up, cancel and advanceEventTime. Full gestures are all the other functions, like click, doubleClick, swipe, etc. These are built on top of the individual events and serve as a good example on how you can build your own full gesture functions.

A touch gesture is started with a down event, followed by a sequence of move events and finally an up event, optionally combined with more sets of down and up events for multi-touch gestures. Most methods accept a pointerId to specify which pointer (finger) the event applies to. Movement can be expressed absolutely with moveTo and updatePointerTo, or relative to the current pointer position with moveBy and updatePointerBy. The moveTo/By methods enqueue an event immediately, while the updatePointerTo/By methods don't. This allows you to update the position of multiple pointers in a single move event for multi-touch gestures. Touch gestures can be cancelled with cancel. All events, regardless the method used, will always contain the current position of all pointers.

The entire event injection state is shared between all perform.*Input methods, meaning you can continue an unfinished touch gesture in a subsequent invocation of performTouchInput or performMultiModalInput. Note however that while the pointer positions are retained across invocation of perform.*Input methods, they are always manipulated in the current node's local coordinate system. That means that two subsequent invocations of performTouchInput on different nodes will report a different currentPosition, even though it is actually the same position on the screen.

All events sent by these methods are batched together and sent as a whole after performTouchInput has executed its code block. Because gestures don't have to be defined all in the same performTouchInput block, keep in mind that while the gesture is not complete, all code you execute in between these blocks will be executed while imaginary fingers are actively touching the screen. The events sent as part of the same batch will not be interrupted by recomposition, however, if a gesture spans multiple performTouchInput blocks it is important to remember that recomposition, layout and drawing could take place during the gesture, which may lead to events being injected into a moving target. As pointer positions are manipulated in the current node's local coordinate system, this could lead to issues caused by the fact that part of the gesture will take effect before the rest of the events have been enqueued.

Example of performing a click:

Example of performing a swipe up:

Example of performing an L-shaped gesture:

Functions

fun currentPosition(pointerId: Int = 0): Offset?

Returns the current position of the given pointerId. The default pointerId is 0. The position is returned in the local coordinate system of the node with which we're interacting. (0, 0) is the top left corner of the node.

fun down(pointerId: Int, position: Offset)

Sends a down event for the pointer with the given pointerId at position on the associated node. The position is in the node's local coordinate system, where (0, 0) is the top left corner of the node.

If no pointers are down yet, this will start a new touch gesture. If a gesture is already in progress, this event is sent at the same timestamp as the last event. If the given pointer is already down, an IllegalArgumentException will be thrown.

Parameters

pointerIdThe id of the pointer, can be any number not yet in use by another pointer
positionThe position of the down event, in the node's local coordinate system
fun down(position: Offset)

Sends a down event for the default pointer at position on the associated node. The position is in the node's local coordinate system, where (0, 0) is the top left corner of the node. The default pointer has pointerId = 0.

If no pointers are down yet, this will start a new touch gesture. If a gesture is already in progress, this event is sent at the same timestamp as the last event. If the default pointer is already down, an IllegalArgumentException will be thrown.

Parameters

positionThe position of the down event, in the node's local coordinate system
fun moveTo(pointerId: Int, position: Offset, delayMillis: Long = eventPeriodMillis)

Sends a move event delayMillis after the last sent event on the associated node, with the position of the pointer with the given pointerId updated to position. The position is in the node's local coordinate system, where (0, 0) is the top left corner of the node.

If the pointer is not yet down, an IllegalArgumentException will be thrown.

Parameters

pointerIdThe id of the pointer to move, as supplied in down
positionThe new position of the pointer, in the node's local coordinate system
delayMillisThe time between the last sent event and this event. eventPeriodMillis by default.
fun moveTo(position: Offset, delayMillis: Long = eventPeriodMillis)

Sends a move event delayMillis after the last sent event on the associated node, with the position of the default pointer updated to position. The position is in the node's local coordinate system, where (0, 0) is the top left corner of the node. The default pointer has pointerId = 0.

If the default pointer is not yet down, an IllegalArgumentException will be thrown.

Parameters

positionThe new position of the pointer, in the node's local coordinate system
delayMillisThe time between the last sent event and this event. eventPeriodMillis by default.
fun updatePointerTo(pointerId: Int, position: Offset)

Updates the position of the pointer with the given pointerId to the given position, but does not send a move event. The move event can be sent with move. The position is in the node's local coordinate system, where (0.px, 0.px) is the top left corner of the node.

If the pointer is not yet down, an IllegalArgumentException will be thrown.

Parameters

pointerIdThe id of the pointer to move, as supplied in down
positionThe new position of the pointer, in the node's local coordinate system
fun moveBy(pointerId: Int, delta: Offset, delayMillis: Long = eventPeriodMillis)

Sends a move event delayMillis after the last sent event on the associated node, with the position of the pointer with the given pointerId moved by the given delta.

If the pointer is not yet down, an IllegalArgumentException will be thrown.

Parameters

pointerIdThe id of the pointer to move, as supplied in down
deltaThe position for this move event, relative to the current position of the pointer. For example, `delta = Offset(10.px, -10.px) will add 10.px to the pointer's x-position, and subtract 10.px from the pointer's y-position.
delayMillisThe time between the last sent event and this event. eventPeriodMillis by default.
fun moveBy(delta: Offset, delayMillis: Long = eventPeriodMillis)

Sends a move event delayMillis after the last sent event on the associated node, with the position of the default pointer moved by the given delta. The default pointer has pointerId = 0.

If the pointer is not yet down, an IllegalArgumentException will be thrown.

Parameters

deltaThe position for this move event, relative to the current position of the pointer. For example, `delta = Offset(10.px, -10.px) will add 10.px to the pointer's x-position, and subtract 10.px from the pointer's y-position.
delayMillisThe time between the last sent event and this event. eventPeriodMillis by default.
fun updatePointerBy(pointerId: Int, delta: Offset)

Updates the position of the pointer with the given pointerId by the given delta, but does not send a move event. The move event can be sent with move.

If the pointer is not yet down, an IllegalArgumentException will be thrown.

Parameters

pointerIdThe id of the pointer to move, as supplied in down
deltaThe position for this move event, relative to the last sent position of the pointer. For example, `delta = Offset(10.px, -10.px) will add 10.px to the pointer's x-position, and subtract 10.px from the pointer's y-position.
fun move(delayMillis: Long = eventPeriodMillis)

Sends a move event delayMillis after the last sent event without updating any of the pointer positions. This can be useful when batching movement of multiple pointers together, which can be done with updatePointerTo and updatePointerBy.

Parameters

delayMillisThe time between the last sent event and this event. eventPeriodMillis by default.
@ExperimentalTestApi
    fun moveWithHistoryMultiPointer(
        relativeHistoricalTimes: List<Long>,
        historicalCoordinates: List<List<Offset>>,
        delayMillis: Long = eventPeriodMillis,
    )

Sends a move event delayMillis after the last sent event without updating any of the pointer positions, while adding the historicalCoordinates at the relativeHistoricalTimes to the move event. This corresponds to the scenario where a touch screen generates touch events quicker than can be dispatched and batches them together.

Parameters

relativeHistoricalTimesTime of each historical event, as a millisecond relative to the time the actual event is sent. For example, -10L means 10ms earlier.
historicalCoordinatesCoordinates of each historical event, in the same coordinate space as moveTo. The outer list must have the same size as the number of pointers in the event, and each inner list must have the same size as relativeHistoricalTimes. The ith pointer is assigned the ith history, with the pointers sorted on ascending pointerId.
delayMillisThe time between the last sent event and this event. eventPeriodMillis by default.
@ExperimentalTestApi
    fun moveWithHistory(
        relativeHistoricalTimes: List<Long>,
        historicalCoordinates: List<Offset>,
        delayMillis: Long = eventPeriodMillis,
    ) =
        moveWithHistoryMultiPointer(
            relativeHistoricalTimes,
            listOf(historicalCoordinates),
            delayMillis,
        )

Sends a move event delayMillis after the last sent event without updating any of the pointer positions, while adding the historicalCoordinates at the relativeHistoricalTimes to the move event. This corresponds to the scenario where a touch screen generates touch events quicker than can be dispatched and batches them together.

This overload is a convenience method for the common case where the gesture only has one pointer.

Parameters

relativeHistoricalTimesTime of each historical event, as a millisecond relative to the time the actual event is sent. For example, -10L means 10ms earlier.
historicalCoordinatesCoordinates of each historical event, in the same coordinate space as moveTo. The list must have the same size as relativeHistoricalTimes.
delayMillisThe time between the last sent event and this event. eventPeriodMillis by default.
fun up(pointerId: Int = 0)

Sends an up event for the pointer with the given pointerId, or the default pointer if pointerId is omitted, on the associated node.

Parameters

pointerIdThe id of the pointer to lift up, as supplied in down
fun cancel(delayMillis: Long = eventPeriodMillis)

Sends a cancel event delayMillis after the last sent event to cancel the current gesture. The cancel event contains the current position of all active pointers.

Parameters

delayMillisThe time between the last sent event and this event. eventPeriodMillis by default.