Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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 @@ -569,7 +569,11 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
}

if (stepsX != 0) {
val actual = actualSteps(stepsX)
val scaledStepsX = scaleDeleteSwipeDeselectSteps(
stepsX, deleteSwipeLineIndex, deleteSwipeCharOffset,
DELETE_SWIPE_DESELECT_CHAR_MULTIPLIER, DELETE_SWIPE_DESELECT_CHAR_TOLERANCE
)
val actual = actualSteps(scaledStepsX)
// Positive offset: selection start is left of the line start (selected more by swiping left).
// Negative offset: selection start is right of the line start (deselected by swiping right
// after a vertical swipe). It can never go past the position where the swipe started.
Expand Down Expand Up @@ -616,7 +620,11 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
val minIndex = -getWordBoundariesForwards(
deleteSwipeInitialText, deleteSwipeSelectionAnchor(), deleteSwipeLineBase()
).size
deleteSwipeWordIndex = (deleteSwipeWordIndex - stepsX).coerceAtLeast(minIndex)
val scaledStepsX = scaleDeleteSwipeDeselectSteps(
stepsX, deleteSwipeLineIndex, deleteSwipeWordIndex,
DELETE_SWIPE_DESELECT_WORD_MULTIPLIER, DELETE_SWIPE_DESELECT_WORD_TOLERANCE
)
deleteSwipeWordIndex = (deleteSwipeWordIndex - scaledStepsX).coerceAtLeast(minIndex)
}

if (deleteSwipeLineIndex != oldLineIndex || deleteSwipeWordIndex != oldWordIndex) {
Expand Down Expand Up @@ -1047,6 +1055,27 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp

private fun Int.isMetaLock() = this == KeyCode.CTRL_LOCK || this == KeyCode.ALT_LOCK || this == KeyCode.FN_LOCK || this == KeyCode.META_LOCK

/** Chars deselected per horizontal step when swiping right after a (nearly) vertical-only delete swipe. */
internal const val DELETE_SWIPE_DESELECT_CHAR_MULTIPLIER = 4
/** Words deselected per horizontal step when swiping right after a (nearly) vertical-only delete swipe. */
internal const val DELETE_SWIPE_DESELECT_WORD_MULTIPLIER = 2
/** Max chars selected to the left of the line start that still count as "nearly vertical" (slight diagonal). */
internal const val DELETE_SWIPE_DESELECT_CHAR_TOLERANCE = 4
/** Max words selected to the left of the line start that still count as "nearly vertical" (slight diagonal). */
internal const val DELETE_SWIPE_DESELECT_WORD_TOLERANCE = 1

/**
* Rightward steps get larger only after a (nearly) vertical-only swipe: the selection base is on a
* line above the swipe start ([lineIndex] > 0) and at most [tolerance] chars/words were added to the
* left of that line start ([horizontalOffset] <= [tolerance]). In that case the finger is still close
* to the right screen edge (the delete key is on the right) and has little room for the right swipe.
* Unchanged: leftward steps, the first line (no vertical swipe, e.g. horizontal-left then right),
* and sharper diagonals, where the finger already has room and precise control is more useful.
*/
internal fun scaleDeleteSwipeDeselectSteps(
stepsX: Int, lineIndex: Int, horizontalOffset: Int, multiplier: Int, tolerance: Int
): Int = if (stepsX > 0 && lineIndex > 0 && horizontalOffset <= tolerance) stepsX * multiplier else stepsX

internal fun getLineBoundariesBackwards(text: String, endOffset: Int): List<Int> {
val boundaries = mutableListOf<Int>()
boundaries.add(endOffset)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,35 @@ class WordDeleteSwipeTest {
KeyboardActionListenerImpl.getWordBoundariesForwards(text, endOffset, startOffset)
)
}

@Test
fun `rightward step is scaled after a vertical-only swipe`() {
// on a line above the swipe start, nothing selected to the left of the line start
assertEquals(4, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(1, 1, 0, 4, 4))
assertEquals(12, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(3, 2, 0, 4, 4))
// already deselecting inside the line (negative offset)
assertEquals(8, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(2, 1, -5, 4, 4))
}

@Test
fun `rightward step is scaled after a slight diagonal swipe`() {
// up to the tolerance (inclusive) still counts as nearly vertical
assertEquals(4, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(1, 1, 2, 4, 4))
assertEquals(4, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(1, 1, 4, 4, 4))
// word mode: one word to the left is tolerated
assertEquals(2, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(1, 1, 1, 2, 1))
}

@Test
fun `rightward step is not scaled in other cases`() {
// first line, no vertical swipe (e.g. horizontal-left then right)
assertEquals(1, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(1, 0, 0, 4, 4))
assertEquals(1, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(1, 0, 6, 4, 4))
// sharper diagonal: more than the tolerance selected to the left
assertEquals(1, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(1, 1, 5, 4, 4))
assertEquals(1, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(1, 1, 2, 2, 1))
// leftward steps are never scaled
assertEquals(-2, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(-2, 1, 0, 4, 4))
assertEquals(0, KeyboardActionListenerImpl.scaleDeleteSwipeDeselectSteps(0, 1, 0, 4, 4))
}
}
Loading