-
-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Support for Web #48
base: main
Are you sure you want to change the base?
Changes from all commits
d508623
f1ee9e5
c50fc2c
f738725
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Miscellaneous | ||
*.class | ||
*.log | ||
*.pyc | ||
*.swp | ||
.DS_Store | ||
.atom/ | ||
.buildlog/ | ||
.history | ||
.svn/ | ||
migrate_working_dir/ | ||
|
||
# IntelliJ related | ||
*.iml | ||
*.ipr | ||
*.iws | ||
.idea/ | ||
|
||
# The .vscode folder contains launch configuration and tasks you configure in | ||
# VS Code which you may wish to be included in version control, so this line | ||
# is commented out by default. | ||
#.vscode/ | ||
|
||
# Flutter/Dart/Pub related | ||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. | ||
/pubspec.lock | ||
**/doc/api/ | ||
.dart_tool/ | ||
build/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../LICENSE |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../README.md |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include: package:flame_lint/analysis_options.yaml |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import 'dart:js_interop'; | ||
|
||
import 'package:gamepads_platform_interface/api/gamepad_controller.dart'; | ||
import 'package:gamepads_platform_interface/gamepads_platform_interface.dart'; | ||
import 'package:web/web.dart'; | ||
|
||
List<GamepadController> getGamepads(GamepadsPlatformInterface plugin) { | ||
final controllers = <GamepadController>[]; | ||
final gamepads = getGamepadList(); | ||
for (var i = 0; i < gamepads.length; i++) { | ||
final gamepad = gamepads[i]; | ||
controllers.add( | ||
GamepadController( | ||
id: gamepad!.index.toString(), | ||
name: gamepad.id, | ||
plugin: plugin, | ||
), | ||
); | ||
} | ||
return controllers; | ||
} | ||
|
||
List<Gamepad?> getGamepadList() { | ||
final gamepads = window.navigator.getGamepads().toDart; | ||
gamepads.removeWhere((item) => item == null); | ||
return gamepads; | ||
} |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,132 @@ | ||||
import 'dart:async'; | ||||
import 'dart:js_interop'; | ||||
|
||||
import 'package:flutter/foundation.dart'; | ||||
import 'package:flutter_web_plugins/flutter_web_plugins.dart'; | ||||
import 'package:gamepads_platform_interface/api/gamepad_controller.dart'; | ||||
import 'package:gamepads_platform_interface/api/gamepad_event.dart'; | ||||
import 'package:gamepads_platform_interface/gamepads_platform_interface.dart'; | ||||
import 'package:gamepads_web/gamepad_detector.dart'; | ||||
import 'package:web/web.dart' as web; | ||||
|
||||
class _GamePadState { | ||||
_GamePadState(int length) { | ||||
keyStates = List<dynamic>.filled(length, null); | ||||
axesStates = List<double>.filled(4, 0); | ||||
} | ||||
|
||||
List<dynamic>? keyStates; | ||||
List<double>? axesStates; | ||||
} | ||||
|
||||
/// A web implementation of the GamepadsWebPlatform of the GamepadsWeb plugin. | ||||
class GamepadsWeb extends GamepadsPlatformInterface { | ||||
int _gamepadCount = 0; | ||||
Timer? _gamepadPollingTimer; | ||||
|
||||
final Map<String, _GamePadState> _lastGamePadstates = {}; | ||||
|
||||
void updateGamepadsStatus() { | ||||
final gamepads = getGamepadList(); | ||||
for (final gamepad in gamepads) { | ||||
final buttonlist = gamepad!.buttons.toDart; | ||||
final axeslist = gamepad.axes.toDart; | ||||
final gamepadId = gamepad.index.toString(); | ||||
_GamePadState lastState; | ||||
if (_lastGamePadstates.containsKey(gamepadId) && | ||||
_lastGamePadstates[gamepadId]?.keyStates?.length == | ||||
buttonlist.length) { | ||||
lastState = _lastGamePadstates[gamepadId]!; | ||||
} else { | ||||
_lastGamePadstates[gamepadId] = _GamePadState(buttonlist.length); | ||||
lastState = _lastGamePadstates[gamepadId]!; | ||||
} | ||||
for (var i = 0; i < buttonlist.length; i++) { | ||||
if (lastState.keyStates?[i] != buttonlist[i].value) { | ||||
lastState.keyStates?[i] = buttonlist[i].value; | ||||
emitGamepadEvent( | ||||
GamepadEvent( | ||||
gamepadId: gamepadId, | ||||
timestamp: DateTime.now().millisecondsSinceEpoch, | ||||
type: KeyType.button, | ||||
key: 'button $i', | ||||
value: buttonlist[i].value, | ||||
), | ||||
); | ||||
} | ||||
} | ||||
for (var i = 0; i < 4; i++) { | ||||
if ((lastState.axesStates![i] - axeslist[i].toDartDouble).abs() > | ||||
0.03) { | ||||
lastState.axesStates?[i] = axeslist[i].toDartDouble; | ||||
emitGamepadEvent( | ||||
GamepadEvent( | ||||
gamepadId: gamepadId, | ||||
timestamp: DateTime.now().millisecondsSinceEpoch, | ||||
type: KeyType.analog, | ||||
key: 'analog $i', | ||||
value: axeslist[i].toDartDouble, | ||||
), | ||||
); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
|
||||
/// Constructs a GamepadsWeb | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
The dart docs should talk about what it does, docs like "constructor constructs" doesn't give anything, so I think you can just remove this. |
||||
GamepadsWeb() { | ||||
web.window.addEventListener( | ||||
'gamepadconnected', | ||||
(web.Event event) { | ||||
_gamepadCount++; | ||||
if (_gamepadCount == 1) { | ||||
// The game pad state for web is not event driven. We need to | ||||
// query the game pad state by ourself. | ||||
// By default we set the query interval is 1ms. | ||||
_gamepadPollingTimer = | ||||
Timer.periodic(const Duration(milliseconds: 1), (timer) { | ||||
updateGamepadsStatus(); | ||||
}); | ||||
} | ||||
}.toJS, | ||||
); | ||||
|
||||
web.window.addEventListener( | ||||
'gamepaddisconnected', | ||||
(web.Event event) { | ||||
_gamepadCount--; | ||||
if (_gamepadCount == 0) { | ||||
_gamepadPollingTimer?.cancel(); | ||||
} | ||||
}.toJS, | ||||
); | ||||
} | ||||
|
||||
static void registerWith(Registrar registrar) { | ||||
GamepadsPlatformInterface.instance = GamepadsWeb(); | ||||
} | ||||
|
||||
List<GamepadController>? controllers; | ||||
|
||||
@override | ||||
Future<List<GamepadController>> listGamepads() async { | ||||
Check notice on line 112 in packages/gamepads_web/lib/gamepads_web.dart GitHub Actions / analyzeThe method doesn't override an inherited method.
|
||||
controllers = getGamepads(this); | ||||
return controllers!; | ||||
} | ||||
|
||||
void emitGamepadEvent(GamepadEvent event) { | ||||
_gamepadEventsStreamController.add(event); | ||||
} | ||||
|
||||
final StreamController<GamepadEvent> _gamepadEventsStreamController = | ||||
StreamController<GamepadEvent>.broadcast(); | ||||
|
||||
@override | ||||
Stream<GamepadEvent> get gamepadEventsStream => | ||||
Check notice on line 125 in packages/gamepads_web/lib/gamepads_web.dart GitHub Actions / analyzeThe getter doesn't override an inherited getter.
|
||||
_gamepadEventsStreamController.stream; | ||||
|
||||
@mustCallSuper | ||||
Future<void> dispose() async { | ||||
_gamepadEventsStreamController.close(); | ||||
} | ||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
name: gamepads_web | ||
description: Web implementation of gamepads, a Flutter plugin to handle gamepad input across multiple platforms. | ||
version: 0.1.0 | ||
homepage: https://github.com/flame-engine/gamepads | ||
repository: https://github.com/flame-engine/gamepads/tree/main/packages/gamepads_web | ||
|
||
flutter: | ||
plugin: | ||
implements: gamepads | ||
platforms: | ||
web: | ||
pluginClass: GamepadsWeb | ||
fileName: gamepads_web.dart | ||
|
||
environment: | ||
sdk: '>=2.19.0 <3.0.0' | ||
flutter: ">=3.3.0" | ||
|
||
dependencies: | ||
flutter: | ||
sdk: flutter | ||
flutter_web_plugins: | ||
sdk: flutter | ||
gamepads_platform_interface: ^0.1.2+1 | ||
js_interop: ^0.0.1 | ||
plugin_platform_interface: ^2.1.8 | ||
web: ^1.1.0 | ||
|
||
dev_dependencies: | ||
flame_lint: ^0.2.0 | ||
flutter_test: | ||
sdk: flutter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file should live in
src
right? And not be exposed directly to the user, since it's not part of the interface.