修复xmb键位映射问题,优化摇杆类控制设备的上下左右方向判断逻辑,并加入死区机制

This commit is contained in:
Alienjack 2025-09-10 22:38:08 +08:00
parent 592d76a302
commit d7671fa66e
3 changed files with 187 additions and 62 deletions

View File

@ -21,6 +21,13 @@ public abstract class EmuCoreBinder<T> : InternalEmuCoreBinder,
IDeviceBinder<T, SwitchJoyCon_D> IDeviceBinder<T, SwitchJoyCon_D>
where T : Enum where T : Enum
{ {
/// <summary>
/// 忽略输入设备的独占属性
/// false:标记为独占的设备Exclusive==true只能绑定到一个控制器上
/// true:设备可以被绑定到所有控制器上,无视设备的独占属性
/// </summary>
protected virtual bool IgnoreInputDeviceExclusive => false;
//每一个实例代表一个对应模拟器平台的控制器索引 //每一个实例代表一个对应模拟器平台的控制器索引
List<ControllerBinder> m_controllerBinders = new List<ControllerBinder>(); List<ControllerBinder> m_controllerBinders = new List<ControllerBinder>();
@ -37,7 +44,7 @@ public abstract class EmuCoreBinder<T> : InternalEmuCoreBinder,
{ {
foreach (var binding in m_controllerBinders) foreach (var binding in m_controllerBinders)
{ {
if (device.Exclusive && GetRegistedBinder(device) != null) continue; if (!CheckDeviceCanBind(device)) break;
binding.RegistInputDevice(device); binding.RegistInputDevice(device);
} }
@ -64,11 +71,20 @@ public abstract class EmuCoreBinder<T> : InternalEmuCoreBinder,
{ {
foreach (var binding in m_controllerBinders) foreach (var binding in m_controllerBinders)
{ {
if (connectDevice.Exclusive && GetRegistedBinder(connectDevice) != null) continue; if (!CheckDeviceCanBind(connectDevice)) return;
binding.RegistInputDevice(connectDevice); binding.RegistInputDevice(connectDevice);
} }
} }
private bool CheckDeviceCanBind(InputDevice_D device)
{
if (IgnoreInputDeviceExclusive) return true;
if (!device.Exclusive) return true;
//当一个输入设备的Exclusive为true时只能绑定到一个控制器
return GetRegistedBinder(device) == null;
}
private void InputDevicesMgr_OnDeviceLost(InputDevice_D lostDevice) private void InputDevicesMgr_OnDeviceLost(InputDevice_D lostDevice)
{ {
foreach (var binding in m_controllerBinders) foreach (var binding in m_controllerBinders)

View File

@ -1,10 +1,12 @@
using AxibugEmuOnline.Client.InputDevices; using AxibugEmuOnline.Client.InputDevices;
using AxibugProtobuf; using AxibugProtobuf;
using static AxibugEmuOnline.Client.NesControllerMapper;
namespace AxibugEmuOnline.Client namespace AxibugEmuOnline.Client
{ {
public class XMBKeyBinding : EmuCoreBinder<EnumCommand> public class XMBKeyBinding : EmuCoreBinder<EnumCommand>
{ {
protected override bool IgnoreInputDeviceExclusive => true;
public override RomPlatformType Platform => RomPlatformType.Invalid; public override RomPlatformType Platform => RomPlatformType.Invalid;
public override int ControllerCount => 2; public override int ControllerCount => 2;
@ -39,6 +41,9 @@ namespace AxibugEmuOnline.Client
} }
public override void Bind(DualShockController_D device, ControllerBinder controller) public override void Bind(DualShockController_D device, ControllerBinder controller)
{ {
switch (controller.ControllerIndex)
{
case 0:
controller.SetBinding(EnumCommand.Back, device.Circle, 0); controller.SetBinding(EnumCommand.Back, device.Circle, 0);
controller.SetBinding(EnumCommand.Enter, device.Cross, 0); controller.SetBinding(EnumCommand.Enter, device.Cross, 0);
controller.SetBinding(EnumCommand.OptionMenu, device.Options, 0); controller.SetBinding(EnumCommand.OptionMenu, device.Options, 0);
@ -51,9 +56,18 @@ namespace AxibugEmuOnline.Client
controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1); controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1);
controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1); controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1);
controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1); controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1);
break;
case 1:
controller.SetBinding(EnumCommand.OptionMenu, device.TouchpadBtn, 0);
controller.SetBinding(EnumCommand.OptionMenu, device.R3, 1);
break;
}
} }
public override void Bind(GamePad_D device, ControllerBinder controller) public override void Bind(GamePad_D device, ControllerBinder controller)
{ {
switch (controller.ControllerIndex)
{
case 0:
controller.SetBinding(EnumCommand.Back, device.East, 0); controller.SetBinding(EnumCommand.Back, device.East, 0);
controller.SetBinding(EnumCommand.Enter, device.South, 0); controller.SetBinding(EnumCommand.Enter, device.South, 0);
controller.SetBinding(EnumCommand.OptionMenu, device.Start, 0); controller.SetBinding(EnumCommand.OptionMenu, device.Start, 0);
@ -66,9 +80,18 @@ namespace AxibugEmuOnline.Client
controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1); controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1);
controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1); controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1);
controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1); controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1);
break;
case 1:
controller.SetBinding(EnumCommand.OptionMenu, device.RightStickPress, 0);
break;
}
} }
public override void Bind(PSVController_D device, ControllerBinder controller) public override void Bind(PSVController_D device, ControllerBinder controller)
{ {
switch (controller.ControllerIndex)
{
case 0:
controller.SetBinding(EnumCommand.Back, device.Circle, 0); controller.SetBinding(EnumCommand.Back, device.Circle, 0);
controller.SetBinding(EnumCommand.Enter, device.Cross, 0); controller.SetBinding(EnumCommand.Enter, device.Cross, 0);
controller.SetBinding(EnumCommand.OptionMenu, device.Start, 0); controller.SetBinding(EnumCommand.OptionMenu, device.Start, 0);
@ -81,9 +104,18 @@ namespace AxibugEmuOnline.Client
controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1); controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1);
controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1); controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1);
controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1); controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1);
break;
case 1:
controller.SetBinding(EnumCommand.OptionMenu, device.Triangle, 0);
break;
}
} }
public override void Bind(XboxController_D device, ControllerBinder controller) public override void Bind(XboxController_D device, ControllerBinder controller)
{ {
switch (controller.ControllerIndex)
{
case 0:
controller.SetBinding(EnumCommand.Back, device.B, 0); controller.SetBinding(EnumCommand.Back, device.B, 0);
controller.SetBinding(EnumCommand.Enter, device.A, 0); controller.SetBinding(EnumCommand.Enter, device.A, 0);
controller.SetBinding(EnumCommand.OptionMenu, device.Menu, 0); controller.SetBinding(EnumCommand.OptionMenu, device.Menu, 0);
@ -96,9 +128,18 @@ namespace AxibugEmuOnline.Client
controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1); controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1);
controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1); controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1);
controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1); controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1);
break;
case 1:
controller.SetBinding(EnumCommand.OptionMenu, device.RightStickPress, 0);
break;
}
} }
public override void Bind(ScreenGamepad_D device, ControllerBinder controller) public override void Bind(ScreenGamepad_D device, ControllerBinder controller)
{ {
switch (controller.ControllerIndex)
{
case 0:
controller.SetBinding(EnumCommand.Back, device.BTN_A, 0); controller.SetBinding(EnumCommand.Back, device.BTN_A, 0);
controller.SetBinding(EnumCommand.Enter, device.BTN_B, 0); controller.SetBinding(EnumCommand.Enter, device.BTN_B, 0);
controller.SetBinding(EnumCommand.OptionMenu, device.OPTION_1, 0); controller.SetBinding(EnumCommand.OptionMenu, device.OPTION_1, 0);
@ -111,6 +152,11 @@ namespace AxibugEmuOnline.Client
controller.SetBinding(EnumCommand.SelectItemLeft, device.JOYSTICK.Left, 1); controller.SetBinding(EnumCommand.SelectItemLeft, device.JOYSTICK.Left, 1);
controller.SetBinding(EnumCommand.SelectItemRight, device.JOYSTICK.Right, 1); controller.SetBinding(EnumCommand.SelectItemRight, device.JOYSTICK.Right, 1);
controller.SetBinding(EnumCommand.SelectItemUp, device.JOYSTICK.Up, 1); controller.SetBinding(EnumCommand.SelectItemUp, device.JOYSTICK.Up, 1);
break;
case 1:
controller.SetBinding(EnumCommand.OptionMenu, device.HOME, 0);
break;
}
} }
public override void Bind(SwitchJoyCon_D device, ControllerBinder controller) public override void Bind(SwitchJoyCon_D device, ControllerBinder controller)
{ {
@ -131,7 +177,7 @@ namespace AxibugEmuOnline.Client
controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1); controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1);
break; break;
case 1://游戏中UI控制 case 1://游戏中UI控制
controller.SetBinding(EnumCommand.OptionMenu, device.Y, 0); controller.SetBinding(EnumCommand.OptionMenu, device.RightStickPress, 0);
break; break;
} }
} }

