From 3443023a0844822f4f320ea4f75d9522fb5bbc01 Mon Sep 17 00:00:00 2001 From: Mary Date: Sun, 2 May 2021 22:01:30 +0200 Subject: [PATCH] hid: Rewrite shared memory management (#2257) * hid: Rewrite shared memory management This entirely rewrite our ancient (and original) HID shared memory interface to be more usable and accurate. HID update logics were updated to reflect those changes but should work still the same way it previously did. This need heavy testing just in case to avoid possible regressions. * Silence warnings * Address gdkchan's comments * Address Ac_K's comments * Address one missing nit --- .../Applets/Controller/ControllerApplet.cs | 1 + Ryujinx.HLE/HOS/Services/Hid/Hid.cs | 50 +- .../HOS/Services/Hid/HidDevices/BaseDevice.cs | 13 - .../Services/Hid/HidDevices/DebugPadDevice.cs | 19 +- .../Services/Hid/HidDevices/KeyboardDevice.cs | 27 +- .../Services/Hid/HidDevices/MouseDevice.cs | 44 +- .../Services/Hid/HidDevices/NpadDevices.cs | 428 ++++++++++++------ .../Services/Hid/HidDevices/TouchDevice.cs | 53 +-- .../Hid/HidDevices/Types/KeyboardInput.cs | 2 +- Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs | 3 +- .../HOS/Services/Hid/Types/Boolean32.cs | 9 - .../Types/{SharedMem/Npad => }/HidVector.cs | 2 +- .../HOS/Services/Hid/Types/Npad/NpadColor.cs | 2 +- .../{SharedMem/Npad => }/NpadJoyHoldType.cs | 4 +- .../Types/SharedMem/CommonEntriesHeader.cs | 11 - .../Hid/Types/SharedMem/DebugPad/DebugPad.cs | 11 - .../Types/SharedMem/DebugPad/DebugPadEntry.cs | 9 - .../Hid/Types/SharedMem/HidSharedMemory.cs | 23 - .../Hid/Types/SharedMem/Keyboard/Keyboard.cs | 11 - .../Types/SharedMem/Keyboard/KeyboardState.cs | 10 - .../Hid/Types/SharedMem/Mouse/Mouse.cs | 12 - .../Types/SharedMem/Mouse/MousePosition.cs | 12 - .../Hid/Types/SharedMem/Mouse/MouseState.cs | 10 - .../Hid/Types/SharedMem/Npad/BatterCharge.cs | 11 - .../Hid/Types/SharedMem/Npad/DeviceType.cs | 26 -- .../Services/Hid/Types/SharedMem/Npad/Npad.cs | 23 - .../SharedMem/Npad/NpadColorDescription.cs | 10 - .../SharedMem/Npad/NpadConnectionState.cs | 13 - .../Hid/Types/SharedMem/Npad/NpadLayout.cs | 10 - .../Types/SharedMem/Npad/NpadLayoutsIndex.cs | 13 - .../Hid/Types/SharedMem/Npad/NpadSixAxis.cs | 10 - .../Hid/Types/SharedMem/Npad/NpadState.cs | 14 - .../Types/SharedMem/Npad/NpadStatesHeader.cs | 16 - .../SharedMem/Npad/NpadSystemProperties.cs | 22 - .../SharedMem/Npad/SixAxisLayoutsIndex.cs | 14 - .../Hid/Types/SharedMem/Npad/SixAxisState.cs | 14 - .../SharedMem/Touchscreen/TouchScreen.cs | 11 - .../SharedMem/Touchscreen/TouchScreenState.cs | 12 - .../Touchscreen/TouchScreenStateData.cs | 19 - .../SharedMemory/Common/AnalogStickState.cs | 8 + .../SharedMemory/Common/AtomicStorage.cs | 26 ++ .../Types/SharedMemory/Common/ISampledData.cs | 7 + .../Hid/Types/SharedMemory/Common/RingLifo.cs | 149 ++++++ .../DebugPad/DebugPadAttribute.cs | 11 + .../SharedMemory/DebugPad/DebugPadButton.cs | 24 + .../SharedMemory/DebugPad/DebugPadState.cs | 15 + .../SharedMemory/Keyboard/KeyboardKey.cs | 29 ++ .../SharedMemory/Keyboard/KeyboardKeyShift.cs | 138 ++++++ .../SharedMemory/Keyboard/KeyboardModifier.cs | 21 + .../SharedMemory/Keyboard/KeyboardState.cs | 13 + .../SharedMemory/Mouse/MouseAttribute.cs | 12 + .../Types/SharedMemory/Mouse/MouseButton.cs | 15 + .../Types/SharedMemory/Mouse/MouseState.cs | 19 + .../Hid/Types/SharedMemory/Npad/DeviceType.cs | 29 ++ .../Types/SharedMemory/Npad/NpadAttribute.cs | 16 + .../SharedMemory/Npad/NpadBatteryLevel.cs | 11 + .../Hid/Types/SharedMemory/Npad/NpadButton.cs | 44 ++ .../SharedMemory/Npad/NpadColorAttribute.cs | 9 + .../SharedMemory/Npad/NpadCommonState.cs | 16 + .../Npad/NpadFullKeyColorState.cs | 9 + .../SharedMemory/Npad/NpadGcTriggerState.cs | 15 + .../SharedMemory/Npad/NpadInternalState.cs | 61 +++ .../Npad/NpadJoyAssignmentMode.cs | 8 + .../SharedMemory/Npad/NpadJoyColorState.cs | 11 + .../Types/SharedMemory/Npad/NpadLarkType.cs | 11 + .../Types/SharedMemory/Npad/NpadLuciaType.cs | 10 + .../Hid/Types/SharedMemory/Npad/NpadState.cs | 18 + .../Types/SharedMemory/Npad/NpadStyleTag.cs | 76 ++++ .../Npad/NpadSystemButtonProperties.cs | 11 + .../SharedMemory/Npad/NpadSystemProperties.cs | 24 + .../Npad/SixAxisSensorAttribute.cs | 12 + .../SharedMemory/Npad/SixAxisSensorState.cs | 19 + .../Hid/Types/SharedMemory/SharedMemory.cs | 66 +++ .../TouchScreen/TouchAttribute.cs | 12 + .../TouchScreen/TouchScreenState.cs | 15 + .../SharedMemory/TouchScreen/TouchState.cs | 19 + Ryujinx.Input/HLE/NpadController.cs | 6 +- 77 files changed, 1395 insertions(+), 624 deletions(-) delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs rename Ryujinx.HLE/HOS/Services/Hid/Types/{SharedMem/Npad => }/HidVector.cs (70%) rename Ryujinx.HLE/HOS/Services/Hid/Types/{SharedMem/Npad => }/NpadJoyHoldType.cs (60%) delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/CommonEntriesHeader.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPad.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPadEntry.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/HidSharedMemory.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/Keyboard.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/KeyboardState.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/Mouse.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MousePosition.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MouseState.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/BatterCharge.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/DeviceType.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadColorDescription.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadConnectionState.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayout.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayoutsIndex.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSixAxis.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadState.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadStatesHeader.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSystemProperties.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisLayoutsIndex.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisState.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreen.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenState.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenStateData.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/AnalogStickState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/AtomicStorage.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/ISampledData.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/RingLifo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadAttribute.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadButton.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardKey.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardKeyShift.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardModifier.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseAttribute.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseButton.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/DeviceType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadAttribute.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadBatteryLevel.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadButton.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadColorAttribute.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadCommonState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadFullKeyColorState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadGcTriggerState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadInternalState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadJoyAssignmentMode.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadJoyColorState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadLarkType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadLuciaType.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadStyleTag.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadSystemButtonProperties.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadSystemProperties.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/SixAxisSensorAttribute.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/SixAxisSensorState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/SharedMemory.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchAttribute.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchScreenState.cs create mode 100644 Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchState.cs diff --git a/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs b/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs index fd89e8f6..0597cf9b 100644 --- a/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs +++ b/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs @@ -4,6 +4,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Services.Hid; +using Ryujinx.HLE.HOS.Services.Hid.Types; using Ryujinx.HLE.HOS.Services.Am.AppletAE; using static Ryujinx.HLE.HOS.Services.Hid.HidServer.HidUtils; diff --git a/Ryujinx.HLE/HOS/Services/Hid/Hid.cs b/Ryujinx.HLE/HOS/Services/Hid/Hid.cs index 18a7ba11..1e85dbf7 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/Hid.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/Hid.cs @@ -3,6 +3,14 @@ using Ryujinx.HLE.Exceptions; using Ryujinx.Common.Configuration.Hid; using System.Collections.Generic; using System.Runtime.CompilerServices; +using Ryujinx.Common.Memory; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad; namespace Ryujinx.HLE.HOS.Services.Hid { @@ -12,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid private readonly ulong _hidMemoryAddress; - internal ref HidSharedMemory SharedMemory => ref _device.Memory.GetRef(_hidMemoryAddress); + internal ref SharedMemory SharedMemory => ref _device.Memory.GetRef(_hidMemoryAddress); internal const int SharedMemEntryCount = 17; @@ -22,32 +30,22 @@ namespace Ryujinx.HLE.HOS.Services.Hid public KeyboardDevice Keyboard; public NpadDevices Npads; + private static void CheckTypeSizeOrThrow(int expectedSize) + { + if (Unsafe.SizeOf() != expectedSize) + { + throw new InvalidStructLayoutException(expectedSize); + } + } + 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); - } + CheckTypeSizeOrThrow>(0x2c8); + CheckTypeSizeOrThrow>(0x2C38); + CheckTypeSizeOrThrow>(0x350); + CheckTypeSizeOrThrow>(0x3D8); + CheckTypeSizeOrThrow>(0x32000); + CheckTypeSizeOrThrow(Horizon.HidSize); } public Hid(in Switch device, ulong sharedHidMemoryAddress) @@ -55,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid _device = device; _hidMemoryAddress = sharedHidMemoryAddress; - device.Memory.ZeroFill(sharedHidMemoryAddress, Horizon.HidSize); + SharedMemory = SharedMemory.Create(); } public void InitDevices() diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs index 59d6dfa3..e8bf628a 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs @@ -12,18 +12,5 @@ namespace Ryujinx.HLE.HOS.Services.Hid _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 index 7e708e32..e3b95390 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs @@ -1,3 +1,6 @@ +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad; + namespace Ryujinx.HLE.HOS.Services.Hid { public class DebugPadDevice : BaseDevice @@ -6,20 +9,20 @@ namespace Ryujinx.HLE.HOS.Services.Hid public void Update() { - ref ShMemDebugPad debugPad = ref _device.Hid.SharedMemory.DebugPad; + ref RingLifo lifo = ref _device.Hid.SharedMemory.DebugPad; - int currentIndex = UpdateEntriesHeader(ref debugPad.Header, out int previousIndex); + ref DebugPadState previousEntry = ref lifo.GetCurrentEntryRef(); - if (!Active) + DebugPadState newState = new DebugPadState(); + + if (Active) { - return; + // TODO: This is a debug device only present in dev environment, do we want to support it? } - ref DebugPadEntry currentEntry = ref debugPad.Entries[currentIndex]; - DebugPadEntry previousEntry = debugPad.Entries[previousIndex]; + newState.SamplingNumber = previousEntry.SamplingNumber + 1; - currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1; - currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1; + lifo.Write(ref newState); } } } \ 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 index e8ed6a3e..99dc078d 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs @@ -1,3 +1,7 @@ +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard; +using System; + namespace Ryujinx.HLE.HOS.Services.Hid { public class KeyboardDevice : BaseDevice @@ -6,27 +10,26 @@ namespace Ryujinx.HLE.HOS.Services.Hid public unsafe void Update(KeyboardInput keyState) { - ref ShMemKeyboard keyboard = ref _device.Hid.SharedMemory.Keyboard; - - int currentIndex = UpdateEntriesHeader(ref keyboard.Header, out int previousIndex); + ref RingLifo lifo = ref _device.Hid.SharedMemory.Keyboard; if (!Active) { + lifo.Clear(); + return; } - ref KeyboardState currentEntry = ref keyboard.Entries[currentIndex]; - KeyboardState previousEntry = keyboard.Entries[previousIndex]; + ref KeyboardState previousEntry = ref lifo.GetCurrentEntryRef(); - currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1; - currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1; - - for (int i = 0; i < 8; ++i) + KeyboardState newState = new KeyboardState { - currentEntry.Keys[i] = (uint)keyState.Keys[i]; - } + SamplingNumber = previousEntry.SamplingNumber + 1, + }; - currentEntry.Modifier = (ulong)keyState.Modifier; + keyState.Keys.AsSpan().CopyTo(newState.Keys.RawData.ToSpan()); + newState.Modifiers = (KeyboardModifier)keyState.Modifier; + + lifo.Write(ref newState); } } } \ 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 index ee58a563..e07c1d20 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs @@ -1,37 +1,35 @@ +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse; + 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) + public void Update(int mouseX, int mouseY, uint buttons = 0, int scrollX = 0, int scrollY = 0) { - ref ShMemMouse mouse = ref _device.Hid.SharedMemory.Mouse; + ref RingLifo lifo = ref _device.Hid.SharedMemory.Mouse; - int currentIndex = UpdateEntriesHeader(ref mouse.Header, out int previousIndex); - - if (!Active) + ref MouseState previousEntry = ref lifo.GetCurrentEntryRef(); + + MouseState newState = new MouseState() { - return; + SamplingNumber = previousEntry.SamplingNumber + 1, + }; + + if (Active) + { + newState.Buttons = (MouseButton)buttons; + newState.X = mouseX; + newState.Y = mouseY; + newState.DeltaX = mouseX - previousEntry.DeltaX; + newState.DeltaY = mouseY - previousEntry.DeltaY; + newState.WheelDeltaX = scrollX; + newState.WheelDeltaY = scrollY; } - 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 - }; + lifo.Write(ref newState); } } } \ 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 index 2150f278..3ff7e733 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs @@ -1,16 +1,17 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Ryujinx.Common; using Ryujinx.Common.Logging; -using Ryujinx.Common.Memory; using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.HLE.HOS.Services.Hid.Types; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad; namespace Ryujinx.HLE.HOS.Services.Hid { public class NpadDevices : BaseDevice { - private const BatteryCharge DefaultBatteryCharge = BatteryCharge.Percent100; - private const int NoMatchNotifyFrequencyMs = 2000; private int _activeCount; private long _lastNotifyTimestamp; @@ -86,7 +87,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid continue; } - ControllerType currentType = _device.Hid.SharedMemory.Npads[i].Header.Type; + ControllerType currentType = (ControllerType)_device.Hid.SharedMemory.Npads[i].InternalState.StyleSet; if (currentType != ControllerType.None && (npad & acceptedTypes) != 0 && _supportedPlayers[i]) { @@ -135,12 +136,24 @@ namespace Ryujinx.HLE.HOS.Services.Hid { Remap(); - UpdateAllEntries(); + Span updated = stackalloc bool[10]; // Update configured inputs for (int i = 0; i < states.Count; ++i) { - UpdateInput(states[i]); + GamepadInput state = states[i]; + + updated[(int)state.PlayerId] = true; + + UpdateInput(state); + } + + for (int i = 0; i < updated.Length; i++) + { + if (!updated[i]) + { + UpdateDisconnectedInput((PlayerIndex)i); + } } } @@ -185,16 +198,16 @@ namespace Ryujinx.HLE.HOS.Services.Hid private void SetupNpad(PlayerIndex player, ControllerType type) { - ref ShMemNpad controller = ref _device.Hid.SharedMemory.Npads[(int)player]; + ref NpadInternalState controller = ref _device.Hid.SharedMemory.Npads[(int)player].InternalState; - ControllerType oldType = controller.Header.Type; + ControllerType oldType = (ControllerType)controller.StyleSet; if (oldType == type) { return; // Already configured } - controller = new ShMemNpad(); // Zero it + controller = NpadInternalState.Create(); // Reset it if (type == ControllerType.None) { @@ -207,87 +220,151 @@ namespace Ryujinx.HLE.HOS.Services.Hid } // 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.JoyAssignmentMode = NpadJoyAssignmentMode.Dual; + controller.FullKeyColor.FullKeyBody = (uint)NpadColor.BodyGray; + controller.FullKeyColor.FullKeyButtons = (uint)NpadColor.ButtonGray; + controller.JoyColor.LeftBody = (uint)NpadColor.BodyNeonBlue; + controller.JoyColor.LeftButtons = (uint)NpadColor.ButtonGray; + controller.JoyColor.RightBody = (uint)NpadColor.BodyNeonRed; + controller.JoyColor.RightButtons = (uint)NpadColor.ButtonGray; - controller.SystemProperties = NpadSystemProperties.PowerInfo0Connected | - NpadSystemProperties.PowerInfo1Connected | - NpadSystemProperties.PowerInfo2Connected; + controller.SystemProperties = NpadSystemProperties.IsPoweredJoyDual | + NpadSystemProperties.IsPoweredJoyLeft | + NpadSystemProperties.IsPoweredJoyRight; - controller.BatteryState.ToSpan().Fill(DefaultBatteryCharge); + controller.BatteryLevelJoyDual = NpadBatteryLevel.Percent100; + controller.BatteryLevelJoyLeft = NpadBatteryLevel.Percent100; + controller.BatteryLevelJoyRight = NpadBatteryLevel.Percent100; switch (type) { case ControllerType.ProController: - defaultHeader.Type = ControllerType.ProController; + controller.StyleSet = NpadStyleTag.FullKey; controller.DeviceType = DeviceType.FullKey; - controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented | - NpadSystemProperties.PlusButtonCapability | - NpadSystemProperties.MinusButtonCapability; + controller.SystemProperties |= NpadSystemProperties.IsAbxyButtonOriented | + NpadSystemProperties.IsPlusAvailable | + NpadSystemProperties.IsMinusAvailable; break; case ControllerType.Handheld: - defaultHeader.Type = ControllerType.Handheld; + controller.StyleSet = NpadStyleTag.Handheld; controller.DeviceType = DeviceType.HandheldLeft | DeviceType.HandheldRight; - controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented | - NpadSystemProperties.PlusButtonCapability | - NpadSystemProperties.MinusButtonCapability; + controller.SystemProperties |= NpadSystemProperties.IsAbxyButtonOriented | + NpadSystemProperties.IsPlusAvailable | + NpadSystemProperties.IsMinusAvailable; break; case ControllerType.JoyconPair: - defaultHeader.Type = ControllerType.JoyconPair; + controller.StyleSet = NpadStyleTag.JoyDual; controller.DeviceType = DeviceType.JoyLeft | DeviceType.JoyRight; - controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented | - NpadSystemProperties.PlusButtonCapability | - NpadSystemProperties.MinusButtonCapability; + controller.SystemProperties |= NpadSystemProperties.IsAbxyButtonOriented | + NpadSystemProperties.IsPlusAvailable | + NpadSystemProperties.IsMinusAvailable; break; case ControllerType.JoyconLeft: - defaultHeader.Type = ControllerType.JoyconLeft; - defaultHeader.IsHalf = true; + controller.StyleSet = NpadStyleTag.JoyLeft; + controller.JoyAssignmentMode = NpadJoyAssignmentMode.Single; controller.DeviceType = DeviceType.JoyLeft; - controller.SystemProperties |= NpadSystemProperties.SlSrButtonOriented | - NpadSystemProperties.MinusButtonCapability; + controller.SystemProperties |= NpadSystemProperties.IsSlSrButtonOriented | + NpadSystemProperties.IsMinusAvailable; break; case ControllerType.JoyconRight: - defaultHeader.Type = ControllerType.JoyconRight; - defaultHeader.IsHalf = true; + controller.StyleSet = NpadStyleTag.JoyRight; + controller.JoyAssignmentMode = NpadJoyAssignmentMode.Single; controller.DeviceType = DeviceType.JoyRight; - controller.SystemProperties |= NpadSystemProperties.SlSrButtonOriented | - NpadSystemProperties.PlusButtonCapability; + controller.SystemProperties |= NpadSystemProperties.IsSlSrButtonOriented | + NpadSystemProperties.IsPlusAvailable; break; case ControllerType.Pokeball: - defaultHeader.Type = ControllerType.Pokeball; + controller.StyleSet = NpadStyleTag.Palma; controller.DeviceType = DeviceType.Palma; break; } - controller.Header = defaultHeader; - _styleSetUpdateEvents[(int)player].ReadableEvent.Signal(); _activeCount++; Logger.Info?.Print(LogClass.Hid, $"Connected Controller {type} to {player}"); } - private static NpadLayoutsIndex ControllerTypeToNpadLayout(ControllerType controllerType) - => controllerType switch + private ref RingLifo GetCommonStateLifo(ref NpadInternalState npad) { - 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 - }; + switch (npad.StyleSet) + { + case NpadStyleTag.FullKey: + return ref npad.FullKey; + case NpadStyleTag.Handheld: + return ref npad.Handheld; + case NpadStyleTag.JoyDual: + return ref npad.JoyDual; + case NpadStyleTag.JoyLeft: + return ref npad.JoyLeft; + case NpadStyleTag.JoyRight: + return ref npad.JoyRight; + case NpadStyleTag.Palma: + return ref npad.Palma; + default: + return ref npad.SystemExt; + } + } + + private void UpdateUnusedInputIfNotEqual(ref RingLifo currentlyUsed, ref RingLifo possiblyUnused) + { + bool isEquals; + + unsafe + { + var aPointer = Unsafe.AsPointer(ref currentlyUsed); + var bPointer = Unsafe.AsPointer(ref possiblyUnused); + + isEquals = aPointer == bPointer; + } + + if (!isEquals) + { + NpadCommonState newState = new NpadCommonState(); + + WriteNewInputEntry(ref possiblyUnused, ref newState); + } + } + + private void WriteNewInputEntry(ref RingLifo lifo, ref NpadCommonState state) + { + ref NpadCommonState previousEntry = ref lifo.GetCurrentEntryRef(); + + state.SamplingNumber = previousEntry.SamplingNumber + 1; + + lifo.Write(ref state); + } + + private void UpdateUnusedSixInputIfNotEqual(ref RingLifo currentlyUsed, ref RingLifo possiblyUnused) + { + bool isEquals; + + unsafe + { + var aPointer = Unsafe.AsPointer(ref currentlyUsed); + var bPointer = Unsafe.AsPointer(ref possiblyUnused); + + isEquals = aPointer == bPointer; + } + + if (!isEquals) + { + SixAxisSensorState newState = new SixAxisSensorState(); + + WriteNewSixInputEntry(ref possiblyUnused, ref newState); + } + } + + private void WriteNewSixInputEntry(ref RingLifo lifo, ref SixAxisSensorState state) + { + ref SixAxisSensorState previousEntry = ref lifo.GetCurrentEntryRef(); + + state.SamplingNumber = previousEntry.SamplingNumber + 1; + + lifo.Write(ref state); + } private void UpdateInput(GamepadInput state) { @@ -296,43 +373,88 @@ namespace Ryujinx.HLE.HOS.Services.Hid return; } - ref ShMemNpad currentNpad = ref _device.Hid.SharedMemory.Npads[(int)state.PlayerId]; + ref NpadInternalState currentNpad = ref _device.Hid.SharedMemory.Npads[(int)state.PlayerId].InternalState; - if (currentNpad.Header.Type == ControllerType.None) + if (currentNpad.StyleSet == NpadStyleTag.None) { return; } - ref NpadLayout currentLayout = ref currentNpad.Layouts[(int)ControllerTypeToNpadLayout(currentNpad.Header.Type)]; - ref NpadState currentEntry = ref currentLayout.Entries[(int)currentLayout.Header.LatestEntry]; + ref RingLifo lifo = ref GetCommonStateLifo(ref currentNpad); - currentEntry.Buttons = state.Buttons; - currentEntry.LStickX = state.LStick.Dx; - currentEntry.LStickY = state.LStick.Dy; - currentEntry.RStickX = state.RStick.Dx; - currentEntry.RStickY = state.RStick.Dy; + NpadCommonState newState = new NpadCommonState + { + Buttons = (NpadButton)state.Buttons, + AnalogStickL = new AnalogStickState + { + X = state.LStick.Dx, + Y = state.LStick.Dy, + }, + AnalogStickR = new AnalogStickState + { + X = state.RStick.Dx, + Y = state.RStick.Dy, + } + }; + + newState.Attributes = NpadAttribute.IsConnected; + + switch (currentNpad.StyleSet) + { + case NpadStyleTag.Handheld: + case NpadStyleTag.FullKey: + newState.Attributes |= NpadAttribute.IsWired; + break; + case NpadStyleTag.JoyDual: + newState.Attributes |= NpadAttribute.IsLeftConnected | + NpadAttribute.IsRightConnected; + break; + case NpadStyleTag.JoyLeft: + newState.Attributes |= NpadAttribute.IsLeftConnected; + break; + case NpadStyleTag.JoyRight: + newState.Attributes |= NpadAttribute.IsRightConnected; + break; + } + + WriteNewInputEntry(ref lifo, ref newState); // Mirror data to Default layout just in case - ref NpadLayout mainLayout = ref currentNpad.Layouts[(int)NpadLayoutsIndex.SystemExternal]; - mainLayout.Entries[(int)mainLayout.Header.LatestEntry] = currentEntry; + if (!currentNpad.StyleSet.HasFlag(NpadStyleTag.SystemExt)) + { + WriteNewInputEntry(ref currentNpad.SystemExt, ref newState); + } + + UpdateUnusedInputIfNotEqual(ref lifo, ref currentNpad.FullKey); + UpdateUnusedInputIfNotEqual(ref lifo, ref currentNpad.Handheld); + UpdateUnusedInputIfNotEqual(ref lifo, ref currentNpad.JoyDual); + UpdateUnusedInputIfNotEqual(ref lifo, ref currentNpad.JoyLeft); + UpdateUnusedInputIfNotEqual(ref lifo, ref currentNpad.JoyRight); + UpdateUnusedInputIfNotEqual(ref lifo, ref currentNpad.Palma); } - private static SixAxixLayoutsIndex ControllerTypeToSixAxisLayout(ControllerType controllerType) - => controllerType switch + private void UpdateDisconnectedInput(PlayerIndex index) { - ControllerType.ProController => SixAxixLayoutsIndex.ProController, - ControllerType.Handheld => SixAxixLayoutsIndex.Handheld, - ControllerType.JoyconPair => SixAxixLayoutsIndex.JoyDualLeft, - ControllerType.JoyconLeft => SixAxixLayoutsIndex.JoyLeft, - ControllerType.JoyconRight => SixAxixLayoutsIndex.JoyRight, - ControllerType.Pokeball => SixAxixLayoutsIndex.Pokeball, - _ => SixAxixLayoutsIndex.SystemExternal - }; + ref NpadInternalState currentNpad = ref _device.Hid.SharedMemory.Npads[(int)index].InternalState; + + NpadCommonState newState = new NpadCommonState(); + + WriteNewInputEntry(ref currentNpad.FullKey, ref newState); + WriteNewInputEntry(ref currentNpad.Handheld, ref newState); + WriteNewInputEntry(ref currentNpad.JoyDual, ref newState); + WriteNewInputEntry(ref currentNpad.JoyLeft, ref newState); + WriteNewInputEntry(ref currentNpad.JoyRight, ref newState); + WriteNewInputEntry(ref currentNpad.Palma, ref newState); + } public void UpdateSixAxis(IList states) { + Span updated = stackalloc bool[10]; + for (int i = 0; i < states.Count; ++i) { + updated[(int)states[i].PlayerId] = true; + if (SetSixAxisState(states[i])) { i++; @@ -345,6 +467,40 @@ namespace Ryujinx.HLE.HOS.Services.Hid SetSixAxisState(states[i], true); } } + + for (int i = 0; i < updated.Length; i++) + { + if (!updated[i]) + { + UpdateDisconnectedInputSixAxis((PlayerIndex)i); + } + } + } + + private ref RingLifo GetSixAxisSensorLifo(ref NpadInternalState npad, bool isRightPair) + { + switch (npad.StyleSet) + { + case NpadStyleTag.FullKey: + return ref npad.FullKeySixAxisSensor; + case NpadStyleTag.Handheld: + return ref npad.HandheldSixAxisSensor; + case NpadStyleTag.JoyDual: + if (isRightPair) + { + return ref npad.JoyDualRightSixAxisSensor; + } + else + { + return ref npad.JoyDualSixAxisSensor; + } + case NpadStyleTag.JoyLeft: + return ref npad.JoyLeftSixAxisSensor; + case NpadStyleTag.JoyRight: + return ref npad.JoyRightSixAxisSensor; + default: + throw new NotImplementedException($"{npad.StyleSet}"); + } } private bool SetSixAxisState(SixAxisInput state, bool isRightPair = false) @@ -354,9 +510,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid return false; } - ref ShMemNpad currentNpad = ref _device.Hid.SharedMemory.Npads[(int)state.PlayerId]; + ref NpadInternalState currentNpad = ref _device.Hid.SharedMemory.Npads[(int)state.PlayerId].InternalState; - if (currentNpad.Header.Type == ControllerType.None) + if (currentNpad.StyleSet == NpadStyleTag.None) { return false; } @@ -382,87 +538,57 @@ namespace Ryujinx.HLE.HOS.Services.Hid Z = state.Rotation.Z }; - ref NpadSixAxis currentLayout = ref currentNpad.Sixaxis[(int)ControllerTypeToSixAxisLayout(currentNpad.Header.Type) + (isRightPair ? 1 : 0)]; - ref SixAxisState currentEntry = ref currentLayout.Entries[(int)currentLayout.Header.LatestEntry]; - - int previousEntryIndex = (int)(currentLayout.Header.LatestEntry == 0 ? - currentLayout.Header.MaxEntryIndex : currentLayout.Header.LatestEntry - 1); - - ref SixAxisState previousEntry = ref currentLayout.Entries[previousEntryIndex]; - - currentEntry.Accelerometer = accel; - currentEntry.Gyroscope = gyro; - currentEntry.Rotations = rotation; - - unsafe + SixAxisSensorState newState = new SixAxisSensorState { - for (int i = 0; i < 9; i++) - { - currentEntry.Orientation[i] = state.Orientation[i]; - } + Acceleration = accel, + AngularVelocity = gyro, + Angle = rotation, + Attributes = SixAxisSensorAttribute.IsConnected + }; + + state.Orientation.AsSpan().CopyTo(newState.Direction.ToSpan()); + + ref RingLifo lifo = ref GetSixAxisSensorLifo(ref currentNpad, isRightPair); + + WriteNewSixInputEntry(ref lifo, ref newState); + + bool needUpdateRight = currentNpad.StyleSet == NpadStyleTag.JoyDual && !isRightPair; + + if (!isRightPair) + { + UpdateUnusedSixInputIfNotEqual(ref lifo, ref currentNpad.FullKeySixAxisSensor); + UpdateUnusedSixInputIfNotEqual(ref lifo, ref currentNpad.HandheldSixAxisSensor); + UpdateUnusedSixInputIfNotEqual(ref lifo, ref currentNpad.JoyDualSixAxisSensor); + UpdateUnusedSixInputIfNotEqual(ref lifo, ref currentNpad.JoyLeftSixAxisSensor); + UpdateUnusedSixInputIfNotEqual(ref lifo, ref currentNpad.JoyRightSixAxisSensor); } - return currentNpad.Header.Type == ControllerType.JoyconPair && !isRightPair; + if (!needUpdateRight) + { + SixAxisSensorState emptyState = new SixAxisSensorState(); + + emptyState.Attributes = SixAxisSensorAttribute.IsConnected; + + WriteNewSixInputEntry(ref currentNpad.JoyDualRightSixAxisSensor, ref emptyState); + } + + return needUpdateRight; } - private void UpdateAllEntries() + private void UpdateDisconnectedInputSixAxis(PlayerIndex index) { - 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 NpadInternalState currentNpad = ref _device.Hid.SharedMemory.Npads[(int)index].InternalState; - ref NpadState currentEntry = ref currentLayout.Entries[currentIndex]; - NpadState previousEntry = currentLayout.Entries[previousIndex]; + SixAxisSensorState newState = new SixAxisSensorState(); - currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1; - currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1; + newState.Attributes = SixAxisSensorAttribute.IsConnected; - 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; - } - } - - ref Array6 sixaxis = ref controllers[i].Sixaxis; - for (int l = 0; l < sixaxis.Length; ++l) - { - ref NpadSixAxis currentLayout = ref sixaxis[l]; - int currentIndex = UpdateEntriesHeader(ref currentLayout.Header, out int previousIndex); - - ref SixAxisState currentEntry = ref currentLayout.Entries[currentIndex]; - SixAxisState previousEntry = currentLayout.Entries[previousIndex]; - - currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1; - currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1; - - currentEntry._unknown2 = 1; - } - } + WriteNewSixInputEntry(ref currentNpad.FullKeySixAxisSensor, ref newState); + WriteNewSixInputEntry(ref currentNpad.HandheldSixAxisSensor, ref newState); + WriteNewSixInputEntry(ref currentNpad.JoyDualSixAxisSensor, ref newState); + WriteNewSixInputEntry(ref currentNpad.JoyDualRightSixAxisSensor, ref newState); + WriteNewSixInputEntry(ref currentNpad.JoyLeftSixAxisSensor, ref newState); + WriteNewSixInputEntry(ref currentNpad.JoyRightSixAxisSensor, ref newState); } } } \ 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 index 10c34453..432a37e3 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs @@ -1,3 +1,5 @@ +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen; using System; namespace Ryujinx.HLE.HOS.Services.Hid @@ -8,39 +10,38 @@ namespace Ryujinx.HLE.HOS.Services.Hid public void Update(params TouchPoint[] points) { - ref ShMemTouchScreen touchscreen = ref _device.Hid.SharedMemory.TouchScreen; + ref RingLifo lifo = ref _device.Hid.SharedMemory.TouchScreen; - int currentIndex = UpdateEntriesHeader(ref touchscreen.Header, out int previousIndex); + ref TouchScreenState previousEntry = ref lifo.GetCurrentEntryRef(); - if (!Active) + TouchScreenState newState = new TouchScreenState { - return; - } + SamplingNumber = previousEntry.SamplingNumber + 1 + }; - 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) + if (Active) { - TouchPoint pi = points[i]; - currentEntry.Touches[i] = new TouchScreenStateData + newState.TouchesCount = points.Length; + + int pointsLength = Math.Min(points.Length, newState.Touches.Length); + + for (int i = 0; i < pointsLength; ++i) { - SampleTimestamp = currentEntry.SampleTimestamp, - X = pi.X, - Y = pi.Y, - TouchIndex = (uint)i, - DiameterX = pi.DiameterX, - DiameterY = pi.DiameterY, - Angle = pi.Angle - }; + TouchPoint pi = points[i]; + newState.Touches[i] = new TouchState + { + DeltaTime = newState.SamplingNumber, + X = pi.X, + Y = pi.Y, + FingerId = (uint)i, + DiameterX = pi.DiameterX, + DiameterY = pi.DiameterY, + RotationAngle = pi.Angle + }; + } } + + lifo.Write(ref newState); } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs index 26681270..be6857fb 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/KeyboardInput.cs @@ -3,6 +3,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid public struct KeyboardInput { public int Modifier; - public int[] Keys; + public ulong[] Keys; } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs index 2ab305ac..e3c22edf 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs @@ -3,6 +3,7 @@ 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.HOS.Services.Hid.Types; using System; using System.Collections.Generic; using System.Runtime.InteropServices; @@ -134,7 +135,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid // Initialize entries to avoid issues with some games. KeyboardInput emptyInput = new KeyboardInput(); - emptyInput.Keys = new int[8]; + emptyInput.Keys = new ulong[4]; for (int entry = 0; entry < Hid.SharedMemEntryCount; entry++) { diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs deleted file mode 100644 index 5a8d51c6..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs +++ /dev/null @@ -1,9 +0,0 @@ -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/SharedMem/Npad/HidVector.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/HidVector.cs similarity index 70% rename from Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/HidVector.cs rename to Ryujinx.HLE/HOS/Services/Hid/Types/HidVector.cs index b41bcb2e..18d9fd9c 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/HidVector.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/HidVector.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Hid +namespace Ryujinx.HLE.HOS.Services.Hid.Types { struct HidVector { diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs index 57b4b366..3c311e21 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs @@ -1,6 +1,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid { - public enum NpadColor : int + public enum NpadColor : uint { BodyGray = 0x828282, BodyNeonRed = 0xFF3C28, diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadJoyHoldType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/NpadJoyHoldType.cs similarity index 60% rename from Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadJoyHoldType.cs rename to Ryujinx.HLE/HOS/Services/Hid/Types/NpadJoyHoldType.cs index a6f29760..d3b51a24 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadJoyHoldType.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/NpadJoyHoldType.cs @@ -1,8 +1,8 @@ -namespace Ryujinx.HLE.HOS.Services.Hid +namespace Ryujinx.HLE.HOS.Services.Hid.Types { enum NpadJoyHoldType { Vertical, Horizontal } -} \ 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 deleted file mode 100644 index f83fdcdf..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/CommonEntriesHeader.cs +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 3fbaa304..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPad.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Ryujinx.Common.Memory; - -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 deleted file mode 100644 index 3089fc5b..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/DebugPad/DebugPadEntry.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Hid -{ - unsafe struct DebugPadEntry - { - public ulong SampleTimestamp; - public ulong SampleTimestamp2; - fixed byte _unknown[0x18]; - } -} \ 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 deleted file mode 100644 index d950425d..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/HidSharedMemory.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Ryujinx.Common.Memory; - -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 deleted file mode 100644 index e2c1844f..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/Keyboard.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Ryujinx.Common.Memory; - -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 deleted file mode 100644 index 1f54a4fd..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Keyboard/KeyboardState.cs +++ /dev/null @@ -1,10 +0,0 @@ -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 deleted file mode 100644 index 6b99e04a..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/Mouse.cs +++ /dev/null @@ -1,12 +0,0 @@ - -using Ryujinx.Common.Memory; - -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 deleted file mode 100644 index e94c9e0c..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MousePosition.cs +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 7856b09d..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/MouseState.cs +++ /dev/null @@ -1,10 +0,0 @@ -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 deleted file mode 100644 index b94ab172..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/BatterCharge.cs +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index f6d7b783..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/DeviceType.cs +++ /dev/null @@ -1,26 +0,0 @@ -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/Npad.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs deleted file mode 100644 index 4ef83f3d..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Ryujinx.Common.Memory; - -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/HOS/Services/Hid/Types/SharedMem/Npad/NpadColorDescription.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadColorDescription.cs deleted file mode 100644 index ccc7cb8d..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadColorDescription.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Hid -{ - [Flags] - enum NpadColorDescription : int - { - ColorDescriptionColorsNonexistent = (1 << 1) - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadConnectionState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadConnectionState.cs deleted file mode 100644 index 60f64fd3..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadConnectionState.cs +++ /dev/null @@ -1,13 +0,0 @@ -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/NpadLayout.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayout.cs deleted file mode 100644 index 24c4f4d4..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayout.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ryujinx.Common.Memory; - -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 deleted file mode 100644 index c4419336..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadLayoutsIndex.cs +++ /dev/null @@ -1,13 +0,0 @@ -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 deleted file mode 100644 index a0a39fdc..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSixAxis.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ryujinx.Common.Memory; - -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 deleted file mode 100644 index 60a5f9d3..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadState.cs +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index 006d4357..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadStatesHeader.cs +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 708f7da9..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/NpadSystemProperties.cs +++ /dev/null @@ -1,22 +0,0 @@ -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/SixAxisLayoutsIndex.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisLayoutsIndex.cs deleted file mode 100644 index a8795fc0..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisLayoutsIndex.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Hid -{ - enum SixAxixLayoutsIndex : int - { - ProController = 0, - Handheld = 1, - JoyDualLeft = 2, - JoyDualRight = 3, - JoyLeft = 4, - JoyRight = 5, - Pokeball = 6, - SystemExternal = 7 - } -} \ 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 deleted file mode 100644 index 12974e7e..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/SixAxisState.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Hid -{ - unsafe struct SixAxisState - { - public ulong SampleTimestamp; - ulong _unknown1; - public ulong SampleTimestamp2; - public HidVector Accelerometer; - public HidVector Gyroscope; - public HidVector Rotations; - public fixed float Orientation[9]; - public ulong _unknown2; - } -} \ 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 deleted file mode 100644 index 5f12295c..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreen.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Ryujinx.Common.Memory; - -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 deleted file mode 100644 index 1c85e291..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenState.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ryujinx.Common.Memory; - -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 deleted file mode 100644 index 4d4c48d1..00000000 --- a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Touchscreen/TouchScreenStateData.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Hid -{ - struct TouchScreenStateData - { - public ulong SampleTimestamp; -#pragma warning disable CS0169 - uint _padding; -#pragma warning restore CS0169 - public uint TouchIndex; - public uint X; - public uint Y; - public uint DiameterX; - public uint DiameterY; - public uint Angle; -#pragma warning disable CS0169 - uint _padding2; -#pragma warning restore CS0169 - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/AnalogStickState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/AnalogStickState.cs new file mode 100644 index 00000000..bf4b5888 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/AnalogStickState.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common +{ + struct AnalogStickState + { + public int X; + public int Y; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/AtomicStorage.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/AtomicStorage.cs new file mode 100644 index 00000000..45b92ba9 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/AtomicStorage.cs @@ -0,0 +1,26 @@ +using System.Threading; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common +{ + struct AtomicStorage where T: unmanaged + { + public ulong SamplingNumber; + public T Object; + + public ulong ReadSamplingNumberAtomic() + { + return Interlocked.Read(ref SamplingNumber); + } + + public void SetObject(ref T obj) + { + ISampledData samplingProvider = obj as ISampledData; + + Interlocked.Exchange(ref SamplingNumber, samplingProvider.SamplingNumber); + + Thread.MemoryBarrier(); + + Object = obj; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/ISampledData.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/ISampledData.cs new file mode 100644 index 00000000..08f76747 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/ISampledData.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common +{ + interface ISampledData + { + ulong SamplingNumber { get; } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/RingLifo.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/RingLifo.cs new file mode 100644 index 00000000..615e3893 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Common/RingLifo.cs @@ -0,0 +1,149 @@ +using Ryujinx.Common.Memory; +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common +{ + struct RingLifo where T: unmanaged + { + private const ulong MaxEntries = 17; + +#pragma warning disable CS0169 + private ulong _unused; +#pragma warning restore CS0169 +#pragma warning disable CS0414 + private ulong _bufferCount; +#pragma warning restore CS0414 + private ulong _index; + private ulong _count; + private Array17> _storage; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ulong ReadCurrentIndex() + { + return Interlocked.Read(ref _index); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ulong ReadCurrentCount() + { + return Interlocked.Read(ref _count); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong GetNextIndexForWrite(ulong index) + { + return (index + 1) % MaxEntries; + } + + public ref AtomicStorage GetCurrentAtomicEntryRef() + { + ulong countAvailaible = Math.Min(Math.Max(0, ReadCurrentCount()), 1); + + if (countAvailaible == 0) + { + _storage[0] = default; + + return ref _storage[0]; + } + + ulong index = ReadCurrentIndex(); + + while (true) + { + int inputEntryIndex = (int)((index + MaxEntries + 1 - countAvailaible) % MaxEntries); + + ref AtomicStorage result = ref _storage[inputEntryIndex]; + + ulong samplingNumber0 = result.ReadSamplingNumberAtomic(); + ulong samplingNumber1 = result.ReadSamplingNumberAtomic(); + + if (samplingNumber0 != samplingNumber1 && (result.SamplingNumber - result.SamplingNumber) != 1) + { + ulong tempCount = Math.Min(ReadCurrentCount(), countAvailaible); + + countAvailaible = Math.Min(tempCount, 1); + index = ReadCurrentIndex(); + + continue; + } + + return ref result; + } + } + + public ref T GetCurrentEntryRef() + { + return ref GetCurrentAtomicEntryRef().Object; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan> ReadEntries(uint maxCount) + { + ulong countAvailaible = Math.Min(Math.Max(0, ReadCurrentCount()), maxCount); + + if (countAvailaible == 0) + { + return ReadOnlySpan>.Empty; + } + + ulong index = ReadCurrentIndex(); + + AtomicStorage[] result = new AtomicStorage[countAvailaible]; + + for (ulong i = 0; i < countAvailaible; i++) + { + int inputEntryIndex = (int)((index + MaxEntries + 1 - countAvailaible + i) % MaxEntries); + int outputEntryIndex = (int)(countAvailaible - i - 1); + + ulong samplingNumber0 = _storage[inputEntryIndex].ReadSamplingNumberAtomic(); + result[outputEntryIndex] = _storage[inputEntryIndex]; + ulong samplingNumber1 = _storage[inputEntryIndex].ReadSamplingNumberAtomic(); + + if (samplingNumber0 != samplingNumber1 && (i > 0 && (result[outputEntryIndex].SamplingNumber - result[outputEntryIndex].SamplingNumber) != 1)) + { + ulong tempCount = Math.Min(ReadCurrentCount(), countAvailaible); + + countAvailaible = Math.Min(tempCount, maxCount); + index = ReadCurrentIndex(); + + i -= 1; + } + } + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ref T value) + { + ulong targetIndex = GetNextIndexForWrite(ReadCurrentIndex()); + + _storage[(int)targetIndex].SetObject(ref value); + + Interlocked.Exchange(ref _index, targetIndex); + + ulong count = ReadCurrentCount(); + + if (count < (MaxEntries - 1)) + { + Interlocked.Increment(ref _count); + } + } + + public void Clear() + { + Interlocked.Exchange(ref _count, 0); + Interlocked.Exchange(ref _index, 0); + } + + public static RingLifo Create() + { + return new RingLifo + { + _bufferCount = MaxEntries + }; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadAttribute.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadAttribute.cs new file mode 100644 index 00000000..ec5bd3c8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadAttribute.cs @@ -0,0 +1,11 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad +{ + [Flags] + enum DebugPadAttribute : uint + { + None = 0, + Connected = 1 << 0 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadButton.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadButton.cs new file mode 100644 index 00000000..e8f28317 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadButton.cs @@ -0,0 +1,24 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad +{ + [Flags] + enum DebugPadButton : uint + { + None = 0, + A = 1 << 0, + B = 1 << 1, + X = 1 << 2, + Y = 1 << 3, + L = 1 << 4, + R = 1 << 5, + ZL = 1 << 6, + ZR = 1 << 7, + Start = 1 << 8, + Select = 1 << 9, + Left = 1 << 10, + Up = 1 << 11, + Right = 1 << 12, + Down = 1 << 13 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadState.cs new file mode 100644 index 00000000..3e1e1ad8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/DebugPad/DebugPadState.cs @@ -0,0 +1,15 @@ +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad +{ + struct DebugPadState : ISampledData + { + public ulong SamplingNumber; + public DebugPadAttribute Attributes; + public DebugPadButton Buttons; + public AnalogStickState AnalogStickR; + public AnalogStickState AnalogStickL; + + ulong ISampledData.SamplingNumber => SamplingNumber; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardKey.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardKey.cs new file mode 100644 index 00000000..22df7c79 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardKey.cs @@ -0,0 +1,29 @@ +using Ryujinx.Common.Memory; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard +{ + struct KeyboardKey + { + public Array4 RawData; + + public bool this[KeyboardKeyShift index] + { + get + { + return (RawData[(int)index / 64] & (1UL << ((int)index & 63))) != 0; + } + set + { + int arrayIndex = (int)index / 64; + ulong mask = 1UL << ((int)index & 63); + + RawData[arrayIndex] &= ~mask; + + if (value) + { + RawData[arrayIndex] |= mask; + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardKeyShift.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardKeyShift.cs new file mode 100644 index 00000000..01c2bb30 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardKeyShift.cs @@ -0,0 +1,138 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard +{ + enum KeyboardKeyShift + { + A = 4, + B = 5, + C = 6, + D = 7, + E = 8, + F = 9, + G = 10, + H = 11, + I = 12, + J = 13, + K = 14, + L = 15, + M = 16, + N = 17, + O = 18, + P = 19, + Q = 20, + R = 21, + S = 22, + T = 23, + U = 24, + V = 25, + W = 26, + X = 27, + Y = 28, + Z = 29, + D1 = 30, + D2 = 31, + D3 = 32, + D4 = 33, + D5 = 34, + D6 = 35, + D7 = 36, + D8 = 37, + D9 = 38, + D0 = 39, + Return = 40, + Escape = 41, + Backspace = 42, + Tab = 43, + Space = 44, + Minus = 45, + Plus = 46, + OpenBracket = 47, + CloseBracket = 48, + Pipe = 49, + Tilde = 50, + Semicolon = 51, + Quote = 52, + Backquote = 53, + Comma = 54, + Period = 55, + Slash = 56, + CapsLock = 57, + F1 = 58, + F2 = 59, + F3 = 60, + F4 = 61, + F5 = 62, + F6 = 63, + F7 = 64, + F8 = 65, + F9 = 66, + F10 = 67, + F11 = 68, + F12 = 69, + PrintScreen = 70, + ScrollLock = 71, + Pause = 72, + Insert = 73, + Home = 74, + PageUp = 75, + Delete = 76, + End = 77, + PageDown = 78, + RightArrow = 79, + LeftArrow = 80, + DownArrow = 81, + UpArrow = 82, + NumLock = 83, + NumPadDivide = 84, + NumPadMultiply = 85, + NumPadSubtract = 86, + NumPadAdd = 87, + NumPadEnter = 88, + NumPad1 = 89, + NumPad2 = 90, + NumPad3 = 91, + NumPad4 = 92, + NumPad5 = 93, + NumPad6 = 94, + NumPad7 = 95, + NumPad8 = 96, + NumPad9 = 97, + NumPad0 = 98, + NumPadDot = 99, + Backslash = 100, + Application = 101, + Power = 102, + NumPadEquals = 103, + F13 = 104, + F14 = 105, + F15 = 106, + F16 = 107, + F17 = 108, + F18 = 109, + F19 = 110, + F20 = 111, + F21 = 112, + F22 = 113, + F23 = 114, + F24 = 115, + NumPadComma = 133, + Ro = 135, + KatakanaHiragana = 136, + Yen = 137, + Henkan = 138, + Muhenkan = 139, + NumPadCommaPc98 = 140, + HangulEnglish = 144, + Hanja = 145, + Katakana = 146, + Hiragana = 147, + ZenkakuHankaku = 148, + LeftControl = 224, + LeftShift = 225, + LeftAlt = 226, + LeftGui = 227, + RightControl = 228, + RightShift = 229, + RightAlt = 230, + RightGui = 231 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardModifier.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardModifier.cs new file mode 100644 index 00000000..72d1603a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardModifier.cs @@ -0,0 +1,21 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard +{ + // TODO: This seems entirely wrong + [Flags] + enum KeyboardModifier : uint + { + None = 0, + Control = 1 << 0, + Shift = 1 << 1, + LeftAlt = 1 << 2, + RightAlt = 1 << 3, + Gui = 1 << 4, + CapsLock = 1 << 8, + ScrollLock = 1 << 9, + NumLock = 1 << 10, + Katakana = 1 << 11, + Hiragana = 1 << 12 + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardState.cs new file mode 100644 index 00000000..37608506 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Keyboard/KeyboardState.cs @@ -0,0 +1,13 @@ +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard +{ + struct KeyboardState : ISampledData + { + public ulong SamplingNumber; + public KeyboardModifier Modifiers; + public KeyboardKey Keys; + + ulong ISampledData.SamplingNumber => SamplingNumber; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseAttribute.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseAttribute.cs new file mode 100644 index 00000000..5ffba0d7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse +{ + [Flags] + enum MouseAttribute : uint + { + None = 0, + Transferable = 1 << 0, + IsConnected = 1 << 1 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseButton.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseButton.cs new file mode 100644 index 00000000..7e35140c --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseButton.cs @@ -0,0 +1,15 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse +{ + [Flags] + enum MouseButton : uint + { + None = 0, + Left = 1 << 0, + Right = 1 << 1, + Middle = 1 << 2, + Forward = 1 << 3, + Back = 1 << 4 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseState.cs new file mode 100644 index 00000000..67ad6bf1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Mouse/MouseState.cs @@ -0,0 +1,19 @@ +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse +{ + struct MouseState : ISampledData + { + public ulong SamplingNumber; + public int X; + public int Y; + public int DeltaX; + public int DeltaY; + public int WheelDeltaX; + public int WheelDeltaY; + public MouseButton Buttons; + public MouseAttribute Attributes; + + ulong ISampledData.SamplingNumber => SamplingNumber; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/DeviceType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/DeviceType.cs new file mode 100644 index 00000000..b0201835 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/DeviceType.cs @@ -0,0 +1,29 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + [Flags] + enum DeviceType : int + { + None = 0, + + FullKey = 1 << 0, + DebugPad = 1 << 1, + HandheldLeft = 1 << 2, + HandheldRight = 1 << 3, + JoyLeft = 1 << 4, + JoyRight = 1 << 5, + Palma = 1 << 6, + LarkHvcLeft = 1 << 7, + LarkHvcRight = 1 << 8, + LarkNesLeft = 1 << 9, + LarkNesRight = 1 << 10, + HandheldLarkHvcLeft = 1 << 11, + HandheldLarkHvcRight = 1 << 12, + HandheldLarkNesLeft = 1 << 13, + HandheldLarkNesRight = 1 << 14, + Lucia = 1 << 15, + + System = 1 << 31 + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadAttribute.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadAttribute.cs new file mode 100644 index 00000000..0960b7bf --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadAttribute.cs @@ -0,0 +1,16 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + [Flags] + enum NpadAttribute : uint + { + None = 0, + IsConnected = 1 << 0, + IsWired = 1 << 1, + IsLeftConnected = 1 << 2, + IsLeftWired = 1 << 3, + IsRightConnected = 1 << 4, + IsRightWired = 1 << 5 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadBatteryLevel.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadBatteryLevel.cs new file mode 100644 index 00000000..477dfd10 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadBatteryLevel.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + enum NpadBatteryLevel : int + { + Percent0, + Percent25, + Percent50, + Percent75, + Percent100 + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadButton.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadButton.cs new file mode 100644 index 00000000..5b3e13a7 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadButton.cs @@ -0,0 +1,44 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + [Flags] + enum NpadButton : ulong + { + None = 0, + A = 1 << 0, + B = 1 << 1, + X = 1 << 2, + Y = 1 << 3, + StickL = 1 << 4, + StickR = 1 << 5, + L = 1 << 6, + R = 1 << 7, + ZL = 1 << 8, + ZR = 1 << 9, + Plus = 1 << 10, + Minus = 1 << 11, + Left = 1 << 12, + Up = 1 << 13, + Right = 1 << 14, + Down = 1 << 15, + StickLLeft = 1 << 16, + StickLUp = 1 << 17, + StickLRight = 1 << 18, + StickLDown = 1 << 19, + StickRLeft = 1 << 20, + StickRUp = 1 << 21, + StickRRight = 1 << 22, + StickRDown = 1 << 23, + LeftSL = 1 << 24, + LeftSR = 1 << 25, + RightSL = 1 << 26, + RightSR = 1 << 27, + Palma = 1 << 28, + + // FIXME: Probably a button on Lark. + Unknown29 = 1 << 29, + + HandheldLeftB = 1 << 30 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadColorAttribute.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadColorAttribute.cs new file mode 100644 index 00000000..1e547cc8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadColorAttribute.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + enum NpadColorAttribute : uint + { + Ok, + ReadError, + NoController + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadCommonState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadCommonState.cs new file mode 100644 index 00000000..eaccef80 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadCommonState.cs @@ -0,0 +1,16 @@ +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + struct NpadCommonState : ISampledData + { + public ulong SamplingNumber; + public NpadButton Buttons; + public AnalogStickState AnalogStickL; + public AnalogStickState AnalogStickR; + public NpadAttribute Attributes; + private uint _reserved; + + ulong ISampledData.SamplingNumber => SamplingNumber; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadFullKeyColorState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadFullKeyColorState.cs new file mode 100644 index 00000000..990eafb2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadFullKeyColorState.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + struct NpadFullKeyColorState + { + public NpadColorAttribute Attribute; + public uint FullKeyBody; + public uint FullKeyButtons; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadGcTriggerState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadGcTriggerState.cs new file mode 100644 index 00000000..52668f85 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadGcTriggerState.cs @@ -0,0 +1,15 @@ +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + struct NpadGcTriggerState : ISampledData + { +#pragma warning disable CS0649 + public ulong SamplingNumber; + public uint TriggerL; + public uint TriggerR; +#pragma warning restore CS0649 + + ulong ISampledData.SamplingNumber => SamplingNumber; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadInternalState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadInternalState.cs new file mode 100644 index 00000000..f225ff67 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadInternalState.cs @@ -0,0 +1,61 @@ +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + struct NpadInternalState + { + public NpadStyleTag StyleSet; + public NpadJoyAssignmentMode JoyAssignmentMode; + public NpadFullKeyColorState FullKeyColor; + public NpadJoyColorState JoyColor; + public RingLifo FullKey; + public RingLifo Handheld; + public RingLifo JoyDual; + public RingLifo JoyLeft; + public RingLifo JoyRight; + public RingLifo Palma; + public RingLifo SystemExt; + public RingLifo FullKeySixAxisSensor; + public RingLifo HandheldSixAxisSensor; + public RingLifo JoyDualSixAxisSensor; + public RingLifo JoyDualRightSixAxisSensor; + public RingLifo JoyLeftSixAxisSensor; + public RingLifo JoyRightSixAxisSensor; + public DeviceType DeviceType; + private uint _reserved1; + public NpadSystemProperties SystemProperties; + public NpadSystemButtonProperties SystemButtonProperties; + public NpadBatteryLevel BatteryLevelJoyDual; + public NpadBatteryLevel BatteryLevelJoyLeft; + public NpadBatteryLevel BatteryLevelJoyRight; + public uint AppletFooterUiAttributes; + public byte AppletFooterUiType; + private unsafe fixed byte _reserved2[0x7B]; + public RingLifo GcTrigger; + public NpadLarkType LarkTypeLeftAndMain; + public NpadLarkType LarkTypeRight; + public NpadLuciaType LuciaType; + public uint Unknown43EC; + + public static NpadInternalState Create() + { + return new NpadInternalState + { + FullKey = RingLifo.Create(), + Handheld = RingLifo.Create(), + JoyDual = RingLifo.Create(), + JoyLeft = RingLifo.Create(), + JoyRight = RingLifo.Create(), + Palma = RingLifo.Create(), + SystemExt = RingLifo.Create(), + FullKeySixAxisSensor = RingLifo.Create(), + HandheldSixAxisSensor = RingLifo.Create(), + JoyDualSixAxisSensor = RingLifo.Create(), + JoyDualRightSixAxisSensor = RingLifo.Create(), + JoyLeftSixAxisSensor = RingLifo.Create(), + JoyRightSixAxisSensor = RingLifo.Create(), + GcTrigger = RingLifo.Create(), + }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadJoyAssignmentMode.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadJoyAssignmentMode.cs new file mode 100644 index 00000000..871c4c5a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadJoyAssignmentMode.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + enum NpadJoyAssignmentMode : uint + { + Dual, + Single + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadJoyColorState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadJoyColorState.cs new file mode 100644 index 00000000..3986dd5e --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadJoyColorState.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + struct NpadJoyColorState + { + public NpadColorAttribute Attribute; + public uint LeftBody; + public uint LeftButtons; + public uint RightBody; + public uint RightButtons; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadLarkType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadLarkType.cs new file mode 100644 index 00000000..a487a911 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadLarkType.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + enum NpadLarkType : uint + { + Invalid, + H1, + H2, + NL, + NR + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadLuciaType.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadLuciaType.cs new file mode 100644 index 00000000..95148485 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadLuciaType.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + enum NpadLuciaType + { + Invalid, + J, + E, + U + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadState.cs new file mode 100644 index 00000000..ed9e7c0d --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadState.cs @@ -0,0 +1,18 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + [StructLayout(LayoutKind.Sequential, Size = 0x5000)] + struct NpadState + { + public NpadInternalState InternalState; + + public static NpadState Create() + { + return new NpadState + { + InternalState = NpadInternalState.Create() + }; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadStyleTag.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadStyleTag.cs new file mode 100644 index 00000000..f31978e2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadStyleTag.cs @@ -0,0 +1,76 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + /// + /// Nintendo pad style + /// + [Flags] + enum NpadStyleTag : uint + { + /// + /// No type. + /// + None = 0, + + /// + /// Pro controller. + /// + FullKey = 1 << 0, + + /// + /// Joy-Con controller in handheld mode. + /// + Handheld = 1 << 1, + + /// + /// Joy-Con controller in dual mode. + /// + JoyDual = 1 << 2, + + /// + /// Joy-Con left controller in single mode. + /// + JoyLeft = 1 << 3, + + /// + /// Joy-Con right controller in single mode. + /// + JoyRight = 1 << 4, + + /// + /// GameCube controller. + /// + Gc = 1 << 5, + + /// + /// Poké Ball Plus controller. + /// + Palma = 1 << 6, + + /// + /// NES and Famicom controller. + /// + Lark = 1 << 7, + + /// + /// NES and Famicom controller in handheld mode. + /// + HandheldLark = 1 << 8, + + /// + /// SNES controller. + /// + Lucia = 1 << 9, + + /// + /// Generic external controller. + /// + SystemExt = 1 << 29, + + /// + /// Generic controller. + /// + System = 1 << 30 + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadSystemButtonProperties.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadSystemButtonProperties.cs new file mode 100644 index 00000000..68603271 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadSystemButtonProperties.cs @@ -0,0 +1,11 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + [Flags] + enum NpadSystemButtonProperties : uint + { + None = 0, + IsUnintendedHomeButtonInputProtectionEnabled = 1 << 0 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadSystemProperties.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadSystemProperties.cs new file mode 100644 index 00000000..13444555 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/NpadSystemProperties.cs @@ -0,0 +1,24 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + [Flags] + enum NpadSystemProperties : ulong + { + None = 0, + + IsChargingJoyDual = 1 << 0, + IsChargingJoyLeft = 1 << 1, + IsChargingJoyRight = 1 << 2, + IsPoweredJoyDual = 1 << 3, + IsPoweredJoyLeft = 1 << 4, + IsPoweredJoyRight = 1 << 5, + IsUnsuportedButtonPressedOnNpadSystem = 1 << 9, + IsUnsuportedButtonPressedOnNpadSystemExt = 1 << 10, + IsAbxyButtonOriented = 1 << 11, + IsSlSrButtonOriented = 1 << 12, + IsPlusAvailable = 1 << 13, + IsMinusAvailable = 1 << 14, + IsDirectionalButtonsAvailable = 1 << 15 + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/SixAxisSensorAttribute.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/SixAxisSensorAttribute.cs new file mode 100644 index 00000000..7ed46d98 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/SixAxisSensorAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + [Flags] + enum SixAxisSensorAttribute : uint + { + None = 0, + IsConnected = 1 << 0, + IsInterpolated = 1 << 1 + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/SixAxisSensorState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/SixAxisSensorState.cs new file mode 100644 index 00000000..d024b0b0 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/Npad/SixAxisSensorState.cs @@ -0,0 +1,19 @@ +using Ryujinx.Common.Memory; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad +{ + struct SixAxisSensorState : ISampledData + { + public ulong DeltaTime; + public ulong SamplingNumber; + public HidVector Acceleration; + public HidVector AngularVelocity; + public HidVector Angle; + public Array9 Direction; + public SixAxisSensorAttribute Attributes; + private uint _reserved; + + ulong ISampledData.SamplingNumber => SamplingNumber; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/SharedMemory.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/SharedMemory.cs new file mode 100644 index 00000000..48acfc3f --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/SharedMemory.cs @@ -0,0 +1,66 @@ +using Ryujinx.Common.Memory; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory +{ + /// + /// Represent the shared memory shared between applications for input. + /// + [StructLayout(LayoutKind.Explicit, Size = 0x40000)] + struct SharedMemory + { + /// + /// Debug controller. + /// + [FieldOffset(0)] + public RingLifo DebugPad; + + /// + /// Touchscreen. + /// + [FieldOffset(0x400)] + public RingLifo TouchScreen; + + /// + /// Mouse. + /// + [FieldOffset(0x3400)] + public RingLifo Mouse; + + /// + /// Keyboard. + /// + [FieldOffset(0x3800)] + public RingLifo Keyboard; + + /// + /// Nintendo Pads. + /// + [FieldOffset(0x9A00)] + public Array10 Npads; + + public static SharedMemory Create() + { + SharedMemory result = new SharedMemory + { + DebugPad = RingLifo.Create(), + TouchScreen = RingLifo.Create(), + Mouse = RingLifo.Create(), + Keyboard = RingLifo.Create(), + }; + + for (int i = 0; i < result.Npads.Length; i++) + { + result.Npads[i] = NpadState.Create(); + } + + return result; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchAttribute.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchAttribute.cs new file mode 100644 index 00000000..8a8f9cc1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen +{ + [Flags] + enum TouchAttribute : uint + { + None = 0, + Start = 1 << 0, + End = 1 << 1 + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchScreenState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchScreenState.cs new file mode 100644 index 00000000..8203e49b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchScreenState.cs @@ -0,0 +1,15 @@ +using Ryujinx.Common.Memory; +using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; + +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen +{ + struct TouchScreenState : ISampledData + { + public ulong SamplingNumber; + public int TouchesCount; + private int _reserved; + public Array16 Touches; + + ulong ISampledData.SamplingNumber => SamplingNumber; + } +} diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchState.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchState.cs new file mode 100644 index 00000000..ba621a2b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Hid/Types/SharedMemory/TouchScreen/TouchState.cs @@ -0,0 +1,19 @@ +namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen +{ + struct TouchState + { + public ulong DeltaTime; +#pragma warning disable CS0649 + public TouchAttribute Attribute; +#pragma warning restore CS0649 + public uint FingerId; + public uint X; + public uint Y; + public uint DiameterX; + public uint DiameterY; + public uint RotationAngle; +#pragma warning disable CS0169 + private uint _reserved; +#pragma warning restore CS0169 + } +} diff --git a/Ryujinx.Input/HLE/NpadController.cs b/Ryujinx.Input/HLE/NpadController.cs index d3553d64..e1a8e2d7 100644 --- a/Ryujinx.Input/HLE/NpadController.cs +++ b/Ryujinx.Input/HLE/NpadController.cs @@ -456,14 +456,14 @@ namespace Ryujinx.Input.HLE KeyboardInput hidKeyboard = new KeyboardInput { Modifier = 0, - Keys = new int[0x8] + Keys = new ulong[0x4] }; foreach (HLEKeyboardMappingEntry entry in KeyMapping) { - int value = keyboardState.IsPressed(entry.TargetKey) ? 1 : 0; + ulong value = keyboardState.IsPressed(entry.TargetKey) ? 1UL : 0UL; - hidKeyboard.Keys[entry.Target / 0x20] |= (value << (entry.Target % 0x20)); + hidKeyboard.Keys[entry.Target / 0x40] |= (value << (entry.Target % 0x40)); } foreach (HLEKeyboardMappingEntry entry in KeyModifierMapping)