Added sentences capitalization support (without pressing enter)
This commit is contained in:
parent
577553db15
commit
95f05a7b96
|
@ -1,9 +1,49 @@
|
||||||
package com.simplemobiletools.keyboard.helpers
|
package com.simplemobiletools.keyboard.helpers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.simplemobiletools.keyboard.extensions.config
|
||||||
|
import com.simplemobiletools.keyboard.helpers.MyKeyboard.Companion.KEYCODE_SPACE
|
||||||
|
|
||||||
enum class ShiftState {
|
enum class ShiftState {
|
||||||
OFF,
|
OFF,
|
||||||
ON_ONE_CHAR,
|
ON_ONE_CHAR,
|
||||||
ON_PERMANENT;
|
ON_PERMANENT;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val endOfSentenceChars: List<Char> = listOf('.', '?', '!')
|
||||||
|
|
||||||
|
fun getDefaultShiftState(context: Context): ShiftState {
|
||||||
|
return when (context.config.enableSentencesCapitalization) {
|
||||||
|
true -> ON_ONE_CHAR
|
||||||
|
else -> OFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getShiftStateForText(context: Context, newText: CharSequence?): ShiftState {
|
||||||
|
if (context.config.enableSentencesCapitalization.not()) return OFF
|
||||||
|
|
||||||
|
val twoLastSymbols = newText?.takeLast(2)
|
||||||
|
return when {
|
||||||
|
twoLastSymbols?.getOrNull(1) == KEYCODE_SPACE.toChar() && endOfSentenceChars.contains(twoLastSymbols.getOrNull(0)) -> {
|
||||||
|
ON_ONE_CHAR
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> OFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun shouldCapitalizeSentence(previousChar: Char?, currentChar: Char): Boolean {
|
||||||
|
return currentChar.code == KEYCODE_SPACE && endOfSentenceChars.contains(previousChar)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun shouldCapitalizeOnDelete(text: CharSequence?): Boolean {
|
||||||
|
if (text.isNullOrEmpty()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return shouldCapitalizeSentence(currentChar = text.last(), previousChar = text.getOrNull(text.lastIndex - 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// limit the count of alternative characters that show up at long pressing a key
|
// limit the count of alternative characters that show up at long pressing a key
|
||||||
|
|
|
@ -255,13 +255,14 @@ class MyKeyboard {
|
||||||
* @param enterKeyType determines what icon should we show on Enter key
|
* @param enterKeyType determines what icon should we show on Enter key
|
||||||
*/
|
*/
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
constructor(context: Context, @XmlRes xmlLayoutResId: Int, enterKeyType: Int) {
|
constructor(context: Context, @XmlRes xmlLayoutResId: Int, enterKeyType: Int, shiftState: ShiftState = ShiftState.OFF) {
|
||||||
mDisplayWidth = context.resources.displayMetrics.widthPixels
|
mDisplayWidth = context.resources.displayMetrics.widthPixels
|
||||||
mDefaultHorizontalGap = 0
|
mDefaultHorizontalGap = 0
|
||||||
mDefaultWidth = mDisplayWidth / 10
|
mDefaultWidth = mDisplayWidth / 10
|
||||||
mDefaultHeight = mDefaultWidth
|
mDefaultHeight = mDefaultWidth
|
||||||
mKeyboardHeightMultiplier = getKeyboardHeightMultiplier(context.config.keyboardHeightMultiplier)
|
mKeyboardHeightMultiplier = getKeyboardHeightMultiplier(context.config.keyboardHeightMultiplier)
|
||||||
mKeys = ArrayList()
|
mKeys = ArrayList()
|
||||||
|
mShiftState = shiftState
|
||||||
mEnterKeyType = enterKeyType
|
mEnterKeyType = enterKeyType
|
||||||
loadKeyboard(context, context.resources.getXml(xmlLayoutResId))
|
loadKeyboard(context, context.resources.getXml(xmlLayoutResId))
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@ import com.simplemobiletools.keyboard.R
|
||||||
import com.simplemobiletools.keyboard.extensions.config
|
import com.simplemobiletools.keyboard.extensions.config
|
||||||
import com.simplemobiletools.keyboard.helpers.*
|
import com.simplemobiletools.keyboard.helpers.*
|
||||||
import com.simplemobiletools.keyboard.views.MyKeyboardView
|
import com.simplemobiletools.keyboard.views.MyKeyboardView
|
||||||
import kotlinx.android.synthetic.main.keyboard_view_keyboard.view.*
|
import kotlinx.android.synthetic.main.keyboard_view_keyboard.view.keyboard_holder
|
||||||
|
import kotlinx.android.synthetic.main.keyboard_view_keyboard.view.keyboard_view
|
||||||
|
|
||||||
// based on https://www.androidauthority.com/lets-build-custom-keyboard-android-832362/
|
// based on https://www.androidauthority.com/lets-build-custom-keyboard-android-832362/
|
||||||
class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
@ -41,7 +42,6 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL
|
||||||
|
|
||||||
override fun onInitializeInterface() {
|
override fun onInitializeInterface() {
|
||||||
super.onInitializeInterface()
|
super.onInitializeInterface()
|
||||||
keyboard = MyKeyboard(this, getKeyboardLayoutXML(), enterKeyType)
|
|
||||||
getSharedPrefs().registerOnSharedPreferenceChangeListener(this)
|
getSharedPrefs().registerOnSharedPreferenceChangeListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +65,7 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL
|
||||||
super.onStartInput(attribute, restarting)
|
super.onStartInput(attribute, restarting)
|
||||||
inputTypeClass = attribute!!.inputType and TYPE_MASK_CLASS
|
inputTypeClass = attribute!!.inputType and TYPE_MASK_CLASS
|
||||||
enterKeyType = attribute.imeOptions and (IME_MASK_ACTION or IME_FLAG_NO_ENTER_ACTION)
|
enterKeyType = attribute.imeOptions and (IME_MASK_ACTION or IME_FLAG_NO_ENTER_ACTION)
|
||||||
|
keyboard = createNewKeyboard()
|
||||||
keyboard = getKeyBoard()
|
|
||||||
keyboardView?.setKeyboard(keyboard!!)
|
keyboardView?.setKeyboard(keyboard!!)
|
||||||
keyboardView?.setEditorInfo(attribute)
|
keyboardView?.setEditorInfo(attribute)
|
||||||
updateShiftKeyState()
|
updateShiftKeyState()
|
||||||
|
@ -97,7 +96,14 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL
|
||||||
when (code) {
|
when (code) {
|
||||||
MyKeyboard.KEYCODE_DELETE -> {
|
MyKeyboard.KEYCODE_DELETE -> {
|
||||||
if (keyboard!!.mShiftState == ShiftState.ON_ONE_CHAR) {
|
if (keyboard!!.mShiftState == ShiftState.ON_ONE_CHAR) {
|
||||||
keyboard!!.mShiftState = ShiftState.OFF
|
keyboard!!.setShifted(ShiftState.OFF)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.enableSentencesCapitalization) {
|
||||||
|
val extractedText = inputConnection.getTextBeforeCursor(3, 0)?.dropLast(1)
|
||||||
|
if (ShiftState.shouldCapitalizeOnDelete(text = extractedText)) {
|
||||||
|
keyboard!!.setShifted(ShiftState.ON_ONE_CHAR)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val selectedText = inputConnection.getSelectedText(0)
|
val selectedText = inputConnection.getSelectedText(0)
|
||||||
|
@ -109,6 +115,7 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL
|
||||||
}
|
}
|
||||||
keyboardView!!.invalidateAllKeys()
|
keyboardView!!.invalidateAllKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
MyKeyboard.KEYCODE_SHIFT -> {
|
MyKeyboard.KEYCODE_SHIFT -> {
|
||||||
if (keyboardMode == KEYBOARD_LETTERS) {
|
if (keyboardMode == KEYBOARD_LETTERS) {
|
||||||
when {
|
when {
|
||||||
|
@ -132,6 +139,7 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL
|
||||||
}
|
}
|
||||||
keyboardView!!.invalidateAllKeys()
|
keyboardView!!.invalidateAllKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
MyKeyboard.KEYCODE_ENTER -> {
|
MyKeyboard.KEYCODE_ENTER -> {
|
||||||
val imeOptionsActionId = getImeOptionsActionId()
|
val imeOptionsActionId = getImeOptionsActionId()
|
||||||
if (imeOptionsActionId != IME_ACTION_NONE) {
|
if (imeOptionsActionId != IME_ACTION_NONE) {
|
||||||
|
@ -139,8 +147,13 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL
|
||||||
} else {
|
} else {
|
||||||
inputConnection.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER))
|
inputConnection.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER))
|
||||||
inputConnection.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER))
|
inputConnection.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER))
|
||||||
|
|
||||||
|
if (config.enableSentencesCapitalization) {
|
||||||
|
keyboard!!.mShiftState = ShiftState.ON_ONE_CHAR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MyKeyboard.KEYCODE_MODE_CHANGE -> {
|
MyKeyboard.KEYCODE_MODE_CHANGE -> {
|
||||||
val keyboardXml = if (keyboardMode == KEYBOARD_LETTERS) {
|
val keyboardXml = if (keyboardMode == KEYBOARD_LETTERS) {
|
||||||
keyboardMode = KEYBOARD_SYMBOLS
|
keyboardMode = KEYBOARD_SYMBOLS
|
||||||
|
@ -152,11 +165,15 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL
|
||||||
keyboard = MyKeyboard(this, keyboardXml, enterKeyType)
|
keyboard = MyKeyboard(this, keyboardXml, enterKeyType)
|
||||||
keyboardView!!.setKeyboard(keyboard!!)
|
keyboardView!!.setKeyboard(keyboard!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
MyKeyboard.KEYCODE_EMOJI -> {
|
MyKeyboard.KEYCODE_EMOJI -> {
|
||||||
keyboardView?.openEmojiPalette()
|
keyboardView?.openEmojiPalette()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
var codeChar = code.toChar()
|
var codeChar = code.toChar()
|
||||||
|
val originalText = inputConnection.getExtractedText(ExtractedTextRequest(), 0)?.text ?: return
|
||||||
|
|
||||||
if (Character.isLetter(codeChar) && keyboard!!.mShiftState > ShiftState.OFF) {
|
if (Character.isLetter(codeChar) && keyboard!!.mShiftState > ShiftState.OFF) {
|
||||||
codeChar = Character.toUpperCase(codeChar)
|
codeChar = Character.toUpperCase(codeChar)
|
||||||
}
|
}
|
||||||
|
@ -165,18 +182,28 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL
|
||||||
// However, avoid doing that in cases when the EditText for example requires numbers as the input.
|
// However, avoid doing that in cases when the EditText for example requires numbers as the input.
|
||||||
// We can detect that by the text not changing on pressing Space.
|
// We can detect that by the text not changing on pressing Space.
|
||||||
if (keyboardMode != KEYBOARD_LETTERS && code == MyKeyboard.KEYCODE_SPACE) {
|
if (keyboardMode != KEYBOARD_LETTERS && code == MyKeyboard.KEYCODE_SPACE) {
|
||||||
val originalText = inputConnection.getExtractedText(ExtractedTextRequest(), 0)?.text ?: return
|
|
||||||
inputConnection.commitText(codeChar.toString(), 1)
|
inputConnection.commitText(codeChar.toString(), 1)
|
||||||
val newText = inputConnection.getExtractedText(ExtractedTextRequest(), 0)?.text
|
val newText = inputConnection.getExtractedText(ExtractedTextRequest(), 0)?.text
|
||||||
switchToLetters = originalText != newText
|
if (originalText != newText) {
|
||||||
|
switchToLetters = true
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
inputConnection.commitText(codeChar.toString(), 1)
|
inputConnection.commitText(codeChar.toString(), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyboard!!.mShiftState == ShiftState.ON_ONE_CHAR && keyboardMode == KEYBOARD_LETTERS) {
|
if (keyboardMode == KEYBOARD_LETTERS) {
|
||||||
keyboard!!.mShiftState = ShiftState.OFF
|
if (keyboard!!.mShiftState == ShiftState.ON_ONE_CHAR) {
|
||||||
|
keyboard!!.setShifted(ShiftState.OFF)
|
||||||
|
}
|
||||||
|
if (config.enableSentencesCapitalization && ShiftState.shouldCapitalizeSentence(
|
||||||
|
previousChar = originalText.lastOrNull(), currentChar = code.toChar()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
keyboard!!.setShifted(ShiftState.ON_ONE_CHAR)
|
||||||
|
}
|
||||||
keyboardView!!.invalidateAllKeys()
|
keyboardView!!.invalidateAllKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,8 +214,12 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL
|
||||||
|
|
||||||
override fun onActionUp() {
|
override fun onActionUp() {
|
||||||
if (switchToLetters) {
|
if (switchToLetters) {
|
||||||
|
// TODO: Change keyboardMode to enum class
|
||||||
keyboardMode = KEYBOARD_LETTERS
|
keyboardMode = KEYBOARD_LETTERS
|
||||||
keyboard = MyKeyboard(this, getKeyboardLayoutXML(), enterKeyType)
|
val text = currentInputConnection?.getExtractedText(ExtractedTextRequest(), 0)?.text
|
||||||
|
val newShiftState = ShiftState.getShiftStateForText(this, text)
|
||||||
|
|
||||||
|
keyboard = MyKeyboard(this, getKeyboardLayoutXML(), enterKeyType, shiftState = newShiftState)
|
||||||
|
|
||||||
val editorInfo = currentInputEditorInfo
|
val editorInfo = currentInputEditorInfo
|
||||||
if (editorInfo != null && editorInfo.inputType != InputType.TYPE_NULL && keyboard?.mShiftState != ShiftState.ON_PERMANENT) {
|
if (editorInfo != null && editorInfo.inputType != InputType.TYPE_NULL && keyboard?.mShiftState != ShiftState.ON_PERMANENT) {
|
||||||
|
@ -215,32 +246,37 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reloadKeyboard() {
|
override fun reloadKeyboard() {
|
||||||
val keyboard = getKeyBoard()
|
val keyboard = createNewKeyboard()
|
||||||
this.keyboard = keyboard
|
this.keyboard = keyboard
|
||||||
keyboardView?.setKeyboard(keyboard)
|
keyboardView?.setKeyboard(keyboard)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getKeyBoard(): MyKeyboard {
|
private fun createNewKeyboard(): MyKeyboard {
|
||||||
val keyboardXml = when (inputTypeClass) {
|
val keyboardXml = when (inputTypeClass) {
|
||||||
TYPE_CLASS_NUMBER -> {
|
TYPE_CLASS_NUMBER -> {
|
||||||
keyboardMode = KEYBOARD_NUMBERS
|
keyboardMode = KEYBOARD_NUMBERS
|
||||||
R.xml.keys_numbers
|
R.xml.keys_numbers
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPE_CLASS_PHONE -> {
|
TYPE_CLASS_PHONE -> {
|
||||||
keyboardMode = KEYBOARD_PHONE
|
keyboardMode = KEYBOARD_PHONE
|
||||||
R.xml.keys_phone
|
R.xml.keys_phone
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPE_CLASS_DATETIME -> {
|
TYPE_CLASS_DATETIME -> {
|
||||||
keyboardMode = KEYBOARD_SYMBOLS
|
keyboardMode = KEYBOARD_SYMBOLS
|
||||||
R.xml.keys_symbols
|
R.xml.keys_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
keyboardMode = KEYBOARD_LETTERS
|
keyboardMode = KEYBOARD_LETTERS
|
||||||
getKeyboardLayoutXML()
|
getKeyboardLayoutXML()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return MyKeyboard(this, keyboardXml, enterKeyType)
|
return MyKeyboard(
|
||||||
|
context = this, xmlLayoutResId = keyboardXml, enterKeyType = enterKeyType, shiftState = ShiftState.getDefaultShiftState(this)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUpdateSelection(oldSelStart: Int, oldSelEnd: Int, newSelStart: Int, newSelEnd: Int, candidatesStart: Int, candidatesEnd: Int) {
|
override fun onUpdateSelection(oldSelStart: Int, oldSelEnd: Int, newSelStart: Int, newSelEnd: Int, candidatesStart: Int, candidatesEnd: Int) {
|
||||||
|
|
Loading…
Reference in New Issue