feat: Add connect and disconnect event streams - #132
Open
spydon wants to merge 2 commits into
Open
Conversation
Closes #131 Every platform already detected gamepads being plugged in and unplugged, but kept it internal. Surface it as `Gamepads.connectionEvents`, with `Gamepads.onConnected` and `Gamepads.onDisconnected` as filtered views. Events carry a `GamepadConnectionEvent` with the `gamepadId`, the user-facing `name` and a `GamepadConnectionType`, instead of a `GamepadController`, which is a resource that subscribes on construction and has to be disposed. The event stream plumbing was duplicated between the method channel and web implementations, so it moved into `GamepadsPlatformInterface` alongside the new connection stream. Two pre-existing bugs got in the way and are fixed here: - On Linux, `gamepads[key]` default-inserts an entry, so the disconnect branch always thought it knew the device; it now uses `find`. - On macOS, the disconnect handler dropped the gamepad without knowing its index, which is the id reported to Dart.
- macOS reported the disconnect id by looking the gamepad up in the array at disconnect time, which shifts as earlier gamepads are removed, so it could differ from the id the gamepad's own input events carried. The id assigned at connect is now remembered and replayed. - macOS derived the disconnect name from the gamepad's `GCDevice`, which is usually torn down by then, yielding "Unknown device". The name is now cached at connect. - Windows copied the gamepad name after setting `stop_thread`, so the reader thread could exit and free the gamepad first. The name is now copied before the flag is set. - iOS read `vendorName` at disconnect time, where it can be nil, dropping the event for a controller whose connection had been reported. The name is now cached when the controller is set up. - Android registered a new `DeviceListener` on every reattach without ever unregistering the previous one, so after a configuration change each connection was reported once per registration. It now registers once.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #131
Every platform already detected gamepads being plugged in and unplugged, but kept it internal. This surfaces it to Dart.
API
The issue suggested
Stream<GamepadController>. Events carry aGamepadConnectionEventwithgamepadId,nameand aGamepadConnectionTypeinstead, because aGamepadControlleris a resource that subscribes on construction and must be disposed, so emitting one per event, especially per disconnect, would either leak subscriptions or hand back an already-dead object. The event mirrorsGamepadEvent, and itsgamepadIdmatches the id fromlist()and from input events.Platform interface
The event
StreamControllerplumbing was duplicated inMethodChannelGamepadsPlatformInterfaceandGamepadsWeb. Both streams now live inGamepadsPlatformInterfacewithemitGamepadEvent/emitGamepadConnectionEventand adisposethat closes both.gamepadEventsStreamwent from abstract to concrete, which is backwards compatible for anyone overriding it.Natives
All five send a new
onGamepadConnectionEventmethod call from hooks they already had:// Optional: send disconnection eventTODO is now done.GamepadsListenergained aconnectionListener.joystickDidDisconnectnow captures the index before removing, since that index is the id reported to Dart.DeviceListenergotadd/removehelpers that emit only on real transitions, soonInputDeviceChangeddoes not double-report. Removal reads the name from the cache, sinceInputDevice.getDevicereturns null once the device is gone.gamepads[key], which default-inserts, soif (existingGamepad)was always true; switched tofindso disconnects only fire for tracked devices and carry the real name.connection_emitteralongsideevent_emitter. The name is copied before the read thread frees theGamepadData.Verification
flutter analyzeclean, all 85 tests pass, including three new ones coveringconnectionEvents,onConnectedandonDisconnectedfiltering. Web and Android compile against these sources (flutter build webandflutter build apk --debugin a scratch app with path overrides).The Swift files parse (
swiftc -parse) but were not type-checked or built, since Xcode is not fully installed on the machine this was written on, and the Linux and Windows C++ could not be compiled from macOS. Those five native files are reviewed but unbuilt and want a CI or local check.Also updates the README with a connection-events section, and the example app to log connects/disconnects and refresh its list from them.