Keyboard inputs fixed

This commit is contained in:
BeZide93 2025-09-05 18:36:23 +02:00 committed by KeatonTheBot
parent be176fd367
commit eee4a6272c
4 changed files with 95 additions and 37 deletions

View file

@ -97,7 +97,8 @@ val jnaInstance: KenjinxNativeJna = Native.load(
object KenjinxNative : KenjinxNativeJna by jnaInstance {
fun loggingSetEnabled(logLevel: LogLevel, enabled: Boolean) = loggingSetEnabled(logLevel.ordinal, enabled)
fun loggingSetEnabled(logLevel: LogLevel, enabled: Boolean) =
loggingSetEnabled(logLevel.ordinal, enabled)
@JvmStatic
fun frameEnded() = MainActivity.frameEnded()
@ -116,6 +117,10 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
progress
)
/**
* Variant A (Pointer Strings via NativeHelpers).
* Used by older JNI/Interop paths.
*/
@JvmStatic
fun updateUiHandler(
newTitlePointer: Long,
@ -127,15 +132,54 @@ object KenjinxNative : KenjinxNativeJna by jnaInstance {
nMode: Int,
newSubtitlePointer: Long,
newInitialTextPointer: Long
) = MainActivity.mainViewModel?.activity?.uiHandler?.update(
newTitle = NativeHelpers.instance.getStringJava(newTitlePointer),
newMessage = NativeHelpers.instance.getStringJava(newMessagePointer),
newWatermark = NativeHelpers.instance.getStringJava(newWatermarkPointer),
newType,
min,
max,
newMode = KeyboardMode.entries[nMode],
newSubtitle = NativeHelpers.instance.getStringJava(newSubtitlePointer),
NativeHelpers.instance.getStringJava(newInitialTextPointer)
)
) {
val title = NativeHelpers.instance.getStringJava(newTitlePointer)
val message = NativeHelpers.instance.getStringJava(newMessagePointer)
val watermark = NativeHelpers.instance.getStringJava(newWatermarkPointer)
val subtitle = NativeHelpers.instance.getStringJava(newSubtitlePointer)
val initialText = NativeHelpers.instance.getStringJava(newInitialTextPointer)
val mode = KeyboardMode.entries.getOrNull(nMode) ?: KeyboardMode.Default
MainActivity.mainViewModel?.activity?.uiHandler?.update(
newTitle = title,
newMessage = message,
newWatermark = watermark,
newType = newType,
min = min,
max = max,
newMode = mode,
newSubtitle = subtitle,
newInitialText = initialText
)
}
/**
* Variant B (strings directly). Used by newer JNI/Interop paths.
* Signature exactly matches the C# call in AndroidUIHandler.cs / Interop.UpdateUiHandler(...).
*/
@JvmStatic
fun uiHandlerUpdate(
title: String,
message: String,
watermark: String,
type: Int,
min: Int,
max: Int,
nMode: Int,
subtitle: String,
initialText: String
) {
val mode = KeyboardMode.entries.getOrNull(nMode) ?: KeyboardMode.Default
MainActivity.mainViewModel?.activity?.uiHandler?.update(
newTitle = title,
newMessage = message,
newWatermark = watermark,
newType = type,
min = min,
max = max,
newMode = mode,
newSubtitle = subtitle,
newInitialText = initialText
)
}
}

View file

