TH1/Unity/Assets/Scripts/TH1_Logic/Input/InputConfigManager.cs
2026-06-05 22:50:45 +08:00

263 lines
8.5 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.

/*
* @Author: 白哉
* @Description:
* @Date: 2025年09月05日 星期五 15:09:36
* @Modify:
*/
using System.Collections.Generic;
using System.IO;
using Logic.CrashSight;
using MemoryPack;
using TH1_Logic.Tools;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace Logic
{
public class InputConfigManager
{
public static InputConfigManager Instance = new InputConfigManager();
private InputConfig _config;
private List<KeyCode> _pressedKeys = new List<KeyCode>();
private bool _isListening = false;
private float _waitTime = 0.2f; // 等待时间,防止误触
private float _lastKeyPressTime;
private InputEnum _curInputEnum;
private Dictionary<InputEnum, List<System.Action>> _inputCallBack;
public InputConfig Config => _config;
public bool IsListening => _isListening;
public void Init()
{
RefreshInputConfig();
_config.Init();
_inputCallBack = new Dictionary<InputEnum, List<System.Action>>();
}
// 开始监听按键绑定, UI 调用开始记录输入
public void StartRecordInput(InputEnum inputEnum)
{
if (_isListening) return;
_curInputEnum = inputEnum;
_isListening = true;
_pressedKeys.Clear();
}
// 外部获取状态使用, 游戏逻辑用
public bool IsActive(InputEnum inputEnum)
{
if (_config == null) return false;
var keyConfig = _config.GetInputKeyConfig(inputEnum);
if (keyConfig == null) return false;
return keyConfig.IsActive;
}
// 注册输入回调
public void RegisterInputCallback(InputEnum inputEnum, System.Action callback)
{
if (!_inputCallBack.ContainsKey(inputEnum))
{
_inputCallBack[inputEnum] = new List<System.Action>();
}
_inputCallBack[inputEnum].Add(callback);
}
public void RefreshInputConfig()
{
if (_config != null) return;
string path = Application.persistentDataPath + "/../Config/input_config.dat";
string backupPath = path + ".bak";
// 尝试读取主文件
_config = FileTools.TryDeserializeFile<InputConfig>(path);
// 主文件损坏,尝试从备份恢复
if (_config == null && File.Exists(backupPath))
{
LogSystem.LogInfo("[InputConfig] 主文件损坏,尝试从备份恢复...");
_config = FileTools.TryDeserializeFile<InputConfig>(backupPath);
if (_config != null)
{
LogSystem.LogInfo("[InputConfig] 从备份恢复成功");
try
{
byte[] bytes = MemoryPackSerializer.Serialize(_config);
FileTools.SafeWriteFile(path, bytes);
}
catch (System.Exception e)
{
LogSystem.LogError($"[InputConfig] 恢复写入主文件失败: {e.Message}");
}
}
else
{
LogSystem.LogError("[InputConfig] 备份文件也已损坏,将重置数据");
}
}
_config ??= new InputConfig();
}
// 保存输入配置
public void SaveInputConfig()
{
if (_config == null) return;
byte[] bytes = MemoryPackSerializer.Serialize(_config);
FileTools.SafeWriteFile(Application.persistentDataPath + "/../Config/input_config.dat", bytes);
}
// 每帧调用返回绑定结果null表示还在监听中
public void Update()
{
UpdateConfigListening();
if (InputTextFocusUtility.IsTextInputFocused())
{
ClearInputActiveState();
return;
}
UpdateConfigActive();
}
private void ClearInputActiveState()
{
if (_config?.InputKeyConfigs == null) return;
foreach (var keyConfig in _config.InputKeyConfigs)
keyConfig.IsActive = false;
}
private void UpdateConfigListening()
{
if (!_isListening) return;
// 检测所有按下的键
foreach (KeyCode key in System.Enum.GetValues(typeof(KeyCode)))
{
if (key == KeyCode.None) continue;
if (Input.GetKeyDown(key))
{
if (!_pressedKeys.Contains(key))
{
_pressedKeys.Add(key);
_lastKeyPressTime = Time.time;
}
}
}
// 检查是否所有键都已释放
if (_pressedKeys.Count > 0)
{
bool allReleased = true;
foreach (var key in _pressedKeys)
{
if (Input.GetKey(key))
{
allReleased = false;
break;
}
}
if (_pressedKeys.Count >= 3) allReleased = true;
// 所有键释放后,确认绑定
if (allReleased && Time.time - _lastKeyPressTime > _waitTime)
{
_isListening = false;
_config?.SetInputKeyConfig(_curInputEnum, _pressedKeys);
SaveInputConfig();
// TODO 这里可以调用 UI 刷新,因为配置发生了变化
}
}
}
private void UpdateConfigActive()
{
if (_config == null || _isListening) return;
foreach (var keyConfig in _config.InputKeyConfigs)
{
keyConfig.IsActive = IsKeyCombinationActive(keyConfig.KeyCodes);
if (IsKeyCombinationTriggered(keyConfig.KeyCodes)) OnInputCallback(keyConfig.InputType);
}
}
// 检查组合键是否被激活
private bool IsKeyCombinationActive(List<KeyCode> keyCodes)
{
for (int i = 0; i < keyCodes.Count; i++)
{
if (!Input.GetKey(keyCodes[i]))
return false;
}
return true;
}
// 检查组合键是否被触发
private bool IsKeyCombinationTriggered(List<KeyCode> keyCodes)
{
if (keyCodes == null || keyCodes.Count == 0) return false;
// 单键情况
if (keyCodes.Count == 1)
{
return Input.GetKeyDown(keyCodes[0]);
}
// 组合键:前面的键必须按住,最后一个键检测 GetKeyDown
for (int i = 0; i < keyCodes.Count - 1; i++)
{
if (!Input.GetKey(keyCodes[i]))
return false;
}
return Input.GetKeyDown(keyCodes[^1]);
}
// 输入触发时的回调
private void OnInputCallback(InputEnum inputEnum)
{
LogSystem.LogInfo($"触发 {inputEnum}");
if (_inputCallBack != null && _inputCallBack.TryGetValue(inputEnum, out var callbackList))
{
foreach (var callback in callbackList)
{
callback?.Invoke();
}
}
}
}
public static class InputTextFocusUtility
{
public static bool IsTextInputFocused()
{
var selected = EventSystem.current?.currentSelectedGameObject;
if (selected == null) return false;
return IsFocusedInputField(selected.GetComponent<TMP_InputField>())
|| IsFocusedInputField(selected.GetComponentInParent<TMP_InputField>())
|| IsFocusedInputField(selected.GetComponent<InputField>())
|| IsFocusedInputField(selected.GetComponentInParent<InputField>());
}
private static bool IsFocusedInputField(TMP_InputField inputField)
{
return inputField != null && inputField.isActiveAndEnabled && inputField.isFocused;
}
private static bool IsFocusedInputField(InputField inputField)
{
return inputField != null && inputField.isActiveAndEnabled && inputField.isFocused;
}
}
}