优化
非适配手柄 增加可选UX_NAVIGATION 宏 优化部分结构
This commit is contained in:
parent
fb9846d10c
commit
dc8923564b
@ -15,7 +15,7 @@ public static class GlyphService
|
|||||||
|
|
||||||
private static InputGlyphDatabase _database;
|
private static InputGlyphDatabase _database;
|
||||||
|
|
||||||
public static InputGlyphDatabase Database
|
static InputGlyphDatabase Database
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -362,5 +362,4 @@ public static class GlyphService
|
|||||||
return StartsWithDevice(path, "<Gamepad>") || StartsWithDevice(path, "<Joystick>") || ContainsAny(path, OtherGamepadGroupHints);
|
return StartsWithDevice(path, "<Gamepad>") || StartsWithDevice(path, "<Joystick>") || ContainsAny(path, OtherGamepadGroupHints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,9 +6,9 @@ using UnityEngine;
|
|||||||
using UnityEngine.InputSystem;
|
using UnityEngine.InputSystem;
|
||||||
using AlicizaX;
|
using AlicizaX;
|
||||||
|
|
||||||
public class InputBindingManager : MonoSingleton<InputBindingManager>
|
public sealed class InputBindingManager : MonoServiceBehaviour<InputBindingManager>
|
||||||
{
|
{
|
||||||
public const string NULL_BINDING = "__NULL__";
|
private const string NULL_BINDING = "__NULL__";
|
||||||
private const string KEYBOARD_DEVICE = "<Keyboard>";
|
private const string KEYBOARD_DEVICE = "<Keyboard>";
|
||||||
private const string MOUSE_DELTA = "<Mouse>/delta";
|
private const string MOUSE_DELTA = "<Mouse>/delta";
|
||||||
private const string MOUSE_SCROLL = "<Mouse>/scroll";
|
private const string MOUSE_SCROLL = "<Mouse>/scroll";
|
||||||
@ -22,7 +22,7 @@ public class InputBindingManager : MonoSingleton<InputBindingManager>
|
|||||||
private const string FILE_NAME = "input_bindings.json";
|
private const string FILE_NAME = "input_bindings.json";
|
||||||
public bool debugMode = false;
|
public bool debugMode = false;
|
||||||
|
|
||||||
internal InputActionRebindingExtensions.RebindingOperation rebindOperation;
|
private InputActionRebindingExtensions.RebindingOperation rebindOperation;
|
||||||
private bool isApplyPending = false;
|
private bool isApplyPending = false;
|
||||||
private string defaultBindingsJson = string.Empty;
|
private string defaultBindingsJson = string.Empty;
|
||||||
private string cachedSavePath;
|
private string cachedSavePath;
|
||||||
@ -31,21 +31,6 @@ public class InputBindingManager : MonoSingleton<InputBindingManager>
|
|||||||
private readonly Dictionary<string, (ActionMap map, ActionMap.Action action)> actionLookup = new(StringComparer.Ordinal);
|
private readonly Dictionary<string, (ActionMap map, ActionMap.Action action)> actionLookup = new(StringComparer.Ordinal);
|
||||||
private readonly Dictionary<Guid, (ActionMap map, ActionMap.Action action)> actionLookupById = new();
|
private readonly Dictionary<Guid, (ActionMap map, ActionMap.Action action)> actionLookupById = new();
|
||||||
private readonly HashSet<string> ambiguousActionNames = new(StringComparer.Ordinal);
|
private readonly HashSet<string> ambiguousActionNames = new(StringComparer.Ordinal);
|
||||||
private event Action _onInputsInit;
|
|
||||||
|
|
||||||
public event Action OnInputsInit
|
|
||||||
{
|
|
||||||
add
|
|
||||||
{
|
|
||||||
_onInputsInit += value;
|
|
||||||
// 重放行为:如果已经初始化,立即调用
|
|
||||||
if (isInputsInitialized)
|
|
||||||
{
|
|
||||||
value?.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
remove { _onInputsInit -= value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public event Action<bool, HashSet<RebindContext>> OnApply;
|
public event Action<bool, HashSet<RebindContext>> OnApply;
|
||||||
public event Action<RebindContext> OnRebindPrepare;
|
public event Action<RebindContext> OnRebindPrepare;
|
||||||
@ -54,12 +39,11 @@ public class InputBindingManager : MonoSingleton<InputBindingManager>
|
|||||||
public event Action<RebindContext, RebindContext> OnRebindConflict;
|
public event Action<RebindContext, RebindContext> OnRebindConflict;
|
||||||
public static event Action BindingsChanged;
|
public static event Action BindingsChanged;
|
||||||
|
|
||||||
private bool isInputsInitialized = false;
|
|
||||||
|
|
||||||
public IReadOnlyDictionary<string, ActionMap> ActionMaps => actionMap;
|
public IReadOnlyDictionary<string, ActionMap> ActionMaps => actionMap;
|
||||||
public IReadOnlyCollection<RebindContext> PreparedRebinds => preparedRebinds;
|
public IReadOnlyCollection<RebindContext> PreparedRebinds => preparedRebinds;
|
||||||
|
|
||||||
public string SavePath
|
private string SavePath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -83,16 +67,9 @@ public class InputBindingManager : MonoSingleton<InputBindingManager>
|
|||||||
Directory.CreateDirectory(directory);
|
Directory.CreateDirectory(directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Awake()
|
|
||||||
|
protected override void OnServiceInitialize()
|
||||||
{
|
{
|
||||||
if (_instance != null && _instance != this)
|
|
||||||
{
|
|
||||||
Destroy(gameObject);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_instance = this;
|
|
||||||
|
|
||||||
if (actions == null)
|
if (actions == null)
|
||||||
{
|
{
|
||||||
Log.Error("InputBindingManager: InputActionAsset not assigned.");
|
Log.Error("InputBindingManager: InputActionAsset not assigned.");
|
||||||
@ -133,23 +110,14 @@ public class InputBindingManager : MonoSingleton<InputBindingManager>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isInputsInitialized = true;
|
|
||||||
_onInputsInit?.Invoke();
|
|
||||||
actions.Enable();
|
actions.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
if (_instance == this)
|
|
||||||
{
|
|
||||||
_instance = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
rebindOperation?.Dispose();
|
rebindOperation?.Dispose();
|
||||||
rebindOperation = null;
|
rebindOperation = null;
|
||||||
|
|
||||||
// 清除所有事件处理器
|
|
||||||
_onInputsInit = null;
|
|
||||||
OnApply = null;
|
OnApply = null;
|
||||||
OnRebindPrepare = null;
|
OnRebindPrepare = null;
|
||||||
OnRebindStart = null;
|
OnRebindStart = null;
|
||||||
@ -379,161 +347,6 @@ public class InputBindingManager : MonoSingleton<InputBindingManager>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------- Public API ---------------- */
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 根据操作名称获取输入操作
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="actionName">操作名称</param>
|
|
||||||
/// <returns>输入操作,未找到则返回 null</returns>
|
|
||||||
public static InputAction Action(string actionName)
|
|
||||||
{
|
|
||||||
var instance = Instance;
|
|
||||||
if (instance == null) return null;
|
|
||||||
|
|
||||||
if (TryGetAction(actionName, out InputAction action))
|
|
||||||
{
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instance.ambiguousActionNames.Contains(actionName))
|
|
||||||
{
|
|
||||||
Log.Error($"[InputBindingManager] Action name '{actionName}' is ambiguous. Use 'MapName/{actionName}' instead.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.Error($"[InputBindingManager] Could not find action '{actionName}'");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryGetAction(string actionName, out InputAction action)
|
|
||||||
{
|
|
||||||
var instance = Instance;
|
|
||||||
if (instance == null || string.IsNullOrWhiteSpace(actionName))
|
|
||||||
{
|
|
||||||
action = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instance.actionLookup.TryGetValue(actionName, out var result))
|
|
||||||
{
|
|
||||||
action = result.action.action;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
action = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 开始重新绑定指定的输入操作
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="actionName">操作名称</param>
|
|
||||||
/// <param name="compositePartName">复合部分名称(可选)</param>
|
|
||||||
public static void StartRebind(string actionName, string compositePartName = null)
|
|
||||||
{
|
|
||||||
var action = Action(actionName);
|
|
||||||
if (action == null) return;
|
|
||||||
|
|
||||||
// 自动决定 bindingIndex 和 deviceMatch
|
|
||||||
int bindingIndex = Instance.FindBestBindingIndexForKeyboard(action, compositePartName);
|
|
||||||
if (bindingIndex < 0)
|
|
||||||
{
|
|
||||||
Log.Error($"[InputBindingManager] No suitable binding found for action '{actionName}' (part={compositePartName ?? "<null>"})");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instance.actions.Disable();
|
|
||||||
Instance.PerformInteractiveRebinding(action, bindingIndex, KEYBOARD_DEVICE, true);
|
|
||||||
Instance.OnRebindStart?.Invoke();
|
|
||||||
if (Instance.debugMode)
|
|
||||||
{
|
|
||||||
Log.Info("[InputBindingManager] Rebind started");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 取消当前的重新绑定操作
|
|
||||||
/// </summary>
|
|
||||||
public static void CancelRebind() => Instance.rebindOperation?.Cancel();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 确认并应用准备好的重新绑定
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="clearConflicts">是否清除冲突</param>
|
|
||||||
/// <returns>是否成功应用</returns>
|
|
||||||
public static async Task<bool> ConfirmApply(bool clearConflicts = true)
|
|
||||||
{
|
|
||||||
if (!Instance.isApplyPending) return false;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 在清除之前创建准备好的重绑定的副本
|
|
||||||
HashSet<RebindContext> appliedContexts = Instance.OnApply != null
|
|
||||||
? new HashSet<RebindContext>(Instance.preparedRebinds)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
foreach (var ctx in Instance.preparedRebinds)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(ctx.overridePath))
|
|
||||||
{
|
|
||||||
if (ctx.overridePath == NULL_BINDING)
|
|
||||||
{
|
|
||||||
ctx.action.RemoveBindingOverride(ctx.bindingIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ctx.action.ApplyBindingOverride(ctx.bindingIndex, ctx.overridePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var bp = GetBindingPath(ctx.action, ctx.bindingIndex);
|
|
||||||
if (bp != null)
|
|
||||||
{
|
|
||||||
bp.EffectivePath = (ctx.overridePath == NULL_BINDING) ? string.Empty : ctx.overridePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Instance.preparedRebinds.Clear();
|
|
||||||
await Instance.WriteOverridesToDiskAsync();
|
|
||||||
BindingsChanged?.Invoke();
|
|
||||||
Instance.OnApply?.Invoke(true, appliedContexts);
|
|
||||||
Instance.isApplyPending = false;
|
|
||||||
if (Instance.debugMode)
|
|
||||||
{
|
|
||||||
Log.Info("[InputBindingManager] Apply confirmed and saved.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Error("[InputBindingManager] Failed to apply binds: " + ex);
|
|
||||||
Instance.OnApply?.Invoke(false, null);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 丢弃准备好的重新绑定
|
|
||||||
/// </summary>
|
|
||||||
public static void DiscardPrepared()
|
|
||||||
{
|
|
||||||
if (!Instance.isApplyPending) return;
|
|
||||||
|
|
||||||
// 在清除之前创建准备好的重绑定的副本(用于事件通知)
|
|
||||||
HashSet<RebindContext> discardedContexts = Instance.OnApply != null
|
|
||||||
? new HashSet<RebindContext>(Instance.preparedRebinds)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
Instance.preparedRebinds.Clear();
|
|
||||||
Instance.isApplyPending = false;
|
|
||||||
Instance.OnApply?.Invoke(false, discardedContexts);
|
|
||||||
if (Instance.debugMode)
|
|
||||||
{
|
|
||||||
Log.Info("[InputBindingManager] Prepared rebinds discarded.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PerformInteractiveRebinding(InputAction action, int bindingIndex, string deviceMatchPath = null, bool excludeMouseMovementAndScroll = true)
|
private void PerformInteractiveRebinding(InputAction action, int bindingIndex, string deviceMatchPath = null, bool excludeMouseMovementAndScroll = true)
|
||||||
{
|
{
|
||||||
@ -692,79 +505,6 @@ public class InputBindingManager : MonoSingleton<InputBindingManager>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重置所有绑定到默认值
|
|
||||||
/// </summary>
|
|
||||||
public async Task ResetToDefaultAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(defaultBindingsJson))
|
|
||||||
{
|
|
||||||
actions.LoadBindingOverridesFromJson(defaultBindingsJson);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var map in actionMap.Values)
|
|
||||||
{
|
|
||||||
foreach (var a in map.actions.Values)
|
|
||||||
{
|
|
||||||
for (int b = 0; b < a.action.bindings.Count; b++)
|
|
||||||
{
|
|
||||||
a.action.RemoveBindingOverride(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RefreshBindingPathsFromActions();
|
|
||||||
await WriteOverridesToDiskAsync();
|
|
||||||
BindingsChanged?.Invoke();
|
|
||||||
if (debugMode)
|
|
||||||
{
|
|
||||||
Log.Info("Reset to default and saved.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Error("Failed to reset defaults: " + ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取指定操作的绑定路径
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="actionName">操作名称</param>
|
|
||||||
/// <param name="bindingIndex">绑定索引</param>
|
|
||||||
/// <returns>绑定路径,未找到则返回 null</returns>
|
|
||||||
public static BindingPath GetBindingPath(string actionName, int bindingIndex = 0)
|
|
||||||
{
|
|
||||||
var instance = Instance;
|
|
||||||
if (instance == null) return null;
|
|
||||||
|
|
||||||
if (instance.TryGetActionRecord(actionName, out var result)
|
|
||||||
&& result.action.bindings.TryGetValue(bindingIndex, out var binding))
|
|
||||||
{
|
|
||||||
return binding.bindingPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BindingPath GetBindingPath(InputAction action, int bindingIndex = 0)
|
|
||||||
{
|
|
||||||
var instance = Instance;
|
|
||||||
if (instance == null || action == null) return null;
|
|
||||||
|
|
||||||
if (instance.TryGetActionRecord(action, out var result)
|
|
||||||
&& result.action.bindings.TryGetValue(bindingIndex, out var binding))
|
|
||||||
{
|
|
||||||
return binding.bindingPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryGetActionRecord(string actionName, out (ActionMap map, ActionMap.Action action) result)
|
private bool TryGetActionRecord(string actionName, out (ActionMap map, ActionMap.Action action) result)
|
||||||
{
|
{
|
||||||
return actionLookup.TryGetValue(actionName, out result);
|
return actionLookup.TryGetValue(actionName, out result);
|
||||||
@ -781,6 +521,7 @@ public class InputBindingManager : MonoSingleton<InputBindingManager>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Public API
|
||||||
|
|
||||||
// 为键盘选择最佳绑定索引;如果 compositePartName != null 则查找部分
|
// 为键盘选择最佳绑定索引;如果 compositePartName != null 则查找部分
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -827,18 +568,225 @@ public class InputBindingManager : MonoSingleton<InputBindingManager>
|
|||||||
return fallbackNonComposite >= 0 ? fallbackNonComposite : fallbackPart;
|
return fallbackNonComposite >= 0 ? fallbackNonComposite : fallbackPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InputBindingManager Instance
|
/// <summary>
|
||||||
|
/// 根据操作名称获取输入操作
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="actionName">操作名称</param>
|
||||||
|
/// <returns>输入操作,未找到则返回 null</returns>
|
||||||
|
public static InputAction Action(string actionName)
|
||||||
{
|
{
|
||||||
get
|
var instance= AppServices.Require<InputBindingManager>();
|
||||||
|
if (instance.TryGetAction(actionName, out InputAction action))
|
||||||
{
|
{
|
||||||
if (_instance == null)
|
return action;
|
||||||
{
|
}
|
||||||
_instance = FindObjectOfType<InputBindingManager>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _instance;
|
if (instance.ambiguousActionNames.Contains(actionName))
|
||||||
|
{
|
||||||
|
Log.Error($"[InputBindingManager] Action name '{actionName}' is ambiguous. Use 'MapName/{actionName}' instead.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Error($"[InputBindingManager] Could not find action '{actionName}'");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetAction(string actionName, out InputAction action)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(actionName))
|
||||||
|
{
|
||||||
|
action = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionLookup.TryGetValue(actionName, out var result))
|
||||||
|
{
|
||||||
|
action = result.action.action;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
action = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开始重新绑定指定的输入操作
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="actionName">操作名称</param>
|
||||||
|
/// <param name="compositePartName">复合部分名称(可选)</param>
|
||||||
|
public void StartRebind(string actionName, string compositePartName = null)
|
||||||
|
{
|
||||||
|
var action = Action(actionName);
|
||||||
|
if (action == null) return;
|
||||||
|
|
||||||
|
// 自动决定 bindingIndex 和 deviceMatch
|
||||||
|
int bindingIndex = FindBestBindingIndexForKeyboard(action, compositePartName);
|
||||||
|
if (bindingIndex < 0)
|
||||||
|
{
|
||||||
|
Log.Error($"[InputBindingManager] No suitable binding found for action '{actionName}' (part={compositePartName ?? "<null>"})");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
actions.Disable();
|
||||||
|
PerformInteractiveRebinding(action, bindingIndex, KEYBOARD_DEVICE, true);
|
||||||
|
OnRebindStart?.Invoke();
|
||||||
|
if (debugMode)
|
||||||
|
{
|
||||||
|
Log.Info("[InputBindingManager] Rebind started");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputBindingManager _instance;
|
/// <summary>
|
||||||
|
/// 取消当前的重新绑定操作
|
||||||
|
/// </summary>
|
||||||
|
public void CancelRebind() => rebindOperation?.Cancel();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 确认并应用准备好的重新绑定
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clearConflicts">是否清除冲突</param>
|
||||||
|
/// <returns>是否成功应用</returns>
|
||||||
|
public async Task<bool> ConfirmApply(bool clearConflicts = true)
|
||||||
|
{
|
||||||
|
if (!isApplyPending) return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 在清除之前创建准备好的重绑定的副本
|
||||||
|
HashSet<RebindContext> appliedContexts = OnApply != null
|
||||||
|
? new HashSet<RebindContext>(preparedRebinds)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
foreach (var ctx in preparedRebinds)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(ctx.overridePath))
|
||||||
|
{
|
||||||
|
if (ctx.overridePath == NULL_BINDING)
|
||||||
|
{
|
||||||
|
ctx.action.RemoveBindingOverride(ctx.bindingIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctx.action.ApplyBindingOverride(ctx.bindingIndex, ctx.overridePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var bp = GetBindingPath(ctx.action, ctx.bindingIndex);
|
||||||
|
if (bp != null)
|
||||||
|
{
|
||||||
|
bp.EffectivePath = (ctx.overridePath == NULL_BINDING) ? string.Empty : ctx.overridePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preparedRebinds.Clear();
|
||||||
|
await WriteOverridesToDiskAsync();
|
||||||
|
BindingsChanged?.Invoke();
|
||||||
|
OnApply?.Invoke(true, appliedContexts);
|
||||||
|
isApplyPending = false;
|
||||||
|
if (debugMode)
|
||||||
|
{
|
||||||
|
Log.Info("[InputBindingManager] Apply confirmed and saved.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error("[InputBindingManager] Failed to apply binds: " + ex);
|
||||||
|
OnApply?.Invoke(false, null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 丢弃准备好的重新绑定
|
||||||
|
/// </summary>
|
||||||
|
public void DiscardPrepared()
|
||||||
|
{
|
||||||
|
if (!isApplyPending) return;
|
||||||
|
|
||||||
|
// 在清除之前创建准备好的重绑定的副本(用于事件通知)
|
||||||
|
HashSet<RebindContext> discardedContexts = OnApply != null
|
||||||
|
? new HashSet<RebindContext>(preparedRebinds)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
preparedRebinds.Clear();
|
||||||
|
isApplyPending = false;
|
||||||
|
OnApply?.Invoke(false, discardedContexts);
|
||||||
|
if (debugMode)
|
||||||
|
{
|
||||||
|
Log.Info("[InputBindingManager] Prepared rebinds discarded.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重置所有绑定到默认值
|
||||||
|
/// </summary>
|
||||||
|
public async Task ResetToDefaultAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(defaultBindingsJson))
|
||||||
|
{
|
||||||
|
actions.LoadBindingOverridesFromJson(defaultBindingsJson);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var map in actionMap.Values)
|
||||||
|
{
|
||||||
|
foreach (var a in map.actions.Values)
|
||||||
|
{
|
||||||
|
for (int b = 0; b < a.action.bindings.Count; b++)
|
||||||
|
{
|
||||||
|
a.action.RemoveBindingOverride(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshBindingPathsFromActions();
|
||||||
|
await WriteOverridesToDiskAsync();
|
||||||
|
BindingsChanged?.Invoke();
|
||||||
|
if (debugMode)
|
||||||
|
{
|
||||||
|
Log.Info("Reset to default and saved.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error("Failed to reset defaults: " + ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定操作的绑定路径
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="actionName">操作名称</param>
|
||||||
|
/// <param name="bindingIndex">绑定索引</param>
|
||||||
|
/// <returns>绑定路径,未找到则返回 null</returns>
|
||||||
|
public BindingPath GetBindingPath(string actionName, int bindingIndex = 0)
|
||||||
|
{
|
||||||
|
if (TryGetActionRecord(actionName, out var result)
|
||||||
|
&& result.action.bindings.TryGetValue(bindingIndex, out var binding))
|
||||||
|
{
|
||||||
|
return binding.bindingPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BindingPath GetBindingPath(InputAction action, int bindingIndex = 0)
|
||||||
|
{
|
||||||
|
if (action == null) return null;
|
||||||
|
|
||||||
|
if (TryGetActionRecord(action, out var result)
|
||||||
|
&& result.action.bindings.TryGetValue(bindingIndex, out var binding))
|
||||||
|
{
|
||||||
|
return binding.bindingPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,20 +31,18 @@ public sealed class InputGlyph : InputGlyphBehaviourBase
|
|||||||
public UnityEvent onNotMatched;
|
public UnityEvent onNotMatched;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Header("Source")]
|
[Header("Source")] [SerializeField] private ActionSourceMode actionSourceMode = ActionSourceMode.ActionReference;
|
||||||
[SerializeField] private ActionSourceMode actionSourceMode = ActionSourceMode.ActionReference;
|
|
||||||
[SerializeField] private InputActionReference actionReference;
|
[SerializeField] private InputActionReference actionReference;
|
||||||
[SerializeField] private Component hotkeyTrigger;
|
[SerializeField] private Component hotkeyTrigger;
|
||||||
[SerializeField] private string actionName;
|
[SerializeField] private string actionName;
|
||||||
[SerializeField] private string compositePartName;
|
[SerializeField] private string compositePartName;
|
||||||
|
|
||||||
[Header("Output")]
|
[Header("Output")] [SerializeField] private OutputMode outputMode = OutputMode.Image;
|
||||||
[SerializeField] private OutputMode outputMode = OutputMode.Image;
|
|
||||||
[SerializeField] private Image targetImage;
|
[SerializeField] private Image targetImage;
|
||||||
[SerializeField] private TMP_Text targetText;
|
[SerializeField] private TMP_Text targetText;
|
||||||
|
|
||||||
[Header("Platform Events")]
|
[Header("Platform Events")] [SerializeField]
|
||||||
[SerializeField] private List<DeviceCategoryEvent> categoryEvents = new();
|
private List<DeviceCategoryEvent> categoryEvents = new();
|
||||||
|
|
||||||
private Sprite _cachedSprite;
|
private Sprite _cachedSprite;
|
||||||
private string _templateText;
|
private string _templateText;
|
||||||
@ -177,7 +175,7 @@ public sealed class InputGlyph : InputGlyphBehaviourBase
|
|||||||
case ActionSourceMode.HotkeyTrigger:
|
case ActionSourceMode.HotkeyTrigger:
|
||||||
return ResolveHotkeyAction();
|
return ResolveHotkeyAction();
|
||||||
case ActionSourceMode.ActionName:
|
case ActionSourceMode.ActionName:
|
||||||
return InputBindingManager.TryGetAction(actionName, out InputAction action) ? action : null;
|
return InputBindingManager.Action(actionName);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,245 +1,245 @@
|
|||||||
using System;
|
// using System;
|
||||||
using System.Collections.Generic;
|
// using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
// using System.Threading.Tasks;
|
||||||
using TMPro;
|
// using TMPro;
|
||||||
using UnityEngine;
|
// using UnityEngine;
|
||||||
using UnityEngine.InputSystem;
|
// using UnityEngine.InputSystem;
|
||||||
using UnityEngine.UI;
|
// using UnityEngine.UI;
|
||||||
|
//
|
||||||
public class TestRebindScript : MonoBehaviour
|
// public class TestRebindScript : MonoBehaviour
|
||||||
{
|
// {
|
||||||
[Header("UI")] public UXButton btn;
|
// [Header("UI")] public UXButton btn;
|
||||||
public TextMeshProUGUI bindKeyText;
|
// public TextMeshProUGUI bindKeyText;
|
||||||
public Image targetImage;
|
// public Image targetImage;
|
||||||
|
//
|
||||||
[Tooltip("如果不使用 actionReference,则用 name 在全局 manager 查找")]
|
// [Tooltip("如果不使用 actionReference,则用 name 在全局 manager 查找")]
|
||||||
public string actionName = "movement";
|
// public string actionName = "movement";
|
||||||
|
//
|
||||||
[Header("Optional composite part (WASD style)")] [Tooltip("如果需要绑定 composite 的某一部分(例如 Up/Down/Left/Right),填这个;留空表示绑定非 composite 或整体 binding")]
|
// [Header("Optional composite part (WASD style)")] [Tooltip("如果需要绑定 composite 的某一部分(例如 Up/Down/Left/Right),填这个;留空表示绑定非 composite 或整体 binding")]
|
||||||
public string compositePartName = "";
|
// public string compositePartName = "";
|
||||||
|
//
|
||||||
[Header("Behavior")] [Tooltip("如果 true,在 Prepare 后自动调用 ConfirmApply() 并保存;否则等待手动 ConfirmPrepared()/CancelPrepared()")]
|
// [Header("Behavior")] [Tooltip("如果 true,在 Prepare 后自动调用 ConfirmApply() 并保存;否则等待手动 ConfirmPrepared()/CancelPrepared()")]
|
||||||
public bool autoConfirm = false;
|
// public bool autoConfirm = false;
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 启动时初始化并订阅事件
|
// /// 启动时初始化并订阅事件
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private void Start()
|
// private void Start()
|
||||||
{
|
// {
|
||||||
if (btn != null) btn.onClick.AddListener(OnBtnClicked);
|
// if (btn != null) btn.onClick.AddListener(OnBtnClicked);
|
||||||
InputDeviceWatcher.OnDeviceChanged += OnDeviceChanged;
|
// InputDeviceWatcher.OnDeviceChanged += OnDeviceChanged;
|
||||||
InputBindingManager.BindingsChanged += OnBindingsChanged;
|
// InputBindingManager.BindingsChanged += OnBindingsChanged;
|
||||||
UpdateBindingText();
|
// UpdateBindingText();
|
||||||
|
//
|
||||||
if (InputBindingManager.Instance != null)
|
// if (InputBindingManager.Instance != null)
|
||||||
{
|
// {
|
||||||
// 订阅事件
|
// // 订阅事件
|
||||||
InputBindingManager.Instance.OnRebindPrepare += OnRebindPrepareHandler;
|
// InputBindingManager.Instance.OnRebindPrepare += OnRebindPrepareHandler;
|
||||||
InputBindingManager.Instance.OnApply += OnApplyHandler;
|
// InputBindingManager.Instance.OnApply += OnApplyHandler;
|
||||||
InputBindingManager.Instance.OnRebindEnd += OnRebindEndHandler;
|
// InputBindingManager.Instance.OnRebindEnd += OnRebindEndHandler;
|
||||||
InputBindingManager.Instance.OnRebindConflict += OnRebindConflictHandler;
|
// InputBindingManager.Instance.OnRebindConflict += OnRebindConflictHandler;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 禁用时取消订阅事件
|
// /// 禁用时取消订阅事件
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private void OnDisable()
|
// private void OnDisable()
|
||||||
{
|
// {
|
||||||
if (btn != null) btn.onClick.RemoveListener(OnBtnClicked);
|
// if (btn != null) btn.onClick.RemoveListener(OnBtnClicked);
|
||||||
InputDeviceWatcher.OnDeviceChanged -= OnDeviceChanged;
|
// InputDeviceWatcher.OnDeviceChanged -= OnDeviceChanged;
|
||||||
InputBindingManager.BindingsChanged -= OnBindingsChanged;
|
// InputBindingManager.BindingsChanged -= OnBindingsChanged;
|
||||||
|
//
|
||||||
if (InputBindingManager.Instance != null)
|
// if (InputBindingManager.Instance != null)
|
||||||
{
|
// {
|
||||||
InputBindingManager.Instance.OnRebindPrepare -= OnRebindPrepareHandler;
|
// InputBindingManager.Instance.OnRebindPrepare -= OnRebindPrepareHandler;
|
||||||
InputBindingManager.Instance.OnApply -= OnApplyHandler;
|
// InputBindingManager.Instance.OnApply -= OnApplyHandler;
|
||||||
InputBindingManager.Instance.OnRebindEnd -= OnRebindEndHandler;
|
// InputBindingManager.Instance.OnRebindEnd -= OnRebindEndHandler;
|
||||||
InputBindingManager.Instance.OnRebindConflict -= OnRebindConflictHandler;
|
// InputBindingManager.Instance.OnRebindConflict -= OnRebindConflictHandler;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 重新绑定准备完成的处理器
|
// /// 重新绑定准备完成的处理器
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private void OnRebindPrepareHandler(InputBindingManager.RebindContext ctx)
|
// private void OnRebindPrepareHandler(InputBindingManager.RebindContext ctx)
|
||||||
{
|
// {
|
||||||
if (IsTargetContext(ctx))
|
// if (IsTargetContext(ctx))
|
||||||
{
|
// {
|
||||||
var disp = ctx.overridePath == InputBindingManager.NULL_BINDING ? "<Cleared>" : ctx.overridePath;
|
// var disp = ctx.overridePath == InputBindingManager.NULL_BINDING ? "<Cleared>" : ctx.overridePath;
|
||||||
bindKeyText.text = disp;
|
// bindKeyText.text = disp;
|
||||||
if (autoConfirm) _ = ConfirmPreparedAsync();
|
// if (autoConfirm) _ = ConfirmPreparedAsync();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 应用重新绑定的处理器
|
// /// 应用重新绑定的处理器
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private void OnApplyHandler(bool success, HashSet<InputBindingManager.RebindContext> appliedContexts)
|
// private void OnApplyHandler(bool success, HashSet<InputBindingManager.RebindContext> appliedContexts)
|
||||||
{
|
// {
|
||||||
if (appliedContexts != null)
|
// if (appliedContexts != null)
|
||||||
{
|
// {
|
||||||
// 仅当任何应用/丢弃的上下文与此实例匹配时才更新
|
// // 仅当任何应用/丢弃的上下文与此实例匹配时才更新
|
||||||
foreach (var ctx in appliedContexts)
|
// foreach (var ctx in appliedContexts)
|
||||||
{
|
// {
|
||||||
if (IsTargetContext(ctx))
|
// if (IsTargetContext(ctx))
|
||||||
{
|
// {
|
||||||
UpdateBindingText();
|
// UpdateBindingText();
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 重新绑定结束的处理器
|
// /// 重新绑定结束的处理器
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private void OnRebindEndHandler(bool success, InputBindingManager.RebindContext context)
|
// private void OnRebindEndHandler(bool success, InputBindingManager.RebindContext context)
|
||||||
{
|
// {
|
||||||
if (IsTargetContext(context))
|
// if (IsTargetContext(context))
|
||||||
{
|
// {
|
||||||
UpdateBindingText();
|
// UpdateBindingText();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 重新绑定冲突的处理器
|
// /// 重新绑定冲突的处理器
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private void OnRebindConflictHandler(InputBindingManager.RebindContext prepared, InputBindingManager.RebindContext conflict)
|
// private void OnRebindConflictHandler(InputBindingManager.RebindContext prepared, InputBindingManager.RebindContext conflict)
|
||||||
{
|
// {
|
||||||
// 如果准备的或冲突的上下文匹配此实例,则更新
|
// // 如果准备的或冲突的上下文匹配此实例,则更新
|
||||||
if (IsTargetContext(prepared) || IsTargetContext(conflict))
|
// if (IsTargetContext(prepared) || IsTargetContext(conflict))
|
||||||
{
|
// {
|
||||||
UpdateBindingText();
|
// UpdateBindingText();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 设备变更的回调
|
// /// 设备变更的回调
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private void OnDeviceChanged(InputDeviceWatcher.InputDeviceCategory _)
|
// private void OnDeviceChanged(InputDeviceWatcher.InputDeviceCategory _)
|
||||||
{
|
// {
|
||||||
UpdateBindingText();
|
// UpdateBindingText();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private void OnBindingsChanged()
|
// private void OnBindingsChanged()
|
||||||
{
|
// {
|
||||||
UpdateBindingText();
|
// UpdateBindingText();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 获取当前的输入操作
|
// /// 获取当前的输入操作
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private InputAction GetAction()
|
// private InputAction GetAction()
|
||||||
{
|
// {
|
||||||
return InputBindingManager.Action(actionName);
|
// return InputBindingManager.Action(actionName);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 判断上下文是否为目标上下文
|
// /// 判断上下文是否为目标上下文
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private bool IsTargetContext(InputBindingManager.RebindContext ctx)
|
// private bool IsTargetContext(InputBindingManager.RebindContext ctx)
|
||||||
{
|
// {
|
||||||
if (ctx == null || ctx.action == null) return false;
|
// if (ctx == null || ctx.action == null) return false;
|
||||||
var action = GetAction();
|
// var action = GetAction();
|
||||||
if (action == null) return false;
|
// if (action == null) return false;
|
||||||
|
//
|
||||||
// 必须匹配操作
|
// // 必须匹配操作
|
||||||
if (ctx.action != action) return false;
|
// if (ctx.action != action) return false;
|
||||||
|
//
|
||||||
// 如果指定了复合部分,需要匹配绑定索引
|
// // 如果指定了复合部分,需要匹配绑定索引
|
||||||
if (!string.IsNullOrEmpty(compositePartName))
|
// if (!string.IsNullOrEmpty(compositePartName))
|
||||||
{
|
// {
|
||||||
// 获取上下文索引处的绑定
|
// // 获取上下文索引处的绑定
|
||||||
if (ctx.bindingIndex < 0 || ctx.bindingIndex >= action.bindings.Count)
|
// if (ctx.bindingIndex < 0 || ctx.bindingIndex >= action.bindings.Count)
|
||||||
return false;
|
// return false;
|
||||||
|
//
|
||||||
var binding = action.bindings[ctx.bindingIndex];
|
// var binding = action.bindings[ctx.bindingIndex];
|
||||||
|
//
|
||||||
// 检查绑定的名称是否与我们的复合部分匹配
|
// // 检查绑定的名称是否与我们的复合部分匹配
|
||||||
return string.Equals(binding.name, compositePartName, StringComparison.OrdinalIgnoreCase);
|
// return string.Equals(binding.name, compositePartName, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 如果未指定复合部分,仅匹配操作就足够了
|
// // 如果未指定复合部分,仅匹配操作就足够了
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 按钮点击的回调
|
// /// 按钮点击的回调
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private void OnBtnClicked()
|
// private void OnBtnClicked()
|
||||||
{
|
// {
|
||||||
// 使用管理器 API(我们传递部分名称,以便管理器可以在需要时选择适当的绑定)
|
// // 使用管理器 API(我们传递部分名称,以便管理器可以在需要时选择适当的绑定)
|
||||||
InputBindingManager.StartRebind(actionName, string.IsNullOrEmpty(compositePartName) ? null : compositePartName);
|
// InputBindingManager.StartRebind(actionName, string.IsNullOrEmpty(compositePartName) ? null : compositePartName);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 确认准备好的重新绑定(公共方法)
|
// /// 确认准备好的重新绑定(公共方法)
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public async void ConfirmPrepared()
|
// public async void ConfirmPrepared()
|
||||||
{
|
// {
|
||||||
bool ok = await ConfirmPreparedAsync();
|
// bool ok = await ConfirmPreparedAsync();
|
||||||
if (!ok) Debug.LogError("ConfirmPrepared: apply failed.");
|
// if (!ok) Debug.LogError("ConfirmPrepared: apply failed.");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 确认准备好的重新绑定(异步)
|
// /// 确认准备好的重新绑定(异步)
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private async Task<bool> ConfirmPreparedAsync()
|
// private async Task<bool> ConfirmPreparedAsync()
|
||||||
{
|
// {
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
var task = InputBindingManager.ConfirmApply();
|
// var task = InputBindingManager.ConfirmApply();
|
||||||
return await task;
|
// return await task;
|
||||||
}
|
// }
|
||||||
catch (Exception ex)
|
// catch (Exception ex)
|
||||||
{
|
// {
|
||||||
Debug.LogError(ex);
|
// Debug.LogError(ex);
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 取消准备好的重新绑定
|
// /// 取消准备好的重新绑定
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public void CancelPrepared()
|
// public void CancelPrepared()
|
||||||
{
|
// {
|
||||||
InputBindingManager.DiscardPrepared();
|
// InputBindingManager.DiscardPrepared();
|
||||||
// UpdateBindingText 将通过 OnApply 事件自动调用
|
// // UpdateBindingText 将通过 OnApply 事件自动调用
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 更新绑定文本和图标显示
|
// /// 更新绑定文本和图标显示
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
private void UpdateBindingText()
|
// private void UpdateBindingText()
|
||||||
{
|
// {
|
||||||
var action = GetAction();
|
// var action = GetAction();
|
||||||
var deviceCat = InputDeviceWatcher.CurrentCategory;
|
// var deviceCat = InputDeviceWatcher.CurrentCategory;
|
||||||
if (action == null)
|
// if (action == null)
|
||||||
{
|
// {
|
||||||
bindKeyText.text = "<no action>";
|
// bindKeyText.text = "<no action>";
|
||||||
if (targetImage != null) targetImage.sprite = null;
|
// if (targetImage != null) targetImage.sprite = null;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
bindKeyText.text = GlyphService.GetDisplayNameFromInputAction(action, compositePartName, deviceCat);
|
// bindKeyText.text = GlyphService.GetDisplayNameFromInputAction(action, compositePartName, deviceCat);
|
||||||
|
//
|
||||||
|
//
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
if (GlyphService.TryGetUISpriteForActionPath(action, compositePartName, deviceCat, out Sprite sprite))
|
// if (GlyphService.TryGetUISpriteForActionPath(action, compositePartName, deviceCat, out Sprite sprite))
|
||||||
{
|
// {
|
||||||
if (targetImage != null) targetImage.sprite = sprite;
|
// if (targetImage != null) targetImage.sprite = sprite;
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
if (targetImage != null) targetImage.sprite = null;
|
// if (targetImage != null) targetImage.sprite = null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
catch
|
// catch
|
||||||
{
|
// {
|
||||||
if (targetImage != null) targetImage.sprite = null;
|
// if (targetImage != null) targetImage.sprite = null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@ -477,7 +477,11 @@ namespace UnityEngine.UI
|
|||||||
|
|
||||||
foreach (var scope in _scopes.Values)
|
foreach (var scope in _scopes.Values)
|
||||||
{
|
{
|
||||||
if (!IsScopeActive(scope) || !UXNavigationRuntime.IsHolderWithinTopScope(scope.Holder))
|
if (!IsScopeActive(scope)
|
||||||
|
#if UX_NAVIGATION
|
||||||
|
|| !UXNavigationRuntime.IsHolderWithinTopScope(scope.Holder)
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -493,7 +497,9 @@ namespace UnityEngine.UI
|
|||||||
foreach (var scope in _scopes.Values)
|
foreach (var scope in _scopes.Values)
|
||||||
{
|
{
|
||||||
if (IsScopeActive(scope)
|
if (IsScopeActive(scope)
|
||||||
|
#if UX_NAVIGATION
|
||||||
&& UXNavigationRuntime.IsHolderWithinTopScope(scope.Holder)
|
&& UXNavigationRuntime.IsHolderWithinTopScope(scope.Holder)
|
||||||
|
#endif
|
||||||
&& !_ancestorHolders.Contains(scope.Holder))
|
&& !_ancestorHolders.Contains(scope.Holder))
|
||||||
{
|
{
|
||||||
_leafScopes.Add(scope);
|
_leafScopes.Add(scope);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#if INPUTSYSTEM_SUPPORT
|
#if INPUTSYSTEM_SUPPORT && UX_NAVIGATION
|
||||||
namespace UnityEngine.UI
|
namespace UnityEngine.UI
|
||||||
{
|
{
|
||||||
public enum UXInputMode : byte
|
public enum UXInputMode : byte
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#if INPUTSYSTEM_SUPPORT
|
#if INPUTSYSTEM_SUPPORT && UX_NAVIGATION
|
||||||
using System;
|
using System;
|
||||||
using UnityEngine.InputSystem;
|
using UnityEngine.InputSystem;
|
||||||
using UnityEngine.InputSystem.Controls;
|
using UnityEngine.InputSystem.Controls;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#if INPUTSYSTEM_SUPPORT
|
#if INPUTSYSTEM_SUPPORT && UX_NAVIGATION
|
||||||
namespace UnityEngine.UI
|
namespace UnityEngine.UI
|
||||||
{
|
{
|
||||||
[DisallowMultipleComponent]
|
[DisallowMultipleComponent]
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#if INPUTSYSTEM_SUPPORT
|
#if INPUTSYSTEM_SUPPORT && UX_NAVIGATION
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AlicizaX;
|
using AlicizaX;
|
||||||
using AlicizaX.UI.Runtime;
|
using AlicizaX.UI.Runtime;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#if INPUTSYSTEM_SUPPORT
|
#if INPUTSYSTEM_SUPPORT && UX_NAVIGATION
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AlicizaX.UI.Runtime;
|
using AlicizaX.UI.Runtime;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#if INPUTSYSTEM_SUPPORT
|
#if INPUTSYSTEM_SUPPORT && UX_NAVIGATION
|
||||||
namespace UnityEngine.UI
|
namespace UnityEngine.UI
|
||||||
{
|
{
|
||||||
[DisallowMultipleComponent]
|
[DisallowMultipleComponent]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user