mirror of
				https://github.com/flame-engine/flame.git
				synced 2025-11-04 13:08:09 +08:00 
			
		
		
		
	This PR fixes #3052 and updates deprecated type references in docs from `RawKeyEvent` to `KeyEvent`. Co-authored-by: Lukas Klingsbo <me@lukas.fyi>
		
			
				
	
	
		
			256 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			256 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
import 'package:flame/components.dart';
 | 
						|
import 'package:flame/events.dart';
 | 
						|
import 'package:flame/game.dart';
 | 
						|
import 'package:flame/text.dart';
 | 
						|
import 'package:flutter/rendering.dart';
 | 
						|
import 'package:flutter/services.dart';
 | 
						|
 | 
						|
class HardwareKeyboardExample extends FlameGame {
 | 
						|
  static const String description = '''
 | 
						|
    This example uses the HardwareKeyboardDetector mixin in order to keep
 | 
						|
    track of which keys on a keyboard are currently pressed.
 | 
						|
 | 
						|
    Tap as many keys on the keyboard at once as you want, and see whether the
 | 
						|
    system can detect them or not.
 | 
						|
  ''';
 | 
						|
 | 
						|
  /// The list of [KeyboardKey] components currently shown on the screen. This
 | 
						|
  /// list is re-generated on every KeyEvent. These components are also
 | 
						|
  /// attached as children.
 | 
						|
  List<KeyboardKey> _keyComponents = [];
 | 
						|
 | 
						|
  void replaceKeyComponents(List<KeyboardKey> newComponents) {
 | 
						|
    for (final key in _keyComponents) {
 | 
						|
      key.visible = false;
 | 
						|
      key.removeFromParent();
 | 
						|
    }
 | 
						|
    _keyComponents = newComponents;
 | 
						|
    addAll(_keyComponents);
 | 
						|
  }
 | 
						|
 | 
						|
  @override
 | 
						|
  void onLoad() {
 | 
						|
    add(MyKeyboardDetector());
 | 
						|
    add(
 | 
						|
      TextComponent(
 | 
						|
        text: 'Press any key(s)',
 | 
						|
        textRenderer: TextPaint(
 | 
						|
          style: const TextStyle(
 | 
						|
            fontSize: 12,
 | 
						|
            color: Color(0x77ffffff),
 | 
						|
          ),
 | 
						|
        ),
 | 
						|
      )..position = Vector2(80, 60),
 | 
						|
    );
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
class MyKeyboardDetector extends HardwareKeyboardDetector
 | 
						|
    with HasGameReference<HardwareKeyboardExample> {
 | 
						|
  @override
 | 
						|
  void onKeyEvent(KeyEvent event) {
 | 
						|
    final newComponents = <KeyboardKey>[];
 | 
						|
    var x0 = 80.0;
 | 
						|
    const y0 = 100.0;
 | 
						|
    for (final key in physicalKeysPressed) {
 | 
						|
      final keyComponent = KeyboardKey(
 | 
						|
        text: keyNames[key] ?? '[${key.usbHidUsage} ${key.debugName}]',
 | 
						|
        position: Vector2(x0, y0),
 | 
						|
      );
 | 
						|
      newComponents.add(keyComponent);
 | 
						|
      x0 += keyComponent.width + 10;
 | 
						|
    }
 | 
						|
    game.replaceKeyComponents(newComponents);
 | 
						|
  }
 | 
						|
 | 
						|
  /// The names of keyboard keys (at least the most important ones). We can't
 | 
						|
  /// rely on `key.debugName` because this property is not available in release
 | 
						|
  /// builds.
 | 
						|
  static final Map<PhysicalKeyboardKey, String> keyNames = {
 | 
						|
    PhysicalKeyboardKey.hyper: 'Hyper',
 | 
						|
    PhysicalKeyboardKey.superKey: 'Super',
 | 
						|
    PhysicalKeyboardKey.fn: 'Fn',
 | 
						|
    PhysicalKeyboardKey.fnLock: 'FnLock',
 | 
						|
    PhysicalKeyboardKey.gameButton1: 'Game 1',
 | 
						|
    PhysicalKeyboardKey.gameButton2: 'Game 2 ',
 | 
						|
    PhysicalKeyboardKey.gameButton3: 'Game 3',
 | 
						|
    PhysicalKeyboardKey.gameButton4: 'Game 4',
 | 
						|
    PhysicalKeyboardKey.gameButton5: 'Game 5',
 | 
						|
    PhysicalKeyboardKey.gameButton6: 'Game 6',
 | 
						|
    PhysicalKeyboardKey.gameButton7: 'Game 7',
 | 
						|
    PhysicalKeyboardKey.gameButton8: 'Game 8',
 | 
						|
    PhysicalKeyboardKey.gameButtonA: 'Game A',
 | 
						|
    PhysicalKeyboardKey.gameButtonB: 'Game B',
 | 
						|
    PhysicalKeyboardKey.gameButtonC: 'Game C',
 | 
						|
    PhysicalKeyboardKey.gameButtonLeft1: 'Game L1',
 | 
						|
    PhysicalKeyboardKey.gameButtonLeft2: 'Game L2',
 | 
						|
    PhysicalKeyboardKey.gameButtonMode: 'Game Mode',
 | 
						|
    PhysicalKeyboardKey.gameButtonRight1: 'Game R1',
 | 
						|
    PhysicalKeyboardKey.gameButtonRight2: 'Game R2',
 | 
						|
    PhysicalKeyboardKey.gameButtonSelect: 'Game Select',
 | 
						|
    PhysicalKeyboardKey.gameButtonStart: 'Game Start',
 | 
						|
    PhysicalKeyboardKey.gameButtonThumbLeft: 'Game LThumb',
 | 
						|
    PhysicalKeyboardKey.gameButtonThumbRight: 'Game RThumb',
 | 
						|
    PhysicalKeyboardKey.gameButtonX: 'Game X',
 | 
						|
    PhysicalKeyboardKey.gameButtonY: 'Game Y',
 | 
						|
    PhysicalKeyboardKey.gameButtonZ: 'Game Z',
 | 
						|
    PhysicalKeyboardKey.keyA: 'A',
 | 
						|
    PhysicalKeyboardKey.keyB: 'B',
 | 
						|
    PhysicalKeyboardKey.keyC: 'C',
 | 
						|
    PhysicalKeyboardKey.keyD: 'D',
 | 
						|
    PhysicalKeyboardKey.keyE: 'E',
 | 
						|
    PhysicalKeyboardKey.keyF: 'F',
 | 
						|
    PhysicalKeyboardKey.keyG: 'G',
 | 
						|
    PhysicalKeyboardKey.keyH: 'H',
 | 
						|
    PhysicalKeyboardKey.keyI: 'I',
 | 
						|
    PhysicalKeyboardKey.keyJ: 'J',
 | 
						|
    PhysicalKeyboardKey.keyK: 'K',
 | 
						|
    PhysicalKeyboardKey.keyL: 'L',
 | 
						|
    PhysicalKeyboardKey.keyM: 'M',
 | 
						|
    PhysicalKeyboardKey.keyN: 'N',
 | 
						|
    PhysicalKeyboardKey.keyO: 'O',
 | 
						|
    PhysicalKeyboardKey.keyP: 'P',
 | 
						|
    PhysicalKeyboardKey.keyQ: 'Q',
 | 
						|
    PhysicalKeyboardKey.keyR: 'R',
 | 
						|
    PhysicalKeyboardKey.keyS: 'S',
 | 
						|
    PhysicalKeyboardKey.keyT: 'T',
 | 
						|
    PhysicalKeyboardKey.keyU: 'U',
 | 
						|
    PhysicalKeyboardKey.keyV: 'V',
 | 
						|
    PhysicalKeyboardKey.keyW: 'W',
 | 
						|
    PhysicalKeyboardKey.keyX: 'X',
 | 
						|
    PhysicalKeyboardKey.keyY: 'Y',
 | 
						|
    PhysicalKeyboardKey.keyZ: 'Z',
 | 
						|
    PhysicalKeyboardKey.digit1: '1',
 | 
						|
    PhysicalKeyboardKey.digit2: '2',
 | 
						|
    PhysicalKeyboardKey.digit3: '3',
 | 
						|
    PhysicalKeyboardKey.digit4: '4',
 | 
						|
    PhysicalKeyboardKey.digit5: '5',
 | 
						|
    PhysicalKeyboardKey.digit6: '6',
 | 
						|
    PhysicalKeyboardKey.digit7: '7',
 | 
						|
    PhysicalKeyboardKey.digit8: '8',
 | 
						|
    PhysicalKeyboardKey.digit9: '9',
 | 
						|
    PhysicalKeyboardKey.digit0: '0',
 | 
						|
    PhysicalKeyboardKey.enter: 'Enter',
 | 
						|
    PhysicalKeyboardKey.escape: 'Esc',
 | 
						|
    PhysicalKeyboardKey.backspace: 'Backspace',
 | 
						|
    PhysicalKeyboardKey.tab: 'Tab',
 | 
						|
    PhysicalKeyboardKey.space: 'Space',
 | 
						|
    PhysicalKeyboardKey.minus: '-',
 | 
						|
    PhysicalKeyboardKey.equal: '=',
 | 
						|
    PhysicalKeyboardKey.bracketLeft: '[',
 | 
						|
    PhysicalKeyboardKey.bracketRight: ']',
 | 
						|
    PhysicalKeyboardKey.backslash: r'\',
 | 
						|
    PhysicalKeyboardKey.semicolon: ';',
 | 
						|
    PhysicalKeyboardKey.quote: "'",
 | 
						|
    PhysicalKeyboardKey.backquote: '`',
 | 
						|
    PhysicalKeyboardKey.comma: ',',
 | 
						|
    PhysicalKeyboardKey.period: '.',
 | 
						|
    PhysicalKeyboardKey.slash: '/',
 | 
						|
    PhysicalKeyboardKey.capsLock: 'CapsLock',
 | 
						|
    PhysicalKeyboardKey.f1: 'F1',
 | 
						|
    PhysicalKeyboardKey.f2: 'F2',
 | 
						|
    PhysicalKeyboardKey.f3: 'F3',
 | 
						|
    PhysicalKeyboardKey.f4: 'F4',
 | 
						|
    PhysicalKeyboardKey.f5: 'F5',
 | 
						|
    PhysicalKeyboardKey.f6: 'F6',
 | 
						|
    PhysicalKeyboardKey.f7: 'F7',
 | 
						|
    PhysicalKeyboardKey.f8: 'F8',
 | 
						|
    PhysicalKeyboardKey.f9: 'F9',
 | 
						|
    PhysicalKeyboardKey.f10: 'F10',
 | 
						|
    PhysicalKeyboardKey.f11: 'F11',
 | 
						|
    PhysicalKeyboardKey.f12: 'F12',
 | 
						|
    PhysicalKeyboardKey.f13: 'F13',
 | 
						|
    PhysicalKeyboardKey.f14: 'F14',
 | 
						|
    PhysicalKeyboardKey.f15: 'F15',
 | 
						|
    PhysicalKeyboardKey.f16: 'F16',
 | 
						|
    PhysicalKeyboardKey.printScreen: 'PrintScreen',
 | 
						|
    PhysicalKeyboardKey.scrollLock: 'ScrollLock',
 | 
						|
    PhysicalKeyboardKey.pause: 'Pause',
 | 
						|
    PhysicalKeyboardKey.insert: 'Insert',
 | 
						|
    PhysicalKeyboardKey.home: 'Home',
 | 
						|
    PhysicalKeyboardKey.pageUp: 'PageUp',
 | 
						|
    PhysicalKeyboardKey.delete: 'Delete',
 | 
						|
    PhysicalKeyboardKey.end: 'End',
 | 
						|
    PhysicalKeyboardKey.pageDown: 'PageDown',
 | 
						|
    PhysicalKeyboardKey.arrowRight: 'ArrowRight',
 | 
						|
    PhysicalKeyboardKey.arrowLeft: 'ArrowLeft',
 | 
						|
    PhysicalKeyboardKey.arrowDown: 'ArrowDown',
 | 
						|
    PhysicalKeyboardKey.arrowUp: 'ArrowUp',
 | 
						|
    PhysicalKeyboardKey.numLock: 'NumLock',
 | 
						|
    PhysicalKeyboardKey.numpadDivide: 'Num /',
 | 
						|
    PhysicalKeyboardKey.numpadMultiply: 'Num *',
 | 
						|
    PhysicalKeyboardKey.numpadSubtract: 'Num -',
 | 
						|
    PhysicalKeyboardKey.numpadAdd: 'Num +',
 | 
						|
    PhysicalKeyboardKey.numpadEnter: 'Num Enter',
 | 
						|
    PhysicalKeyboardKey.numpad1: 'Num 1',
 | 
						|
    PhysicalKeyboardKey.numpad2: 'Num 2',
 | 
						|
    PhysicalKeyboardKey.numpad3: 'Num 3',
 | 
						|
    PhysicalKeyboardKey.numpad4: 'Num 4',
 | 
						|
    PhysicalKeyboardKey.numpad5: 'Num 5',
 | 
						|
    PhysicalKeyboardKey.numpad6: 'Num 6',
 | 
						|
    PhysicalKeyboardKey.numpad7: 'Num 7',
 | 
						|
    PhysicalKeyboardKey.numpad8: 'Num 8',
 | 
						|
    PhysicalKeyboardKey.numpad9: 'Num 9',
 | 
						|
    PhysicalKeyboardKey.numpad0: 'Num 0',
 | 
						|
    PhysicalKeyboardKey.numpadDecimal: 'Num .',
 | 
						|
    PhysicalKeyboardKey.contextMenu: 'ContextMenu',
 | 
						|
    PhysicalKeyboardKey.controlLeft: 'LControl',
 | 
						|
    PhysicalKeyboardKey.shiftLeft: 'LShift',
 | 
						|
    PhysicalKeyboardKey.altLeft: 'LAlt',
 | 
						|
    PhysicalKeyboardKey.metaLeft: 'LMeta',
 | 
						|
    PhysicalKeyboardKey.controlRight: 'RControl',
 | 
						|
    PhysicalKeyboardKey.shiftRight: 'RShift',
 | 
						|
    PhysicalKeyboardKey.altRight: 'RAlt',
 | 
						|
    PhysicalKeyboardKey.metaRight: 'RMeta',
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
class KeyboardKey extends PositionComponent {
 | 
						|
  KeyboardKey({required this.text, super.position}) {
 | 
						|
    textElement = textRenderer.format(text);
 | 
						|
    width = textElement.metrics.width + padding.x;
 | 
						|
    height = textElement.metrics.height + padding.y;
 | 
						|
    textElement.translate(
 | 
						|
      padding.x / 2,
 | 
						|
      padding.y / 2 + textElement.metrics.ascent,
 | 
						|
    );
 | 
						|
    rect = RRect.fromLTRBR(0, 0, width, height, const Radius.circular(8));
 | 
						|
  }
 | 
						|
 | 
						|
  final String text;
 | 
						|
  late final InlineTextElement textElement;
 | 
						|
  late final RRect rect;
 | 
						|
 | 
						|
  /// The KeyEvents may occur very fast, and out of sync with the game loop.
 | 
						|
  /// On each such event we remove old KeyboardKey components, and add new ones.
 | 
						|
  /// However, since multiple KeyEvents may occur within a single game tick,
 | 
						|
  /// we end up adding/removing components many times within that tick, and for
 | 
						|
  /// a brief moment there could be a situation that the old components still
 | 
						|
  /// haven't been removed while the new ones were already added. In order to
 | 
						|
  /// prevent this from happening, we mark all components that are about to be
 | 
						|
  /// removed as "not visible", which prevents them from being rendered while
 | 
						|
  /// they are waiting to be removed.
 | 
						|
  bool visible = true;
 | 
						|
 | 
						|
  static final Vector2 padding = Vector2(24, 12);
 | 
						|
  static final Paint borderPaint = Paint()
 | 
						|
    ..style = PaintingStyle.stroke
 | 
						|
    ..strokeWidth = 3
 | 
						|
    ..color = const Color(0xffb5ffd0);
 | 
						|
  static final TextPaint textRenderer = TextPaint(
 | 
						|
    style: const TextStyle(
 | 
						|
      fontSize: 20,
 | 
						|
      fontWeight: FontWeight.bold,
 | 
						|
      color: Color(0xffb5ffd0),
 | 
						|
    ),
 | 
						|
  );
 | 
						|
 | 
						|
  @override
 | 
						|
  void render(Canvas canvas) {
 | 
						|
    if (visible) {
 | 
						|
      canvas.drawRRect(rect, borderPaint);
 | 
						|
      textElement.draw(canvas);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |