Flutter RawKeyboardListener listening twice?
Solution 1
Your callback is getting called for both keydown and keyup events with instances of following classes:
- RawKeyDownEvent
- RawKeyUpEvent
You can pass the whole object to handleKey, and filter based on runtime type of object. for example
handleKey(RawKeyEvent key) {
print("Event runtimeType is ${key.runtimeType}");
if(key.runtimeType.toString() == 'RawKeyDownEvent'){
RawKeyEventDataAndroid data = key.data as RawKeyEventDataAndroid;
String _keyCode;
_keyCode = data.keyCode.toString(); //keycode of key event (66 is return)
print("why does this run twice $_keyCode");
}
}
_buildTextComposer() {
TextField _textField = new TextField(
controller: _controller,
onSubmitted: _handleSubmitted,
);
FocusScope.of(context).requestFocus(_textNode);
return new RawKeyboardListener(
focusNode: _textNode,
onKey: handleKey,
child: _textField
);
}
If this still does not help, check actual runtimeTypes logged from handleKey method, and filter by those.
Solution 2
You are right. RawKeyboardListener
listens on raw keyboard events. Which means it returns down and up (or how the naming convention is on touchscreens). Knowing that you could simply create a if-statement and just get through the event once:
bool _tempKeyPressedOnce = false;
if (!_tempKeyPressedOnce) {
// do stuff
_tempKeyPressedOnce = true;
}
Solution 3
I prefer using is
rather than accessing the runtime type:
onKey: (RawKeyEvent event) {
if (event is RawKeyDownEvent) {
// handle key down
} else if (event is RawKeyUpEvent) {
// handle key up
}
},
Solution 4
Eyo, played around with the values variables and noticed that if you use the iskeypressed on the second time round it's false. Id hazard a guess that normally its either detecting the press and the release.
so
RawKeyboardListener(
focusNode: FocusNode(),
autofocus: true,
//includeSemantics: true,
onKey: (value){
print("1) ${value.data}");
print("2) ${value.character.toString()}");
print("3) ${value.toString()}");
print("4) ${value.physicalKey.debugName}");
print("5) ${value.logicalKey.keyId}");
print("6) ${value.isKeyPressed(LogicalKeyboardKey.enter)}");
setState(() {
///add string to list and clear text or not ?
value.logicalKey == LogicalKeyboardKey.enter ? print("YES A") : 0;
value.isKeyPressed(LogicalKeyboardKey.enter) ? print("YES B") : 0;
}
);
},
Results in a
flutter: 1) Instance of 'RawKeyEventDataWindows'
flutter: 2)
flutter: 3) RawKeyDownEvent#13d45(logicalKey: LogicalKeyboardKey#70028(keyId: "0x100070028", keyLabel: "Enter", debugName: "Enter"), physicalKey: PhysicalKeyboardKey#70028(usbHidUsage: "0x00070028", debugName: "Enter"))
flutter: 4) Enter
flutter: 5) 4295426088
flutter: 6) true
flutter: YES A
flutter: YES B
flutter: NEXT SET
flutter: ***********************************
flutter: 1) Instance of 'RawKeyEventDataWindows'
flutter: 2) null
flutter: 3) RawKeyUpEvent#9dc07(logicalKey: LogicalKeyboardKey#70028(keyId: "0x100070028", keyLabel: "Enter", debugName: "Enter"), physicalKey: PhysicalKeyboardKey#70028(usbHidUsage: "0x00070028", debugName: "Enter"))
flutter: 4) Enter
flutter: 5) 4295426088
flutter: 6) false
flutter: YES A
flutter: NEXT SET
flutter: ***********************************
Solution 5
This is how you can get it to work:
RawKeyboardListener(
focusNode: FocusNode(),
onKey: (event) {
// Only taking key down event into consideration
if (event.runtimeType == RawKeyDownEvent) {
bool shiftPressed = event.isShiftPressed; // true: if shift key is pressed
}
},
child: TextField(),
)
Related videos on Youtube
Jayden
Updated on June 04, 2022Comments
-
Jayden almost 2 years
What I am trying to achieve is when viewing this widget, the
RawKeyboardListener
starts listening straight away when theTextField
is not selected/in focus. It runs theHandleKey function
to deal with what I want to do with thekeyCode
.The issue I am having is when running the app for the first time, the
handleKey function
seems to be running twice. So in the example below it would printwhy does this run twice $_keyCode
TWICE when I only enter 1 key. I think it listens to keyUp AND keyDown. The result I want is for it to only run once...However, the code works fine as well when I select the TextField and do a regular submit with the emulator keyboard.
I am struggling to understand why it only has a problem after interacting with the TextField. I feel like it needs a
Future
orawait
somewhere? but I have no idea.Please help.
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'dart:async'; class KeyboardListener extends StatefulWidget { KeyboardListener(); @override _RawKeyboardListenerState createState() => new _RawKeyboardListenerState(); } class _RawKeyboardListenerState extends State<KeyboardListener> { TextEditingController _controller = new TextEditingController(); FocusNode _textNode = new FocusNode(); @override initState() { super.initState(); } //Handle when submitting void _handleSubmitted(String finalinput) { setState(() { SystemChannels.textInput.invokeMethod('TextInput.hide'); //hide keyboard again _controller.clear(); }); } handleKey(RawKeyEventDataAndroid key) { String _keyCode; _keyCode = key.keyCode.toString(); //keycode of key event (66 is return) print("why does this run twice $_keyCode"); } _buildTextComposer() { TextField _textField = new TextField( controller: _controller, onSubmitted: _handleSubmitted, ); FocusScope.of(context).requestFocus(_textNode); return new RawKeyboardListener( focusNode: _textNode, onKey: (key) => handleKey(key.data), child: _textField ); } @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar(title: new Text("Search Item")), body: _buildTextComposer(), ); } }
-
Mahesh Jamdade over 2 yearsThat's intended to notify key press and key release.
-
-
Jayden almost 6 yearsBut how do I access the
RawKeyDownEvent
or whatever I need to get to see if it is only a keydown or up so I can then use a bool on it -
Bostrot almost 6 yearsSomething like this:
RawKeyDownEvent keyDownEvent = key; keyDownEvent.data;
-
Kirill Karmazin over 4 yearsafaik this listener only works for physical keyboards, it doesn't work for 'soft' keyboard, right?
-
Gyuri Majercsik almost 4 yearsI would rather use the instance-of kind operator: key is RawKeyDownEvent
-
TomTom101 over 3 yearsBeware that this would not work in a production release where runtimeType will get optimized out, i.e. is not available.
-
lolbardsnin almost 3 yearsah just realised RawKeyUpEvent#9dc07 RawKeyDownEvent#13d45
-
Chris almost 2 yearsPerfect! Best answer, although should explain what the others have already i.e. that two events are triggering