Flutter: How can I prevent default behaviour on key press?
Asked Answered
W

3

8

I'm trying to intercept when a user presses the volume buttons to perform a specific action and prevent the default behaviour (volume changes).

This is the code I have so far:

RawKeyboard.instance.addListener(_keyboardListener);

void _keyboardListener(RawKeyEvent e) {
  if(e.runtimeType == RawKeyUpEvent) {
    RawKeyEventDataAndroid eA = e.data;
    if(eA.keyCode == 24) { //volume up key
      _goNextPage();
    }
    if(eA.keyCode == 25) { //volume down key
      _goPrevPage();
    }
  }
}

How would I go about preventing the volume from changing (and stopping the volume slider from appearing at the top)?

A Javascript analogous would be calling event.preventDefault() on the key event.

This seems to be a rather trivial matter, but I haven't been able to find any answers in the docs.

Thanks.

Wellesley answered 26/11, 2018 at 0:34 Comment(2)
Did you ever find a solution?Trichomoniasis
Unfortunately, no.Wellesley
E
4

I've faced a similar problem and what to share how I solved it.

To stop the propagation we have to return true from onKey method of a FocusNode in the focus nodes tree. To achieve this I've wrapped my app body with FocusScope and Focus widgets like this:

MaterialApp(
      home: Scaffold(
          body: FocusScope(
              autofocus: true,
              child: Focus(
                  autofocus: true,
                  canRequestFocus: true,
                  onKey: (data, event) {
                    if (event.isKeyPressed(LogicalKeyboardKey.audioVolumeUp)) {
                      print("Volume up");
                      return true;
                    }
                    if (event
                        .isKeyPressed(LogicalKeyboardKey.audioVolumeDown)) {
                      print("Volume down");
                      return true;
                    }
                    return false;
                  },
                  child: Text(text: "Hallochen")))))
Ectopia answered 20/10, 2020 at 14:24 Comment(0)
M
1

Thanks to Sergey's answer I was able to solve the issue as well. In my case, I wanted to create a ListView, with pull to refresh (RefreshIndicator) that will work for both mobile devices and web.

I tried to implement a refresh indicator which will appear when the user clicks F5 to refresh the web page, but I had to prevent the browser from actually refreshing the page.

Here's an example of my implementation, which prevents refresh from occuring when the user clicks F5.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';


class ExamplePage extends StatefulWidget {
  @override
  _ExamplePageState createState() => _ExamplePageState();
}

class _ExamplePageState extends State<ExamplePage> {
  final GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();
  final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = new GlobalKey<RefreshIndicatorState>();
  
  List items = [];

  Future<void> _pullRefresh() async {
    await Future.delayed(Duration(milliseconds: 1000));
  }
  
  @override
  Widget build(BuildContext context) {
    return FocusScope(
      autofocus: true,
      child: Focus(
        autofocus: true,
        canRequestFocus: true,
        onKey: (data, event) {
          if (event
              .isKeyPressed(LogicalKeyboardKey.f5)) {
            _refreshIndicatorKey.currentState!.show();
            return KeyEventResult.handled;
          }
          return KeyEventResult.ignored;
        },
        child: Container(
            padding: EdgeInsets.all(15.0),
            child: RefreshIndicator(
              key: _refreshIndicatorKey,
              onRefresh: _pullRefresh,
              child: AnimatedList(
                key: listKey,
                initialItemCount: items.length,
                itemBuilder: (context, index, animation) {
                  return _buildItem(context, index, animation);
                },
              ),
            ),
        ),
      ),
    );
  }
  
    Widget _buildItem(
      BuildContext context, int index, Animation<double> animation) {
    return Text("Example");
    }
}
Minnich answered 20/9, 2021 at 22:8 Comment(0)
P
0

all the solutions here are for Focus widget, they inspired me but were not quite the solution for me as I was using RawKeyboardListener and did not wanna change to something else.

here is what worked for me:

final node = FocusNode();
final fnode = FocusScopeNode();

@override
Widget build(BuildContext context) {
  return FocusScope(
    node: fnode,
    child: RawKeyboardListener(
      focusNode: node,
      ...
    ),
  );
}
Plumcot answered 9/7, 2022 at 19:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.