---
title: "TouchInjectionScope"
description: "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][TouchInjectionScope.click], [doubleClick][TouchInjectionScope.doubleClick],
[swipe][TouchInjectionScope.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:"
type: "interface"
---

<div class='type'>Interface</div>


<a id='references'></a>

<div class='sourceset sourceset-common'>Common</div>



```kotlin
@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

```kotlin
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.


```kotlin
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

| | |
| --- | --- |
| pointerId | The id of the pointer, can be any number not yet in use by another pointer |
| position | The position of the down event, in the node's local coordinate system |



```kotlin
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

| | |
| --- | --- |
| position | The position of the down event, in the node's local coordinate system |



```kotlin
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

| | |
| --- | --- |
| pointerId | The id of the pointer to move, as supplied in `down` |
| position | The new position of the pointer, in the node's local coordinate system |
| delayMillis | The time between the last sent event and this event. `eventPeriodMillis` by default. |



```kotlin
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

| | |
| --- | --- |
| position | The new position of the pointer, in the node's local coordinate system |
| delayMillis | The time between the last sent event and this event. `eventPeriodMillis` by default. |



```kotlin
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

| | |
| --- | --- |
| pointerId | The id of the pointer to move, as supplied in `down` |
| position | The new position of the pointer, in the node's local coordinate system |



```kotlin
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

| | |
| --- | --- |
| pointerId | The id of the pointer to move, as supplied in `down` |
| delta | The 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. |
| delayMillis | The time between the last sent event and this event. `eventPeriodMillis` by default. |



```kotlin
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

| | |
| --- | --- |
| delta | The 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. |
| delayMillis | The time between the last sent event and this event. `eventPeriodMillis` by default. |



```kotlin
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

| | |
| --- | --- |
| pointerId | The id of the pointer to move, as supplied in `down` |
| delta | The 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. |



```kotlin
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

| | |
| --- | --- |
| delayMillis | The time between the last sent event and this event. `eventPeriodMillis` by default. |



```kotlin
@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

| | |
| --- | --- |
| relativeHistoricalTimes | Time of each historical event, as a millisecond relative to the time the actual event is sent. For example, -10L means 10ms earlier. |
| historicalCoordinates | Coordinates 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 `i`th pointer is assigned the `i`th history, with the pointers sorted on ascending pointerId. |
| delayMillis | The time between the last sent event and this event. `eventPeriodMillis` by default. |



```kotlin
@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

| | |
| --- | --- |
| relativeHistoricalTimes | Time of each historical event, as a millisecond relative to the time the actual event is sent. For example, -10L means 10ms earlier. |
| historicalCoordinates | Coordinates of each historical event, in the same coordinate space as `moveTo`. The list must have the same size as `relativeHistoricalTimes`. |
| delayMillis | The time between the last sent event and this event. `eventPeriodMillis` by default. |



```kotlin
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

| | |
| --- | --- |
| pointerId | The id of the pointer to lift up, as supplied in `down` |



```kotlin
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

| | |
| --- | --- |
| delayMillis | The time between the last sent event and this event. `eventPeriodMillis` by default. |




## Code Examples

### touchInputClick
```kotlin
fun touchInputClick() {
    composeTestRule.onNodeWithTag("myComponent").performTouchInput { click() }
}
```

### touchInputLShapedGesture
```kotlin
fun touchInputLShapedGesture() {
    composeTestRule.onNodeWithTag("myComponent").performTouchInput {
        down(topLeft)
        moveTo(topLeft + percentOffset(0f, .1f))
        moveTo(topLeft + percentOffset(0f, .2f))
        moveTo(topLeft + percentOffset(0f, .3f))
        moveTo(topLeft + percentOffset(0f, .4f))
        moveTo(centerLeft)
        moveTo(centerLeft + percentOffset(.1f, 0f))
        moveTo(centerLeft + percentOffset(.2f, 0f))
        moveTo(centerLeft + percentOffset(.3f, 0f))
        moveTo(centerLeft + percentOffset(.4f, 0f))
        moveTo(center)
        up()
    }
}
```

### touchInputSwipeUp
```kotlin
fun touchInputSwipeUp() {
    composeTestRule.onNodeWithTag("myComponent").performTouchInput { swipeUp() }
}
```

