Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter RawKeyboardListener listening twice?

What I am trying to achieve is when viewing this widget, the RawKeyboardListener starts listening straight away when the TextField is not selected/in focus. It runs the HandleKey function to deal with what I want to do with the keyCode.

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 print why 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 or await 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(),
    );
  }
}
like image 780
Jayden Avatar asked Jun 22 '18 09:06

Jayden


2 Answers

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.

like image 141
Ganapat Avatar answered Nov 17 '22 21:11

Ganapat


The onKey callback is triggered for both key down and key up events. That's why it appears to be called twice for a single key press.

When handling the events, 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
  }
},
like image 5
Suragch Avatar answered Nov 17 '22 20:11

Suragch