diff --git a/packages/gamepads/example/lib/main.dart b/packages/gamepads/example/lib/main.dart index 519fd1d..3f9f6fb 100644 --- a/packages/gamepads/example/lib/main.dart +++ b/packages/gamepads/example/lib/main.dart @@ -96,8 +96,13 @@ class _MyHomePageState extends State { const Text('Gamepads:'), if (loading) const CircularProgressIndicator() - else - ..._gamepads.map((e) => Text('${e.id} - ${e.name}')), + else ...[ + for (final gamepad in _gamepads) ...[ + Text('${gamepad.id} - ${gamepad.name}'), + Text(' Analog inputs: ${gamepad.state.analogInputs}'), + Text(' Button inputs: ${gamepad.state.buttonInputs}'), + ], + ], ], ), ), diff --git a/packages/gamepads_platform_interface/lib/api/gamepad_controller.dart b/packages/gamepads_platform_interface/lib/api/gamepad_controller.dart index d1ea9d4..9557b4b 100644 --- a/packages/gamepads_platform_interface/lib/api/gamepad_controller.dart +++ b/packages/gamepads_platform_interface/lib/api/gamepad_controller.dart @@ -1,4 +1,14 @@ +import 'dart:async'; + +import 'package:gamepads_platform_interface/api/gamepad_event.dart'; +import 'package:gamepads_platform_interface/api/gamepad_state.dart'; +import 'package:gamepads_platform_interface/gamepads_platform_interface.dart'; + /// Represents a single, currently connected joystick controller (or gamepad). +/// +/// By calling the constructor, this object will automatically subscribe to +/// events and update its internal [state]. To stop listening, be sure to call +/// [dispose]. Failing to do so may result in the object leaking memory. class GamepadController { /// A unique identifier for the gamepad controller. /// @@ -9,14 +19,30 @@ class GamepadController { /// A user-facing, platform-dependant name for the gamepad controller. final String name; + final state = GamepadState(); + + StreamSubscription? _subscription; + GamepadController({ required this.id, required this.name, - }); + required GamepadsPlatformInterface plugin, + }) { + _subscription = plugin.eventsByGamepad(id).listen(state.update); + } - factory GamepadController.parse(Map map) { + factory GamepadController.parse( + Map map, + GamepadsPlatformInterface plugin, + ) { final id = map['id'] as String; final name = map['name'] as String; - return GamepadController(id: id, name: name); + return GamepadController(id: id, name: name, plugin: plugin); + } + + /// Stops listening for new inputs. + Future dispose() async { + await _subscription?.cancel(); + _subscription = null; } } diff --git a/packages/gamepads_platform_interface/lib/api/gamepad_state.dart b/packages/gamepads_platform_interface/lib/api/gamepad_state.dart new file mode 100644 index 0000000..e80f469 --- /dev/null +++ b/packages/gamepads_platform_interface/lib/api/gamepad_state.dart @@ -0,0 +1,27 @@ +import 'package:gamepads_platform_interface/api/gamepad_event.dart'; + +/// The current state of a gamepad. +/// +/// This class keeps mutable state and is intended to be kept up-to-date by +/// calling [update] with the latest [GamepadEvent]. The [analogInputs] and +/// [buttonInputs] maps correspond to [KeyType.analog] and [KeyType.button], +/// respectively. +class GamepadState { + /// Contains inputs from events where [GamepadEvent.type] is [KeyType.analog]. + final Map analogInputs = {}; + + /// Contains inputs from events where [GamepadEvent.type] is [KeyType.button]. + final Map buttonInputs = {}; + + /// Updates the state based on the given event. + void update(GamepadEvent event) { + switch (event.type) { + case KeyType.analog: + analogInputs[event.key] = event.value; + break; + case KeyType.button: + buttonInputs[event.key] = event.value == 1; + break; + } + } +} diff --git a/packages/gamepads_platform_interface/lib/gamepads_platform_interface.dart b/packages/gamepads_platform_interface/lib/gamepads_platform_interface.dart index 4824eb4..6a47f65 100644 --- a/packages/gamepads_platform_interface/lib/gamepads_platform_interface.dart +++ b/packages/gamepads_platform_interface/lib/gamepads_platform_interface.dart @@ -20,4 +20,7 @@ abstract class GamepadsPlatformInterface extends PlatformInterface { Future> listGamepads(); Stream get gamepadEventsStream; + + Stream eventsByGamepad(String gamepadId) => + gamepadEventsStream.where((event) => event.gamepadId == gamepadId); } diff --git a/packages/gamepads_platform_interface/lib/method_channel_gamepads_platform_interface.dart b/packages/gamepads_platform_interface/lib/method_channel_gamepads_platform_interface.dart index d7bc11c..41afd92 100644 --- a/packages/gamepads_platform_interface/lib/method_channel_gamepads_platform_interface.dart +++ b/packages/gamepads_platform_interface/lib/method_channel_gamepads_platform_interface.dart @@ -21,7 +21,7 @@ class MethodChannelGamepadsPlatformInterface extends GamepadsPlatformInterface { {}, ); return result!.map((Object? e) { - return GamepadController.parse(e! as Map); + return GamepadController.parse(e! as Map, this); }).toList(); }