import { Dualsense } from "./dualsense"; import { Input, InputParams } from "./input"; /** The state exposed by a DualsenseManager via the Input system */ export interface DualsenseManagerState { /** Number of currently connected controllers */ active: number; /** All managed controllers, keyed by slot index (player number) */ players: ReadonlyMap; } /** Settings for the DualsenseManager */ export interface DualsenseManagerParams extends InputParams { /** Polling interval (ms) for discovering new devices in Node.js. Default: 2000 */ discoveryInterval?: number; /** Whether to automatically assign player LED patterns. Default: true */ autoAssignPlayerLeds?: boolean; } /** * Manages multiple Dualsense controllers. Automatically discovers devices, * assigns player LEDs, and provides indexed access to each controller. * * Extends Input so that events from all managed controllers bubble up: * - `change` fires when the controller count changes or any controller input changes * - `press` / `release` bubble from any managed controller (including connection state) */ export declare class DualsenseManager extends Input { /** Current manager state: active count and player map */ state: DualsenseManagerState; /** Whether to auto-assign player LED patterns on connection */ autoAssignPlayerLeds: boolean; /** Player LED bitmask patterns indexed by slot number (0–30) */ private readonly playerPatterns; /** All controller slots, indexed by slot number */ private readonly slots; /** Map from node-hid serial to slot index — best-effort, used as a fallback */ private readonly serialToSlot; /** Map from canonical hardware identity to slot index — preferred when available */ private readonly identityToSlot; /** Discovery polling timer (Node.js only) */ private discoveryTimer?; /** Whether we're running in a browser environment */ private readonly isBrowser; constructor(params?: DualsenseManagerParams); get active(): boolean; /** * All managed controller instances (including disconnected ones awaiting * reconnection). Excludes provisional slots whose identity is still being * resolved — those become visible only after firmware info loads, to * avoid surfacing controllers that may be merged into an existing slot. */ get controllers(): readonly Dualsense[]; /** Number of managed controllers (including disconnected ones awaiting reconnection) */ get count(): number; /** Get a controller by slot index */ get(index: number): Dualsense | undefined; /** Iterate over all managed controllers */ [Symbol.iterator](): IterableIterator; /** Slots that are visible to the consumer (i.e. identity has been resolved) */ private publicSlots; /** * True while at least one controller has been discovered but is still * waiting for firmware info to load. Useful for showing a "connecting" * state in the UI without surfacing the unresolved slot itself. */ get pending(): boolean; /** * Override the player LED pattern for a given slot index. * @param index Slot index (0-based) * @param bitmask 5-bit LED bitmask (0x00–0x1f) */ setPlayerPattern(index: number, bitmask: number): void; /** Get the player LED pattern for a given slot index */ getPlayerPattern(index: number): number; /** * Release a controller slot, freeing it for reuse. * If the controller is still connected, it will be disconnected. * @param index Slot index to release */ release(index: number): void; /** * Release all disconnected controller slots. * Connected controllers are not affected. */ releaseDisconnected(): void; /** * Stop discovery and disconnect all controllers. */ dispose(): void; /** * For WebHID: returns a click handler that opens the device picker, * allowing the user to select multiple controllers at once. */ getRequest(): () => Promise; /** Previous state snapshot, for deduplication */ private lastActive; private lastPlayerCount; /** Fingerprint of the last published player set (slot indices + connected flags) */ private lastPlayerKey; /** Build a new state snapshot and push it through InputSet */ private updateState; /** * Create a Dualsense instance and register it in a (provisional) slot. * The caller is responsible for opening the device on the provider — the * manager treats this as the *only* path that opens new devices, so * identity matching can run before the slot becomes visible. * * Note: identity is the sole reconnection key. We do NOT key on node-hid's * serialNumber because it can be missing or wrong. Path is tracked only * so we can re-target the same device on transplant. */ private createSlot; /** * Called when a slot's HID layer has finished reading firmware/factory info. * If the resolved identity matches a *different* (disconnected) slot, the * underlying device is transplanted into that slot's existing provider so * the consumer's Dualsense reference is preserved across reconnect. */ private handleSlotReady; /** Mark a slot as visible to consumers and publish state */ private promoteSlot; /** * Move the device handle from `from` into `into`'s existing provider so * the existing Dualsense instance reconnects in place. Then remove `from`. */ private transplant; /** Remove a slot without firing the player-LED reshuffle */ private dropSlot; private startNodeDiscovery; /** * Handle a newly discovered device from enumeration. Opens the device on * a fresh provider, which adds it to `claimedDevices` so subsequent polls * skip it. Identity matching (and any merge into a disconnected slot) * happens later, once firmware info has been read. */ private processDiscoveredDevice; private startWebDiscovery; /** HIDDevice objects we've already handed to a provider */ private readonly knownWebDevices; private addWebDevice; } //# sourceMappingURL=manager.d.ts.map