Files
flame/doc/keyboard-input.md
Renan c833319c49 Feat: Add keyboard with focus node implementation (#909)
* Add keyboard with focus node implementation

* a

* format and make it stabel compatible

* Add mixin to game

* fixes

* add tests

* format

* docs

* more docs

* Update doc/keyboard-input.md

Co-authored-by: Erick <erickzanardoo@gmail.com>

* rename test

* Apply suggestions from code review

Co-authored-by: Luan Nico <luanpotter27@gmail.com>

* fix test

* Update tutorials/2_sprite_animations_gestures/README.md

Co-authored-by: Luan Nico <luanpotter27@gmail.com>

* docs

* Apply suggestions from code review

Co-authored-by: Jochum van der Ploeg <jochum@vdploeg.net>

* yo

Co-authored-by: Erick <erickzanardoo@gmail.com>
Co-authored-by: Luan Nico <luanpotter27@gmail.com>
Co-authored-by: Jochum van der Ploeg <jochum@vdploeg.net>
2021-08-31 19:38:21 -03:00

4.1 KiB

Keyboard Input

This includes documentation for keyboard inputs.

For other input documents, see also:

Intro

The keyboard API on flame relies on the Flutter's Focus widget.

To customize focus behavior, see Controlling focus.

There are two ways a game can be sensitive to key strokes; at the game level and at a component level. For each we have a mixin that can me added to Games and BaseComponents, respectively.

Receive keyboard events in a game level

To make a Game sub class sensitive to key stroke, mix it with KeyboardEvents.

After that, it will be possible to override an onKeyEvent method.

This method receives two parameters, first the RawKeyEvent that triggered the callback in the first place. The second is a set of the currently pressed LogicalKeyboardKey.

The return value should be a KeyEventResult.

KeyEventResult.handled will tell the framework that the key stroke was resolved inside of Flame and skip any other keyboard handler widgets apart of GameWidget.

KeyEventResult.ignored will tell the framework to keep testing this event in any other keyboard handler widget apart of GameWidget. If the event is not resolved by any handler, the framework will trigger SystemSoundType.alert.

KeyEventResult.skipRemainingHandlers is very similar to .ignored, apart from the fact that will skip any other handler widget and will straight up play the alert sound.

Minimal example:

class MyGame extends Game with KeyboardEvents {
  // ...
  @override
  KeyEventResult onKeyEvent(
    RawKeyEvent event,
    Set<LogicalKeyboardKey> keysPressed,
  ) {
    final isKeyDown = event is RawKeyDownEvent;
    
    final isSpace = event == LogicalKeyboardKey.space;

    if (isSpace && isKeyDown) {
      if (keysPressed.contains(LogicalKeyboardKey.altLeft) ||
          keysPressed.contains(LogicalKeyboardKey.altRight)) {
        this.shootHarder();
      } else {
        this.shoot();
      }
      return KeyEventResult.handled;
    }
    return KeyEventResult.ignored;
  }
}

Receive keyboard events in a component level

To receive keyboard events directly in components, there is the mixin KeyboardHandler.

Similarly to Tappable and Draggable, KeyboardHandler can be mixed into any BaseComponent subclass.

KeyboardHandlers must only be added to games that are mixed with HasKeyboardHandlerComponents.

⚠️ Attention: If HasKeyboardHandlerComponents is used, you must remove KeyboardEvents from the game mixin list to avoid conflicts.

After applying HasKeyboardHandlerComponents, it will be possible to override an onKeyEvent method.

This method receives two parameters. First the RawKeyEvent that triggered the callback in the first place. The second is a set of the currently pressed LogicalKeyboardKeys.

The returned value should be true to allow the continuous propagation of the key event among other components. To not allow any other component to receive the event, return false.

Controlling focus

On the widget level, it is possible to use the FocusNode API to control whether the game is focused or not.

GameWidget has an optional focusNode parameter that allow its focus to be controlled externally.

By default GameWidget has its autofocus set to true, which means it will get focused once it is mounted. To override that behavior, set autofocus to false.

For a more complete example see here.