diff --git a/app/src/main/kotlin/com/simplemobiletools/keyboard/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/keyboard/helpers/Constants.kt new file mode 100644 index 0000000..97cf735 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/keyboard/helpers/Constants.kt @@ -0,0 +1,5 @@ +package com.simplemobiletools.keyboard.helpers + +const val SHIFT_OFF = 0 +const val SHIFT_ON_ONE_CHAR = 1 +const val SHIFT_ON_PERMANENT = 2 diff --git a/app/src/main/kotlin/com/simplemobiletools/keyboard/helpers/MyKeyboard.kt b/app/src/main/kotlin/com/simplemobiletools/keyboard/helpers/MyKeyboard.kt index 134b598..0871ff9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/keyboard/helpers/MyKeyboard.kt +++ b/app/src/main/kotlin/com/simplemobiletools/keyboard/helpers/MyKeyboard.kt @@ -67,7 +67,7 @@ class MyKeyboard { protected var mDefaultVerticalGap = 0 /** Is the keyboard in the shifted state */ - var isShifted = false + var shiftState = SHIFT_OFF /** Key instance for the shift key, if present */ private val mShiftKeys = arrayOf(null, null) @@ -562,13 +562,13 @@ class MyKeyboard { // also recalculate the vertical sizes/positions when we get this resize call. } - fun setShifted(shiftState: Boolean): Boolean { + fun setShifted(shiftState: Int): Boolean { for (shiftKey in mShiftKeys) { - shiftKey?.on = shiftState + shiftKey?.on = shiftState > SHIFT_OFF } - if (isShifted != shiftState) { - isShifted = shiftState + if (this.shiftState != shiftState) { + this.shiftState = shiftState return true } 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 e055121..edac81a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/keyboard/services/SimpleKeyboardIME.kt +++ b/app/src/main/kotlin/com/simplemobiletools/keyboard/services/SimpleKeyboardIME.kt @@ -7,13 +7,18 @@ import android.view.View import com.simplemobiletools.commons.extensions.performHapticFeedback import com.simplemobiletools.keyboard.R import com.simplemobiletools.keyboard.helpers.MyKeyboard +import com.simplemobiletools.keyboard.helpers.SHIFT_OFF +import com.simplemobiletools.keyboard.helpers.SHIFT_ON_ONE_CHAR +import com.simplemobiletools.keyboard.helpers.SHIFT_ON_PERMANENT import com.simplemobiletools.keyboard.views.MyKeyboardView // based on https://www.androidauthority.com/lets-build-custom-keyboard-android-832362/ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionListener { + private var SHIFT_PERM_TOGGLE_SPEED = 500 // how quickly do we have to doubletap shift to enable permanent caps lock + private var keyboard: MyKeyboard? = null private var keyboardView: MyKeyboardView? = null - private var caps = false + private var lastShiftPressTS = 0L override fun onCreateInputView(): View { keyboardView = layoutInflater.inflate(R.layout.keyboard_view_keyboard, null) as MyKeyboardView @@ -31,30 +36,46 @@ class SimpleKeyboardIME : InputMethodService(), MyKeyboardView.OnKeyboardActionL override fun onKey(primaryCode: Int, keyCodes: IntArray?) { val inputConnection = currentInputConnection - if (inputConnection != null) { - when (primaryCode) { - MyKeyboard.KEYCODE_DELETE -> { - val selectedText = inputConnection.getSelectedText(0) - if (TextUtils.isEmpty(selectedText)) { - inputConnection.deleteSurroundingText(1, 0) - } else { - inputConnection.commitText("", 1) - } - keyboard!!.isShifted = caps - keyboardView!!.invalidateAllKeys() + if (keyboard == null || inputConnection == null) { + return + } + + when (primaryCode) { + MyKeyboard.KEYCODE_DELETE -> { + if (keyboard!!.shiftState == SHIFT_ON_ONE_CHAR) { + keyboard!!.shiftState = SHIFT_OFF } - MyKeyboard.KEYCODE_SHIFT -> { - caps = !caps - keyboard!!.isShifted = caps - keyboardView!!.invalidateAllKeys() + + val selectedText = inputConnection.getSelectedText(0) + if (TextUtils.isEmpty(selectedText)) { + inputConnection.deleteSurroundingText(1, 0) + } else { + inputConnection.commitText("", 1) } - MyKeyboard.KEYCODE_DONE -> inputConnection.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)) - else -> { - var code = primaryCode.toChar() - if (Character.isLetter(code) && caps) { - code = Character.toUpperCase(code) - } - inputConnection.commitText(code.toString(), 1) + keyboardView!!.invalidateAllKeys() + } + MyKeyboard.KEYCODE_SHIFT -> { + when { + keyboard!!.shiftState == SHIFT_ON_PERMANENT -> keyboard!!.shiftState = SHIFT_OFF + System.currentTimeMillis() - lastShiftPressTS < SHIFT_PERM_TOGGLE_SPEED -> keyboard!!.shiftState = SHIFT_ON_PERMANENT + keyboard!!.shiftState == SHIFT_ON_ONE_CHAR -> keyboard!!.shiftState = SHIFT_OFF + keyboard!!.shiftState == SHIFT_OFF -> keyboard!!.shiftState = SHIFT_ON_ONE_CHAR + } + + lastShiftPressTS = System.currentTimeMillis() + keyboardView!!.invalidateAllKeys() + } + MyKeyboard.KEYCODE_DONE -> inputConnection.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER)) + else -> { + var code = primaryCode.toChar() + if (Character.isLetter(code) && keyboard!!.shiftState > SHIFT_OFF) { + code = Character.toUpperCase(code) + } + + inputConnection.commitText(code.toString(), 1) + if (keyboard!!.shiftState == SHIFT_ON_ONE_CHAR) { + keyboard!!.shiftState = SHIFT_OFF + keyboardView!!.invalidateAllKeys() } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/keyboard/views/MyKeyboardView.kt b/app/src/main/kotlin/com/simplemobiletools/keyboard/views/MyKeyboardView.kt index 05707b4..3e96f50 100644 --- a/app/src/main/kotlin/com/simplemobiletools/keyboard/views/MyKeyboardView.kt +++ b/app/src/main/kotlin/com/simplemobiletools/keyboard/views/MyKeyboardView.kt @@ -5,6 +5,7 @@ import android.content.Context import android.graphics.* import android.graphics.Paint.Align import android.graphics.drawable.Drawable +import android.inputmethodservice.KeyboardView import android.media.AudioManager import android.os.Handler import android.os.Message @@ -18,6 +19,9 @@ import android.widget.PopupWindow import android.widget.TextView import com.simplemobiletools.keyboard.R import com.simplemobiletools.keyboard.helpers.MyKeyboard +import com.simplemobiletools.keyboard.helpers.SHIFT_OFF +import com.simplemobiletools.keyboard.helpers.SHIFT_ON_ONE_CHAR +import com.simplemobiletools.keyboard.helpers.SHIFT_ON_PERMANENT import java.util.* /** @@ -415,13 +419,11 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut * @return true if the shift key state changed, false if there was no change * @see KeyboardView.isShifted */ - fun setShifted(shifted: Boolean): Boolean { - if (mKeyboard?.setShifted(shifted) == true) { + fun setShifted(shiftState: Int) { + if (mKeyboard?.setShifted(shiftState) == true) { // The whole keyboard probably needs to be redrawn invalidateAllKeys() - return true } - return false } /** @@ -431,7 +433,7 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut * @see KeyboardView.setShifted */ fun isShifted(): Boolean { - return mKeyboard?.isShifted ?: false + return mKeyboard?.shiftState ?: SHIFT_OFF > SHIFT_OFF } fun setPopupParent(v: View) { @@ -456,7 +458,7 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut private fun adjustCase(label: CharSequence): CharSequence? { var newLabel: CharSequence? = label - if (newLabel != null && newLabel.isNotEmpty() && mKeyboard!!.isShifted && newLabel.length < 3 && Character.isLowerCase(newLabel[0])) { + if (newLabel != null && newLabel.isNotEmpty() && mKeyboard!!.shiftState > SHIFT_OFF && newLabel.length < 3 && Character.isLowerCase(newLabel[0])) { newLabel = newLabel.toString().toUpperCase() } return newLabel @@ -598,12 +600,12 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut ) // Turn off drop shadow paint.setShadowLayer(0f, 0f, 0f, 0) - } else if (key.icon != null) { + } else if (key.icon != null && mKeyboard != null) { if (key.codes.size == 1 && key.codes.contains(-1)) { - val drawableId = if (isShifted()) { - R.drawable.ic_caps_vector - } else { - R.drawable.ic_caps_outline_vector + val drawableId = when (mKeyboard!!.shiftState) { + SHIFT_OFF -> R.drawable.ic_caps_outline_vector + SHIFT_ON_ONE_CHAR -> R.drawable.ic_caps_vector + else -> R.drawable.ic_caps_underlined_vector } key.icon = resources.getDrawable(drawableId) } @@ -808,7 +810,11 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut mPreviewText!!.setCompoundDrawables(null, null, null, bottomDrawable) } else { mPreviewText!!.setCompoundDrawables(null, null, null, null) - mPreviewText!!.text = getPreviewText(key) + try { + mPreviewText!!.text = getPreviewText(key) + } catch (ignored: Exception) { + } + if (key.label.length > 1 && key.codes.size < 2) { mPreviewText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize.toFloat()) mPreviewText!!.typeface = Typeface.DEFAULT_BOLD @@ -1020,7 +1026,9 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut val x = mPopupX + mMiniKeyboardContainer!!.paddingRight + mCoordinates[0] val y = mPopupY + mMiniKeyboardContainer!!.paddingBottom + mCoordinates[1] mMiniKeyboard!!.setPopupOffset(if (x < 0) 0 else x, y) - mMiniKeyboard!!.setShifted(isShifted()) + + val miniShiftStatus = if (isShifted()) SHIFT_ON_PERMANENT else SHIFT_OFF + mMiniKeyboard!!.setShifted(miniShiftStatus) mPopupKeyboard.contentView = mMiniKeyboardContainer mPopupKeyboard.width = mMiniKeyboardContainer!!.measuredWidth mPopupKeyboard.height = mMiniKeyboardContainer!!.measuredHeight