AlicizaX/Client/Assets/InputGlyph/TestRebindScript.cs
2026-03-11 11:40:00 +08:00

200 lines
6.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
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 void Start()
{
if (btn != null) btn.onClick.AddListener(OnBtnClicked);
InputDeviceWatcher.OnDeviceChanged += OnDeviceChanged;
UpdateBindingText();
if (InputBindingManager.Instance != null)
{
// Subscribe to events
InputBindingManager.Instance.OnRebindPrepare += OnRebindPrepareHandler;
InputBindingManager.Instance.OnApply += OnApplyHandler;
InputBindingManager.Instance.OnRebindEnd += OnRebindEndHandler;
InputBindingManager.Instance.OnRebindConflict += OnRebindConflictHandler;
}
}
private void OnDisable()
{
if (btn != null) btn.onClick.RemoveListener(OnBtnClicked);
InputDeviceWatcher.OnDeviceChanged -= OnDeviceChanged;
if (InputBindingManager.Instance != null)
{
InputBindingManager.Instance.OnRebindPrepare -= OnRebindPrepareHandler;
InputBindingManager.Instance.OnApply -= OnApplyHandler;
InputBindingManager.Instance.OnRebindEnd -= OnRebindEndHandler;
InputBindingManager.Instance.OnRebindConflict -= OnRebindConflictHandler;
}
}
private void OnRebindPrepareHandler(InputBindingManager.RebindContext ctx)
{
if (IsTargetContext(ctx))
{
var disp = ctx.overridePath == InputBindingManager.NULL_BINDING ? "<Cleared>" : ctx.overridePath;
bindKeyText.text = disp;
if (autoConfirm) _ = ConfirmPreparedAsync();
}
}
private void OnApplyHandler(bool success, HashSet<InputBindingManager.RebindContext> appliedContexts)
{
if (appliedContexts != null)
{
// Only update if any of the applied/discarded contexts match this instance
foreach (var ctx in appliedContexts)
{
if (IsTargetContext(ctx))
{
UpdateBindingText();
break;
}
}
}
}
private void OnRebindEndHandler(bool success, InputBindingManager.RebindContext context)
{
if (IsTargetContext(context))
{
UpdateBindingText();
}
}
private void OnRebindConflictHandler(InputBindingManager.RebindContext prepared, InputBindingManager.RebindContext conflict)
{
// Update if either the prepared or conflict context matches this instance
if (IsTargetContext(prepared) || IsTargetContext(conflict))
{
UpdateBindingText();
}
}
private void OnDeviceChanged(InputDeviceWatcher.InputDeviceCategory _)
{
UpdateBindingText();
}
private InputAction GetAction()
{
return InputBindingManager.Action(actionName);
}
private bool IsTargetContext(InputBindingManager.RebindContext ctx)
{
if (ctx == null || ctx.action == null) return false;
var action = GetAction();
if (action == null) return false;
// Must match the action
if (ctx.action != action) return false;
// If we have a composite part specified, we need to match the binding index
if (!string.IsNullOrEmpty(compositePartName))
{
// Get the binding at the context's index
if (ctx.bindingIndex < 0 || ctx.bindingIndex >= action.bindings.Count)
return false;
var binding = action.bindings[ctx.bindingIndex];
// Check if the binding's name matches our composite part
return string.Equals(binding.name, compositePartName, StringComparison.OrdinalIgnoreCase);
}
// If no composite part specified, just matching the action is enough
return true;
}
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();
return await task;
}
catch (Exception ex)
{
Debug.LogError(ex);
return false;
}
}
public void CancelPrepared()
{
InputBindingManager.DiscardPrepared();
// UpdateBindingText will be called automatically via OnApply event
}
private void UpdateBindingText()
{
var action = GetAction();
if (action == null)
{
bindKeyText.text = "<no action>";
if (targetImage != null) targetImage.sprite = null;
return;
}
bindKeyText.text = GlyphService.GetDisplayNameFromInputAction(action, compositePartName);
try
{
var deviceCat = InputDeviceWatcher.CurrentCategory;
InputActionReference refr=default;
// string controlPath = GlyphService.GetBindingControlPath(action, compositePartName, deviceCat);
if ( GlyphService.TryGetUISpriteForActionPath(action,compositePartName, deviceCat, out Sprite sprite))
{
if (targetImage != null) targetImage.sprite = sprite;
}
else
{
if (targetImage != null) targetImage.sprite = null;
}
}
catch
{
if (targetImage != null) targetImage.sprite = null;
}
}
}