diff --git a/java/src/org/futo/inputmethod/latin/uix/Action.kt b/java/src/org/futo/inputmethod/latin/uix/Action.kt index 1572fa8a17..6cf4d66149 100644 --- a/java/src/org/futo/inputmethod/latin/uix/Action.kt +++ b/java/src/org/futo/inputmethod/latin/uix/Action.kt @@ -14,6 +14,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.input.key.KeyEvent import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -149,6 +150,14 @@ abstract class ActionWindow { open fun close(): CloseResult { return CloseResult.Default } + + /** + * Called for a hardware key event while this window is open, before the event reaches focused + * composables in the window. This lets a window respond to e.g. a TV remote's D-pad center / + * Enter, where there is no touchscreen to tap the window. Return true to consume the event; + * the default implementation ignores all key events. + */ + open fun onKeyEvent(event: KeyEvent): Boolean = false } interface PersistentActionState { diff --git a/java/src/org/futo/inputmethod/latin/uix/UixManager.kt b/java/src/org/futo/inputmethod/latin/uix/UixManager.kt index 6191a1e09c..74b92ff61b 100644 --- a/java/src/org/futo/inputmethod/latin/uix/UixManager.kt +++ b/java/src/org/futo/inputmethod/latin/uix/UixManager.kt @@ -75,6 +75,7 @@ import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.drawscope.scale import androidx.compose.ui.graphics.drawscope.translate +import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.layout.onGloballyPositioned @@ -808,7 +809,7 @@ class UixManager(private val latinIME: LatinIME) { } val showingAboveKeyboard = !mainKeyboardHidden.value - Column { + Column(Modifier.onPreviewKeyEvent { windowImpl.onKeyEvent(it) }) { Column( Modifier.background( if (showingAboveKeyboard) { diff --git a/java/src/org/futo/inputmethod/latin/uix/actions/VoiceInputAction.kt b/java/src/org/futo/inputmethod/latin/uix/actions/VoiceInputAction.kt index 560e4dad18..b854e6e373 100644 --- a/java/src/org/futo/inputmethod/latin/uix/actions/VoiceInputAction.kt +++ b/java/src/org/futo/inputmethod/latin/uix/actions/VoiceInputAction.kt @@ -13,6 +13,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +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.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics @@ -236,6 +241,22 @@ private class VoiceInputActionWindow( return CloseResult.Default } + override fun onKeyEvent(event: KeyEvent): Boolean { + // On a device driven by a D-pad / remote (e.g. Android TV) there is no touchscreen to tap + // the window to finish, and the D-pad center would otherwise activate the focused "back" + // button in the action bar and cancel dictation. Treat center/enter as a tap on the + // window: finish recognition and submit the result. + return when (event.key) { + Key.DirectionCenter, Key.Enter, Key.NumPadEnter -> { + if (event.type == KeyEventType.KeyUp) { + recognizerView.value?.finish() + } + true + } + else -> false + } + } + private var wasFinished = false private var cancelPlayed = false override fun cancelled() {