Andrew Rudenko
4 years ago
3 changed files with 119 additions and 0 deletions
After Width: | Height: | Size: 1.3 MiB |
@ -0,0 +1,119 @@ |
|||||||
|
# Keyboard events handling |
||||||
|
|
||||||
|
## Prerequisites |
||||||
|
|
||||||
|
This tutorial expects set and ready Compose project build similar to which is described in [Getting Started tutorial](../Getting_Started) |
||||||
|
|
||||||
|
## KeySets & ShortcutHandler |
||||||
|
|
||||||
|
Compose for Desktop has a few utilities to work with shortcuts: |
||||||
|
|
||||||
|
`KeysSet` represents a simultaneously pressed chord of keys. You can construct a `KeysSet` using Key's extension function: |
||||||
|
|
||||||
|
``` kotlin |
||||||
|
Key.CtrlLeft + Key.Enter |
||||||
|
``` |
||||||
|
|
||||||
|
`ShortcutHandler` accepts `KeysSet` and returns a handler which could be used as a callback for `keyInputFilter` |
||||||
|
|
||||||
|
## Event handlers |
||||||
|
|
||||||
|
There are two different ways how you can handle key events in Compose for Desktop: |
||||||
|
|
||||||
|
- By setting up an event handler based on a focused component |
||||||
|
- By setting up an event handler in the scope of the window |
||||||
|
|
||||||
|
## Focus related events |
||||||
|
|
||||||
|
It's working in the same way as in Compose for Android, see for details [API Reference](https://developer.android.com/reference/kotlin/androidx/compose/ui/input/key/package-summary#keyinputfilter) |
||||||
|
|
||||||
|
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 |
||||||
|
|
||||||
|
@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.keyInputFilter( |
||||||
|
ShortcutHandler(Key.CtrlLeft + Key.Enter) { |
||||||
|
consumedText += text.length |
||||||
|
text = "" |
||||||
|
} |
||||||
|
) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
Note an annotation `@OptIn(ExperimentalKeyInput::class)`. Keyboard-related event handlers are a still-experimental feature of Compose and API changes are possible, so it requires it to use special annotation to emphasize the experimental nature of the code. |
||||||
|
|
||||||
|
![keyInputFilter](keyInputFilter.gif) |
||||||
|
|
||||||
|
## Window-scoped events |
||||||
|
|
||||||
|
`AppWindow` instances have `keyboard` property. Using it, it's possible to define keyboard shortcuts that are always active for the current window. See 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.shortcut(Key.Escape) { |
||||||
|
it.close() |
||||||
|
} |
||||||
|
}.show { |
||||||
|
Text("I'm popup!") |
||||||
|
} |
||||||
|
} |
||||||
|
) { |
||||||
|
Text("Open popup") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
![window_keyboard](window_keyboard.gif) |
After Width: | Height: | Size: 486 KiB |
Loading…
Reference in new issue