Skip to content

Commit f5351bd

Browse files
committed
Merge branch 'feature/1918-input-key-event-actions-evdev' into develop
2 parents 047f2eb + 858a98d commit f5351bd

File tree

32 files changed

+2085
-634
lines changed

32 files changed

+2085
-634
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- #1915 ask user to remove "adb shell" from Shell command.
88
- #1904 inform the user how to enable the accessibility service with PRO mode or ADB.
99
- #1911 constraint for physical device orientation that ignores auto rotate setting.
10+
- #1918 improve how key event actions are performed with system bridge
1011

1112
## Bug fixes
1213

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.github.sds100.keymapper.base.actions
2+
3+
/**
4+
* Identifies which device triggered the action.
5+
*/
6+
sealed class PerformActionTriggerDevice {
7+
/**
8+
* The action was triggered by an evdev-level input device.
9+
*/
10+
data class Evdev(val deviceId: Int) : PerformActionTriggerDevice()
11+
12+
data object Default : PerformActionTriggerDevice()
13+
}

base/src/main/java/io/github/sds100/keymapper/base/actions/PerformActionsUseCase.kt

Lines changed: 14 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,13 @@ import io.github.sds100.keymapper.common.utils.KMError.SdkVersionTooLow
2828
import io.github.sds100.keymapper.common.utils.KMResult
2929
import io.github.sds100.keymapper.common.utils.Orientation
3030
import io.github.sds100.keymapper.common.utils.Success
31-
import io.github.sds100.keymapper.common.utils.dataOrNull
3231
import io.github.sds100.keymapper.common.utils.firstBlocking
3332
import io.github.sds100.keymapper.common.utils.getWordBoundaries
34-
import io.github.sds100.keymapper.common.utils.ifIsData
3533
import io.github.sds100.keymapper.common.utils.onFailure
3634
import io.github.sds100.keymapper.common.utils.onSuccess
3735
import io.github.sds100.keymapper.common.utils.otherwise
3836
import io.github.sds100.keymapper.common.utils.success
3937
import io.github.sds100.keymapper.common.utils.then
40-
import io.github.sds100.keymapper.common.utils.withFlag
4138
import io.github.sds100.keymapper.data.Keys
4239
import io.github.sds100.keymapper.data.PreferenceDefaults
4340
import io.github.sds100.keymapper.data.repositories.PreferenceRepository
@@ -52,7 +49,6 @@ import io.github.sds100.keymapper.system.devices.DevicesAdapter
5249
import io.github.sds100.keymapper.system.display.DisplayAdapter
5350
import io.github.sds100.keymapper.system.files.FileAdapter
5451
import io.github.sds100.keymapper.system.files.FileUtils
55-
import io.github.sds100.keymapper.system.inputevents.KeyEventUtils
5652
import io.github.sds100.keymapper.system.inputevents.Scancode
5753
import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter
5854
import io.github.sds100.keymapper.system.intents.IntentAdapter
@@ -78,12 +74,9 @@ import kotlin.math.absoluteValue
7874
import kotlinx.coroutines.CoroutineScope
7975
import kotlinx.coroutines.delay
8076
import kotlinx.coroutines.flow.Flow
81-
import kotlinx.coroutines.flow.SharingStarted
82-
import kotlinx.coroutines.flow.StateFlow
8377
import kotlinx.coroutines.flow.filterNotNull
8478
import kotlinx.coroutines.flow.first
8579
import kotlinx.coroutines.flow.map
86-
import kotlinx.coroutines.flow.stateIn
8780
import kotlinx.coroutines.runBlocking
8881
import kotlinx.coroutines.withTimeoutOrNull
8982
import timber.log.Timber
@@ -143,15 +136,19 @@ class PerformActionsUseCaseImpl @AssistedInject constructor(
143136
)
144137
}
145138

146-
private val injectKeyEventsWithSystemBridge: StateFlow<Boolean> =
147-
settingsRepository.get(Keys.keyEventActionsUseSystemBridge)
148-
.map { it ?: PreferenceDefaults.KEY_EVENT_ACTIONS_USE_SYSTEM_BRIDGE }
149-
.stateIn(coroutineScope, SharingStarted.Eagerly, false)
139+
private val performKeyEventActionDelegate: PerformKeyEventActionDelegate =
140+
PerformKeyEventActionDelegate(
141+
coroutineScope,
142+
settingsRepository,
143+
inputEventHub,
144+
devicesAdapter,
145+
)
150146

