From 65d278d907abee3817d73832a3afddd5a3455c9a Mon Sep 17 00:00:00 2001 From: Nehemiah of Zebulun Date: Tue, 29 Aug 2023 21:09:20 +0200 Subject: [PATCH] Progress --- app/src/main/java/net/mezimmah/wkt9/WKT9.kt | 68 ++++--- .../mezimmah/wkt9/inputmode/AlphaInputMode.kt | 177 +++++++++++++++++- .../mezimmah/wkt9/inputmode/WordInputMode.kt | 47 ++--- .../mezimmah/wkt9/keypad/KeyEventResult.kt | 4 +- 4 files changed, 238 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/net/mezimmah/wkt9/WKT9.kt b/app/src/main/java/net/mezimmah/wkt9/WKT9.kt index ebf2370..0d398ae 100644 --- a/app/src/main/java/net/mezimmah/wkt9/WKT9.kt +++ b/app/src/main/java/net/mezimmah/wkt9/WKT9.kt @@ -174,10 +174,10 @@ class WKT9: InputMethodService() { when (inputType) { InputType.TYPE_CLASS_DATETIME, InputType.TYPE_CLASS_NUMBER, - InputType.TYPE_CLASS_PHONE -> enableInputMode(WKT9InputMode.NUMERIC, inputType) + InputType.TYPE_CLASS_PHONE -> enableInputMode(WKT9InputMode.NUMERIC) InputType.TYPE_CLASS_TEXT -> - if (lastInputMode == WKT9InputMode.ALPHA) enableInputMode(WKT9InputMode.ALPHA, inputType) - else enableInputMode(WKT9InputMode.WORD, inputType) + if (lastInputMode == WKT9InputMode.ALPHA) enableInputMode(WKT9InputMode.ALPHA) + else enableInputMode(WKT9InputMode.WORD) else -> Log.d(tag, "Mode without input...") } @@ -254,12 +254,9 @@ class WKT9: InputMethodService() { } // Todo: inputType - private fun enableInputMode(mode: WKT9InputMode, inputType: Int) { + private fun enableInputMode(mode: WKT9InputMode) { lastInputMode = mode - if (inputType.and(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) - Log.d(tag, "InputConnection expects email address") - inputMode = when(mode) { WKT9InputMode.ALPHA -> alphaInputMode WKT9InputMode.NUMERIC -> numericInputMode @@ -277,6 +274,24 @@ class WKT9: InputMethodService() { } else false } + @SuppressLint("DiscouragedApi") + private fun getIconResource(): Int { + val name = inputMode?.let { + val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager + val inputMethodSubtype = inputMethodManager.currentInputMethodSubtype + + it.mode + .plus("_") + .plus(inputMethodSubtype.languageTag) + .plus("_") + .plus(inputStatus.toString()) + .replace("-", "_") + .lowercase() + } ?: "wkt9" + + return resources.getIdentifier(name, "drawable", packageName) + } + private fun goHome() { with(Intent(Intent.ACTION_MAIN)) { this.addCategory(Intent.CATEGORY_HOME) @@ -314,6 +329,7 @@ class WKT9: InputMethodService() { if (res.updateInputStatus) updateInputStatus() if (res.updateWordStatus) onUpdateWordStatus() if (res.focus) onFocus() + if (res.switchInputMode != null) onSwitchInputMode(res.switchInputMode) return res.consumed } @@ -359,7 +375,14 @@ class WKT9: InputMethodService() { clearCandidates() candidates.forEach { - this.candidates.add(it) + val candidate = + when (inputStatus) { + Status.CAP -> it.replaceFirstChar { char -> char.uppercase() } + Status.UPPER -> it.uppercase() + else -> it + } + + this.candidates.add(candidate) } loadCandidates(candidateIndex) @@ -453,6 +476,17 @@ class WKT9: InputMethodService() { handleComposeTimeout(this.timeout) } + private fun onSwitchInputMode(mode: WKT9InputMode) { + when (mode) { + WKT9InputMode.ALPHA -> enableInputMode(WKT9InputMode.ALPHA) + WKT9InputMode.NUMERIC -> enableInputMode(WKT9InputMode.NUMERIC) + WKT9InputMode.WORD -> enableInputMode(WKT9InputMode.WORD) + } + + clearCandidates() + updateInputStatus() + } + private fun onTranscribe() { val recorder = this.recorder ?: return @@ -510,24 +544,6 @@ class WKT9: InputMethodService() { composeText(candidates[candidateIndex]) } - @SuppressLint("DiscouragedApi") - private fun getIconResource(): Int { - val name = inputMode?.let { - val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager - val inputMethodSubtype = inputMethodManager.currentInputMethodSubtype - - it.mode - .plus("_") - .plus(inputMethodSubtype.languageTag) - .plus("_") - .plus(inputStatus.toString()) - .replace('-', '_') - .lowercase() - } ?: "wkt9" - - return resources.getIdentifier(name, "drawable", packageName) - } - private fun updateInputStatus() { inputStatus = inputMode?.status ?: Status.CAP diff --git a/app/src/main/java/net/mezimmah/wkt9/inputmode/AlphaInputMode.kt b/app/src/main/java/net/mezimmah/wkt9/inputmode/AlphaInputMode.kt index db7f8b1..f385d84 100644 --- a/app/src/main/java/net/mezimmah/wkt9/inputmode/AlphaInputMode.kt +++ b/app/src/main/java/net/mezimmah/wkt9/inputmode/AlphaInputMode.kt @@ -1,31 +1,188 @@ package net.mezimmah.wkt9.inputmode +import android.util.Log +import net.mezimmah.wkt9.keypad.Command import net.mezimmah.wkt9.keypad.Key +import net.mezimmah.wkt9.keypad.KeyCommandResolver import net.mezimmah.wkt9.keypad.KeyEventResult +import net.mezimmah.wkt9.keypad.KeyLayout class AlphaInputMode: InputMode { + private val tag = "WKT9" + private val keyCommandResolver: KeyCommandResolver = KeyCommandResolver.getBasic() + private var newKey = true + private var keyIndex = 0 + private var lastKey: Key? = null + override val mode: String = "alpha" override var status: Status = Status.CAP private set - override fun onKeyDown(key: Key, sentenceStart: Boolean): KeyEventResult { - return KeyEventResult(consumed = false) + init { + Log.d(tag, "Started alpha input mode.") } - override fun onKeyLongDown(key: Key, sentenceStart: Boolean): KeyEventResult { - return KeyEventResult(consumed = false) + override fun onKeyDown(key: Key, composing: Boolean): KeyEventResult { + keyStats(key) + + return when(keyCommandResolver.getCommand(key)) { + Command.BACK -> KeyEventResult(consumed = false) + Command.CHARACTER -> composeCharacter(key, composing) + Command.DELETE -> deleteCharacter(composing) + Command.SPACE -> finalizeWordOrSentence(composing) + Command.LEFT -> navigateLeft() + Command.RIGHT -> navigateRight() + Command.SELECT -> focus() + else -> KeyEventResult() + } } - override fun onKeyDownRepeatedly(key: Key, repeat: Int, sentenceStart: Boolean): KeyEventResult { - return KeyEventResult(consumed = false) + override fun onKeyLongDown(key: Key, composing: Boolean): KeyEventResult { + return when(keyCommandResolver.getCommand(key, true)) { + Command.RECORD -> record(composing) + Command.SWITCH_MODE -> switchMode(composing) + else -> KeyEventResult(true) + } } - override fun afterKeyDown(key: Key, sentenceStart: Boolean): KeyEventResult { - return KeyEventResult(consumed = false) + override fun onKeyDownRepeatedly(key: Key, repeat: Int, composing: Boolean): KeyEventResult { + return when(keyCommandResolver.getCommand(key, repeat = repeat)) { + Command.HOME -> goHome(repeat, composing) + Command.DELETE -> deleteCharacter(composing) + else -> KeyEventResult() + } } - override fun afterKeyLongDown(key: Key, keyDownMS: Long, sentenceStart: Boolean): KeyEventResult { - return KeyEventResult(consumed = false) + override fun afterKeyDown(key: Key, composing: Boolean): KeyEventResult { + return when(keyCommandResolver.getCommand(key, after = true)) { + Command.BACK -> goBack(composing) + Command.SHIFT_MODE -> shiftMode() + else -> KeyEventResult() + } + } + + override fun afterKeyLongDown(key: Key, keyDownMS: Long, composing: Boolean): KeyEventResult { + return when(keyCommandResolver.getCommand(key, after = true, longPress = true)) { + Command.TRANSCRIBE -> transcribe(composing) + else -> KeyEventResult() + } + } + + private fun deleteCharacter(composing: Boolean): KeyEventResult { + return KeyEventResult( + finishComposing = composing, + deleteBeforeCursor = 1 + ) + } + + private fun composeCharacter(key: Key, composing: Boolean): KeyEventResult { + if (composing && !newKey) return navigateRight() + + val layout = KeyLayout.en_US[key] ?: return KeyEventResult(true) + val candidates = layout.map { it.toString() } + + return KeyEventResult( + consumed = true, + finishComposing = composing, + startComposing = true, + candidates = candidates, + timeout = 400 + ) + } + + private fun finalizeWordOrSentence(composing: Boolean): KeyEventResult { + if (composing && !newKey) return navigateRight() + + return KeyEventResult( + finishComposing = composing, + startComposing = true, + candidates = listOf(" ", ". ", "? ", "! ", ", ", ": ", "; "), + timeout = 700 + ) + } + + private fun focus(): KeyEventResult { + return KeyEventResult( + consumed = true, + focus = true + ) + } + + private fun goBack(composing: Boolean): KeyEventResult { + return KeyEventResult( + consumed = false, + finishComposing = composing + ) + } + + private fun goHome(repeat: Int, composing: Boolean): KeyEventResult { + if (repeat > 1) return KeyEventResult(true) + + return KeyEventResult( + consumed = true, + finishComposing = composing, + goHome = true + ) + } + + private fun keyStats(key: Key) { + when (key != lastKey) { + true -> { + newKey = true + keyIndex = 0 + } + false -> { + newKey = false + keyIndex++ + } + } + + lastKey = key + } + + private fun navigateLeft(): KeyEventResult { + return KeyEventResult(left = true) + } + + private fun navigateRight(): KeyEventResult { + return KeyEventResult(right = true) + } + + private fun record(composing: Boolean): KeyEventResult { + return KeyEventResult( + consumed = true, + finishComposing = composing, + record = true + ) + } + + private fun shiftMode(): KeyEventResult { + status = when(status) { + Status.CAP -> Status.UPPER + Status.UPPER -> Status.LOWER + else -> Status.CAP + } + + return KeyEventResult( + consumed = true, + updateInputStatus = true + ) + } + + private fun switchMode(composing: Boolean): KeyEventResult { + return KeyEventResult( + consumed = true, + finishComposing = composing, + switchInputMode = WKT9InputMode.WORD + ) + } + + private fun transcribe(composing: Boolean): KeyEventResult { + return KeyEventResult( + consumed = true, + finishComposing = composing, + transcribe = true + ) } } \ No newline at end of file diff --git a/app/src/main/java/net/mezimmah/wkt9/inputmode/WordInputMode.kt b/app/src/main/java/net/mezimmah/wkt9/inputmode/WordInputMode.kt index dfba572..7bd7d32 100644 --- a/app/src/main/java/net/mezimmah/wkt9/inputmode/WordInputMode.kt +++ b/app/src/main/java/net/mezimmah/wkt9/inputmode/WordInputMode.kt @@ -28,9 +28,9 @@ class WordInputMode: InputMode { keyStats(key) return when(keyCommandResolver.getCommand(key)) { - Command.BACK -> KeyEventResult(false) + Command.BACK -> KeyEventResult(consumed = false) Command.CHARACTER -> buildCodeWord(key) - Command.DELETE -> deleteCharacter() + Command.DELETE -> deleteCharacter(0, composing) Command.SPACE -> finalizeWordOrSentence(composing) Command.LEFT -> navigateLeft() Command.RIGHT -> navigateRight() @@ -41,23 +41,23 @@ class WordInputMode: InputMode { override fun onKeyLongDown(key: Key, composing: Boolean): KeyEventResult { return when(keyCommandResolver.getCommand(key, true)) { - Command.RECORD -> record() - Command.SWITCH_MODE -> switchMode() + Command.RECORD -> record(composing) + Command.SWITCH_MODE -> switchMode(composing) else -> KeyEventResult(true) } } override fun onKeyDownRepeatedly(key: Key, repeat: Int, composing: Boolean): KeyEventResult { return when(keyCommandResolver.getCommand(key, repeat = repeat)) { - Command.HOME -> goHome(repeat) - Command.DELETE -> deleteCharacter(repeat) + Command.HOME -> goHome(repeat, composing) + Command.DELETE -> deleteCharacter(repeat, composing) else -> KeyEventResult() } } override fun afterKeyDown(key: Key, composing: Boolean): KeyEventResult { return when(keyCommandResolver.getCommand(key, after = true)) { - Command.BACK -> goBack() + Command.BACK -> goBack(composing) Command.SHIFT_MODE -> shiftMode(composing) else -> KeyEventResult() } @@ -65,7 +65,7 @@ class WordInputMode: InputMode { override fun afterKeyLongDown(key: Key, keyDownMS: Long, composing: Boolean): KeyEventResult { return when(keyCommandResolver.getCommand(key, after = true, longPress = true)) { - Command.TRANSCRIBE -> transcribe() + Command.TRANSCRIBE -> transcribe(composing) else -> KeyEventResult() } } @@ -82,11 +82,11 @@ class WordInputMode: InputMode { ) } - private fun deleteCharacter(repeat: Int = 0): KeyEventResult { + private fun deleteCharacter(repeat: Int = 0, composing: Boolean): KeyEventResult { if (repeat == 0) codeWord.clear() return KeyEventResult( - finishComposing = true, + finishComposing = composing, deleteBeforeCursor = 1 ) } @@ -113,23 +113,23 @@ class WordInputMode: InputMode { ) } - private fun goBack(): KeyEventResult { + private fun goBack(composing: Boolean): KeyEventResult { reset() return KeyEventResult( consumed = false, - finishComposing = true + finishComposing = composing ) } - private fun goHome(repeat: Int): KeyEventResult { + private fun goHome(repeat: Int, composing: Boolean): KeyEventResult { if (repeat > 1) return KeyEventResult(true) reset() return KeyEventResult( consumed = true, - finishComposing = true, + finishComposing = composing, goHome = true ) } @@ -157,12 +157,12 @@ class WordInputMode: InputMode { return KeyEventResult(right = true) } - private fun record(): KeyEventResult { + private fun record(composing: Boolean): KeyEventResult { codeWord.clear() return KeyEventResult( consumed = true, - finishComposing = true, + finishComposing = composing, record = true ) } @@ -190,15 +190,20 @@ class WordInputMode: InputMode { ) } - private fun switchMode(): KeyEventResult { + private fun switchMode(composing: Boolean): KeyEventResult { reset() - return KeyEventResult(true) - } - - private fun transcribe(): KeyEventResult { return KeyEventResult( consumed = true, + finishComposing = composing, + switchInputMode = WKT9InputMode.ALPHA + ) + } + + private fun transcribe(composing: Boolean): KeyEventResult { + return KeyEventResult( + consumed = true, + finishComposing = composing, transcribe = true ) } diff --git a/app/src/main/java/net/mezimmah/wkt9/keypad/KeyEventResult.kt b/app/src/main/java/net/mezimmah/wkt9/keypad/KeyEventResult.kt index 9582bb7..e80e4f9 100644 --- a/app/src/main/java/net/mezimmah/wkt9/keypad/KeyEventResult.kt +++ b/app/src/main/java/net/mezimmah/wkt9/keypad/KeyEventResult.kt @@ -1,5 +1,6 @@ package net.mezimmah.wkt9.keypad +import net.mezimmah.wkt9.inputmode.WKT9InputMode import java.lang.StringBuilder data class KeyEventResult( @@ -18,5 +19,6 @@ data class KeyEventResult( val transcribe: Boolean = false, val updateInputStatus: Boolean = false, val updateWordStatus: Boolean = false, - val focus: Boolean = false + val focus: Boolean = false, + val switchInputMode: WKT9InputMode? = null )