mirror of
https://github.com/florisboard/florisboard.git
synced 2024-09-19 19:42:20 +02:00
Implement auto selection of keyViews and ability to cancel key presses
ELI5: When you press on a key and the while holding down move you couldn't escape that key press. Now, if you move to far, it cancels the initial key press and triggers a new one at the location your pointer is currently on. Also works for extended popups.
This commit is contained in:
parent
138efec980
commit
f0950fb879
@ -11,7 +11,6 @@ import android.os.VibrationEffect
|
||||
import android.os.Vibrator
|
||||
import android.util.TypedValue
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import androidx.core.content.ContextCompat.getDrawable
|
||||
@ -29,8 +28,7 @@ class KeyView(
|
||||
context: Context, val data: KeyData, private val florisboard: FlorisBoard, private val keyboardView: KeyboardView
|
||||
) : AppCompatButton(
|
||||
context, null, R.attr.keyViewStyle
|
||||
), View.OnTouchListener {
|
||||
|
||||
) {
|
||||
private var isKeyPressed: Boolean = false
|
||||
set(value) {
|
||||
field = value
|
||||
@ -42,8 +40,6 @@ class KeyView(
|
||||
private var shouldBlockNextKeyCode: Boolean = false
|
||||
|
||||
init {
|
||||
super.setOnTouchListener(this)
|
||||
|
||||
val flexLayoutParams = FlexboxLayout.LayoutParams(
|
||||
FlexboxLayout.LayoutParams.WRAP_CONTENT, FlexboxLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
@ -124,7 +120,7 @@ class KeyView(
|
||||
|
||||
private fun keyPressSound() {
|
||||
if (florisboard.prefs!!.soundEnabled) {
|
||||
var soundVolume = florisboard.prefs!!.soundVolume
|
||||
val soundVolume = florisboard.prefs!!.soundVolume
|
||||
val effect = when (data.code) {
|
||||
KeyCode.SPACE -> AudioManager.FX_KEYPRESS_SPACEBAR
|
||||
KeyCode.DELETE -> AudioManager.FX_KEYPRESS_DELETE
|
||||
@ -139,8 +135,10 @@ class KeyView(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
||||
when (event.action) {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
||||
val event = event ?: return false
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
popupManager.show()
|
||||
isKeyPressed = true
|
||||
@ -169,6 +167,21 @@ class KeyView(
|
||||
}
|
||||
}, delayMillis.toLong())
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (popupManager.isShowingExtendedPopup) {
|
||||
val isPointerWithinBounds = popupManager.propagateMotionEvent(event)
|
||||
if (!isPointerWithinBounds && !shouldBlockNextKeyCode) {
|
||||
keyboardView.shouldStealMotionEvents = true
|
||||
}
|
||||
} else {
|
||||
if (event.x < -0.1f * measuredWidth || event.x > 1.1f * measuredWidth
|
||||
|| event.y < -0.35f * measuredHeight || event.y > 1.35f * measuredHeight) {
|
||||
if (!shouldBlockNextKeyCode) {
|
||||
keyboardView.shouldStealMotionEvents = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
isKeyPressed = false
|
||||
osHandler.removeCallbacksAndMessages(null)
|
||||
@ -176,18 +189,12 @@ class KeyView(
|
||||
osTimer = null
|
||||
val retData = popupManager.getActiveKeyData()
|
||||
popupManager.hide()
|
||||
if (event.action == MotionEvent.ACTION_UP && !shouldBlockNextKeyCode) {
|
||||
if (event.actionMasked != MotionEvent.ACTION_CANCEL && !shouldBlockNextKeyCode) {
|
||||
florisboard.sendKeyPress(retData)
|
||||
} else {
|
||||
shouldBlockNextKeyCode = false
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
// TODO: Add cancel event if pointer moves to far from key and popup window
|
||||
if (popupManager.isShowingExtendedPopup) {
|
||||
popupManager.propagateMotionEvent(event)
|
||||
}
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
|
@ -1,7 +1,9 @@
|
||||
package dev.patrickgold.florisboard.ime.keyboard
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import dev.patrickgold.florisboard.R
|
||||
|
||||
@ -17,4 +19,13 @@ class KeyboardRowView : FlexboxLayout {
|
||||
resources.getDimension(R.dimen.keyboard_row_marginV).toInt()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onInterceptTouchEvent(event: MotionEvent?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package dev.patrickgold.florisboard.ime.keyboard
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.ContextThemeWrapper
|
||||
import android.view.MotionEvent
|
||||
import android.widget.LinearLayout
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
@ -15,10 +16,10 @@ class KeyboardView(
|
||||
) : LinearLayout(
|
||||
context, null, R.attr.keyboardViewStyle
|
||||
) {
|
||||
|
||||
var computedLayout: ComputedLayoutData? = null
|
||||
var desiredKeyWidth: Int = resources.getDimension(R.dimen.key_width).toInt()
|
||||
var desiredKeyHeight: Int = resources.getDimension(R.dimen.key_height).toInt()
|
||||
var shouldStealMotionEvents: Boolean = false
|
||||
|
||||
private fun buildLayout() {
|
||||
destroyLayout()
|
||||
@ -51,6 +52,19 @@ class KeyboardView(
|
||||
buildLayout()
|
||||
}
|
||||
|
||||
override fun onInterceptTouchEvent(event: MotionEvent?): Boolean {
|
||||
return shouldStealMotionEvents
|
||||
}
|
||||
|
||||
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
||||
shouldStealMotionEvents = false
|
||||
if (event != null && event.action == MotionEvent.ACTION_MOVE) {
|
||||
event.action = MotionEvent.ACTION_DOWN
|
||||
dispatchTouchEvent(event)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val widthSize = MeasureSpec.getSize(widthMeasureSpec)
|
||||
|
||||
|
@ -86,10 +86,7 @@ class KeyPopupManager(
|
||||
else -> View.VISIBLE
|
||||
}
|
||||
val w = createPopupWindow(popupView, keyPopupWidth, keyPopupHeight)
|
||||
w.setTouchInterceptor { _, event ->
|
||||
keyView.dispatchTouchEvent(event)
|
||||
true
|
||||
}
|
||||
w.setTouchInterceptor { _, _ -> false }
|
||||
w.showAsDropDown(keyView, ((keyView.measuredWidth - keyPopupWidth) / 2), -keyPopupHeight)
|
||||
window = w
|
||||
}
|
||||
@ -141,15 +138,26 @@ class KeyPopupManager(
|
||||
windowExt = w
|
||||
}
|
||||
|
||||
fun propagateMotionEvent(event: MotionEvent) {
|
||||
fun propagateMotionEvent(event: MotionEvent): Boolean {
|
||||
if (!isShowingExtendedPopup) {
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
val kX: Float = event.x / keyPopupWidth.toFloat()
|
||||
val keyPopupDiffX = ((keyView.measuredWidth - keyPopupWidth) / 2)
|
||||
|
||||
// check if out of boundary on y-axis
|
||||
if (event.y < -keyPopupHeight || event.y > 0.9f * keyPopupHeight) {
|
||||
return false
|
||||
}
|
||||
|
||||
activeExtIndex = when {
|
||||
anchorLeft -> when {
|
||||
// check if out of boundary on x-axis
|
||||
event.x < keyPopupDiffX - keyPopupWidth ||
|
||||
event.x > (keyPopupDiffX + (row0count + 1) * keyPopupWidth) -> {
|
||||
return false
|
||||
}
|
||||
// row 1
|
||||
event.y < 0 && row1count > 0 -> when {
|
||||
kX >= row1count -> row1count - 1
|
||||
@ -164,6 +172,11 @@ class KeyPopupManager(
|
||||
}
|
||||
}
|
||||
anchorRight -> when {
|
||||
// check if out of boundary on x-axis
|
||||
event.x > keyView.measuredWidth - keyPopupDiffX + keyPopupWidth ||
|
||||
event.x < (keyView.measuredWidth - keyPopupDiffX - (row0count + 1) * keyPopupWidth) -> {
|
||||
return false
|
||||
}
|
||||
// row 1
|
||||
event.y < 0 && row1count > 0 -> when {
|
||||
kX >= 0 -> row1count - 1
|
||||
@ -184,6 +197,8 @@ class KeyPopupManager(
|
||||
val textView = popupViewExt.getChildAt(k) as KeyPopupExtendedSingleView
|
||||
textView.isActive = k == activeExtIndex
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun getActiveKeyData(): KeyData {
|
||||
|
Loading…
Reference in New Issue
Block a user