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
#-
Focus.onKey=>Focus.onKeyEvent - El argumento
onKeydeFocusNode.attach=> argumentoonKeyEvent -
FocusNode.onKey=>FocusNode.onKeyEvent -
FocusOnKeyCallback=>FocusOnKeyEventCallback -
FocusScope.onKey=>FocusScope.onKeyEvent -
FocusScopeNode.onKey=>FocusScopeNode.onKeyEvent -
RawKeyboard=>HardwareKeyboard -
RawKeyboardListener=>KeyboardListener -
RawKeyDownEvent=>KeyDownEvent -
RawKeyEvent=>KeyEvent -
RawKeyUpEvent=>KeyUpEvent
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.
-
debugKeyEventSimulatorTransitModeOverride -
GLFWKeyHelper -
GtkKeyHelper -
KeyboardSide -
KeyDataTransitMode -
KeyEventManager KeyHelperKeyMessage-
KeyMessageHandler -
KeySimulatorTransitModeVariant -
ModifierKey -
RawKeyEventData -
RawKeyEventDataAndroid -
RawKeyEventDataFuchsia -
RawKeyEventDataIos -
RawKeyEventDataLinux -
RawKeyEventDataMacOs -
RawKeyEventDataWeb -
RawKeyEventDataWindows -
RawKeyEventHandler -
ServicesBinding.keyEventManager
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.
Migrar isKeyPressed y funciones relacionadas
#
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:
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:
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:
Widget build(BuildContext context) {
return Focus(
onKey: (RawKeyEvent keyEvent) {
print('Key event: $keyEvent');
return KeyEventResult.ignored;
}
child: child,
);
}
Después:
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:
KeyEventResult _handleKeyEvent(RawKeyEvent keyEvent) {
if (keyEvent is RawKeyDownEvent) {
print('Key down: ${keyEvent.data.logicalKey.keyLabel}(${keyEvent.repeat ? ' (repeated)' : ''})');
}
return KeyEventResult.ignored;
}
Después:
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:
-
Focus.onKeyEvent -
FocusNode.onKeyEvent -
FocusOnKeyEventCallback -
FocusScope.onKeyEvent -
FocusScopeNode.onKeyEvent -
HardwareKeyboard -
KeyboardListener -
KeyDownEvent -
KeyRepeatEvent KeyEvent-
KeyEventHandler KeyUpEvent
Issues relevantes:
PRs relevantes:
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-05. Ver código fuente oreportar un problema.