logo SERENITY
Game Systems Foundation
Search Results for

    Show / Hide Table of Contents

    Namespace Serenity.Feedback.Infrastructure.Services

    Classes

    ActingDeviceTracker

    Simple holder for the last input device that drove a UI action. Written by the UI input layer (the navigate/submit/cancel callbacks, where the triggering device is known) and read by UnityGamepadTargetResolver when resolving the acting pad. Registered as a single instance in the service locator so both sides share the same value.

    DualSenseOutputWriter

    Drives vibration, the LED AND both adaptive triggers on a DualSense in a SINGLE HID output report, over USB.

    Stock Unity exposes no adaptive-trigger output, and its built-in DualSense vibration/LED reports do not address the trigger region — so any built-in vibration or color update CLOBBERS an active trigger effect (verified on hardware). The DualSense output report is monolithic (one report carries vibration + LED + both triggers), so the only clobber-free option is to own the whole report ourselves. This writer keeps per-device state as the single source of truth and re-emits the full report on every change, exactly like DualShock4OutputWriter does for the DS4.

    Two report formats are emitted: the USB report (id 0x02, 48-byte payload) and the Bluetooth report (id 0x31, 78 bytes, CRC32-suffixed). On Linux both buses are driven through a raw hidraw handle (Unity's Linux backend routes no HID output). On Windows USB uses Unity's ExecuteCommand, while Bluetooth — which Unity's built-in DualSense output does not support — is driven through a raw HID handle that pads the 0x31 report to the OS output-report length (validated on hardware). macOS drives USB only. Methods return false for non-DualSense pads and on unsupported platforms.

    DualShock4OutputWriter

    Drives vibration AND the LED on a DualShock 4 in a SINGLE HID output report.

    Unity's high-level SetMotorSpeeds and SetLightBarColor each send a separate report that zeroes the other's bytes (the package even flags this with ////FIXME: SetLightBarColor and SetMotorSpeeds to not mutually respect their settings), so on a DS4 the two effects clobber each other and the auto-reset of one clips the other. The DS4 hardware itself packs vibration and color into one report — only the wrapper splits them, and the combining struct (DualShockHIDOutputReport) is internal. This writer mirrors that report in our own Serenity.Feedback.Infrastructure.Services.DualShock4CombinedOutputReport and sends both together via the public InputDevice.ExecuteCommand, exactly like native titles do. DualSense already combines internally, so it does not go through here.

    Per-device state is the single source of truth: setting motors preserves the current color and vice-versa, which is what makes the two channels coexist and stops each reset from blanking the other. Methods return false for non-DS4 pads (and on non-desktop platforms) so callers fall back to the standard path.

    Transport: USB uses Unity's ExecuteCommand (the 32-byte 0x05 report); Bluetooth uses the reframed 0x11/CRC32 report sent through a raw HID handle (Serenity.Feedback.Infrastructure.Hid.GamepadHidrawTransport) — on Linux for both buses, and on Windows for Bluetooth only (Unity's built-in DS4 output is inert over Bluetooth). The bus is detected once and cached. macOS drives USB only.

    UnityFeedbackDefinitionProvider

    Unity implementation of IFeedbackDefinitionProvider. Resolves FeedbackDefinition ScriptableObjects by Id or Guid via UnityAssetUtils (Addressables / Resources), then maps them to DTOs.

    UnityFeedbackService

    Unity MonoBehaviour implementation of IFeedbackService and IFeedbackRuntime. Routes each effect of a definition to every channel that can play it, and owns the single global stop/lifecycle safety net (application focus/pause, scene unload, play-mode exit, disable/destroy, and the vibration-disabled setting). Per-effect timing/restoration is owned by each channel via the coroutine host this class exposes through IFeedbackRuntime.

    UnityFeedbackServiceFactory

    Factory that creates the UnityFeedbackService as a DontDestroyOnLoad MonoBehaviour. The component is returned UNINITIALIZED: the installer first constructs the channels (which take the service as their IFeedbackRuntime), then calls Initialize(IGameSettingsService, IFeedbackSettings, IFeedbackDefinitionProvider, List<IFeedbackChannel>, IEventDispatcherService, ILogService).

    UnityGamepadTargetResolver

    Resolves a FeedbackTarget or a PlayerInput object to a Unity UnityEngine.InputSystem.Gamepad. Returns null when a gamepad cannot be resolved; callers are expected to no-op on null.

    Interfaces

    IGamepadOutputBackend

    A per-controller output backend that drives vibration and/or the LED on a specific gamepad family (DualShock 4, DualSense, Switch Pro, ...) through whatever transport that family needs — Unity's HID ExecuteCommand or a raw OS HID handle. The vibration and LED channels iterate the registered backends in order and take the FIRST that claims the pad, falling back to Unity's built-in API when none do.

    This is the controller-extension seam: supporting a new controller means adding a backend and registering it in the installer — no channel changes (open/closed). It is also where a future transport swap lives (e.g. moving a PlayStation pad off Unity's ExecuteCommand onto raw HID): add a backend that uses the other transport and the channels are unaffected.

    Every method returns false for a pad this backend does not handle (wrong family, unsupported connection, or unsupported platform) so the caller falls through to the next backend or the default path.

    In this article
    © 2026 Serenity. All Rights Reserved