182 lines
6.4 KiB
C#
182 lines
6.4 KiB
C#
using System;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
|
|
namespace InputGlyphsFramework
|
|
{
|
|
/// <summary>
|
|
/// Central input service. Holds reference to PlayerInput, loads/saves binding overrides,
|
|
/// exposes simple helpers and broadcasts control-scheme and binding change events.
|
|
/// </summary>
|
|
[DefaultExecutionOrder(-200)]
|
|
public class InputService : MonoBehaviour
|
|
{
|
|
public static InputService Instance { get; private set; }
|
|
|
|
[Header("References")] public PlayerInput playerInput;
|
|
|
|
[Header("Persistence")] public string bindingsPrefsKey = "bindings_v1";
|
|
|
|
// Events
|
|
public event Action<InputAction, int> OnBindingChanged;
|
|
public event Action<string> OnControlSchemeChanged;
|
|
|
|
void Awake()
|
|
{
|
|
if (Instance != null && Instance != this)
|
|
{
|
|
Destroy(this);
|
|
return;
|
|
}
|
|
|
|
Instance = this;
|
|
|
|
if (playerInput == null) playerInput = GetComponent<PlayerInput>();
|
|
|
|
// subscribe to device watcher (user provided)
|
|
try
|
|
{
|
|
InputDeviceWatcher.OnDeviceChanged += DeviceChanged;
|
|
}
|
|
catch
|
|
{
|
|
/* if DeviceInputWatcher not present at compile time ignore */
|
|
}
|
|
|
|
if (playerInput != null)
|
|
playerInput.onControlsChanged += PlayerInput_onControlsChanged;
|
|
|
|
// Load overrides if exist
|
|
LoadOverridesFromPrefs();
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
if (Instance == this) Instance = null;
|
|
try
|
|
{
|
|
InputDeviceWatcher.OnDeviceChanged -= DeviceChanged;
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
if (playerInput != null) playerInput.onControlsChanged -= PlayerInput_onControlsChanged;
|
|
}
|
|
|
|
private void PlayerInput_onControlsChanged(PlayerInput obj)
|
|
{
|
|
OnControlSchemeChanged?.Invoke(obj.currentControlScheme);
|
|
}
|
|
|
|
private void DeviceChanged(InputDeviceWatcher.InputDeviceCategory cat)
|
|
{
|
|
// Map DeviceInputWatcher category to simple scheme string
|
|
string scheme = "Keyboard";
|
|
switch (cat)
|
|
{
|
|
case InputDeviceWatcher.InputDeviceCategory.Keyboard: scheme = "Keyboard"; break;
|
|
case InputDeviceWatcher.InputDeviceCategory.Xbox: scheme = "Gamepad"; break;
|
|
case InputDeviceWatcher.InputDeviceCategory.PlayStation: scheme = "Gamepad"; break;
|
|
case InputDeviceWatcher.InputDeviceCategory.Other: scheme = "Keyboard"; break; // default to keyboard
|
|
}
|
|
|
|
OnControlSchemeChanged?.Invoke(scheme);
|
|
}
|
|
|
|
// Save overrides JSON
|
|
public void SaveOverridesToPrefs()
|
|
{
|
|
if (playerInput == null || playerInput.actions == null) return;
|
|
try
|
|
{
|
|
string json = playerInput.actions.SaveBindingOverridesAsJson();
|
|
PlayerPrefs.SetString(bindingsPrefsKey, json);
|
|
PlayerPrefs.Save();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogWarning("InputService: Failed to save binding overrides: " + e.Message);
|
|
}
|
|
}
|
|
|
|
// Load overrides; if none present the action asset keeps defaults
|
|
public void LoadOverridesFromPrefs()
|
|
{
|
|
if (playerInput == null || playerInput.actions == null) return;
|
|
if (!PlayerPrefs.HasKey(bindingsPrefsKey)) return;
|
|
var json = PlayerPrefs.GetString(bindingsPrefsKey);
|
|
if (string.IsNullOrEmpty(json)) return;
|
|
try
|
|
{
|
|
playerInput.actions.LoadBindingOverridesFromJson(json);
|
|
// Notify listeners for all actions (best-effort)
|
|
foreach (var map in playerInput.actions.actionMaps)
|
|
{
|
|
foreach (var action in map.actions)
|
|
OnBindingChanged?.Invoke(action, -1);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogWarning("InputService: Failed to load binding overrides: " + e.Message);
|
|
}
|
|
}
|
|
|
|
|
|
public static string GetBindingDisplay(InputAction action)
|
|
{
|
|
if (action == null) return string.Empty;
|
|
InputControl control = GetBindingControl(action);
|
|
return control != null ? control.displayName : string.Empty;
|
|
}
|
|
|
|
public static string GetBindingControlPath(InputAction action)
|
|
{
|
|
if (action == null) return string.Empty;
|
|
InputControl control = GetBindingControl(action);
|
|
return control != null ? control.path : string.Empty;
|
|
}
|
|
|
|
public static InputControl GetBindingControl(InputAction action)
|
|
{
|
|
if (action == null) return null;
|
|
var curCategory = InputDeviceWatcher.CurrentCategory;
|
|
var curDeviceName = InputDeviceWatcher.CurrentDeviceName ?? "";
|
|
var hints = GetDeviceHintsForCategory(curCategory);
|
|
foreach (var control in action.controls)
|
|
{
|
|
if (!string.IsNullOrEmpty(curDeviceName) && (control.device.displayName ?? "").Equals(curDeviceName, StringComparison.OrdinalIgnoreCase)
|
|
|| hints.Any(h => (control.device.layout ?? "").ToLowerInvariant().Contains(h.ToLowerInvariant())))
|
|
{
|
|
return control;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
static string[] GetDeviceHintsForCategory(InputDeviceWatcher.InputDeviceCategory cat)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case InputDeviceWatcher.InputDeviceCategory.Keyboard:
|
|
return new[] { "Keyboard", "Mouse" };
|
|
case InputDeviceWatcher.InputDeviceCategory.Xbox:
|
|
return new[] { "XInput", "Xbox", "Gamepad" };
|
|
case InputDeviceWatcher.InputDeviceCategory.PlayStation:
|
|
return new[] { "DualShock", "DualSense", "PlayStation", "Gamepad" };
|
|
default:
|
|
return new[] { "Gamepad", "Joystick", "Keyboard", "Mouse" };
|
|
}
|
|
}
|
|
|
|
// Notify when a binding was changed programmatically
|
|
public void NotifyBindingChanged(InputAction action, int bindingIndex)
|
|
{
|
|
OnBindingChanged?.Invoke(action, bindingIndex);
|
|
}
|
|
}
|
|
}
|