Skip to content

Commit 796b5d7

Browse files
committed
#563 fix: send key event action when imitating button presses
1 parent 13baa7e commit 796b5d7

File tree

6 files changed

+179
-55
lines changed

6 files changed

+179
-55
lines changed

app/src/main/java/io/github/sds100/keymapper/service/MyAccessibilityService.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,9 @@ class MyAccessibilityService : AccessibilityService(),
357357
imePackageName = imePackageName,
358358
keyCode = it.keyCode,
359359
metaState = it.metaState,
360-
deviceId = it.deviceId
360+
keyEventAction = it.keyEventAction,
361+
deviceId = it.deviceId,
362+
scanCode = it.scanCode
361363
)
362364
}
363365
}
@@ -508,13 +510,16 @@ class MyAccessibilityService : AccessibilityService(),
508510

509511
if (!AppPreferences.keymapsPaused) {
510512
try {
511-
return mKeymapDetectionDelegate.onKeyEvent(
513+
val consume = mKeymapDetectionDelegate.onKeyEvent(
512514
event.keyCode,
513515
event.action,
514516
event.device.descriptor,
515517
event.device.isExternalCompat,
516518
event.metaState,
517-
event.deviceId)
519+
event.deviceId,
520+
event.scanCode)
521+
522+
return consume
518523
} catch (e: Exception) {
519524
Timber.e(e)
520525
}

app/src/main/java/io/github/sds100/keymapper/util/Event.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ data class PerformAction(val action: Action,
3434
val additionalMetaState: Int = 0,
3535
val keyEventAction: KeyEventAction = KeyEventAction.DOWN_UP) : Event()
3636

37-
class ImitateButtonPress(val keyCode: Int, val metaState: Int = 0, val deviceId: Int = 0) : Event()
37+
data class ImitateButtonPress(
38+
val keyCode: Int,
39+
val metaState: Int = 0,
40+
val deviceId: Int = 0,
41+
val keyEventAction: KeyEventAction,
42+
val scanCode: Int = 0
43+
) : Event()
44+
3845
class ChoosePackage : Event()
3946
class ChooseBluetoothDevice : Event()
4047
class OpenUrl(val url: String) : Event()

app/src/main/java/io/github/sds100/keymapper/util/KeyboardUtils.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,8 @@ object KeyboardUtils {
263263
keyCode: Int,
264264
metaState: Int = 0,
265265
keyEventAction: KeyEventAction = KeyEventAction.DOWN_UP,
266-
deviceId: Int
266+
deviceId: Int,
267+
scanCode: Int = 0
267268
) {
268269
val intentAction = when (keyEventAction) {
269270
KeyEventAction.DOWN -> KEY_MAPPER_INPUT_METHOD_ACTION_INPUT_DOWN
@@ -281,7 +282,7 @@ object KeyboardUtils {
281282

282283
val eventTime = SystemClock.uptimeMillis()
283284

284-
val keyEvent = KeyEvent(eventTime, eventTime, action, keyCode, 0, metaState, deviceId, 0)
285+
val keyEvent = KeyEvent(eventTime, eventTime, action, keyCode, 0, metaState, deviceId, scanCode)
285286

286287
putExtra(KEY_MAPPER_INPUT_METHOD_EXTRA_KEY_EVENT, keyEvent)
287288

app/src/main/java/io/github/sds100/keymapper/util/delegate/KeymapDetectionDelegate.kt

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
506506

507507
private var mModifierKeyEventActions = false
508508
private var mNotModifierKeyEventActions = false
509-
private var mUnmappedKeycodesToConsumeOnUp = mutableSetOf<Int>()
509+
private var keyCodesToImitateUpAction = mutableSetOf<Int>()
510510
private var mMetaStateFromActions = 0
511511
private var mMetaStateFromKeyEvent = 0
512512

@@ -557,7 +557,8 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
557557
descriptor: String,
558558
isExternal: Boolean,
559559
metaState: Int,
560-
deviceId: Int
560+
deviceId: Int,
561+
scanCode: Int = 0
561562
): Boolean {
562563
if (!mDetectKeymaps) return false
563564

@@ -587,8 +588,8 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
587588
}
588589

589590
when (action) {
590-
KeyEvent.ACTION_DOWN -> return onKeyDown(event, deviceId)
591-
KeyEvent.ACTION_UP -> return onKeyUp(event, deviceId)
591+
KeyEvent.ACTION_DOWN -> return onKeyDown(event, deviceId, scanCode)
592+
KeyEvent.ACTION_UP -> return onKeyUp(event, deviceId, scanCode)
592593
}
593594

594595
return false
@@ -597,7 +598,7 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
597598
/**
598599
* @return whether to consume the [KeyEvent].
599600
*/
600-
private fun onKeyDown(event: Event, deviceId: Int): Boolean {
601+
private fun onKeyDown(event: Event, deviceId: Int, scanCode: Int): Boolean {
601602

602603
mEventDownTimeMap[event] = currentTime
603604

@@ -763,17 +764,23 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
763764
}
764765
}
765766

766-
if (mModifierKeyEventActions && !isModifierKeyCode && mMetaStateFromActions != 0
767+
if (mModifierKeyEventActions
768+
&& !isModifierKeyCode
769+
&& mMetaStateFromActions != 0
767770
&& !mappedToParallelTriggerAction) {
768771

769772
consumeEvent = true
770-
mUnmappedKeycodesToConsumeOnUp.add(event.keyCode)
773+
keyCodesToImitateUpAction.add(event.keyCode)
771774

772-
imitateButtonPress.value = ImitateButtonPress(event.keyCode,
773-
mMetaStateFromKeyEvent.withFlag(mMetaStateFromActions), deviceId)
775+
imitateButtonPress.value = ImitateButtonPress(
776+
event.keyCode,
777+
mMetaStateFromKeyEvent.withFlag(mMetaStateFromActions),
778+
deviceId,
779+
KeyEventAction.DOWN,
780+
scanCode)
774781

775782
mCoroutineScope.launch {
776-
repeatImitatingKey(event.keyCode, deviceId)
783+
repeatImitatingKey(event.keyCode, deviceId, scanCode)
777784
}
778785
}
779786

@@ -915,14 +922,15 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
915922
/**
916923
* @return whether to consume the event.
917924
*/
918-
private fun onKeyUp(event: Event, deviceId: Int): Boolean {
925+
private fun onKeyUp(event: Event, deviceId: Int, scanCode: Int): Boolean {
919926
val keyCode = event.keyCode
920927

921928
val downTime = mEventDownTimeMap[event] ?: currentTime
922929
mEventDownTimeMap.remove(event)
923930

924931
var consumeEvent = false
925-
var imitateButtonPress = false
932+
var imitateDownUpKeyEvent = false
933+
var imitateUpKeyEvent = false
926934

927935
var successfulLongPress = false
928936
var successfulDoublePress = false
@@ -940,9 +948,12 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
940948

941949
val imitateKeyAfterDoublePressTimeout = mutableListOf<Long>()
942950

943-
if (mUnmappedKeycodesToConsumeOnUp.contains(keyCode)) {
951+
var metaStateFromActionsToRemove = 0
952+
953+
if (keyCodesToImitateUpAction.contains(keyCode)) {
944954
consumeEvent = true
945-
mUnmappedKeycodesToConsumeOnUp.remove(keyCode)
955+
imitateUpKeyEvent = true
956+
keyCodesToImitateUpAction.remove(keyCode)
946957
}
947958

948959
if (mDetectSequenceDoublePresses) {
@@ -1000,7 +1011,7 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
10001011
successfulLongPress = true
10011012
} else if (mDetectSequenceLongPresses &&
10021013
mLongPressSequenceEvents.any { it.first.matchesEvent(event.withLongPress) }) {
1003-
imitateButtonPress = true
1014+
imitateDownUpKeyEvent = true
10041015
}
10051016

10061017
val encodedEventWithClickType = when {
@@ -1127,12 +1138,12 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
11271138
longPressSingleKeyTriggerJustReleased = true
11281139
}
11291140

1130-
if (!imitateButtonPress) {
1141+
if (!imitateDownUpKeyEvent) {
11311142
if (singleKeyTrigger && !successfulLongPress) {
1132-
imitateButtonPress = true
1143+
imitateDownUpKeyEvent = true
11331144
} else if (lastMatchedIndex > -1 &&
11341145
lastMatchedIndex < mParallelTriggerEvents[triggerIndex].lastIndex) {
1135-
imitateButtonPress = true
1146+
imitateDownUpKeyEvent = true
11361147
}
11371148
}
11381149
}
@@ -1145,6 +1156,7 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
11451156
}
11461157

11471158
mLastMatchedParallelEventIndices[triggerIndex] = lastHeldDownEventIndex
1159+
mMetaStateFromActions = mMetaStateFromActions.minusFlag(metaStateFromActionsToRemove)
11481160

11491161
//cancel repeating action jobs for this trigger
11501162
if (lastHeldDownEventIndex != mParallelTriggerEvents[triggerIndex].lastIndex) {
@@ -1272,18 +1284,32 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
12721284
return@launch
12731285
}
12741286

1275-
this@KeymapDetectionDelegate.imitateButtonPress.value = ImitateButtonPress(keyCode)
1287+
this@KeymapDetectionDelegate.imitateButtonPress.value =
1288+
ImitateButtonPress(keyCode, keyEventAction = KeyEventAction.DOWN_UP, scanCode = scanCode)
12761289
}
12771290
}
12781291
}
12791292
//only imitate a key if an action isn't going to be performed
1280-
else if (imitateButtonPress
1293+
else if ((imitateDownUpKeyEvent || imitateUpKeyEvent)
12811294
&& detectedSequenceTriggerIndexes.isEmpty()
12821295
&& detectedParallelTriggerIndexes.isEmpty()
12831296
&& !shortPressSingleKeyTriggerJustReleased
12841297
&& !mappedToDoublePress) {
12851298

1286-
this.imitateButtonPress.value = ImitateButtonPress(keyCode)
1299+
val keyEventAction = if (imitateUpKeyEvent) {
1300+
KeyEventAction.UP
1301+
} else {
1302+
KeyEventAction.DOWN_UP
1303+
}
1304+
1305+
this.imitateButtonPress.value = ImitateButtonPress(
1306+
keyCode,
1307+
mMetaStateFromKeyEvent.withFlag(mMetaStateFromActions),
1308+
deviceId,
1309+
keyEventAction,
1310+
scanCode)
1311+
1312+
keyCodesToImitateUpAction.remove(event.keyCode)
12871313
}
12881314

12891315
return consumeEvent
@@ -1319,7 +1345,7 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
13191345

13201346
mMetaStateFromActions = 0
13211347
mMetaStateFromKeyEvent = 0
1322-
mUnmappedKeycodesToConsumeOnUp = mutableSetOf()
1348+
keyCodesToImitateUpAction = mutableSetOf()
13231349

13241350
mRepeatJobs.valueIterator().forEach {
13251351
it.forEach { job ->
@@ -1420,12 +1446,16 @@ class KeymapDetectionDelegate(private val mCoroutineScope: CoroutineScope,
14201446
throw Exception("Action $action not in the action map!")
14211447
}
14221448

1423-
private suspend fun repeatImitatingKey(keyCode: Int, deviceId: Int) {
1449+
private suspend fun repeatImitatingKey(keyCode: Int, deviceId: Int, scanCode: Int) {
14241450
delay(400)
14251451

1426-
while (mUnmappedKeycodesToConsumeOnUp.contains(keyCode)) {
1427-
imitateButtonPress.postValue(ImitateButtonPress(keyCode,
1428-
mMetaStateFromKeyEvent.withFlag(mMetaStateFromActions), deviceId))
1452+
while (keyCodesToImitateUpAction.contains(keyCode)) {
1453+
imitateButtonPress.postValue(ImitateButtonPress(
1454+
keyCode,
1455+
mMetaStateFromKeyEvent.withFlag(mMetaStateFromActions),
1456+
deviceId,
1457+
KeyEventAction.DOWN,
1458+
scanCode)) //use down action because this is what Android does
14291459

14301460
delay(50)
14311461
}

0 commit comments

Comments
 (0)