Little rewrite of HID input (#723)

* change hid sharedmem writing to use structures
This commit is contained in:
emmauss 2019-07-22 20:15:46 +03:00 committed by GitHub
parent 1f3a34dd7a
commit d254548548
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 682 additions and 409 deletions

View file

@ -0,0 +1,142 @@
using static Ryujinx.HLE.Input.Hid;
namespace Ryujinx.HLE.Input
{
public abstract class BaseController : IHidDevice
{
protected ControllerStatus HidControllerType;
protected ControllerId ControllerId;
private long _currentLayoutOffset;
private long _mainLayoutOffset;
protected long DeviceStateOffset => Offset + 0x4188;
protected Switch Device { get; }
public long Offset { get; private set; }
public bool Connected { get; protected set; }
public ControllerHeader Header { get; private set; }
public ControllerStateHeader CurrentStateHeader { get; private set; }
public ControllerDeviceState DeviceState { get; private set; }
public ControllerLayouts CurrentLayout { get; private set; }
public ControllerState LastInputState { get; set; }
public ControllerConnectionState ConnectionState { get; protected set; }
public BaseController(Switch device, ControllerStatus controllerType)
{
Device = device;
HidControllerType = controllerType;
}
protected void Initialize(
bool isHalf,
(NpadColor left, NpadColor right) bodyColors,
(NpadColor left, NpadColor right) buttonColors,
ControllerColorDescription singleColorDesc = 0,
ControllerColorDescription splitColorDesc = 0,
NpadColor singleBodyColor = 0,
NpadColor singleButtonColor = 0
)
{
Header = new ControllerHeader()
{
IsJoyConHalf = isHalf ? 1 : 0,
LeftBodyColor = bodyColors.left,
LeftButtonColor = buttonColors.left,
RightBodyColor = bodyColors.right,
RightButtonColor = buttonColors.right,
Status = HidControllerType,
SingleBodyColor = singleBodyColor,
SingleButtonColor = singleButtonColor,
SplitColorDescription = splitColorDesc,
SingleColorDescription = singleColorDesc,
};
CurrentStateHeader = new ControllerStateHeader
{
EntryCount = HidEntryCount,
MaxEntryCount = HidEntryCount - 1,
CurrentEntryIndex = -1
};
DeviceState = new ControllerDeviceState()
{
PowerInfo0BatteryState = BatteryState.Percent100,
PowerInfo1BatteryState = BatteryState.Percent100,
PowerInfo2BatteryState = BatteryState.Percent100,
DeviceType = ControllerDeviceType.NPadLeftController | ControllerDeviceType.NPadRightController,
DeviceFlags = DeviceFlags.PowerInfo0Connected
| DeviceFlags.PowerInfo1Connected
| DeviceFlags.PowerInfo2Connected
};
LastInputState = new ControllerState()
{
SamplesTimestamp = -1,
SamplesTimestamp2 = -1
};
}
public virtual void Connect(ControllerId controllerId)
{
ControllerId = controllerId;
Offset = Device.Hid.HidPosition + HidControllersOffset + (int)controllerId * HidControllerSize;
_mainLayoutOffset = Offset + HidControllerHeaderSize
+ ((int)ControllerLayouts.Main * HidControllerLayoutsSize);
Device.Memory.FillWithZeros(Offset, 0x5000);
Device.Memory.WriteStruct(Offset, Header);
Device.Memory.WriteStruct(DeviceStateOffset, DeviceState);
Connected = true;
}
public void SetLayout(ControllerLayouts controllerLayout)
{
CurrentLayout = controllerLayout;
_currentLayoutOffset = Offset + HidControllerHeaderSize
+ ((int)controllerLayout * HidControllerLayoutsSize);
}
public void SendInput(
ControllerButtons buttons,
JoystickPosition leftStick,
JoystickPosition rightStick)
{
ControllerState currentInput = new ControllerState()
{
SamplesTimestamp = (long)LastInputState.SamplesTimestamp + 1,
SamplesTimestamp2 = (long)LastInputState.SamplesTimestamp + 1,
ButtonState = buttons,
ConnectionState = ConnectionState,
LeftStick = leftStick,
RightStick = rightStick
};
ControllerStateHeader newInputStateHeader = new ControllerStateHeader
{
EntryCount = HidEntryCount,
MaxEntryCount = HidEntryCount - 1,
CurrentEntryIndex = (CurrentStateHeader.CurrentEntryIndex + 1) % HidEntryCount,
Timestamp = GetTimestamp(),
};
Device.Memory.WriteStruct(_currentLayoutOffset, newInputStateHeader);
Device.Memory.WriteStruct(_mainLayoutOffset, newInputStateHeader);
long currentInputStateOffset = HidControllersLayoutHeaderSize
+ newInputStateHeader.CurrentEntryIndex * HidControllersInputEntrySize;
Device.Memory.WriteStruct(_currentLayoutOffset + currentInputStateOffset, currentInput);
Device.Memory.WriteStruct(_mainLayoutOffset + currentInputStateOffset, currentInput);
LastInputState = currentInput;
CurrentStateHeader = newInputStateHeader;
}
}
}

View file

@ -0,0 +1,68 @@
namespace Ryujinx.HLE.Input
{
public class NpadController : BaseController
{
private (NpadColor Left, NpadColor Right) _npadBodyColors;
private (NpadColor Left, NpadColor Right) _npadButtonColors;
private bool _isHalf;
public NpadController(
ControllerStatus controllerStatus,
Switch device,
(NpadColor, NpadColor) npadBodyColors,
(NpadColor, NpadColor) npadButtonColors) : base(device, controllerStatus)
{
_npadBodyColors = npadBodyColors;
_npadButtonColors = npadButtonColors;
}
public override void Connect(ControllerId controllerId)
{
if (HidControllerType != ControllerStatus.NpadLeft && HidControllerType != ControllerStatus.NpadRight)
{
_isHalf = false;
}
ConnectionState = ControllerConnectionState.ControllerStateConnected;
if (controllerId == ControllerId.ControllerHandheld)
ConnectionState |= ControllerConnectionState.ControllerStateWired;
ControllerColorDescription singleColorDesc =
ControllerColorDescription.ColorDescriptionColorsNonexistent;
ControllerColorDescription splitColorDesc = 0;
NpadColor singleBodyColor = NpadColor.Black;
NpadColor singleButtonColor = NpadColor.Black;
Initialize(_isHalf,
(_npadBodyColors.Left, _npadBodyColors.Right),
(_npadButtonColors.Left, _npadButtonColors.Right),
singleColorDesc,
splitColorDesc,
singleBodyColor,
singleButtonColor );
base.Connect(controllerId);
var _currentLayout = ControllerLayouts.HandheldJoined;
switch (HidControllerType)
{
case ControllerStatus.NpadLeft:
_currentLayout = ControllerLayouts.Left;
break;
case ControllerStatus.NpadRight:
_currentLayout = ControllerLayouts.Right;
break;
case ControllerStatus.NpadPair:
_currentLayout = ControllerLayouts.Joined;
break;
}
SetLayout(_currentLayout);
}
}
}

View file

@ -0,0 +1,42 @@
namespace Ryujinx.HLE.Input
{
public class ProController : BaseController
{
private bool _wired = false;
private NpadColor _bodyColor;
private NpadColor _buttonColor;
public ProController(Switch device,
NpadColor bodyColor,
NpadColor buttonColor) : base(device, ControllerStatus.ProController)
{
_wired = true;
_bodyColor = bodyColor;
_buttonColor = buttonColor;
}
public override void Connect(ControllerId controllerId)
{
ControllerColorDescription singleColorDesc =
ControllerColorDescription.ColorDescriptionColorsNonexistent;
ControllerColorDescription splitColorDesc = 0;
ConnectionState = ControllerConnectionState.ControllerStateConnected | ControllerConnectionState.ControllerStateWired;
Initialize(false,
(0, 0),
(0, 0),
singleColorDesc,
splitColorDesc,
_bodyColor,
_buttonColor);
base.Connect(controllerId);
SetLayout(ControllerLayouts.ProController);
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.HLE.Input
{
public enum BatteryState : int
{
// TODO : Check if these are the correct states
Percent0 = 0,
Percent25 = 1,
Percent50 = 2,
Percent75 = 3,
Percent100 = 4
}
}

View file

@ -0,0 +1,35 @@
using System;
namespace Ryujinx.HLE.Input
{
[Flags]
public enum ControllerButtons : long
{
A = 1 << 0,
B = 1 << 1,
X = 1 << 2,
Y = 1 << 3,
StickLeft = 1 << 4,
StickRight = 1 << 5,
L = 1 << 6,
R = 1 << 7,
Zl = 1 << 8,
Zr = 1 << 9,
Plus = 1 << 10,
Minus = 1 << 11,
DpadLeft = 1 << 12,
DpadUp = 1 << 13,
DPadRight = 1 << 14,
DpadDown = 1 << 15,
LStickLeft = 1 << 16,
LStickUp = 1 << 17,
LStickRight = 1 << 18,
LStickDown = 1 << 19,
RStickLeft = 1 << 20,
RStickUp = 1 << 21,
RStickRight = 1 << 22,
RStickDown = 1 << 23,
Sl = 1 << 24,
Sr = 1 << 25
}
}

View file

@ -0,0 +1,10 @@
using System;
namespace Ryujinx.HLE.Input
{
[Flags]
public enum ControllerColorDescription : int
{
ColorDescriptionColorsNonexistent = (1 << 1)
}
}

View file

@ -0,0 +1,11 @@
using System;
namespace Ryujinx.HLE.Input
{
[Flags]
public enum ControllerConnectionState : long
{
ControllerStateConnected = (1 << 0),
ControllerStateWired = (1 << 1)
}
}

View file

@ -0,0 +1,18 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.Input
{
[StructLayout(LayoutKind.Sequential)]
public unsafe struct ControllerDeviceState
{
public ControllerDeviceType DeviceType;
public int Padding;
public DeviceFlags DeviceFlags;
public int UnintendedHomeButtonInputProtectionEnabled;
public BatteryState PowerInfo0BatteryState;
public BatteryState PowerInfo1BatteryState;
public BatteryState PowerInfo2BatteryState;
public fixed byte ControllerMac[16];
public fixed byte ControllerMac2[16];
}
}

View file

@ -0,0 +1,12 @@
using System;
namespace Ryujinx.HLE.Input
{
[Flags]
public enum ControllerDeviceType : int
{
ProController = 1 << 0,
NPadLeftController = 1 << 4,
NPadRightController = 1 << 5,
}
}

View file

@ -0,0 +1,19 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.Input
{
[StructLayout(LayoutKind.Sequential)]
public struct ControllerHeader
{
public ControllerStatus Status;
public int IsJoyConHalf;
public ControllerColorDescription SingleColorDescription;
public NpadColor SingleBodyColor;
public NpadColor SingleButtonColor;
public ControllerColorDescription SplitColorDescription;
public NpadColor RightBodyColor;
public NpadColor RightButtonColor;
public NpadColor LeftBodyColor;
public NpadColor LeftButtonColor;
}
}

View file

@ -0,0 +1,16 @@
namespace Ryujinx.HLE.Input
{
public enum ControllerId
{
ControllerPlayer1 = 0,
ControllerPlayer2 = 1,
ControllerPlayer3 = 2,
ControllerPlayer4 = 3,
ControllerPlayer5 = 4,
ControllerPlayer6 = 5,
ControllerPlayer7 = 6,
ControllerPlayer8 = 7,
ControllerHandheld = 8,
ControllerUnknown = 9
}
}

View file

@ -0,0 +1,13 @@
namespace Ryujinx.HLE.Input
{
public enum ControllerLayouts
{
ProController = 0,
HandheldJoined = 1,
Joined = 2,
Left = 3,
Right = 4,
MainNoAnalog = 5,
Main = 6
}
}

View file

@ -0,0 +1,15 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.Input
{
[StructLayout(LayoutKind.Sequential)]
public struct ControllerState
{
public long SamplesTimestamp;
public long SamplesTimestamp2;
public ControllerButtons ButtonState;
public JoystickPosition LeftStick;
public JoystickPosition RightStick;
public ControllerConnectionState ConnectionState;
}
}

View file

@ -0,0 +1,13 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.Input
{
[StructLayout(LayoutKind.Sequential)]
public struct ControllerStateHeader
{
public long Timestamp;
public long EntryCount;
public long CurrentEntryIndex;
public long MaxEntryCount;
}
}

View file

@ -0,0 +1,14 @@
using System;
namespace Ryujinx.HLE.Input
{
[Flags]
public enum ControllerStatus : int
{
ProController = 1 << 0,
Handheld = 1 << 1,
NpadPair = 1 << 2,
NpadLeft = 1 << 3,
NpadRight = 1 << 4
}
}

View file

@ -0,0 +1,22 @@
using System;
namespace Ryujinx.HLE.Input
{
[Flags]
public enum DeviceFlags : long
{
PowerInfo0Charging = 1 << 0,
PowerInfo1Charging = 1 << 1,
PowerInfo2Charging = 1 << 2,
PowerInfo0Connected = 1 << 3,
PowerInfo1Connected = 1 << 4,
PowerInfo2Connected = 1 << 5,
UnsupportedButtonPressedNpadSystem = 1 << 9,
UnsupportedButtonPressedNpadSystemExt = 1 << 10,
AbxyButtonOriented = 1 << 11,
SlSrButtonOriented = 1 << 12,
PlusButtonCapability = 1 << 13,
MinusButtonCapability = 1 << 14,
DirectionalButtonsSupported = 1 << 15
}
}

View file

@ -0,0 +1,10 @@
using System;
namespace Ryujinx.HLE.Input
{
[Flags]
public enum HotkeyButtons
{
ToggleVSync = 1 << 0,
}
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.HLE.Input
{
public struct JoystickPosition
{
public int Dx;
public int Dy;
}
}

View file

@ -0,0 +1,23 @@
namespace Ryujinx.HLE.Input
{
public enum NpadColor : int //Thanks to CTCaer
{
Black = 0,
BodyGrey = 0x828282,
BodyNeonBlue = 0x0AB9E6,
BodyNeonRed = 0xFF3C28,
BodyNeonYellow = 0xE6FF00,
BodyNeonPink = 0xFF3278,
BodyNeonGreen = 0x1EDC00,
BodyRed = 0xE10F00,
ButtonsGrey = 0x0F0F0F,
ButtonsNeonBlue = 0x001E1E,
ButtonsNeonRed = 0x1E0A0A,
ButtonsNeonYellow = 0x142800,
ButtonsNeonPink = 0x28001E,
ButtonsNeonGreen = 0x002800,
ButtonsRed = 0x280A0A
}
}