Skip to content

Commit 07a8da6

Browse files
committed
#1620 enable Key Mapper Basic Input Method without user interaction on Android 13+.
1 parent 14f2216 commit 07a8da6

File tree

13 files changed

+52
-14
lines changed

13 files changed

+52
-14
lines changed

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
_See the changes from previous 3.0 Beta releases as well._
44

5+
## Added
6+
7+
- #1620 enable Key Mapper Basic Input Method without user interaction on Android 13+.
8+
59
## Changed
610

7-
- *Finally* renamed the theme settings after many years. @jambl3r
11+
- *Finally* renamed the theme settings after many years. @jambl3r.
812

913
## Bug fixes
1014

11-
- #1618, #1532, #1590 The Key Mapper keyboard is no longer required for Text actions
15+
- #1618, #1532, #1590 The Key Mapper keyboard is no longer required for Text actions.
1216

1317
## [3.0 Beta 3](https://github.com/sds100/KeyMapper/releases/tag/v3.0.0-beta.3)
1418

app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/KeyMapListViewModel.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,9 @@ class KeyMapListViewModel(
539539
}
540540

541541
fun onEnableGuiKeyboardClick() {
542-
setupGuiKeyboard.enableInputMethod()
542+
coroutineScope.launch {
543+
setupGuiKeyboard.enableInputMethod()
544+
}
543545
}
544546

