forked from Mirror/Ryujinx
HID SharedMem Rework (#1003)
* Delete old HLE.Input * Add new HLE Input. git shows Hid.cs as modified because of the same name. It is new. * Change HID Service * Change Ryujinx UI to reflect new Input * Add basic ControllerApplet * Add DebugPad Should fix Kirby Star Allies * Address Ac_K's comments * Moved all of HLE.Input to Services.Hid * Separated all structs and enums each to a file * Removed vars * Made some naming changes to align with switchbrew * Added official joycon colors As an aside, fixed a mistake in touchscreen headers and added checks to important SharedMem structs at init time. * Further address Ac_K's comments * Addressed gdkchan's and some more Ac_K's comments * Address AcK's review comments * Address AcK's second review comments * Replace missed Marshal.SizeOf and address gdkchan's comments
This commit is contained in:
parent
5b5239ab5b
commit
2365ddfc36
105 changed files with 1500 additions and 1044 deletions
|
@ -1,6 +1,7 @@
|
|||
using ARMeilleure.Memory;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.HLE
|
||||
{
|
||||
|
@ -64,6 +65,11 @@ namespace Ryujinx.HLE
|
|||
return Marshal.PtrToStructure<T>((IntPtr)(_ramPtr + position));
|
||||
}
|
||||
|
||||
public unsafe ref T GetStructRef<T>(long position)
|
||||
{
|
||||
return ref Unsafe.AsRef<T>((void*)(IntPtr)(_ramPtr + position));
|
||||
}
|
||||
|
||||
public void WriteSByte(long position, sbyte value)
|
||||
{
|
||||
WriteByte(position, (byte)value);
|
||||
|
|
15
Ryujinx.HLE/Exceptions/InvalidStructLayoutException.cs
Normal file
15
Ryujinx.HLE/Exceptions/InvalidStructLayoutException.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.HLE.Exceptions
|
||||
{
|
||||
public class InvalidStructLayoutException<T> : Exception
|
||||
{
|
||||
static readonly Type _structType = typeof(T);
|
||||
|
||||
public InvalidStructLayoutException(string message) : base(message) {}
|
||||
|
||||
public InvalidStructLayoutException(int expectedSize) :
|
||||
base($"Type {_structType.Name} has the wrong size. Expected: {expectedSize} bytes, Got: {Unsafe.SizeOf<T>()} bytes") {}
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||
_appletMapping = new Dictionary<AppletId, Type>
|
||||
{
|
||||
{ AppletId.PlayerSelect, typeof(PlayerSelectApplet) },
|
||||
{ AppletId.Controller, typeof(ControllerApplet) },
|
||||
{ AppletId.SoftwareKeyboard, typeof(SoftwareKeyboardApplet) }
|
||||
};
|
||||
}
|
||||
|
|
114
Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs
Normal file
114
Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs
Normal file
|
@ -0,0 +1,114 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Hid;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||
|
||||
using static Ryujinx.HLE.HOS.Services.Hid.HidServer.HidUtils;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
internal class ControllerApplet : IApplet
|
||||
{
|
||||
private Horizon _system;
|
||||
|
||||
private AppletSession _normalSession;
|
||||
|
||||
public event EventHandler AppletStateChanged;
|
||||
|
||||
public ControllerApplet(Horizon system)
|
||||
{
|
||||
_system = system;
|
||||
}
|
||||
|
||||
unsafe public ResultCode Start(AppletSession normalSession,
|
||||
AppletSession interactiveSession)
|
||||
{
|
||||
_normalSession = normalSession;
|
||||
|
||||
byte[] launchParams = _normalSession.Pop();
|
||||
byte[] controllerSupportArgPrivate = _normalSession.Pop();
|
||||
ControllerSupportArgPrivate privateArg = IApplet.ReadStruct<ControllerSupportArgPrivate>(controllerSupportArgPrivate);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceHid, $"ControllerApplet ArgPriv {privateArg.PrivateSize} {privateArg.ArgSize} {privateArg.Mode}" +
|
||||
$"HoldType:{(NpadJoyHoldType)privateArg.NpadJoyHoldType} StyleSets:{(ControllerType)privateArg.NpadStyleSet}");
|
||||
|
||||
if (privateArg.Mode != ControllerSupportMode.ShowControllerSupport)
|
||||
{
|
||||
_normalSession.Push(BuildResponse()); // Dummy response for other modes
|
||||
AppletStateChanged?.Invoke(this, null);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
byte[] controllerSupportArg = _normalSession.Pop();
|
||||
|
||||
ControllerSupportArgHeader argHeader;
|
||||
|
||||
if (privateArg.ArgSize == Marshal.SizeOf<ControllerSupportArg>())
|
||||
{
|
||||
ControllerSupportArg arg = IApplet.ReadStruct<ControllerSupportArg>(controllerSupportArg);
|
||||
argHeader = arg.Header;
|
||||
// Read enable text here?
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceHid, $"Unknown revision of ControllerSupportArg.");
|
||||
|
||||
argHeader = IApplet.ReadStruct<ControllerSupportArgHeader>(controllerSupportArg); // Read just the header
|
||||
}
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceHid, $"ControllerApplet Arg {argHeader.PlayerCountMin} {argHeader.PlayerCountMax} {argHeader.EnableTakeOverConnection} {argHeader.EnableSingleMode}");
|
||||
|
||||
// Currently, the only purpose of this applet is to help
|
||||
// choose the primary input controller for the game
|
||||
// TODO: Ideally should hook back to HID.Controller. When applet is called, can choose appropriate controller and attach to appropriate id.
|
||||
if (argHeader.PlayerCountMin > 1)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.ServiceHid, "More than one controller was requested.");
|
||||
}
|
||||
|
||||
ControllerSupportResultInfo result = new ControllerSupportResultInfo
|
||||
{
|
||||
PlayerCount = 1,
|
||||
SelectedId = (uint)GetNpadIdTypeFromIndex(_system.Device.Hid.Npads.PrimaryController)
|
||||
};
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceHid, $"ControllerApplet ReturnResult {result.PlayerCount} {result.SelectedId}");
|
||||
|
||||
_normalSession.Push(BuildResponse(result));
|
||||
AppletStateChanged?.Invoke(this, null);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public ResultCode GetResult()
|
||||
{
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
private byte[] BuildResponse(ControllerSupportResultInfo result)
|
||||
{
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
writer.Write(MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref result, Unsafe.SizeOf<ControllerSupportResultInfo>())));
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] BuildResponse()
|
||||
{
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
writer.Write((ulong)ResultCode.Success);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArg.cs
Normal file
11
Ryujinx.HLE/HOS/Applets/Controller/ControllerSupportArg.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
// (8.0.0+ version)
|
||||
unsafe struct ControllerSupportArg
|
||||
{
|
||||
public ControllerSupportArgHeader Header;
|
||||
public fixed uint IdentificationColor[8];
|
||||
public byte EnableExplainText;
|
||||
public fixed byte ExplainText[8 * 0x81];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
struct ControllerSupportArgHeader
|
||||
{
|
||||
public sbyte PlayerCountMin;
|
||||
public sbyte PlayerCountMax;
|
||||
public byte EnableTakeOverConnection;
|
||||
public byte EnableLeftJustify;
|
||||
public byte EnablePermitJoyDual;
|
||||
public byte EnableSingleMode;
|
||||
public byte EnableIdentificationColor;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
struct ControllerSupportArgPrivate
|
||||
{
|
||||
public uint PrivateSize;
|
||||
public uint ArgSize;
|
||||
public byte Flag0;
|
||||
public byte Flag1;
|
||||
public ControllerSupportMode Mode;
|
||||
public byte ControllerSupportCaller;
|
||||
public uint NpadStyleSet;
|
||||
public uint NpadJoyHoldType;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
enum ControllerSupportMode : byte
|
||||
{
|
||||
ShowControllerSupport = 0,
|
||||
ShowControllerStrapGuide = 1,
|
||||
ShowControllerFirmwareUpdate = 2
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
unsafe struct ControllerSupportResultInfo
|
||||
{
|
||||
public sbyte PlayerCount;
|
||||
fixed byte _padding[3];
|
||||
public uint SelectedId;
|
||||
public uint Result;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
|
@ -11,5 +12,10 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||
AppletSession interactiveSession);
|
||||
|
||||
ResultCode GetResult();
|
||||
|
||||
static T ReadStruct<T>(ReadOnlySpan<byte> data) where T : struct
|
||||
{
|
||||
return MemoryMarshal.Cast<byte, T>(data)[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||
var keyboardConfig = _normalSession.Pop();
|
||||
var transferMemory = _normalSession.Pop();
|
||||
|
||||
_keyboardConfig = ReadStruct<SoftwareKeyboardConfig>(keyboardConfig);
|
||||
_keyboardConfig = IApplet.ReadStruct<SoftwareKeyboardConfig>(keyboardConfig);
|
||||
|
||||
if (_keyboardConfig.UseUtf8)
|
||||
{
|
||||
|
@ -176,20 +176,5 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static T ReadStruct<T>(byte[] data)
|
||||
where T : struct
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
|
||||
try
|
||||
{
|
||||
return Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
88
Ryujinx.HLE/HOS/Services/Hid/Hid.cs
Normal file
88
Ryujinx.HLE/HOS/Services/Hid/Hid.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public class Hid
|
||||
{
|
||||
private readonly Switch _device;
|
||||
private long _hidMemoryAddress;
|
||||
|
||||
internal ref HidSharedMemory SharedMemory => ref _device.Memory.GetStructRef<HidSharedMemory>(_hidMemoryAddress);
|
||||
internal const int SharedMemEntryCount = 17;
|
||||
|
||||
public DebugPadDevice DebugPad;
|
||||
public TouchDevice Touchscreen;
|
||||
public MouseDevice Mouse;
|
||||
public KeyboardDevice Keyboard;
|
||||
public NpadDevices Npads;
|
||||
|
||||
static Hid()
|
||||
{
|
||||
if (Unsafe.SizeOf<ShMemDebugPad>() != 0x400)
|
||||
{
|
||||
throw new InvalidStructLayoutException<ShMemDebugPad>(0x400);
|
||||
}
|
||||
if (Unsafe.SizeOf<ShMemTouchScreen>() != 0x3000)
|
||||
{
|
||||
throw new InvalidStructLayoutException<ShMemTouchScreen>(0x3000);
|
||||
}
|
||||
if (Unsafe.SizeOf<ShMemKeyboard>() != 0x400)
|
||||
{
|
||||
throw new InvalidStructLayoutException<ShMemKeyboard>(0x400);
|
||||
}
|
||||
if (Unsafe.SizeOf<ShMemMouse>() != 0x400)
|
||||
{
|
||||
throw new InvalidStructLayoutException<ShMemMouse>(0x400);
|
||||
}
|
||||
if (Unsafe.SizeOf<ShMemNpad>() != 0x5000)
|
||||
{
|
||||
throw new InvalidStructLayoutException<ShMemNpad>(0x5000);
|
||||
}
|
||||
if (Unsafe.SizeOf<HidSharedMemory>() != Horizon.HidSize)
|
||||
{
|
||||
throw new InvalidStructLayoutException<HidSharedMemory>(Horizon.HidSize);
|
||||
}
|
||||
}
|
||||
|
||||
public Hid(in Switch device, long sharedHidMemoryAddress)
|
||||
{
|
||||
_device = device;
|
||||
_hidMemoryAddress = sharedHidMemoryAddress;
|
||||
|
||||
device.Memory.FillWithZeros(sharedHidMemoryAddress, Horizon.HidSize);
|
||||
}
|
||||
|
||||
public void InitDevices()
|
||||
{
|
||||
DebugPad = new DebugPadDevice(_device, true);
|
||||
Touchscreen = new TouchDevice(_device, true);
|
||||
Mouse = new MouseDevice(_device, false);
|
||||
Keyboard = new KeyboardDevice(_device, false);
|
||||
Npads = new NpadDevices(_device, true);
|
||||
}
|
||||
|
||||
public ControllerKeys UpdateStickButtons(JoystickPosition leftStick, JoystickPosition rightStick)
|
||||
{
|
||||
ControllerKeys result = 0;
|
||||
|
||||
result |= (leftStick.Dx < 0) ? ControllerKeys.LStickLeft : result;
|
||||
result |= (leftStick.Dx > 0) ? ControllerKeys.LStickRight : result;
|
||||
result |= (leftStick.Dy < 0) ? ControllerKeys.LStickDown : result;
|
||||
result |= (leftStick.Dy > 0) ? ControllerKeys.LStickUp : result;
|
||||
|
||||
result |= (rightStick.Dx < 0) ? ControllerKeys.RStickLeft : result;
|
||||
result |= (rightStick.Dx > 0) ? ControllerKeys.RStickRight : result;
|
||||
result |= (rightStick.Dy < 0) ? ControllerKeys.RStickDown : result;
|
||||
result |= (rightStick.Dy > 0) ? ControllerKeys.RStickUp : result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static ulong GetTimestampTicks()
|
||||
{
|
||||
return (ulong)PerformanceCounter.ElapsedMilliseconds * 19200;
|
||||
}
|
||||
}
|
||||
}
|
29
Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs
Normal file
29
Ryujinx.HLE/HOS/Services/Hid/HidDevices/BaseDevice.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using static Ryujinx.HLE.HOS.Services.Hid.Hid;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public abstract class BaseDevice
|
||||
{
|
||||
protected readonly Switch _device;
|
||||
public bool Active;
|
||||
|
||||
public BaseDevice(Switch device, bool active)
|
||||
{
|
||||
_device = device;
|
||||
Active = active;
|
||||
}
|
||||
|
||||
internal static int UpdateEntriesHeader(ref CommonEntriesHeader header, out int previousEntry)
|
||||
{
|
||||
header.NumEntries = SharedMemEntryCount;
|
||||
header.MaxEntryIndex = SharedMemEntryCount - 1;
|
||||
|
||||
previousEntry = (int)header.LatestEntry;
|
||||
header.LatestEntry = (header.LatestEntry + 1) % SharedMemEntryCount;
|
||||
|
||||
header.TimestampTicks = GetTimestampTicks();
|
||||
|
||||
return (int)header.LatestEntry; // EntryCount shouldn't overflow int
|
||||
}
|
||||
}
|
||||
}
|
24
Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs
Normal file
24
Ryujinx.HLE/HOS/Services/Hid/HidDevices/DebugPadDevice.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public class DebugPadDevice : BaseDevice
|
||||
{
|
||||
public DebugPadDevice(Switch device, bool active) : base(device, active) { }
|
||||
|
||||
public void Update()
|
||||
{
|
||||
ref ShMemDebugPad debugPad = ref _device.Hid.SharedMemory.DebugPad;
|
||||
|
||||
int currentIndex = UpdateEntriesHeader(ref debugPad.Header, out int previousIndex);
|
||||
|
||||
if (!Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ref DebugPadEntry currentEntry = ref debugPad.Entries[currentIndex];
|
||||
DebugPadEntry previousEntry = debugPad.Entries[previousIndex];
|
||||
|
||||
currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
|
||||
}
|
||||
}
|
||||
}
|
32
Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs
Normal file
32
Ryujinx.HLE/HOS/Services/Hid/HidDevices/KeyboardDevice.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public class KeyboardDevice : BaseDevice
|
||||
{
|
||||
public KeyboardDevice(Switch device, bool active) : base(device, active) { }
|
||||
|
||||
public unsafe void Update(KeyboardInput keyState)
|
||||
{
|
||||
ref ShMemKeyboard keyboard = ref _device.Hid.SharedMemory.Keyboard;
|
||||
|
||||
int currentIndex = UpdateEntriesHeader(ref keyboard.Header, out int previousIndex);
|
||||
|
||||
if (!Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ref KeyboardState currentEntry = ref keyboard.Entries[currentIndex];
|
||||
KeyboardState previousEntry = keyboard.Entries[previousIndex];
|
||||
|
||||
currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
|
||||
currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1;
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
currentEntry.Keys[i] = (uint)keyState.Keys[i];
|
||||
}
|
||||
|
||||
currentEntry.Modifier = (ulong)keyState.Modifier;
|
||||
}
|
||||
}
|
||||
}
|
37
Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs
Normal file
37
Ryujinx.HLE/HOS/Services/Hid/HidDevices/MouseDevice.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public class MouseDevice : BaseDevice
|
||||
{
|
||||
public MouseDevice(Switch device, bool active) : base(device, active) { }
|
||||
|
||||
public void Update(int mouseX, int mouseY, int buttons = 0, int scrollX = 0, int scrollY = 0)
|
||||
{
|
||||
ref ShMemMouse mouse = ref _device.Hid.SharedMemory.Mouse;
|
||||
|
||||
int currentIndex = UpdateEntriesHeader(ref mouse.Header, out int previousIndex);
|
||||
|
||||
if (!Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ref MouseState currentEntry = ref mouse.Entries[currentIndex];
|
||||
MouseState previousEntry = mouse.Entries[previousIndex];
|
||||
|
||||
currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
|
||||
currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1;
|
||||
|
||||
currentEntry.Buttons = (ulong)buttons;
|
||||
|
||||
currentEntry.Position = new MousePosition
|
||||
{
|
||||
X = mouseX,
|
||||
Y = mouseY,
|
||||
VelocityX = mouseX - previousEntry.Position.X,
|
||||
VelocityY = mouseY - previousEntry.Position.Y,
|
||||
ScrollVelocityX = scrollX,
|
||||
ScrollVelocityY = scrollY
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
332
Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs
Normal file
332
Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs
Normal file
|
@ -0,0 +1,332 @@
|
|||
using System;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Common.Logging;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public class NpadDevices : BaseDevice
|
||||
{
|
||||
internal NpadJoyHoldType JoyHold = NpadJoyHoldType.Vertical;
|
||||
internal bool SixAxisActive = false; // TODO: link to hidserver when implemented
|
||||
|
||||
enum FilterState
|
||||
{
|
||||
Unconfigured = 0,
|
||||
Configured = 1,
|
||||
Accepted = 2
|
||||
}
|
||||
|
||||
struct NpadConfig
|
||||
{
|
||||
public ControllerType ConfiguredType;
|
||||
public FilterState State;
|
||||
}
|
||||
|
||||
private const int _maxControllers = 9; // Players1-8 and Handheld
|
||||
private NpadConfig[] _configuredNpads;
|
||||
|
||||
private ControllerType _supportedStyleSets = ControllerType.ProController |
|
||||
ControllerType.JoyconPair |
|
||||
ControllerType.JoyconLeft |
|
||||
ControllerType.JoyconRight |
|
||||
ControllerType.Handheld;
|
||||
|
||||
public ControllerType SupportedStyleSets
|
||||
{
|
||||
get { return _supportedStyleSets; }
|
||||
set
|
||||
{
|
||||
if (_supportedStyleSets != value) // Deal with spamming
|
||||
{
|
||||
_supportedStyleSets = value;
|
||||
MatchControllers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerIndex PrimaryController { get; set; } = PlayerIndex.Unknown;
|
||||
|
||||
KEvent[] _styleSetUpdateEvents;
|
||||
|
||||
static readonly Array3<BatteryCharge> _fullBattery;
|
||||
|
||||
public NpadDevices(Switch device, bool active = true) : base(device, active)
|
||||
{
|
||||
_configuredNpads = new NpadConfig[_maxControllers];
|
||||
|
||||
_styleSetUpdateEvents = new KEvent[_maxControllers];
|
||||
|
||||
for (int i = 0; i < _styleSetUpdateEvents.Length; ++i)
|
||||
{
|
||||
_styleSetUpdateEvents[i] = new KEvent(_device.System);
|
||||
}
|
||||
|
||||
_fullBattery[0] = _fullBattery[1] = _fullBattery[2] = BatteryCharge.Percent100;
|
||||
}
|
||||
|
||||
public void AddControllers(params ControllerConfig[] configs)
|
||||
{
|
||||
for (int i = 0; i < configs.Length; ++i)
|
||||
{
|
||||
PlayerIndex player = configs[i].Player;
|
||||
ControllerType controllerType = configs[i].Type;
|
||||
|
||||
if (player > PlayerIndex.Handheld)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Player must be Player1-8 or Handheld");
|
||||
}
|
||||
|
||||
if (controllerType == ControllerType.Handheld)
|
||||
{
|
||||
player = PlayerIndex.Handheld;
|
||||
}
|
||||
|
||||
_configuredNpads[(int)player] = new NpadConfig { ConfiguredType = controllerType, State = FilterState.Configured };
|
||||
}
|
||||
|
||||
MatchControllers();
|
||||
}
|
||||
|
||||
void MatchControllers()
|
||||
{
|
||||
PrimaryController = PlayerIndex.Unknown;
|
||||
|
||||
for (int i = 0; i < _configuredNpads.Length; ++i)
|
||||
{
|
||||
ref NpadConfig config = ref _configuredNpads[i];
|
||||
|
||||
if (config.State == FilterState.Unconfigured)
|
||||
{
|
||||
continue; // Ignore unconfigured
|
||||
}
|
||||
|
||||
if ((config.ConfiguredType & _supportedStyleSets) == 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.Hid, $"ControllerType {config.ConfiguredType} (connected to {(PlayerIndex)i}) not supported by game. Removing...");
|
||||
|
||||
config.State = FilterState.Configured;
|
||||
_device.Hid.SharedMemory.Npads[i] = new ShMemNpad(); // Zero it
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
InitController((PlayerIndex)i, config.ConfiguredType);
|
||||
}
|
||||
|
||||
// Couldn't find any matching configuration. Reassign to something that works.
|
||||
if (PrimaryController == PlayerIndex.Unknown)
|
||||
{
|
||||
ControllerType[] npadsTypeList = (ControllerType[])Enum.GetValues(typeof(ControllerType));
|
||||
|
||||
// Skip None Type
|
||||
for (int i = 1; i < npadsTypeList.Length; ++i)
|
||||
{
|
||||
ControllerType controllerType = npadsTypeList[i];
|
||||
if ((controllerType & _supportedStyleSets) != 0)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.Hid, $"No matching controllers found. Reassigning input as ControllerType {controllerType}...");
|
||||
|
||||
InitController(controllerType == ControllerType.Handheld ? PlayerIndex.Handheld : PlayerIndex.Player1, controllerType);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.PrintError(LogClass.Hid, "Couldn't find any appropriate controller.");
|
||||
}
|
||||
}
|
||||
|
||||
internal ref KEvent GetStyleSetUpdateEvent(PlayerIndex player)
|
||||
{
|
||||
return ref _styleSetUpdateEvents[(int)player];
|
||||
}
|
||||
|
||||
void InitController(PlayerIndex player, ControllerType type)
|
||||
{
|
||||
if (type == ControllerType.Handheld)
|
||||
{
|
||||
player = PlayerIndex.Handheld;
|
||||
}
|
||||
|
||||
ref ShMemNpad controller = ref _device.Hid.SharedMemory.Npads[(int)player];
|
||||
|
||||
controller = new ShMemNpad(); // Zero it
|
||||
|
||||
// TODO: Allow customizing colors at config
|
||||
NpadStateHeader defaultHeader = new NpadStateHeader
|
||||
{
|
||||
IsHalf = false,
|
||||
SingleColorBody = NpadColor.BodyGray,
|
||||
SingleColorButtons = NpadColor.ButtonGray,
|
||||
LeftColorBody = NpadColor.BodyNeonBlue,
|
||||
LeftColorButtons = NpadColor.ButtonGray,
|
||||
RightColorBody = NpadColor.BodyNeonRed,
|
||||
RightColorButtons = NpadColor.ButtonGray
|
||||
};
|
||||
|
||||
controller.SystemProperties = NpadSystemProperties.PowerInfo0Connected |
|
||||
NpadSystemProperties.PowerInfo1Connected |
|
||||
NpadSystemProperties.PowerInfo2Connected;
|
||||
|
||||
controller.BatteryState = _fullBattery;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ControllerType.ProController:
|
||||
defaultHeader.Type = ControllerType.ProController;
|
||||
controller.DeviceType = DeviceType.FullKey;
|
||||
controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented |
|
||||
NpadSystemProperties.PlusButtonCapability |
|
||||
NpadSystemProperties.MinusButtonCapability;
|
||||
break;
|
||||
case ControllerType.Handheld:
|
||||
defaultHeader.Type = ControllerType.Handheld;
|
||||
controller.DeviceType = DeviceType.HandheldLeft |
|
||||
DeviceType.HandheldRight;
|
||||
controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented |
|
||||
NpadSystemProperties.PlusButtonCapability |
|
||||
NpadSystemProperties.MinusButtonCapability;
|
||||
break;
|
||||
case ControllerType.JoyconPair:
|
||||
defaultHeader.Type = ControllerType.JoyconPair;
|
||||
controller.DeviceType = DeviceType.JoyLeft |
|
||||
DeviceType.JoyRight;
|
||||
controller.SystemProperties |= NpadSystemProperties.AbxyButtonOriented |
|
||||
NpadSystemProperties.PlusButtonCapability |
|
||||
NpadSystemProperties.MinusButtonCapability;
|
||||
break;
|
||||
case ControllerType.JoyconLeft:
|
||||
defaultHeader.Type = ControllerType.JoyconLeft;
|
||||
defaultHeader.IsHalf = true;
|
||||
controller.DeviceType = DeviceType.JoyLeft;
|
||||
controller.SystemProperties |= NpadSystemProperties.SlSrButtonOriented |
|
||||
NpadSystemProperties.MinusButtonCapability;
|
||||
break;
|
||||
case ControllerType.JoyconRight:
|
||||
defaultHeader.Type = ControllerType.JoyconRight;
|
||||
defaultHeader.IsHalf = true;
|
||||
controller.DeviceType = DeviceType.JoyRight;
|
||||
controller.SystemProperties |= NpadSystemProperties.SlSrButtonOriented |
|
||||
NpadSystemProperties.PlusButtonCapability;
|
||||
break;
|
||||
case ControllerType.Pokeball:
|
||||
defaultHeader.Type = ControllerType.Pokeball;
|
||||
controller.DeviceType = DeviceType.Palma;
|
||||
break;
|
||||
}
|
||||
|
||||
controller.Header = defaultHeader;
|
||||
|
||||
if (PrimaryController == PlayerIndex.Unknown)
|
||||
{
|
||||
PrimaryController = player;
|
||||
}
|
||||
|
||||
_configuredNpads[(int)player].State = FilterState.Accepted;
|
||||
|
||||
_styleSetUpdateEvents[(int)player].ReadableEvent.Signal();
|
||||
|
||||
Logger.PrintInfo(LogClass.Hid, $"Connected ControllerType {type} to PlayerIndex {player}");
|
||||
}
|
||||
|
||||
static NpadLayoutsIndex ControllerTypeToLayout(ControllerType controllerType)
|
||||
=> controllerType switch
|
||||
{
|
||||
ControllerType.ProController => NpadLayoutsIndex.ProController,
|
||||
ControllerType.Handheld => NpadLayoutsIndex.Handheld,
|
||||
ControllerType.JoyconPair => NpadLayoutsIndex.JoyDual,
|
||||
ControllerType.JoyconLeft => NpadLayoutsIndex.JoyLeft,
|
||||
ControllerType.JoyconRight => NpadLayoutsIndex.JoyRight,
|
||||
ControllerType.Pokeball => NpadLayoutsIndex.Pokeball,
|
||||
_ => NpadLayoutsIndex.SystemExternal
|
||||
};
|
||||
|
||||
public void SetGamepadsInput(params GamepadInput[] states)
|
||||
{
|
||||
UpdateAllEntries();
|
||||
|
||||
for (int i = 0; i < states.Length; ++i)
|
||||
{
|
||||
SetGamepadState(states[i].PlayerId, states[i].Buttons, states[i].LStick, states[i].RStick);
|
||||
}
|
||||
}
|
||||
|
||||
void SetGamepadState(PlayerIndex player, ControllerKeys buttons,
|
||||
JoystickPosition leftJoystick, JoystickPosition rightJoystick)
|
||||
{
|
||||
if (player == PlayerIndex.Auto)
|
||||
{
|
||||
player = PrimaryController;
|
||||
}
|
||||
|
||||
if (player == PlayerIndex.Unknown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_configuredNpads[(int)player].State != FilterState.Accepted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ref ShMemNpad currentNpad = ref _device.Hid.SharedMemory.Npads[(int)player];
|
||||
ref NpadLayout currentLayout = ref currentNpad.Layouts[(int)ControllerTypeToLayout(currentNpad.Header.Type)];
|
||||
ref NpadState currentEntry = ref currentLayout.Entries[(int)currentLayout.Header.LatestEntry];
|
||||
|
||||
currentEntry.Buttons = buttons;
|
||||
currentEntry.LStickX = leftJoystick.Dx;
|
||||
currentEntry.LStickY = leftJoystick.Dy;
|
||||
currentEntry.RStickX = rightJoystick.Dx;
|
||||
currentEntry.RStickY = rightJoystick.Dy;
|
||||
|
||||
// Mirror data to Default layout just in case
|
||||
ref NpadLayout mainLayout = ref currentNpad.Layouts[(int)NpadLayoutsIndex.SystemExternal];
|
||||
mainLayout.Entries[(int)mainLayout.Header.LatestEntry] = currentEntry;
|
||||
}
|
||||
|
||||
void UpdateAllEntries()
|
||||
{
|
||||
ref Array10<ShMemNpad> controllers = ref _device.Hid.SharedMemory.Npads;
|
||||
for (int i = 0; i < controllers.Length; ++i)
|
||||
{
|
||||
ref Array7<NpadLayout> layouts = ref controllers[i].Layouts;
|
||||
for (int l = 0; l < layouts.Length; ++l)
|
||||
{
|
||||
ref NpadLayout currentLayout = ref layouts[l];
|
||||
int currentIndex = UpdateEntriesHeader(ref currentLayout.Header, out int previousIndex);
|
||||
|
||||
ref NpadState currentEntry = ref currentLayout.Entries[currentIndex];
|
||||
NpadState previousEntry = currentLayout.Entries[previousIndex];
|
||||
|
||||
currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
|
||||
currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1;
|
||||
|
||||
if (controllers[i].Header.Type == ControllerType.None)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
currentEntry.ConnectionState = NpadConnectionState.ControllerStateConnected;
|
||||
|
||||
switch (controllers[i].Header.Type)
|
||||
{
|
||||
case ControllerType.Handheld:
|
||||
case ControllerType.ProController:
|
||||
currentEntry.ConnectionState |= NpadConnectionState.ControllerStateWired;
|
||||
break;
|
||||
case ControllerType.JoyconPair:
|
||||
currentEntry.ConnectionState |= NpadConnectionState.JoyLeftConnected |
|
||||
NpadConnectionState.JoyRightConnected;
|
||||
break;
|
||||
case ControllerType.JoyconLeft:
|
||||
currentEntry.ConnectionState |= NpadConnectionState.JoyLeftConnected;
|
||||
break;
|
||||
case ControllerType.JoyconRight:
|
||||
currentEntry.ConnectionState |= NpadConnectionState.JoyRightConnected;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
46
Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs
Normal file
46
Ryujinx.HLE/HOS/Services/Hid/HidDevices/TouchDevice.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public class TouchDevice : BaseDevice
|
||||
{
|
||||
public TouchDevice(Switch device, bool active) : base(device, active) { }
|
||||
|
||||
public void Update(params TouchPoint[] points)
|
||||
{
|
||||
ref ShMemTouchScreen touchscreen = ref _device.Hid.SharedMemory.TouchScreen;
|
||||
|
||||
int currentIndex = UpdateEntriesHeader(ref touchscreen.Header, out int previousIndex);
|
||||
|
||||
if (!Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ref TouchScreenState currentEntry = ref touchscreen.Entries[currentIndex];
|
||||
TouchScreenState previousEntry = touchscreen.Entries[previousIndex];
|
||||
|
||||
currentEntry.SampleTimestamp = previousEntry.SampleTimestamp + 1;
|
||||
currentEntry.SampleTimestamp2 = previousEntry.SampleTimestamp2 + 1;
|
||||
|
||||
currentEntry.NumTouches = (ulong)points.Length;
|
||||
|
||||
int pointsLength = Math.Min(points.Length, currentEntry.Touches.Length);
|
||||
|
||||
for (int i = 0; i < pointsLength; ++i)
|
||||
{
|
||||
TouchPoint pi = points[i];
|
||||
currentEntry.Touches[i] = new TouchScreenStateData
|
||||
{
|
||||
SampleTimestamp = currentEntry.SampleTimestamp,
|
||||
X = pi.X,
|
||||
Y = pi.Y,
|
||||
TouchIndex = (uint)i,
|
||||
DiameterX = pi.DiameterX,
|
||||
DiameterY = pi.DiameterY,
|
||||
Angle = pi.Angle
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public struct ControllerConfig
|
||||
{
|
||||
public PlayerIndex Player;
|
||||
public ControllerType Type;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public struct GamepadInput
|
||||
{
|
||||
public PlayerIndex PlayerId;
|
||||
public ControllerKeys Buttons;
|
||||
public JoystickPosition LStick;
|
||||
public JoystickPosition RStick;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public struct JoystickPosition
|
||||
{
|
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public struct KeyboardInput
|
||||
{
|
||||
public int Modifier;
|
||||
public int[] Keys;
|
||||
}
|
||||
}
|
11
Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs
Normal file
11
Ryujinx.HLE/HOS/Services/Hid/HidDevices/Types/TouchPoint.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public struct TouchPoint
|
||||
{
|
||||
public uint X;
|
||||
public uint Y;
|
||||
public uint DiameterX;
|
||||
public uint DiameterY;
|
||||
public uint Angle;
|
||||
}
|
||||
}
|
|
@ -1,46 +1,39 @@
|
|||
using Ryujinx.HLE.Input;
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
|
||||
{
|
||||
static class HidUtils
|
||||
{
|
||||
public static ControllerId GetIndexFromNpadIdType(HidNpadIdType npadIdType)
|
||||
public static PlayerIndex GetIndexFromNpadIdType(NpadIdType npadIdType)
|
||||
=> npadIdType switch
|
||||
{
|
||||
switch (npadIdType)
|
||||
{
|
||||
case HidNpadIdType.Player1: return ControllerId.ControllerPlayer1;
|
||||
case HidNpadIdType.Player2: return ControllerId.ControllerPlayer2;
|
||||
case HidNpadIdType.Player3: return ControllerId.ControllerPlayer3;
|
||||
case HidNpadIdType.Player4: return ControllerId.ControllerPlayer4;
|
||||
case HidNpadIdType.Player5: return ControllerId.ControllerPlayer5;
|
||||
case HidNpadIdType.Player6: return ControllerId.ControllerPlayer6;
|
||||
case HidNpadIdType.Player7: return ControllerId.ControllerPlayer7;
|
||||
case HidNpadIdType.Player8: return ControllerId.ControllerPlayer8;
|
||||
case HidNpadIdType.Handheld: return ControllerId.ControllerHandheld;
|
||||
case HidNpadIdType.Unknown: return ControllerId.ControllerUnknown;
|
||||
NpadIdType.Player1 => PlayerIndex.Player1,
|
||||
NpadIdType.Player2 => PlayerIndex.Player2,
|
||||
NpadIdType.Player3 => PlayerIndex.Player3,
|
||||
NpadIdType.Player4 => PlayerIndex.Player4,
|
||||
NpadIdType.Player5 => PlayerIndex.Player5,
|
||||
NpadIdType.Player6 => PlayerIndex.Player6,
|
||||
NpadIdType.Player7 => PlayerIndex.Player7,
|
||||
NpadIdType.Player8 => PlayerIndex.Player8,
|
||||
NpadIdType.Handheld => PlayerIndex.Handheld,
|
||||
NpadIdType.Unknown => PlayerIndex.Unknown,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(npadIdType))
|
||||
};
|
||||
|
||||
default: throw new ArgumentOutOfRangeException(nameof(npadIdType));
|
||||
}
|
||||
}
|
||||
|
||||
public static HidNpadIdType GetNpadIdTypeFromIndex(ControllerId index)
|
||||
public static NpadIdType GetNpadIdTypeFromIndex(PlayerIndex index)
|
||||
=> index switch
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case ControllerId.ControllerPlayer1: return HidNpadIdType.Player1;
|
||||
case ControllerId.ControllerPlayer2: return HidNpadIdType.Player2;
|
||||
case ControllerId.ControllerPlayer3: return HidNpadIdType.Player3;
|
||||
case ControllerId.ControllerPlayer4: return HidNpadIdType.Player4;
|
||||
case ControllerId.ControllerPlayer5: return HidNpadIdType.Player5;
|
||||
case ControllerId.ControllerPlayer6: return HidNpadIdType.Player6;
|
||||
case ControllerId.ControllerPlayer7: return HidNpadIdType.Player7;
|
||||
case ControllerId.ControllerPlayer8: return HidNpadIdType.Player8;
|
||||
case ControllerId.ControllerHandheld: return HidNpadIdType.Handheld;
|
||||
case ControllerId.ControllerUnknown: return HidNpadIdType.Unknown;
|
||||
|
||||
default: throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
PlayerIndex.Player1 => NpadIdType.Player1,
|
||||
PlayerIndex.Player2 => NpadIdType.Player2,
|
||||
PlayerIndex.Player3 => NpadIdType.Player3,
|
||||
PlayerIndex.Player4 => NpadIdType.Player4,
|
||||
PlayerIndex.Player5 => NpadIdType.Player5,
|
||||
PlayerIndex.Player6 => NpadIdType.Player6,
|
||||
PlayerIndex.Player7 => NpadIdType.Player7,
|
||||
PlayerIndex.Player8 => NpadIdType.Player8,
|
||||
PlayerIndex.Handheld => NpadIdType.Handheld,
|
||||
PlayerIndex.Unknown => NpadIdType.Unknown,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(index))
|
||||
};
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ using Ryujinx.HLE.HOS.Ipc;
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
|
||||
using Ryujinx.HLE.Input;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
|
@ -11,7 +10,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
[Service("hid")]
|
||||
class IHidServer : IpcService
|
||||
{
|
||||
private KEvent _npadStyleSetUpdateEvent;
|
||||
private KEvent _xpadIdEvent;
|
||||
private KEvent _palmaOperationCompleteEvent;
|
||||
|
||||
|
@ -22,8 +20,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
private bool _vibrationPermitted;
|
||||
private bool _usbFullKeyControllerEnabled;
|
||||
|
||||
private HidNpadJoyHoldType _npadJoyHoldType;
|
||||
private HidNpadStyle _npadStyleSet;
|
||||
private HidNpadJoyAssignmentMode _npadJoyAssignmentMode;
|
||||
private HidNpadHandheldActivationMode _npadHandheldActivationMode;
|
||||
private HidGyroscopeZeroDriftMode _gyroscopeZeroDriftMode;
|
||||
|
@ -39,12 +35,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
|
||||
public IHidServer(ServiceCtx context)
|
||||
{
|
||||
_npadStyleSetUpdateEvent = new KEvent(context.Device.System);
|
||||
_xpadIdEvent = new KEvent(context.Device.System);
|
||||
_palmaOperationCompleteEvent = new KEvent(context.Device.System);
|
||||
|
||||
_npadJoyHoldType = HidNpadJoyHoldType.Vertical;
|
||||
_npadStyleSet = HidNpadStyle.FullKey | HidNpadStyle.Dual | HidNpadStyle.Left | HidNpadStyle.Right | HidNpadStyle.Handheld;
|
||||
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Dual;
|
||||
_npadHandheldActivationMode = HidNpadHandheldActivationMode.Dual;
|
||||
_gyroscopeZeroDriftMode = HidGyroscopeZeroDriftMode.Standard;
|
||||
|
@ -85,6 +78,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
context.Device.Hid.Touchscreen.Active = true;
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
||||
|
||||
return ResultCode.Success;
|
||||
|
@ -96,6 +90,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
context.Device.Hid.Mouse.Active = true;
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
||||
|
||||
return ResultCode.Success;
|
||||
|
@ -107,6 +102,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
context.Device.Hid.Keyboard.Active = true;
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
||||
|
||||
return ResultCode.Success;
|
||||
|
@ -542,13 +538,15 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
// SetSupportedNpadStyleSet(nn::applet::AppletResourceUserId, nn::hid::NpadStyleTag)
|
||||
public ResultCode SetSupportedNpadStyleSet(ServiceCtx context)
|
||||
{
|
||||
_npadStyleSet = (HidNpadStyle)context.RequestData.ReadInt32();
|
||||
|
||||
ControllerType type = (ControllerType)context.RequestData.ReadInt32();
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadStyleSet });
|
||||
Logger.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
type
|
||||
});
|
||||
|
||||
_npadStyleSetUpdateEvent.ReadableEvent.Signal();
|
||||
context.Device.Hid.Npads.SupportedStyleSets = type;
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -559,9 +557,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
context.ResponseData.Write((int)_npadStyleSet);
|
||||
context.ResponseData.Write((int)context.Device.Hid.Npads.SupportedStyleSets);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadStyleSet });
|
||||
Logger.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
context.Device.Hid.Npads.SupportedStyleSets
|
||||
});
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -571,9 +572,16 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
public ResultCode SetSupportedNpadIdType(ServiceCtx context)
|
||||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
ControllerId npadIdType = (ControllerId)context.RequestData.ReadInt64();
|
||||
long arraySize = context.Request.PtrBuff[0].Size / 4;
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, npadIdType });
|
||||
NpadIdType[] supportedPlayerIds = new NpadIdType[arraySize];
|
||||
|
||||
for (int i = 0; i < arraySize; ++i)
|
||||
{
|
||||
supportedPlayerIds[i] = (NpadIdType)context.Memory.ReadInt32(context.Request.PtrBuff[0].Position + i * 4);
|
||||
}
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceHid, $"{arraySize} " + string.Join(",", supportedPlayerIds));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -584,6 +592,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
context.Device.Hid.Npads.Active = true;
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
||||
|
||||
return ResultCode.Success;
|
||||
|
@ -595,6 +604,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
context.Device.Hid.Npads.Active = false;
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
||||
|
||||
return ResultCode.Success;
|
||||
|
@ -604,11 +614,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
// AcquireNpadStyleSetUpdateEventHandle(nn::applet::AppletResourceUserId, uint, ulong) -> nn::sf::NativeHandle
|
||||
public ResultCode AcquireNpadStyleSetUpdateEventHandle(ServiceCtx context)
|
||||
{
|
||||
PlayerIndex npadId = HidUtils.GetIndexFromNpadIdType((NpadIdType)context.RequestData.ReadInt32());
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
int npadId = context.RequestData.ReadInt32();
|
||||
long npadStyleSet = context.RequestData.ReadInt64();
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_npadStyleSetUpdateEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
KEvent evnt = context.Device.Hid.Npads.GetStyleSetUpdateEvent(npadId);
|
||||
if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out int handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
@ -624,8 +635,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
// DisconnectNpad(nn::applet::AppletResourceUserId, uint NpadIdType)
|
||||
public ResultCode DisconnectNpad(ServiceCtx context)
|
||||
{
|
||||
NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadInt32();
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
int npadIdType = context.RequestData.ReadInt32();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, npadIdType });
|
||||
|
||||
|
@ -651,10 +662,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
// ActivateNpadWithRevision(nn::applet::AppletResourceUserId, int Unknown)
|
||||
public ResultCode ActivateNpadWithRevision(ServiceCtx context)
|
||||
{
|
||||
int revision = context.RequestData.ReadInt32();
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
int unknown = context.RequestData.ReadInt32();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, unknown });
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, revision });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -664,9 +675,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
public ResultCode SetNpadJoyHoldType(ServiceCtx context)
|
||||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
_npadJoyHoldType = (HidNpadJoyHoldType)context.RequestData.ReadInt64();
|
||||
context.Device.Hid.Npads.JoyHold = (NpadJoyHoldType)context.RequestData.ReadInt64();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadJoyHoldType });
|
||||
Logger.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
context.Device.Hid.Npads.JoyHold
|
||||
});
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -677,9 +691,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
{
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
context.ResponseData.Write((long)_npadJoyHoldType);
|
||||
context.ResponseData.Write((long)context.Device.Hid.Npads.JoyHold);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadJoyHoldType });
|
||||
Logger.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
context.Device.Hid.Npads.JoyHold
|
||||
});
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -688,7 +705,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
// SetNpadJoyAssignmentModeSingleByDefault(uint HidControllerId, nn::applet::AppletResourceUserId)
|
||||
public ResultCode SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx context)
|
||||
{
|
||||
ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32();
|
||||
PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32();
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Single;
|
||||
|
@ -702,7 +719,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
// SetNpadJoyAssignmentModeSingle(uint HidControllerId, nn::applet::AppletResourceUserId, long HidNpadJoyDeviceType)
|
||||
public ResultCode SetNpadJoyAssignmentModeSingle(ServiceCtx context)
|
||||
{
|
||||
ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32();
|
||||
PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32();
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)context.RequestData.ReadInt64();
|
||||
|
||||
|
@ -717,7 +734,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
// SetNpadJoyAssignmentModeDual(uint HidControllerId, nn::applet::AppletResourceUserId)
|
||||
public ResultCode SetNpadJoyAssignmentModeDual(ServiceCtx context)
|
||||
{
|
||||
ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32();
|
||||
PlayerIndex hidControllerId = HidUtils.GetIndexFromNpadIdType((NpadIdType)context.RequestData.ReadInt32());
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Dual;
|
||||
|
@ -831,7 +848,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
// SetNpadJoyAssignmentModeSingleWithDestination(uint HidControllerId, long HidNpadJoyDeviceType, nn::applet::AppletResourceUserId) -> bool Unknown0, uint Unknown1
|
||||
public ResultCode SetNpadJoyAssignmentModeSingleWithDestination(ServiceCtx context)
|
||||
{
|
||||
ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32();
|
||||
PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32();
|
||||
HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)context.RequestData.ReadInt64();
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
|
||||
using Ryujinx.HLE.Input;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid.Irs
|
||||
|
@ -57,16 +56,16 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
|
|||
// GetNpadIrCameraHandle(u32) -> nn::irsensor::IrCameraHandle
|
||||
public ResultCode GetNpadIrCameraHandle(ServiceCtx context)
|
||||
{
|
||||
HidNpadIdType npadIdType = (HidNpadIdType)context.RequestData.ReadUInt32();
|
||||
NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadUInt32();
|
||||
|
||||
if (npadIdType > HidNpadIdType.Player8 &&
|
||||
npadIdType != HidNpadIdType.Unknown &&
|
||||
npadIdType != HidNpadIdType.Handheld)
|
||||
if (npadIdType > NpadIdType.Player8 &&
|
||||
npadIdType != NpadIdType.Unknown &&
|
||||
npadIdType != NpadIdType.Handheld)
|
||||
{
|
||||
return ResultCode.NpadIdOutOfRange;
|
||||
}
|
||||
|
||||
ControllerId irCameraHandle = HidUtils.GetIndexFromNpadIdType(npadIdType);
|
||||
PlayerIndex irCameraHandle = HidUtils.GetIndexFromNpadIdType(npadIdType);
|
||||
|
||||
context.ResponseData.Write((int)irCameraHandle);
|
||||
|
||||
|
|
9
Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs
Normal file
9
Ryujinx.HLE/HOS/Services/Hid/Types/Boolean32.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct Boolean32
|
||||
{
|
||||
private uint _value;
|
||||
public static implicit operator bool(Boolean32 value) => (value._value & 1) != 0;
|
||||
public static implicit operator Boolean32(bool value) => new Boolean32() { _value = value ? 1u : 0u };
|
||||
}
|
||||
}
|
45
Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerKeys.cs
Normal file
45
Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerKeys.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
[Flags]
|
||||
public enum ControllerKeys : long
|
||||
{
|
||||
A = 1 << 0,
|
||||
B = 1 << 1,
|
||||
X = 1 << 2,
|
||||
Y = 1 << 3,
|
||||
LStick = 1 << 4,
|
||||
RStick = 1 << 5,
|
||||
L = 1 << 6,
|
||||
R = 1 << 7,
|
||||
Zl = 1 << 8,
|
||||
Zr = 1 << 9,
|
||||
Plus = 1 << 10,
|
||||
Minus = 1 << 11,
|
||||
DpadLeft = 1 << 12,
|
||||
DpadUp = 1 << 13,
|
||||
DpadRight = 1 << 14,
|
||||
DpadDown = 1 << 15,
|
||||
LStickLeft = 1 << 16,
|
||||
LStickUp = 1 << 17,
|
||||
LStickRight = 1 << 18,
|
||||
LStickDown = 1 << 19,
|
||||
RStickLeft = 1 << 20,
|
||||
RStickUp = 1 << 21,
|
||||
RStickRight = 1 << 22,
|
||||
RStickDown = 1 << 23,
|
||||
SlLeft = 1 << 24,
|
||||
SrLeft = 1 << 25,
|
||||
SlRight = 1 << 26,
|
||||
SrRight = 1 << 27,
|
||||
|
||||
// Generic Catch-all
|
||||
Up = DpadUp | LStickUp | RStickUp,
|
||||
Down = DpadDown | LStickDown | RStickDown,
|
||||
Left = DpadLeft | LStickLeft | RStickLeft,
|
||||
Right = DpadRight | LStickRight | RStickRight,
|
||||
Sl = SlLeft | SlRight,
|
||||
Sr = SrLeft | SrRight
|
||||
}
|
||||
}
|
19
Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerType.cs
Normal file
19
Ryujinx.HLE/HOS/Services/Hid/Types/Npad/ControllerType.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
[Flags]
|
||||
public enum ControllerType : int
|
||||
{
|
||||
None,
|
||||
ProController = 1 << 0,
|
||||
Handheld = 1 << 1,
|
||||
JoyconPair = 1 << 2,
|
||||
JoyconLeft = 1 << 3,
|
||||
JoyconRight = 1 << 4,
|
||||
Invalid = 1 << 5,
|
||||
Pokeball = 1 << 6,
|
||||
SystemExternal = 1 << 29,
|
||||
System = 1 << 30
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public enum HidNpadJoyHoldType
|
||||
{
|
||||
Vertical,
|
||||
Horizontal
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
[Flags]
|
||||
public enum HidNpadStyle
|
||||
{
|
||||
None,
|
||||
FullKey = 1 << 0,
|
||||
Handheld = 1 << 1,
|
||||
Dual = 1 << 2,
|
||||
Left = 1 << 3,
|
||||
Right = 1 << 4,
|
||||
Invalid = 1 << 5
|
||||
}
|
||||
}
|
37
Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs
Normal file
37
Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadColor.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public enum NpadColor : int
|
||||
{
|
||||
BodyGray = 0x828282,
|
||||
BodyNeonRed = 0xFF3C28,
|
||||
BodyNeonBlue = 0x0AB9E6,
|
||||
BodyNeonYellow = 0xE6FF00,
|
||||
BodyNeonGreen = 0x1EDC00,
|
||||
BodyNeonPink = 0xFF3278,
|
||||
BodyRed = 0xE10F00,
|
||||
BodyBlue = 0x4655F5,
|
||||
BodyNeonPurple = 0xB400E6,
|
||||
BodyNeonOrange = 0xFAA005,
|
||||
BodyPokemonLetsGoPikachu = 0xFFDC00,
|
||||
BodyPokemonLetsGoEevee = 0xC88C32,
|
||||
BodyNintendoLaboCreatorsContestEdition = 0xD7AA73,
|
||||
BodyAnimalCrossingSpecialEditionLeftJoyCon = 0x82FF96,
|
||||
BodyAnimalCrossingSpecialEditionRightJoyCon = 0x96F5F5,
|
||||
|
||||
ButtonGray = 0x0F0F0F,
|
||||
ButtonNeonRed = 0x1E0A0A,
|
||||
ButtonNeonBlue = 0x001E1E,
|
||||
ButtonNeonYellow = 0x142800,
|
||||
ButtonNeonGreen = 0x002800,
|
||||
ButtonNeonPink = 0x28001E,
|
||||
ButtonRed = 0x280A0A,
|
||||
ButtonBlue = 0x00000A,
|
||||
ButtonNeonPurple = 0x140014,
|
||||
ButtonNeonOrange = 0x0F0A00,
|
||||
ButtonPokemonLetsGoPikachu = 0x322800,
|
||||
ButtonPokemonLetsGoEevee = 0x281900,
|
||||
ButtonNintendoLaboCreatorsContestEdition = 0x1E1914,
|
||||
ButtonAnimalCrossingSpecialEditionLeftJoyCon = 0x0A1E0A,
|
||||
ButtonAnimalCrossingSpecialEditionRightJoyCon = 0x0A1E28
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public enum HidNpadIdType
|
||||
public enum NpadIdType
|
||||
{
|
||||
Player1 = 0,
|
||||
Player2 = 1,
|
17
Ryujinx.HLE/HOS/Services/Hid/Types/Npad/PlayerIndex.cs
Normal file
17
Ryujinx.HLE/HOS/Services/Hid/Types/Npad/PlayerIndex.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public enum PlayerIndex : int
|
||||
{
|
||||
Player1 = 0,
|
||||
Player2 = 1,
|
||||
Player3 = 2,
|
||||
Player4 = 3,
|
||||
Player5 = 4,
|
||||
Player6 = 5,
|
||||
Player7 = 6,
|
||||
Player8 = 7,
|
||||
Handheld = 8,
|
||||
Unknown = 9,
|
||||
Auto = 10 // Shouldn't be used directly
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct CommonEntriesHeader
|
||||
{
|
||||
public ulong TimestampTicks;
|
||||
public ulong NumEntries;
|
||||
public ulong LatestEntry;
|
||||
public ulong MaxEntryIndex;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
unsafe struct ShMemDebugPad
|
||||
{
|
||||
public CommonEntriesHeader Header;
|
||||
public Array17<DebugPadEntry> Entries;
|
||||
fixed byte _padding[0x138];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
unsafe struct DebugPadEntry
|
||||
{
|
||||
public ulong SampleTimestamp;
|
||||
fixed byte _unknown[0x20];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
// TODO: Add missing structs
|
||||
unsafe struct HidSharedMemory
|
||||
{
|
||||
public ShMemDebugPad DebugPad;
|
||||
public ShMemTouchScreen TouchScreen;
|
||||
public ShMemMouse Mouse;
|
||||
public ShMemKeyboard Keyboard;
|
||||
public fixed byte BasicXpad[0x4 * 0x400];
|
||||
public fixed byte HomeButton[0x200];
|
||||
public fixed byte SleepButton[0x200];
|
||||
public fixed byte CaptureButton[0x200];
|
||||
public fixed byte InputDetector[0x10 * 0x80];
|
||||
public fixed byte UniquePad[0x10 * 0x400];
|
||||
public Array10<ShMemNpad> Npads;
|
||||
public fixed byte Gesture[0x800];
|
||||
public fixed byte ConsoleSixAxisSensor[0x20];
|
||||
fixed byte _padding[0x3de0];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
unsafe struct ShMemKeyboard
|
||||
{
|
||||
public CommonEntriesHeader Header;
|
||||
public Array17<KeyboardState> Entries;
|
||||
fixed byte _padding[0x28];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
unsafe struct KeyboardState
|
||||
{
|
||||
public ulong SampleTimestamp;
|
||||
public ulong SampleTimestamp2;
|
||||
public ulong Modifier;
|
||||
public fixed uint Keys[8];
|
||||
}
|
||||
}
|
10
Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/Mouse.cs
Normal file
10
Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Mouse/Mouse.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
unsafe struct ShMemMouse
|
||||
{
|
||||
public CommonEntriesHeader Header;
|
||||
public Array17<MouseState> Entries;
|
||||
fixed byte _padding[0xB0];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct MousePosition
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
public int VelocityX;
|
||||
public int VelocityY;
|
||||
public int ScrollVelocityX;
|
||||
public int ScrollVelocityY;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct MouseState
|
||||
{
|
||||
public ulong SampleTimestamp;
|
||||
public ulong SampleTimestamp2;
|
||||
public MousePosition Position;
|
||||
public ulong Buttons;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
enum BatteryCharge : int
|
||||
{
|
||||
Percent0 = 0,
|
||||
Percent25 = 1,
|
||||
Percent50 = 2,
|
||||
Percent75 = 3,
|
||||
Percent100 = 4
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
[Flags]
|
||||
enum DeviceType : int
|
||||
{
|
||||
FullKey = 1 << 0,
|
||||
DebugPad = 1 << 1,
|
||||
HandheldLeft = 1 << 2,
|
||||
HandheldRight = 1 << 3,
|
||||
JoyLeft = 1 << 4,
|
||||
JoyRight = 1 << 5,
|
||||
Palma = 1 << 6, // Poké Ball Plus
|
||||
FamicomLeft = 1 << 7,
|
||||
FamicomRight = 1 << 8,
|
||||
NESLeft = 1 << 9,
|
||||
NESRight = 1 << 10,
|
||||
HandheldFamicomLeft = 1 << 11,
|
||||
HandheldFamicomRight = 1 << 12,
|
||||
HandheldNESLeft = 1 << 13,
|
||||
HandheldNESRight = 1 << 14,
|
||||
Lucia = 1 << 15,
|
||||
System = 1 << 31
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct HidVector
|
||||
{
|
||||
public float X;
|
||||
public float Y;
|
||||
public float Z;
|
||||
}
|
||||
}
|
21
Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs
Normal file
21
Ryujinx.HLE/HOS/Services/Hid/Types/SharedMem/Npad/Npad.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
// TODO: Add missing structs
|
||||
unsafe struct ShMemNpad
|
||||
{
|
||||
public NpadStateHeader Header;
|
||||
public Array7<NpadLayout> Layouts; // One for each NpadLayoutsIndex
|
||||
public Array6<NpadSixAxis> Sixaxis;
|
||||
public DeviceType DeviceType;
|
||||
uint _padding1;
|
||||
public NpadSystemProperties SystemProperties;
|
||||
public uint NpadSystemButtonProperties;
|
||||
public Array3<BatteryCharge> 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];
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
[Flags]
|
||||
public enum ControllerColorDescription : int
|
||||
enum NpadColorDescription : int
|
||||
{
|
||||
ColorDescriptionColorsNonexistent = (1 << 1)
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
[Flags]
|
||||
enum NpadConnectionState : long
|
||||
{
|
||||
ControllerStateConnected = (1 << 0),
|
||||
ControllerStateWired = (1 << 1),
|
||||
JoyLeftConnected = (1 << 2),
|
||||
JoyRightConnected = (1 << 4)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
enum NpadJoyHoldType
|
||||
{
|
||||
Vertical,
|
||||
Horizontal
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct NpadLayout
|
||||
{
|
||||
public CommonEntriesHeader Header;
|
||||
public Array17<NpadState> Entries;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
enum NpadLayoutsIndex : int
|
||||
{
|
||||
ProController = 0,
|
||||
Handheld = 1,
|
||||
JoyDual = 2,
|
||||
JoyLeft = 3,
|
||||
JoyRight = 4,
|
||||
Pokeball = 5,
|
||||
SystemExternal = 6
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct NpadSixAxis
|
||||
{
|
||||
public CommonEntriesHeader Header;
|
||||
public Array17<SixAxisState> Entries;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct NpadState
|
||||
{
|
||||
public ulong SampleTimestamp;
|
||||
public ulong SampleTimestamp2;
|
||||
public ControllerKeys Buttons;
|
||||
public int LStickX;
|
||||
public int LStickY;
|
||||
public int RStickX;
|
||||
public int RStickY;
|
||||
public NpadConnectionState ConnectionState;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct NpadStateHeader
|
||||
{
|
||||
public ControllerType Type;
|
||||
public Boolean32 IsHalf;
|
||||
public NpadColorDescription SingleColorsDescriptor;
|
||||
public NpadColor SingleColorBody;
|
||||
public NpadColor SingleColorButtons;
|
||||
public NpadColorDescription SplitColorsDescriptor;
|
||||
public NpadColor LeftColorBody;
|
||||
public NpadColor LeftColorButtons;
|
||||
public NpadColor RightColorBody;
|
||||
public NpadColor RightColorButtons;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
[Flags]
|
||||
enum NpadSystemProperties : long
|
||||
{
|
||||
PowerInfo0Charging = 1 << 0,
|
||||
PowerInfo1Charging = 1 << 1,
|
||||
PowerInfo2Charging = 1 << 2,
|
||||
PowerInfo0Connected = 1 << 3,
|
||||
PowerInfo1Connected = 1 << 4,
|
||||
PowerInfo2Connected = 1 << 5,
|
||||
UnsupportedButtonPressedNpadSystem = 1 << 9,
|
||||
UnsupportedButtonPressedNpadSystemExt = 1 << 10,
|
||||
AbxyButtonOriented = 1 << 11,
|
||||
SlSrButtonOriented = 1 << 12,
|
||||
PlusButtonCapability = 1 << 13,
|
||||
MinusButtonCapability = 1 << 14,
|
||||
DirectionalButtonsSupported = 1 << 15
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
unsafe struct SixAxisState
|
||||
{
|
||||
public ulong SampleTimestamp;
|
||||
ulong _unknown1;
|
||||
public ulong SampleTimestamp2;
|
||||
public HidVector Accelerometer;
|
||||
public HidVector Gyroscope;
|
||||
HidVector unknownSensor;
|
||||
public fixed float Orientation[9];
|
||||
ulong _unknown2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct Array2<T> where T : unmanaged
|
||||
{
|
||||
T e0, e1;
|
||||
public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 2)[index];
|
||||
public int Length => 2;
|
||||
}
|
||||
|
||||
struct Array3<T> where T : unmanaged
|
||||
{
|
||||
T e0, e1, e2;
|
||||
public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 3)[index];
|
||||
public int Length => 3;
|
||||
}
|
||||
|
||||
struct Array6<T> where T : unmanaged
|
||||
{
|
||||
T e0, e1, e2, e3, e4, e5;
|
||||
public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 6)[index];
|
||||
public int Length => 6;
|
||||
}
|
||||
|
||||
struct Array7<T> where T : unmanaged
|
||||
{
|
||||
T e0, e1, e2, e3, e4, e5, e6;
|
||||
public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 7)[index];
|
||||
public int Length => 7;
|
||||
}
|
||||
|
||||
struct Array10<T> where T : unmanaged
|
||||
{
|
||||
T e0, e1, e2, e3, e4, e5, e6, e7, e8, e9;
|
||||
public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 10)[index];
|
||||
public int Length => 10;
|
||||
}
|
||||
|
||||
struct Array16<T> where T : unmanaged
|
||||
{
|
||||
T e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15;
|
||||
public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 16)[index];
|
||||
public int Length => 16;
|
||||
}
|
||||
|
||||
struct Array17<T> where T : unmanaged
|
||||
{
|
||||
T e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16;
|
||||
public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref e0, 17)[index];
|
||||
public int Length => 17;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
unsafe struct ShMemTouchScreen
|
||||
{
|
||||
public CommonEntriesHeader Header;
|
||||
public Array17<TouchScreenState> Entries;
|
||||
fixed byte _padding[0x3c8];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct TouchScreenState
|
||||
{
|
||||
public ulong SampleTimestamp;
|
||||
public ulong SampleTimestamp2;
|
||||
public ulong NumTouches;
|
||||
public Array16<TouchScreenStateData> Touches;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
struct TouchScreenStateData
|
||||
{
|
||||
public ulong SampleTimestamp;
|
||||
uint _padding;
|
||||
public uint TouchIndex;
|
||||
public uint X;
|
||||
public uint Y;
|
||||
public uint DiameterX;
|
||||
public uint DiameterY;
|
||||
public uint Angle;
|
||||
uint _padding2;
|
||||
}
|
||||
}
|
|
@ -43,8 +43,8 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||
// TODO: When we will be able to add multiple controllers add one entry by controller here.
|
||||
Device device1 = new Device
|
||||
{
|
||||
NpadIdType = HidNpadIdType.Player1,
|
||||
Handle = HidUtils.GetIndexFromNpadIdType(HidNpadIdType.Player1),
|
||||
NpadIdType = NpadIdType.Player1,
|
||||
Handle = HidUtils.GetIndexFromNpadIdType(NpadIdType.Player1),
|
||||
State = DeviceState.Initialized
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Hid;
|
||||
using Ryujinx.HLE.Input;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager
|
||||
{
|
||||
|
@ -14,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager
|
|||
|
||||
public DeviceState State = DeviceState.Unavailable;
|
||||
|
||||
public ControllerId Handle;
|
||||
public HidNpadIdType NpadIdType;
|
||||
public PlayerIndex Handle;
|
||||
public NpadIdType NpadIdType;
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
using static Ryujinx.HLE.Input.Hid;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public abstract class BaseController : IHidDevice
|
||||
{
|
||||
protected ControllerStatus HidControllerType;
|
||||
protected ControllerId ControllerId;
|
||||
|
||||
private long _currentLayoutOffset;
|
||||
private long _mainLayoutOffset;
|
||||
|
||||
protected long DeviceStateOffset => Offset + 0x4188;
|
||||
|
||||
protected Switch Device { get; }
|
||||
|
||||
public long Offset { get; private set; }
|
||||
public bool Connected { get; protected set; }
|
||||
|
||||
public ControllerHeader Header { get; private set; }
|
||||
public ControllerStateHeader CurrentStateHeader { get; private set; }
|
||||
public ControllerDeviceState DeviceState { get; private set; }
|
||||
public ControllerLayouts CurrentLayout { get; private set; }
|
||||
public ControllerState LastInputState { get; set; }
|
||||
public ControllerConnectionState ConnectionState { get; protected set; }
|
||||
|
||||
public BaseController(Switch device, ControllerStatus controllerType)
|
||||
{
|
||||
Device = device;
|
||||
HidControllerType = controllerType;
|
||||
}
|
||||
|
||||
protected void Initialize(
|
||||
bool isHalf,
|
||||
(NpadColor left, NpadColor right) bodyColors,
|
||||
(NpadColor left, NpadColor right) buttonColors,
|
||||
ControllerColorDescription singleColorDesc = 0,
|
||||
ControllerColorDescription splitColorDesc = 0,
|
||||
NpadColor singleBodyColor = 0,
|
||||
NpadColor singleButtonColor = 0
|
||||
)
|
||||
{
|
||||
Header = new ControllerHeader()
|
||||
{
|
||||
IsJoyConHalf = isHalf ? 1 : 0,
|
||||
LeftBodyColor = bodyColors.left,
|
||||
LeftButtonColor = buttonColors.left,
|
||||
RightBodyColor = bodyColors.right,
|
||||
RightButtonColor = buttonColors.right,
|
||||
Status = HidControllerType,
|
||||
SingleBodyColor = singleBodyColor,
|
||||
SingleButtonColor = singleButtonColor,
|
||||
SplitColorDescription = splitColorDesc,
|
||||
SingleColorDescription = singleColorDesc,
|
||||
};
|
||||
|
||||
CurrentStateHeader = new ControllerStateHeader
|
||||
{
|
||||
EntryCount = HidEntryCount,
|
||||
MaxEntryCount = HidEntryCount - 1,
|
||||
CurrentEntryIndex = -1
|
||||
};
|
||||
|
||||
DeviceState = new ControllerDeviceState()
|
||||
{
|
||||
PowerInfo0BatteryState = BatteryState.Percent100,
|
||||
PowerInfo1BatteryState = BatteryState.Percent100,
|
||||
PowerInfo2BatteryState = BatteryState.Percent100,
|
||||
DeviceType = ControllerDeviceType.NPadLeftController | ControllerDeviceType.NPadRightController,
|
||||
DeviceFlags = DeviceFlags.PowerInfo0Connected
|
||||
| DeviceFlags.PowerInfo1Connected
|
||||
| DeviceFlags.PowerInfo2Connected
|
||||
};
|
||||
|
||||
LastInputState = new ControllerState()
|
||||
{
|
||||
SamplesTimestamp = -1,
|
||||
SamplesTimestamp2 = -1
|
||||
};
|
||||
}
|
||||
|
||||
public virtual void Connect(ControllerId controllerId)
|
||||
{
|
||||
ControllerId = controllerId;
|
||||
|
||||
Offset = Device.Hid.HidPosition + HidControllersOffset + (int)controllerId * HidControllerSize;
|
||||
|
||||
_mainLayoutOffset = Offset + HidControllerHeaderSize
|
||||
+ ((int)ControllerLayouts.Main * HidControllerLayoutsSize);
|
||||
|
||||
Device.Memory.FillWithZeros(Offset, 0x5000);
|
||||
Device.Memory.WriteStruct(Offset, Header);
|
||||
Device.Memory.WriteStruct(DeviceStateOffset, DeviceState);
|
||||
|
||||
Connected = true;
|
||||
}
|
||||
|
||||
public void SetLayout(ControllerLayouts controllerLayout)
|
||||
{
|
||||
CurrentLayout = controllerLayout;
|
||||
|
||||
_currentLayoutOffset = Offset + HidControllerHeaderSize
|
||||
+ ((int)controllerLayout * HidControllerLayoutsSize);
|
||||
}
|
||||
|
||||
public void SendInput(
|
||||
ControllerButtons buttons,
|
||||
JoystickPosition leftStick,
|
||||
JoystickPosition rightStick)
|
||||
{
|
||||
ControllerState currentInput = new ControllerState()
|
||||
{
|
||||
SamplesTimestamp = (long)LastInputState.SamplesTimestamp + 1,
|
||||
SamplesTimestamp2 = (long)LastInputState.SamplesTimestamp + 1,
|
||||
ButtonState = buttons,
|
||||
ConnectionState = ConnectionState,
|
||||
LeftStick = leftStick,
|
||||
RightStick = rightStick
|
||||
};
|
||||
|
||||
ControllerStateHeader newInputStateHeader = new ControllerStateHeader
|
||||
{
|
||||
EntryCount = HidEntryCount,
|
||||
MaxEntryCount = HidEntryCount - 1,
|
||||
CurrentEntryIndex = (CurrentStateHeader.CurrentEntryIndex + 1) % HidEntryCount,
|
||||
Timestamp = GetTimestamp(),
|
||||
};
|
||||
|
||||
Device.Memory.WriteStruct(_currentLayoutOffset, newInputStateHeader);
|
||||
Device.Memory.WriteStruct(_mainLayoutOffset, newInputStateHeader);
|
||||
|
||||
long currentInputStateOffset = HidControllersLayoutHeaderSize
|
||||
+ newInputStateHeader.CurrentEntryIndex * HidControllersInputEntrySize;
|
||||
|
||||
Device.Memory.WriteStruct(_currentLayoutOffset + currentInputStateOffset, currentInput);
|
||||
Device.Memory.WriteStruct(_mainLayoutOffset + currentInputStateOffset, currentInput);
|
||||
|
||||
LastInputState = currentInput;
|
||||
CurrentStateHeader = newInputStateHeader;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public class NpadController : BaseController
|
||||
{
|
||||
private (NpadColor Left, NpadColor Right) _npadBodyColors;
|
||||
private (NpadColor Left, NpadColor Right) _npadButtonColors;
|
||||
|
||||
private bool _isHalf;
|
||||
|
||||
public NpadController(
|
||||
ControllerStatus controllerStatus,
|
||||
Switch device,
|
||||
(NpadColor, NpadColor) npadBodyColors,
|
||||
(NpadColor, NpadColor) npadButtonColors) : base(device, controllerStatus)
|
||||
{
|
||||
_npadBodyColors = npadBodyColors;
|
||||
_npadButtonColors = npadButtonColors;
|
||||
}
|
||||
|
||||
public override void Connect(ControllerId controllerId)
|
||||
{
|
||||
if (HidControllerType != ControllerStatus.NpadLeft && HidControllerType != ControllerStatus.NpadRight)
|
||||
{
|
||||
_isHalf = false;
|
||||
}
|
||||
|
||||
ConnectionState = ControllerConnectionState.ControllerStateConnected;
|
||||
|
||||
if (controllerId == ControllerId.ControllerHandheld)
|
||||
ConnectionState |= ControllerConnectionState.ControllerStateWired;
|
||||
|
||||
ControllerColorDescription singleColorDesc =
|
||||
ControllerColorDescription.ColorDescriptionColorsNonexistent;
|
||||
|
||||
ControllerColorDescription splitColorDesc = 0;
|
||||
|
||||
NpadColor singleBodyColor = NpadColor.Black;
|
||||
NpadColor singleButtonColor = NpadColor.Black;
|
||||
|
||||
Initialize(_isHalf,
|
||||
(_npadBodyColors.Left, _npadBodyColors.Right),
|
||||
(_npadButtonColors.Left, _npadButtonColors.Right),
|
||||
singleColorDesc,
|
||||
splitColorDesc,
|
||||
singleBodyColor,
|
||||
singleButtonColor );
|
||||
|
||||
base.Connect(controllerId);
|
||||
|
||||
var _currentLayout = ControllerLayouts.HandheldJoined;
|
||||
|
||||
switch (HidControllerType)
|
||||
{
|
||||
case ControllerStatus.NpadLeft:
|
||||
_currentLayout = ControllerLayouts.Left;
|
||||
break;
|
||||
case ControllerStatus.NpadRight:
|
||||
_currentLayout = ControllerLayouts.Right;
|
||||
break;
|
||||
case ControllerStatus.NpadPair:
|
||||
_currentLayout = ControllerLayouts.Joined;
|
||||
break;
|
||||
}
|
||||
|
||||
SetLayout(_currentLayout);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public class ProController : BaseController
|
||||
{
|
||||
private bool _wired = false;
|
||||
|
||||
private NpadColor _bodyColor;
|
||||
private NpadColor _buttonColor;
|
||||
|
||||
public ProController(Switch device,
|
||||
NpadColor bodyColor,
|
||||
NpadColor buttonColor) : base(device, ControllerStatus.ProController)
|
||||
{
|
||||
_wired = true;
|
||||
|
||||
_bodyColor = bodyColor;
|
||||
_buttonColor = buttonColor;
|
||||
}
|
||||
|
||||
public override void Connect(ControllerId controllerId)
|
||||
{
|
||||
ControllerColorDescription singleColorDesc =
|
||||
ControllerColorDescription.ColorDescriptionColorsNonexistent;
|
||||
|
||||
ControllerColorDescription splitColorDesc = 0;
|
||||
|
||||
ConnectionState = ControllerConnectionState.ControllerStateConnected | ControllerConnectionState.ControllerStateWired;
|
||||
|
||||
Initialize(false,
|
||||
(0, 0),
|
||||
(0, 0),
|
||||
singleColorDesc,
|
||||
splitColorDesc,
|
||||
_bodyColor,
|
||||
_buttonColor);
|
||||
|
||||
base.Connect(controllerId);
|
||||
|
||||
SetLayout(ControllerLayouts.ProController);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public enum BatteryState : int
|
||||
{
|
||||
// TODO : Check if these are the correct states
|
||||
Percent0 = 0,
|
||||
Percent25 = 1,
|
||||
Percent50 = 2,
|
||||
Percent75 = 3,
|
||||
Percent100 = 4
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[Flags]
|
||||
public enum ControllerButtons : long
|
||||
{
|
||||
A = 1 << 0,
|
||||
B = 1 << 1,
|
||||
X = 1 << 2,
|
||||
Y = 1 << 3,
|
||||
StickLeft = 1 << 4,
|
||||
StickRight = 1 << 5,
|
||||
L = 1 << 6,
|
||||
R = 1 << 7,
|
||||
Zl = 1 << 8,
|
||||
Zr = 1 << 9,
|
||||
Plus = 1 << 10,
|
||||
Minus = 1 << 11,
|
||||
DpadLeft = 1 << 12,
|
||||
DpadUp = 1 << 13,
|
||||
DPadRight = 1 << 14,
|
||||
DpadDown = 1 << 15,
|
||||
LStickLeft = 1 << 16,
|
||||
LStickUp = 1 << 17,
|
||||
LStickRight = 1 << 18,
|
||||
LStickDown = 1 << 19,
|
||||
RStickLeft = 1 << 20,
|
||||
RStickUp = 1 << 21,
|
||||
RStickRight = 1 << 22,
|
||||
RStickDown = 1 << 23,
|
||||
Sl = 1 << 24,
|
||||
Sr = 1 << 25
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[Flags]
|
||||
public enum ControllerConnectionState : long
|
||||
{
|
||||
ControllerStateConnected = (1 << 0),
|
||||
ControllerStateWired = (1 << 1)
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct ControllerDeviceState
|
||||
{
|
||||
public ControllerDeviceType DeviceType;
|
||||
public int Padding;
|
||||
public DeviceFlags DeviceFlags;
|
||||
public int UnintendedHomeButtonInputProtectionEnabled;
|
||||
public BatteryState PowerInfo0BatteryState;
|
||||
public BatteryState PowerInfo1BatteryState;
|
||||
public BatteryState PowerInfo2BatteryState;
|
||||
public fixed byte ControllerMac[16];
|
||||
public fixed byte ControllerMac2[16];
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[Flags]
|
||||
public enum ControllerDeviceType : int
|
||||
{
|
||||
ProController = 1 << 0,
|
||||
NPadLeftController = 1 << 4,
|
||||
NPadRightController = 1 << 5,
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ControllerHeader
|
||||
{
|
||||
public ControllerStatus Status;
|
||||
public int IsJoyConHalf;
|
||||
public ControllerColorDescription SingleColorDescription;
|
||||
public NpadColor SingleBodyColor;
|
||||
public NpadColor SingleButtonColor;
|
||||
public ControllerColorDescription SplitColorDescription;
|
||||
public NpadColor RightBodyColor;
|
||||
public NpadColor RightButtonColor;
|
||||
public NpadColor LeftBodyColor;
|
||||
public NpadColor LeftButtonColor;
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public enum ControllerId
|
||||
{
|
||||
ControllerPlayer1 = 0,
|
||||
ControllerPlayer2 = 1,
|
||||
ControllerPlayer3 = 2,
|
||||
ControllerPlayer4 = 3,
|
||||
ControllerPlayer5 = 4,
|
||||
ControllerPlayer6 = 5,
|
||||
ControllerPlayer7 = 6,
|
||||
ControllerPlayer8 = 7,
|
||||
ControllerHandheld = 8,
|
||||
ControllerUnknown = 9
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public enum ControllerLayouts
|
||||
{
|
||||
ProController = 0,
|
||||
HandheldJoined = 1,
|
||||
Joined = 2,
|
||||
Left = 3,
|
||||
Right = 4,
|
||||
MainNoAnalog = 5,
|
||||
Main = 6
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ControllerState
|
||||
{
|
||||
public long SamplesTimestamp;
|
||||
public long SamplesTimestamp2;
|
||||
public ControllerButtons ButtonState;
|
||||
public JoystickPosition LeftStick;
|
||||
public JoystickPosition RightStick;
|
||||
public ControllerConnectionState ConnectionState;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ControllerStateHeader
|
||||
{
|
||||
public long Timestamp;
|
||||
public long EntryCount;
|
||||
public long CurrentEntryIndex;
|
||||
public long MaxEntryCount;
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[Flags]
|
||||
public enum ControllerStatus : int
|
||||
{
|
||||
ProController = 1 << 0,
|
||||
Handheld = 1 << 1,
|
||||
NpadPair = 1 << 2,
|
||||
NpadLeft = 1 << 3,
|
||||
NpadRight = 1 << 4
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[Flags]
|
||||
public enum DeviceFlags : long
|
||||
{
|
||||
PowerInfo0Charging = 1 << 0,
|
||||
PowerInfo1Charging = 1 << 1,
|
||||
PowerInfo2Charging = 1 << 2,
|
||||
PowerInfo0Connected = 1 << 3,
|
||||
PowerInfo1Connected = 1 << 4,
|
||||
PowerInfo2Connected = 1 << 5,
|
||||
UnsupportedButtonPressedNpadSystem = 1 << 9,
|
||||
UnsupportedButtonPressedNpadSystemExt = 1 << 10,
|
||||
AbxyButtonOriented = 1 << 11,
|
||||
SlSrButtonOriented = 1 << 12,
|
||||
PlusButtonCapability = 1 << 13,
|
||||
MinusButtonCapability = 1 << 14,
|
||||
DirectionalButtonsSupported = 1 << 15
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[Flags]
|
||||
public enum HotkeyButtons
|
||||
{
|
||||
ToggleVSync = 1 << 0,
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public enum NpadColor : int //Thanks to CTCaer
|
||||
{
|
||||
Black = 0,
|
||||
|
||||
BodyGrey = 0x828282,
|
||||
BodyNeonBlue = 0x0AB9E6,
|
||||
BodyNeonRed = 0xFF3C28,
|
||||
BodyNeonYellow = 0xE6FF00,
|
||||
BodyNeonPink = 0xFF3278,
|
||||
BodyNeonGreen = 0x1EDC00,
|
||||
BodyRed = 0xE10F00,
|
||||
|
||||
ButtonsGrey = 0x0F0F0F,
|
||||
ButtonsNeonBlue = 0x001E1E,
|
||||
ButtonsNeonRed = 0x1E0A0A,
|
||||
ButtonsNeonYellow = 0x142800,
|
||||
ButtonsNeonPink = 0x28001E,
|
||||
ButtonsNeonGreen = 0x002800,
|
||||
ButtonsRed = 0x280A0A
|
||||
}
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Configuration.Hid;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public partial class Hid
|
||||
{
|
||||
private Switch _device;
|
||||
|
||||
private long _touchScreenOffset;
|
||||
private long _touchEntriesOffset;
|
||||
private long _keyboardOffset;
|
||||
|
||||
private TouchHeader _currentTouchHeader;
|
||||
private KeyboardHeader _currentKeyboardHeader;
|
||||
private KeyboardEntry _currentKeyboardEntry;
|
||||
|
||||
public BaseController PrimaryController { get; private set; }
|
||||
|
||||
internal long HidPosition;
|
||||
|
||||
public Hid(Switch device, long hidPosition)
|
||||
{
|
||||
_device = device;
|
||||
HidPosition = hidPosition;
|
||||
|
||||
device.Memory.FillWithZeros(hidPosition, Horizon.HidSize);
|
||||
|
||||
_currentTouchHeader = new TouchHeader()
|
||||
{
|
||||
CurrentEntryIndex = -1,
|
||||
};
|
||||
|
||||
_currentKeyboardHeader = new KeyboardHeader()
|
||||
{
|
||||
CurrentEntryIndex = -1,
|
||||
};
|
||||
|
||||
_currentKeyboardEntry = new KeyboardEntry()
|
||||
{
|
||||
SamplesTimestamp = -1,
|
||||
SamplesTimestamp2 = -1
|
||||
};
|
||||
|
||||
_touchScreenOffset = HidPosition + HidTouchScreenOffset;
|
||||
_touchEntriesOffset = _touchScreenOffset + HidTouchHeaderSize;
|
||||
_keyboardOffset = HidPosition + HidKeyboardOffset;
|
||||
}
|
||||
|
||||
private static ControllerStatus ConvertControllerTypeToState(ControllerType controllerType)
|
||||
{
|
||||
switch (controllerType)
|
||||
{
|
||||
case ControllerType.Handheld: return ControllerStatus.Handheld;
|
||||
case ControllerType.NpadLeft: return ControllerStatus.NpadLeft;
|
||||
case ControllerType.NpadRight: return ControllerStatus.NpadRight;
|
||||
case ControllerType.NpadPair: return ControllerStatus.NpadPair;
|
||||
case ControllerType.ProController: return ControllerStatus.ProController;
|
||||
default: throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void InitializePrimaryController(ControllerType controllerType)
|
||||
{
|
||||
ControllerId controllerId = controllerType == ControllerType.Handheld ?
|
||||
ControllerId.ControllerHandheld : ControllerId.ControllerPlayer1;
|
||||
|
||||
if (controllerType == ControllerType.ProController)
|
||||
{
|
||||
PrimaryController = new ProController(_device, NpadColor.Black, NpadColor.Black);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrimaryController = new NpadController(ConvertControllerTypeToState(controllerType),
|
||||
_device,
|
||||
(NpadColor.BodyNeonRed, NpadColor.BodyNeonRed),
|
||||
(NpadColor.ButtonsNeonBlue, NpadColor.ButtonsNeonBlue));
|
||||
}
|
||||
|
||||
PrimaryController.Connect(controllerId);
|
||||
}
|
||||
|
||||
public ControllerButtons UpdateStickButtons(
|
||||
JoystickPosition leftStick,
|
||||
JoystickPosition rightStick)
|
||||
{
|
||||
ControllerButtons result = 0;
|
||||
|
||||
if (rightStick.Dx < 0)
|
||||
{
|
||||
result |= ControllerButtons.RStickLeft;
|
||||
}
|
||||
|
||||
if (rightStick.Dx > 0)
|
||||
{
|
||||
result |= ControllerButtons.RStickRight;
|
||||
}
|
||||
|
||||
if (rightStick.Dy < 0)
|
||||
{
|
||||
result |= ControllerButtons.RStickDown;
|
||||
}
|
||||
|
||||
if (rightStick.Dy > 0)
|
||||
{
|
||||
result |= ControllerButtons.RStickUp;
|
||||
}
|
||||
|
||||
if (leftStick.Dx < 0)
|
||||
{
|
||||
result |= ControllerButtons.LStickLeft;
|
||||
}
|
||||
|
||||
if (leftStick.Dx > 0)
|
||||
{
|
||||
result |= ControllerButtons.LStickRight;
|
||||
}
|
||||
|
||||
if (leftStick.Dy < 0)
|
||||
{
|
||||
result |= ControllerButtons.LStickDown;
|
||||
}
|
||||
|
||||
if (leftStick.Dy > 0)
|
||||
{
|
||||
result |= ControllerButtons.LStickUp;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
public void SetTouchPoints(params TouchPoint[] points)
|
||||
{
|
||||
long timestamp = GetTimestamp();
|
||||
long sampleCounter = _currentTouchHeader.SamplesTimestamp + 1;
|
||||
|
||||
var newTouchHeader = new TouchHeader
|
||||
{
|
||||
CurrentEntryIndex = (_currentTouchHeader.CurrentEntryIndex + 1) % HidEntryCount,
|
||||
EntryCount = HidEntryCount,
|
||||
MaxEntries = HidEntryCount - 1,
|
||||
SamplesTimestamp = sampleCounter,
|
||||
Timestamp = timestamp,
|
||||
};
|
||||
|
||||
long currentTouchEntryOffset = _touchEntriesOffset + newTouchHeader.CurrentEntryIndex * HidTouchEntrySize;
|
||||
|
||||
TouchEntry touchEntry = new TouchEntry()
|
||||
{
|
||||
SamplesTimestamp = sampleCounter,
|
||||
TouchCount = points.Length
|
||||
};
|
||||
|
||||
_device.Memory.WriteStruct(currentTouchEntryOffset, touchEntry);
|
||||
|
||||
currentTouchEntryOffset += HidTouchEntryHeaderSize;
|
||||
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
TouchData touch = new TouchData()
|
||||
{
|
||||
Angle = points[i].Angle,
|
||||
DiameterX = points[i].DiameterX,
|
||||
DiameterY = points[i].DiameterY,
|
||||
Index = i,
|
||||
SampleTimestamp = sampleCounter,
|
||||
X = points[i].X,
|
||||
Y = points[i].Y
|
||||
};
|
||||
|
||||
_device.Memory.WriteStruct(currentTouchEntryOffset, touch);
|
||||
|
||||
currentTouchEntryOffset += HidTouchEntryTouchSize;
|
||||
}
|
||||
|
||||
_device.Memory.WriteStruct(_touchScreenOffset, newTouchHeader);
|
||||
|
||||
_currentTouchHeader = newTouchHeader;
|
||||
}
|
||||
|
||||
public unsafe void WriteKeyboard(Keyboard keyboard)
|
||||
{
|
||||
long timestamp = GetTimestamp();
|
||||
|
||||
var newKeyboardHeader = new KeyboardHeader()
|
||||
{
|
||||
CurrentEntryIndex = (_currentKeyboardHeader.CurrentEntryIndex + 1) % HidEntryCount,
|
||||
EntryCount = HidEntryCount,
|
||||
MaxEntries = HidEntryCount - 1,
|
||||
Timestamp = timestamp,
|
||||
};
|
||||
|
||||
_device.Memory.WriteStruct(_keyboardOffset, newKeyboardHeader);
|
||||
|
||||
long keyboardEntryOffset = _keyboardOffset + HidKeyboardHeaderSize;
|
||||
keyboardEntryOffset += newKeyboardHeader.CurrentEntryIndex * HidKeyboardEntrySize;
|
||||
|
||||
var newkeyboardEntry = new KeyboardEntry()
|
||||
{
|
||||
SamplesTimestamp = _currentKeyboardEntry.SamplesTimestamp + 1,
|
||||
SamplesTimestamp2 = _currentKeyboardEntry.SamplesTimestamp2 + 1,
|
||||
Keys = keyboard.Keys,
|
||||
Modifier = keyboard.Modifier,
|
||||
};
|
||||
|
||||
_device.Memory.WriteStruct(keyboardEntryOffset, newkeyboardEntry);
|
||||
|
||||
_currentKeyboardEntry = newkeyboardEntry;
|
||||
_currentKeyboardHeader = newKeyboardHeader;
|
||||
}
|
||||
|
||||
internal static long GetTimestamp()
|
||||
{
|
||||
return PerformanceCounter.ElapsedMilliseconds * 19200;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public partial class Hid
|
||||
{
|
||||
/*
|
||||
* Reference:
|
||||
* https://github.com/reswitched/libtransistor/blob/development/lib/hid.c
|
||||
* https://github.com/reswitched/libtransistor/blob/development/include/libtransistor/hid.h
|
||||
* https://github.com/switchbrew/libnx/blob/master/nx/source/services/hid.c
|
||||
* https://github.com/switchbrew/libnx/blob/master/nx/include/switch/services/hid.h
|
||||
*/
|
||||
|
||||
internal const int HidHeaderSize = 0x400;
|
||||
internal const int HidTouchScreenSize = 0x3000;
|
||||
internal const int HidMouseSize = 0x400;
|
||||
internal const int HidKeyboardSize = 0x400;
|
||||
internal const int HidUnkSection1Size = 0x400;
|
||||
internal const int HidUnkSection2Size = 0x400;
|
||||
internal const int HidUnkSection3Size = 0x400;
|
||||
internal const int HidUnkSection4Size = 0x400;
|
||||
internal const int HidUnkSection5Size = 0x200;
|
||||
internal const int HidUnkSection6Size = 0x200;
|
||||
internal const int HidUnkSection7Size = 0x200;
|
||||
internal const int HidUnkSection8Size = 0x800;
|
||||
internal const int HidControllerSerialsSize = 0x4000;
|
||||
internal const int HidControllersSize = 0x32000;
|
||||
internal const int HidUnkSection9Size = 0x800;
|
||||
|
||||
internal const int HidKeyboardHeaderSize = 0x20;
|
||||
internal const int HidKeyboardEntrySize = 0x38;
|
||||
|
||||
internal const int HidTouchHeaderSize = 0x28;
|
||||
internal const int HidTouchEntrySize = 0x298;
|
||||
|
||||
internal const int HidTouchEntryHeaderSize = 0x10;
|
||||
internal const int HidTouchEntryTouchSize = 0x28;
|
||||
|
||||
internal const int HidControllerSize = 0x5000;
|
||||
internal const int HidControllerHeaderSize = 0x28;
|
||||
internal const int HidControllerLayoutsSize = 0x350;
|
||||
|
||||
internal const int HidControllersLayoutHeaderSize = 0x20;
|
||||
internal const int HidControllersInputEntrySize = 0x30;
|
||||
|
||||
internal const int HidHeaderOffset = 0;
|
||||
internal const int HidTouchScreenOffset = HidHeaderOffset + HidHeaderSize;
|
||||
internal const int HidMouseOffset = HidTouchScreenOffset + HidTouchScreenSize;
|
||||
internal const int HidKeyboardOffset = HidMouseOffset + HidMouseSize;
|
||||
internal const int HidUnkSection1Offset = HidKeyboardOffset + HidKeyboardSize;
|
||||
internal const int HidUnkSection2Offset = HidUnkSection1Offset + HidUnkSection1Size;
|
||||
internal const int HidUnkSection3Offset = HidUnkSection2Offset + HidUnkSection2Size;
|
||||
internal const int HidUnkSection4Offset = HidUnkSection3Offset + HidUnkSection3Size;
|
||||
internal const int HidUnkSection5Offset = HidUnkSection4Offset + HidUnkSection4Size;
|
||||
internal const int HidUnkSection6Offset = HidUnkSection5Offset + HidUnkSection5Size;
|
||||
internal const int HidUnkSection7Offset = HidUnkSection6Offset + HidUnkSection6Size;
|
||||
internal const int HidUnkSection8Offset = HidUnkSection7Offset + HidUnkSection7Size;
|
||||
internal const int HidControllerSerialsOffset = HidUnkSection8Offset + HidUnkSection8Size;
|
||||
internal const int HidControllersOffset = HidControllerSerialsOffset + HidControllerSerialsSize;
|
||||
internal const int HidUnkSection9Offset = HidControllersOffset + HidControllersSize;
|
||||
|
||||
internal const int HidEntryCount = 17;
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
interface IHidDevice
|
||||
{
|
||||
long Offset { get; }
|
||||
bool Connected { get; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public struct Keyboard
|
||||
{
|
||||
public int Modifier;
|
||||
public int[] Keys;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct KeyboardEntry
|
||||
{
|
||||
public long SamplesTimestamp;
|
||||
public long SamplesTimestamp2;
|
||||
public long Modifier;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray , SizeConst = 0x8)]
|
||||
public int[] Keys;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct KeyboardHeader
|
||||
{
|
||||
public long Timestamp;
|
||||
public long EntryCount;
|
||||
public long CurrentEntryIndex;
|
||||
public long MaxEntries;
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct TouchData
|
||||
{
|
||||
public long SampleTimestamp;
|
||||
public int Padding;
|
||||
public int Index;
|
||||
public int X;
|
||||
public int Y;
|
||||
public int DiameterX;
|
||||
public int DiameterY;
|
||||
public int Angle;
|
||||
public int Padding2;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct TouchEntry
|
||||
{
|
||||
public long SamplesTimestamp;
|
||||
public long TouchCount;
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct TouchHeader
|
||||
{
|
||||
public long Timestamp;
|
||||
public long EntryCount;
|
||||
public long CurrentEntryIndex;
|
||||
public long MaxEntries;
|
||||
public long SamplesTimestamp;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public struct TouchPoint
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
public int DiameterX;
|
||||
public int DiameterY;
|
||||
public int Angle;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue