Skip to content

Commit

Permalink
RELEASE build, fixed fast typing (wultiple touch events)
Browse files Browse the repository at this point in the history
  • Loading branch information
roalyr committed Dec 22, 2024
1 parent 2cea4e4 commit 8eca53c
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 26 deletions.
10 changes: 8 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,28 @@ plugins {
id("org.jetbrains.kotlin.plugin.serialization")
}
android {
signingConfigs {
create("release") {
}
}
namespace = "com.roalyr.customkeyboardengine"
compileSdk = 34

defaultConfig {
applicationId = "com.roalyr.customkeyboardengine"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.2"
versionCode = 2
versionName = "1.2.1"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
versionNameSuffix = "-beta"
}


buildTypes {
release {
isMinifyEnabled = false
Expand Down
Binary file added app/release/baselineProfiles/0/app-release.dm
Binary file not shown.
Binary file added app/release/baselineProfiles/1/app-release.dm
Binary file not shown.
37 changes: 37 additions & 0 deletions app/release/output-metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.roalyr.customkeyboardengine",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 2,
"versionName": "1.2.1-beta",
"outputFile": "app-release.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/app-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/app-release.dm"
]
}
],
"minSdkVersionForDexing": 26
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,12 @@ class CustomKeyboardView @JvmOverloads constructor(
private var isKeyRepeated = false
private var isLongPressHandled = false
private var downKeyIndex = -1
private var currentKey: Key? = null

private var repeatKeyRunnable: Runnable? = null

private val activeKeys = mutableMapOf<Int, Key?>() // Track active keys by pointer ID


companion object {
private const val TAG = "CustomKeyboardView"
private const val MSG_LONGPRESS = 1
Expand All @@ -71,7 +74,6 @@ class CustomKeyboardView @JvmOverloads constructor(
private const val REPEAT_START_DELAY = 250
}

///////////////////////////////////
// INIT
init {
isFocusable = true
Expand All @@ -87,10 +89,7 @@ class CustomKeyboardView @JvmOverloads constructor(
invalidateAllKeys()
}


/////////////////////////////////////
// Handle events

private val handlerCallback = Handler.Callback { msg ->
if (msg.what == MSG_LONGPRESS) {
val key = msg.obj as? Key
Expand All @@ -105,7 +104,7 @@ class CustomKeyboardView @JvmOverloads constructor(

private val handler = Handler(Looper.getMainLooper(), handlerCallback)

private fun handleTouchDown(x: Int, y: Int) {
private fun handleTouchDown(x: Int, y: Int, pointerId: Int) {
val key = keyboard?.getKeyAt(x.toFloat(), y.toFloat()) ?: return

downKeyIndex = keys?.indexOf(key) ?: -1
Expand All @@ -120,35 +119,40 @@ class CustomKeyboardView @JvmOverloads constructor(
scheduleLongPress(key)
}

// Save key reference for later use in handleTouchUp
currentKey = key
// Save key reference in the activeKeys map
activeKeys[pointerId] = key
}

private fun handleTouchUp(x: Int, y: Int) {
// Cancel repeat and long press behavior

private fun handleTouchUp(x: Int, y: Int, pointerId: Int) {
cancelRepeatKey()
handler.removeMessages(MSG_LONGPRESS)

currentKey?.let { key ->
// Retrieve the key associated with this pointer ID
val key = activeKeys[pointerId]

key?.let {
when {
isLongPressHandled -> {
// Skip short press if long press is already handled
return
}
isKeyRepeated -> {
// Skip short press if key repeat is already handled
return
}
else -> {
keyboardActionListener?.onKey(key.keyCode, key.label)
keyboardActionListener?.onKey(it.keyCode, it.label)
}
}
}

// Reset states
// Reset states for this pointer
isLongPressHandled = false
isKeyRepeated = false
currentKey = null
activeKeys.remove(pointerId)
}



private fun handleLongPress(key: Key) {
isLongPressHandled = true
keyboardActionListener?.onKey(key.keyCodeLongPress, key.smallLabel)
Expand Down Expand Up @@ -203,22 +207,54 @@ class CustomKeyboardView @JvmOverloads constructor(
}

override fun onTouchEvent(event: MotionEvent): Boolean {
val action = event.action
val scaledX = (event.x / scaleX).toInt()
val scaledY = (event.y / scaleY).toInt()
val actionMasked = event.actionMasked // Use actionMasked for multi-touch support
val pointerIndex = event.actionIndex // Index of the pointer causing the event
val pointerId = event.getPointerId(pointerIndex)

when (actionMasked) {
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
// Handle new touch
val scaledX = (event.getX(pointerIndex) / scaleX).toInt()
val scaledY = (event.getY(pointerIndex) / scaleY).toInt()
handleTouchDown(scaledX, scaledY, pointerId)
performClick()
//Log.d("TOUCH", "Pointer Down: Index $pointerIndex, x=$scaledX, y=$scaledY")
}

when (action) {
MotionEvent.ACTION_DOWN -> {
handleTouchDown(scaledX, scaledY)
MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
// Handle touch release
val scaledX = (event.getX(pointerIndex) / scaleX).toInt()
val scaledY = (event.getY(pointerIndex) / scaleY).toInt()
handleTouchUp(scaledX, scaledY, pointerId)
performClick()
//Log.d("TOUCH", "Pointer Up: Index $pointerIndex, x=$scaledX, y=$scaledY")
}

MotionEvent.ACTION_MOVE -> handleTouchMove(scaledX, scaledY)
MotionEvent.ACTION_UP -> handleTouchUp(scaledX, scaledY)
MotionEvent.ACTION_MOVE -> {
// Handle touch move for all active pointers
//for (i in 0 until event.pointerCount) {
//val scaledX = (event.getX(i) / scaleX).toInt()
//val scaledY = (event.getY(i) / scaleY).toInt()
//handleTouchMove(scaledX, scaledY)
//Log.d("TOUCH", "Pointer Move: Index $i, x=$scaledX, y=$scaledY")
//}
}

MotionEvent.ACTION_CANCEL -> {
// Handle cancel action if necessary
//Log.d("TOUCH", "Action Cancel")
}
}
return true
}


override fun performClick(): Boolean {
// Call the superclass implementation (important for accessibility events)
super.performClick()
return true
}

private fun handleTouchMove(x: Int, y: Int) {
// Optional: Cancel repeat/long press if the finger moves off the key
if (keyboard?.getKeyAt(x.toFloat(), y.toFloat()) == null) {
Expand Down

0 comments on commit 8eca53c

Please sign in to comment.