キーボードイベント
Compose Multiplatform for Desktop では、キーボードイベントを2つの異なるスコープでイベントハンドラーを設定することで管理できます。
- フォーカスされた要素に基づくイベントハンドラー。
- ウィンドウスコープのイベントハンドラー。
フォーカスされたコンポーネントでのイベント
このアプローチは、キーボードのキーを押すと、現在フォーカスされているコンポーネントのイベントハンドラーがトリガーされることを意味します。
典型的なシナリオは、TextField
のようなアクティブなコントロールにキーボードハンドラーを定義することです。キーイベントがデフォルトのアクションをトリガーする前にインターセプトするには、onKeyEvent
と onPreviewKeyEvent
の両方のモディファイアを使用できます。 onKeyEvent
モディファイアを使用すると個々のキーストロークを処理でき、onPreviewKeyEvent
はショートカットを定義するのに適しています。
次のサンプルは、 を押しながら、どのキーが押されたかに応じて異なるアクションを実行する TextField
のインタラクションを示しています。
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.isCtrlPressed
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.window.singleWindowApplication
fun main() = singleWindowApplication (title = "Key events") {
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.onPreviewKeyEvent {
when {
(it.isCtrlPressed && it.key == Key.Minus && it.type == KeyEventType.KeyUp) -> {
consumedText -= text.length
text = ""
true
}
(it.isCtrlPressed && it.key == Key.Equals && it.type == KeyEventType.KeyUp) -> {
consumedText += text.length
text = ""
true
}
else -> false
}
}
)
}
}
}

ウィンドウスコープでのイベント
現在のウィンドウ内で常にアクティブなキーボードイベントハンドラーを定義するには、Window
、singleWindowApplication
、Dialog
関数で利用可能な onPreviewKeyEvent
および onKeyEvent
パラメーターを使用します。 これらは、イベントが消費されなかった場合のディスパッチ方法が異なります。onPreviewKeyEvent
はイベントを最初の子にディスパッチし、onKeyEvent
はイベントをコンポーザブルの親にディスパッチします。通常、onPreviewKeyEvent
はイベントのインターセプトに推奨されます。これは、画面全体のキーボードショートカットさえも実装できるためです。
次のサンプルは、Escape
キーを押してポップアップダイアログを閉じたり、 ショートカットを押してウィンドウの内容を変更したりするなど、ウィンドウのインタラクションを示しています。
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.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.isCtrlPressed
import androidx.compose.ui.input.key.isShiftPressed
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.type
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogWindow
import androidx.compose.ui.window.singleWindowApplication
private var cleared by mutableStateOf(false)
fun main() = singleWindowApplication(
title = "Keyboard events",
onKeyEvent = {
if (
it.isCtrlPressed &&
it.isShiftPressed &&
it.key == Key.C &&
it.type == KeyEventType.KeyDown
) {
cleared = true
true
} else {
false
}
}
) {
MaterialTheme {
if (cleared) {
Text("The App was cleared!")
} else {
App()
}
}
}
@Composable
fun App() {
var isDialogOpen by remember { mutableStateOf(false) }
if (isDialogOpen) {
DialogWindow(onCloseRequest = { isDialogOpen = false },
title = "Dialog",
onPreviewKeyEvent = {
if (it.key == Key.Escape && it.type == KeyEventType.KeyDown) {
isDialogOpen = false
true
} else {
false
}
}) {
Text("Hello!")
}
}
Column(Modifier.fillMaxSize(), Arrangement.spacedBy(5.dp)) {
Button(
modifier = Modifier.padding(4.dp),
onClick = { isDialogOpen = true }
) {
Text("Open dialog")
}
}
}

次のステップ
- 詳細については、APIリファレンスを参照してください。
- 他のデスクトップコンポーネントに関するチュートリアルを探索してください。