diff --git a/Ryujinx.HLE/DeviceMemory.cs b/Ryujinx.HLE/DeviceMemory.cs index 38864bc2..22945b83 100644 --- a/Ryujinx.HLE/DeviceMemory.cs +++ b/Ryujinx.HLE/DeviceMemory.cs @@ -1,6 +1,7 @@ using ARMeilleure.Memory; using System; using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; namespace Ryujinx.HLE { @@ -64,6 +65,11 @@ namespace Ryujinx.HLE return Marshal.PtrToStructure((IntPtr)(_ramPtr + position)); } + public unsafe ref T GetStructRef(long position) + { + return ref Unsafe.AsRef((void*)(IntPtr)(_ramPtr + position)); + } + public void WriteSByte(long position, sbyte value) { WriteByte(position, (byte)value); diff --git a/Ryujinx.HLE/Exceptions/InvalidStructLayoutException.cs b/Ryujinx.HLE/Exceptions/InvalidStructLayoutException.cs new file mode 100644 index 00000000..f4ccb7ba --- /dev/null +++ b/Ryujinx.HLE/Exceptions/InvalidStructLayoutException.cs @@ -0,0 +1,15 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Ryujinx.HLE.Exceptions +{ + public class InvalidStructLayoutException : Exception + { + static readonly Type _structType = typeof(T); + + public InvalidStructLayoutException(string message) : base(message) {} + + public InvalidStructLayoutException(int expectedSize) : + base($"Type {_structType.Name} has the wrong size. Expected: {expectedSize} bytes, Got: {Unsafe.SizeOf()} bytes") {} + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Applets/AppletManager.cs b/Ryujinx.HLE/HOS/Applets/AppletManager.cs index e7314540..1cba9ec9 100644 --- a/Ryujinx.HLE/HOS/Applets/AppletManager.cs +++ b/Ryujinx.HLE/HOS/Applets/AppletManager.cs @@ -13,6 +13,7 @@ namespace Ryujinx.HLE.HOS.Applets _appletMapping = new Dictionary { { AppletId.PlayerSelect, typeof(PlayerSelectApplet) }, + { AppletId.Controller, typeof(ControllerApplet) }, { AppletId.SoftwareKeyboard, typeof(SoftwareKeyboardApplet) } }; } diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs new file mode 100644 index 00000000..5bfffdb2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs @@ -0,0 +1,114 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.Services.Hid; +using Ryujinx.HLE.HOS.Services.Am.AppletAE; + +using static Ryujinx.HLE.HOS.Services.Hid.HidServer.HidUtils; + +namespace Ryujinx.HLE.HOS.Applets +{ + internal class ControllerApplet : IApplet + { + private Horizon _system; + + private AppletSession _normalSession; + + public event EventHandler AppletStateChanged; + + public ControllerApplet(Horizon system) + { + _system = system; + } + + unsafe public ResultCode Start(AppletSession normalSession, + AppletSession interactiveSession) + { + _normalSession = normalSession; + + byte[] launchParams = _normalSession.Pop(); + byte[] controllerSupportArgPrivate = _normalSession.Pop(); + ControllerSupportArgPrivate privateArg = IApplet.ReadStruct(controllerSupportArgPrivate); + + Logger.PrintStub(LogClass.ServiceHid, $"ControllerApplet ArgPriv {privateArg.PrivateSize} {privateArg.ArgSize} {privateArg.Mode}" + + $"HoldType:{(NpadJoyHoldType)privateArg.NpadJoyHoldType} StyleSets:{(ControllerType)privateArg.NpadStyleSet}"); + + if (privateArg.Mode != ControllerSupportMode.ShowControllerSupport) + { + _normalSession.Push(BuildResponse()); // Dummy response for other modes + AppletStateChanged?.Invoke(this, null); + + return ResultCode.Success; + } + + byte[] controllerSupportArg = _normalSession.Pop(); + + ControllerSupportArgHeader argHeader; + + if (privateArg.ArgSize == Marshal.SizeOf()) + { + ControllerSupportArg arg = IApplet.ReadStruct(controllerSupportArg); + argHeader = arg.Header; + // Read enable text here? + } + else + { + Logger.PrintStub(LogClass.ServiceHid, $"Unknown revision of ControllerSupportArg."); + + argHeader = IApplet.ReadStruct(controllerSupportArg); // Read just the header + } + + Logger.PrintStub(LogClass.ServiceHid, $"ControllerApplet Arg {argHeader.PlayerCountMin} {argHeader.PlayerCountMax} {argHeader.EnableTakeOverConnection} {argHeader.EnableSingleMode}"); + + // Currently, the only purpose of this applet is to help + // choose the primary input controller for the game + // TODO: Ideally should hook back to HID.Controller. When applet is called, can choose appropriate controller and attach to appropriate id. + if (argHeader.PlayerCountMin > 1) + { + Logger.PrintWarning(LogClass.ServiceHid, "More than one controller was requested."); + } + + ControllerSupportResultInfo result = new ControllerSupportResultInfo + { + PlayerCount = 1, + SelectedId = (uint)GetNpadIdTypeFromIndex(_system.Device.Hid.Npads.PrimaryController) + }; + + Logger.PrintStub(LogClass.ServiceHid, $"ControllerApplet ReturnResult {result.PlayerCount} {result.SelectedId}"); + + _normalSession.Push(BuildResponse(result)); + AppletStateChanged?.Invoke(this, null); + + return ResultCode.Success; + } + + public ResultCode GetResult() + { + return ResultCode.Success; + } + + private byte[] BuildResponse(ControllerSupportResultInfo result) + { + using (MemoryStream stream = new MemoryStream()) + using (BinaryWriter writer = new BinaryWriter(stream)) + { + writer.Write(MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref result, Unsafe.SizeOf()))); + + return stream.ToArray(); + } + } + + private byte[] BuildResponse() + { + using (MemoryStream stream = new MemoryStream()) + using (BinaryWriter writer = new BinaryWriter(stream)) + { + writer.Write((ulong)ResultCode.Success); + + return stream.ToArray(); + } + } + } +} diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArg.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArg.cs new file mode 100644 index 00000000..62ebff30 --- /dev/null +++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArg.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Applets +{ + // (8.0.0+ version) + unsafe struct ControllerSupportArg + { + public ControllerSupportArgHeader Header; + public fixed uint IdentificationColor[8]; + public byte EnableExplainText; + public fixed byte ExplainText[8 * 0x81]; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgHeader.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgHeader.cs new file mode 100644 index 00000000..dfe26093 --- /dev/null +++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgHeader.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Applets +{ + struct ControllerSupportArgHeader + { + public sbyte PlayerCountMin; + public sbyte PlayerCountMax; + public byte EnableTakeOverConnection; + public byte EnableLeftJustify; + public byte EnablePermitJoyDual; + public byte EnableSingleMode; + public byte EnableIdentificationColor; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgPrivate.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgPrivate.cs new file mode 100644 index 00000000..2e393de4 --- /dev/null +++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArgPrivate.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.HLE.HOS.Applets +{ + struct ControllerSupportArgPrivate + { + public uint PrivateSize; + public uint ArgSize; + public byte Flag0; + public byte Flag1; + public ControllerSupportMode Mode; + public byte ControllerSupportCaller; + public uint NpadStyleSet; + public uint NpadJoyHoldType; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportMode.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportMode.cs new file mode 100644 index 00000000..9496c1dd --- /dev/null +++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportMode.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Applets +{ + enum ControllerSupportMode : byte + { + ShowControllerSupport = 0, + ShowControllerStrapGuide = 1, + ShowControllerFirmwareUpdate = 2 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportResultInfo.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportResultInfo.cs new file mode 100644 index 00000000..4fcd37db --- /dev/null +++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportResultInfo.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Applets +{ + unsafe struct ControllerSupportResultInfo + { + public sbyte PlayerCount; + fixed byte _padding[3]; + public uint SelectedId; + public uint Result; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Applets/IApplet.cs b/Ryujinx.HLE/HOS/Applets/IApplet.cs index c2d4aada..b10ede68 100644 --- a/Ryujinx.HLE/HOS/Applets/IApplet.cs +++ b/Ryujinx.HLE/HOS/Applets/IApplet.cs @@ -1,5 +1,6 @@ using Ryujinx.HLE.HOS.Services.Am.AppletAE; using System; +using System.Runtime.InteropServices; namespace Ryujinx.HLE.HOS.Applets { @@ -11,5 +12,10 @@ namespace Ryujinx.HLE.HOS.Applets AppletSession interactiveSession); ResultCode GetResult(); + + static T ReadStruct(ReadOnlySpan data) where T : struct + { + return MemoryMarshal.Cast(data)[0]; + } } } diff --git a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs index e142838c..ed54eb98 100644 --- a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs +++ b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs @@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Applets var keyboardConfig = _normalSession.Pop(); var transferMemory = _normalSession.Pop(); - _keyboardConfig = ReadStruct(keyboardConfig); + _keyboardConfig = IApplet.ReadStruct(keyboardConfig); if (_keyboardConfig.UseUtf8) { @@ -176,20 +176,5 @@ namespace Ryujinx.HLE.HOS.Applets return stream.ToArray(); } } - - private static T ReadStruct(byte[] data) - where T : struct - { - GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); - - try - { - return Marshal.PtrToStructure(handle.AddrOfPinnedObject()); - } - finally - { - handle.Free(); - } - } } } diff --git a/Ryujinx.HLE/HOS/Services/Hid/Hid.cs b/Ryujinx.HLE/HOS/Services/Hid/Hid.cs new file mode 100644 index 00000000..e07577ed --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Hid.cs @@ -0,0 +1,88 @@ +using Ryujinx.Common; +using Ryujinx.HLE.Exceptions; +using System.Runtime.CompilerServices; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public class Hid + { + private readonly Switch _device; + private long _hidMemoryAddress; + + internal ref HidSharedMemory SharedMemory => ref _device.Memory.GetStructRef(_hidMemoryAddress); + internal const int SharedMemEntryCount = 17; + + public DebugPadDevice DebugPad; + public TouchDevice Touchscreen; + public MouseDevice Mouse; + public KeyboardDevice Keyboard; + public NpadDevices Npads; + + static Hid() + { + if (Unsafe.SizeOf() != 0x400) + { + throw new InvalidStructLayoutException(0x400); + } + if (Unsafe.SizeOf() != 0x3000) + { + throw new InvalidStructLayoutException(0x3000); + } + if (Unsafe.SizeOf() != 0x400) + { + throw new InvalidStructLayoutException(0x400); + } + if (Unsafe.SizeOf() != 0x400) + { + throw new InvalidStructLayoutException(0x400); + } + if (Unsafe.SizeOf() != 0x5000) + { + throw new InvalidStructLayoutException(0x5000); + } + if (Unsafe.SizeOf() != Horizon.HidSize) + { + throw new InvalidStructLayoutException(Horizon.HidSize); + } + } + + public Hid(in Switch device, long sharedHidMemoryAddress) + { + _device = device; + _hidMemoryAddress = sharedHidMemoryAddress; + + device.Memory.FillWithZeros(sharedHidMemoryAddress, Horizon.HidSize); + } + + public void InitDevices() + { + DebugPad = new DebugPadDevice(_device, true); + Touchscreen = new TouchDevice(_device, true); + Mouse = new MouseDevice(_device, false); + Keyboard = new KeyboardDevice(_device, false); + Npads = new NpadDevices(_device, true); + } + + public ControllerKeys UpdateStickButtons(JoystickPosition leftStick, JoystickPosition rightStick) + { + ControllerKeys result = 0; + + result |= (leftStick.Dx < 0) ? ControllerKeys.LStickLeft : result; + result |= (leftStick.Dx > 0) ? ControllerKeys.LStickRight : result; + result |= (leftStick.Dy < 0) ? ControllerKeys.LStickDown : result; + result |= (leftStick.Dy > 0) ? ControllerKeys.LStickUp : result; + + result |= (rightStick.Dx < 0) ? ControllerKeys.RStickLeft : result; + result |= (rightStick.Dx > 0) ? ControllerKeys.RStickRight : result; + result |= (rightStick.Dy < 0) ? ControllerKeys.RStickDown : result; + result |= (rightStick.Dy > 0) ? ControllerKeys.RStickUp : result; + + return result; + } + + internal static ulong GetTimestampTicks() + { + return (ulong)PerformanceCounter.ElapsedMilliseconds * 19200; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs new file mode 100644 index 00000000..59d6dfa3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs @@ -0,0 +1,29 @@ +using static Ryujinx.HLE.HOS.Services.Hid.Hid; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public abstract class BaseDevice + { + protected readonly Switch _device; + public bool Active; + + public BaseDevice(Switch device, bool active) + { + _device = device; + Active = active; + } + + internal static int UpdateEntriesHeader(ref CommonEntriesHeader header, out int previousEntry) + { + header.NumEntries = SharedMemEntryCount; + header.MaxEntryIndex = SharedMemEntryCount - 1; + + previousEntry = (int)header.LatestEntry; + header.LatestEntry = (header.LatestEntry + 1) % SharedMemEntryCount; + + header.TimestampTicks = GetTimestampTicks(); + + return (int)header.LatestEntry; // EntryCount shouldn't overflow int + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs new file mode 100644 index 00000000..77e9205f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs @@ -0,0 +1,24 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public class DebugPadDevice : BaseDevice + { + public DebugPadDevice(Switch device, bool active) : base(device, active) { } + + public void Update() + { + ref ShMemDebugPad debugPad = ref _device.Hid.SharedMemory.DebugPad; + + int currentIndex = UpdateEntriesHeader(ref debugPad.Header, out int previousIndex); + + if (!Active) + { + return; + } + + ref DebugPadEntry currentEntry = ref debugPad.Entries[currentIndex]; + DebugPadEntry previousEntry = debugPad.Entries[previousIndex]; + + currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs new file mode 100644 index 00000000..e8ed6a3e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs @@ -0,0 +1,32 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public class KeyboardDevice : BaseDevice + { + public KeyboardDevice(Switch device, bool active) : base(device, active) { } + + public unsafe void Update(KeyboardInput keyState) + { + ref ShMemKeyboard keyboard = ref _device.Hid.SharedMemory.Keyboard; + + int currentIndex = UpdateEntriesHeader(ref keyboard.Header, out int previousIndex); + + if (!Active) + { + return; + } + + ref KeyboardState currentEntry = ref keyboard.Entries[currentIndex]; + KeyboardState previousEntry = keyboard.Entries[previousIndex]; + + currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1; + currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1; + + for (int i = 0; i < 8; ++i) + { + currentEntry.Keys[i] = (uint)keyState.Keys[i]; + } + + currentEntry.Modifier = (ulong)keyState.Modifier; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs new file mode 100644 index 00000000..ee58a563 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs @@ -0,0 +1,37 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public class MouseDevice : BaseDevice + { + public MouseDevice(Switch device, bool active) : base(device, active) { } + + public void Update(int mouseX, int mouseY, int buttons = 0, int scrollX = 0, int scrollY = 0) + { + ref ShMemMouse mouse = ref _device.Hid.SharedMemory.Mouse; + + int currentIndex = UpdateEntriesHeader(ref mouse.Header, out int previousIndex); + + if (!Active) + { + return; + } + + ref MouseState currentEntry = ref mouse.Entries[currentIndex]; + MouseState previousEntry = mouse.Entries[previousIndex]; + + currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1; + currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1; + + currentEntry.Buttons = (ulong)buttons; + + currentEntry.Position = new MousePosition + { + X = mouseX, + Y = mouseY, + VelocityX = mouseX - previousEntry.Position.X, + VelocityY = mouseY - previousEntry.Position.Y, + ScrollVelocityX = scrollX, + ScrollVelocityY = scrollY + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs new file mode 100644 index 00000000..ff330312 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs @@ -0,0 +1,332 @@ +using System; +using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Common.Logging; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public class NpadDevices : BaseDevice + { + internal NpadJoyHoldType JoyHold = NpadJoyHoldType.Vertical; + internal bool SixAxisActive = false; // TODO: link to hidserver when implemented + + enum FilterState + { + Unconfigured = 0, + Configured = 1, + Accepted = 2 + } + + struct NpadConfig + { + public ControllerType ConfiguredType; + public FilterState State; + } + + private const int _maxControllers = 9; // Players1-8 and Handheld + private NpadConfig[] _configuredNpads; + + private ControllerType _supportedStyleSets = ControllerType.ProController | + ControllerType.JoyconPair | + ControllerType.JoyconLeft | + ControllerType.JoyconRight | + ControllerType.Handheld; + + public ControllerType SupportedStyleSets + { + get { return _supportedStyleSets; } + set + { + if (_supportedStyleSets != value) // Deal with spamming + { + _supportedStyleSets = value; + MatchControllers(); + } + } + } + + public PlayerIndex PrimaryController { get; set; } = PlayerIndex.Unknown; + + KEvent[] _styleSetUpdateEvents; + + static readonly Array3 _fullBattery; + + public NpadDevices(Switch device, bool active = true) : base(device, active) + { + _configuredNpads = new NpadConfig[_maxControllers]; + + _styleSetUpdateEvents = new KEvent[_maxControllers]; + + for (int i = 0; i < _styleSetUpdateEvents.Length; ++i) + { + _styleSetUpdateEvents[i] = new KEvent(_device.System); + } + + _fullBattery[0] = _fullBattery[1] = _fullBattery[2] = BatteryCharge.Percent100; + } + + public void AddControllers(params ControllerConfig[] configs) + { + for (int i = 0; i < configs.Length; ++i) + { + PlayerIndex player = configs[i].Player; + ControllerType controllerType = configs[i].Type; + + if (player > PlayerIndex.Handheld) + { + throw new ArgumentOutOfRangeException("Player must be Player1-8 or Handheld"); + } + + if (controllerType == ControllerType.Handheld) + { + player = PlayerIndex.Handheld; + } + + _configuredNpads[(int)player] = new NpadConfig { ConfiguredType = controllerType, State = FilterState.Configured }; + } + + MatchControllers(); + } + + void MatchControllers() + { + PrimaryController = PlayerIndex.Unknown; + + for (int i = 0; i < _configuredNpads.Length; ++i) + { + ref NpadConfig config = ref _configuredNpads[i]; + + if (config.State == FilterState.Unconfigured) + { + continue; // Ignore unconfigured + } + + if ((config.ConfiguredType & _supportedStyleSets) == 0) + { + Logger.PrintWarning(LogClass.Hid, $"ControllerType {config.ConfiguredType} (connected to {(PlayerIndex)i}) not supported by game. Removing..."); + + config.State = FilterState.Configured; + _device.Hid.SharedMemory.Npads[i] = new ShMemNpad(); // Zero it + + continue; + } + + InitController((PlayerIndex)i, config.ConfiguredType); + } + + // Couldn't find any matching configuration. Reassign to something that works. + if (PrimaryController == PlayerIndex.Unknown) + { + ControllerType[] npadsTypeList = (ControllerType[])Enum.GetValues(typeof(ControllerType)); + + // Skip None Type + for (int i = 1; i < npadsTypeList.Length; ++i) + { + ControllerType controllerType = npadsTypeList[i]; + if ((controllerType & _supportedStyleSets) != 0) + { + Logger.PrintWarning(LogClass.Hid, $"No matching controllers found. Reassigning input as ControllerType {controllerType}..."); + + InitController(controllerType == ControllerType.Handheld ? PlayerIndex.Handheld : PlayerIndex.Player1, controllerType); + + return; + } + } + + Logger.PrintError(LogClass.Hid, "Couldn't find any appropriate controller."); + } + } + + internal ref KEvent GetStyleSetUpdateEvent(PlayerIndex player) + { + return ref _styleSetUpdateEvents[(int)player]; + } + + void InitController(PlayerIndex player, ControllerType type) + { + if (type == ControllerType.Handheld) + { + player = PlayerIndex.Handheld; + } + + ref ShMemNpad controller = ref _device.Hid.SharedMemory.Npads[(int)player]; + + controller = new ShMemNpad(); // Zero it + + // TODO: Allow customizing colors at config + NpadStateHeader defaultHeader = new NpadStateHeader + { + IsHalf = false, + SingleColorBody = NpadColor.BodyGray, + SingleColorButtons = NpadColor.ButtonGray, + LeftColorBody = NpadColor.BodyNeonBlue, + LeftColorButtons = NpadColor.ButtonGray, + RightColorBody = NpadColor.BodyNeonRed, + RightColorButtons = NpadColor.ButtonGray + }; + + controller.SystemProperties = NpadSystemProperties.PowerInfo0Connected | + NpadSystemProperties.PowerInfo1Connected | + NpadSystemProperties.PowerInfo2Connected; + + controller.BatteryState = _fullBattery; + + switch (type) + { + case ControllerType.ProController: + defaultHeader.Type = ControllerType.ProController; + controller.DeviceType = DeviceType.FullKey; + controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented | + NpadSystemProperties.PlusButtonCapability | + NpadSystemProperties.MinusButtonCapability; + break; + case ControllerType.Handheld: + defaultHeader.Type = ControllerType.Handheld; + controller.DeviceType = DeviceType.HandheldLeft | + DeviceType.HandheldRight; + controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented | + NpadSystemProperties.PlusButtonCapability | + NpadSystemProperties.MinusButtonCapability; + break; + case ControllerType.JoyconPair: + defaultHeader.Type = ControllerType.JoyconPair; + controller.DeviceType = DeviceType.JoyLeft | + DeviceType.JoyRight; + controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented | + NpadSystemProperties.PlusButtonCapability | + NpadSystemProperties.MinusButtonCapability; + break; + case ControllerType.JoyconLeft: + defaultHeader.Type = ControllerType.JoyconLeft; + defaultHeader.IsHalf = true; + controller.DeviceType = DeviceType.JoyLeft; + controller.SystemProperties |= NpadSystemProperties.SlSrButtonOriented | + NpadSystemProperties.MinusButtonCapability; + break; + case ControllerType.JoyconRight: + defaultHeader.Type = ControllerType.JoyconRight; + defaultHeader.IsHalf = true; + controller.DeviceType = DeviceType.JoyRight; + controller.SystemProperties |= NpadSystemProperties.SlSrButtonOriented | + NpadSystemProperties.PlusButtonCapability; + break; + case ControllerType.Pokeball: + defaultHeader.Type = ControllerType.Pokeball; + controller.DeviceType = DeviceType.Palma; + break; + } + + controller.Header = defaultHeader; + + if (PrimaryController == PlayerIndex.Unknown) + { + PrimaryController = player; + } + + _configuredNpads[(int)player].State = FilterState.Accepted; + + _styleSetUpdateEvents[(int)player].ReadableEvent.Signal(); + + Logger.PrintInfo(LogClass.Hid, $"Connected ControllerType {type} to PlayerIndex {player}"); + } + + static NpadLayoutsIndex ControllerTypeToLayout(ControllerType controllerType) + => controllerType switch + { + ControllerType.ProController => NpadLayoutsIndex.ProController, + ControllerType.Handheld => NpadLayoutsIndex.Handheld, + ControllerType.JoyconPair => NpadLayoutsIndex.JoyDual, + ControllerType.JoyconLeft => NpadLayoutsIndex.JoyLeft, + ControllerType.JoyconRight => NpadLayoutsIndex.JoyRight, + ControllerType.Pokeball => NpadLayoutsIndex.Pokeball, + _ => NpadLayoutsIndex.SystemExternal + }; + + public void SetGamepadsInput(params GamepadInput[] states) + { + UpdateAllEntries(); + + for (int i = 0; i < states.Length; ++i) + { + SetGamepadState(states[i].PlayerId, states[i].Buttons, states[i].LStick, states[i].RStick); + } + } + + void SetGamepadState(PlayerIndex player, ControllerKeys buttons, + JoystickPosition leftJoystick, JoystickPosition rightJoystick) + { + if (player == PlayerIndex.Auto) + { + player = PrimaryController; + } + + if (player == PlayerIndex.Unknown) + { + return; + } + + if (_configuredNpads[(int)player].State != FilterState.Accepted) + { + return; + } + + ref ShMemNpad currentNpad = ref _device.Hid.SharedMemory.Npads[(int)player]; + ref NpadLayout currentLayout = ref currentNpad.Layouts[(int)ControllerTypeToLayout(currentNpad.Header.Type)]; + ref NpadState currentEntry = ref currentLayout.Entries[(int)currentLayout.Header.LatestEntry]; + + currentEntry.Buttons = buttons; + currentEntry.LStickX = leftJoystick.Dx; + currentEntry.LStickY = leftJoystick.Dy; + currentEntry.RStickX = rightJoystick.Dx; + currentEntry.RStickY = rightJoystick.Dy; + + // Mirror data to Default layout just in case + ref NpadLayout mainLayout = ref currentNpad.Layouts[(int)NpadLayoutsIndex.SystemExternal]; + mainLayout.Entries[(int)mainLayout.Header.LatestEntry] = currentEntry; + } + + void UpdateAllEntries() + { + ref Array10 controllers = ref _device.Hid.SharedMemory.Npads; + for (int i = 0; i < controllers.Length; ++i) + { + ref Array7 layouts = ref controllers[i].Layouts; + for (int l = 0; l < layouts.Length; ++l) + { + ref NpadLayout currentLayout = ref layouts[l]; + int currentIndex = UpdateEntriesHeader(ref currentLayout.Header, out int previousIndex); + + ref NpadState currentEntry = ref currentLayout.Entries[currentIndex]; + NpadState previousEntry = currentLayout.Entries[previousIndex]; + + currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1; + currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1; + + if (controllers[i].Header.Type == ControllerType.None) + { + continue; + } + + currentEntry.ConnectionState = NpadConnectionState.ControllerStateConnected; + + switch (controllers[i].Header.Type) + { + case ControllerType.Handheld: + case ControllerType.ProController: + currentEntry.ConnectionState |= NpadConnectionState.ControllerStateWired; + break; + case ControllerType.JoyconPair: + currentEntry.ConnectionState |= NpadConnectionState.JoyLeftConnected | + NpadConnectionState.JoyRightConnected; + break; + case ControllerType.JoyconLeft: + currentEntry.ConnectionState |= NpadConnectionState.JoyLeftConnected; + break; + case ControllerType.JoyconRight: + currentEntry.ConnectionState |= NpadConnectionState.JoyRightConnected; + break; + } + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs new file mode 100644 index 00000000..10c34453 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs @@ -0,0 +1,46 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public class TouchDevice : BaseDevice + { + public TouchDevice(Switch device, bool active) : base(device, active) { } + + public void Update(params TouchPoint[] points) + { + ref ShMemTouchScreen touchscreen = ref _device.Hid.SharedMemory.TouchScreen; + + int currentIndex = UpdateEntriesHeader(ref touchscreen.Header, out int previousIndex); + + if (!Active) + { + return; + } + + ref TouchScreenState currentEntry = ref touchscreen.Entries[currentIndex]; + TouchScreenState previousEntry = touchscreen.Entries[previousIndex]; + + currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1; + currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1; + + currentEntry.NumTouches = (ulong)points.Length; + + int pointsLength = Math.Min(points.Length, currentEntry.Touches.Length); + + for (int i = 0; i < pointsLength; ++i) + { + TouchPoint pi = points[i]; + currentEntry.Touches[i] = new TouchScreenStateData + { + SampleTimestamp = currentEntry.SampleTimestamp, + X = pi.X, + Y = pi.Y, + TouchIndex = (uint)i, + DiameterX = pi.DiameterX, + DiameterY = pi.DiameterY, + Angle = pi.Angle + }; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/ControllerConfig.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/ControllerConfig.cs new file mode 100644 index 00000000..e59ba312 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/ControllerConfig.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public struct ControllerConfig + { + public PlayerIndex Player; + public ControllerType Type; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/GamepadInput.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/GamepadInput.cs new file mode 100644 index 00000000..2488057e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/GamepadInput.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public struct GamepadInput + { + public PlayerIndex PlayerId; + public ControllerKeys Buttons; + public JoystickPosition LStick; + public JoystickPosition RStick; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/JoystickPosition.cs similarity index 71% rename from Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs rename to Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/JoystickPosition.cs index 1442bc60..6df477d6 100644 --- a/Ryujinx.HLE/Input/Controller/Types/JoystickPosition.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/JoystickPosition.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Input +namespace Ryujinx.HLE.HOS.Services.Hid { public struct JoystickPosition { diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs new file mode 100644 index 00000000..26681270 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public struct KeyboardInput + { + public int Modifier; + public int[] Keys; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs new file mode 100644 index 00000000..d1172dd0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public struct TouchPoint + { + public uint X; + public uint Y; + public uint DiameterX; + public uint DiameterY; + public uint Angle; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs index c89ea306..c2cd8432 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/HidUtils.cs @@ -1,46 +1,39 @@ -using Ryujinx.HLE.Input; -using System; +using System; namespace Ryujinx.HLE.HOS.Services.Hid.HidServer { static class HidUtils { - public static ControllerId GetIndexFromNpadIdType(HidNpadIdType npadIdType) + public static PlayerIndex GetIndexFromNpadIdType(NpadIdType npadIdType) + => npadIdType switch { - switch (npadIdType) - { - case HidNpadIdType.Player1: return ControllerId.ControllerPlayer1; - case HidNpadIdType.Player2: return ControllerId.ControllerPlayer2; - case HidNpadIdType.Player3: return ControllerId.ControllerPlayer3; - case HidNpadIdType.Player4: return ControllerId.ControllerPlayer4; - case HidNpadIdType.Player5: return ControllerId.ControllerPlayer5; - case HidNpadIdType.Player6: return ControllerId.ControllerPlayer6; - case HidNpadIdType.Player7: return ControllerId.ControllerPlayer7; - case HidNpadIdType.Player8: return ControllerId.ControllerPlayer8; - case HidNpadIdType.Handheld: return ControllerId.ControllerHandheld; - case HidNpadIdType.Unknown: return ControllerId.ControllerUnknown; + NpadIdType.Player1 => PlayerIndex.Player1, + NpadIdType.Player2 => PlayerIndex.Player2, + NpadIdType.Player3 => PlayerIndex.Player3, + NpadIdType.Player4 => PlayerIndex.Player4, + NpadIdType.Player5 => PlayerIndex.Player5, + NpadIdType.Player6 => PlayerIndex.Player6, + NpadIdType.Player7 => PlayerIndex.Player7, + NpadIdType.Player8 => PlayerIndex.Player8, + NpadIdType.Handheld => PlayerIndex.Handheld, + NpadIdType.Unknown => PlayerIndex.Unknown, + _ => throw new ArgumentOutOfRangeException(nameof(npadIdType)) + }; - default: throw new ArgumentOutOfRangeException(nameof(npadIdType)); - } - } - - public static HidNpadIdType GetNpadIdTypeFromIndex(ControllerId index) + public static NpadIdType GetNpadIdTypeFromIndex(PlayerIndex index) + => index switch { - switch (index) - { - case ControllerId.ControllerPlayer1: return HidNpadIdType.Player1; - case ControllerId.ControllerPlayer2: return HidNpadIdType.Player2; - case ControllerId.ControllerPlayer3: return HidNpadIdType.Player3; - case ControllerId.ControllerPlayer4: return HidNpadIdType.Player4; - case ControllerId.ControllerPlayer5: return HidNpadIdType.Player5; - case ControllerId.ControllerPlayer6: return HidNpadIdType.Player6; - case ControllerId.ControllerPlayer7: return HidNpadIdType.Player7; - case ControllerId.ControllerPlayer8: return HidNpadIdType.Player8; - case ControllerId.ControllerHandheld: return HidNpadIdType.Handheld; - case ControllerId.ControllerUnknown: return HidNpadIdType.Unknown; - - default: throw new ArgumentOutOfRangeException(nameof(index)); - } - } + PlayerIndex.Player1 => NpadIdType.Player1, + PlayerIndex.Player2 => NpadIdType.Player2, + PlayerIndex.Player3 => NpadIdType.Player3, + PlayerIndex.Player4 => NpadIdType.Player4, + PlayerIndex.Player5 => NpadIdType.Player5, + PlayerIndex.Player6 => NpadIdType.Player6, + PlayerIndex.Player7 => NpadIdType.Player7, + PlayerIndex.Player8 => NpadIdType.Player8, + PlayerIndex.Handheld => NpadIdType.Handheld, + PlayerIndex.Unknown => NpadIdType.Unknown, + _ => throw new ArgumentOutOfRangeException(nameof(index)) + }; } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadHandheldActivationMode.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadHandheldActivationMode.cs similarity index 100% rename from Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadHandheldActivationMode.cs rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadHandheldActivationMode.cs diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyAssignmentMode.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadJoyAssignmentMode.cs similarity index 100% rename from Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyAssignmentMode.cs rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadJoyAssignmentMode.cs diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyDeviceType.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadJoyDeviceType.cs similarity index 100% rename from Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyDeviceType.cs rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Npad/HidNpadJoyDeviceType.cs diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidAccelerometerParameters.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidAccelerometerParameters.cs similarity index 100% rename from Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidAccelerometerParameters.cs rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidAccelerometerParameters.cs diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidGyroscopeZeroDriftMode.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidGyroscopeZeroDriftMode.cs similarity index 100% rename from Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidGyroscopeZeroDriftMode.cs rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidGyroscopeZeroDriftMode.cs diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidSensorFusionParameters.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidSensorFusionParameters.cs similarity index 100% rename from Ryujinx.HLE/HOS/Services/Hid/Types/SixAxis/HidSensorFusionParameters.cs rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/SixAxis/HidSensorFusionParameters.cs diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDevicePosition.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDevicePosition.cs similarity index 100% rename from Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDevicePosition.cs rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDevicePosition.cs diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceType.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs similarity index 100% rename from Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceType.cs rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceValue.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceValue.cs similarity index 100% rename from Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationDeviceValue.cs rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceValue.cs diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationValue.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs similarity index 100% rename from Ryujinx.HLE/HOS/Services/Hid/Types/Vibration/HidVibrationValue.cs rename to Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs index 1af9baf8..e34c4213 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs @@ -3,7 +3,6 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Hid.HidServer; -using Ryujinx.HLE.Input; using System; namespace Ryujinx.HLE.HOS.Services.Hid @@ -11,7 +10,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid [Service("hid")] class IHidServer : IpcService { - private KEvent _npadStyleSetUpdateEvent; private KEvent _xpadIdEvent; private KEvent _palmaOperationCompleteEvent; @@ -22,8 +20,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid private bool _vibrationPermitted; private bool _usbFullKeyControllerEnabled; - private HidNpadJoyHoldType _npadJoyHoldType; - private HidNpadStyle _npadStyleSet; private HidNpadJoyAssignmentMode _npadJoyAssignmentMode; private HidNpadHandheldActivationMode _npadHandheldActivationMode; private HidGyroscopeZeroDriftMode _gyroscopeZeroDriftMode; @@ -39,12 +35,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid public IHidServer(ServiceCtx context) { - _npadStyleSetUpdateEvent = new KEvent(context.Device.System); _xpadIdEvent = new KEvent(context.Device.System); _palmaOperationCompleteEvent = new KEvent(context.Device.System); - _npadJoyHoldType = HidNpadJoyHoldType.Vertical; - _npadStyleSet = HidNpadStyle.FullKey | HidNpadStyle.Dual | HidNpadStyle.Left | HidNpadStyle.Right | HidNpadStyle.Handheld; _npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Dual; _npadHandheldActivationMode = HidNpadHandheldActivationMode.Dual; _gyroscopeZeroDriftMode = HidGyroscopeZeroDriftMode.Standard; @@ -85,6 +78,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid { long appletResourceUserId = context.RequestData.ReadInt64(); + context.Device.Hid.Touchscreen.Active = true; Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId }); return ResultCode.Success; @@ -96,6 +90,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid { long appletResourceUserId = context.RequestData.ReadInt64(); + context.Device.Hid.Mouse.Active = true; Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId }); return ResultCode.Success; @@ -107,6 +102,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid { long appletResourceUserId = context.RequestData.ReadInt64(); + context.Device.Hid.Keyboard.Active = true; Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId }); return ResultCode.Success; @@ -542,13 +538,15 @@ namespace Ryujinx.HLE.HOS.Services.Hid // SetSupportedNpadStyleSet(nn::applet::AppletResourceUserId, nn::hid::NpadStyleTag) public ResultCode SetSupportedNpadStyleSet(ServiceCtx context) { - _npadStyleSet = (HidNpadStyle)context.RequestData.ReadInt32(); - + ControllerType type = (ControllerType)context.RequestData.ReadInt32(); long appletResourceUserId = context.RequestData.ReadInt64(); - Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadStyleSet }); + Logger.PrintStub(LogClass.ServiceHid, new { + appletResourceUserId, + type + }); - _npadStyleSetUpdateEvent.ReadableEvent.Signal(); + context.Device.Hid.Npads.SupportedStyleSets = type; return ResultCode.Success; } @@ -559,9 +557,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid { long appletResourceUserId = context.RequestData.ReadInt64(); - context.ResponseData.Write((int)_npadStyleSet); + context.ResponseData.Write((int)context.Device.Hid.Npads.SupportedStyleSets); - Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadStyleSet }); + Logger.PrintStub(LogClass.ServiceHid, new { + appletResourceUserId, + context.Device.Hid.Npads.SupportedStyleSets + }); return ResultCode.Success; } @@ -570,10 +571,17 @@ namespace Ryujinx.HLE.HOS.Services.Hid // SetSupportedNpadIdType(nn::applet::AppletResourceUserId, array) public ResultCode SetSupportedNpadIdType(ServiceCtx context) { - long appletResourceUserId = context.RequestData.ReadInt64(); - ControllerId npadIdType = (ControllerId)context.RequestData.ReadInt64(); + long appletResourceUserId = context.RequestData.ReadInt64(); + long arraySize = context.Request.PtrBuff[0].Size / 4; - Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, npadIdType }); + NpadIdType[] supportedPlayerIds = new NpadIdType[arraySize]; + + for (int i = 0; i < arraySize; ++i) + { + supportedPlayerIds[i] = (NpadIdType)context.Memory.ReadInt32(context.Request.PtrBuff[0].Position + i * 4); + } + + Logger.PrintStub(LogClass.ServiceHid, $"{arraySize} " + string.Join(",", supportedPlayerIds)); return ResultCode.Success; } @@ -584,6 +592,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid { long appletResourceUserId = context.RequestData.ReadInt64(); + context.Device.Hid.Npads.Active = true; Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId }); return ResultCode.Success; @@ -595,6 +604,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid { long appletResourceUserId = context.RequestData.ReadInt64(); + context.Device.Hid.Npads.Active = false; Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId }); return ResultCode.Success; @@ -604,11 +614,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid // AcquireNpadStyleSetUpdateEventHandle(nn::applet::AppletResourceUserId, uint, ulong) -> nn::sf::NativeHandle public ResultCode AcquireNpadStyleSetUpdateEventHandle(ServiceCtx context) { - long appletResourceUserId = context.RequestData.ReadInt64(); - int npadId = context.RequestData.ReadInt32(); - long npadStyleSet = context.RequestData.ReadInt64(); + PlayerIndex npadId = HidUtils.GetIndexFromNpadIdType((NpadIdType)context.RequestData.ReadInt32()); + long appletResourceUserId = context.RequestData.ReadInt64(); + long npadStyleSet = context.RequestData.ReadInt64(); - if (context.Process.HandleTable.GenerateHandle(_npadStyleSetUpdateEvent.ReadableEvent, out int handle) != KernelResult.Success) + KEvent evnt = context.Device.Hid.Npads.GetStyleSetUpdateEvent(npadId); + if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out int handle) != KernelResult.Success) { throw new InvalidOperationException("Out of handles!"); } @@ -624,8 +635,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid // DisconnectNpad(nn::applet::AppletResourceUserId, uint NpadIdType) public ResultCode DisconnectNpad(ServiceCtx context) { - long appletResourceUserId = context.RequestData.ReadInt64(); - int npadIdType = context.RequestData.ReadInt32(); + NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadInt32(); + long appletResourceUserId = context.RequestData.ReadInt64(); Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, npadIdType }); @@ -651,10 +662,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid // ActivateNpadWithRevision(nn::applet::AppletResourceUserId, int Unknown) public ResultCode ActivateNpadWithRevision(ServiceCtx context) { + int revision = context.RequestData.ReadInt32(); long appletResourceUserId = context.RequestData.ReadInt64(); - int unknown = context.RequestData.ReadInt32(); - Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, unknown }); + Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, revision }); return ResultCode.Success; } @@ -664,9 +675,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid public ResultCode SetNpadJoyHoldType(ServiceCtx context) { long appletResourceUserId = context.RequestData.ReadInt64(); - _npadJoyHoldType = (HidNpadJoyHoldType)context.RequestData.ReadInt64(); + context.Device.Hid.Npads.JoyHold = (NpadJoyHoldType)context.RequestData.ReadInt64(); - Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadJoyHoldType }); + Logger.PrintStub(LogClass.ServiceHid, new { + appletResourceUserId, + context.Device.Hid.Npads.JoyHold + }); return ResultCode.Success; } @@ -677,9 +691,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid { long appletResourceUserId = context.RequestData.ReadInt64(); - context.ResponseData.Write((long)_npadJoyHoldType); + context.ResponseData.Write((long)context.Device.Hid.Npads.JoyHold); - Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadJoyHoldType }); + Logger.PrintStub(LogClass.ServiceHid, new { + appletResourceUserId, + context.Device.Hid.Npads.JoyHold + }); return ResultCode.Success; } @@ -688,8 +705,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid // SetNpadJoyAssignmentModeSingleByDefault(uint HidControllerId, nn::applet::AppletResourceUserId) public ResultCode SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx context) { - ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32(); - long appletResourceUserId = context.RequestData.ReadInt64(); + PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32(); + long appletResourceUserId = context.RequestData.ReadInt64(); _npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Single; @@ -702,7 +719,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid // SetNpadJoyAssignmentModeSingle(uint HidControllerId, nn::applet::AppletResourceUserId, long HidNpadJoyDeviceType) public ResultCode SetNpadJoyAssignmentModeSingle(ServiceCtx context) { - ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32(); + PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32(); long appletResourceUserId = context.RequestData.ReadInt64(); HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)context.RequestData.ReadInt64(); @@ -717,8 +734,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid // SetNpadJoyAssignmentModeDual(uint HidControllerId, nn::applet::AppletResourceUserId) public ResultCode SetNpadJoyAssignmentModeDual(ServiceCtx context) { - ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32(); - long appletResourceUserId = context.RequestData.ReadInt64(); + PlayerIndex hidControllerId = HidUtils.GetIndexFromNpadIdType((NpadIdType)context.RequestData.ReadInt32()); + long appletResourceUserId = context.RequestData.ReadInt64(); _npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Dual; @@ -831,7 +848,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid // SetNpadJoyAssignmentModeSingleWithDestination(uint HidControllerId, long HidNpadJoyDeviceType, nn::applet::AppletResourceUserId) -> bool Unknown0, uint Unknown1 public ResultCode SetNpadJoyAssignmentModeSingleWithDestination(ServiceCtx context) { - ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32(); + PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32(); HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)context.RequestData.ReadInt64(); long appletResourceUserId = context.RequestData.ReadInt64(); diff --git a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs index cd571f11..4851a259 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/Irs/IIrSensorServer.cs @@ -2,7 +2,6 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Services.Hid.HidServer; -using Ryujinx.HLE.Input; using System; namespace Ryujinx.HLE.HOS.Services.Hid.Irs @@ -57,16 +56,16 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs // GetNpadIrCameraHandle(u32) -> nn::irsensor::IrCameraHandle public ResultCode GetNpadIrCameraHandle(ServiceCtx context) { - HidNpadIdType npadIdType = (HidNpadIdType)context.RequestData.ReadUInt32(); + NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadUInt32(); - if (npadIdType > HidNpadIdType.Player8 && - npadIdType != HidNpadIdType.Unknown && - npadIdType != HidNpadIdType.Handheld) + if (npadIdType > NpadIdType.Player8 && + npadIdType != NpadIdType.Unknown && + npadIdType != NpadIdType.Handheld) { return ResultCode.NpadIdOutOfRange; } - ControllerId irCameraHandle = HidUtils.GetIndexFromNpadIdType(npadIdType); + PlayerIndex irCameraHandle = HidUtils.GetIndexFromNpadIdType(npadIdType); context.ResponseData.Write((int)irCameraHandle); diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs new file mode 100644 index 00000000..5a8d51c6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct Boolean32 + { + private uint _value; + public static implicit operator bool(Boolean32 value) => (value._value & 1) != 0; + public static implicit operator Boolean32(bool value) => new Boolean32() { _value = value ? 1u : 0u }; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerKeys.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerKeys.cs new file mode 100644 index 00000000..db0319ed --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerKeys.cs @@ -0,0 +1,45 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + [Flags] + public enum ControllerKeys : long + { + A = 1 << 0, + B = 1 << 1, + X = 1 << 2, + Y = 1 << 3, + LStick = 1 << 4, + RStick = 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, + SlLeft = 1 << 24, + SrLeft = 1 << 25, + SlRight = 1 << 26, + SrRight = 1 << 27, + + // Generic Catch-all + Up = DpadUp | LStickUp | RStickUp, + Down = DpadDown | LStickDown | RStickDown, + Left = DpadLeft | LStickLeft | RStickLeft, + Right = DpadRight | LStickRight | RStickRight, + Sl = SlLeft | SlRight, + Sr = SrLeft | SrRight + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerType.cs new file mode 100644 index 00000000..f65c3079 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerType.cs @@ -0,0 +1,19 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + [Flags] + public enum ControllerType : int + { + None, + ProController = 1 << 0, + Handheld = 1 << 1, + JoyconPair = 1 << 2, + JoyconLeft = 1 << 3, + JoyconRight = 1 << 4, + Invalid = 1 << 5, + Pokeball = 1 << 6, + SystemExternal = 1 << 29, + System = 1 << 30 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyHoldType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyHoldType.cs deleted file mode 100644 index 3bd3aa91..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadJoyHoldType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Hid -{ - public enum HidNpadJoyHoldType - { - Vertical, - Horizontal - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadStyle.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadStyle.cs deleted file mode 100644 index 93717acf..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadStyle.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Hid -{ - [Flags] - public enum HidNpadStyle - { - None, - FullKey = 1 << 0, - Handheld = 1 << 1, - Dual = 1 << 2, - Left = 1 << 3, - Right = 1 << 4, - Invalid = 1 << 5 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs new file mode 100644 index 00000000..57b4b366 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs @@ -0,0 +1,37 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public enum NpadColor : int + { + BodyGray = 0x828282, + BodyNeonRed = 0xFF3C28, + BodyNeonBlue = 0x0AB9E6, + BodyNeonYellow = 0xE6FF00, + BodyNeonGreen = 0x1EDC00, + BodyNeonPink = 0xFF3278, + BodyRed = 0xE10F00, + BodyBlue = 0x4655F5, + BodyNeonPurple = 0xB400E6, + BodyNeonOrange = 0xFAA005, + BodyPokemonLetsGoPikachu = 0xFFDC00, + BodyPokemonLetsGoEevee = 0xC88C32, + BodyNintendoLaboCreatorsContestEdition = 0xD7AA73, + BodyAnimalCrossingSpecialEditionLeftJoyCon = 0x82FF96, + BodyAnimalCrossingSpecialEditionRightJoyCon = 0x96F5F5, + + ButtonGray = 0x0F0F0F, + ButtonNeonRed = 0x1E0A0A, + ButtonNeonBlue = 0x001E1E, + ButtonNeonYellow = 0x142800, + ButtonNeonGreen = 0x002800, + ButtonNeonPink = 0x28001E, + ButtonRed = 0x280A0A, + ButtonBlue = 0x00000A, + ButtonNeonPurple = 0x140014, + ButtonNeonOrange = 0x0F0A00, + ButtonPokemonLetsGoPikachu = 0x322800, + ButtonPokemonLetsGoEevee = 0x281900, + ButtonNintendoLaboCreatorsContestEdition = 0x1E1914, + ButtonAnimalCrossingSpecialEditionLeftJoyCon = 0x0A1E0A, + ButtonAnimalCrossingSpecialEditionRightJoyCon = 0x0A1E28 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadIdType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadIdType.cs similarity index 90% rename from Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadIdType.cs rename to Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadIdType.cs index 9a3989de..5f6a68cb 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/HidNpadIdType.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadIdType.cs @@ -1,6 +1,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid { - public enum HidNpadIdType + public enum NpadIdType { Player1 = 0, Player2 = 1, diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/PlayerIndex.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/PlayerIndex.cs new file mode 100644 index 00000000..f4ced5df --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/PlayerIndex.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + public enum PlayerIndex : int + { + Player1 = 0, + Player2 = 1, + Player3 = 2, + Player4 = 3, + Player5 = 4, + Player6 = 5, + Player7 = 6, + Player8 = 7, + Handheld = 8, + Unknown = 9, + Auto = 10 // Shouldn't be used directly + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/CommonEntriesHeader.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/CommonEntriesHeader.cs new file mode 100644 index 00000000..f83fdcdf --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/CommonEntriesHeader.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct CommonEntriesHeader + { + public ulong TimestampTicks; + public ulong NumEntries; + public ulong LatestEntry; + public ulong MaxEntryIndex; + } +} + diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPad.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPad.cs new file mode 100644 index 00000000..e68924da --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPad.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + unsafe struct ShMemDebugPad + { + public CommonEntriesHeader Header; + public Array17 Entries; + fixed byte _padding[0x138]; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPadEntry.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPadEntry.cs new file mode 100644 index 00000000..4a3e7a2e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPadEntry.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + unsafe struct DebugPadEntry + { + public ulong SampleTimestamp; + fixed byte _unknown[0x20]; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/HidSharedMemory.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/HidSharedMemory.cs new file mode 100644 index 00000000..d2bd8a23 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/HidSharedMemory.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + // TODO: Add missing structs + unsafe struct HidSharedMemory + { + public ShMemDebugPad DebugPad; + public ShMemTouchScreen TouchScreen; + public ShMemMouse Mouse; + public ShMemKeyboard Keyboard; + public fixed byte BasicXpad[0x4 * 0x400]; + public fixed byte HomeButton[0x200]; + public fixed byte SleepButton[0x200]; + public fixed byte CaptureButton[0x200]; + public fixed byte InputDetector[0x10 * 0x80]; + public fixed byte UniquePad[0x10 * 0x400]; + public Array10 Npads; + public fixed byte Gesture[0x800]; + public fixed byte ConsoleSixAxisSensor[0x20]; + fixed byte _padding[0x3de0]; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/Keyboard.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/Keyboard.cs new file mode 100644 index 00000000..dcfa5aa1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/Keyboard.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + unsafe struct ShMemKeyboard + { + public CommonEntriesHeader Header; + public Array17 Entries; + fixed byte _padding[0x28]; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/KeyboardState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/KeyboardState.cs new file mode 100644 index 00000000..1f54a4fd --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/KeyboardState.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + unsafe struct KeyboardState + { + public ulong SampleTimestamp; + public ulong SampleTimestamp2; + public ulong Modifier; + public fixed uint Keys[8]; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/Mouse.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/Mouse.cs new file mode 100644 index 00000000..c1f45c5c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/Mouse.cs @@ -0,0 +1,10 @@ + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + unsafe struct ShMemMouse + { + public CommonEntriesHeader Header; + public Array17 Entries; + fixed byte _padding[0xB0]; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MousePosition.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MousePosition.cs new file mode 100644 index 00000000..e94c9e0c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MousePosition.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct MousePosition + { + public int X; + public int Y; + public int VelocityX; + public int VelocityY; + public int ScrollVelocityX; + public int ScrollVelocityY; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MouseState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MouseState.cs new file mode 100644 index 00000000..7856b09d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MouseState.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct MouseState + { + public ulong SampleTimestamp; + public ulong SampleTimestamp2; + public MousePosition Position; + public ulong Buttons; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/BatterCharge.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/BatterCharge.cs new file mode 100644 index 00000000..b94ab172 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/BatterCharge.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + enum BatteryCharge : int + { + Percent0 = 0, + Percent25 = 1, + Percent50 = 2, + Percent75 = 3, + Percent100 = 4 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/DeviceType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/DeviceType.cs new file mode 100644 index 00000000..f6d7b783 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/DeviceType.cs @@ -0,0 +1,26 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + [Flags] + enum DeviceType : int + { + FullKey = 1 << 0, + DebugPad = 1 << 1, + HandheldLeft = 1 << 2, + HandheldRight = 1 << 3, + JoyLeft = 1 << 4, + JoyRight = 1 << 5, + Palma = 1 << 6, // Poké Ball Plus + FamicomLeft = 1 << 7, + FamicomRight = 1 << 8, + NESLeft = 1 << 9, + NESRight = 1 << 10, + HandheldFamicomLeft = 1 << 11, + HandheldFamicomRight = 1 << 12, + HandheldNESLeft = 1 << 13, + HandheldNESRight = 1 << 14, + Lucia = 1 << 15, + System = 1 << 31 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/HidVector.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/HidVector.cs new file mode 100644 index 00000000..b41bcb2e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/HidVector.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct HidVector + { + public float X; + public float Y; + public float Z; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs new file mode 100644 index 00000000..0bb2628f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs @@ -0,0 +1,21 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + // TODO: Add missing structs + unsafe struct ShMemNpad + { + public NpadStateHeader Header; + public Array7 Layouts; // One for each NpadLayoutsIndex + public Array6 Sixaxis; + public DeviceType DeviceType; + uint _padding1; + public NpadSystemProperties SystemProperties; + public uint NpadSystemButtonProperties; + public Array3 BatteryState; + public fixed byte NfcXcdDeviceHandleHeader[0x20]; + public fixed byte NfcXcdDeviceHandleState[0x20 * 2]; + public ulong Mutex; + public fixed byte NpadGcTriggerHeader[0x20]; + public fixed byte NpadGcTriggerState[0x18 * 17]; + fixed byte _padding2[0xC38]; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadColorDescription.cs similarity index 55% rename from Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs rename to Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadColorDescription.cs index c31f41a3..ccc7cb8d 100644 --- a/Ryujinx.HLE/Input/Controller/Types/ControllerColorDescription.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadColorDescription.cs @@ -1,9 +1,9 @@ using System; -namespace Ryujinx.HLE.Input +namespace Ryujinx.HLE.HOS.Services.Hid { [Flags] - public enum ControllerColorDescription : int + enum NpadColorDescription : int { ColorDescriptionColorsNonexistent = (1 << 1) } diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadConnectionState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadConnectionState.cs new file mode 100644 index 00000000..60f64fd3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadConnectionState.cs @@ -0,0 +1,13 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + [Flags] + enum NpadConnectionState : long + { + ControllerStateConnected = (1 << 0), + ControllerStateWired = (1 << 1), + JoyLeftConnected = (1 << 2), + JoyRightConnected = (1 << 4) + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadJoyHoldType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadJoyHoldType.cs new file mode 100644 index 00000000..a6f29760 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadJoyHoldType.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + enum NpadJoyHoldType + { + Vertical, + Horizontal + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayout.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayout.cs new file mode 100644 index 00000000..9851a6b1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayout.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct NpadLayout + { + public CommonEntriesHeader Header; + public Array17 Entries; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayoutsIndex.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayoutsIndex.cs new file mode 100644 index 00000000..29eb8d3d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayoutsIndex.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + enum NpadLayoutsIndex : int + { + ProController = 0, + Handheld = 1, + JoyDual = 2, + JoyLeft = 3, + JoyRight = 4, + Pokeball = 5, + SystemExternal = 6 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSixAxis.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSixAxis.cs new file mode 100644 index 00000000..5f65db39 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSixAxis.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct NpadSixAxis + { + public CommonEntriesHeader Header; + public Array17 Entries; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadState.cs new file mode 100644 index 00000000..60a5f9d3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadState.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct NpadState + { + public ulong SampleTimestamp; + public ulong SampleTimestamp2; + public ControllerKeys Buttons; + public int LStickX; + public int LStickY; + public int RStickX; + public int RStickY; + public NpadConnectionState ConnectionState; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadStatesHeader.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadStatesHeader.cs new file mode 100644 index 00000000..006d4357 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadStatesHeader.cs @@ -0,0 +1,16 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct NpadStateHeader + { + public ControllerType Type; + public Boolean32 IsHalf; + public NpadColorDescription SingleColorsDescriptor; + public NpadColor SingleColorBody; + public NpadColor SingleColorButtons; + public NpadColorDescription SplitColorsDescriptor; + public NpadColor LeftColorBody; + public NpadColor LeftColorButtons; + public NpadColor RightColorBody; + public NpadColor RightColorButtons; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSystemProperties.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSystemProperties.cs new file mode 100644 index 00000000..708f7da9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSystemProperties.cs @@ -0,0 +1,22 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + [Flags] + enum NpadSystemProperties : 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 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisState.cs new file mode 100644 index 00000000..0a799916 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisState.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + unsafe struct SixAxisState + { + public ulong SampleTimestamp; + ulong _unknown1; + public ulong SampleTimestamp2; + public HidVector Accelerometer; + public HidVector Gyroscope; + HidVector unknownSensor; + public fixed float Orientation[9]; + ulong _unknown2; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/StructArrayHelpers.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/StructArrayHelpers.cs new file mode 100644 index 00000000..f513cf8b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/StructArrayHelpers.cs @@ -0,0 +1,53 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct Array2 where T : unmanaged + { + T e0, e1; + public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 2)[index]; + public int Length => 2; + } + + struct Array3 where T : unmanaged + { + T e0, e1, e2; + public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 3)[index]; + public int Length => 3; + } + + struct Array6 where T : unmanaged + { + T e0, e1, e2, e3, e4, e5; + public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 6)[index]; + public int Length => 6; + } + + struct Array7 where T : unmanaged + { + T e0, e1, e2, e3, e4, e5, e6; + public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 7)[index]; + public int Length => 7; + } + + struct Array10 where T : unmanaged + { + T e0, e1, e2, e3, e4, e5, e6, e7, e8, e9; + public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 10)[index]; + public int Length => 10; + } + + struct Array16 where T : unmanaged + { + T e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15; + public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 16)[index]; + public int Length => 16; + } + + struct Array17 where T : unmanaged + { + T e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16; + public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 17)[index]; + public int Length => 17; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreen.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreen.cs new file mode 100644 index 00000000..618ddd98 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreen.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + unsafe struct ShMemTouchScreen + { + public CommonEntriesHeader Header; + public Array17 Entries; + fixed byte _padding[0x3c8]; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenState.cs new file mode 100644 index 00000000..a0a9cf23 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenState.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct TouchScreenState + { + public ulong SampleTimestamp; + public ulong SampleTimestamp2; + public ulong NumTouches; + public Array16 Touches; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenStateData.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenStateData.cs new file mode 100644 index 00000000..872064b3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenStateData.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.HLE.HOS.Services.Hid +{ + struct TouchScreenStateData + { + public ulong SampleTimestamp; + uint _padding; + public uint TouchIndex; + public uint X; + public uint Y; + public uint DiameterX; + public uint DiameterY; + public uint Angle; + uint _padding2; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs index d26b4eb9..3f6518e5 100644 --- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs +++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/IUser.cs @@ -43,8 +43,8 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp // TODO: When we will be able to add multiple controllers add one entry by controller here. Device device1 = new Device { - NpadIdType = HidNpadIdType.Player1, - Handle = HidUtils.GetIndexFromNpadIdType(HidNpadIdType.Player1), + NpadIdType = NpadIdType.Player1, + Handle = HidUtils.GetIndexFromNpadIdType(NpadIdType.Player1), State = DeviceState.Initialized }; diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs index 40e7c880..7eaf4ac8 100644 --- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs +++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/UserManager/Types/Device.cs @@ -1,6 +1,5 @@ using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Hid; -using Ryujinx.HLE.Input; namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager { @@ -14,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager public DeviceState State = DeviceState.Unavailable; - public ControllerId Handle; - public HidNpadIdType NpadIdType; + public PlayerIndex Handle; + public NpadIdType NpadIdType; } } \ No newline at end of file diff --git a/Ryujinx.HLE/Input/Controller/BaseController.cs b/Ryujinx.HLE/Input/Controller/BaseController.cs deleted file mode 100644 index dfd54a83..00000000 --- a/Ryujinx.HLE/Input/Controller/BaseController.cs +++ /dev/null @@ -1,142 +0,0 @@ -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 deleted file mode 100644 index b4304b8f..00000000 --- a/Ryujinx.HLE/Input/Controller/NpadController.cs +++ /dev/null @@ -1,68 +0,0 @@ -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 deleted file mode 100644 index ae574260..00000000 --- a/Ryujinx.HLE/Input/Controller/ProController.cs +++ /dev/null @@ -1,42 +0,0 @@ -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 deleted file mode 100644 index 4279d7a0..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/BatteryState.cs +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 879257f2..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/ControllerButtons.cs +++ /dev/null @@ -1,35 +0,0 @@ -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/ControllerConnectionState.cs b/Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs deleted file mode 100644 index 526da1ff..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/ControllerConnectionState.cs +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 45895a1e..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceState.cs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 8043d8a0..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/ControllerDeviceType.cs +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index cbb5b6f5..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/ControllerHeader.cs +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index c82056c6..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/ControllerId.cs +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index fedc0399..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/ControllerLayouts.cs +++ /dev/null @@ -1,13 +0,0 @@ -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 deleted file mode 100644 index 4847438d..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/ControllerState.cs +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index f885c00c..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/ControllerStateHeader.cs +++ /dev/null @@ -1,13 +0,0 @@ -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 deleted file mode 100644 index 9444d7b0..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/ControllerStatus.cs +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index 53913175..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/DeviceFlags.cs +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index be76ee1e..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/HotkeyButtons.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Ryujinx.HLE.Input -{ - [Flags] - public enum HotkeyButtons - { - ToggleVSync = 1 << 0, - } -} diff --git a/Ryujinx.HLE/Input/Controller/Types/NpadColor.cs b/Ryujinx.HLE/Input/Controller/Types/NpadColor.cs deleted file mode 100644 index a60f94aa..00000000 --- a/Ryujinx.HLE/Input/Controller/Types/NpadColor.cs +++ /dev/null @@ -1,23 +0,0 @@ -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 diff --git a/Ryujinx.HLE/Input/Hid.cs b/Ryujinx.HLE/Input/Hid.cs deleted file mode 100644 index 5cb7f09d..00000000 --- a/Ryujinx.HLE/Input/Hid.cs +++ /dev/null @@ -1,218 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.Configuration.Hid; -using Ryujinx.HLE.HOS; -using System; - -namespace Ryujinx.HLE.Input -{ - public partial class Hid - { - private Switch _device; - - private long _touchScreenOffset; - private long _touchEntriesOffset; - private long _keyboardOffset; - - private TouchHeader _currentTouchHeader; - private KeyboardHeader _currentKeyboardHeader; - private KeyboardEntry _currentKeyboardEntry; - - public BaseController PrimaryController { get; private set; } - - internal long HidPosition; - - public Hid(Switch device, long hidPosition) - { - _device = device; - HidPosition = hidPosition; - - device.Memory.FillWithZeros(hidPosition, Horizon.HidSize); - - _currentTouchHeader = new TouchHeader() - { - CurrentEntryIndex = -1, - }; - - _currentKeyboardHeader = new KeyboardHeader() - { - CurrentEntryIndex = -1, - }; - - _currentKeyboardEntry = new KeyboardEntry() - { - SamplesTimestamp = -1, - SamplesTimestamp2 = -1 - }; - - _touchScreenOffset = HidPosition + HidTouchScreenOffset; - _touchEntriesOffset = _touchScreenOffset + HidTouchHeaderSize; - _keyboardOffset = HidPosition + HidKeyboardOffset; - } - - private static ControllerStatus ConvertControllerTypeToState(ControllerType controllerType) - { - switch (controllerType) - { - case ControllerType.Handheld: return ControllerStatus.Handheld; - case ControllerType.NpadLeft: return ControllerStatus.NpadLeft; - case ControllerType.NpadRight: return ControllerStatus.NpadRight; - case ControllerType.NpadPair: return ControllerStatus.NpadPair; - case ControllerType.ProController: return ControllerStatus.ProController; - default: throw new NotImplementedException(); - } - } - - public void InitializePrimaryController(ControllerType controllerType) - { - ControllerId controllerId = controllerType == ControllerType.Handheld ? - ControllerId.ControllerHandheld : ControllerId.ControllerPlayer1; - - if (controllerType == ControllerType.ProController) - { - PrimaryController = new ProController(_device, NpadColor.Black, NpadColor.Black); - } - else - { - PrimaryController = new NpadController(ConvertControllerTypeToState(controllerType), - _device, - (NpadColor.BodyNeonRed, NpadColor.BodyNeonRed), - (NpadColor.ButtonsNeonBlue, NpadColor.ButtonsNeonBlue)); - } - - PrimaryController.Connect(controllerId); - } - - public ControllerButtons UpdateStickButtons( - JoystickPosition leftStick, - JoystickPosition rightStick) - { - ControllerButtons result = 0; - - if (rightStick.Dx < 0) - { - result |= ControllerButtons.RStickLeft; - } - - if (rightStick.Dx > 0) - { - result |= ControllerButtons.RStickRight; - } - - if (rightStick.Dy < 0) - { - result |= ControllerButtons.RStickDown; - } - - if (rightStick.Dy > 0) - { - result |= ControllerButtons.RStickUp; - } - - if (leftStick.Dx < 0) - { - result |= ControllerButtons.LStickLeft; - } - - if (leftStick.Dx > 0) - { - result |= ControllerButtons.LStickRight; - } - - if (leftStick.Dy < 0) - { - result |= ControllerButtons.LStickDown; - } - - if (leftStick.Dy > 0) - { - result |= ControllerButtons.LStickUp; - } - - return result; - } - public void SetTouchPoints(params TouchPoint[] points) - { - long timestamp = GetTimestamp(); - long sampleCounter = _currentTouchHeader.SamplesTimestamp + 1; - - var newTouchHeader = new TouchHeader - { - CurrentEntryIndex = (_currentTouchHeader.CurrentEntryIndex + 1) % HidEntryCount, - EntryCount = HidEntryCount, - MaxEntries = HidEntryCount - 1, - SamplesTimestamp = sampleCounter, - Timestamp = timestamp, - }; - - long currentTouchEntryOffset = _touchEntriesOffset + newTouchHeader.CurrentEntryIndex * HidTouchEntrySize; - - TouchEntry touchEntry = new TouchEntry() - { - SamplesTimestamp = sampleCounter, - TouchCount = points.Length - }; - - _device.Memory.WriteStruct(currentTouchEntryOffset, touchEntry); - - currentTouchEntryOffset += HidTouchEntryHeaderSize; - - for (int i = 0; i < points.Length; i++) - { - TouchData touch = new TouchData() - { - Angle = points[i].Angle, - DiameterX = points[i].DiameterX, - DiameterY = points[i].DiameterY, - Index = i, - SampleTimestamp = sampleCounter, - X = points[i].X, - Y = points[i].Y - }; - - _device.Memory.WriteStruct(currentTouchEntryOffset, touch); - - currentTouchEntryOffset += HidTouchEntryTouchSize; - } - - _device.Memory.WriteStruct(_touchScreenOffset, newTouchHeader); - - _currentTouchHeader = newTouchHeader; - } - - public unsafe void WriteKeyboard(Keyboard keyboard) - { - long timestamp = GetTimestamp(); - - var newKeyboardHeader = new KeyboardHeader() - { - CurrentEntryIndex = (_currentKeyboardHeader.CurrentEntryIndex + 1) % HidEntryCount, - EntryCount = HidEntryCount, - MaxEntries = HidEntryCount - 1, - Timestamp = timestamp, - }; - - _device.Memory.WriteStruct(_keyboardOffset, newKeyboardHeader); - - long keyboardEntryOffset = _keyboardOffset + HidKeyboardHeaderSize; - keyboardEntryOffset += newKeyboardHeader.CurrentEntryIndex * HidKeyboardEntrySize; - - var newkeyboardEntry = new KeyboardEntry() - { - SamplesTimestamp = _currentKeyboardEntry.SamplesTimestamp + 1, - SamplesTimestamp2 = _currentKeyboardEntry.SamplesTimestamp2 + 1, - Keys = keyboard.Keys, - Modifier = keyboard.Modifier, - }; - - _device.Memory.WriteStruct(keyboardEntryOffset, newkeyboardEntry); - - _currentKeyboardEntry = newkeyboardEntry; - _currentKeyboardHeader = newKeyboardHeader; - } - - internal static long GetTimestamp() - { - return PerformanceCounter.ElapsedMilliseconds * 19200; - } - } -} diff --git a/Ryujinx.HLE/Input/HidValues.cs b/Ryujinx.HLE/Input/HidValues.cs deleted file mode 100644 index 06fe8fc0..00000000 --- a/Ryujinx.HLE/Input/HidValues.cs +++ /dev/null @@ -1,63 +0,0 @@ -namespace Ryujinx.HLE.Input -{ - public partial class Hid - { - /* - * Reference: - * https://github.com/reswitched/libtransistor/blob/development/lib/hid.c - * https://github.com/reswitched/libtransistor/blob/development/include/libtransistor/hid.h - * https://github.com/switchbrew/libnx/blob/master/nx/source/services/hid.c - * https://github.com/switchbrew/libnx/blob/master/nx/include/switch/services/hid.h - */ - - internal const int HidHeaderSize = 0x400; - internal const int HidTouchScreenSize = 0x3000; - internal const int HidMouseSize = 0x400; - internal const int HidKeyboardSize = 0x400; - internal const int HidUnkSection1Size = 0x400; - internal const int HidUnkSection2Size = 0x400; - internal const int HidUnkSection3Size = 0x400; - internal const int HidUnkSection4Size = 0x400; - internal const int HidUnkSection5Size = 0x200; - internal const int HidUnkSection6Size = 0x200; - internal const int HidUnkSection7Size = 0x200; - internal const int HidUnkSection8Size = 0x800; - internal const int HidControllerSerialsSize = 0x4000; - internal const int HidControllersSize = 0x32000; - internal const int HidUnkSection9Size = 0x800; - - internal const int HidKeyboardHeaderSize = 0x20; - internal const int HidKeyboardEntrySize = 0x38; - - internal const int HidTouchHeaderSize = 0x28; - internal const int HidTouchEntrySize = 0x298; - - internal const int HidTouchEntryHeaderSize = 0x10; - internal const int HidTouchEntryTouchSize = 0x28; - - internal const int HidControllerSize = 0x5000; - internal const int HidControllerHeaderSize = 0x28; - internal const int HidControllerLayoutsSize = 0x350; - - internal const int HidControllersLayoutHeaderSize = 0x20; - internal const int HidControllersInputEntrySize = 0x30; - - internal const int HidHeaderOffset = 0; - internal const int HidTouchScreenOffset = HidHeaderOffset + HidHeaderSize; - internal const int HidMouseOffset = HidTouchScreenOffset + HidTouchScreenSize; - internal const int HidKeyboardOffset = HidMouseOffset + HidMouseSize; - internal const int HidUnkSection1Offset = HidKeyboardOffset + HidKeyboardSize; - internal const int HidUnkSection2Offset = HidUnkSection1Offset + HidUnkSection1Size; - internal const int HidUnkSection3Offset = HidUnkSection2Offset + HidUnkSection2Size; - internal const int HidUnkSection4Offset = HidUnkSection3Offset + HidUnkSection3Size; - internal const int HidUnkSection5Offset = HidUnkSection4Offset + HidUnkSection4Size; - internal const int HidUnkSection6Offset = HidUnkSection5Offset + HidUnkSection5Size; - internal const int HidUnkSection7Offset = HidUnkSection6Offset + HidUnkSection6Size; - internal const int HidUnkSection8Offset = HidUnkSection7Offset + HidUnkSection7Size; - internal const int HidControllerSerialsOffset = HidUnkSection8Offset + HidUnkSection8Size; - internal const int HidControllersOffset = HidControllerSerialsOffset + HidControllerSerialsSize; - internal const int HidUnkSection9Offset = HidControllersOffset + HidControllersSize; - - internal const int HidEntryCount = 17; - } -} diff --git a/Ryujinx.HLE/Input/IHidDevice.cs b/Ryujinx.HLE/Input/IHidDevice.cs deleted file mode 100644 index 0b07e767..00000000 --- a/Ryujinx.HLE/Input/IHidDevice.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.Input -{ - interface IHidDevice - { - long Offset { get; } - bool Connected { get; } - } -} diff --git a/Ryujinx.HLE/Input/Keyboard/Keyboard.cs b/Ryujinx.HLE/Input/Keyboard/Keyboard.cs deleted file mode 100644 index 7220e518..00000000 --- a/Ryujinx.HLE/Input/Keyboard/Keyboard.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.Input -{ - public struct Keyboard - { - public int Modifier; - public int[] Keys; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/Input/Keyboard/KeyboardEntry.cs b/Ryujinx.HLE/Input/Keyboard/KeyboardEntry.cs deleted file mode 100644 index be7d9399..00000000 --- a/Ryujinx.HLE/Input/Keyboard/KeyboardEntry.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.Input -{ - [StructLayout(LayoutKind.Sequential)] - public struct KeyboardEntry - { - public long SamplesTimestamp; - public long SamplesTimestamp2; - public long Modifier; - - [MarshalAs(UnmanagedType.ByValArray , SizeConst = 0x8)] - public int[] Keys; - } -} diff --git a/Ryujinx.HLE/Input/Keyboard/KeyboardHeader.cs b/Ryujinx.HLE/Input/Keyboard/KeyboardHeader.cs deleted file mode 100644 index 882ccbab..00000000 --- a/Ryujinx.HLE/Input/Keyboard/KeyboardHeader.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.Input -{ - [StructLayout(LayoutKind.Sequential)] - public struct KeyboardHeader - { - public long Timestamp; - public long EntryCount; - public long CurrentEntryIndex; - public long MaxEntries; - } -} diff --git a/Ryujinx.HLE/Input/Touch/TouchData.cs b/Ryujinx.HLE/Input/Touch/TouchData.cs deleted file mode 100644 index 8489ef70..00000000 --- a/Ryujinx.HLE/Input/Touch/TouchData.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.Input -{ - [StructLayout(LayoutKind.Sequential)] - public struct TouchData - { - public long SampleTimestamp; - public int Padding; - public int Index; - public int X; - public int Y; - public int DiameterX; - public int DiameterY; - public int Angle; - public int Padding2; - } -} diff --git a/Ryujinx.HLE/Input/Touch/TouchEntry.cs b/Ryujinx.HLE/Input/Touch/TouchEntry.cs deleted file mode 100644 index 2ef09d75..00000000 --- a/Ryujinx.HLE/Input/Touch/TouchEntry.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.Input -{ - [StructLayout(LayoutKind.Sequential)] - public unsafe struct TouchEntry - { - public long SamplesTimestamp; - public long TouchCount; - } -} diff --git a/Ryujinx.HLE/Input/Touch/TouchHeader.cs b/Ryujinx.HLE/Input/Touch/TouchHeader.cs deleted file mode 100644 index dd93137c..00000000 --- a/Ryujinx.HLE/Input/Touch/TouchHeader.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.Input -{ - [StructLayout(LayoutKind.Sequential)] - public struct TouchHeader - { - public long Timestamp; - public long EntryCount; - public long CurrentEntryIndex; - public long MaxEntries; - public long SamplesTimestamp; - } -} diff --git a/Ryujinx.HLE/Input/Touch/TouchPoint.cs b/Ryujinx.HLE/Input/Touch/TouchPoint.cs deleted file mode 100644 index a9b095de..00000000 --- a/Ryujinx.HLE/Input/Touch/TouchPoint.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.HLE.Input -{ - public struct TouchPoint - { - public int X; - public int Y; - public int DiameterX; - public int DiameterY; - public int Angle; - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index 3cd290bd..040fbf1c 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -7,8 +7,8 @@ using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services; +using Ryujinx.HLE.HOS.Services.Hid; using Ryujinx.HLE.HOS.SystemState; -using Ryujinx.HLE.Input; using System; using System.Threading; @@ -61,6 +61,7 @@ namespace Ryujinx.HLE Statistics = new PerformanceStatistics(); Hid = new Hid(this, System.HidBaseAddress); + Hid.InitDevices(); VsyncEvent = new AutoResetEvent(true); } diff --git a/Ryujinx/Ui/GLRenderer.cs b/Ryujinx/Ui/GLRenderer.cs index 1105004a..f69d88ce 100644 --- a/Ryujinx/Ui/GLRenderer.cs +++ b/Ryujinx/Ui/GLRenderer.cs @@ -7,7 +7,7 @@ using OpenTK.Platform; using Ryujinx.Configuration; using Ryujinx.Graphics.OpenGL; using Ryujinx.HLE; -using Ryujinx.HLE.Input; +using Ryujinx.HLE.HOS.Services.Hid; using Ryujinx.Ui; using System; using System.Collections.Generic; @@ -382,10 +382,10 @@ namespace Ryujinx.Ui } HotkeyButtons currentHotkeyButtons = 0; - ControllerButtons currentButton = 0; + ControllerKeys currentButton = 0; JoystickPosition leftJoystick; JoystickPosition rightJoystick; - HLE.Input.Keyboard? hidKeyboard = null; + KeyboardInput? hidKeyboard = null; int leftJoystickDx = 0; int leftJoystickDy = 0; @@ -417,7 +417,7 @@ namespace Ryujinx.Ui if (!hidKeyboard.HasValue) { - hidKeyboard = new HLE.Input.Keyboard + hidKeyboard = new KeyboardInput { Modifier = 0, Keys = new int[0x8] @@ -489,8 +489,8 @@ namespace Ryujinx.Ui TouchPoint currentPoint = new TouchPoint { - X = mX, - Y = mY, + X = (uint)mX, + Y = (uint)mY, // Placeholder values till more data is acquired DiameterX = 10, @@ -500,23 +500,29 @@ namespace Ryujinx.Ui hasTouch = true; - _device.Hid.SetTouchPoints(currentPoint); + _device.Hid.Touchscreen.Update(currentPoint); } } if (!hasTouch) { - _device.Hid.SetTouchPoints(); + _device.Hid.Touchscreen.Update(); } if (ConfigurationState.Instance.Hid.EnableKeyboard && hidKeyboard.HasValue) { - _device.Hid.WriteKeyboard(hidKeyboard.Value); + _device.Hid.Keyboard.Update(hidKeyboard.Value); } - BaseController controller = _device.Hid.PrimaryController; + _device.Hid.DebugPad.Update(); - controller.SendInput(currentButton, leftJoystick, rightJoystick); + _device.Hid.Npads.SetGamepadsInput(new GamepadInput + { + PlayerId = PlayerIndex.Auto, + Buttons = currentButton, + LStick = leftJoystick, + RStick = rightJoystick + }); // Toggle vsync if (currentHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync) && diff --git a/Ryujinx/Ui/KeyboardControls.cs b/Ryujinx/Ui/KeyboardControls.cs index db9c0cda..1f19fe32 100644 --- a/Ryujinx/Ui/KeyboardControls.cs +++ b/Ryujinx/Ui/KeyboardControls.cs @@ -1,32 +1,39 @@ -using OpenTK.Input; -using Ryujinx.HLE.Input; +using System; +using OpenTK.Input; +using Ryujinx.HLE.HOS.Services.Hid; using Ryujinx.UI.Input; namespace Ryujinx.Ui { + [Flags] + public enum HotkeyButtons + { + ToggleVSync = 1 << 0, + } + public static class KeyboardControls { - public static ControllerButtons GetButtons(NpadKeyboard npad, KeyboardState keyboard) + public static ControllerKeys GetButtons(NpadKeyboard npad, KeyboardState keyboard) { - ControllerButtons buttons = 0; + ControllerKeys buttons = 0; - if (keyboard[(Key)npad.LeftJoycon.StickButton]) buttons |= ControllerButtons.StickLeft; - if (keyboard[(Key)npad.LeftJoycon.DPadUp]) buttons |= ControllerButtons.DpadUp; - if (keyboard[(Key)npad.LeftJoycon.DPadDown]) buttons |= ControllerButtons.DpadDown; - if (keyboard[(Key)npad.LeftJoycon.DPadLeft]) buttons |= ControllerButtons.DpadLeft; - if (keyboard[(Key)npad.LeftJoycon.DPadRight]) buttons |= ControllerButtons.DPadRight; - if (keyboard[(Key)npad.LeftJoycon.ButtonMinus]) buttons |= ControllerButtons.Minus; - if (keyboard[(Key)npad.LeftJoycon.ButtonL]) buttons |= ControllerButtons.L; - if (keyboard[(Key)npad.LeftJoycon.ButtonZl]) buttons |= ControllerButtons.Zl; + if (keyboard[(Key)npad.LeftJoycon.StickButton]) buttons |= ControllerKeys.LStick; + if (keyboard[(Key)npad.LeftJoycon.DPadUp]) buttons |= ControllerKeys.DpadUp; + if (keyboard[(Key)npad.LeftJoycon.DPadDown]) buttons |= ControllerKeys.DpadDown; + if (keyboard[(Key)npad.LeftJoycon.DPadLeft]) buttons |= ControllerKeys.DpadLeft; + if (keyboard[(Key)npad.LeftJoycon.DPadRight]) buttons |= ControllerKeys.DpadRight; + if (keyboard[(Key)npad.LeftJoycon.ButtonMinus]) buttons |= ControllerKeys.Minus; + if (keyboard[(Key)npad.LeftJoycon.ButtonL]) buttons |= ControllerKeys.L | ControllerKeys.Sl; + if (keyboard[(Key)npad.LeftJoycon.ButtonZl]) buttons |= ControllerKeys.Zl; - if (keyboard[(Key)npad.RightJoycon.StickButton]) buttons |= ControllerButtons.StickRight; - if (keyboard[(Key)npad.RightJoycon.ButtonA]) buttons |= ControllerButtons.A; - if (keyboard[(Key)npad.RightJoycon.ButtonB]) buttons |= ControllerButtons.B; - if (keyboard[(Key)npad.RightJoycon.ButtonX]) buttons |= ControllerButtons.X; - if (keyboard[(Key)npad.RightJoycon.ButtonY]) buttons |= ControllerButtons.Y; - if (keyboard[(Key)npad.RightJoycon.ButtonPlus]) buttons |= ControllerButtons.Plus; - if (keyboard[(Key)npad.RightJoycon.ButtonR]) buttons |= ControllerButtons.R; - if (keyboard[(Key)npad.RightJoycon.ButtonZr]) buttons |= ControllerButtons.Zr; + if (keyboard[(Key)npad.RightJoycon.StickButton]) buttons |= ControllerKeys.RStick; + if (keyboard[(Key)npad.RightJoycon.ButtonA]) buttons |= ControllerKeys.A; + if (keyboard[(Key)npad.RightJoycon.ButtonB]) buttons |= ControllerKeys.B; + if (keyboard[(Key)npad.RightJoycon.ButtonX]) buttons |= ControllerKeys.X; + if (keyboard[(Key)npad.RightJoycon.ButtonY]) buttons |= ControllerKeys.Y; + if (keyboard[(Key)npad.RightJoycon.ButtonPlus]) buttons |= ControllerKeys.Plus; + if (keyboard[(Key)npad.RightJoycon.ButtonR]) buttons |= ControllerKeys.R | ControllerKeys.Sr; + if (keyboard[(Key)npad.RightJoycon.ButtonZr]) buttons |= ControllerKeys.Zr; return buttons; } @@ -216,9 +223,9 @@ namespace Ryujinx.Ui new KeyMappingEntry { TargetKey = Key.NumLock, Target = 10 }, }; - public static HLE.Input.Keyboard GetKeysDown(NpadKeyboard npad, KeyboardState keyboard) + public static KeyboardInput GetKeysDown(NpadKeyboard npad, KeyboardState keyboard) { - HLE.Input.Keyboard hidKeyboard = new HLE.Input.Keyboard + KeyboardInput hidKeyboard = new KeyboardInput { Modifier = 0, Keys = new int[0x8] diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index 2415280b..4bbfc78b 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -10,6 +10,7 @@ using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.OpenGL; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem.Content; +using Ryujinx.HLE.HOS.Services.Hid; using System; using System.Collections.Generic; using System.Diagnostics; @@ -446,7 +447,19 @@ namespace Ryujinx.Ui private void CreateGameWindow(HLE.Switch device) { - device.Hid.InitializePrimaryController(ConfigurationState.Instance.Hid.ControllerType); + ControllerType type = (Ryujinx.Configuration.Hid.ControllerType)ConfigurationState.Instance.Hid.ControllerType switch { + Ryujinx.Configuration.Hid.ControllerType.ProController => ControllerType.ProController, + Ryujinx.Configuration.Hid.ControllerType.Handheld => ControllerType.Handheld, + Ryujinx.Configuration.Hid.ControllerType.NpadPair => ControllerType.JoyconPair, + Ryujinx.Configuration.Hid.ControllerType.NpadLeft => ControllerType.JoyconLeft, + Ryujinx.Configuration.Hid.ControllerType.NpadRight => ControllerType.JoyconRight, + _ => ControllerType.Handheld + }; + + device.Hid.Npads.AddControllers(new ControllerConfig { + Player = PlayerIndex.Player1, + Type = type + }); _gLWidget = new GLRenderer(_emulationContext); diff --git a/Ryujinx/Ui/NpadController.cs b/Ryujinx/Ui/NpadController.cs index 67961b49..b92f687c 100644 --- a/Ryujinx/Ui/NpadController.cs +++ b/Ryujinx/Ui/NpadController.cs @@ -1,7 +1,7 @@ using OpenTK; using OpenTK.Input; using Ryujinx.Common.Configuration.Hid; -using Ryujinx.HLE.Input; +using Ryujinx.HLE.HOS.Services.Hid; using System; using InnerNpadController = Ryujinx.Common.Configuration.Hid.NpadController; @@ -24,7 +24,7 @@ namespace Ryujinx.Ui.Input return _inner.Enabled && Joystick.GetState(_inner.Index).IsConnected; } - public ControllerButtons GetButtons() + public ControllerKeys GetButtons() { if (!IsEnabled()) { @@ -33,30 +33,30 @@ namespace Ryujinx.Ui.Input JoystickState joystickState = Joystick.GetState(_inner.Index); - ControllerButtons buttons = 0; + ControllerKeys buttons = 0; - if (IsActivated(joystickState, _inner.LeftJoycon.DPadUp)) buttons |= ControllerButtons.DpadUp; - if (IsActivated(joystickState, _inner.LeftJoycon.DPadDown)) buttons |= ControllerButtons.DpadDown; - if (IsActivated(joystickState, _inner.LeftJoycon.DPadLeft)) buttons |= ControllerButtons.DpadLeft; - if (IsActivated(joystickState, _inner.LeftJoycon.DPadRight)) buttons |= ControllerButtons.DPadRight; - if (IsActivated(joystickState, _inner.LeftJoycon.StickButton)) buttons |= ControllerButtons.StickLeft; - if (IsActivated(joystickState, _inner.LeftJoycon.ButtonMinus)) buttons |= ControllerButtons.Minus; - if (IsActivated(joystickState, _inner.LeftJoycon.ButtonL)) buttons |= ControllerButtons.L; - if (IsActivated(joystickState, _inner.LeftJoycon.ButtonZl)) buttons |= ControllerButtons.Zl; + if (IsActivated(joystickState, _inner.LeftJoycon.DPadUp)) buttons |= ControllerKeys.DpadUp; + if (IsActivated(joystickState, _inner.LeftJoycon.DPadDown)) buttons |= ControllerKeys.DpadDown; + if (IsActivated(joystickState, _inner.LeftJoycon.DPadLeft)) buttons |= ControllerKeys.DpadLeft; + if (IsActivated(joystickState, _inner.LeftJoycon.DPadRight)) buttons |= ControllerKeys.DpadRight; + if (IsActivated(joystickState, _inner.LeftJoycon.StickButton)) buttons |= ControllerKeys.LStick; + if (IsActivated(joystickState, _inner.LeftJoycon.ButtonMinus)) buttons |= ControllerKeys.Minus; + if (IsActivated(joystickState, _inner.LeftJoycon.ButtonL)) buttons |= ControllerKeys.L | ControllerKeys.Sl; + if (IsActivated(joystickState, _inner.LeftJoycon.ButtonZl)) buttons |= ControllerKeys.Zl; - if (IsActivated(joystickState, _inner.RightJoycon.ButtonA)) buttons |= ControllerButtons.A; - if (IsActivated(joystickState, _inner.RightJoycon.ButtonB)) buttons |= ControllerButtons.B; - if (IsActivated(joystickState, _inner.RightJoycon.ButtonX)) buttons |= ControllerButtons.X; - if (IsActivated(joystickState, _inner.RightJoycon.ButtonY)) buttons |= ControllerButtons.Y; - if (IsActivated(joystickState, _inner.RightJoycon.StickButton)) buttons |= ControllerButtons.StickRight; - if (IsActivated(joystickState, _inner.RightJoycon.ButtonPlus)) buttons |= ControllerButtons.Plus; - if (IsActivated(joystickState, _inner.RightJoycon.ButtonR)) buttons |= ControllerButtons.R; - if (IsActivated(joystickState, _inner.RightJoycon.ButtonZr)) buttons |= ControllerButtons.Zr; + if (IsActivated(joystickState, _inner.RightJoycon.ButtonA)) buttons |= ControllerKeys.A; + if (IsActivated(joystickState, _inner.RightJoycon.ButtonB)) buttons |= ControllerKeys.B; + if (IsActivated(joystickState, _inner.RightJoycon.ButtonX)) buttons |= ControllerKeys.X; + if (IsActivated(joystickState, _inner.RightJoycon.ButtonY)) buttons |= ControllerKeys.Y; + if (IsActivated(joystickState, _inner.RightJoycon.StickButton)) buttons |= ControllerKeys.RStick; + if (IsActivated(joystickState, _inner.RightJoycon.ButtonPlus)) buttons |= ControllerKeys.Plus; + if (IsActivated(joystickState, _inner.RightJoycon.ButtonR)) buttons |= ControllerKeys.R | ControllerKeys.Sr; + if (IsActivated(joystickState, _inner.RightJoycon.ButtonZr)) buttons |= ControllerKeys.Zr; return buttons; } - private bool IsActivated(JoystickState joystickState,ControllerInputId controllerInputId) + private bool IsActivated(JoystickState joystickState, ControllerInputId controllerInputId) { if (controllerInputId <= ControllerInputId.Button20) {