Cómo controlar las acciones del teclado

Cuando el usuario enfoca un componente de texto editable, como TextField, y el dispositivo tiene un teclado de hardware conectado, y el sistema controla todas las entradas. Puedes administrar los eventos de teclas para proporcionar combinaciones de teclas.

Combinaciones de teclas predeterminadas

Las siguientes combinaciones de teclas están disponibles de forma predeterminada.

Combinación de teclas Acción Elementos componibles que admiten el atajo
Mayúsculas+Ctrl+Flecha hacia la izquierda/derecha Selecciona el texto hasta el principio o el final de la palabra BasicTextField, TextField
Mayúsculas+Ctrl+Flecha hacia arriba/Flecha hacia abajo Seleccionar el texto hasta el principio o final del párrafo BasicTextField, TextField
Mayúsculas + Alt + Flecha hacia arriba/Flecha hacia abajo o Mayúsculas + Meta + Flecha hacia la izquierda/Flecha hacia la derecha Selecciona el texto hasta el principio o el final del texto BasicTextField, TextField
Mayúsculas + Flecha hacia la izquierda/Flecha hacia la derecha Selecciona caracteres BasicTextField, TextField
Ctrl+A Seleccionar todo BasicTextField, TextField
Ctrl + C/Ctrl + X/Ctrl + V Copiar, cortar y pegar BasicTextField, TextField
Ctrl + Z o Ctrl + Mayúsculas + Z Deshacer y rehacer BasicTextField, TextField
PageDown/PageUp Desplazamiento LazyColumn, el modificador verticalScroll, el modificador scrollable

Eventos clave

En Compose, puedes controlar una pulsación de tecla individual con el modificador onKeyEvent. El modificador acepta una lambda que se llama cuando el componente modificado recibe un evento clave. Un evento de tecla se describe como un objeto KeyEvent. Para obtener la información de cada evento de tecla, puedes consultar el objeto en la expresión lambda que se pasa al modificador onKeyEvent.

Una pulsación de tecla envía dos eventos de tecla. Uno se activa cuando el usuario presiona la tecla y el otro se activa cuando se suelta la tecla. Puedes distinguir los dos eventos clave haciendo referencia al atributo type del objeto KeyEvent.

El valor que se muestra de la lambda onKeyEvent indica si el evento clave se controla o no. Muestra true si tu app controla el evento de tecla, lo que detiene la propagación del evento.

En el siguiente fragmento, se muestra cómo llamar a una función doSomething() cuando el usuario suelta la tecla S en el componente Box:

Box(
    modifier = Modifier.focusable().onKeyEvent {
        if(
            it.type == KeyEventType.KeyUp &&
            it.key == Key.S
        ) {
            doSomething()
            true
        } else {
            false
        }
    }
)  {
    Text("Press S key")
}

Teclas modificadoras

Un objeto KeyEvent tiene los siguientes atributos que indican sin importar si se presionan o no las teclas modificadoras:

Describe con especificidad los eventos clave que controla tu app. En el siguiente fragmento, se llama a una función doSomething() solo si el usuario suelta la tecla S. Si el usuario presiona cualquier tecla modificadora, como la tecla Mayúsculas, la app no llama a la función.

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

Eventos de clic de tecla Intro y barra espaciadora

La tecla Barra espaciadora y la tecla Intro también activan los eventos de clic. Por ejemplo, los usuarios pueden activar o desactivar (reproducir o pausar) la reproducción de contenido multimedia con la barra espaciadora o la tecla Intro manejando los eventos de clic de la siguiente manera:

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

El modificador clickable intercepta los eventos de teclas y llama a la devolución de llamada onClick() cuando se presiona la barra espaciadora o la tecla Intro. Por eso, se llama a la función togglePausePlay() Para ello, presiona la barra espaciadora o la tecla Intro en el fragmento.

Eventos de teclas no consumidos

Los eventos de tecla no consumidos se propagan desde el componente en el que se produjo el evento hasta el componente exterior envolvente. En el siguiente ejemplo, InnerComponent consume eventos de teclas cuando se suelta la tecla S, por lo que OuterComponent no recibe ningún evento de tecla activado por soltar la tecla S. Por eso, nunca se llama a la función actionB().

OuterComponent puede controlar otros eventos de teclas en InnerComponent, como soltar la tecla D. Se llama a la función actionC() porque el evento de tecla para liberar la tecla D se propaga a 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
            }
        }
    )
}

Modificador onKeyPreviewEvent

En algunos casos de uso, deseas interceptar un evento de tecla antes de que active la acción predeterminada. Agregar accesos directos personalizados a un TextField es uno típico. El siguiente fragmento permite a los usuarios pasar al siguiente componente enfocado presionando la tecla 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
        }
    }
)

De forma predeterminada, el componente TextField agrega un carácter de tabulación cada vez que los usuarios presionan la tecla Tab, incluso si el evento de tecla se controla con el modificador onKeyEvent. Para mover el enfoque del teclado sin agregar ningún carácter de tabulación, controla el evento de tecla antes de activar las acciones asociadas con él, como en el fragmento. La lambda onKeyPreviewEvent() intercepta el evento de tecla mostrando true.

El componente superior puede interceptar el evento de tecla que ocurre en sus elementos secundarios. En el siguiente fragmento, se llama a la función previewSKey() cuando los usuarios presionen la tecla S en lugar de llamar a la función 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")
  }
}

Tampoco se activa la lambda onPreviewKeyEvent() para el componente Box cuando los usuarios presionan la tecla Tab. Primero se llama a la lambda onPreviewKeyEvent() en el componente superior. Luego, se llama a onPreviewKeyEvent() en el componente secundario. Puedes implementar combinaciones de teclas en toda la pantalla con este comportamiento.

Recursos adicionales