using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.InputDevices; using AxibugProtobuf; using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace AxibugEmuOnline.Client { /// /// 管理键位映射设置 /// public class KeyMapperSetting { Dictionary m_binders = new Dictionary(); Dictionary m_bindersByType = new Dictionary(); public KeyMapperSetting() { var baseType = typeof(EmuCoreControllerKeyBinding); foreach (var t in baseType.Assembly.ExportedTypes) { if (t.IsAbstract) continue; if (!baseType.IsAssignableFrom(t)) continue; var binderIns = Activator.CreateInstance(t) as EmuCoreControllerKeyBinding; m_binders.Add(binderIns.Platform, binderIns); m_bindersByType.Add(binderIns.GetType(), binderIns); } } public T GetBinder() where T : EmuCoreControllerKeyBinding { m_bindersByType.TryGetValue(typeof(T), out var binder); return binder as T; } } /// /// 此类为内部继承, 请勿继承此类 /// public abstract class EmuCoreControllerKeyBinding { /// 所属核心 public abstract RomPlatformType Platform { get; } /// 控制器数量 public abstract int ControllerCount { get; } } /// /// 模拟器核心控制器键位绑定器 /// /// public abstract class EmuCoreControllerKeyBinding : EmuCoreControllerKeyBinding where T : Enum { List m_bindingPages = new List(); KeyBoard m_currentKeyboard; public EmuCoreControllerKeyBinding() { for (int i = 0; i < ControllerCount; i++) { m_bindingPages.Add(new BindingPage(i, this)); } m_currentKeyboard = App.inputDevicesMgr.GetKeyboard(); if (m_currentKeyboard != null) LoadKeyboardMapper(); App.inputDevicesMgr.OnDeviceLost += InputDevicesMgr_OnDeviceLost; App.inputDevicesMgr.OnDeviceConnected += InputDevicesMgr_OnDeviceConnected; } private void InputDevicesMgr_OnDeviceConnected(InputDevice connectDevice) { if (m_currentKeyboard == null && connectDevice is KeyBoard) //未建立键盘按键映射设置时,并且有新的键盘连接时,建立键盘映射设置 { m_currentKeyboard = connectDevice as KeyBoard; LoadKeyboardMapper(); } } private void InputDevicesMgr_OnDeviceLost(InputDevice lostDevice) { if (lostDevice == m_currentKeyboard) //当前键盘设备丢失,与其他键盘重新建立连接 { m_currentKeyboard = App.inputDevicesMgr.GetKeyboard(); LoadKeyboardMapper(); } } IEnumerable DefineKeys() { return Enum.GetValues(typeof(T)).Cast(); } /// /// 加载键盘映射配置 /// void LoadKeyboardMapper() { foreach (var binding in m_bindingPages) { binding.ClearKeyboardBinding(); if (m_currentKeyboard != null) OnLoadKeyboardMapper(m_currentKeyboard, binding); } } /// 当加载键盘映射设置时触发 /// /// protected abstract void OnLoadKeyboardMapper(KeyBoard keyboard, BindingPage binding); public bool Start(T emuControl, int controllerIndex) { var binding = m_bindingPages[controllerIndex]; foreach (var key in binding.GetBinding(emuControl)) { if (key.Start) return true; } return false; } public bool Release(T emuControl, int controllerIndex) { var binding = m_bindingPages[controllerIndex]; foreach (var key in binding.GetBinding(emuControl)) { if (key.Release) return true; } return false; } /// /// 获取指定控件是否处于按下状态 /// 如果绑定了多个物理按键,则只有这多个物理按键全部不处于按下状态时,才会返回false /// /// /// /// public bool GetKey(T emuControl, int controllerIndex) { var binding = m_bindingPages[controllerIndex]; foreach (var key in binding.GetBinding(emuControl)) { if (key.Performing) return true; } return false; } /// /// 获取调用帧是否有任意按键触发了按下操作 /// /// /// public bool AnyKeyDown(int controllerIndex) { var binding = m_bindingPages[controllerIndex]; return binding.AnyKeyDown(); } /// /// 获取指定控件的向量值 /// 通常用于摇杆类型的控件 /// 如果同时绑定了多个物理输入设备,只会返回其中一个物理设备的向量值 /// /// 模拟器平台的具体键枚举 /// 模拟器平台的控制器序号 /// public Vector2 GetVector2(T emuControl, int controllerIndex) { var binding = m_bindingPages[controllerIndex]; foreach (var control in binding.GetBinding(emuControl)) { if (!control.Performing) continue; return control.GetVector2(); } return default(Vector2); } /// /// 获取指定控件的浮点值,取值范围为[0f,1f] /// 通常用于线性类按键,例如PS手柄的扳机键 /// 普通的按键也能读取这个值,但返回值只会有0f和1f两种值 /// 如果同时绑定了多个物理控件,则会从所有处于按下状态的物理控件中取平均值 /// /// 模拟器平台的具体键枚举 /// 模拟器平台的控制器序号 /// public float GetFloat(T emuControl, int controllerIndex) { var totalFloat = 0f; var totalControl = 0; var binding = m_bindingPages[controllerIndex]; foreach (var key in binding.GetBinding(emuControl)) { if (!key.Performing) continue; totalControl++; totalFloat += key.GetFlaot(); } if (totalControl == 0) return default(float); else return totalFloat / totalControl; } public class BindingPage { Dictionary> m_mapSetting = new Dictionary>(); public int ControllerIndex { get; } public EmuCoreControllerKeyBinding Host { get; } internal BindingPage(int controllerIndex, EmuCoreControllerKeyBinding host) { ControllerIndex = controllerIndex; Host = host; foreach (var emuBtn in host.DefineKeys()) m_mapSetting[emuBtn] = new List(); } /// /// 移除与键盘设备建立的绑定设置 /// internal void ClearKeyboardBinding() { foreach (var list in m_mapSetting.Values) { for (int i = 0; i < list.Count; i++) { var inputControl = list[i]; if (inputControl.Device is KeyBoard) { list.RemoveAt(i); i--; } } } } public void SetBinding(T emuBtn, InputDevice.InputControl key, int settingSlot) { var settingList = m_mapSetting[emuBtn]; int needFixCount = settingSlot - settingList.Count + 1; if (needFixCount > 0) for (int i = 0; i < needFixCount; i++) settingList.Add(null); settingList[settingSlot] = key; } public InputDevice.InputControl GetBinding(T emuBtn, int settingSlot) { var settingList = m_mapSetting[emuBtn]; if (settingSlot >= settingList.Count) return null; return settingList[settingSlot]; } public List GetBinding(T emuBtn) { return m_mapSetting[emuBtn]; } public bool AnyKeyDown() { foreach (var item in m_mapSetting) { foreach (var key in item.Value) { if (key.Start) return true; } } return false; } } } }