Saltar al contenido principal

Migrar el sistema RawKeyEvent/RawKeyboard al sistema KeyEvent/HardwareKeyboard

El subsistema de eventos de teclado en crudo (raw key event) ha sido reemplazado por el subsistema de eventos de teclado, y las APIs que usan RawKeyEvent y RawKeyboard se convierten a KeyEvent y HardwareKeyboard.

Resumen

#

Desde hace algún tiempo (años), Flutter ha tenido dos sistemas de eventos de teclado implementados. El nuevo sistema alcanzó la paridad con el antiguo sistema de eventos de teclado en crudo (raw key event) específico de la plataforma, y el sistema en crudo ha quedado obsoleto.

Contexto

#

En el subsistema original de eventos de teclado, el manejo de las particularidades de cada plataforma en el framework y en las aplicaciones cliente causaba un código excesivamente complejo, y el sistema antiguo no representaba correctamente el estado real de los eventos de teclado en el sistema.

La API heredada RawKeyboard ha quedado obsoleta y se eliminará en el futuro. Las APIs HardwareKeyboard y KeyEvent reemplazan a esta API heredada. Un ejemplo de este cambio es que FocusNode.onKeyEvent reemplaza a FocusNode.onKey.

El comportamiento de RawKeyboard proporcionaba un modelo de eventos menos unificado y menos regular de lo que lo hace HardwareKeyboard. Considera los siguientes ejemplos:

  • Los eventos de pulsación (down) no siempre se correspondían con un evento de liberación (up), y viceversa (el conjunto de teclas presionadas se actualizaba silenciosamente).
  • La tecla lógica del evento de pulsación (down) no siempre era la misma que la del evento de liberación (up).
  • Los eventos de pulsación (down) y los eventos de repetición no eran fácilmente distinguibles (tenían que ser rastreados manualmente).
  • Los modos de bloqueo (como CapsLock) solo tenían registrado su estado "activado". No había forma de obtener su estado de presionado.

Así nació el nuevo sistema basado en KeyEvent/HardwareKeyboard y, para minimizar los cambios de ruptura, se implementó en paralelo con el antiguo sistema con la intención de eventualmente declarar obsoleto el sistema en crudo (raw). Ese momento ha llegado, y los desarrolladores de aplicaciones deberían migrar su código para evitar los cambios de ruptura que ocurrirán cuando se eliminen las APIs obsoletas.

Descripción del cambio

#

A continuación se muestran las APIs que han quedado obsoletas.

APIs obsoletas que tienen un equivalente

#

APIs que han sido descontinuadas

#

Estas APIs ya no son necesarias una vez que solo hay un sistema de eventos de teclado, o su funcionalidad ya no se ofrece.

Guía de migración

#

Las bibliotecas del framework de Flutter ya han sido migradas. Si tu código utiliza alguna de las clases o métodos enumerados en la sección anterior, migra a estas nuevas APIs.

Migrar tu código que usa RawKeyEvent

#

En su mayor parte, existen APIs de KeyEvent equivalentes disponibles para todas las APIs de RawKeyEvent.

Algunas APIs relacionadas con información específica de la plataforma contenida en objetos RawKeyEventData o sus subclases han sido eliminadas y ya no son compatibles. Una excepción es que la información de RawKeyEventDataAndroid.eventSource ahora es accesible como KeyEvent.deviceType en un formato más independiente de la plataforma.

#

Si el código heredado utilizaba las APIs RawKeyEvent.isKeyPressed, RawKeyEvent.isControlPressed, RawKeyEvent.isShiftPressed, RawKeyEvent.isAltPressed, o RawKeyEvent.isMetaPressed, ahora existen funciones equivalentes en la instancia singleton HardwareKeyboard, pero no están disponibles en [KeyEvent]. RawKeyEvent.isKeyPressed está disponible como HardwareKeyboard.isLogicalKeyPressed.

Antes:

dart
KeyEventResult _handleKeyEvent(RawKeyEvent keyEvent) {
  if (keyEvent.isControlPressed ||
      keyEvent.isShiftPressed ||
      keyEvent.isAltPressed ||
      keyEvent.isMetaPressed) {
    print('Modifier pressed: $keyEvent');
  }
  if (keyEvent.isKeyPressed(LogicalKeyboardKey.keyA)) {
    print('Key A pressed.');
  }
  return KeyEventResult.ignored;
}

Después:

dart
KeyEventResult _handleKeyEvent(KeyEvent _) {
  if (HardwareKeyboard.instance.isControlPressed ||
      HardwareKeyboard.instance.isShiftPressed ||
      HardwareKeyboard.instance.isAltPressed ||
      HardwareKeyboard.instance.isMetaPressed) {
    print('Modifier pressed: $keyEvent');
  }
  if (HardwareKeyboard.instance.isLogicalKeyPressed(LogicalKeyboardKey.keyA)) {
    print('Key A pressed.');
  }
  return KeyEventResult.ignored;
}

Configurar onKey para el enfoque

#

Si el código heredado utilizaba los parámetros Focus.onKey, FocusScope.onKey, FocusNode.onKey, o FocusScopeNode.onKey, entonces existe un parámetro equivalente Focus.onKeyEvent, FocusScope.onKeyEvent, FocusNode.onKeyEvent, o FocusScopeNode.onKeyEvent que proporciona KeyEvents en lugar de RawKeyEvents.

Antes:

dart
Widget build(BuildContext context) {
  return Focus(
    onKey: (RawKeyEvent keyEvent) {
      print('Key event: $keyEvent');
      return KeyEventResult.ignored;
    }
    child: child,
  );
}

Después:

dart
Widget build(BuildContext context) {
  return Focus(
    onKeyEvent: (KeyEvent keyEvent) {
      print('Key event: $keyEvent');
      return KeyEventResult.ignored;
    }
    child: child,
  );
}

Manejo de eventos de teclado repetidos

#

Si dependías del atributo RawKeyEvent.repeat para determinar si una tecla era un evento de tecla repetido, eso ahora se ha separado en un tipo KeyRepeatEvent independiente.

Antes:

dart
KeyEventResult _handleKeyEvent(RawKeyEvent keyEvent) {
  if (keyEvent is RawKeyDownEvent) {
    print('Key down: ${keyEvent.data.logicalKey.keyLabel}(${keyEvent.repeat ? ' (repeated)' : ''})');
  }
  return KeyEventResult.ignored;
}

Después:

dart
KeyEventResult _handleKeyEvent(KeyEvent _) {
  if (keyEvent is KeyDownEvent || keyEvent is KeyRepeatEvent) {
    print('Key down: ${keyEvent.logicalKey.keyLabel}(${keyEvent is KeyRepeatEvent ? ' (repeated)' : ''})');
  }
  return KeyEventResult.ignored;
}

Aunque no es una subclase de KeyDownEvent, un KeyRepeatEvent también es un evento de tecla presionada (key down). No asumas que keyEvent is! KeyDownEvent solo permite eventos de tecla liberada (key up). Comprueba tanto KeyDownEvent como KeyRepeatEvent.

Timeline

#

Introducido en la versión: 3.18.0-7.0.pre
En el lanzamiento estable: 3.19.0

Referencias

#

Documentación de la API de reemplazo:

Issues relevantes:

PRs relevantes: