How to handle key events during TextField editing in Compose?
Asked Answered
H

1

2

I'm making a chess engine on desktop compose, one of the things I'm trying to implement is a TextField where i can paste in several moves to recreate games.

I'm having problems saving the text that I input into my TextField composable.

My text composable is as follows, I understand that with my current implementation it prints every time the move variable changes, but i just wanted this to happen when I press the ENTER key on my keyboard.

I'm using the print to try some code but what i want to do is to save the String to a list or something, but that i can implement in my own later.

I only find explanations on how to do it with android and android specific methods.

Text("   Play", textAlign = TextAlign.Center, fontSize = 30.sp)
val move = remember { mutableStateOf("Play") }
TextField(
    value = move.value,
    onValueChange = { move.value = it },
    label = { Text("Move") },
    maxLines = 1,
    textStyle = TextStyle(color = Color.Black, fontWeight = FontWeight.Bold),
    modifier = Modifier.padding(20.dp)
)
println(move.value)

It has been pointed out to me a solution to handle the ENTER keybind as been answered here: How to trigger PC Keyboard inputs in Kotlin Desktop Compose I'm just having some issues, that I press ENTER unable to handle the String when I press ENTER it prints continuosly isntead of only once based on my research I need to implement something like this: Box doesn't capture key events in Compose Desktop but i can't seem to be able to use the KeyEvent.ACTION_UP not sure if it's specific to the editText, if I'm missing some imports, or if there's another way to do it with the TextField composable.

My code after the given suggestions

val requester = remember { FocusRequester() }
LaunchedEffect(Unit) {
    requester.requestFocus()
}
Text("   Play", textAlign = TextAlign.Center, fontSize = 30.sp)
val move = remember { mutableStateOf("Play") }
TextField(
    value = move.value,
    onValueChange = { move.value = it },
    label = { Text("Move") },
    maxLines = 1,
    textStyle = TextStyle(color = Color.Black, fontWeight = FontWeight.Bold),
    modifier = Modifier.padding(20.dp)
        .onKeyEvent {
    //if(keyCode==KeyEvent.KEYCODE_ENTER&&event.action==KeyEvent.ACTION_UP){
            if (it.key == Key.Enter) {
                println(move.value)
                true
            } else {
                // let other handlers receive this event
                false
            }
        }
        .focusRequester(requester)
        .focusable()
)

I managed to fix this problem by changing the if condition to this:

if (it.key == Key.Enter && move.value!="") {
    println(move.value)
    move.value = ""
    true
}

So that everytime I write something and press ENTER it prints the String and clears the mutableState, and while ENTER is still pressed it won't print because the mutableState is an empty String. I'm still looking for a better solution than this

Helenhelena answered 23/11, 2021 at 20:30 Comment(2)
Only partly, because I still don't know how to save the move mutableState, i thought of declaring it as a global variable and creating a methode in Thread to keep checking if ENTER was pressed, but this type of variable is part of a composable and cant be declared outside a composable, so as far as I'm aware i can't declare it globally.Helenhelena
I managed to implement it as you said but I just have to quick questions so the only way to do it is using ExperimentalUI and everytime I press the key it prints continuosly isntead of only once based on my research I need to implement something like this #47299435 but i can't seem to be able to use the KeyEvent.ACTION_UP not sure if it's because it is specific to the editText, and if so, do i need to change my implementation to something like that or is it just because I'm missing an import?Helenhelena
S
9

You can capture key events with Modifier.onKeyEvent. With the text field you don't need any focus capturing, because it's already there. If you would need to do the same for a custom view, check out this answer

To check which button was pressed you can use key, and to check where it was released, you can check type:

TextField(
    value = text,
    onValueChange = { text = it },
    modifier = Modifier
        .onKeyEvent { keyEvent ->
            if (keyEvent.key != Key.Enter) return@onKeyEvent false
            if (keyEvent.type == KeyEventType.KeyUp) {
                println("Enter released")
            }
            true
        }
)
Surmise answered 25/11, 2021 at 2:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.