151147
override suspend fun perform(
152148
action: ActionData,
153149
inputEventAction: InputEventAction,
154150
keyMetaState: Int,
151+
device: PerformActionTriggerDevice,
155152
) {
156153
/**
157154
* Is null if the action is being performed asynchronously
@@ -172,48 +169,12 @@ class PerformActionsUseCaseImpl @AssistedInject constructor(
172169
}
173170

174171
is ActionData.InputKeyEvent -> {
175-
val deviceId: Int = getDeviceIdForKeyEventAction(action)
176-
177-
// See issue #1683. Some apps ignore key events which do not have a source.
178-
val source = when {
179-
KeyEventUtils.isDpadKeyCode(action.keyCode) -> InputDevice.SOURCE_DPAD
180-
KeyEventUtils.isGamepadButton(action.keyCode) -> InputDevice.SOURCE_GAMEPAD
181-
else -> InputDevice.SOURCE_KEYBOARD
182-
}
183-
184-
val firstInputAction = if (inputEventAction == InputEventAction.UP) {
185-
KeyEvent.ACTION_UP
186-
} else {
187-
KeyEvent.ACTION_DOWN
188-
}
189-
190-
val model = InjectKeyEventModel(
191-
keyCode = action.keyCode,
192-
action = firstInputAction,
193-
metaState = keyMetaState.withFlag(action.metaState),
194-
deviceId = deviceId,
195-
source = source,
196-
repeatCount = 0,
197-
scanCode = 0,
172+
result = performKeyEventActionDelegate.perform(
173+
action,
174+
inputEventAction,
175+
keyMetaState,
176+
device,
198177
)
199-
200-
if (inputEventAction == InputEventAction.DOWN_UP) {
201-
result = inputEventHub.injectKeyEvent(
202-
model,
203-
useSystemBridgeIfAvailable = injectKeyEventsWithSystemBridge.value,
204-
)
205-
.then {
206-
inputEventHub.injectKeyEvent(
207-
model.copy(action = KeyEvent.ACTION_UP),
208-
useSystemBridgeIfAvailable = injectKeyEventsWithSystemBridge.value,
209-
)
210-
}
211-
} else {
212-
result = inputEventHub.injectKeyEvent(
213-
model,
214-
useSystemBridgeIfAvailable = injectKeyEventsWithSystemBridge.value,
215-
)
216-
}
217178
}
218179

219180
is ActionData.PhoneCall -> {
@@ -1108,53 +1069,6 @@ class PerformActionsUseCaseImpl @AssistedInject constructor(
11081069
.map { it ?: PreferenceDefaults.HOLD_DOWN_DURATION }
11091070
.map { it.toLong() }
11101071

1111-
private fun getDeviceIdForKeyEventAction(action: ActionData.InputKeyEvent): Int {
1112-
if (action.device?.descriptor == null) {
1113-
// automatically select a game controller as the input device for game controller key events
1114-
1115-
if (KeyEventUtils.isGamepadKeyCode(action.keyCode)) {
1116-
devicesAdapter.connectedInputDevices.value.ifIsData { inputDevices ->
1117-
val device = inputDevices.find { it.isGameController }
1118-
1119-
if (device != null) {
1120-
return device.id
1121-
}
1122-
}
1123-
}
1124-
1125-
return 0
1126-
}
1127-
1128-
val inputDevices = devicesAdapter.connectedInputDevices.value
1129-
1130-
val devicesWithSameDescriptor =
1131-
inputDevices.dataOrNull()
1132-
?.filter { it.descriptor == action.device.descriptor }
1133-
?: emptyList()
1134-
1135-
if (devicesWithSameDescriptor.isEmpty()) {
1136-
return -1
1137-
}
1138-
1139-
if (devicesWithSameDescriptor.size == 1) {
1140-
return devicesWithSameDescriptor[0].id
1141-
}
1142-
1143-
/*
1144-
if there are multiple devices use the device that supports the key
1145-
code. if none do then use the first one
1146-
*/
1147-
val deviceThatHasKey = devicesWithSameDescriptor.singleOrNull {
1148-
devicesAdapter.deviceHasKey(it.id, action.keyCode)
1149-
}
1150-
1151-
val device = deviceThatHasKey
1152-
?: devicesWithSameDescriptor.singleOrNull { it.name == action.device.name }
1153-
?: devicesWithSameDescriptor[0]
1154-
1155-
return device.id
1156-
}
1157-
11581072
private fun closeStatusBarShade(): KMResult<*> {
11591073
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
11601074
return service
@@ -1233,6 +1147,7 @@ interface PerformActionsUseCase {
12331147
action: ActionData,
12341148
inputEventAction: InputEventAction = InputEventAction.DOWN_UP,
12351149
keyMetaState: Int = 0,
1150+
device: PerformActionTriggerDevice = PerformActionTriggerDevice.Default,
12361151
)
12371152

12381153
fun getErrorSnapshot(): ActionErrorSnapshot

0 commit comments

Comments
 (0)