AlicizaX/Client/Assets/InputGlyph/TestRebindScript.cs

172 lines
5.6 KiB
C#
Raw Normal View History

// TestRebindScript.cs
using System;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using InputRemapper;
using UnityEngine.UI;
public class TestRebindScript : MonoBehaviour
{
[Header("UI")]
public UXButton btn;
public TextMeshProUGUI bindKeyText;
public Image targetImage;
[Tooltip("如果不使用 actionReference则用 name 在全局 manager 查找")]
public string actionName = "movement";
[Header("Optional composite part (WASD style)")]
[Tooltip("如果需要绑定 composite 的某一部分(例如 Up/Down/Left/Right填这个留空表示绑定非 composite 或整体 binding")]
public string compositePartName = "";
[Header("Behavior")]
[Tooltip("如果 true在 Prepare 后自动调用 ConfirmApply() 并保存;否则等待手动 ConfirmPrepared()/CancelPrepared()")]
public bool autoConfirm = false;
private int targetBindingIndex = -1;
private IDisposable prepareSub;
private IDisposable applySub;
private IDisposable rebindEndSub;
private void Start()
{
if (btn != null) btn.onClick.AddListener(OnBtnClicked);
InputDeviceWatcher.OnDeviceChanged += OnDeviceChanged;
ResolveBindingIndex();
UpdateBindingText();
if (InputBindingManager.Instance != null)
{
prepareSub = InputBindingManager.Instance.OnRebindPrepare.Subscribe(ctx =>
{
if (IsTargetContext(ctx))
{
var disp = ctx.overridePath == InputBindingManager.NULL_BINDING ? "<Cleared>" : ctx.overridePath;
bindKeyText.text = disp;
if (autoConfirm) _ = ConfirmPreparedAsync();
}
});
applySub = InputBindingManager.Instance.OnApply.Subscribe(_ => UpdateBindingText());
rebindEndSub = InputBindingManager.Instance.OnRebindEnd.Subscribe(_ => UpdateBindingText());
}
}
private void OnDisable()
{
if (btn != null) btn.onClick.RemoveListener(OnBtnClicked);
InputDeviceWatcher.OnDeviceChanged -= OnDeviceChanged;
prepareSub?.Dispose();
applySub?.Dispose();
rebindEndSub?.Dispose();
}
private void OnDeviceChanged(InputDeviceWatcher.InputDeviceCategory _)
{
UpdateBindingText();
}
private InputAction GetAction()
{
return InputBindingManager.Action(actionName);
}
private void ResolveBindingIndex()
{
var action = GetAction();
if (action == null)
{
Debug.LogError($"TestRebindScript: Action not found ('{actionName}').");
targetBindingIndex = -1;
return;
}
// Ask manager to choose best index for keyboard and optional composite part
targetBindingIndex = InputBindingManager.Instance.FindBestBindingIndexForKeyboard(action, string.IsNullOrEmpty(compositePartName) ? null : compositePartName);
}
private bool IsTargetContext(InputRemapper.InputBindingManager.RebindContext ctx)
{
if (ctx == null || ctx.action == null) return false;
var action = GetAction();
if (action == null) return false;
return ctx.action == action && ctx.bindingIndex == targetBindingIndex;
}
private void OnBtnClicked()
{
// Use manager API (we pass part name so manager can pick proper binding if needed)
InputBindingManager.StartRebind(actionName, string.IsNullOrEmpty(compositePartName) ? null : compositePartName);
}
public async void ConfirmPrepared()
{
bool ok = await ConfirmPreparedAsync();
if (!ok) Debug.LogError("ConfirmPrepared: apply failed.");
}
private async Task<bool> ConfirmPreparedAsync()
{
try
{
var task = InputBindingManager.ConfirmApply();
if (task == null) return false;
return await task;
}
catch (Exception ex) { Debug.LogError(ex); return false; }
}
public void CancelPrepared()
{
InputBindingManager.DiscardPrepared();
UpdateBindingText();
}
private void UpdateBindingText()
{
var action = GetAction();
if (action == null)
{
bindKeyText.text = "<no action>";
if (targetImage != null) targetImage.sprite = null;
return;
}
// Ensure binding index is refreshed (action/bindings may change)
if (targetBindingIndex < 0 || targetBindingIndex >= action.bindings.Count)
ResolveBindingIndex();
if (targetBindingIndex < 0)
{
bindKeyText.text = "<no binding>";
if (targetImage != null) targetImage.sprite = null;
return;
}
string disp = action.GetBindingDisplayString(targetBindingIndex);
bindKeyText.text = string.IsNullOrEmpty(disp) ? "<unbound>" : disp;
// **Important**: use GlyphService with InputAction and device category (not manager-internal path)
try
{
var deviceCat = InputDeviceWatcher.CurrentCategory;
string controlPath = GlyphService.GetBindingControlPath(action, deviceCat);
if (!string.IsNullOrEmpty(controlPath) && GlyphService.TryGetUISpriteForActionPath(controlPath, deviceCat, out Sprite sprite))
{
if (targetImage != null) targetImage.sprite = sprite;
}
else
{
if (targetImage != null) targetImage.sprite = null;
}
}
catch
{
if (targetImage != null) targetImage.sprite = null;
}
}
}