ユーザーが TextField などの編集可能なテキスト コンポーネントにフォーカスを当て、デバイスにハードウェア
キーボードが接続されている場合、すべての入力はシステムによって処理されます。
キーイベントを処理することで、キーボード
ショートカットを提供できます。
デフォルトのキーボード ショートカット
次のキーボード ショートカットは、すぐに使用できます。
| キーボード ショートカット | アクション | ショートカットをサポートするコンポーザブル |
|---|---|---|
| Shift+Ctrl+左矢印/右矢印 | 単語の先頭/末尾までテキストを選択する | BasicTextField、TextField |
| Shift+Ctrl+↑/↓ | 段落の先頭/末尾までテキストを選択する | BasicTextField、TextField |
| Shift+Alt+↑/↓ または Shift+Meta+左矢印/右矢印 | テキストの先頭/末尾までテキストを選択する | BasicTextField、TextField |
| Shift+左矢印/右矢印 | 文字を選択する | BasicTextField、TextField |
| Ctrl+A | すべて選択 | BasicTextField、TextField |
| Ctrl+C/Ctrl+X/Ctrl+V | コピー/切り取り/貼り付け | BasicTextField、TextField |
| Ctrl+Z/Ctrl+Shift+Z | 元に戻す/やり直す | BasicTextField、TextField |
| PageDown/PageUp | スクロール | LazyColumn、verticalScroll 修飾子、scrollable 修飾子 |
キーイベント
Compose では、
onKeyEvent修飾子を使用して個々のキーストロークを処理できます。
この修飾子は、変更されたコンポーネントがキーイベントを受信したときに呼び出されるラムダを受け取ります。
キーイベントはKeyEvent オブジェクトとして記述されます。
onKeyEvent
修飾子に渡されるラムダ内のオブジェクトを参照することで、各キーイベントの情報を取得できます。
キーストロークは 2 つのキーイベントを送信します。
1 つはユーザーがキーを押したときにトリガーされ、もう 1
つはキーが離されたときにトリガーされます。
2 つのキーイベントは
type 属性を参照することで区別できます。KeyEvent
onKeyEvent ラムダの戻り値は、キーイベントが処理されたかどうかを示します。アプリがキーイベントを処理する場合は
true を返します。これにより、イベントの伝播が停止します。
次のスニペットは、ユーザーが Box コンポーネントで S キーを離したときに doSomething() 関数
を呼び出す方法を示しています。
Box( modifier = Modifier .onKeyEvent { if ( it.type == KeyEventType.KeyUp && it.key == Key.S ) { doSomething() true } else { false } } .focusable() ) { Text("Press S key") }
修飾キー
KeyEvent オブジェクトには、修飾キーが押されているかどうかを示す次の属性があります。
アプリが処理するキーイベントを具体的に記述してください。
次のスニペットでは、ユーザーが S キーのみを離した場合にのみ doSomething() 関数が呼び出されます。ユーザーが修飾キー(Shift キーなど)を押すと、アプリは関数を呼び出しません。
Box( modifier = Modifier .focusable() .onKeyEvent { if ( it.type == KeyEventType.KeyUp && it.key == Key.S && !it.isAltPressed && !it.isCtrlPressed && !it.isMetaPressed && !it.isShiftPressed ) { doSomething() true } else { false } } ) { Text("Press S key with a modifier key") }
Space キーと Enter キーのクリック イベント
Spacebar キーと Enter キーもクリック イベントをトリガーします。 たとえば、ユーザーは次のようにクリックイベントを処理することで、メディア再生を切り替える(再生または一時停止する)ことができます 。Spacebar キーまたは Enter キーを使用します 。
MediaPlayer(modifier = Modifier.clickable { togglePausePlay() })
clickable 修飾子はキーイベントをインターセプトし
onClick() コールバックを呼び出します。Spacebar キーまたは
Enter キーが押されると。
そのため、スニペットで Spacebar キーまたは Enter キーを押すと、togglePausePlay() 関数が呼び出されます。
使用されていないキーイベント
使用されていないキーイベントは、イベントが発生したコンポーネントから、それを囲む外部コンポーネントに伝播されます。
次の例では、InnerComponent がキーイベントを使用するため、
OuterComponent は
S キーを離すことでトリガーされるキーイベントを受信しません。
そのため、actionB() 関数は呼び出されません。
InnerComponent での他のキーイベント(D キーを離すなど)は、OuterComponent で処理できます。actionC() 関数が呼び出されます。これは、D キーを離すキーイベントが OuterComponent に伝播されるためです。
OuterComponent( modifier = Modifier.onKeyEvent { when { it.type == KeyEventType.KeyUp && it.key == Key.S -> { actionB() // This function is never called. true } it.type == KeyEventType.KeyUp && it.key == Key.D -> { actionC() true } else -> false } } ) { InnerComponent( modifier = Modifier.onKeyEvent { if (it.type == KeyEventType.KeyUp && it.key == Key.S) { actionA() true } else { false } } ) }
onKeyPreviewEvent 修飾子
ユースケースによっては、キーイベントがデフォルトのアクションをトリガーする前にインターセプトしたい場合があります。
TextField
にカスタム ショートカットを追加するのは、その典型的な例です。次のスニペットでは、ユーザーが
tabキーを押すと、次のフォーカス可能なコンポーネントに移動できます。
val focusManager = LocalFocusManager.current var textFieldValue by remember { mutableStateOf(TextFieldValue()) } TextField( textFieldValue, onValueChange = { textFieldValue = it }, modifier = Modifier.onPreviewKeyEvent { if (it.type == KeyEventType.KeyUp && it.key == Key.Tab) { focusManager.moveFocus(FocusDirection.Next) true } else { false } } )
デフォルトでは、TextField コンポーネントは、ユーザーが Tab キーを押すたびにタブ文字を追加します。キーイベントが onKeyEvent 修飾子で処理されている場合でも。タブ文字を追加せずにキーボード
フォーカスを移動するには、スニペットのように、キーイベントに関連付けられたアクションをトリガーする前にキーイベントを処理します。
onKeyPreviewEvent() ラムダは、キーイベント
を true 返すことでインターセプトします。
親コンポーネントは、子で発生するキーイベントをインターセプトできます。
次のスニペットでは、ユーザーが S キーを押すと、actionForPreview() 関数ではなく previewSKey() 関数が呼び出されます。
Column( modifier = Modifier.onPreviewKeyEvent { if (it.key == Key.S) { previewSKey() true } else { false } } ) { Box( modifier = Modifier .focusable() .onPreviewKeyEvent { actionForPreview(it) false } .onKeyEvent { actionForKeyEvent(it) true } ) { Text("Press any key") } }
onPreviewKeyEvent() ラムダは、ユーザーが Tab キーを押しても Box コンポーネントに対してトリガーされません。onPreviewKeyEvent() ラムダは、まず親コンポーネントで呼び出され、次に子コンポーネントで
onPreviewKeyEvent() が呼び出されます。この動作を利用して、画面全体のキーボード
ショートカットを実装できます。
参考情報
- キーボード ショートカット ヘルパー: ユーザーがアプリで提供されているキーボード ショートカットを検索できるシステム画面。