Nikolay Igotti
4 years ago
committed by
GitHub
3 changed files with 128 additions and 0 deletions
@ -0,0 +1,128 @@
|
||||
# Keyboard events handling |
||||
|
||||
## Prerequisites |
||||
|
||||
This tutorial expects that you have already set up the Compose project as described in the [Getting Started tutorial](../Getting_Started) |
||||
|
||||
## What is covered |
||||
|
||||
In this tutorial, we will look at two different ways of handling keyboard events in Compose for Desktop as well as the utilities that we have to do this. |
||||
|
||||
## KeySets |
||||
|
||||
Compose for Desktop has a few utilities to work with shortcuts: |
||||
|
||||
`KeysSet` represents a set of keys that can be simultaneously pressed. You can construct a KeysSet using the Key's extension function: |
||||
|
||||
``` kotlin |
||||
Key.CtrlLeft + Key.Enter |
||||
``` |
||||
|
||||
## Event handlers |
||||
|
||||
There are two ways to handle key events in Compose for Desktop: |
||||
|
||||
- By setting up an event handler based on the element that is in focus |
||||
- By setting up an event handler in the scope of the window |
||||
|
||||
## Focus related events |
||||
|
||||
It works the same as Compose for Android, for details see [API Reference](https://developer.android.com/reference/kotlin/androidx/compose/ui/input/key/package-summary#keyinputfilter) |
||||
|
||||
`Modifier.shortcuts` is used to define one or multiple callbacks for `KeysSet`s. |
||||
|
||||
The most common use case is to define keyboard handlers for active controls like `TextField`. Here is an example: |
||||
|
||||
``` kotlin |
||||
import androidx.compose.desktop.Window |
||||
import androidx.compose.foundation.Text |
||||
import androidx.compose.foundation.layout.Arrangement |
||||
import androidx.compose.foundation.layout.Column |
||||
import androidx.compose.foundation.layout.fillMaxSize |
||||
import androidx.compose.material.MaterialTheme |
||||
import androidx.compose.material.TextField |
||||
import androidx.compose.runtime.mutableStateOf |
||||
import androidx.compose.runtime.remember |
||||
import androidx.compose.ui.Modifier |
||||
import androidx.compose.ui.input.key.* |
||||
import androidx.compose.ui.unit.IntSize |
||||
import androidx.compose.ui.unit.dp |
||||
import androidx.compose.runtime.getValue |
||||
import androidx.compose.runtime.setValue |
||||
import androidx.compose.ui.input.key.shortcuts |
||||
|
||||
@OptIn(ExperimentalKeyInput::class) |
||||
fun main() = Window(title = "Compose for Desktop", size = IntSize(300, 300)) { |
||||
MaterialTheme { |
||||
var consumedText by remember { mutableStateOf(0) } |
||||
var text by remember { mutableStateOf("") } |
||||
Column(Modifier.fillMaxSize(), Arrangement.spacedBy(5.dp)) { |
||||
Text("Consumed text: $consumedText") |
||||
TextField( |
||||
value = text, |
||||
onValueChange = { text = it }, |
||||
modifier = Modifier.shortcuts { |
||||
on(Key.CtrlLeft + Key.Minus) { |
||||
consumedText -= text.length |
||||
text = "" |
||||
} |
||||
on(Key.CtrlLeft + Key.Equals) { |
||||
consumedText += text.length |
||||
text = "" |
||||
} |
||||
} |
||||
) |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
|
||||
|
||||
Note the annotation `@OptIn(ExperimentalKeyInput::class)`. Keyboard-related event handlers are still an experimental feature of Compose, and later API changes are possible. So it requires the use of a special annotation to emphasize the experimental nature of the code. |
||||
|
||||
![keyInputFilter](keyInputFilter.gif) |
||||
|
||||
## Window-scoped events |
||||
|
||||
`AppWindow` instances have a `keyboard` property. It is possible to use it to define keyboard shortcuts that are always active in the current window. Here is an example: |
||||
|
||||
``` kotlin |
||||
import androidx.compose.desktop.AppWindow |
||||
import androidx.compose.desktop.Window |
||||
import androidx.compose.foundation.Text |
||||
import androidx.compose.foundation.layout.Arrangement |
||||
import androidx.compose.foundation.layout.Column |
||||
import androidx.compose.foundation.layout.fillMaxSize |
||||
import androidx.compose.foundation.layout.padding |
||||
import androidx.compose.material.Button |
||||
import androidx.compose.material.MaterialTheme |
||||
import androidx.compose.ui.Modifier |
||||
import androidx.compose.ui.input.key.ExperimentalKeyInput |
||||
import androidx.compose.ui.input.key.Key |
||||
import androidx.compose.ui.unit.IntSize |
||||
import androidx.compose.ui.unit.dp |
||||
|
||||
@OptIn(ExperimentalKeyInput::class) |
||||
fun main() = Window(title = "Compose for Desktop", size = IntSize(300, 300)) { |
||||
MaterialTheme { |
||||
Column(Modifier.fillMaxSize(), Arrangement.spacedBy(5.dp)) { |
||||
Button( |
||||
modifier = Modifier.padding(4.dp), |
||||
onClick = { |
||||
AppWindow(size = IntSize(200, 200)).also { |
||||
it.keyboard.setShortcut(Key.Escape) { |
||||
it.close() |
||||
} |
||||
}.show { |
||||
Text("I'm popup!") |
||||
} |
||||
} |
||||
) { |
||||
Text("Open popup") |
||||
} |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
|
||||
![window_keyboard](window_keyboard.gif) |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 486 KiB |
Loading…
Reference in new issue