diff options
Diffstat (limited to 'Ryujinx.HLE/Input/Controller')
19 files changed, 503 insertions, 0 deletions
diff --git a/Ryujinx.HLE/Input/Controller/BaseController.cs b/Ryujinx.HLE/Input/Controller/BaseController.cs new file mode 100644 index 00000000..dfd54a83 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/BaseController.cs @@ -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; + } + } +} diff --git a/Ryujinx.HLE/Input/Controller/NpadController.cs b/Ryujinx.HLE/Input/Controller/NpadController.cs new file mode 100644 index 00000000..b4304b8f --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/NpadController.cs @@ -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); + } + } +} diff --git a/Ryujinx.HLE/Input/Controller/ProController.cs b/Ryujinx.HLE/Input/Controller/ProController.cs new file mode 100644 index 00000000..ae574260 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/ProController.cs @@ -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); + } + } +} diff --git a/Ryujinx.HLE/Input/Controller/Types/BatteryState.cs b/Ryujinx.HLE/Input/Controller/Types/BatteryState.cs new file mode 100644 index 00000000..4279d7a0 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/BatteryState.cs @@ -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 + } +} diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerButtons.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerButtons.cs new file mode 100644 index 00000000..879257f2 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/ControllerButtons.cs @@ -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 + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs new file mode 100644 index 00000000..c31f41a3 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs @@ -0,0 +1,10 @@ +using System; + +namespace Ryujinx.HLE.Input +{ + [Flags] + public enum ControllerColorDescription : int + { + ColorDescriptionColorsNonexistent = (1 << 1) + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs new file mode 100644 index 00000000..526da1ff --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs @@ -0,0 +1,11 @@ +using System; + +namespace Ryujinx.HLE.Input +{ + [Flags] + public enum ControllerConnectionState : long + { + ControllerStateConnected = (1 << 0), + ControllerStateWired = (1 << 1) + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceState.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceState.cs new file mode 100644 index 00000000..45895a1e --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceState.cs @@ -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]; + } +} diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceType.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceType.cs new file mode 100644 index 00000000..8043d8a0 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceType.cs @@ -0,0 +1,12 @@ +using System; + +namespace Ryujinx.HLE.Input +{ + [Flags] + public enum ControllerDeviceType : int + { + ProController = 1 << 0, + NPadLeftController = 1 << 4, + NPadRightController = 1 << 5, + } +} diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerHeader.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerHeader.cs new file mode 100644 index 00000000..cbb5b6f5 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/ControllerHeader.cs @@ -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; + } +} diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerId.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerId.cs new file mode 100644 index 00000000..c82056c6 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/ControllerId.cs @@ -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 + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerLayouts.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerLayouts.cs new file mode 100644 index 00000000..fedc0399 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/ControllerLayouts.cs @@ -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 + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerState.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerState.cs new file mode 100644 index 00000000..4847438d --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/ControllerState.cs @@ -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; + } +} diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerStateHeader.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerStateHeader.cs new file mode 100644 index 00000000..f885c00c --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/ControllerStateHeader.cs @@ -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; + } +} diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerStatus.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerStatus.cs new file mode 100644 index 00000000..9444d7b0 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/ControllerStatus.cs @@ -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 + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/Input/Controller/Types/DeviceFlags.cs b/Ryujinx.HLE/Input/Controller/Types/DeviceFlags.cs new file mode 100644 index 00000000..53913175 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/DeviceFlags.cs @@ -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 + } +} diff --git a/Ryujinx.HLE/Input/Controller/Types/HotkeyButtons.cs b/Ryujinx.HLE/Input/Controller/Types/HotkeyButtons.cs new file mode 100644 index 00000000..be76ee1e --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/HotkeyButtons.cs @@ -0,0 +1,10 @@ +using System; + +namespace Ryujinx.HLE.Input +{ + [Flags] + public enum HotkeyButtons + { + ToggleVSync = 1 << 0, + } +} diff --git a/Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs b/Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs new file mode 100644 index 00000000..1442bc60 --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.Input +{ + public struct JoystickPosition + { + public int Dx; + public int Dy; + } +}
\ No newline at end of file diff --git a/Ryujinx.HLE/Input/Controller/Types/NpadColor.cs b/Ryujinx.HLE/Input/Controller/Types/NpadColor.cs new file mode 100644 index 00000000..a60f94aa --- /dev/null +++ b/Ryujinx.HLE/Input/Controller/Types/NpadColor.cs @@ -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 + } +}
\ No newline at end of file |
