Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial iOS floating cursor support #1312

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,17 @@

package androidx.compose.ui.platform

import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.DpOffset

internal interface IOSSkikoInput {

fun beginFloatingCursor(offset: DpOffset) {}

fun updateFloatingCursor(offset: DpOffset) {}

fun endFloatingCursor() {}

/**
* A Boolean value that indicates whether the text-entry object has any text.
* https://developer.apple.com/documentation/uikit/uikeyinput/1614457-hastext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,33 @@

package androidx.compose.ui.platform

import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Matrix
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.type
import androidx.compose.ui.scene.getConstraintsToFillParent
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.input.CommitTextCommand
import androidx.compose.ui.text.input.EditCommand
import androidx.compose.ui.text.input.EditProcessor
import androidx.compose.ui.text.input.FinishComposingTextCommand
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.ImeOptions
import androidx.compose.ui.text.input.OffsetMapping
import androidx.compose.ui.text.input.PlatformTextInputService
import androidx.compose.ui.text.input.SetComposingRegionCommand
import androidx.compose.ui.text.input.SetComposingTextCommand
import androidx.compose.ui.text.input.SetSelectionCommand
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.asCGRect
import androidx.compose.ui.unit.toDpRect
import androidx.compose.ui.unit.toOffset
import androidx.compose.ui.window.FocusStack
import androidx.compose.ui.window.IntermediateTextInputUIView
import androidx.compose.ui.window.KeyboardEventHandler
Expand All @@ -63,6 +69,7 @@ internal class UIKitTextInputService(
private var currentImeOptions: ImeOptions? = null
private var currentImeActionHandler: ((ImeAction) -> Unit)? = null
private var textUIView: IntermediateTextInputUIView? = null
private var textLayoutResult : TextLayoutResult? = null

/**
* Workaround to prevent calling textWillChange, textDidChange, selectionWillChange, and
Expand Down Expand Up @@ -192,6 +199,25 @@ internal class UIKitTextInputService(
}
}

override fun updateTextLayoutResult(
textFieldValue: TextFieldValue,
offsetMapping: OffsetMapping,
textLayoutResult: TextLayoutResult,
textFieldToRootTransform: (Matrix) -> Unit,
innerTextFieldBounds: Rect,
decorationBoxBounds: Rect
) {
super.updateTextLayoutResult(
textFieldValue,
offsetMapping,
textLayoutResult,
textFieldToRootTransform,
innerTextFieldBounds,
decorationBoxBounds
)
this.textLayoutResult = textLayoutResult
}

private fun handleEnterKey(event: KeyEvent): Boolean {
_tempImeActionIsCalledWithHardwareReturnKey = false
return when (event.type) {
Expand Down Expand Up @@ -332,6 +358,28 @@ internal class UIKitTextInputService(
}

private fun createSkikoInput(value: TextFieldValue) = object : IOSSkikoInput {

private var floatingCursorTranslation : Offset? = null

override fun beginFloatingCursor(offset: DpOffset) {
val cursorPos = getCursorPos() ?: getState()?.selection?.start ?: return
val cursorRect = textLayoutResult?.getCursorRect(cursorPos) ?: return
floatingCursorTranslation = cursorRect.center - offset.toOffset(densityProvider())
}

override fun updateFloatingCursor(offset: DpOffset) {
val translation = floatingCursorTranslation ?: return
val offsetPx = offset.toOffset(densityProvider())
val pos = textLayoutResult
?.getOffsetForPosition(offsetPx + translation) ?: return

sendEditCommand(SetSelectionCommand(pos, pos))
}

override fun endFloatingCursor() {
floatingCursorTranslation = null
}

/**
* A Boolean value that indicates whether the text-entry object has any text.
* https://developer.apple.com/documentation/uikit/uikeyinput/1614457-hastext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@

package androidx.compose.ui.window

import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.EmptyInputTraits
import androidx.compose.ui.platform.IOSSkikoInput
import androidx.compose.ui.platform.SkikoUITextInputTraits
import androidx.compose.ui.platform.TextActions
import androidx.compose.ui.platform.ViewConfiguration
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import kotlinx.cinterop.COpaquePointer
import kotlinx.cinterop.CValue
import kotlinx.cinterop.readValue
Expand Down Expand Up @@ -98,6 +101,18 @@ internal class IntermediateTextInputUIView(

override fun canBecomeFirstResponder() = true

override fun beginFloatingCursorAtPoint(point: CValue<CGPoint>) {
input?.beginFloatingCursor(point.useContents { DpOffset(x.dp, y.dp) })
}

override fun updateFloatingCursorAtPoint(point: CValue<CGPoint>) {
input?.updateFloatingCursor(point.useContents { DpOffset(x.dp, y.dp) })
}

override fun endFloatingCursor() {
input?.endFloatingCursor()
}

override fun pressesBegan(presses: Set<*>, withEvent: UIPressesEvent?) {
keyboardEventHandler?.pressesBegan(presses, withEvent)
super.pressesBegan(presses, withEvent)
Expand Down
Loading