View File

@ -18,20 +18,22 @@ namespace AxibugEmuOnline.Client.InputDevices
{ {
var axis = GetVector2(); var axis = GetVector2();
Up.m_performing = axis.y > 0f; var dir = GetDirection(axis, 0.15f);
Up.m_performing = dir == Direction.Up;
Up.Update(); Up.Update();
Down.m_performing = axis.y < 0f; Down.m_performing = dir == Direction.Down;
Down.Update(); Down.Update();
Left.m_performing = axis.x < 0f; Left.m_performing = dir == Direction.Left;
Left.Update(); Left.Update();
Right.m_performing = axis.x > 0f; Right.m_performing = dir == Direction.Right;
Right.Update(); Right.Update();
} }
public class VirtualButton : InputControl_C public class VirtualButton : InputControl_C
{ {
internal bool m_performing; internal bool m_performing;
@ -53,5 +55,66 @@ namespace AxibugEmuOnline.Client.InputDevices
return Performing ? 1 : 0; return Performing ? 1 : 0;
} }
} }
enum Direction
{
None,
Up,
Down,
Left,
Right
}
static Direction GetDirection(Vector2 input, float deadzone)
{
// 检查死区:如果点在死区半径内,返回无
if (input.magnitude <= deadzone)
{
return Direction.None;
}
// 标准化向量(确保在单位圆上)
Vector2 normalized = input.normalized;
// 计算点与四个方向基准向量的点积
float dotUp = Vector2.Dot(normalized, Vector2.up); // (0, 1)
float dotDown = Vector2.Dot(normalized, Vector2.down); // (0, -1)
float dotRight = Vector2.Dot(normalized, Vector2.right); // (1, 0)
float dotLeft = Vector2.Dot(normalized, Vector2.left); // (-1, 0)
// 找出最大点积对应的方向
Direction bestDirection = Direction.None;
float maxDot = -1f; // 初始化为最小值
// 检查上方向
if (dotUp > maxDot)
{
maxDot = dotUp;
bestDirection = Direction.Up;
}
// 检查下方向
if (dotDown > maxDot)
{
maxDot = dotDown;
bestDirection = Direction.Down;
}
// 检查右方向
if (dotRight > maxDot)
{
maxDot = dotRight;
bestDirection = Direction.Right;
}
// 检查左方向
if (dotLeft > maxDot)
{
bestDirection = Direction.Left;
}
return bestDirection;
}
} }
} }