using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.UI;
namespace BaseGames.UI
{
///
/// 多设备 UI 焦点守护:挂在持有 EventSystem 的对象上。
///
/// 解决"鼠标点击空白处 → 当前选中被清空 → 切换到键盘/手柄时无选中项可导航"的问题:
/// 记录最近一个有效选中项;当选中丢失且玩家按下导航/确认键(键盘方向键 / 手柄摇杆·十字键 / Submit)时,
/// 自动把焦点恢复到上一个仍可交互的选中项。仅在"导航意图"出现时恢复,不与鼠标悬停/点击冲突。
///
/// 设备无关:依赖 的 move/submit Action,
/// 因此键盘、Xbox、Switch、PlayStation 手柄(均归一为 Gamepad 布局)统一生效。
///
[DefaultExecutionOrder(100)]
public class UISelectionRestorer : MonoBehaviour
{
[Tooltip("始终保持选中:选中丢失(如鼠标点击空白处)即立即恢复,无需等待导航键。\n" +
"适合\"菜单始终有一项高亮\"的手感;关闭则仅在按下方向/确认键时恢复(避免抢占鼠标)。")]
[SerializeField] private bool _keepSelectionAlways = true;
private GameObject _lastSelected;
private void Update()
{
var es = EventSystem.current;
if (es == null) return;
var current = es.currentSelectedGameObject;
if (current != null && current.activeInHierarchy)
{
_lastSelected = current; // 记录最近的有效选中
return;
}
// 选中已丢失:始终保持模式下立即恢复;否则仅在出现导航/确认意图时恢复
if (!_keepSelectionAlways && !NavigationIntentThisFrame(es)) return;
if (_lastSelected == null || !_lastSelected.activeInHierarchy) return;
var sel = _lastSelected.GetComponent();
if (sel == null || !sel.IsInteractable()) return;
es.SetSelectedGameObject(_lastSelected);
}
private static bool NavigationIntentThisFrame(EventSystem es)
{
if (es.currentInputModule is not InputSystemUIInputModule m) return false;
if (m.move != null && m.move.action != null && m.move.action.WasPerformedThisFrame()) return true;
if (m.submit != null && m.submit.action != null && m.submit.action.WasPerformedThisFrame()) return true;
return false;
}
}
}