@ -28,7 +28,6 @@ import org.kenjinx.android.viewmodels.GameModel
import org.kenjinx.android.views.MainView
import androidx.core.net.toUri
class MainActivity : BaseActivity() {
private var physicalControllerManager: PhysicalControllerManager =
PhysicalControllerManager(this)
@ -123,8 +122,7 @@ class MainActivity : BaseActivity() {
motionSensorManager = MotionSensorManager(this)
Thread.setDefaultUncaughtExceptionHandler(crashHandler)
if (
!Environment.isExternalStorageManager()
if (!Environment.isExternalStorageManager()
) {
storageHelper?.storage?.requestFullStorageAccess()
}
@ -143,6 +141,9 @@ class MainActivity : BaseActivity() {
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
// >>> Important: Initialize UI handler (for software keyboard/dialog)
uiHandler = UiHandler()
mainViewModel = MainViewModel(this)
mainViewModel!!.physicalControllerManager = physicalControllerManager
mainViewModel!!.motionSensorManager = motionSensorManager
@ -152,7 +153,6 @@ class MainActivity : BaseActivity() {
mainViewModel?.apply {
setContent {
KenjinxAndroidTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
@ -219,7 +219,7 @@ class MainActivity : BaseActivity() {
override fun onPause() {
super.onPause()
isActive = true
isActive = false
if (isGameRunning) {
mainViewModel?.performanceManager?.setTurboMode(false)
@ -232,7 +232,7 @@ class MainActivity : BaseActivity() {
when (storedIntent.action) {
Intent.ACTION_VIEW, "org.kenjinx.android.LAUNCH_GAME" -> {
val bootPath = storedIntent.getStringExtra("bootPath")
val forceNceAndPptc = storedIntent.getBooleanExtra("forceNceAndPptc",false)
val forceNceAndPptc = storedIntent.getBooleanExtra("forceNceAndPptc", false)
if (bootPath != null) {
val uri = bootPath.toUri()
@ -260,7 +260,6 @@ class MainActivity : BaseActivity() {
// Clean up resources if needed
mainViewModel?.let {
// Perform any critical cleanup
it.performanceManager?.setTurboMode(false)
}

View file

@ -17,8 +17,12 @@ import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
@ -27,6 +31,7 @@ import androidx.compose.ui.window.DialogProperties
import com.halilibo.richtext.markdown.Markdown
import com.halilibo.richtext.ui.material3.RichText
import org.kenjinx.android.widgets.SimpleAlertDialog
import kotlinx.coroutines.delay
enum class KeyboardMode {
Default, Numeric, ASCII, FullLatin, Alphabet, SimplifiedChinese, TraditionalChinese, Korean, LanguageSet2, LanguageSet2Latin
@ -46,6 +51,7 @@ class UiHandler {
var message: String = ""
init {
// 2.0.3 compatible: no parameters
KenjinxNative.uiHandlerSetup()
}
@ -77,15 +83,21 @@ class UiHandler {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Compose() {
val showMessageListener = remember {
showMessage
}
val showMessageListener = remember { showMessage }
val inputListener = remember { inputText }
val validation = remember { mutableStateOf("") }
val inputListener = remember {
inputText
}
val validation = remember {
mutableStateOf("")
// Focus & keyboard control so the popup can be typed immediately like in 2.0.3
val focusRequester = remember { FocusRequester() }
val keyboard = LocalSoftwareKeyboardController.current
LaunchedEffect(showMessageListener.value, type) {
if (showMessageListener.value && type == 2) {
// small delay until the dialog is mounted
delay(100)
focusRequester.requestFocus()
keyboard?.show()
}
}
fun validate(): Boolean {
@ -94,7 +106,6 @@ class UiHandler {
} else {
return inputText.value.length < minLength || inputText.value.length > maxLength
}
return false
}
@ -103,9 +114,7 @@ class UiHandler {
KeyboardMode.Default -> KeyboardType.Text
KeyboardMode.Numeric -> KeyboardType.Decimal
KeyboardMode.ASCII -> KeyboardType.Ascii
else -> {
KeyboardType.Text
}
else -> KeyboardType.Text
}
}
@ -160,10 +169,9 @@ class UiHandler {
onValueChange = { inputListener.value = it },
modifier = Modifier
.fillMaxWidth()
.padding(4.dp),
label = {
Text(text = watermark)
},
.padding(4.dp)
.focusRequester(focusRequester),
label = { Text(text = watermark) },
keyboardOptions = KeyboardOptions(keyboardType = getInputType()),
isError = validate()
)
@ -173,7 +181,8 @@ class UiHandler {
onValueChange = { inputListener.value = it },
modifier = Modifier
.fillMaxWidth()
.padding(4.dp),
.padding(4.dp)
.focusRequester(focusRequester),
keyboardOptions = KeyboardOptions(
keyboardType = getInputType(),
imeAction = ImeAction.Done
@ -211,4 +220,3 @@ class UiHandler {
}
}
}

View file

@ -250,6 +250,13 @@ class GameViews {
mutableStateOf(false)
}
// NEW: If the software keyboard is open, catch Back and close ONLY the dialog.
val uiHandler = mainViewModel.activity.uiHandler
BackHandler(enabled = uiHandler.showMessage.value) {
KenjinxNative.uiHandlerSetResponse(false, "")
uiHandler.showMessage.value = false
}
BackHandler {
showBackNotice.value = true
}