From 08ea2c489a027928e1e567a81d90da8c63327ada Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 12 Apr 2026 22:25:38 +0000 Subject: [PATCH 1/2] #2106 fix: show dialog when using in-app keyboard switcher to disable auto-switch When the user taps the "Choose keyboard" menu item on the home screen and the automatic keyboard switching feature is enabled, show a dialog warning that auto-switch will be disabled. If the user confirms, the feature is turned off and the IME picker is opened. This prevents KeyMapper immediately and silently switching back to its own IME after the user has deliberately selected another keyboard. https://claude.ai/code/session_01AdijnJnpbsCqPDTYobwnLa --- .../keyevent/FixKeyEventActionDelegate.kt | 5 +++++ .../base/home/KeyMapListViewModel.kt | 22 ++++++++++++++++++- base/src/main/res/values/strings.xml | 3 +++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/FixKeyEventActionDelegate.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/FixKeyEventActionDelegate.kt index c555f586f9..2336ba4dc5 100644 --- a/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/FixKeyEventActionDelegate.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/FixKeyEventActionDelegate.kt @@ -63,6 +63,10 @@ class FixKeyEventActionDelegateImpl @Inject constructor( preferenceRepository.get(Keys.keyEventActionsUseSystemBridge) .map { it ?: PreferenceDefaults.KEY_EVENT_ACTIONS_USE_SYSTEM_BRIDGE } + override val isAutoSwitchImeEnabled: Flow = + preferenceRepository.get(Keys.changeImeOnInputFocus) + .map { it ?: PreferenceDefaults.CHANGE_IME_ON_INPUT_FOCUS } + private val showBottomSheet: MutableStateFlow = MutableStateFlow(false) @OptIn(ExperimentalCoroutinesApi::class) @@ -166,6 +170,7 @@ class FixKeyEventActionDelegateImpl @Inject constructor( interface FixKeyEventActionDelegate { val fixKeyEventActionState: StateFlow + val isAutoSwitchImeEnabled: Flow fun showFixKeyEventActionBottomSheet() fun dismissFixKeyEventActionBottomSheet() diff --git a/base/src/main/java/io/github/sds100/keymapper/base/home/KeyMapListViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/home/KeyMapListViewModel.kt index 414dfc2ac2..e7086c2439 100644 --- a/base/src/main/java/io/github/sds100/keymapper/base/home/KeyMapListViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/home/KeyMapListViewModel.kt @@ -907,7 +907,27 @@ class KeyMapListViewModel( } fun showInputMethodPicker() { - showInputMethodPickerUseCase.show(fromForeground = true) + coroutineScope.launch { + val autoSwitchEnabled = isAutoSwitchImeEnabled.first() + + if (autoSwitchEnabled) { + val response = showDialog( + "disable_auto_switch_ime_dialog", + DialogModel.Alert( + title = getString(R.string.dialog_title_disable_auto_switch_ime), + message = getString(R.string.dialog_message_disable_auto_switch_ime), + positiveButtonText = getString(R.string.pos_ok), + negativeButtonText = getString(R.string.neg_cancel), + ), + ) + + if (response != DialogResponse.POSITIVE) return@launch + + onAutoSwitchImeCheckedChange(false) + } + + showInputMethodPickerUseCase.show(fromForeground = true) + } } private suspend fun onAutomaticBackupResult(result: KMResult<*>) { diff --git a/base/src/main/res/values/strings.xml b/base/src/main/res/values/strings.xml index 9bb7dc5d2f..8f820b1af2 100644 --- a/base/src/main/res/values/strings.xml +++ b/base/src/main/res/values/strings.xml @@ -1901,4 +1901,7 @@ Open Discord Email us + Disable auto-switch keyboard? + Choosing a keyboard here will disable the automatic keyboard switching feature. You can re-enable it in Settings. + From bfb0d8a2fe1b8d288eeff1f6f570bb504348b026 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 13 Apr 2026 08:21:45 +0000 Subject: [PATCH 2/2] #2106 refactor: move auto-switch IME logic to ShowInputMethodPickerUseCase Move isAutoSwitchImeEnabled flow and disableAutoSwitch() out of FixKeyEventActionDelegate (where they don't belong) and into ShowInputMethodPickerUseCase which owns all IME picker concerns. KeyMapListViewModel now reads/writes through the use case. https://claude.ai/code/session_01AdijnJnpbsCqPDTYobwnLa --- .../keyevent/FixKeyEventActionDelegate.kt | 5 ----- .../keymapper/base/home/KeyMapListViewModel.kt | 4 ++-- .../inputmethod/ShowInputMethodPickerUseCase.kt | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/FixKeyEventActionDelegate.kt b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/FixKeyEventActionDelegate.kt index 2336ba4dc5..c555f586f9 100644 --- a/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/FixKeyEventActionDelegate.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/actions/keyevent/FixKeyEventActionDelegate.kt @@ -63,10 +63,6 @@ class FixKeyEventActionDelegateImpl @Inject constructor( preferenceRepository.get(Keys.keyEventActionsUseSystemBridge) .map { it ?: PreferenceDefaults.KEY_EVENT_ACTIONS_USE_SYSTEM_BRIDGE } - override val isAutoSwitchImeEnabled: Flow = - preferenceRepository.get(Keys.changeImeOnInputFocus) - .map { it ?: PreferenceDefaults.CHANGE_IME_ON_INPUT_FOCUS } - private val showBottomSheet: MutableStateFlow = MutableStateFlow(false) @OptIn(ExperimentalCoroutinesApi::class) @@ -170,7 +166,6 @@ class FixKeyEventActionDelegateImpl @Inject constructor( interface FixKeyEventActionDelegate { val fixKeyEventActionState: StateFlow - val isAutoSwitchImeEnabled: Flow fun showFixKeyEventActionBottomSheet() fun dismissFixKeyEventActionBottomSheet() diff --git a/base/src/main/java/io/github/sds100/keymapper/base/home/KeyMapListViewModel.kt b/base/src/main/java/io/github/sds100/keymapper/base/home/KeyMapListViewModel.kt index e7086c2439..6a2100b5a0 100644 --- a/base/src/main/java/io/github/sds100/keymapper/base/home/KeyMapListViewModel.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/home/KeyMapListViewModel.kt @@ -908,7 +908,7 @@ class KeyMapListViewModel( fun showInputMethodPicker() { coroutineScope.launch { - val autoSwitchEnabled = isAutoSwitchImeEnabled.first() + val autoSwitchEnabled = showInputMethodPickerUseCase.isAutoSwitchImeEnabled.first() if (autoSwitchEnabled) { val response = showDialog( @@ -923,7 +923,7 @@ class KeyMapListViewModel( if (response != DialogResponse.POSITIVE) return@launch - onAutoSwitchImeCheckedChange(false) + showInputMethodPickerUseCase.disableAutoSwitch() } showInputMethodPickerUseCase.show(fromForeground = true) diff --git a/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ShowInputMethodPickerUseCase.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ShowInputMethodPickerUseCase.kt index 38caa71748..d2f2e6c846 100644 --- a/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ShowInputMethodPickerUseCase.kt +++ b/base/src/main/java/io/github/sds100/keymapper/base/system/inputmethod/ShowInputMethodPickerUseCase.kt @@ -1,16 +1,33 @@ package io.github.sds100.keymapper.base.system.inputmethod +import io.github.sds100.keymapper.data.Keys +import io.github.sds100.keymapper.data.PreferenceDefaults +import io.github.sds100.keymapper.data.repositories.PreferenceRepository import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map class ShowInputMethodPickerUseCaseImpl @Inject constructor( private val inputMethodAdapter: InputMethodAdapter, + private val preferenceRepository: PreferenceRepository, ) : ShowInputMethodPickerUseCase { + override val isAutoSwitchImeEnabled: Flow = + preferenceRepository.get(Keys.changeImeOnInputFocus) + .map { it ?: PreferenceDefaults.CHANGE_IME_ON_INPUT_FOCUS } + + override fun disableAutoSwitch() { + preferenceRepository.set(Keys.changeImeOnInputFocus, false) + } + override fun show(fromForeground: Boolean) { inputMethodAdapter.showImePicker(fromForeground = fromForeground) } } interface ShowInputMethodPickerUseCase { + val isAutoSwitchImeEnabled: Flow + + fun disableAutoSwitch() fun show(fromForeground: Boolean) }