HardwareKeyboard class Null safety

Manages key events from hardware keyboards.

HardwareKeyboard manages all key events of the Flutter application from hardware keyboards (in contrast to on-screen keyboards). It receives key data from the native platform, dispatches key events to registered handlers, and records the keyboard state.

To stay notified whenever keys are pressed, held, or released, add a handler with addHandler. To only be notified when a specific part of the app is focused, use a Focus widget's onFocusChanged attribute instead of addHandler. Handlers should be removed with removeHandler when notification is no longer necessary, or when the handler is being disposed.

To query whether a key is being held, or a lock mode is enabled, use physicalKeysPressed, logicalKeysPressed, or lockModesEnabled. These states will have been updated with the event when used during a key event handler.

The singleton HardwareKeyboard instance is held by the ServicesBinding as ServicesBinding.keyboard, and can be conveniently accessed using the HardwareKeyboard.instance static accessor.

Event model

Flutter uses a universal event model (KeyEvent) and key options (LogicalKeyboardKey and PhysicalKeyboardKey) regardless of the native platform, while preserving platform-specific features as much as possible.

HardwareKeyboard guarantees that the key model is "regularized": The key event stream consists of "key tap sequences", where a key tap sequence is defined as one KeyDownEvent, zero or more KeyRepeatEvents, and one KeyUpEvent in order, all with the same physical key and logical key.


  • Tap and hold key A, US layout:
    • KeyDownEvent(physicalKey: keyA, logicalKey: keyA, character: "a")
    • KeyRepeatEvent(physicalKey: keyA, logicalKey: keyA, character: "a")
    • KeyUpEvent(physicalKey: keyA, logicalKey: keyA)
  • Press ShiftLeft, tap key A, then release ShiftLeft, US layout:
    • KeyDownEvent(physicalKey: shiftLeft, logicalKey: shiftLeft)
    • KeyDownEvent(physicalKey: keyA, logicalKey: keyA, character: "A")
    • KeyRepeatEvent(physicalKey: keyA, logicalKey: keyA, character: "A")
    • KeyUpEvent(physicalKey: keyA, logicalKey: keyA)
    • KeyUpEvent(physicalKey: shiftLeft, logicalKey: shiftLeft)
  • Tap key Q, French layout:
    • KeyDownEvent(physicalKey: keyA, logicalKey: keyQ, character: "q")
    • KeyUpEvent(physicalKey: keyA, logicalKey: keyQ)
  • Tap CapsLock:
    • KeyDownEvent(physicalKey: capsLock, logicalKey: capsLock)
    • KeyUpEvent(physicalKey: capsLock, logicalKey: capsLock)

When the Flutter application starts, all keys are released, and all lock modes are disabled. Upon key events, HardwareKeyboard will update its states, then dispatch callbacks: KeyDownEvents and KeyUpEvents set or reset the pressing state, while KeyDownEvents also toggle lock modes.

Flutter will try to synchronize with the ground truth of keyboard states using synthesized events (KeyEvent.synthesized), subject to the availability of the platform. The desynchronization can be caused by non-empty initial state or a change in the focused window or application. For example, if CapsLock is enabled when the application starts, then immediately before the first key event, a synthesized KeyDownEvent and KeyUpEvent of CapsLock will be dispatched.

The resulting event stream does not map one-to-one to the native key event stream. Some native events might be skipped, while some events might be synthesized and do not correspond to native events. Synthesized events will be indicated by KeyEvent.synthesized.


  • Flutter starts with CapsLock on, the first press of keyA:
    • KeyDownEvent(physicalKey: capsLock, logicalKey: capsLock, synthesized: true)
    • KeyUpEvent(physicalKey: capsLock, logicalKey: capsLock, synthesized: true)
    • KeyDownEvent(physicalKey: keyA, logicalKey: keyA, character: "a")
  • While holding ShiftLeft, lose window focus, release shiftLeft, then focus back and press keyA:
    • KeyUpEvent(physicalKey: shiftLeft, logicalKey: shiftLeft, synthesized: true)
    • KeyDownEvent(physicalKey: keyA, logicalKey: keyA, character: "a")

Flutter does not distinguish between multiple keyboards. Flutter will process all events as if they come from a single keyboard, and try to resolve any conflicts and provide a regularized key event stream, which can deviate from the ground truth.

Compared to RawKeyboard

RawKeyboard is the legacy API, and will be deprecated and removed in the future. It is recommended to always use HardwareKeyboard and KeyEvent APIs (such as FocusNode.onKeyEvent) to handle key events.

Behavior-wise, RawKeyboard provides a less unified, less regular event model than HardwareKeyboard. For example:

  • Down events might not be matched with an up event, and vice versa (the set of pressed keys is silently updated).
  • The logical key of the down event might not be the same as that of the up event.
  • Down events and repeat events are not easily distinguishable (must be tracked manually).
  • Lock modes (such as CapsLock) only have their "enabled" state recorded. There's no way to acquire their pressing state.

See also:




hashCode int
The hash code for this object. [...]
read-only, inherited
lockModesEnabled Set<KeyboardLockMode>
The set of KeyboardLockMode that are enabled. [...]
logicalKeysPressed Set<LogicalKeyboardKey>
The set of LogicalKeyboardKeys that are pressed. [...]
physicalKeysPressed Set<PhysicalKeyboardKey>
The set of PhysicalKeyboardKeys that are pressed. [...]
runtimeType Type
A representation of the runtime type of the object.
read-only, inherited


addHandler(KeyEventCallback handler) → void
Register a listener that is called every time a hardware key event occurs. [...]
clearState() → void
Clear all keyboard states and additional handlers. [...]
handleKeyEvent(KeyEvent event) bool
Process a new KeyEvent by recording the state changes and dispatching to handlers.
lookUpLayout(PhysicalKeyboardKey physicalKey) LogicalKeyboardKey?
Returns the logical key that corresponds to the given pressed physical key. [...]
noSuchMethod(Invocation invocation) → dynamic
Invoked when a non-existent method or property is accessed. [...]
removeHandler(KeyEventCallback handler) → void
Stop calling the given listener every time a hardware key event occurs. [...]
toString() String
A string representation of this object. [...]


operator ==(Object other) bool
The equality operator. [...]

Static Properties

instance HardwareKeyboard
Provides convenient access to the current HardwareKeyboard singleton from the ServicesBinding instance.