mirror of
https://github.com/GreemDev/Ryujinx.git
synced 2024-12-23 16:15:47 +00:00
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 ARMeilleure.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE
|
namespace Ryujinx.HLE
|
||||||
{
|
{
|
||||||
|
@ -64,6 +65,11 @@ namespace Ryujinx.HLE
|
||||||
return Marshal.PtrToStructure<T>((IntPtr)(_ramPtr + position));
|
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)
|
public void WriteSByte(long position, sbyte value)
|
||||||
{
|
{
|
||||||
WriteByte(position, (byte)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>
|
_appletMapping = new Dictionary<AppletId, Type>
|
||||||
{
|
{
|
||||||
{ AppletId.PlayerSelect, typeof(PlayerSelectApplet) },
|
{ AppletId.PlayerSelect, typeof(PlayerSelectApplet) },
|
||||||
|
{ AppletId.Controller, typeof(ControllerApplet) },
|
||||||
{ AppletId.SoftwareKeyboard, typeof(SoftwareKeyboardApplet) }
|
{ 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 Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Applets
|
namespace Ryujinx.HLE.HOS.Applets
|
||||||
{
|
{
|
||||||
|
@ -11,5 +12,10 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||||
AppletSession interactiveSession);
|
AppletSession interactiveSession);
|
||||||
|
|
||||||
ResultCode GetResult();
|
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 keyboardConfig = _normalSession.Pop();
|
||||||
var transferMemory = _normalSession.Pop();
|
var transferMemory = _normalSession.Pop();
|
||||||
|
|
||||||
_keyboardConfig = ReadStruct<SoftwareKeyboardConfig>(keyboardConfig);
|
_keyboardConfig = IApplet.ReadStruct<SoftwareKeyboardConfig>(keyboardConfig);
|
||||||
|
|
||||||
if (_keyboardConfig.UseUtf8)
|
if (_keyboardConfig.UseUtf8)
|
||||||
{
|
{
|
||||||
|
@ -176,20 +176,5 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||||
return stream.ToArray();
|
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
|
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
|
namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
|
||||||
{
|
{
|
||||||
static class HidUtils
|
static class HidUtils
|
||||||
{
|
{
|
||||||
public static ControllerId GetIndexFromNpadIdType(HidNpadIdType npadIdType)
|
public static PlayerIndex GetIndexFromNpadIdType(NpadIdType npadIdType)
|
||||||
|
=> npadIdType switch
|
||||||
{
|
{
|
||||||
switch (npadIdType)
|
NpadIdType.Player1 => PlayerIndex.Player1,
|
||||||
{
|
NpadIdType.Player2 => PlayerIndex.Player2,
|
||||||
case HidNpadIdType.Player1: return ControllerId.ControllerPlayer1;
|
NpadIdType.Player3 => PlayerIndex.Player3,
|
||||||
case HidNpadIdType.Player2: return ControllerId.ControllerPlayer2;
|
NpadIdType.Player4 => PlayerIndex.Player4,
|
||||||
case HidNpadIdType.Player3: return ControllerId.ControllerPlayer3;
|
NpadIdType.Player5 => PlayerIndex.Player5,
|
||||||
case HidNpadIdType.Player4: return ControllerId.ControllerPlayer4;
|
NpadIdType.Player6 => PlayerIndex.Player6,
|
||||||
case HidNpadIdType.Player5: return ControllerId.ControllerPlayer5;
|
NpadIdType.Player7 => PlayerIndex.Player7,
|
||||||
case HidNpadIdType.Player6: return ControllerId.ControllerPlayer6;
|
NpadIdType.Player8 => PlayerIndex.Player8,
|
||||||
case HidNpadIdType.Player7: return ControllerId.ControllerPlayer7;
|
NpadIdType.Handheld => PlayerIndex.Handheld,
|
||||||
case HidNpadIdType.Player8: return ControllerId.ControllerPlayer8;
|
NpadIdType.Unknown => PlayerIndex.Unknown,
|
||||||
case HidNpadIdType.Handheld: return ControllerId.ControllerHandheld;
|
_ => throw new ArgumentOutOfRangeException(nameof(npadIdType))
|
||||||
case HidNpadIdType.Unknown: return ControllerId.ControllerUnknown;
|
};
|
||||||
|
|
||||||
default: throw new ArgumentOutOfRangeException(nameof(npadIdType));
|
public static NpadIdType GetNpadIdTypeFromIndex(PlayerIndex index)
|
||||||
}
|
=> index switch
|
||||||
}
|
|
||||||
|
|
||||||
public static HidNpadIdType GetNpadIdTypeFromIndex(ControllerId index)
|
|
||||||
{
|
{
|
||||||
switch (index)
|
PlayerIndex.Player1 => NpadIdType.Player1,
|
||||||
{
|
PlayerIndex.Player2 => NpadIdType.Player2,
|
||||||
case ControllerId.ControllerPlayer1: return HidNpadIdType.Player1;
|
PlayerIndex.Player3 => NpadIdType.Player3,
|
||||||
case ControllerId.ControllerPlayer2: return HidNpadIdType.Player2;
|
PlayerIndex.Player4 => NpadIdType.Player4,
|
||||||
case ControllerId.ControllerPlayer3: return HidNpadIdType.Player3;
|
PlayerIndex.Player5 => NpadIdType.Player5,
|
||||||
case ControllerId.ControllerPlayer4: return HidNpadIdType.Player4;
|
PlayerIndex.Player6 => NpadIdType.Player6,
|
||||||
case ControllerId.ControllerPlayer5: return HidNpadIdType.Player5;
|
PlayerIndex.Player7 => NpadIdType.Player7,
|
||||||
case ControllerId.ControllerPlayer6: return HidNpadIdType.Player6;
|
PlayerIndex.Player8 => NpadIdType.Player8,
|
||||||
case ControllerId.ControllerPlayer7: return HidNpadIdType.Player7;
|
PlayerIndex.Handheld => NpadIdType.Handheld,
|
||||||
case ControllerId.ControllerPlayer8: return HidNpadIdType.Player8;
|
PlayerIndex.Unknown => NpadIdType.Unknown,
|
||||||
case ControllerId.ControllerHandheld: return HidNpadIdType.Handheld;
|
_ => throw new ArgumentOutOfRangeException(nameof(index))
|
||||||
case ControllerId.ControllerUnknown: return HidNpadIdType.Unknown;
|
};
|
||||||
|
|
||||||
default: 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.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
|
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
|
||||||
using Ryujinx.HLE.Input;
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
|
@ -11,7 +10,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
[Service("hid")]
|
[Service("hid")]
|
||||||
class IHidServer : IpcService
|
class IHidServer : IpcService
|
||||||
{
|
{
|
||||||
private KEvent _npadStyleSetUpdateEvent;
|
|
||||||
private KEvent _xpadIdEvent;
|
private KEvent _xpadIdEvent;
|
||||||
private KEvent _palmaOperationCompleteEvent;
|
private KEvent _palmaOperationCompleteEvent;
|
||||||
|
|
||||||
|
@ -22,8 +20,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
private bool _vibrationPermitted;
|
private bool _vibrationPermitted;
|
||||||
private bool _usbFullKeyControllerEnabled;
|
private bool _usbFullKeyControllerEnabled;
|
||||||
|
|
||||||
private HidNpadJoyHoldType _npadJoyHoldType;
|
|
||||||
private HidNpadStyle _npadStyleSet;
|
|
||||||
private HidNpadJoyAssignmentMode _npadJoyAssignmentMode;
|
private HidNpadJoyAssignmentMode _npadJoyAssignmentMode;
|
||||||
private HidNpadHandheldActivationMode _npadHandheldActivationMode;
|
private HidNpadHandheldActivationMode _npadHandheldActivationMode;
|
||||||
private HidGyroscopeZeroDriftMode _gyroscopeZeroDriftMode;
|
private HidGyroscopeZeroDriftMode _gyroscopeZeroDriftMode;
|
||||||
|
@ -39,12 +35,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
|
|
||||||
public IHidServer(ServiceCtx context)
|
public IHidServer(ServiceCtx context)
|
||||||
{
|
{
|
||||||
_npadStyleSetUpdateEvent = new KEvent(context.Device.System);
|
|
||||||
_xpadIdEvent = new KEvent(context.Device.System);
|
_xpadIdEvent = new KEvent(context.Device.System);
|
||||||
_palmaOperationCompleteEvent = 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;
|
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Dual;
|
||||||
_npadHandheldActivationMode = HidNpadHandheldActivationMode.Dual;
|
_npadHandheldActivationMode = HidNpadHandheldActivationMode.Dual;
|
||||||
_gyroscopeZeroDriftMode = HidGyroscopeZeroDriftMode.Standard;
|
_gyroscopeZeroDriftMode = HidGyroscopeZeroDriftMode.Standard;
|
||||||
|
@ -85,6 +78,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
{
|
{
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
context.Device.Hid.Touchscreen.Active = true;
|
||||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
|
@ -96,6 +90,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
{
|
{
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
context.Device.Hid.Mouse.Active = true;
|
||||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
|
@ -107,6 +102,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
{
|
{
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
context.Device.Hid.Keyboard.Active = true;
|
||||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
|
@ -542,13 +538,15 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
// SetSupportedNpadStyleSet(nn::applet::AppletResourceUserId, nn::hid::NpadStyleTag)
|
// SetSupportedNpadStyleSet(nn::applet::AppletResourceUserId, nn::hid::NpadStyleTag)
|
||||||
public ResultCode SetSupportedNpadStyleSet(ServiceCtx context)
|
public ResultCode SetSupportedNpadStyleSet(ServiceCtx context)
|
||||||
{
|
{
|
||||||
_npadStyleSet = (HidNpadStyle)context.RequestData.ReadInt32();
|
ControllerType type = (ControllerType)context.RequestData.ReadInt32();
|
||||||
|
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -559,9 +557,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
{
|
{
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -571,9 +572,16 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
public ResultCode SetSupportedNpadIdType(ServiceCtx context)
|
public ResultCode SetSupportedNpadIdType(ServiceCtx context)
|
||||||
{
|
{
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -584,6 +592,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
{
|
{
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
context.Device.Hid.Npads.Active = true;
|
||||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
|
@ -595,6 +604,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
{
|
{
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
context.Device.Hid.Npads.Active = false;
|
||||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
|
@ -604,11 +614,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
// AcquireNpadStyleSetUpdateEventHandle(nn::applet::AppletResourceUserId, uint, ulong) -> nn::sf::NativeHandle
|
// AcquireNpadStyleSetUpdateEventHandle(nn::applet::AppletResourceUserId, uint, ulong) -> nn::sf::NativeHandle
|
||||||
public ResultCode AcquireNpadStyleSetUpdateEventHandle(ServiceCtx context)
|
public ResultCode AcquireNpadStyleSetUpdateEventHandle(ServiceCtx context)
|
||||||
{
|
{
|
||||||
|
PlayerIndex npadId = HidUtils.GetIndexFromNpadIdType((NpadIdType)context.RequestData.ReadInt32());
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
int npadId = context.RequestData.ReadInt32();
|
|
||||||
long npadStyleSet = context.RequestData.ReadInt64();
|
long npadStyleSet = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
if (context.Process.HandleTable.GenerateHandle(_npadStyleSetUpdateEvent.ReadableEvent, out int handle) != KernelResult.Success)
|
KEvent evnt = context.Device.Hid.Npads.GetStyleSetUpdateEvent(npadId);
|
||||||
|
if (context.Process.HandleTable.GenerateHandle(evnt.ReadableEvent, out int handle) != KernelResult.Success)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Out of handles!");
|
throw new InvalidOperationException("Out of handles!");
|
||||||
}
|
}
|
||||||
|
@ -624,8 +635,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
// DisconnectNpad(nn::applet::AppletResourceUserId, uint NpadIdType)
|
// DisconnectNpad(nn::applet::AppletResourceUserId, uint NpadIdType)
|
||||||
public ResultCode DisconnectNpad(ServiceCtx context)
|
public ResultCode DisconnectNpad(ServiceCtx context)
|
||||||
{
|
{
|
||||||
|
NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadInt32();
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
int npadIdType = context.RequestData.ReadInt32();
|
|
||||||
|
|
||||||
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, npadIdType });
|
Logger.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, npadIdType });
|
||||||
|
|
||||||
|
@ -651,10 +662,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
// ActivateNpadWithRevision(nn::applet::AppletResourceUserId, int Unknown)
|
// ActivateNpadWithRevision(nn::applet::AppletResourceUserId, int Unknown)
|
||||||
public ResultCode ActivateNpadWithRevision(ServiceCtx context)
|
public ResultCode ActivateNpadWithRevision(ServiceCtx context)
|
||||||
{
|
{
|
||||||
|
int revision = context.RequestData.ReadInt32();
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -664,9 +675,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
public ResultCode SetNpadJoyHoldType(ServiceCtx context)
|
public ResultCode SetNpadJoyHoldType(ServiceCtx context)
|
||||||
{
|
{
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -677,9 +691,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
{
|
{
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
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;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -688,7 +705,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
// SetNpadJoyAssignmentModeSingleByDefault(uint HidControllerId, nn::applet::AppletResourceUserId)
|
// SetNpadJoyAssignmentModeSingleByDefault(uint HidControllerId, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx context)
|
public ResultCode SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32();
|
PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32();
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Single;
|
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Single;
|
||||||
|
@ -702,7 +719,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
// SetNpadJoyAssignmentModeSingle(uint HidControllerId, nn::applet::AppletResourceUserId, long HidNpadJoyDeviceType)
|
// SetNpadJoyAssignmentModeSingle(uint HidControllerId, nn::applet::AppletResourceUserId, long HidNpadJoyDeviceType)
|
||||||
public ResultCode SetNpadJoyAssignmentModeSingle(ServiceCtx context)
|
public ResultCode SetNpadJoyAssignmentModeSingle(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32();
|
PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32();
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)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)
|
// SetNpadJoyAssignmentModeDual(uint HidControllerId, nn::applet::AppletResourceUserId)
|
||||||
public ResultCode SetNpadJoyAssignmentModeDual(ServiceCtx context)
|
public ResultCode SetNpadJoyAssignmentModeDual(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32();
|
PlayerIndex hidControllerId = HidUtils.GetIndexFromNpadIdType((NpadIdType)context.RequestData.ReadInt32());
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Dual;
|
_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
|
// SetNpadJoyAssignmentModeSingleWithDestination(uint HidControllerId, long HidNpadJoyDeviceType, nn::applet::AppletResourceUserId) -> bool Unknown0, uint Unknown1
|
||||||
public ResultCode SetNpadJoyAssignmentModeSingleWithDestination(ServiceCtx context)
|
public ResultCode SetNpadJoyAssignmentModeSingleWithDestination(ServiceCtx context)
|
||||||
{
|
{
|
||||||
ControllerId hidControllerId = (ControllerId)context.RequestData.ReadInt32();
|
PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32();
|
||||||
HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)context.RequestData.ReadInt64();
|
HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)context.RequestData.ReadInt64();
|
||||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
|
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
|
||||||
using Ryujinx.HLE.Input;
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Hid.Irs
|
namespace Ryujinx.HLE.HOS.Services.Hid.Irs
|
||||||
|
@ -57,16 +56,16 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Irs
|
||||||
// GetNpadIrCameraHandle(u32) -> nn::irsensor::IrCameraHandle
|
// GetNpadIrCameraHandle(u32) -> nn::irsensor::IrCameraHandle
|
||||||
public ResultCode GetNpadIrCameraHandle(ServiceCtx context)
|
public ResultCode GetNpadIrCameraHandle(ServiceCtx context)
|
||||||
{
|
{
|
||||||
HidNpadIdType npadIdType = (HidNpadIdType)context.RequestData.ReadUInt32();
|
NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadUInt32();
|
||||||
|
|
||||||
if (npadIdType > HidNpadIdType.Player8 &&
|
if (npadIdType > NpadIdType.Player8 &&
|
||||||
npadIdType != HidNpadIdType.Unknown &&
|
npadIdType != NpadIdType.Unknown &&
|
||||||
npadIdType != HidNpadIdType.Handheld)
|
npadIdType != NpadIdType.Handheld)
|
||||||
{
|
{
|
||||||
return ResultCode.NpadIdOutOfRange;
|
return ResultCode.NpadIdOutOfRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerId irCameraHandle = HidUtils.GetIndexFromNpadIdType(npadIdType);
|
PlayerIndex irCameraHandle = HidUtils.GetIndexFromNpadIdType(npadIdType);
|
||||||
|
|
||||||
context.ResponseData.Write((int)irCameraHandle);
|
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
|
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
{
|
{
|
||||||
public enum HidNpadIdType
|
public enum NpadIdType
|
||||||
{
|
{
|
||||||
Player1 = 0,
|
Player1 = 0,
|
||||||
Player2 = 1,
|
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;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Input
|
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
{
|
{
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum ControllerColorDescription : int
|
enum NpadColorDescription : int
|
||||||
{
|
{
|
||||||
ColorDescriptionColorsNonexistent = (1 << 1)
|
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.
|
// TODO: When we will be able to add multiple controllers add one entry by controller here.
|
||||||
Device device1 = new Device
|
Device device1 = new Device
|
||||||
{
|
{
|
||||||
NpadIdType = HidNpadIdType.Player1,
|
NpadIdType = NpadIdType.Player1,
|
||||||
Handle = HidUtils.GetIndexFromNpadIdType(HidNpadIdType.Player1),
|
Handle = HidUtils.GetIndexFromNpadIdType(NpadIdType.Player1),
|
||||||
State = DeviceState.Initialized
|
State = DeviceState.Initialized
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid;
|
using Ryujinx.HLE.HOS.Services.Hid;
|
||||||
using Ryujinx.HLE.Input;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.UserManager
|
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 DeviceState State = DeviceState.Unavailable;
|
||||||
|
|
||||||
public ControllerId Handle;
|
public PlayerIndex Handle;
|
||||||
public HidNpadIdType NpadIdType;
|
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