Skip to content

Commit 46a6938

Browse files
authored
Fixes incorrect input parsing, causing backspace & suggestion issues (#836)
1 parent 24e834b commit 46a6938

6 files changed

Lines changed: 72 additions & 3 deletions

File tree

app/src/main/java/com/urik/keyboard/service/BackspaceHandler.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,10 @@ class BackspaceHandler(
306306
}
307307
}
308308

309-
if (!inputState.isAcceleratedDeletion && !inputState.isUrlOrEmailField) {
309+
if (!inputState.isAcceleratedDeletion &&
310+
!inputState.isUrlOrEmailField &&
311+
!inputState.isSuggestionsDisabled
312+
) {
310313
val remainingText = textBeforeCursor.dropLast(graphemeLength)
311314

312315
if (remainingText.isNotEmpty() && remainingText.last() == '\n') {

app/src/main/java/com/urik/keyboard/service/InputFieldClassifier.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ object InputFieldClassifier {
4646
if (inputClass == InputType.TYPE_CLASS_TEXT) {
4747
val flags = inputType and InputType.TYPE_MASK_FLAGS
4848
val variation = inputType and InputType.TYPE_MASK_VARIATION
49-
if (flags and InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS != 0) return true
49+
if (flags and InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS != 0 &&
50+
flags and InputType.TYPE_TEXT_FLAG_AUTO_CORRECT == 0
51+
) {
52+
return true
53+
}
5054
if (flags and InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE != 0) return true
5155
if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) return true
5256
}

app/src/main/java/com/urik/keyboard/service/SwipeWordHandler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class SwipeWordHandler(
3131

3232
if (inputState.isRawKeyEventField) return
3333

34-
if (inputState.requiresDirectCommit) {
34+
if (inputState.requiresDirectCommit || inputState.isSuggestionsDisabled) {
3535
if (!inputState.isSecureField && !inputState.isTerminalField) {
3636
outputBridge.beginBatchEdit()
3737
try {

app/src/test/java/com/urik/keyboard/service/BackspaceHandlerTest.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,24 @@ class BackspaceHandlerTest {
134134
verify(mockSuggestionPipeline, never()).learnWordAndInvalidateCache(any(), any())
135135
verify(mockSuggestionPipeline, never()).recordWordUsage(any())
136136
}
137+
138+
@Test
139+
fun `backspace in suggestions-disabled field deletes without recomposition`() = runTest(testDispatcher) {
140+
realInputState.isSuggestionsDisabled = true
141+
realInputState.displayBuffer = ""
142+
realInputState.composingRegionStart = -1
143+
whenever(mockOutputBridge.safeGetCursorPosition()).thenReturn(4)
144+
whenever(mockOutputBridge.safeGetTextBeforeCursor(any(), any())).thenReturn("word")
145+
whenever(mockOutputBridge.calculateParagraphBoundedComposingRegion("wor", 3))
146+
.thenReturn(Triple(0, 3, "wor"))
147+
148+
handler.handle()
149+
advanceUntilIdle()
150+
151+
verify(mockOutputBridge, never()).setComposingRegion(any(), any())
152+
assertEquals("", realInputState.displayBuffer)
153+
assertEquals(-1, realInputState.composingRegionStart)
154+
verify(mockSuggestionPipeline, never()).requestSuggestions(any(), any())
155+
verify(mockOutputBridge).deleteSurroundingText(1, 0)
156+
}
137157
}

app/src/test/java/com/urik/keyboard/service/InputFieldClassifierTest.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,25 @@ class InputFieldClassifierTest {
147147
assertTrue(InputFieldClassifier.classify(info).isSuggestionsDisabled)
148148
}
149149

150+
@Test
151+
fun `classify NO_SUGGESTIONS with AUTO_CORRECT isSuggestionsDisabled false`() {
152+
val info = createEditorInfo(
153+
inputFlags = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS or InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
154+
)
155+
assertFalse(InputFieldClassifier.classify(info).isSuggestionsDisabled)
156+
}
157+
158+
@Test
159+
fun `classify instagram message field flags isSuggestionsDisabled false`() {
160+
val info = createEditorInfo(
161+
inputFlags = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS or
162+
InputType.TYPE_TEXT_FLAG_AUTO_CORRECT or
163+
InputType.TYPE_TEXT_FLAG_MULTI_LINE or
164+
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
165+
)
166+
assertFalse(InputFieldClassifier.classify(info).isSuggestionsDisabled)
167+
}
168+
150169
@Test
151170
fun `classify TYPE_TEXT_FLAG_AUTO_COMPLETE isSuggestionsDisabled true`() {
152171
val info = createEditorInfo(inputFlags = InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE)

app/src/test/java/com/urik/keyboard/service/SwipeWordHandlerTest.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
77
import kotlinx.coroutines.flow.MutableStateFlow
88
import kotlinx.coroutines.test.StandardTestDispatcher
99
import kotlinx.coroutines.test.TestScope
10+
import kotlinx.coroutines.test.advanceUntilIdle
11+
import kotlinx.coroutines.test.runTest
1012
import org.junit.After
1113
import org.junit.Assert.assertEquals
1214
import org.junit.Assert.assertTrue
1315
import org.junit.Before
1416
import org.junit.Test
1517
import org.mockito.Mockito.mock
18+
import org.mockito.Mockito.never
1619
import org.mockito.Mockito.verify
1720
import org.mockito.MockitoAnnotations
1821
import org.mockito.kotlin.any
@@ -99,6 +102,26 @@ class SwipeWordHandlerTest {
99102
verify(mockOutputBridge).commitText("hello", 1)
100103
}
101104

105+
@Test
106+
fun `swipe in suggestions-disabled field commits directly without composing region`() = runTest(testDispatcher) {
107+
realInputState.isSuggestionsDisabled = true
108+
whenever(mockOutputBridge.safeGetTextBeforeCursor(1)).thenReturn("")
109+
whenever(mockOutputBridge.safeGetTextBeforeCursor(50)).thenReturn("")
110+
whenever(mockCaseTransformer.applyCasing(any(), any(), any(), any())).thenAnswer { invocation ->
111+
(invocation.arguments[0] as SpellingSuggestion).word
112+
}
113+
114+
handler.handle("hello")
115+
advanceUntilIdle()
116+
117+
verify(mockOutputBridge).commitText("hello", 1)
118+
verify(mockOutputBridge, never()).setComposingText(any(), any())
119+
assertEquals("", realInputState.displayBuffer)
120+
assertEquals(-1, realInputState.composingRegionStart)
121+
verify(mockTextInputProcessor, never()).processWordInput(any(), any())
122+
verify(mockSuggestionPipeline, never()).coordinateStateTransition(any())
123+
}
124+
102125
@Test
103126
fun `empty validated word returns early without side effects`() {
104127
handler.handle("")

0 commit comments

Comments
 (0)