處理鍵盤動作

當使用者將焦點放在可編輯的文字元件 (例如 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 修飾符處理個別按鍵操作。這個修飾符接受 lambda,當被修飾的元件收到按鍵事件時,系統會呼叫此 lambda。重要事件會以 KeyEvent 物件的形式描述。您可以參照傳遞至 onKeyEvent 修飾符的 lambda 中的物件,取得每個按鍵事件的資訊。

按鍵動作會傳送兩個按鍵事件。一個在使用者按下按鍵時觸發,另一個則在放開按鍵時觸發。您可以參考 KeyEvent 物件的 type 屬性,區分這兩個重要事件。

onKeyEvent lambda 的傳回值會指出是否已處理按鍵事件。如果應用程式處理按鍵事件,請傳回 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")
}

空白鍵和 Enter 鍵點擊事件

空白鍵和 Enter 鍵也會觸發點擊事件。舉例來說,使用者可以透過處理點擊事件,使用空格鍵或 Enter 鍵切換 (播放或暫停) 媒體播放,如下所示:

MediaPlayer(modifier = Modifier.clickable { togglePausePlay() })

clickable 修飾符會攔截按鍵事件,並在按下空白鍵或 Enter 鍵時呼叫 onClick() 回呼。因此,在程式碼片段中按下空格鍵或 Enter 鍵,即可呼叫 togglePausePlay() 函式。

未使用的重要事件

未使用的重要事件會從事件發生的元件,傳播到外層元件。在以下範例中,InnerComponent 會在 S 鍵放開時消耗按鍵事件,因此 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
        }
    }
)

根據預設,每當使用者按下 Tab 鍵時,TextField 元件就會新增一個 Tab 字元,即使按鍵事件是以 onKeyEvent 修飾符處理也一樣。如要移動鍵盤焦點而不新增任何 Tab 字元,請在觸發與按鍵事件相關聯的動作之前處理按鍵事件,如程式碼片段所示。onKeyPreviewEvent() lambda 會傳回 true,藉此攔截按鍵事件。

父項元件可以攔截子項上發生的按鍵事件。在下列程式碼片段中,使用者按下 S 鍵時,系統會呼叫 previewSKey() 函式,而不是 actionForPreview() 函式。

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")
    }
}

使用者按下 Tab 鍵時,也不會觸發 Box 元件的 onPreviewKeyEvent() lambda。系統會先在父項元件上呼叫 onPreviewKeyEvent() lambda,然後在子項元件中呼叫 onPreviewKeyEvent()。您可以利用這項行為,實作全螢幕鍵盤快速鍵。

其他資源