From aef91d8a42391ae2de52ad7979bd481fb127ea00 Mon Sep 17 00:00:00 2001 From: merkost Date: Tue, 23 May 2023 13:18:52 +1000 Subject: [PATCH] Moved capitalization logic in a separate function Added inputTypeClassVariation for controlling whether keyboard is in password mode to turn off capitalization --- .../keyboard/helpers/Constants.kt | 49 +++++---- .../keyboard/services/SimpleKeyboardIME.kt | 103 ++++++++++++------ 2 files changed, 96 insertions(+), 56 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/keyboard/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/keyboard/helpers/Constants.kt index 28fcfed..ae441c4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/keyboard/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/keyboard/helpers/Constants.kt @@ -1,6 +1,7 @@ package com.simplemobiletools.keyboard.helpers import android.content.Context +import android.text.InputType import com.simplemobiletools.keyboard.extensions.config import com.simplemobiletools.keyboard.helpers.MyKeyboard.Companion.KEYCODE_SPACE @@ -10,23 +11,25 @@ enum class ShiftState { ON_PERMANENT; companion object { + private val MIN_TEXT_LENGTH = 2 private val endOfSentenceChars: List = listOf('.', '?', '!') - fun getDefaultShiftState(context: Context): ShiftState { + fun getDefaultShiftState(context: Context, inputTypeClassVariation: Int): ShiftState { + if (isInputTypePassword(inputTypeClassVariation)) { + return OFF + } return when (context.config.enableSentencesCapitalization) { true -> ON_ONE_CHAR else -> OFF } } - fun getShiftStateForText(context: Context, newText: String?): ShiftState { - if (!context.config.enableSentencesCapitalization) { + fun getShiftStateForText(context: Context, inputTypeClassVariation: Int, text: String?): ShiftState { + if (isInputTypePassword(inputTypeClassVariation)) { return OFF } - - val twoLastSymbols = newText?.takeLast(2) return when { - shouldCapitalizeSentence(previousChar = twoLastSymbols?.getOrNull(0), currentChar = twoLastSymbols?.getOrNull(1)) -> { + shouldCapitalize(context, text) -> { ON_ONE_CHAR } else -> { @@ -35,24 +38,30 @@ enum class ShiftState { } } - fun getCapitalizationOnDelete(context: Context, text: CharSequence?): ShiftState { + fun shouldCapitalize(context: Context, text: String?): Boolean { + //To capitalize first letter in textField + if (text.isNullOrEmpty()) { + return true + } + if (!context.config.enableSentencesCapitalization) { - return OFF - } - - return if (text.isNullOrEmpty() || shouldCapitalizeSentence(currentChar = text.last(), previousChar = text.getOrNull(text.lastIndex - 1))) { - ON_ONE_CHAR - } else { - OFF - } - } - - private fun shouldCapitalizeSentence(previousChar: Char?, currentChar: Char?): Boolean { - if (previousChar == null || currentChar == null) { return false } - return currentChar.code == KEYCODE_SPACE && endOfSentenceChars.contains(previousChar) + val twoLastSymbols = text.takeLast(2) + + if (twoLastSymbols.length < MIN_TEXT_LENGTH) { + return false + } + + return endOfSentenceChars.contains(twoLastSymbols.first()) && twoLastSymbols.last().code == KEYCODE_SPACE + } + + fun isInputTypePassword(inputTypeVariation: Int): Boolean { + return inputTypeVariation == InputType.TYPE_TEXT_VARIATION_PASSWORD + || inputTypeVariation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD + || inputTypeVariation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD + || inputTypeVariation == InputType.TYPE_NUMBER_VARIATION_PASSWORD } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/keyboard/services/SimpleKeyboardIME.kt b/app/src/main/kotlin/com/simplemobiletools/keyboard/services/SimpleKeyboardIME.kt index 8709ec3..77c42af 100644 --- a/app/src/main/kotlin/com/simplemobiletools/keyboard/services/SimpleKeyboardIME.kt +++ b/app/src/main/kotlin/com/simplemobiletools/keyboard/services/SimpleKeyboardIME.kt @@ -3,10 +3,7 @@ package com.simplemobiletools.keyboard.services import android.content.SharedPreferences import android.inputmethodservice.InputMethodService import android.text.InputType -import android.text.InputType.TYPE_CLASS_DATETIME -import android.text.InputType.TYPE_CLASS_NUMBER -import android.text.InputType.TYPE_CLASS_PHONE -import android.text.InputType.TYPE_MASK_CLASS +import android.text.InputType.* import android.text.TextUtils import android.view.KeyEvent import android.view.View @@ -37,6 +34,7 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL private var lastShiftPressTS = 0L private var keyboardMode = KEYBOARD_LETTERS private var inputTypeClass = InputType.TYPE_CLASS_TEXT + private var inputTypeClassVariation = InputType.TYPE_CLASS_TEXT private var enterKeyType = IME_ACTION_NONE private var switchToLetters = false @@ -64,23 +62,64 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL override fun onStartInput(attribute: EditorInfo?, restarting: Boolean) { super.onStartInput(attribute, restarting) inputTypeClass = attribute!!.inputType and TYPE_MASK_CLASS + inputTypeClassVariation = attribute!!.inputType and TYPE_MASK_VARIATION + enterKeyType = attribute.imeOptions and (IME_MASK_ACTION or IME_FLAG_NO_ENTER_ACTION) keyboard = createNewKeyboard() keyboardView?.setKeyboard(keyboard!!) keyboardView?.setEditorInfo(attribute) - updateShiftKeyState() + updateShiftKeyState(null) } - private fun updateShiftKeyState() { - if (keyboardMode == KEYBOARD_LETTERS) { - val editorInfo = currentInputEditorInfo - if (editorInfo != null && editorInfo.inputType != InputType.TYPE_NULL && keyboard?.mShiftState != ShiftState.ON_PERMANENT) { - if (currentInputConnection.getCursorCapsMode(editorInfo.inputType) != 0) { - keyboard?.setShifted(ShiftState.ON_ONE_CHAR) - keyboardView?.invalidateAllKeys() + private fun updateShiftKeyState(code: Int?) { + if (code == MyKeyboard.KEYCODE_SHIFT || code == MyKeyboard.KEYCODE_DELETE) { + return + } + + if (keyboardMode != KEYBOARD_LETTERS || ShiftState.isInputTypePassword(inputTypeClassVariation)) { + return + } + + val text = currentInputConnection.getTextBeforeCursor(2, 0) ?: return + //Capitalize first letter on startup or if text is empty + if (code == null || text.isEmpty()) { + keyboard!!.setShifted(ShiftState.ON_ONE_CHAR) + keyboardView?.invalidateAllKeys() + return + } + + //Capitalize sentences if needed + if (config.enableSentencesCapitalization) { + + //Capitalize on Enter click + if (code == MyKeyboard.KEYCODE_ENTER) { + keyboard!!.setShifted(ShiftState.ON_ONE_CHAR) + keyboardView?.invalidateAllKeys() + return + } + + + if (ShiftState.shouldCapitalize(this, text.toString())) { + keyboard!!.setShifted(ShiftState.ON_ONE_CHAR) + keyboardView?.invalidateAllKeys() + return + } else { + //Try capitalizing based on the editor info like google keep or google messenger apps + val editorInfo = currentInputEditorInfo + + if (editorInfo != null && editorInfo.inputType != InputType.TYPE_NULL && keyboard?.mShiftState != ShiftState.ON_PERMANENT) { + if (currentInputConnection.getCursorCapsMode(editorInfo.inputType) != 0) { + keyboard?.setShifted(ShiftState.ON_ONE_CHAR) + keyboardView?.invalidateAllKeys() + return + } } } } + + //Else just reset shift to OFF + keyboard?.setShifted(ShiftState.OFF) + keyboardView?.invalidateAllKeys() } override fun onKey(code: Int) { @@ -96,19 +135,22 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL when (code) { MyKeyboard.KEYCODE_DELETE -> { - if (keyboard!!.mShiftState != ShiftState.ON_PERMANENT) { - val extractedText = inputConnection.getTextBeforeCursor(3, 0)?.dropLast(1) - keyboard!!.setShifted(ShiftState.getCapitalizationOnDelete(context = this, text = extractedText)) - } - val selectedText = inputConnection.getSelectedText(0) if (TextUtils.isEmpty(selectedText)) { + val text = inputConnection.getTextBeforeCursor(3, 0)?.dropLast(1) + + if (keyboard?.mShiftState != ShiftState.ON_PERMANENT) { + keyboard?.setShifted(ShiftState.getShiftStateForText(this, inputTypeClassVariation, text?.toString())) + keyboardView?.invalidateAllKeys() + } + inputConnection.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)) inputConnection.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL)) } else { + + inputConnection.commitText("", 1) } - keyboardView!!.invalidateAllKeys() } MyKeyboard.KEYCODE_SHIFT -> { @@ -142,11 +184,6 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL } else { inputConnection.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)) inputConnection.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER)) - - if (config.enableSentencesCapitalization) { - keyboard!!.setShifted(ShiftState.ON_ONE_CHAR) - keyboardView!!.invalidateAllKeys() - } } } @@ -186,17 +223,10 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL } else { inputConnection.commitText(codeChar.toString(), 1) } - - if (keyboardMode == KEYBOARD_LETTERS && keyboard!!.mShiftState != ShiftState.ON_PERMANENT) { - keyboard!!.setShifted(ShiftState.getShiftStateForText(this, newText = "$originalText$codeChar")) - keyboardView!!.invalidateAllKeys() - } - } } - - if (code != MyKeyboard.KEYCODE_SHIFT && config.enableSentencesCapitalization) { - updateShiftKeyState() + if (keyboard!!.mShiftState != ShiftState.ON_PERMANENT) { + updateShiftKeyState(code) } } @@ -204,8 +234,10 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL if (switchToLetters) { // TODO: Change keyboardMode to enum class keyboardMode = KEYBOARD_LETTERS - val text = currentInputConnection?.getExtractedText(ExtractedTextRequest(), 0)?.text - val newShiftState = ShiftState.getShiftStateForText(this, text?.toString().orEmpty()) + + //Check if capitalization is needed after switching to letters layout + val text = currentInputConnection?.getTextBeforeCursor(2, 0) + val newShiftState = ShiftState.getShiftStateForText(this, inputTypeClassVariation, text?.toString()) keyboard = MyKeyboard(this, getKeyboardLayoutXML(), enterKeyType, shiftState = newShiftState) @@ -261,9 +293,8 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL getKeyboardLayoutXML() } } - return MyKeyboard( - context = this, xmlLayoutResId = keyboardXml, enterKeyType = enterKeyType, shiftState = ShiftState.getDefaultShiftState(this) + context = this, xmlLayoutResId = keyboardXml, enterKeyType = enterKeyType, shiftState = ShiftState.getDefaultShiftState(this, inputTypeClassVariation) ) }