mirror of
				https://github.com/flame-engine/flame.git
				synced 2025-10-31 08:56:01 +08:00 
			
		
		
		
	 12841d6471
			
		
	
	12841d6471
	
	
	
		
			
			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);
 | |
|     }
 | |
|   }
 | |
| }
 |