InputDevice中的keybase基类改为inputcontrol,突出基础类型作为一个输入控件的概念,以免和按钮类控件混淆

This commit is contained in:
ALIENJACK\alien 2025-03-14 11:02:38 +08:00
parent 955a35659a
commit 4e1f8fd045
7 changed files with 289 additions and 87 deletions

View File

@ -85,17 +85,18 @@ namespace AxibugEmuOnline.Client
protected abstract void OnLoadDefaultMapper(BindingPage binding);
/// <summary>
/// 获取指定按键是否处于按下状态
/// 获取指定控件是否处于按下状态
/// <para>如果绑定了多个物理按键,则只有这多个物理按键全部不处于按下状态时,才会返回false</para>
/// </summary>
/// <param name="emuBtn"></param>
/// <param name="emuControl"></param>
/// <param name="controllerIndex"></param>
/// <returns></returns>
public bool GetKey(T emuBtn, int controllerIndex)
public bool GetKey(T emuControl, int controllerIndex)
{
var binding = m_bindingPages[controllerIndex];
foreach (var key in binding.GetBinding(emuBtn))
foreach (var key in binding.GetBinding(emuControl))
{
if (key.IsPressing()) return true;
if (key.Performing) return true;
}
return false;
@ -113,46 +114,56 @@ namespace AxibugEmuOnline.Client
}
/// <summary>
/// 获取指定按键的值
/// 获取指定控件的向量值
/// <para>通常用于摇杆类型的控件</para>
/// <para>如果同时绑定了多个物理输入设备,只会返回其中一个物理设备的向量值</para>
/// </summary>
/// <param name="emuBtn">模拟器平台的具体键枚举</param>
/// <param name="emuControl">模拟器平台的具体键枚举</param>
/// <param name="controllerIndex">模拟器平台的控制器序号</param>
/// <returns></returns>
public Vector2 GetVector2(T emuBtn, int controllerIndex)
public Vector2 GetVector2(T emuControl, int controllerIndex)
{
var binding = m_bindingPages[controllerIndex];
foreach (var key in binding.GetBinding(emuBtn))
foreach (var control in binding.GetBinding(emuControl))
{
if (!key.IsPressing()) continue;
if (!control.Performing) continue;
return key.GetVector2();
return control.GetVector2();
}
return default(Vector2);
}
/// <summary>
/// 获取指定按键的值
/// 获取指定控件的浮点值,取值范围为[0f,1f]
/// <para>通常用于线性类按键,例如PS手柄的扳机键</para>
/// <para>普通的按键也能读取这个值,但返回值只会有0f和1f两种值</para>
/// <para>如果同时绑定了多个物理控件,则会从所有处于按下状态的物理控件中取平均值</para>
/// </summary>
/// <param name="emuBtn">模拟器平台的具体键枚举</param>
/// <param name="emuControl">模拟器平台的具体键枚举</param>
/// <param name="controllerIndex">模拟器平台的控制器序号</param>
/// <returns></returns>
public float GetFloat(T emuBtn, int controllerIndex)
public float GetFloat(T emuControl, int controllerIndex)
{
var binding = m_bindingPages[controllerIndex];
foreach (var key in binding.GetBinding(emuBtn))
{
if (!key.IsPressing()) continue;
var totalFloat = 0f;
var totalControl = 0;
return key.GetFlaot();
var binding = m_bindingPages[controllerIndex];
foreach (var key in binding.GetBinding(emuControl))
{
if (!key.Performing) continue;
totalControl++;
totalFloat += key.GetFlaot();
}
return default(float);
if (totalControl == 0) return default(float);
else return totalFloat / totalControl;
}
public class BindingPage
{
Dictionary<T, List<InputDevice.KeyBase>> m_mapSetting = new Dictionary<T, List<InputDevice.KeyBase>>();
Dictionary<T, List<InputDevice.InputControl>> m_mapSetting = new Dictionary<T, List<InputDevice.InputControl>>();
public int ControllerIndex { get; }
public EmuCoreControllerKeyBinding<T> Host { get; }
@ -163,7 +174,7 @@ namespace AxibugEmuOnline.Client
Host = host;
foreach (var emuBtn in host.DefineKeys())
m_mapSetting[emuBtn] = new List<InputDevice.KeyBase>();
m_mapSetting[emuBtn] = new List<InputDevice.InputControl>();
}
public void ClearBinding()
@ -171,7 +182,7 @@ namespace AxibugEmuOnline.Client
foreach (var list in m_mapSetting.Values) list.Clear();
}
public void SetBinding(T emuBtn, InputDevice.KeyBase key, int settingSlot)
public void SetBinding(T emuBtn, InputDevice.InputControl key, int settingSlot)
{
var settingList = m_mapSetting[emuBtn];
@ -181,14 +192,14 @@ namespace AxibugEmuOnline.Client
settingList[settingSlot] = key;
}
public InputDevice.KeyBase GetBinding(T emuBtn, int settingSlot)
public InputDevice.InputControl GetBinding(T emuBtn, int settingSlot)
{
var settingList = m_mapSetting[emuBtn];
if (settingSlot >= settingList.Count) return null;
return settingList[settingSlot];
}
public List<InputDevice.KeyBase> GetBinding(T emuBtn)
public List<InputDevice.InputControl> GetBinding(T emuBtn)
{
return m_mapSetting[emuBtn];
}
@ -199,7 +210,7 @@ namespace AxibugEmuOnline.Client
{
foreach (var key in item.Value)
{
if (key.GetButtonDown()) return true;
if (key.Start) return true;
}
}

