May be this is a late answer. But I have faced the same problem on a TV app. Those above mentioned steps are applicable, if there are no textfeilds in your app. If you are using textfeilds in your app, you should use FocasableActionDetector widget. The FocusableActionDetector includes Shortcuts, Actions and Focus widgets. The way I handled things was, I created a list of FocusNodes and assign them to focusable widgets in the page. then I would wrap all the focusable widgets with FocusableActionDetector give the necessary Keypress logic in the action parameter of the FocusableActionDetector. Here is an example of how to implement it.
class LoginPage extends StatefulWidget {
LoginPage({Key? key}) : super(key: key);
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
GlobalKey<FormState> get loginFormKey => formKey ??= GlobalKey<FormState>();
int loginIndex = 0;
list<FocusNode> loginNodes = <FocusNode>[];
@override
void initState() {
for (var i = 0; i < 5; i++) {
loginNodes.add(FocusNode(debugLabel: 'loginNode $i'));
}
super.initState();
}
@override
void dispose() {
loginNodes.dispose();
super.dispose();
}
Map<ShortcutActivator, Intent> navigationIntents = {
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowRight): const RightbuttonIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowLeft): const LeftbuttonIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowUp): const UpbuttonIntent(),
LogicalKeySet(LogicalKeyboardKey.arrowDown): const DownbuttonIntent(),
LogicalKeySet(LogicalKeyboardKey.goBack): const BackButtonIntent()
//LogicalKeySet(LogicalKeyboardKey.back)
};
@override
Widget build(BuildContext context) {
return
FocusableActionDetector(
shortcuts: navigationIntents,
actions: <Type, Action<Intent>>{
DownbuttonIntent: CallbackAction<DownbuttonIntent>(
onInvoke: (intent) {
// if (loginIndex <= 0) loginIndex = 0;
if (loginIndex <= loginNodes.length - 1) {
loginIndex++;
log('index in downIntent if is $loginIndex');
FocusScope.of(context).requestFocus(loginNodes[loginIndex]);
} else if (loginIndex > loginNodes.length - 1) {
loginIndex = 4;
log('index in downIntent else is $loginIndex');
FocusScope.of(context).requestFocus(loginNodes[3]);
}
// log('index in downIntent is $loginIndex');
return KeyEventResult.ignored;
},
),
UpbuttonIntent: CallbackAction<UpbuttonIntent>(
onInvoke: (intent) {
if (loginIndex >= 0) {
loginIndex--;
FocusScope.of(context).requestFocus(loginNodes[loginIndex]);
log('index in upIntent else is $loginIndex');
} else if (loginIndex <= 0) {
loginIndex = 0;
log('index in upIntent if is $loginIndex');
FocusScope.of(context).requestFocus(loginNodes[0]);
loginNodes.refresh();
}
return KeyEventResult.ignored;
},
),
},
child: AuthScreenWrapper(
authForm: AuthForm(
formKey: loginFormKey,
title: 'login'.tr,
subtitle: 'login_to_continue'.tr,
formComponents: [
EmailInputField(emailFocus: loginNodes[0]),
PasswordInputField(passwordFocus: loginNodes[1]),
KeepMeForgotButtons(
rememberNode: loginNodes[2],
),
LoginButton(
btnNode: loginNodes[3],
),
],
),
),
);
}
}
I hope this help for someone who has faced the same problem as mine