@@ -249,7 +249,7 @@ class KeyMapController(
249249 MutableList (triggers.size) { mutableSetOf<Int >() }
250250
251251 for (triggerIndex in parallelTriggers) {
252- val trigger = triggers[triggerIndex]
252+ val parallelTrigger = triggers[triggerIndex]
253253
254254 otherTriggerLoop@ for (otherTriggerIndex in sequenceTriggers) {
255255 val otherTrigger = triggers[otherTriggerIndex]
@@ -259,7 +259,7 @@ class KeyMapController(
259259 continue @otherTriggerLoop
260260 }
261261
262- for ((keyIndex, key) in trigger .keys.withIndex()) {
262+ for ((keyIndex, key) in parallelTrigger .keys.withIndex()) {
263263 var lastMatchedIndex: Int? = null
264264
265265 for ((otherKeyIndex, otherKey) in otherTrigger.keys.withIndex()) {
@@ -271,7 +271,7 @@ class KeyMapController(
271271 continue @otherTriggerLoop
272272 }
273273
274- if (keyIndex == trigger .keys.lastIndex) {
274+ if (keyIndex == parallelTrigger .keys.lastIndex) {
275275 sequenceTriggersOverlappingParallelTriggers[triggerIndex].add(
276276 otherTriggerIndex,
277277 )
@@ -489,30 +489,36 @@ class KeyMapController(
489489
490490 private var modifierKeyEventActions: Boolean = false
491491 private var notModifierKeyEventActions: Boolean = false
492- private var keyCodesToImitateUpAction: MutableSet <Int > = mutableSetOf< Int > ()
492+ private var keyCodesToImitateUpAction: MutableSet <Int > = mutableSetOf ()
493493 private var metaStateFromActions: Int = 0
494494 private var metaStateFromKeyEvent: Int = 0
495495
496- private val eventDownTimeMap: MutableMap <Event , Long > = mutableMapOf<Event , Long >()
496+ private val eventDownTimeMap: MutableMap <Event , Long > = mutableMapOf ()
497+
498+ /* *
499+ * This solves issue #1386. This stores the jobs that will wait until the sequence trigger
500+ * times out and check whether the overlapping sequence trigger was indeed triggered.
501+ */
502+ private val performActionsAfterSequenceTriggerTimeout: MutableMap <Int , Job > = mutableMapOf ()
497503
498504 /* *
499505 * The indexes of parallel triggers that didn't have their actions performed because there is a matching trigger but
500506 * for a long-press. These actions should only be performed if the long-press fails, otherwise when the user
501507 * holds down the trigger keys for the long-press trigger, actions from both triggers will be performed.
502508 */
503- private val performActionsOnFailedLongPress: MutableSet <Int > = mutableSetOf< Int > ()
509+ private val performActionsOnFailedLongPress: MutableSet <Int > = mutableSetOf ()
504510
505511 /* *
506512 * The indexes of parallel triggers that didn't have their actions performed because there is a matching trigger but
507513 * for a double-press. These actions should only be performed if the double-press fails, otherwise each time the user
508514 * presses the keys for the double press, actions from both triggers will be performed.
509515 */
510- private val performActionsOnFailedDoublePress: MutableSet <Int > = mutableSetOf< Int > ()
516+ private val performActionsOnFailedDoublePress: MutableSet <Int > = mutableSetOf ()
511517
512518 /* *
513519 * Maps jobs to perform an action after a long press to their corresponding parallel trigger index
514520 */
515- private val parallelTriggerLongPressJobs: SparseArrayCompat <Job > = SparseArrayCompat < Job > ()
521+ private val parallelTriggerLongPressJobs: SparseArrayCompat <Job > = SparseArrayCompat ()
516522
517523 /* *
518524 * Keys that are detected through an input method will potentially send multiple DOWN key events
@@ -849,31 +855,63 @@ class KeyMapController(
849855 mappedToParallelTriggerAction = true
850856 parallelTriggersAwaitingReleaseAfterBeingTriggered[triggerIndex] = true
851857
852- val actionKeys = triggerActions[triggerIndex]
858+ // See issue #1386.
859+ val overlappingSequenceTrigger =
860+ sequenceTriggersOverlappingParallelTriggers[triggerIndex]
861+ // Only consider the sequence triggers where this
862+ // short press trigger has been already pressed
863+ // or will be pressed next.
864+ .filter {
865+ for (i in 0 .. (lastMatchedEventIndices[it] + 1 )) {
866+ val matchingEvent = triggers[it].matchingEventAtIndex(
867+ event.withShortPress,
868+ i,
869+ )
870+
871+ if (matchingEvent) {
872+ return @filter true
873+ }
874+ }
875+
876+ return @filter false
877+ }
878+ .maxByOrNull { sequenceTriggerTimeout(triggers[it]) }
879+
880+ if (overlappingSequenceTrigger == null ) {
881+ val actionKeys = triggerActions[triggerIndex]
853882
854- actionKeys.forEach { actionKey ->
855- val action = actionMap[actionKey] ? : return @forEach
883+ actionKeys.forEach { actionKey ->
884+ val action = actionMap[actionKey] ? : return @forEach
856885
857- if (action.data is ActionData .InputKeyEvent ) {
858- val actionKeyCode = action.data.keyCode
886+ if (action.data is ActionData .InputKeyEvent ) {
887+ val actionKeyCode = action.data.keyCode
859888
860- if (isModifierKey(actionKeyCode)) {
861- val actionMetaState =
862- InputEventUtils .modifierKeycodeToMetaState(actionKeyCode)
863- metaStateFromActions =
864- metaStateFromActions.withFlag(actionMetaState)
889+ if (isModifierKey(actionKeyCode)) {
890+ val actionMetaState =
891+ InputEventUtils .modifierKeycodeToMetaState(actionKeyCode)
892+ metaStateFromActions =
893+ metaStateFromActions.withFlag(actionMetaState)
894+ }
865895 }
866- }
867896
868- detectedShortPressTriggers.add(triggerIndex)
897+ detectedShortPressTriggers.add(triggerIndex)
869898
870- val vibrateDuration = when {
871- trigger.vibrate -> vibrateDuration(trigger)
872- forceVibrate.value -> defaultVibrateDuration.value
873- else -> - 1L
899+ val vibrateDuration = when {
900+ trigger.vibrate -> vibrateDuration(trigger)
901+ forceVibrate.value -> defaultVibrateDuration.value
902+ else -> - 1L
903+ }
904+
905+ vibrateDurations.add(vibrateDuration)
874906 }
907+ } else {
908+ performActionsAfterSequenceTriggerTimeout[triggerIndex]?.cancel()
875909
876- vibrateDurations.add(vibrateDuration)
910+ performActionsAfterSequenceTriggerTimeout[triggerIndex] =
911+ performActionsAfterSequenceTriggerTimeout(
912+ triggerIndex,
913+ overlappingSequenceTrigger,
914+ )
877915 }
878916 }
879917 }
@@ -1443,14 +1481,14 @@ class KeyMapController(
14431481 metaStateFromKeyEvent = 0
14441482 keyCodesToImitateUpAction = mutableSetOf ()
14451483
1446- parallelTriggerLongPressJobs.valueIterator().forEach {
1447- it.cancel()
1448- }
1449-
1484+ parallelTriggerLongPressJobs.valueIterator().forEach { it.cancel() }
14501485 parallelTriggerLongPressJobs.clear()
14511486
14521487 parallelTriggerActionPerformers.values.forEach { it.reset() }
14531488 sequenceTriggerActionPerformers.values.forEach { it.reset() }
1489+
1490+ performActionsAfterSequenceTriggerTimeout.forEach { (_, job) -> job.cancel() }
1491+ performActionsAfterSequenceTriggerTimeout.clear()
14541492 }
14551493
14561494 /* *
@@ -1499,6 +1537,40 @@ class KeyMapController(
14991537 return detectedTriggerIndexes.isNotEmpty()
15001538 }
15011539
1540+ /* *
1541+ * For parallel triggers only.
1542+ */
1543+ private fun performActionsAfterSequenceTriggerTimeout (
1544+ triggerIndex : Int ,
1545+ sequenceTriggerIndex : Int ,
1546+ ) = coroutineScope.launch {
1547+ val timeout = sequenceTriggerTimeout(triggers[sequenceTriggerIndex])
1548+
1549+ delay(timeout)
1550+
1551+ // If it equals -1 then it means the sequence trigger was triggered
1552+ // and it reset the counter.
1553+ if (lastMatchedEventIndices[sequenceTriggerIndex] == - 1 ) {
1554+ return @launch
1555+ }
1556+
1557+ parallelTriggerActionPerformers[triggerIndex]?.onTriggered(
1558+ calledOnTriggerRelease = true ,
1559+ metaState = metaStateFromActions.withFlag(metaStateFromKeyEvent),
1560+ )
1561+
1562+ if (triggers[triggerIndex].vibrate ||
1563+ forceVibrate.value ||
1564+ triggers[triggerIndex].longPressDoubleVibration
1565+ ) {
1566+ useCase.vibrate(vibrateDuration(triggers[triggerIndex]))
1567+ }
1568+
1569+ if (triggers[triggerIndex].showToast) {
1570+ useCase.showTriggeredToast()
1571+ }
1572+ }
1573+
15021574 private fun encodeActionList (actions : List <KeyMapAction >): IntArray = actions.map { getActionKey(it) }.toIntArray()
15031575
15041576 /* *
0 commit comments