545547
fun onChooseGuiKeyboardClick() {

app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/trigger/BaseConfigTriggerViewModel.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,9 @@ abstract class BaseConfigTriggerViewModel(
754754
}
755755

756756
fun onEnableGuiKeyboardClick() {
757-
setupGuiKeyboard.enableInputMethod()
757+
coroutineScope.launch {
758+
setupGuiKeyboard.enableInputMethod()
759+
}
758760
}
759761

760762
fun onChooseGuiKeyboardClick() {

app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/trigger/SetupGuiKeyboardUseCase.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class SetupGuiKeyboardUseCaseImpl(
3131
}
3232
}
3333

34-
override fun enableInputMethod() {
34+
override suspend fun enableInputMethod() {
3535
inputMethodAdapter.getInfoByPackageName(KeyMapperImeHelper.KEY_MAPPER_GUI_IME_PACKAGE)
3636
.onSuccess {
3737
inputMethodAdapter.enableIme(it.id)
@@ -54,7 +54,7 @@ interface SetupGuiKeyboardUseCase {
5454
val isInstalled: Flow<Boolean>
5555

5656
val isEnabled: Flow<Boolean>
57-
fun enableInputMethod()
57+
suspend fun enableInputMethod()
5858

5959
val isChosen: Flow<Boolean>
6060
fun chooseInputMethod()

app/src/main/java/io/github/sds100/keymapper/settings/ConfigSettingsUseCase.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class ConfigSettingsUseCaseImpl(
8181
override val connectedInputDevices: StateFlow<State<List<InputDeviceInfo>>>
8282
get() = devicesAdapter.connectedInputDevices
8383

84-
override fun enableCompatibleIme() {
84+
override suspend fun enableCompatibleIme() {
8585
imeHelper.enableCompatibleInputMethods()
8686
}
8787

@@ -190,7 +190,7 @@ interface ConfigSettingsUseCase {
190190
val rerouteKeyEvents: Flow<Boolean>
191191
val isCompatibleImeChosen: Flow<Boolean>
192192
val isCompatibleImeEnabled: Flow<Boolean>
193-
fun enableCompatibleIme()
193+
suspend fun enableCompatibleIme()
194194
suspend fun chooseCompatibleIme(): Result<ImeInfo>
195195
suspend fun showImePicker(): Result<*>
196196

app/src/main/java/io/github/sds100/keymapper/settings/SettingsViewModel.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ class SettingsViewModel(
140140
}
141141

142142
fun onEnableCompatibleImeClick() {
143-
useCase.enableCompatibleIme()
143+
viewModelScope.launch {
144+
useCase.enableCompatibleIme()
145+
}
144146
}
145147

146148
fun resetDefaultMappingOptions() {

app/src/main/java/io/github/sds100/keymapper/system/accessibility/BaseAccessibilityServiceController.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,11 @@ abstract class BaseAccessibilityServiceController(
509509
}
510510

511511
is ServiceEvent.TriggerKeyMap -> triggerKeyMapFromIntent(event.uid)
512+
513+
is ServiceEvent.EnableInputMethod -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
514+
accessibilityService.setInputMethodEnabled(event.imeId, true)
515+
}
516+
512517
else -> Unit
513518
}
514519
}

app/src/main/java/io/github/sds100/keymapper/system/accessibility/IAccessibilityService.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ interface IAccessibilityService {
4949
val rootNode: AccessibilityNodeModel?
5050
val activeWindowPackage: Flow<String?>
5151

52+
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
53+
fun setInputMethodEnabled(imeId: String, enabled: Boolean)
5254
fun hideKeyboard()
5355
fun showKeyboard()
5456
val isKeyboardHidden: Flow<Boolean>

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.accessibilityservice.AccessibilityService
44
import android.accessibilityservice.FingerprintGestureController
55
import android.accessibilityservice.GestureDescription
66
import android.accessibilityservice.GestureDescription.StrokeDescription
7+
import android.annotation.SuppressLint
78
import android.app.ActivityManager
89
import android.content.Intent
910
import android.content.res.Configuration
@@ -566,4 +567,11 @@ class MyAccessibilityService :
566567
inputMethod?.currentInputConnection?.commitText(text, 1, null)
567568
}
568569
}
570+
571+
override fun setInputMethodEnabled(imeId: String, enabled: Boolean) {
572+
@SuppressLint("CheckResult")
573+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
574+
softKeyboardController.setInputMethodEnabled(imeId, enabled)
575+
}
576+
}
569577
}

app/src/main/java/io/github/sds100/keymapper/system/inputmethod/AndroidInputMethodAdapter.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import android.provider.Settings
1313
import android.view.inputmethod.InputMethodManager
1414
import androidx.core.content.ContextCompat
1515
import androidx.core.content.getSystemService
16+
import io.github.sds100.keymapper.Constants
1617
import io.github.sds100.keymapper.system.JobSchedulerHelper
1718
import io.github.sds100.keymapper.system.SettingsUtils
1819
import io.github.sds100.keymapper.system.accessibility.ServiceAdapter
@@ -177,7 +178,7 @@ class AndroidInputMethodAdapter(
177178
}
178179
}
179180

180-
override fun enableIme(imeId: String): Result<*> = enableImeWithoutUserInput(imeId).otherwise {
181+
override suspend fun enableIme(imeId: String): Result<*> = enableImeWithoutUserInput(imeId).otherwise {
181182
try {
182183
val intent = Intent(Settings.ACTION_INPUT_METHOD_SETTINGS)
183184
intent.flags = Intent.FLAG_ACTIVITY_NO_HISTORY or Intent.FLAG_ACTIVITY_NEW_TASK
@@ -189,7 +190,15 @@ class AndroidInputMethodAdapter(
189190
}
190191
}
191192

192-
private fun enableImeWithoutUserInput(imeId: String): Result<*> = suAdapter.execute("ime enable $imeId")
193+
private suspend fun enableImeWithoutUserInput(imeId: String): Result<*> {
194+
return getInfoByPackageName(Constants.PACKAGE_NAME).then { keyMapperImeInfo ->
195+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && imeId == keyMapperImeInfo.id) {
196+
serviceAdapter.send(ServiceEvent.EnableInputMethod(keyMapperImeInfo.id))
197+
} else {
198+
suAdapter.execute("ime enable $imeId")
199+
}
200+
}
201+
}
193202

194203
override suspend fun chooseImeWithoutUserInput(imeId: String): Result<ImeInfo> {
195204
getInfoById(imeId).onSuccess {
@@ -292,7 +301,8 @@ class AndroidInputMethodAdapter(
292301
private fun getChosenImeId(): String = Settings.Secure.getString(ctx.contentResolver, Settings.Secure.DEFAULT_INPUT_METHOD)
293302

294303
private fun getImeId(packageName: String): Result<String> {
295-
val imeId = inputMethodManager.inputMethodList.find { it.packageName == packageName }?.id
304+
val imeId =
305+
inputMethodManager.inputMethodList.find { it.packageName == packageName }?.id
296306

297307
return if (imeId == null) {
298308
Error.InputMethodNotFound(packageName)

0 commit comments

Comments
 (0)