---
title: "performIndirectPointerInput"
description: "Executes an indirect pointer gesture globally, targeting the currently focused Compose UI (from root to the focused node)."
type: "function"
lastmod: "2026-05-08T01:17:01.147027Z"
---
## API Reference

### performIndirectPointerInput

> Source set: Common

```kotlin
fun SemanticsNodeInteractionsProvider.performIndirectPointerInput(
    indirectPointerEventPrimaryDirectionalMotionAxis:
        IndirectPointerEventPrimaryDirectionalMotionAxis,
    inputDeviceSize: IntSize,
    block: IndirectPointerInjectionScope.() -> Unit,
)
```

Executes an indirect pointer gesture globally, targeting the currently focused Compose UI (from
root to the focused node).

This API requires an active focus state meaning developers need to request focus to the component
or a child of the component via [SemanticsNodeInteraction.requestFocus()](/jetpack-compose/androidx.compose.ui/ui-test/classes/SemanticsNodeInteraction) before calling this
function. If no component is currently focused, this will throw an `AssertionError`.

If there are multiple Compose roots present, this action will target the first focused root.

Indirect pointer input events are touch events that are from an external touchpad whose
coordinates are not tied to the screen coordinates.

These events are dispatched through the focused tree, and components will only receive these
events if they are focused, or an ancestor of a focused item.

The gesture doesn't need to be complete and can be resumed in a later invocation of
`performIndirectPointerInput { ... }`. The event time is initialized to the current time of the
[MainTestClock](/jetpack-compose/androidx.compose.ui/ui-test/interfaces/MainTestClock).

Be aware that if you split a gesture over multiple invocations of `performIndirectPointerInput {
... }`, everything that happens in between will run as if the gesture is still ongoing (imagine a
finger still touching the touchpad).

All events that are injected from the `block` are batched together and sent after `block` is
complete. This method blocks while the events are injected. If an error occurs during execution
of `block` or injection of the events, all (subsequent) events are dropped and the error is
thrown here.

Due to the batching of events, all events in a block are sent together and no recomposition will
take place in between events. Additionally, all events will be generated before any of the events
take effect.

Example of performing a swipe:

Examples of click:

Example of performing a click-and-drag:

#### Parameters

| | |
| --- | --- |
| indirectPointerEventPrimaryDirectionalMotionAxis | The main movement axis (horizontal or vertical) for single-directional scrolling when using the touchpad `inputDeviceSize`. For instance, if the primary axis is set to X, a display prioritizes scrolling its content (both horizontal and vertical containers) based on the device's X-axis movement. Note that this input axis may not correspond directly to the resulting scrolling axis on the display (e.g., X-axis movement causing vertical scrolling). |
| inputDeviceSize | The dimensions of the external indirect pointer input device that provide the boundaries for indirect input. If you go outside these dimensions, the tests will throw an exception. Note: This is not related to the screen coordinates. |
| block | Block of code/events to execute in indirect scope. |

## Code Examples
### indirectPointerInputAssertDuringClick
```kotlin
fun indirectPointerInputAssertDuringClick() {
    // Ensure the node is within the focus path (otherwise, you won't get the event).
    composeTestRule.onNodeWithTag("myComponent").requestFocus()
    composeTestRule.performIndirectPointerInput(
        indirectPointerEventPrimaryDirectionalMotionAxis =
            IndirectPointerEventPrimaryDirectionalMotionAxis.X,
        // Horizontal trackpad
        inputDeviceSize = IntSize(width = 5000, height = 1000),
    ) {
        down(position = Offset(x = inputDeviceCenterX, y = inputDeviceCenterY))
    }
    // Assert some pressed state is visible
    composeTestRule.performIndirectPointerInput(
        indirectPointerEventPrimaryDirectionalMotionAxis =
            IndirectPointerEventPrimaryDirectionalMotionAxis.X,
        // Horizontal trackpad
        inputDeviceSize = IntSize(width = 5000, height = 1000),
    ) {
        up()
    }
}
```
### indirectPointerInputClick
```kotlin
// Click options:
fun indirectPointerInputClick() {
    // Ensure the node is within the focus path (otherwise, you won't get the event).
    composeTestRule.onNodeWithTag("myComponent").requestFocus()
    composeTestRule.performIndirectPointerInput(
        indirectPointerEventPrimaryDirectionalMotionAxis =
            IndirectPointerEventPrimaryDirectionalMotionAxis.X,
        // Horizontal trackpad
        inputDeviceSize = IntSize(width = 5000, height = 1000),
    ) {
        click()
    }
}
```
### indirectPointerInputClickAndDrag
```kotlin
fun indirectPointerInputClickAndDrag() {
    // Ensure the node is within the focus path (otherwise, you won't get the event).
    composeTestRule.onNodeWithTag("myComponent").requestFocus()
    composeTestRule.performIndirectPointerInput(
        indirectPointerEventPrimaryDirectionalMotionAxis =
            IndirectPointerEventPrimaryDirectionalMotionAxis.X,
        // Horizontal trackpad
        inputDeviceSize = IntSize(width = 5000, height = 1000),
    ) {
        click()
        advanceEventTime(durationMillis = 100)
        swipeLeft(startX = inputDeviceRight, endX = inputDeviceLeft)
    }
}
```
### indirectPointerInputSwipeRight
```kotlin
// Swipe options
fun indirectPointerInputSwipeRight() {
    // Ensure your node is within the focus path (otherwise, you won't get the event).
    composeTestRule.onNodeWithTag("myComponent").requestFocus()
    composeTestRule.performIndirectPointerInput(
        indirectPointerEventPrimaryDirectionalMotionAxis =
            IndirectPointerEventPrimaryDirectionalMotionAxis.X,
        // Horizontal trackpad
        inputDeviceSize = IntSize(width = 5000, height = 1000),
    ) {
        swipeRight(startX = inputDeviceLeft, endX = inputDeviceRight)
    }
}
```
