diff --git a/app/src/main/java/net/mezimmah/wkt9/WKT9.kt b/app/src/main/java/net/mezimmah/wkt9/WKT9.kt index bda821d..b200456 100644 --- a/app/src/main/java/net/mezimmah/wkt9/WKT9.kt +++ b/app/src/main/java/net/mezimmah/wkt9/WKT9.kt @@ -18,6 +18,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import net.mezimmah.wkt9.dao.SettingDao import net.mezimmah.wkt9.dao.WordDao @@ -51,6 +52,8 @@ class WKT9: InputMethodService() { private var queryJob: Job? = null private val ioScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) private var ioJob: Job? = null + private val commitScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) + private var commitJob: Job? = null private var cursorPosition = 0 private var longPressTimeout = 700 @@ -71,7 +74,8 @@ class WKT9: InputMethodService() { private var composing = false private val candidates: MutableList = mutableListOf() private var candidateIndex = 0 - private var sentenceStart = false + private var inputStatus: Status = Status.CAP + private var timeout: Int? = null // UI private lateinit var inputView: View @@ -112,7 +116,7 @@ class WKT9: InputMethodService() { inputMode = null cursorPosition = 0 - sentenceStart = false + inputStatus = Status.CAP } override fun onFinishInputView(finishingInput: Boolean) { @@ -127,10 +131,10 @@ class WKT9: InputMethodService() { return inputMode?.let { val keyEventResult = - if (repeatCount > 0) it.onKeyDownRepeatedly(key, repeatCount, sentenceStart) + if (repeatCount > 0) it.onKeyDownRepeatedly(key, repeatCount, composing) else { event?.startTracking() - it.onKeyDown(key, sentenceStart) + it.onKeyDown(key, composing) } handleKeyEventResult(keyEventResult) @@ -145,8 +149,8 @@ class WKT9: InputMethodService() { return inputMode?.let { val keyEventResult = - if (keyDownMS >= longPressTimeout) it.afterKeyLongDown(key, keyDownMS, sentenceStart) - else it.afterKeyDown(key, sentenceStart) + if (keyDownMS >= longPressTimeout) it.afterKeyLongDown(key, keyDownMS, composing) + else it.afterKeyDown(key, composing) handleKeyEventResult(keyEventResult) } ?: super.onKeyUp(keyCode, event) @@ -156,7 +160,7 @@ class WKT9: InputMethodService() { val key = keypad.getKey(keyCode) ?: return super.onKeyLongPress(keyCode, event) return inputMode?.let { - val keyEventResult = it.onKeyLongDown(key, sentenceStart) + val keyEventResult = it.onKeyLongDown(key, composing) handleKeyEventResult(keyEventResult) } ?: super.onKeyLongPress(keyCode, event) @@ -166,9 +170,6 @@ class WKT9: InputMethodService() { val inputType = attribute?.inputType?.and(InputType.TYPE_MASK_CLASS) ?: 0 cursorPosition = attribute?.initialSelEnd ?: 0 - sentenceStart = - if (cursorPosition == 0) true - else isSentenceStart() when (inputType) { InputType.TYPE_CLASS_DATETIME, @@ -180,7 +181,7 @@ class WKT9: InputMethodService() { else -> Log.d(tag, "Mode without input...") } - showStatusIcon(0) + updateInputStatus() super.onStartInput(attribute, restarting) } @@ -205,17 +206,6 @@ class WKT9: InputMethodService() { ) } - override fun showStatusIcon(iconResId: Int) { - if (iconResId != 0) super.showStatusIcon(iconResId) - - when (inputMode) { - is WordInputMode -> super.showStatusIcon(R.drawable.word) - is AlphaInputMode -> super.showStatusIcon(R.drawable.alpha) - is NumericInputMode -> super.showStatusIcon(R.drawable.numeric) - else -> super.showStatusIcon(R.drawable.wkt9) - } - } - private fun clearCandidates() { clearCandidateUI() @@ -242,7 +232,7 @@ class WKT9: InputMethodService() { private fun deleteText(beforeCursor: Int, afterCursor: Int) { currentInputConnection?.deleteSurroundingText(beforeCursor, afterCursor) - sentenceStart = isSentenceStart() + updateInputStatus() } // Todo: inputType @@ -262,7 +252,9 @@ class WKT9: InputMethodService() { private fun finishComposingText(): Boolean { return if (composing) { composing = false - sentenceStart = isSentenceStart() + + updateInputStatus() + currentInputConnection?.finishComposingText() ?: false } else false } @@ -276,11 +268,25 @@ class WKT9: InputMethodService() { } } + private fun handleComposeTimeout(timeout: Int?) { + this.timeout = timeout + + commitJob?.cancel() + + if (timeout == null) return + + commitJob = commitScope.launch { + delay(timeout.toLong()) + finishComposingText() + clearCandidates() + } + } + private fun handleKeyEventResult(res: KeyEventResult): Boolean { if (res.finishComposing) finishComposingText() if (res.startComposing) markComposingRegion() - if (!res.codeWord.isNullOrEmpty()) onCodeWordUpdate(res.codeWord) - if (!res.candidates.isNullOrEmpty()) onCandidates(res.candidates) + if (!res.codeWord.isNullOrEmpty()) onCodeWordUpdate(res.codeWord, res.timeout) + if (!res.candidates.isNullOrEmpty()) onCandidates(res.candidates, res.timeout) if (res.deleteBeforeCursor > 0 || res.deleteAfterCursor > 0) onDelete(res.deleteBeforeCursor, res.deleteAfterCursor) if (res.goHome) goHome() if (res.left) onLeft() @@ -288,6 +294,7 @@ class WKT9: InputMethodService() { if (res.record) onRecord() if (res.transcribe) onTranscribe() if (res.updateStatus) onUpdateStatus() +// if (res.sentenceStart != null) sentenceStart = res.sentenceStart if (res.focus) onFocus() return res.consumed @@ -330,7 +337,7 @@ class WKT9: InputMethodService() { return composing } - private fun onCandidates(candidates: List) { + private fun onCandidates(candidates: List, timeout: Int?) { clearCandidates() candidates.forEach { @@ -339,9 +346,10 @@ class WKT9: InputMethodService() { loadCandidates(candidateIndex) composeText(candidates[candidateIndex]) + handleComposeTimeout(timeout) } - private fun onCodeWordUpdate(codeWord: StringBuilder) { + private fun onCodeWordUpdate(codeWord: StringBuilder, timeout: Int?) { clearCandidates() queryJob?.cancel() @@ -352,6 +360,7 @@ class WKT9: InputMethodService() { loadCandidates(candidateIndex) composeText(candidates[candidateIndex], 1) + handleComposeTimeout(timeout) } } @@ -374,6 +383,7 @@ class WKT9: InputMethodService() { clearCandidateUI() loadCandidates(candidateIndex) composeText(candidates[candidateIndex]) + handleComposeTimeout(this.timeout) } private fun onRecord() { @@ -422,6 +432,7 @@ class WKT9: InputMethodService() { clearCandidateUI() loadCandidates(candidateIndex) composeText(candidates[candidateIndex]) + handleComposeTimeout(this.timeout) } private fun onTranscribe() { @@ -457,14 +468,44 @@ class WKT9: InputMethodService() { Log.d(tag, "We're going to update the status...") } + private fun updateInputStatus() { + when (inputMode?.status) { + Status.UPPER -> { + inputStatus = Status.UPPER + + showStatusIcon(R.drawable.shift) + } + + Status.CAP -> { + if (isSentenceStart()) { + inputStatus = Status.CAP + + showStatusIcon(R.drawable.shift) + } else { + inputStatus = Status.LOWER + + showStatusIcon(R.drawable.word) + } + } + + else -> { + inputStatus = Status.LOWER + + showStatusIcon(R.drawable.word) + } + } + } + private suspend fun queryT9Candidates(codeWord: StringBuilder, limit: Int = 10): Boolean { val words = wordDao.findCandidates(codeWord.toString(), limit) words.forEach { word -> val candidate = - if (sentenceStart && inputMode?.status == Status.WORD_CAP) word.word.replaceFirstChar { it.uppercase() } - else if (inputMode?.status == Status.WORD_UPPER) word.word.uppercase() - else word.word + when (inputStatus) { + Status.CAP -> word.word.replaceFirstChar { it.uppercase() } + Status.UPPER -> word.word.uppercase() + else -> word.word + } candidates.add(candidate) } 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 aa3c840..46250fb 100644 --- a/app/src/main/java/net/mezimmah/wkt9/inputmode/AlphaInputMode.kt +++ b/app/src/main/java/net/mezimmah/wkt9/inputmode/AlphaInputMode.kt @@ -4,7 +4,7 @@ import net.mezimmah.wkt9.keypad.Key import net.mezimmah.wkt9.keypad.KeyEventResult class AlphaInputMode: InputMode { - override var status: Status = Status.ALPHA_CAP + override var status: Status = Status.CAP private set override fun onKeyDown(key: Key, sentenceStart: Boolean): KeyEventResult { diff --git a/app/src/main/java/net/mezimmah/wkt9/inputmode/InputMode.kt b/app/src/main/java/net/mezimmah/wkt9/inputmode/InputMode.kt index 7145cc5..cb4090b 100644 --- a/app/src/main/java/net/mezimmah/wkt9/inputmode/InputMode.kt +++ b/app/src/main/java/net/mezimmah/wkt9/inputmode/InputMode.kt @@ -6,13 +6,13 @@ import net.mezimmah.wkt9.keypad.KeyEventResult interface InputMode { val status: Status - fun onKeyDown(key: Key, sentenceStart: Boolean): KeyEventResult + fun onKeyDown(key: Key, composing: Boolean): KeyEventResult - fun onKeyLongDown(key: Key, sentenceStart: Boolean): KeyEventResult + fun onKeyLongDown(key: Key, composing: Boolean): KeyEventResult - fun onKeyDownRepeatedly(key: Key, repeat: Int, sentenceStart: Boolean): KeyEventResult + fun onKeyDownRepeatedly(key: Key, repeat: Int, composing: Boolean): KeyEventResult - fun afterKeyDown(key: Key, sentenceStart: Boolean): KeyEventResult + fun afterKeyDown(key: Key, composing: Boolean): KeyEventResult - fun afterKeyLongDown(key: Key, keyDownMS: Long, sentenceStart: Boolean): KeyEventResult + fun afterKeyLongDown(key: Key, keyDownMS: Long, composing: Boolean): KeyEventResult } \ No newline at end of file diff --git a/app/src/main/java/net/mezimmah/wkt9/inputmode/Status.kt b/app/src/main/java/net/mezimmah/wkt9/inputmode/Status.kt index 7c497f7..3a09743 100644 --- a/app/src/main/java/net/mezimmah/wkt9/inputmode/Status.kt +++ b/app/src/main/java/net/mezimmah/wkt9/inputmode/Status.kt @@ -1,11 +1,8 @@ package net.mezimmah.wkt9.inputmode enum class Status(val idx: Int) { - WORD(0), - WORD_CAP(1), - WORD_UPPER(2), - ALPHA(3), - ALPHA_CAP(4), - ALPHA_UPPER(5), - NUM(6) + CAP(0), + UPPER(1), + LOWER(2), + NUM(3) } \ 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 257a465..af70110 100644 --- a/app/src/main/java/net/mezimmah/wkt9/inputmode/WordInputMode.kt +++ b/app/src/main/java/net/mezimmah/wkt9/inputmode/WordInputMode.kt @@ -15,21 +15,21 @@ class WordInputMode: InputMode { private var keyIndex = 0 private var lastKey: Key? = null - override var status: Status = Status.WORD_CAP + override var status: Status = Status.CAP private set init { Log.d(tag, "Started word input mode.") } - override fun onKeyDown(key: Key, sentenceStart: Boolean): KeyEventResult { + override fun onKeyDown(key: Key, composing: Boolean): KeyEventResult { keyStats(key) return when(keyCommandResolver.getCommand(key)) { Command.BACK -> KeyEventResult(false) Command.CHARACTER -> buildCodeWord(key) Command.DELETE -> deleteCharacter() - Command.SPACE -> finalizeWordOrSentence() + Command.SPACE -> finalizeWordOrSentence(composing) Command.LEFT -> navigateLeft() Command.RIGHT -> navigateRight() Command.SELECT -> focus() @@ -37,7 +37,7 @@ class WordInputMode: InputMode { } } - override fun onKeyLongDown(key: Key, sentenceStart: Boolean): KeyEventResult { + override fun onKeyLongDown(key: Key, composing: Boolean): KeyEventResult { return when(keyCommandResolver.getCommand(key, true)) { Command.RECORD -> record() Command.SWITCH_MODE -> switchMode() @@ -45,7 +45,7 @@ class WordInputMode: InputMode { } } - override fun onKeyDownRepeatedly(key: Key, repeat: Int, sentenceStart: Boolean): KeyEventResult { + 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) @@ -53,15 +53,15 @@ class WordInputMode: InputMode { } } - override fun afterKeyDown(key: Key, sentenceStart: Boolean): KeyEventResult { + override fun afterKeyDown(key: Key, composing: Boolean): KeyEventResult { return when(keyCommandResolver.getCommand(key, after = true)) { Command.BACK -> goBack() - Command.SHIFT_MODE -> shiftMode(sentenceStart) + Command.SHIFT_MODE -> shiftMode(composing) else -> KeyEventResult() } } - override fun afterKeyLongDown(key: Key, keyDownMS: Long, sentenceStart: Boolean): KeyEventResult { + override fun afterKeyLongDown(key: Key, keyDownMS: Long, composing: Boolean): KeyEventResult { return when(keyCommandResolver.getCommand(key, after = true, longPress = true)) { Command.TRANSCRIBE -> transcribe() else -> KeyEventResult() @@ -89,8 +89,8 @@ class WordInputMode: InputMode { ) } - private fun finalizeWordOrSentence(): KeyEventResult { - if (!newKey) return navigateRight() + private fun finalizeWordOrSentence(composing: Boolean): KeyEventResult { + if (composing && !newKey) return navigateRight() val finishComposing = codeWord.isNotEmpty() @@ -99,7 +99,8 @@ class WordInputMode: InputMode { return KeyEventResult( finishComposing = finishComposing, startComposing = true, - candidates = listOf(" ", ". ", "? ", "! ", ", ", ": ", "; ") + candidates = listOf(" ", ". ", "? ", "! ", ", ", ": ", "; "), + timeout = 700 ) } @@ -171,33 +172,34 @@ class WordInputMode: InputMode { lastKey = null } - private fun shiftMode(sentenceStart: Boolean): KeyEventResult { - reset() + private fun shiftMode(composing: Boolean): KeyEventResult { + Log.d(tag, "Composing: $composing") - if (status == Status.WORD_CAP && sentenceStart || status == Status.WORD && !sentenceStart) { - return KeyEventResult( - consumed = true, - sentenceStart = !sentenceStart - ) - } + return KeyEventResult() +// reset() - status = when(status) { - Status.WORD_CAP -> Status.WORD_UPPER - Status.WORD -> Status.WORD_CAP - else -> Status.WORD - } +// if (status == Status.CAP && sentenceStart || status == Status.LOWER && !sentenceStart) { +// return KeyEventResult( +// consumed = true, +// sentenceStart = !sentenceStart +// ) +// } +// +// status = when(status) { +// Status.CAP -> Status.UPPER +// Status.LOWER -> Status.CAP +// else -> Status.LOWER +// } - return KeyEventResult( - consumed = true, - updateStatus = true - ) +// return KeyEventResult( +// consumed = true, +// updateStatus = true +// ) } private fun switchMode(): KeyEventResult { reset() - Log.d(tag, "Switch mode") - return KeyEventResult(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 0ef64f8..55f29ea 100644 --- a/app/src/main/java/net/mezimmah/wkt9/keypad/KeyEventResult.kt +++ b/app/src/main/java/net/mezimmah/wkt9/keypad/KeyEventResult.kt @@ -8,6 +8,7 @@ data class KeyEventResult( val startComposing: Boolean = false, val codeWord: StringBuilder? = null, val candidates: List? = null, + val timeout: Int? = null, val deleteBeforeCursor: Int = 0, val deleteAfterCursor: Int = 0, val goHome: Boolean = false,