mirror of
https://github.com/geode-sdk/android-launcher.git
synced 2026-10-21 16:32:39 +00:00
Merge branch 'orchid-pruning'
This commit is contained in:
11 files changed
+609
-76
No files matched your search
@@ -125,7 +125,7 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".GeometryDashActivity"
|
android:name=".GeometryDashActivity"
|
||||||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard"
|
android:configChanges="fontScale|layoutDirection|density|smallestScreenSize|screenSize|uiMode|screenLayout|orientation|navigation|keyboardHidden|keyboard|locale"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:screenOrientation="landscape"
|
android:screenOrientation="landscape"
|
||||||
|
|||||||
@@ -2,33 +2,106 @@ package com.customRobTop
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.*
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.provider.DocumentsContract
|
||||||
|
import android.provider.OpenableColumns
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
|
import com.customRobTop.contracts.ImportFileActivityContract
|
||||||
|
import com.customRobTop.contracts.ShareFileActivityContract
|
||||||
import com.geode.launcher.R
|
import com.geode.launcher.R
|
||||||
|
import com.geode.launcher.utils.DownloadUtils
|
||||||
|
import com.geode.launcher.utils.LaunchUtils
|
||||||
|
import org.cocos2dx.lib.Cocos2dxGLSurfaceView
|
||||||
import org.cocos2dx.lib.Cocos2dxGLSurfaceView.Companion.closeIMEKeyboard
|
import org.cocos2dx.lib.Cocos2dxGLSurfaceView.Companion.closeIMEKeyboard
|
||||||
import org.cocos2dx.lib.Cocos2dxGLSurfaceView.Companion.openIMEKeyboard
|
import org.cocos2dx.lib.Cocos2dxGLSurfaceView.Companion.openIMEKeyboard
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.OutputStream
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.*
|
import java.util.UUID
|
||||||
|
|
||||||
|
|
||||||
@Suppress("unused", "UNUSED_PARAMETER")
|
@Suppress("unused", "UNUSED_PARAMETER")
|
||||||
object BaseRobTopActivity {
|
object BaseRobTopActivity {
|
||||||
|
const val KEYBOARD_INPUT_MULTILINE = 1
|
||||||
|
const val KEYBOARD_INPUT_NUMERIC = 4
|
||||||
|
const val KEYBOARD_INPUT_PASSWORD = 2
|
||||||
|
const val LEVEL_EXTENSION: String = ".gdlvl"
|
||||||
|
|
||||||
private var isLoaded = false
|
private var isLoaded = false
|
||||||
var blockBackButton = false
|
var blockBackButton = false
|
||||||
private var keyboardActive = false
|
private var keyboardActive = false
|
||||||
|
var curKeyboardInputFlags = 0
|
||||||
|
|
||||||
var isPaused = false
|
var isPaused = false
|
||||||
|
|
||||||
lateinit var me: WeakReference<Activity>
|
lateinit var me: WeakReference<Activity>
|
||||||
private var shouldResumeSound = true
|
private var shouldResumeSound = true
|
||||||
|
|
||||||
fun setCurrentActivity(currentActivity: Activity) {
|
private var pendingExportPaths = emptyList<String>()
|
||||||
|
|
||||||
|
private lateinit var importFileActivityContract: ActivityResultLauncher<Unit>
|
||||||
|
private lateinit var shareFileActivityContract: ActivityResultLauncher<String>
|
||||||
|
private lateinit var shareFolderActivityContract: ActivityResultLauncher<Uri?>
|
||||||
|
|
||||||
|
fun setCurrentActivity(currentActivity: AppCompatActivity) {
|
||||||
me = WeakReference(currentActivity)
|
me = WeakReference(currentActivity)
|
||||||
|
|
||||||
|
importFileActivityContract = currentActivity.registerForActivityResult(ImportFileActivityContract()) { uris ->
|
||||||
|
val filePaths = copyPickedFiles(uris)
|
||||||
|
|
||||||
|
Cocos2dxGLSurfaceView.cocos2dxGLSurfaceView.queueEvent {
|
||||||
|
JniToCpp.filesPicked(filePaths.toTypedArray())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shareFileActivityContract = currentActivity.registerForActivityResult(ShareFileActivityContract()) { uri ->
|
||||||
|
val currentlyPending = pendingExportPaths
|
||||||
|
pendingExportPaths = emptyList()
|
||||||
|
|
||||||
|
val exportPath = currentlyPending.firstOrNull()
|
||||||
|
if (exportPath == null || uri == null) {
|
||||||
|
Cocos2dxGLSurfaceView.cocos2dxGLSurfaceView.queueEvent {
|
||||||
|
JniToCpp.fileShareFinished(false)
|
||||||
|
}
|
||||||
|
return@registerForActivityResult
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = saveToDocument(exportPath, uri)
|
||||||
|
Cocos2dxGLSurfaceView.cocos2dxGLSurfaceView.queueEvent {
|
||||||
|
JniToCpp.fileShareFinished(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shareFolderActivityContract = currentActivity.registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
|
||||||
|
val currentlyPending = pendingExportPaths
|
||||||
|
pendingExportPaths = emptyList()
|
||||||
|
|
||||||
|
if (uri == null) {
|
||||||
|
Cocos2dxGLSurfaceView.cocos2dxGLSurfaceView.queueEvent {
|
||||||
|
JniToCpp.fileShareFinished(false)
|
||||||
|
}
|
||||||
|
return@registerForActivityResult
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = saveToFolder(currentlyPending, uri) > 0
|
||||||
|
Cocos2dxGLSurfaceView.cocos2dxGLSurfaceView.queueEvent {
|
||||||
|
JniToCpp.fileShareFinished(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("HardwareIds")
|
@SuppressLint("HardwareIds")
|
||||||
@@ -87,6 +160,18 @@ object BaseRobTopActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getClipboardString(): String {
|
||||||
|
me.get()?.run {
|
||||||
|
val manager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
|
val clip = manager.primaryClip
|
||||||
|
if (clip != null && clip.itemCount > 0) {
|
||||||
|
return clip.getItemAt(0).coerceToText(this).toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun sendMail(subject: String, body: String, to: String) {
|
fun sendMail(subject: String, body: String, to: String) {
|
||||||
me.get()?.runOnUiThread {
|
me.get()?.runOnUiThread {
|
||||||
@@ -264,4 +349,164 @@ object BaseRobTopActivity {
|
|||||||
level = DeprecationLevel.HIDDEN
|
level = DeprecationLevel.HIDDEN
|
||||||
)
|
)
|
||||||
fun logEvent(event: String) {}
|
fun logEvent(event: String) {}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun setKeyboardInputFlags(flags: Int) {
|
||||||
|
curKeyboardInputFlags = flags
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun pickImportFiles() {
|
||||||
|
try {
|
||||||
|
importFileActivityContract.launch(Unit)
|
||||||
|
} catch (_: ActivityNotFoundException) {
|
||||||
|
me.get()?.apply {
|
||||||
|
runOnUiThread {
|
||||||
|
Toast.makeText(
|
||||||
|
this,
|
||||||
|
R.string.no_activity_found,
|
||||||
|
Toast.LENGTH_SHORT,
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun copyPickedFiles(uris: List<Uri>): List<String> {
|
||||||
|
val me = me.get() ?: return emptyList()
|
||||||
|
|
||||||
|
val importsDir = File(LaunchUtils.getSaveDirectory(me), "imports")
|
||||||
|
importsDir.mkdirs()
|
||||||
|
|
||||||
|
return uris.mapIndexedNotNull { index, uri ->
|
||||||
|
val displayName = displayName(uri)
|
||||||
|
?: "import_$index$LEVEL_EXTENSION"
|
||||||
|
if (!displayName.endsWith(LEVEL_EXTENSION)) {
|
||||||
|
return@mapIndexedNotNull null
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputFile = File(importsDir, displayName)
|
||||||
|
var counter = 2
|
||||||
|
while (outputFile.exists()) {
|
||||||
|
outputFile = File(importsDir, "${counter}_$displayName")
|
||||||
|
counter++
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
me.contentResolver.openInputStream(uri)?.use { input ->
|
||||||
|
outputFile.outputStream().use { output ->
|
||||||
|
DownloadUtils.copyFile(input, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
outputFile.absolutePath
|
||||||
|
}
|
||||||
|
} catch (_: Exception) {
|
||||||
|
outputFile.delete()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun displayName(uri: Uri): String? {
|
||||||
|
me.get()?.contentResolver?.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)?.use { cursorQuery ->
|
||||||
|
if (cursorQuery.moveToFirst()) {
|
||||||
|
val displayName = cursorQuery.getString(0)
|
||||||
|
if (displayName.isNotEmpty()) {
|
||||||
|
return File(displayName).name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun shareFiles(files: Array<String>) {
|
||||||
|
pendingExportPaths = files.toList()
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (files.size == 1) {
|
||||||
|
shareFileActivityContract.launch(files.first())
|
||||||
|
return
|
||||||
|
} else if (files.size > 1) {
|
||||||
|
shareFolderActivityContract.launch(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (_: ActivityNotFoundException) {
|
||||||
|
me.get()?.apply {
|
||||||
|
runOnUiThread {
|
||||||
|
Toast.makeText(
|
||||||
|
this,
|
||||||
|
R.string.no_activity_found,
|
||||||
|
Toast.LENGTH_SHORT,
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cocos2dxGLSurfaceView.cocos2dxGLSurfaceView.queueEvent {
|
||||||
|
JniToCpp.fileShareFinished(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveToFolder(exportPaths: List<String>, treeUri: Uri): Int {
|
||||||
|
val uri = DocumentsContract.buildDocumentUriUsingTree(treeUri, DocumentsContract.getTreeDocumentId(treeUri))
|
||||||
|
|
||||||
|
val me = me.get() ?: return 0
|
||||||
|
|
||||||
|
return exportPaths.count { path ->
|
||||||
|
val filename = File(path).name
|
||||||
|
val documentUri = DocumentsContract.createDocument(me.contentResolver, uri, "application/octet-stream", filename)
|
||||||
|
?: return@count false
|
||||||
|
|
||||||
|
saveToDocument(path, documentUri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveToDocument(exportPath: String, uri: Uri): Boolean {
|
||||||
|
try {
|
||||||
|
FileInputStream(exportPath).use { inputStream ->
|
||||||
|
openOutput(uri).use { outputStream ->
|
||||||
|
if (outputStream != null) {
|
||||||
|
DownloadUtils.copyFile(inputStream, outputStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureLevelExtension(uri)
|
||||||
|
return true
|
||||||
|
} catch (_: IOException) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openOutput(uri: Uri): OutputStream? {
|
||||||
|
val me = me.get() ?: return null
|
||||||
|
return try {
|
||||||
|
me.contentResolver.openOutputStream(uri, "wt")
|
||||||
|
} catch (_: IOException) {
|
||||||
|
me.contentResolver.openOutputStream(uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ensureLevelExtension(uri: Uri) {
|
||||||
|
val displayName = displayName(uri)
|
||||||
|
if (displayName == null || displayName.endsWith(LEVEL_EXTENSION)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val me = me.get() ?: return
|
||||||
|
|
||||||
|
val extensionIdx = displayName.lastIndexOf(".gdlvl.")
|
||||||
|
val substring = if (extensionIdx < 0) {
|
||||||
|
displayName + LEVEL_EXTENSION
|
||||||
|
} else {
|
||||||
|
displayName.substring(0, extensionIdx + 6)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
DocumentsContract.renameDocument(me.contentResolver, uri, substring)
|
||||||
|
} catch (_: IOException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -55,4 +55,16 @@ object JniToCpp {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
external fun videoAdShowed()
|
external fun videoAdShowed()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
external fun filesPicked(files: Array<String>)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
external fun fileShareFinished(success: Boolean)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
external fun textInputCaretToEnd()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
external fun textInputDone()
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.customRobTop.contracts
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.activity.result.contract.ActivityResultContract
|
||||||
|
|
||||||
|
class ImportFileActivityContract : ActivityResultContract<Unit, List<Uri>>() {
|
||||||
|
override fun createIntent(
|
||||||
|
context: Context,
|
||||||
|
input: Unit
|
||||||
|
): Intent {
|
||||||
|
return Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||||
|
addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
type = "*/*"
|
||||||
|
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun parseResult(
|
||||||
|
resultCode: Int,
|
||||||
|
intent: Intent?
|
||||||
|
): List<Uri> {
|
||||||
|
if (resultCode != Activity.RESULT_OK || intent == null) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
val clipData = intent.clipData
|
||||||
|
return if (clipData != null) {
|
||||||
|
List(clipData.itemCount) { i -> clipData.getItemAt(i).uri }
|
||||||
|
} else {
|
||||||
|
val intentData = intent.data
|
||||||
|
if (intentData != null)
|
||||||
|
listOf(intentData)
|
||||||
|
else
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.customRobTop.contracts
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.DocumentsContract
|
||||||
|
import androidx.activity.result.contract.ActivityResultContract
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class ShareFileActivityContract : ActivityResultContract<String, Uri?>() {
|
||||||
|
override fun createIntent(
|
||||||
|
context: Context,
|
||||||
|
input: String
|
||||||
|
): Intent {
|
||||||
|
return Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
|
||||||
|
addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
type = "application/octet-stream"
|
||||||
|
putExtra(Intent.EXTRA_TITLE, File(input).name)
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
putExtra(DocumentsContract.EXTRA_INITIAL_URI,
|
||||||
|
DocumentsContract.buildDocumentUri("com.android.externalstorage.documents", "primary:Download")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun parseResult(
|
||||||
|
resultCode: Int,
|
||||||
|
intent: Intent?
|
||||||
|
): Uri? {
|
||||||
|
if (resultCode != Activity.RESULT_OK || intent == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return intent.data
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -171,7 +171,8 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
|||||||
tryLoadLibrary(gdPackageInfo, Constants.FMOD_LIB_NAME)
|
tryLoadLibrary(gdPackageInfo, Constants.FMOD_LIB_NAME)
|
||||||
tryLoadLibrary(gdPackageInfo, Constants.COCOS_LIB_NAME)
|
tryLoadLibrary(gdPackageInfo, Constants.COCOS_LIB_NAME)
|
||||||
|
|
||||||
if (GamePackageUtils.getGameVersionCode(packageManager) >= 39L) {
|
val gameVersionCode = GamePackageUtils.getGameVersionCode(packageManager)
|
||||||
|
if (gameVersionCode >= 39L) {
|
||||||
// this fix requires geode v3, which is 2.206+
|
// this fix requires geode v3, which is 2.206+
|
||||||
// there is a short period in which 2.206 users will still have geode v2, but whatever. ig
|
// there is a short period in which 2.206 users will still have geode v2, but whatever. ig
|
||||||
LauncherFix.enableExceptionsRenaming()
|
LauncherFix.enableExceptionsRenaming()
|
||||||
@@ -182,6 +183,9 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
|||||||
loadInternalMods()
|
loadInternalMods()
|
||||||
|
|
||||||
val baseView = createView()
|
val baseView = createView()
|
||||||
|
if (gameVersionCode >= 42L) {
|
||||||
|
mGLSurfaceView?.sendNewCocosEvents = true
|
||||||
|
}
|
||||||
|
|
||||||
if (!GeodeUtils.handleSafeArea && Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {
|
if (!GeodeUtils.handleSafeArea && Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {
|
||||||
val frameLayoutParams = ViewGroup.LayoutParams(
|
val frameLayoutParams = ViewGroup.LayoutParams(
|
||||||
@@ -205,12 +209,22 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
|||||||
left = 0, top = 0, right = 0, bottom = 0
|
left = 0, top = 0, right = 0, bottom = 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cocos2dxGLSurfaceView.onKeyboardInsets(insets)
|
||||||
|
|
||||||
WindowInsets.CONSUMED
|
WindowInsets.CONSUMED
|
||||||
}
|
}
|
||||||
|
|
||||||
frameLayout.addView(baseView)
|
frameLayout.addView(baseView)
|
||||||
setContentView(frameLayout)
|
setContentView(frameLayout)
|
||||||
} else {
|
} else {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
baseView.setOnApplyWindowInsetsListener { view, insets ->
|
||||||
|
Cocos2dxGLSurfaceView.onKeyboardInsets(insets)
|
||||||
|
return@setOnApplyWindowInsetsListener view.onApplyWindowInsets(insets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setContentView(baseView)
|
setContentView(baseView)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,6 +511,10 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
|||||||
editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
|
editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
|
||||||
glSurfaceView.cocos2dxEditText = editText
|
glSurfaceView.cocos2dxEditText = editText
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
glSurfaceView.defaultFocusHighlightEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
return frameLayout
|
return frameLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ object GamePackageUtils {
|
|||||||
39L to "2.206",
|
39L to "2.206",
|
||||||
40L to "2.2074", // ok
|
40L to "2.2074", // ok
|
||||||
41L to "2.2081",
|
41L to "2.2081",
|
||||||
|
42L to "2.209",
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -800,7 +800,7 @@ object GeodeUtils {
|
|||||||
|
|
||||||
external fun internalKeyEvent(timestamp: Long, deviceId: Int, eventSource: Int, keyCode: Int, modifiers: Int, isDown: Boolean, repeatCount: Int)
|
external fun internalKeyEvent(timestamp: Long, deviceId: Int, eventSource: Int, keyCode: Int, modifiers: Int, isDown: Boolean, repeatCount: Int)
|
||||||
external fun internalTouchEvent(timestamp: Long, deviceId: Int, eventSource: Int, eventType: Int, ids: IntArray, xs: FloatArray, ys: FloatArray)
|
external fun internalTouchEvent(timestamp: Long, deviceId: Int, eventSource: Int, eventType: Int, ids: IntArray, xs: FloatArray, ys: FloatArray)
|
||||||
external fun internalScrollEvent(timestamp: Long, deviceId: Int, eventSource: Int, scrollX: Float, scrollY: Float)
|
external fun internalScrollEvent(timestamp: Long, deviceId: Int, eventSource: Int, scrollX: Float, scrollY: Float, mouseX: Float, mouseY: Float)
|
||||||
external fun internalJoystickEvent(timestamp: Long, deviceId: Int, eventSource: Int, leftX: FloatArray, leftY: FloatArray, rightX: FloatArray, rightY: FloatArray, hatX: FloatArray, hatY: FloatArray, leftTrigger: FloatArray, rightTrigger: FloatArray)
|
external fun internalJoystickEvent(timestamp: Long, deviceId: Int, eventSource: Int, leftX: FloatArray, leftY: FloatArray, rightX: FloatArray, rightY: FloatArray, hatX: FloatArray, hatY: FloatArray, leftTrigger: FloatArray, rightTrigger: FloatArray)
|
||||||
|
|
||||||
external fun inputDeviceAdded(deviceId: Int)
|
external fun inputDeviceAdded(deviceId: Int)
|
||||||
|
|||||||
@@ -8,11 +8,13 @@ import android.os.Build
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.os.Message
|
import android.os.Message
|
||||||
import android.util.Log
|
import android.text.InputType
|
||||||
import android.view.InputDevice
|
import android.view.InputDevice
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.Surface
|
import android.view.Surface
|
||||||
|
import android.view.WindowInsets
|
||||||
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.widget.AppCompatEditText
|
import androidx.appcompat.widget.AppCompatEditText
|
||||||
@@ -25,12 +27,54 @@ private const val HANDLER_CLOSE_IME_KEYBOARD = 3
|
|||||||
private const val MS_TO_NS = 1_000_000
|
private const val MS_TO_NS = 1_000_000
|
||||||
private const val SEC_TO_NS = 1_000_000_000.0
|
private const val SEC_TO_NS = 1_000_000_000.0
|
||||||
|
|
||||||
|
fun inputTypeForFlags(i: Int): Int {
|
||||||
|
if ((i and BaseRobTopActivity.KEYBOARD_INPUT_NUMERIC) != 0) {
|
||||||
|
return InputType.TYPE_NUMBER_FLAG_DECIMAL or InputType.TYPE_NUMBER_FLAG_SIGNED or InputType.TYPE_CLASS_NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i and BaseRobTopActivity.KEYBOARD_INPUT_PASSWORD) != 0) {
|
||||||
|
return InputType.TYPE_TEXT_VARIATION_PASSWORD or InputType.TYPE_CLASS_TEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i and BaseRobTopActivity.KEYBOARD_INPUT_MULTILINE) != 0) {
|
||||||
|
return InputType.TYPE_TEXT_FLAG_MULTI_LINE or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES or InputType.TYPE_CLASS_TEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
return InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS or InputType.TYPE_CLASS_TEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun usesInlineKeyboard(): Boolean {
|
||||||
|
return Build.VERSION.SDK_INT >= 30
|
||||||
|
}
|
||||||
|
|
||||||
|
fun imeOptionsForFlags(i: Int): Int {
|
||||||
|
val i2 = if ((i and BaseRobTopActivity.KEYBOARD_INPUT_MULTILINE) == 0 || !usesInlineKeyboard())
|
||||||
|
EditorInfo.IME_ACTION_DONE else EditorInfo.IME_ACTION_NONE
|
||||||
|
|
||||||
|
return if (usesInlineKeyboard())
|
||||||
|
EditorInfo.IME_FLAG_NO_FULLSCREEN or EditorInfo.IME_FLAG_NO_EXTRACT_UI or i2
|
||||||
|
else i2
|
||||||
|
}
|
||||||
|
|
||||||
class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
||||||
companion object {
|
companion object {
|
||||||
lateinit var cocos2dxGLSurfaceView: Cocos2dxGLSurfaceView
|
lateinit var cocos2dxGLSurfaceView: Cocos2dxGLSurfaceView
|
||||||
private lateinit var handler: Handler
|
private lateinit var handler: Handler
|
||||||
private lateinit var cocos2dxTextInputWrapper: Cocos2dxTextInputWrapper
|
private lateinit var cocos2dxTextInputWrapper: Cocos2dxTextInputWrapper
|
||||||
|
|
||||||
|
private var keyboardVisible = false
|
||||||
|
private var keyboardHeight = 0
|
||||||
|
|
||||||
|
private var keyboardHideCheck = Runnable {
|
||||||
|
if (keyboardVisible) {
|
||||||
|
return@Runnable
|
||||||
|
}
|
||||||
|
|
||||||
|
cocos2dxGLSurfaceView.queueEvent {
|
||||||
|
cocos2dxGLSurfaceView.cocos2dxRenderer.handleTextClosed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun openIMEKeyboard() {
|
fun openIMEKeyboard() {
|
||||||
val msg = Message()
|
val msg = Message()
|
||||||
@@ -50,6 +94,26 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
|||||||
cocos2dxGLSurfaceView.queueEvent {
|
cocos2dxGLSurfaceView.queueEvent {
|
||||||
Cocos2dxAccelerometer.onSensorChanged(x, y, z, timestamp)
|
Cocos2dxAccelerometer.onSensorChanged(x, y, z, timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.R)
|
||||||
|
fun onKeyboardInsets(windowInsets: WindowInsets) {
|
||||||
|
val visible = windowInsets.isVisible(WindowInsets.Type.ime())
|
||||||
|
val offsetHeight = if (visible) windowInsets.getInsets(WindowInsets.Type.ime()).bottom else 0
|
||||||
|
|
||||||
|
if (visible == keyboardVisible && offsetHeight == keyboardHeight) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
keyboardVisible = visible
|
||||||
|
keyboardHeight = offsetHeight
|
||||||
|
|
||||||
|
handler.removeCallbacks(keyboardHideCheck)
|
||||||
|
if (!visible) {
|
||||||
|
handler.postDelayed(keyboardHideCheck, 150L)
|
||||||
|
} else {
|
||||||
|
cocos2dxGLSurfaceView.cocos2dxRenderer.handleKeyboardWillShow(keyboardHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var cocos2dxRenderer: Cocos2dxRenderer
|
private lateinit var cocos2dxRenderer: Cocos2dxRenderer
|
||||||
@@ -65,6 +129,9 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
|||||||
private set
|
private set
|
||||||
var supportsResizeEvents = false
|
var supportsResizeEvents = false
|
||||||
|
|
||||||
|
// 2.209+ events for keyboard and such
|
||||||
|
var sendNewCocosEvents = false
|
||||||
|
|
||||||
var cocos2dxEditText: AppCompatEditText? = null
|
var cocos2dxEditText: AppCompatEditText? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
@@ -85,9 +152,11 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
|||||||
HANDLER_OPEN_IME_KEYBOARD -> {
|
HANDLER_OPEN_IME_KEYBOARD -> {
|
||||||
if (cocos2dxEditText?.requestFocus() == true) {
|
if (cocos2dxEditText?.requestFocus() == true) {
|
||||||
cocos2dxEditText?.apply {
|
cocos2dxEditText?.apply {
|
||||||
removeTextChangedListener(
|
removeTextChangedListener(cocos2dxTextInputWrapper)
|
||||||
cocos2dxTextInputWrapper
|
|
||||||
)
|
inputType = inputTypeForFlags(BaseRobTopActivity.curKeyboardInputFlags)
|
||||||
|
imeOptions = imeOptionsForFlags(BaseRobTopActivity.curKeyboardInputFlags)
|
||||||
|
|
||||||
setText("")
|
setText("")
|
||||||
val text = msg.obj as String
|
val text = msg.obj as String
|
||||||
append(text)
|
append(text)
|
||||||
@@ -100,16 +169,13 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
|||||||
cocos2dxEditText,
|
cocos2dxEditText,
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
Log.d("GLSurfaceView", "showSoftInput")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
HANDLER_CLOSE_IME_KEYBOARD -> {
|
HANDLER_CLOSE_IME_KEYBOARD -> {
|
||||||
cocos2dxEditText?.apply {
|
cocos2dxEditText?.apply {
|
||||||
removeTextChangedListener(
|
removeTextChangedListener(cocos2dxTextInputWrapper)
|
||||||
cocos2dxTextInputWrapper
|
|
||||||
)
|
|
||||||
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(
|
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(
|
||||||
windowToken,
|
windowToken,
|
||||||
0
|
0
|
||||||
@@ -117,8 +183,10 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
requestFocus()
|
requestFocus()
|
||||||
Log.d("GLSurfaceView", "HideSoftInput")
|
|
||||||
|
queueEvent {
|
||||||
cocos2dxRenderer.handleTextClosed()
|
cocos2dxRenderer.handleTextClosed()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
else -> return
|
else -> return
|
||||||
@@ -297,6 +365,58 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun queueKeyboardEvent(keyCode: Int, event: KeyEvent, down: Boolean) {
|
||||||
|
sendNextEventTimestamp(event.eventTime * MS_TO_NS)
|
||||||
|
|
||||||
|
if (useKeyboardEvents) {
|
||||||
|
if (down) {
|
||||||
|
queueEvent {
|
||||||
|
GeodeUtils.nativeKeyDown(keyCode, event.modifiers, event.repeatCount != 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
queueEvent {
|
||||||
|
GeodeUtils.nativeKeyUp(keyCode, event.modifiers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controllerEventsEnabled) {
|
||||||
|
queueEvent {
|
||||||
|
GeodeUtils.internalKeyEvent(
|
||||||
|
event.eventTime * MS_TO_NS,
|
||||||
|
event.deviceId,
|
||||||
|
event.source,
|
||||||
|
event.keyCode,
|
||||||
|
event.modifiers,
|
||||||
|
down,
|
||||||
|
event.repeatCount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendNewCocosEvents) {
|
||||||
|
if (KeyEvent.isGamepadButton(keyCode)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_ESCAPE && BaseRobTopActivity.blockBackButton) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val isRepeat = event.repeatCount > 0
|
||||||
|
val eventTimestamp = event.eventTime / 1000.0
|
||||||
|
|
||||||
|
queueEvent {
|
||||||
|
cocos2dxRenderer.handleKeyboardEvent(
|
||||||
|
keyCode, down, isRepeat, eventTimestamp,
|
||||||
|
event.isShiftPressed, event.isCtrlPressed, event.isAltPressed
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun legacyKeyDown(keyCode: Int, keyEvent: KeyEvent): Boolean {
|
private fun legacyKeyDown(keyCode: Int, keyEvent: KeyEvent): Boolean {
|
||||||
return when (keyCode) {
|
return when (keyCode) {
|
||||||
KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_MENU -> {
|
KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_MENU -> {
|
||||||
@@ -354,67 +474,51 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
||||||
if (!useKeyboardEvents && !controllerEventsEnabled) {
|
val deliverGeodeEvents = useKeyboardEvents || controllerEventsEnabled
|
||||||
|
if (!deliverGeodeEvents && !sendNewCocosEvents) {
|
||||||
return legacyKeyDown(keyCode, event)
|
return legacyKeyDown(keyCode, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (keyCode) {
|
if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
|
||||||
// ignore system keys
|
if (deliverGeodeEvents) {
|
||||||
KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_MUTE -> {
|
queueKeyboardEvent(keyCode, event, true)
|
||||||
super.onKeyDown(keyCode, event)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
if (BaseRobTopActivity.blockBackButton) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
queueEvent {
|
|
||||||
sendNextEventTimestamp(event.eventTime * MS_TO_NS)
|
|
||||||
|
|
||||||
if (useKeyboardEvents) {
|
|
||||||
GeodeUtils.nativeKeyDown(keyCode, event.modifiers, event.repeatCount != 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (controllerEventsEnabled) {
|
|
||||||
GeodeUtils.internalKeyEvent(event.eventTime * MS_TO_NS, event.deviceId, event.source, event.keyCode, event.modifiers, true, event.repeatCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
|
|
||||||
if (!useKeyboardEvents && !controllerEventsEnabled) {
|
|
||||||
return super.onKeyUp(keyCode, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
return when (keyCode) {
|
|
||||||
KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_MUTE -> {
|
|
||||||
super.onKeyUp(keyCode, event)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
if (event.repeatCount != 0 || BaseRobTopActivity.blockBackButton) {
|
if (event.repeatCount != 0 || BaseRobTopActivity.blockBackButton) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
queueEvent {
|
queueEvent {
|
||||||
sendNextEventTimestamp(event.eventTime * MS_TO_NS)
|
cocos2dxRenderer.handleKeyDown(keyCode)
|
||||||
|
}
|
||||||
if (useKeyboardEvents) {
|
return true
|
||||||
GeodeUtils.nativeKeyUp(keyCode, event.modifiers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controllerEventsEnabled) {
|
if (event.isSystem) {
|
||||||
GeodeUtils.internalKeyEvent(event.eventTime * MS_TO_NS, event.deviceId, event.source, event.keyCode, event.modifiers, false, event.repeatCount)
|
return super.onKeyDown(keyCode, event)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
queueKeyboardEvent(keyCode, event, true)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
|
||||||
|
val deliverGeodeEvents = useKeyboardEvents || controllerEventsEnabled
|
||||||
|
if (!deliverGeodeEvents && !sendNewCocosEvents) {
|
||||||
|
return super.onKeyUp(keyCode, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.isSystem) {
|
||||||
|
return super.onKeyUp(keyCode, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queueKeyboardEvent(keyCode, event, false)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// i'm lazy.
|
// i'm lazy.
|
||||||
// https://developer.android.com/develop/ui/views/touch-and-input/game-controllers/controller-input
|
// https://developer.android.com/develop/ui/views/touch-and-input/game-controllers/controller-input
|
||||||
private fun getCenteredAxis(
|
private fun getCenteredAxis(
|
||||||
@@ -475,11 +579,15 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onGenericMotionEvent(event: MotionEvent?): Boolean {
|
override fun onGenericMotionEvent(event: MotionEvent?): Boolean {
|
||||||
if (!useKeyboardEvents && !controllerEventsEnabled) {
|
val hasGeodeEvents = useKeyboardEvents || controllerEventsEnabled
|
||||||
|
if (!hasGeodeEvents && !sendNewCocosEvents) {
|
||||||
return super.onGenericMotionEvent(event)
|
return super.onGenericMotionEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event?.action == MotionEvent.ACTION_SCROLL) {
|
if (event?.action == MotionEvent.ACTION_SCROLL) {
|
||||||
|
val mouseX = event.x
|
||||||
|
val mouseY = event.y
|
||||||
|
|
||||||
val scrollX = event.getAxisValue(MotionEvent.AXIS_HSCROLL)
|
val scrollX = event.getAxisValue(MotionEvent.AXIS_HSCROLL)
|
||||||
val scrollY = event.getAxisValue(MotionEvent.AXIS_VSCROLL)
|
val scrollY = event.getAxisValue(MotionEvent.AXIS_VSCROLL)
|
||||||
val timestamp = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
val timestamp = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||||
@@ -493,7 +601,11 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (controllerEventsEnabled) {
|
if (controllerEventsEnabled) {
|
||||||
GeodeUtils.internalScrollEvent(timestamp, event.deviceId, event.source, scrollX, scrollY)
|
GeodeUtils.internalScrollEvent(timestamp, event.deviceId, event.source, scrollX, scrollY, mouseX, mouseY)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasGeodeEvents && sendNewCocosEvents) {
|
||||||
|
cocos2dxRenderer.handleScroll(mouseX, mouseY, scrollY, scrollX)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,12 +28,29 @@ class Cocos2dxRenderer(private var handler: Cocos2dxGLSurfaceView) : GLSurfaceVi
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
private external fun nativeKeyDown(keyCode: Int): Boolean
|
private external fun nativeKeyDown(keyCode: Int): Boolean
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private external fun nativeKeyboardEvent(
|
||||||
|
keyCode: Int,
|
||||||
|
down: Boolean,
|
||||||
|
isRepeat: Boolean,
|
||||||
|
timestamp: Double,
|
||||||
|
shiftPressed: Boolean,
|
||||||
|
ctrlPressed: Boolean,
|
||||||
|
altPressed: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private external fun nativeKeyboardWillShow(offset: Int)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private external fun nativeOnPause()
|
private external fun nativeOnPause()
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private external fun nativeOnResume()
|
private external fun nativeOnResume()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private external fun nativeScroll(x: Float, y: Float, scrollY: Float, scrollX: Float)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private external fun nativeRender()
|
private external fun nativeRender()
|
||||||
|
|
||||||
@@ -133,6 +150,18 @@ class Cocos2dxRenderer(private var handler: Cocos2dxGLSurfaceView) : GLSurfaceVi
|
|||||||
nativeKeyDown(keyCode)
|
nativeKeyDown(keyCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun handleKeyboardWillShow(offset: Int) {
|
||||||
|
nativeKeyboardWillShow(offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun handleKeyboardEvent(keyCode: Int, down: Boolean, isRepeat: Boolean, timestamp: Double, shiftPressed: Boolean, ctrlPressed: Boolean, altPressed: Boolean) {
|
||||||
|
nativeKeyboardEvent(keyCode, down, isRepeat, timestamp, shiftPressed, ctrlPressed, altPressed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun handleScroll(x: Float, y: Float, scrollY: Float, scrollX: Float) {
|
||||||
|
nativeScroll(x, y, scrollY, scrollX)
|
||||||
|
}
|
||||||
|
|
||||||
fun handleOnPause() {
|
fun handleOnPause() {
|
||||||
nativeOnPause()
|
nativeOnPause()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import android.text.TextWatcher
|
|||||||
import android.widget.TextView.OnEditorActionListener
|
import android.widget.TextView.OnEditorActionListener
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import com.customRobTop.JniToCpp
|
||||||
|
|
||||||
class Cocos2dxTextInputWrapper(private val cocos2dxGLSurfaceView: Cocos2dxGLSurfaceView) : TextWatcher, OnEditorActionListener {
|
class Cocos2dxTextInputWrapper(private val cocos2dxGLSurfaceView: Cocos2dxGLSurfaceView) : TextWatcher, OnEditorActionListener {
|
||||||
private var originText: String? = null
|
private var originText: String? = null
|
||||||
@@ -19,21 +21,33 @@ class Cocos2dxTextInputWrapper(private val cocos2dxGLSurfaceView: Cocos2dxGLSurf
|
|||||||
this.originText = originText
|
this.originText = originText
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun afterTextChanged(s: Editable) {
|
override fun afterTextChanged(editable: Editable) {
|
||||||
if (!isFullScreenEdit) {
|
if (isFullScreenEdit) {
|
||||||
var nModified = s.length - text!!.length
|
return
|
||||||
if (nModified > 0) {
|
}
|
||||||
cocos2dxGLSurfaceView.insertText(
|
|
||||||
s.subSequence(text!!.length, s.length).toString()
|
val cText = text ?: return
|
||||||
)
|
|
||||||
} else {
|
val str = editable.toString()
|
||||||
while (nModified < 0) {
|
val unchanged = str.commonPrefixWith(cText)
|
||||||
|
|
||||||
|
var unchangedUntil = unchanged.length
|
||||||
|
if (unchangedUntil > 0 && unchangedUntil < str.length && Character.isLowSurrogate(unchanged.last())) {
|
||||||
|
unchangedUntil--
|
||||||
|
}
|
||||||
|
|
||||||
|
val codePointLength = cText.codePointCount(unchangedUntil, cText.length)
|
||||||
|
repeat(codePointLength) {
|
||||||
cocos2dxGLSurfaceView.deleteBackward()
|
cocos2dxGLSurfaceView.deleteBackward()
|
||||||
nModified++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unchangedUntil < str.length) {
|
||||||
|
cocos2dxGLSurfaceView.insertText(
|
||||||
|
str.substring(unchangedUntil)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
text = s.toString()
|
|
||||||
}
|
text = str
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun beforeTextChanged(
|
override fun beforeTextChanged(
|
||||||
@@ -47,22 +61,44 @@ class Cocos2dxTextInputWrapper(private val cocos2dxGLSurfaceView: Cocos2dxGLSurf
|
|||||||
|
|
||||||
override fun onTextChanged(pCharSequence: CharSequence, start: Int, before: Int, count: Int) {}
|
override fun onTextChanged(pCharSequence: CharSequence, start: Int, before: Int, count: Int) {}
|
||||||
override fun onEditorAction(textView: TextView, actionID: Int, keyEvent: KeyEvent?): Boolean {
|
override fun onEditorAction(textView: TextView, actionID: Int, keyEvent: KeyEvent?): Boolean {
|
||||||
if (cocos2dxGLSurfaceView.cocos2dxEditText == textView && isFullScreenEdit) {
|
val fullscreenIme = cocos2dxGLSurfaceView.cocos2dxEditText == textView && isFullScreenEdit
|
||||||
|
if (fullscreenIme) {
|
||||||
|
var text = textView.text.toString()
|
||||||
|
if (originText != text) {
|
||||||
|
if (cocos2dxGLSurfaceView.sendNewCocosEvents) {
|
||||||
|
cocos2dxGLSurfaceView.queueEvent {
|
||||||
|
JniToCpp.textInputCaretToEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i in originText!!.length downTo 1) {
|
for (i in originText!!.length downTo 1) {
|
||||||
cocos2dxGLSurfaceView.deleteBackward()
|
cocos2dxGLSurfaceView.deleteBackward()
|
||||||
}
|
}
|
||||||
var text = textView.text.toString()
|
|
||||||
|
// this bit was removed in 2.209, and I don't know if it's important on previous versions
|
||||||
|
if (!cocos2dxGLSurfaceView.sendNewCocosEvents) {
|
||||||
if (!text.endsWith('\n')) {
|
if (!text.endsWith('\n')) {
|
||||||
text += '\n'
|
text += '\n'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cocos2dxGLSurfaceView.insertText(text)
|
cocos2dxGLSurfaceView.insertText(text)
|
||||||
}
|
}
|
||||||
if (actionID != 6) {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fullscreenIme || actionID == EditorInfo.IME_ACTION_DONE) {
|
||||||
|
if (cocos2dxGLSurfaceView.sendNewCocosEvents) {
|
||||||
|
cocos2dxGLSurfaceView.queueEvent {
|
||||||
|
JniToCpp.textInputDone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionID == EditorInfo.IME_ACTION_DONE) {
|
||||||
cocos2dxGLSurfaceView.requestFocus()
|
cocos2dxGLSurfaceView.requestFocus()
|
||||||
Cocos2dxGLSurfaceView.closeIMEKeyboard()
|
Cocos2dxGLSurfaceView.closeIMEKeyboard()
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user