Reputation: 515
I'm trying to detect key presses like "Enter", "Delete" and "Backspace" within flutter. My issue with using a RawKeyboardListener
is that it takes focus away from any child widgets.
For example
RawKeyboardListener(
focusNode: _focusNode,
onKey: handleKey,
child: TextField()
)
This makes it impossible to detect both key presses and use the Textfield
at the same time.
Does anyone have a alternative way for detecting key presses.
Thanks
Upvotes: 21
Views: 13386
Reputation: 5293
Flutter has a keyboard service that provides Flutter with raw key events from hardware keyboards, and you can ask this service to give you key events as well.
A benefit of this approach is that it doesn't prevent existing Flutter focus nodes from receiving events, so you don't have to manually handle keyboard event propagation.
This works on desktop, but note that it doesn't work for mobile (iOS / Android).
You can add a listener to this service like so:
import 'package:flutter/services.dart';
ServicesBinding.instance.keyboard.addHandler(_onKey);
...where _onKey
is a bool Function(KeyEvent)
. Here's an example event handler:
bool _onKey(KeyEvent event) {
final key = event.logicalKey.keyLabel;
if (event is KeyDownEvent) {
print("Key down: $key");
} else if (event is KeyUpEvent) {
print("Key up: $key");
} else if (event is KeyRepeatEvent) {
print("Key repeat: $key");
}
return false;
}
See here for more info: https://api.flutter.dev/flutter/services/HardwareKeyboard/addHandler.html
Note that this event handler will always receive key events, even if a text box is currently in focus.
Here's an example of using this technique in a widget:
import 'package:flutter/services.dart';
// ...
class MyApp extends StatefulWidget {
// ...
}
class _MyAppState extends State<MyApp> {
// ...
bool _onKey(KeyEvent event) {
final key = event.logicalKey.keyLabel;
if (event is KeyDownEvent) {
print("Key down: $key");
} else if (event is KeyUpEvent) {
print("Key up: $key");
} else if (event is KeyRepeatEvent) {
print("Key repeat: $key");
}
return false;
}
@override
void initState() {
super.initState();
ServicesBinding.instance.keyboard.addHandler(_onKey);
}
@override
void dispose() {
ServicesBinding.instance.keyboard.removeHandler(_onKey);
super.dispose();
}
@override
Widget build(BuildContext context) {
// ...
}
}
Upvotes: 14
Reputation: 534
You can use dart:ui
and set method window.onKeyData
in initState
in a stateful widget
Be careful with that method as if you have any focusable nodes on the screen you will need to pass events to them too, otherwise, for example, TextField will not work.
@override
void initState() {
window.onKeyData = (final keyData) {
if (keyData.logical == LogicalKeyboardKey.escape.keyId) {
widget.onPressed();
return true;
}
/// Let event pass to other focuses if it is not the key we looking for
return false;
};
super.initState();
}
@override
void dispose() {
window.onKeyData = null;
super.dispose();
}
Upvotes: 2
Reputation: 92
You can use the following from dart_html:
window.onKeyPress.listen((KeyboardEvent e) {
print(e.charCode.toString() + " " + new String.fromCharCode(e.charCode));
});
Upvotes: 5