Skip to content

[Quastion] Changing how the gesture recognition works #171

@Ethran

Description

@Ethran

I was thinking about changing gesture handling from pointerInput to pointerInteropFilter.

pointerInput is the Compose pointer system and it doesn't forward Android MotionEvent objects to lower layers of the app. Because of that, stylus/pen MotionEvent handling in my renderer must be proxied through a MutableSharedFlow today, which feels like the wrong abstraction:

I would like to handle drawing-related MotionEvent (stylus/pen) directly in the rendering class, something like what the OpenGL renderer currently expects:

  • OpenGLRenderer.kt (desired target for raw MotionEvent handling):
    // THIS DOES NOT GET ANY EVENTS, see EditorGestureReceiver.
    @SuppressLint("ClickableViewAccessibility")
    val onTouchListener = View.OnTouchListener { view, event ->
    val point = getStrokePoint(event)
    motionEventPredictor?.record(event)
    if (event.getToolType(0) != MotionEvent.TOOL_TYPE_STYLUS)
    return@OnTouchListener true
    Log.d("MotionEvent", event.toString())
    when (event?.action) {
    MotionEvent.ACTION_DOWN -> {
    // Ask that the input system not batch MotionEvents
    // but instead deliver them as soon as they're available
    view.requestUnbufferedDispatch(event)
    frontBufferRenderer?.renderFrontBufferedLayer(point)
    }
    MotionEvent.ACTION_MOVE -> {
    previousX = currentX
    previousY = currentY
    currentX = event.x
    currentY = event.y
    // Send the short line to front buffered layer: fast rendering
    frontBufferRenderer?.renderFrontBufferedLayer(point)
    }
    MotionEvent.ACTION_UP -> {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
    (event.flags and MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED
    ) {
    frontBufferRenderer?.cancel()
    } else {
    frontBufferRenderer?.commit()
    }
    }
    MotionEvent.ACTION_CANCEL -> {
    frontBufferRenderer?.cancel()
    }
    }
    true
    }
    }

The pointerInteropFilter modifier receives Android MotionEvent and returns a Boolean indicating whether the event was consumed; by returning false you can allow the event to continue to lower-level handlers. That should make it possible to let the renderer (or an Android view) receive raw MotionEvent objects without going through a MutableSharedFlow proxy.

I don't have much Kotlin experience, so if someone knows more about Compose pointer handling (pointerInput vs pointerInteropFilter or maybe there is something even better in this situation) I'd appreciate any guidance. I don't want to start a large redesign unless it's actually the better approach.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions