Skip to content

Game.Input.DeviceListener

Assembly: Assembly-CSharp
Namespace: Game.Input

Type: public class

Base: IInputStateChangeMonitor, IDisposable

Summary:
DeviceListener watches a specific Unity InputSystem InputDevice for button presses and raises a UnityEvent when the device is activated. It registers itself as an InputState change monitor on the device's valid controls (currently only ButtonControl), buffers activation state, and exposes a UnityEvent (DeviceEvent) that clients can subscribe to. The listener must be polled via Tick() (typically each frame) to forward activations to subscribers. Implements IDisposable to ensure it stops listening and removes change monitors when disposed.


Fields

  • private List<InputControl> m_Controls
    Holds the filtered list of controls from the target device that the listener monitors. Only controls that pass ValidateControl (button controls) are added.

  • private bool m_Listening
    Tracks whether the listener is currently registered with the InputState change system.

  • private float m_RequiredDelta
    A threshold value supplied in the constructor. In the provided implementation this field is stored but not used — likely intended for future use to require a minimum change magnitude before activation.

  • private float m_Delta
    Internal timer/delta used by Tick() to decay over time. Its current behavior is a simple timed decay; specific uses beyond that are not present in this class.

  • private bool m_Activated
    Set when a monitored control is detected as pressed in NotifyControlStateChanged. Tick() consumes this flag and triggers the event.

  • public DeviceEvent EventDeviceActivated
    UnityEvent instance used for subscribers to be notified when the device is activated.

  • (Nested Type) public class DeviceEvent : UnityEvent<InputDevice>
    A UnityEvent specialization that carries the activated InputDevice to listeners.

Properties

  • public InputDevice device { get; private set; }
    The InputDevice instance this listener monitors. The setter is private; the device is provided at construction.

Constructors

  • public DeviceListener(InputDevice device, float requiredDelta)
    Creates a DeviceListener for the given device. It:
  • Initializes the EventDeviceActivated UnityEvent.
  • Stores the device and requiredDelta.
  • Builds the m_Controls list by iterating device.allControls and adding controls that ValidateControl accepts (currently ButtonControl instances).

Methods

  • public void Tick()
    Should be called regularly (e.g., once per frame). It decays m_Delta over Time.deltaTime and, if m_Activated was set by the change monitor, resets m_Activated and invokes EventDeviceActivated with the monitored device. This decouples InputSystem notifications from when subscribers are notified (ensures invocation happens on the Tick caller's context).

  • public void StartListening()
    Begin monitoring the device's filtered controls. If already listening, this is a no-op. Resets activation state and m_Delta and registers this instance as a change monitor for each control via InputState.AddChangeMonitor(control, this, -1L).

  • public void StopListening()
    Stops monitoring. If not listening, this is a no-op. Clears activation state and m_Delta and removes the change monitors via InputState.RemoveChangeMonitor(control, this, -1L).

  • private bool ValidateControl(InputControl control)
    Determines whether a control should be monitored. Current implementation returns true only for ButtonControl (so only button-type controls are tracked).

  • public void NotifyControlStateChanged(InputControl control, double time, InputEventPtr eventPtr, long monitorIndex)
    IInputStateChangeMonitor callback invoked by the Input System when the control state changes. If the control is a ButtonControl and wasPressedThisFrame is true, sets m_Activated = true. Actual event invocation is deferred until Tick().

  • public void NotifyTimerExpired(InputControl control, double time, long monitorIndex, int timerIndex)
    IInputStateChangeMonitor callback for timer expiration. Currently empty (no behavior implemented).

  • public void Dispose()
    Implements IDisposable. Calls StopListening() to remove change monitors and clear state.

Notes and caveats: - m_RequiredDelta is stored but unused in the current implementation — if your mod expects threshold filtering, you'll need to extend the class to make use of it. - NotifyControlStateChanged uses wasPressedThisFrame which requires the Unity Input System to be properly updated and may rely on being called on the main thread / during normal input processing. - Tick() must be called by client code (for example, from a MonoBehaviour.Update) so that EventDeviceActivated gets invoked on the main thread and subscribers are notified.

Usage Example

// Example MonoBehaviour that uses DeviceListener to watch an InputDevice
using UnityEngine;
using UnityEngine.InputSystem;
using Game.Input;

public class DeviceWatcher : MonoBehaviour
{
    private DeviceListener _listener;

    void Start()
    {
        // Example: pick the first Gamepad if available
        InputDevice device = Gamepad.current;
        if (device == null)
        {
            Debug.LogWarning("No gamepad found.");
            return;
        }

        _listener = new DeviceListener(device, 0.1f);
        _listener.EventDeviceActivated.AddListener(OnDeviceActivated);
        _listener.StartListening();
    }

    void Update()
    {
        // Must call Tick every frame so the listener can invoke the UnityEvent on the main thread
        _listener?.Tick();
    }

    private void OnDeviceActivated(InputDevice device)
    {
        Debug.Log($"Device activated: {device.displayName}");
        // Handle activation (e.g., assign device, show UI, etc.)
    }

    void OnDestroy()
    {
        // Clean up and remove monitors
        if (_listener != null)
        {
            _listener.EventDeviceActivated.RemoveListener(OnDeviceActivated);
            _listener.Dispose();
            _listener = null;
        }
    }
}

{{ Additional notes: This class is a thin adapter between the Unity Input System's low-level change monitors and UnityEvent-based callbacks. If you need to monitor axes or analog controls, extend ValidateControl and NotifyControlStateChanged logic accordingly. If using multiple DeviceListener instances, ensure proper StartListening/StopListening lifecycle management to avoid leftover monitors. }}