'Flutter RawKeyboardListener Text Field Focus control

I am developing an android TV application using flutter. The remote control key which user is pressing, can be detected by RawKeyboardListener. But the focus is having an issue. Initially the focus will be in username field, then once editing complete it will move to password field, and then to the button. So OnTap mehthod will be triggered. After that the focus is only going to username button for up arrow key. No response for down arrow key. Also if the data entered again, even if the button is having focus, I am not able to enter it(onTap function is not working). Any idea??

import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
import 'package:google_fonts/google_fonts.dart';
   
    class WelcomePage extends StatefulWidget {
      @override
      _WelcomePageState createState() => _WelcomePageState();
    }
    
    class _WelcomePageState extends State<WelcomePage> {
      TextEditingController nameController = TextEditingController();
      TextEditingController passwordController = TextEditingController();
      var usermame, password = '';
      late FocusNode _fs = FocusNode();
      FocusNode? userNameFocusNode;
      FocusNode? passwordFocusNode;
      FocusNode? buttonFocusNode;
    
      @override
      void initState() {
        super.initState();
        _fs = FocusNode();
        userNameFocusNode = FocusNode();
        passwordFocusNode = FocusNode();
        buttonFocusNode = FocusNode();
        setFirstFocus();
      }
    
      setFirstFocus() {
        if (userNameFocusNode == null) {
          userNameFocusNode = FocusNode();
          passwordFocusNode = FocusNode();
          buttonFocusNode = FocusNode();
          FocusScope.of(context).requestFocus(userNameFocusNode);
        }
        changeFocus(BuildContext context, FocusNode node) {
          FocusScope.of(context).requestFocus(node);
        }
      }
    
      @override
      void dispose() {
        super.dispose();
        _fs.dispose();
        userNameFocusNode?.dispose();
        passwordFocusNode?.dispose();
        buttonFocusNode?.dispose();
      }
    
      Widget _title() {
        return RichText(
          textAlign: TextAlign.center,
          text: TextSpan(
              text: 'Login Page',
              style: GoogleFonts.portLligatSans(
                textStyle: Theme.of(context).textTheme.headline4,
                fontSize: 50,
                fontWeight: FontWeight.w700,
                color: Colors.red,
              ),
        );
      }
    
      Widget _usernameController() {
        return Container(
            width: MediaQuery.of(context).size.width / 2.5,
            padding: const EdgeInsets.symmetric(vertical: 13),
            alignment: Alignment.center,
            child: TextFormField(
              textInputAction: TextInputAction.done,
                onEditingComplete: () {
                  userNameFocusNode!.unfocus();
                  FocusScope.of(context).requestFocus(passwordFocusNode);
                },
                textAlign: TextAlign.left,
                focusNode: userNameFocusNode,
                autofocus: true,
                controller: nameController,
                style:
                    const TextStyle(fontSize: 22.0, height: 1, color: Colors.white),
                decoration: InputDecoration(
                  isDense: true,
                  prefixIcon: const Padding(
                    padding: EdgeInsets.only(left: 0),
                    child: Icon(
                      Icons.person,
                      size: 30,
                      color: Colors.white,
                    ),
                  ),
                  fillColor: Colors.white,
                  border: OutlineInputBorder(
                    borderSide: const BorderSide(color: Colors.white, width: 5.00),
                    borderRadius: BorderRadius.circular(20.0),
                  ),
                  labelText: ' Username',
                  labelStyle: const TextStyle(color: Colors.white, fontSize: 20),
                )));
      }
    
      Widget _passwordController() {
        return Container(
            width: MediaQuery.of(context).size.width / 2.5,
            padding: const EdgeInsets.symmetric(vertical: 13),
            alignment: Alignment.center,
            child: TextFormField(
                textInputAction: TextInputAction.done,
                onEditingComplete: () {
                  passwordFocusNode!.unfocus();
                  FocusScope.of(context).requestFocus(buttonFocusNode);
                },
                focusNode: passwordFocusNode,
                obscureText: true,
                textAlign: TextAlign.left,
                autofocus: true,
                controller: passwordController,
                style:
                    const TextStyle(fontSize: 22.0, height: 1, color: Colors.white),
                decoration: InputDecoration(
                  isDense: true,
                  prefixIcon: const Padding(
                    padding: EdgeInsets.only(left: 0),
                    child: Icon(
                      Icons.https,
                      size: 25,
                      color: Colors.white,
                    ),
                  ),
                  fillColor: Colors.white,
                  border: OutlineInputBorder(
                    borderSide: const BorderSide(color: Colors.white, width: 5.00),
                    borderRadius: BorderRadius.circular(20.0),
                  ),
                  labelText: ' Password',
                  labelStyle: const TextStyle(color: Colors.white, fontSize: 20),
                )));
      }
    
      Widget _submitButton() {
        return InkWell(
              focusNode: buttonFocusNode,
              onTap: () {
                print('${nameController.text} + ${passwordController.text}');
              },
              child: Container(
                width: MediaQuery.of(context).size.width / 2.5,
                padding: const EdgeInsets.symmetric(vertical: 5),
                alignment: Alignment.center,
                decoration: BoxDecoration(
                    borderRadius: const BorderRadius.all(Radius.circular(10)),
                    boxShadow: <BoxShadow>[
                      BoxShadow(
                          color: const Color(0xffdf8e33).withAlpha(100),
                          offset: const Offset(2, 4),
                          blurRadius: 8,
                          spreadRadius: 2)
                    ],
                    color: Colors.white),
                child: const Text(
                  'Login',
                  style: TextStyle(fontSize: 20, color: Colors.red),
                ),
              ),
            );
      }
    
      void snackBardata(context, String actionMsg, var duration, Color snColour,
          Color snDataColor) {
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text(
            actionMsg,
            style: TextStyle(
              color: snDataColor,
              fontSize: 20,
            ),
            textAlign: TextAlign.center,
          ),
          duration: Duration(seconds: 2),
          backgroundColor: snColour,
          behavior: SnackBarBehavior.floating,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(20),
          ),
        ));
      }
    
      void _handleKeyPressed(context, event) {
        if (event is RawKeyDownEvent) {
          switch (event.data.logicalKey.keyLabel.toString()) {
            case 'Select':
              {
                _fs.unfocus();
                print('select key pressed');
                FocusScope.of(context).requestFocus(buttonFocusNode);
              }
              break;
            case 'Arrow Down':
              {
                print('arrow down');
                FocusScope.of(context).requestFocus(userNameFocusNode);
              }
              break;
            case 'Arrow Left':
              {}
              break;
            case 'Arrow Up':
              {
                print('arrow up');
                FocusScope.of(context).requestFocus(passwordFocusNode);
              }
              break;
            case 'Arrow Right':
              {}
              break;
            default:
              {
                print('unknown--------------------------------');
              }
              break;
          }
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Shortcuts(
            shortcuts: {
              LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
            },
            child: Scaffold(
              body: SingleChildScrollView(
                child: Container(
                  padding: const EdgeInsets.symmetric(horizontal: 20),
                  height: MediaQuery.of(context).size.height,
                  width: MediaQuery.of(context).size.width,
                  decoration: BoxDecoration(
                      image: DecorationImage(
                        image: const AssetImage('assets/asset1.jpg'),
                        fit: BoxFit.fill,
                        colorFilter: ColorFilter.mode(
                            Colors.black.withOpacity(0.6), BlendMode.hardLight),
                      ),
                      borderRadius: const BorderRadius.all(Radius.circular(0)),
                      boxShadow: <BoxShadow>[
                        BoxShadow(
                            color: Colors.grey.shade200,
                            offset: const Offset(2, 4),
                            blurRadius: 5,
                            spreadRadius: 2)
                      ],
                      gradient: const LinearGradient(
                          begin: Alignment.topCenter, end: Alignment.bottomCenter,
                          // colors: [Colors.yellow, Colors.teal])),
                          colors: [Color(0xfffbb448), Color(0xffe46b10)])),
                  child: RawKeyboardListener(
                    focusNode: _fs,
                    onKey: (event) {
                      _handleKeyPressed(context, event);
                    },
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        _title(),
                        const SizedBox(
                          height: 20,
                        ),
                        _usernameController(),
                        _passwordController(),
                        const SizedBox(
                          height: 20,
                        ),
                        _submitButton(),
                        const SizedBox(
                          height: 20,
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ));
      }
    }


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source