using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.InputDevices;
using AxibugProtobuf;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace AxibugEmuOnline.Client.Settings
{
///
/// 管理键位映射设置
///
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 T GetBinder(RomPlatformType romType) where T : EmuCoreControllerKeyBinding
{
m_binders.TryGetValue(romType, 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();
public EmuCoreControllerKeyBinding()
{
for (int i = 0; i < ControllerCount; i++)
{
m_bindingPages.Add(new BindingPage(i, this));
}
var keyboard = App.input.GetDevice();
if (keyboard != null)
{
foreach (var binding in m_bindingPages)
{
binding.RegistInputDevice(keyboard);
}
}
var psvController = App.input.GetDevice();
if (psvController != null)
{
foreach (var binding in m_bindingPages)
{
binding.RegistInputDevice(psvController);
}
}
App.input.OnDeviceLost += InputDevicesMgr_OnDeviceLost;
App.input.OnDeviceConnected += InputDevicesMgr_OnDeviceConnected;
}
private void InputDevicesMgr_OnDeviceConnected(InputDevice_D connectDevice)
{
if (connectDevice is Keyboard_D)
{
foreach (var binding in m_bindingPages)
{
binding.RegistInputDevice(connectDevice);
}
}
}
private void InputDevicesMgr_OnDeviceLost(InputDevice_D lostDevice)
{
foreach (var binding in m_bindingPages)
{
binding.UnregistInputDevice(lostDevice);
}
if (lostDevice is Keyboard_D) //键盘丢失,立即查找还存在的键盘并建立连接
{
var anotherKeyboard = App.input.GetDevice();
if (anotherKeyboard != null)
{
foreach (var binding in m_bindingPages)
{
binding.UnregistInputDevice(lostDevice);
}
}
}
}
IEnumerable DefineKeys()
{
return Enum.GetValues(typeof(T)).Cast();
}
internal void RaiseDeviceRegist(InputDevice_D device, BindingPage binding)
{
OnRegistDevices(device, binding);
}
protected abstract void OnRegistDevices(InputDevice_D device, 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 MapSetting : Dictionary> { }
public class BindingPage
{
Dictionary m_registedDevices = new Dictionary();
Dictionary m_mapSetting = new Dictionary();
public int ControllerIndex { get; }
public EmuCoreControllerKeyBinding Host { get; }
internal BindingPage(int controllerIndex, EmuCoreControllerKeyBinding host)
{
ControllerIndex = controllerIndex;
Host = host;
}
internal bool IsRegisted() where DEVICE : InputDevice_D
{
var type = typeof(T);
return IsRegisted(type);
}
internal bool IsRegisted(Type deviceType)
{
return m_registedDevices.ContainsKey(deviceType);
}
internal void RegistInputDevice(InputDevice_D device)
{
var type = device.GetType();
if (IsRegisted(type)) return;
m_registedDevices.Add(type, device);
m_mapSetting[device] = new MapSetting();
Host.RaiseDeviceRegist(device, this);
}
internal void UnregistInputDevice(InputDevice_D device)
{
var type = device.GetType();
if (!IsRegisted(type)) return;
m_registedDevices.Remove(type);
m_mapSetting.Remove(device);
}
public void SetBinding(T emuBtn, InputControl_C key, int settingSlot)
{
var device = key.Device;
m_registedDevices.TryGetValue(device.GetType(), out var inputDevice);
Debug.Assert(inputDevice == device);
var setting = m_mapSetting[inputDevice];
if (!setting.TryGetValue(emuBtn, out var settingList))
{
settingList = new List();
setting[emuBtn] = settingList;
}
int needFixCount = settingSlot - settingList.Count + 1;
if (needFixCount > 0) for (int i = 0; i < needFixCount; i++) settingList.Add(null);
settingList[settingSlot] = key;
}
public InputControl_C GetBinding(T emuBtn, InputDevice_D device, int settingSlot)
{
m_mapSetting.TryGetValue(device, out var mapSetting);
if (mapSetting == null) return null;
mapSetting.TryGetValue(emuBtn, out var settingList);
if (settingList == null || settingSlot >= settingList.Count) return null;
return settingList[settingSlot];
}
private List m_caches = new List();
public IEnumerable GetBinding(T emuBtn)
{
m_caches.Clear();
foreach (var mapSettings in m_mapSetting.Values)
{
mapSettings.TryGetValue(emuBtn, out var bindControls);
if (bindControls != null)
{
m_caches.AddRange(bindControls);
}
}
return m_caches;
}
public bool AnyKeyDown()
{
foreach (var mapSettings in m_mapSetting.Values)
{
foreach (var keys in mapSettings.Values)
{
foreach (var key in keys)
{
if (key.Start) return true;
}
}
}
return false;
}
}
}
}