View File

@ -1,6 +1,5 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
namespace AxibugEmuOnline.Client.InputDevices
{
@ -19,12 +18,12 @@ namespace AxibugEmuOnline.Client.InputDevices
private void OnDeviceLost(InputDevice lostDevice)
{
RemoveDevice(lostDevice);
}
private void OnDeviceConnected(InputDevice connectDevice)
{
throw new System.NotImplementedException();
AddDevice(connectDevice);
}
public void AddDevice(InputDevice device)
@ -37,7 +36,7 @@ namespace AxibugEmuOnline.Client.InputDevices
m_devices.Remove(device.UniqueName);
}
public InputDevice.KeyBase GetKeyByPath(string path)
public InputDevice.InputControl GetKeyByPath(string path)
{
var temp = path.Split("/");
Debug.Assert(temp.Length == 2, "Invalid Path Format");
@ -48,7 +47,7 @@ namespace AxibugEmuOnline.Client.InputDevices
var targetDevice = FindDeviceByName(deviceName);
if (targetDevice == null) return null;
var key = targetDevice.FindKeyByKeyName(keyName);
var key = targetDevice.FindControlByName(keyName);
return key;
}
@ -83,22 +82,22 @@ namespace AxibugEmuOnline.Client.InputDevices
{
public abstract string UniqueName { get; }
public delegate void OnKeyStateChangedHandle(KeyBase sender);
public event OnKeyStateChangedHandle OnKeyStateChanged;
/// <summary> 指示该设备是否在线 </summary>
public abstract bool Online { get; }
/// <summary> 指示该设备当前帧是否有任意键被按下 </summary>
public bool Online => m_resolver.CheckOnline(this);
/// <summary> 指示该设备当前帧是否有任意控件被激发 </summary>
public bool AnyKeyDown { get; private set; }
/// <summary> 获得输入解决器 </summary>
internal InputResolver Resolver => m_resolver;
protected Dictionary<string, KeyBase> m_keyMapper = new Dictionary<string, KeyBase>();
protected Dictionary<string, InputControl> m_controlMapper = new Dictionary<string, InputControl>();
protected InputResolver m_resolver;
public InputDevice(InputResolver resolver)
{
m_resolver = resolver;
foreach (var key in DefineKeys())
foreach (var control in DefineControls())
{
m_keyMapper[key.KeyName] = key;
m_controlMapper.Add(control.ControlName, control);
}
}
@ -106,49 +105,54 @@ namespace AxibugEmuOnline.Client.InputDevices
{
AnyKeyDown = false;
foreach (var key in m_keyMapper.Values)
foreach (var control in m_controlMapper.Values)
{
if (key.GetButtonDown())
if (control.Start)
{
AnyKeyDown = true;
RaiseKeyEvent(key);
}
}
}
protected abstract IEnumerable<KeyBase> DefineKeys();
protected void RaiseKeyEvent(KeyBase sender)
{
OnKeyStateChanged?.Invoke(sender);
}
/// <summary> 用于列出这个输入设备的所有输入控件实例 </summary>
/// <returns></returns>
protected abstract IEnumerable<InputControl> DefineControls();
public KeyBase FindKeyByKeyName(string keyName)
/// <summary> 通过控件名称,找到对应的控件 </summary>
/// <param name="keyName"></param>
/// <returns></returns>
public InputControl FindControlByName(string controlName)
{
m_keyMapper.TryGetValue(keyName, out var key);
m_controlMapper.TryGetValue(controlName, out var key);
return key;
}
/// <summary>
/// 输入设备的接口
/// 输入设备的抽象控件接口
/// </summary>
public abstract class KeyBase
public abstract class InputControl
{
public InputDevice HostDevice { get; internal set; }
/// <summary> 获取该键是否在当前调用帧被按下 </summary>
public abstract bool GetButtonDown();
/// <summary> 获取该键是否在当前调用帧被抬起 </summary>
public abstract bool GetButtonUp();
/// <summary> 获取该键是否在当前调用帧是否处于按下状态 </summary>
public abstract bool IsPressing();
/// <summary> 控件所属设备 </summary>
public InputDevice Device { get; internal set; }
public virtual Vector2 GetVector2() { throw new System.NotImplementedException(); }
public virtual float GetFlaot() { throw new System.NotImplementedException(); }
/// <summary> 获取该控件是否在当前调用帧被激发 </summary>
public abstract bool Start { get; }
/// <summary> 获取该控件是否在当前调用帧被释放 </summary>
public abstract bool Release { get; }
/// <summary> 获取该控件是否在当前调用帧是否处于活动状态 </summary>
public abstract bool Performing { get; }
/// <summary> 键名 </summary>
public abstract string KeyName { get; }
/// <summary> 获得该控件的以二维向量表达的值 </summary>
/// <returns></returns>
public abstract Vector2 GetVector2();
/// <summary> 获得该控件的以浮点数表达的值 </summary>
public abstract float GetFlaot();
/// <summary> 控件名,这个控件名称必须是唯一的 </summary>
public abstract string ControlName { get; }
public string GetPath()
{
return $"{HostDevice.UniqueName}/{KeyName}";
return $"{Device.UniqueName}/{ControlName}";
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using UnityEngine;
namespace AxibugEmuOnline.Client.InputDevices
{
@ -53,5 +54,26 @@ namespace AxibugEmuOnline.Client.InputDevices
{
OnDeviceConnected?.Invoke(connectDevice);
}
/// <summary>
/// 获取一个键盘设备的指定按键当前调用帧是否触发了按下动作
/// </summary>
/// <param name="keyboard">键盘设备实例,来自Resolver提供的设备实例</param>
/// <param name="key">键盘按键枚举值</param>
/// <returns></returns>
public abstract bool GetKeyDown(KeyBoard keyboard, KeyCode key);
/// <summary>
/// 获取一个键盘设备的指定按键当前调用帧是否触发了放开动作
/// </summary>
/// <param name="keyboard">键盘设备实例,来自Resolver提供的设备实例</param>
/// <param name="key">键盘按键枚举值</param>
public abstract bool GetKeyUp(KeyBoard keyboard, KeyCode key);
/// <summary>
/// 获取一个键盘设备的指定按键当前调用帧是否处于按下状态
/// </summary>
/// <param name="keyboard">键盘设备实例,来自Resolver提供的设备实例</param>
/// <param name="key">键盘按键枚举值</param>
public abstract bool GetKey(KeyBoard keyboard, KeyCode key);
}
}

View File

@ -1,22 +1,21 @@
#if ENABLE_INPUT_SYSTEM
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem.Controls;
using IP = UnityEngine.InputSystem.InputSystem;
using IPDevice = UnityEngine.InputSystem.InputDevice;
using IPKeyboard = UnityEngine.InputSystem.Keyboard;
namespace AxibugEmuOnline.Client.InputDevices
{
/// <summary> InputSystem对接 </summary>
public class InputSystemResolver : InputResolver
/// <summary> InputSystem对接 </summary>
public partial class InputSystemResolver : InputResolver
{
DualWayDictionary<IPDevice, InputDevice> m_devices = new DualWayDictionary<IPDevice, InputDevice>();
protected override void OnInit()
{
foreach (var device in IP.devices)
{
AddDevice(device);
}
foreach (var device in IP.devices) AddDevice(device);
IP.onDeviceChange += IP_onDeviceChange;
}
@ -60,6 +59,175 @@ namespace AxibugEmuOnline.Client.InputDevices
{
return m_devices.Values;
}
public override bool GetKeyDown(KeyBoard keyboard, KeyCode key)
{
if (m_devices.TryGetKey(keyboard, out var ipdev))
{
var ipKeyboard = ipdev as IPKeyboard;
if (ipKeyboard == null) return false;
var k = GetIPKeyboardKey(ipKeyboard, key);
return k.wasPressedThisFrame;
}
return false;
}
public override bool GetKeyUp(KeyBoard keyboard, KeyCode key)
{
if (m_devices.TryGetKey(keyboard, out var ipdev))
{
var ipKeyboard = ipdev as IPKeyboard;
if (ipKeyboard == null) return false;
var k = GetIPKeyboardKey(ipKeyboard, key);
return k.wasReleasedThisFrame;
}
return false;
}
public override bool GetKey(KeyBoard keyboard, KeyCode key)
{
if (m_devices.TryGetKey(keyboard, out var ipdev))
{
var ipKeyboard = ipdev as IPKeyboard;
if (ipKeyboard == null) return false;
var k = GetIPKeyboardKey(ipKeyboard, key);
return k.isPressed;
}
return false;
}
}
public partial class InputSystemResolver : InputResolver
{
static ButtonControl GetIPKeyboardKey(IPKeyboard keyboard, KeyCode key)
{
switch (key)
{
// 字母键A-Z
case KeyCode.A: return keyboard.aKey;
case KeyCode.B: return keyboard.bKey;
case KeyCode.C: return keyboard.cKey;
case KeyCode.D: return keyboard.dKey;
case KeyCode.E: return keyboard.eKey;
case KeyCode.F: return keyboard.fKey;
case KeyCode.G: return keyboard.gKey;
case KeyCode.H: return keyboard.hKey;
case KeyCode.I: return keyboard.iKey;
case KeyCode.J: return keyboard.jKey;
case KeyCode.K: return keyboard.kKey;
case KeyCode.L: return keyboard.lKey;
case KeyCode.M: return keyboard.mKey;
case KeyCode.N: return keyboard.nKey;
case KeyCode.O: return keyboard.oKey;
case KeyCode.P: return keyboard.pKey;
case KeyCode.Q: return keyboard.qKey;
case KeyCode.R: return keyboard.rKey;
case KeyCode.S: return keyboard.sKey;
case KeyCode.T: return keyboard.tKey;
case KeyCode.U: return keyboard.uKey;
case KeyCode.V: return keyboard.vKey;
case KeyCode.W: return keyboard.wKey;
case KeyCode.X: return keyboard.xKey;
case KeyCode.Y: return keyboard.yKey;
case KeyCode.Z: return keyboard.zKey;
// 数字键0-9
case KeyCode.Alpha0: return keyboard.digit0Key;
case KeyCode.Alpha1: return keyboard.digit1Key;
case KeyCode.Alpha2: return keyboard.digit2Key;
case KeyCode.Alpha3: return keyboard.digit3Key;
case KeyCode.Alpha4: return keyboard.digit4Key;
case KeyCode.Alpha5: return keyboard.digit5Key;
case KeyCode.Alpha6: return keyboard.digit6Key;
case KeyCode.Alpha7: return keyboard.digit7Key;
case KeyCode.Alpha8: return keyboard.digit8Key;
case KeyCode.Alpha9: return keyboard.digit9Key;
// 小键盘
case KeyCode.Keypad0: return keyboard.numpad0Key;
case KeyCode.Keypad1: return keyboard.numpad1Key;
case KeyCode.Keypad2: return keyboard.numpad2Key;
case KeyCode.Keypad3: return keyboard.numpad3Key;
case KeyCode.Keypad4: return keyboard.numpad4Key;
case KeyCode.Keypad5: return keyboard.numpad5Key;
case KeyCode.Keypad6: return keyboard.numpad6Key;
case KeyCode.Keypad7: return keyboard.numpad7Key;
case KeyCode.Keypad8: return keyboard.numpad8Key;
case KeyCode.Keypad9: return keyboard.numpad9Key;
case KeyCode.KeypadPeriod: return keyboard.numpadPeriodKey;
case KeyCode.KeypadDivide: return keyboard.numpadDivideKey;
case KeyCode.KeypadMultiply: return keyboard.numpadMultiplyKey;
case KeyCode.KeypadMinus: return keyboard.numpadMinusKey;
case KeyCode.KeypadPlus: return keyboard.numpadPlusKey;
case KeyCode.KeypadEnter: return keyboard.numpadEnterKey;
case KeyCode.KeypadEquals: return keyboard.numpadEqualsKey;
// 功能键F1-F15
case KeyCode.F1: return keyboard.f1Key;
case KeyCode.F2: return keyboard.f2Key;
case KeyCode.F3: return keyboard.f3Key;
case KeyCode.F4: return keyboard.f4Key;
case KeyCode.F5: return keyboard.f5Key;
case KeyCode.F6: return keyboard.f6Key;
case KeyCode.F7: return keyboard.f7Key;
case KeyCode.F8: return keyboard.f8Key;
case KeyCode.F9: return keyboard.f9Key;
case KeyCode.F10: return keyboard.f10Key;
case KeyCode.F11: return keyboard.f11Key;
case KeyCode.F12: return keyboard.f12Key;
// 方向键
case KeyCode.UpArrow: return keyboard.upArrowKey;
case KeyCode.DownArrow: return keyboard.downArrowKey;
case KeyCode.LeftArrow: return keyboard.leftArrowKey;
case KeyCode.RightArrow: return keyboard.rightArrowKey;
// 符号键
case KeyCode.Space: return keyboard.spaceKey;
case KeyCode.Backspace: return keyboard.backspaceKey;
case KeyCode.Tab: return keyboard.tabKey;
case KeyCode.Return: return keyboard.enterKey;
case KeyCode.Escape: return keyboard.escapeKey;
case KeyCode.LeftShift: return keyboard.leftShiftKey;
case KeyCode.RightShift: return keyboard.rightShiftKey;
case KeyCode.LeftControl: return keyboard.leftCtrlKey;
case KeyCode.RightControl: return keyboard.rightCtrlKey;
case KeyCode.LeftAlt: return keyboard.leftAltKey;
case KeyCode.RightAlt: return keyboard.rightAltKey;
case KeyCode.LeftCommand: return keyboard.leftCommandKey; // macOS Command键
case KeyCode.RightCommand: return keyboard.rightCommandKey;
case KeyCode.CapsLock: return keyboard.capsLockKey;
case KeyCode.Numlock: return keyboard.numLockKey;
case KeyCode.ScrollLock: return keyboard.scrollLockKey;
case KeyCode.Print: return keyboard.printScreenKey;
case KeyCode.Pause: return keyboard.pauseKey;
case KeyCode.Insert: return keyboard.insertKey;
case KeyCode.Home: return keyboard.homeKey;
case KeyCode.End: return keyboard.endKey;
case KeyCode.PageUp: return keyboard.pageUpKey;
case KeyCode.PageDown: return keyboard.pageDownKey;
case KeyCode.Delete: return keyboard.deleteKey;
case KeyCode.Comma: return keyboard.commaKey;
case KeyCode.Period: return keyboard.periodKey;
case KeyCode.Slash: return keyboard.slashKey;
case KeyCode.BackQuote: return keyboard.backquoteKey;
case KeyCode.Minus: return keyboard.minusKey;
case KeyCode.Equals: return keyboard.equalsKey;
case KeyCode.LeftBracket: return keyboard.leftBracketKey;
case KeyCode.RightBracket: return keyboard.rightBracketKey;
case KeyCode.Backslash: return keyboard.backslashKey;
case KeyCode.Semicolon: return keyboard.semicolonKey;
case KeyCode.Quote: return keyboard.quoteKey;
default:
throw new System.NotImplementedException($"Not Find KeyCode Mapper Code from {key}");
}
}
}
}
#endif

View File

@ -7,41 +7,38 @@ namespace AxibugEmuOnline.Client.InputDevices
public partial class KeyBoard : InputDevice
{
public override string UniqueName => nameof(KeyBoard);
public override bool Online => true;
public KeyBoard(InputResolver resolver) : base(resolver) { }
protected override IEnumerable<KeyBase> DefineKeys()
protected override IEnumerable<InputControl> DefineControls()
{
var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc) as KeyBase);
var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc) as InputControl);
return keys;
}
public class KeyboardKey : KeyBase
public class KeyboardKey : InputControl
{
internal KeyCode m_listenKey;
KeyCode m_keycode;
public override bool Start => Device.Resolver.GetKeyDown(Device as KeyBoard, m_keycode);
public override bool Release => Device.Resolver.GetKeyUp(Device as KeyBoard, m_keycode);
public override bool Performing => Device.Resolver.GetKey(Device as KeyBoard, m_keycode);
public KeyboardKey(KeyCode listenKey)
{
m_listenKey = listenKey;
m_keycode = listenKey;
}
public override bool GetButtonDown()
public override string ControlName => m_keycode.ToString();
public override Vector2 GetVector2()
{
return Input.GetKeyDown(m_listenKey);
return default(Vector2);
}
public override bool GetButtonUp()
public override float GetFlaot()
{
return Input.GetKeyUp(m_listenKey);
return Performing ? 1 : 0;
}
public override bool IsPressing()
{
return Input.GetKey(m_listenKey);
}
public override string KeyName => m_listenKey.ToString();
}
}