HID Implementation (#20)

* Basic HID Implementation

* Basic HID Implementation in Config

* HID Corrections

* HID Corrections 2
This commit is contained in:
Ac_K 2018-02-18 00:54:19 +01:00 committed by gdkchan
parent 595e7ee588
commit f469b968a8
12 changed files with 758 additions and 75 deletions

View File

@ -16,6 +16,8 @@ namespace Ryujinx
public static bool LoggingEnableFatal { get; private set; } public static bool LoggingEnableFatal { get; private set; }
public static bool LoggingEnableLogFile { get; private set; } public static bool LoggingEnableLogFile { get; private set; }
public static JoyCon FakeJoyCon { get; private set; }
public static void Read() public static void Read()
{ {
IniParser Parser = new IniParser(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Ryujinx.conf")); IniParser Parser = new IniParser(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Ryujinx.conf"));
@ -27,6 +29,41 @@ namespace Ryujinx
LoggingEnableError = Convert.ToBoolean(Parser.Value("Logging_Enable_Error")); LoggingEnableError = Convert.ToBoolean(Parser.Value("Logging_Enable_Error"));
LoggingEnableFatal = Convert.ToBoolean(Parser.Value("Logging_Enable_Fatal")); LoggingEnableFatal = Convert.ToBoolean(Parser.Value("Logging_Enable_Fatal"));
LoggingEnableLogFile = Convert.ToBoolean(Parser.Value("Logging_Enable_LogFile")); LoggingEnableLogFile = Convert.ToBoolean(Parser.Value("Logging_Enable_LogFile"));
FakeJoyCon = new JoyCon
{
Left = new JoyConLeft
{
StickUp = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Up")),
StickDown = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Down")),
StickLeft = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Left")),
StickRight = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Right")),
StickButton = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Stick_Button")),
DPadUp = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Up")),
DPadDown = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Down")),
DPadLeft = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Left")),
DPadRight = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_DPad_Right")),
ButtonMinus = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_Minus")),
ButtonL = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_L")),
ButtonZL = Convert.ToInt16(Parser.Value("Controls_Left_FakeJoycon_Button_ZL"))
},
Right = new JoyConRight
{
StickUp = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Up")),
StickDown = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Down")),
StickLeft = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Left")),
StickRight = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Right")),
StickButton = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Stick_Button")),
ButtonA = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_A")),
ButtonB = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_B")),
ButtonX = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_X")),
ButtonY = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_Y")),
ButtonPlus = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_Plus")),
ButtonR = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_R")),
ButtonZR = Convert.ToInt16(Parser.Value("Controls_Right_FakeJoycon_Button_ZR"))
}
};
} }
} }

185
Ryujinx/Hid.cs Normal file
View File

@ -0,0 +1,185 @@
using Ryujinx.OsHle;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx
{
public class Hid
{
/*
Thanks to:
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
struct HidSharedMemory
{
header[0x400];
touchscreen[0x3000];
mouse[0x400];
keyboard[0x400];
unkSection1[0x400];
unkSection2[0x400];
unkSection3[0x400];
unkSection4[0x400];
unkSection5[0x200];
unkSection6[0x200];
unkSection7[0x200];
unkSection8[0x800];
controllerSerials[0x4000];
controllers[0x5000 * 10];
unkSection9[0x4600];
}
*/
private const int Hid_Num_Entries = 16;
private Switch Ns;
private long SharedMemOffset;
public Hid(Switch Ns)
{
this.Ns = Ns;
}
public void Init(long HidOffset)
{
unsafe
{
if (HidOffset == 0 || HidOffset + Horizon.HidSize > uint.MaxValue)
{
return;
}
SharedMemOffset = HidOffset;
uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader));
IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
HidTouchScreen TouchScreen = new HidTouchScreen();
TouchScreen.Header.TimestampTicks = (ulong)Environment.TickCount;
TouchScreen.Header.NumEntries = (ulong)Hid_Num_Entries;
TouchScreen.Header.LatestEntry = 0;
TouchScreen.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1;
TouchScreen.Header.Timestamp = (ulong)Environment.TickCount;
//TODO: Write this structure when the input is implemented
//Marshal.StructureToPtr(TouchScreen, HidPtr, false);
InnerOffset += (uint)Marshal.SizeOf(typeof(HidTouchScreen));
HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
HidMouse Mouse = new HidMouse();
Mouse.Header.TimestampTicks = (ulong)Environment.TickCount;
Mouse.Header.NumEntries = (ulong)Hid_Num_Entries;
Mouse.Header.LatestEntry = 0;
Mouse.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1;
//TODO: Write this structure when the input is implemented
//Marshal.StructureToPtr(Mouse, HidPtr, false);
InnerOffset += (uint)Marshal.SizeOf(typeof(HidMouse));
HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
HidKeyboard Keyboard = new HidKeyboard();
Keyboard.Header.TimestampTicks = (ulong)Environment.TickCount;
Keyboard.Header.NumEntries = (ulong)Hid_Num_Entries;
Keyboard.Header.LatestEntry = 0;
Keyboard.Header.MaxEntryIndex = (ulong)Hid_Num_Entries - 1;
//TODO: Write this structure when the input is implemented
//Marshal.StructureToPtr(Keyboard, HidPtr, false);
InnerOffset += (uint)Marshal.SizeOf(typeof(HidKeyboard)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection1)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection2)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection3)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection4)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection5)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection6)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection7)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection8)) +
(uint)Marshal.SizeOf(typeof(HidControllerSerials));
//Increase the loop to initialize more controller.
for (int i = 8; i < Enum.GetNames(typeof(HidControllerID)).Length - 1; i++)
{
HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset + (uint)(Marshal.SizeOf(typeof(HidController)) * i));
HidController Controller = new HidController();
Controller.Header.Type = (uint)(HidControllerType.ControllerType_Handheld | HidControllerType.ControllerType_JoyconPair);
Controller.Header.IsHalf = 0;
Controller.Header.SingleColorsDescriptor = (uint)(HidControllerColorDescription.ColorDesc_ColorsNonexistent);
Controller.Header.SingleColorBody = 0;
Controller.Header.SingleColorButtons = 0;
Controller.Header.SplitColorsDescriptor = 0;
Controller.Header.LeftColorBody = (uint)JoyConColor.Body_Neon_Red;
Controller.Header.LeftColorButtons = (uint)JoyConColor.Buttons_Neon_Red;
Controller.Header.RightColorBody = (uint)JoyConColor.Body_Neon_Blue;
Controller.Header.RightColorButtons = (uint)JoyConColor.Buttons_Neon_Blue;
Controller.Layouts = new HidControllerLayout[Enum.GetNames(typeof(HidControllerLayouts)).Length];
Controller.Layouts[(int)HidControllerLayouts.Main] = new HidControllerLayout();
Controller.Layouts[(int)HidControllerLayouts.Main].Header.LatestEntry = (ulong)Hid_Num_Entries;
Marshal.StructureToPtr(Controller, HidPtr, false);
}
Logging.Info("HID Initialized!");
}
}
public void SendControllerButtons(HidControllerID ControllerId,
HidControllerLayouts Layout,
HidControllerKeys Buttons,
JoystickPosition LeftJoystick,
JoystickPosition RightJoystick)
{
uint InnerOffset = (uint)Marshal.SizeOf(typeof(HidSharedMemHeader)) +
(uint)Marshal.SizeOf(typeof(HidTouchScreen)) +
(uint)Marshal.SizeOf(typeof(HidMouse)) +
(uint)Marshal.SizeOf(typeof(HidKeyboard)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection1)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection2)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection3)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection4)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection5)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection6)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection7)) +
(uint)Marshal.SizeOf(typeof(HidUnknownSection8)) +
(uint)Marshal.SizeOf(typeof(HidControllerSerials)) +
((uint)(Marshal.SizeOf(typeof(HidController)) * (int)ControllerId)) +
(uint)Marshal.SizeOf(typeof(HidControllerHeader)) +
(uint)Layout * (uint)Marshal.SizeOf(typeof(HidControllerLayout));
IntPtr HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
HidControllerLayoutHeader OldControllerHeaderLayout = (HidControllerLayoutHeader)Marshal.PtrToStructure(HidPtr, typeof(HidControllerLayoutHeader));
HidControllerLayoutHeader ControllerLayoutHeader = new HidControllerLayoutHeader
{
TimestampTicks = (ulong)Environment.TickCount,
NumEntries = (ulong)Hid_Num_Entries,
MaxEntryIndex = (ulong)Hid_Num_Entries - 1,
LatestEntry = (OldControllerHeaderLayout.LatestEntry < (ulong)Hid_Num_Entries ? OldControllerHeaderLayout.LatestEntry + 1 : 0)
};
Marshal.StructureToPtr(ControllerLayoutHeader, HidPtr, false);
InnerOffset += (uint)Marshal.SizeOf(typeof(HidControllerLayoutHeader)) + (uint)((uint)(ControllerLayoutHeader.LatestEntry) * Marshal.SizeOf(typeof(HidControllerInputEntry)));
HidPtr = new IntPtr(Ns.Ram.ToInt64() + (uint)SharedMemOffset + InnerOffset);
HidControllerInputEntry ControllerInputEntry = new HidControllerInputEntry();
ControllerInputEntry.Timestamp = (ulong)Environment.TickCount;
ControllerInputEntry.Timestamp_2 = (ulong)Environment.TickCount;
ControllerInputEntry.Buttons = (ulong)Buttons;
ControllerInputEntry.Joysticks = new JoystickPosition[(int)HidControllerJoystick.Joystick_Num_Sticks];
ControllerInputEntry.Joysticks[(int)HidControllerJoystick.Joystick_Left] = LeftJoystick;
ControllerInputEntry.Joysticks[(int)HidControllerJoystick.Joystick_Right] = RightJoystick;
ControllerInputEntry.ConnectionState = (ulong)(HidControllerConnectionState.Controller_State_Connected | HidControllerConnectionState.Controller_State_Wired);
Marshal.StructureToPtr(ControllerInputEntry, HidPtr, false);
}
}
}

View File

@ -0,0 +1,184 @@
using System.Runtime.InteropServices;
namespace Ryujinx
{
public enum HidControllerKeys
{
KEY_A = (1 << 0),
KEY_B = (1 << 1),
KEY_X = (1 << 2),
KEY_Y = (1 << 3),
KEY_LSTICK = (1 << 4),
KEY_RSTICK = (1 << 5),
KEY_L = (1 << 6),
KEY_R = (1 << 7),
KEY_ZL = (1 << 8),
KEY_ZR = (1 << 9),
KEY_PLUS = (1 << 10),
KEY_MINUS = (1 << 11),
KEY_DLEFT = (1 << 12),
KEY_DUP = (1 << 13),
KEY_DRIGHT = (1 << 14),
KEY_DDOWN = (1 << 15),
KEY_LSTICK_LEFT = (1 << 16),
KEY_LSTICK_UP = (1 << 17),
KEY_LSTICK_RIGHT = (1 << 18),
KEY_LSTICK_DOWN = (1 << 19),
KEY_RSTICK_LEFT = (1 << 20),
KEY_RSTICK_UP = (1 << 21),
KEY_RSTICK_RIGHT = (1 << 22),
KEY_RSTICK_DOWN = (1 << 23),
KEY_SL = (1 << 24),
KEY_SR = (1 << 25),
// Pseudo-key for at least one finger on the touch screen
KEY_TOUCH = (1 << 26),
// Buttons by orientation (for single Joy-Con), also works with Joy-Con pairs, Pro Controller
KEY_JOYCON_RIGHT = (1 << 0),
KEY_JOYCON_DOWN = (1 << 1),
KEY_JOYCON_UP = (1 << 2),
KEY_JOYCON_LEFT = (1 << 3),
// Generic catch-all directions, also works for single Joy-Con
KEY_UP = KEY_DUP | KEY_LSTICK_UP | KEY_RSTICK_UP,
KEY_DOWN = KEY_DDOWN | KEY_LSTICK_DOWN | KEY_RSTICK_DOWN,
KEY_LEFT = KEY_DLEFT | KEY_LSTICK_LEFT | KEY_RSTICK_LEFT,
KEY_RIGHT = KEY_DRIGHT | KEY_LSTICK_RIGHT | KEY_RSTICK_RIGHT,
}
public enum HidControllerID
{
CONTROLLER_PLAYER_1 = 0,
CONTROLLER_PLAYER_2 = 1,
CONTROLLER_PLAYER_3 = 2,
CONTROLLER_PLAYER_4 = 3,
CONTROLLER_PLAYER_5 = 4,
CONTROLLER_PLAYER_6 = 5,
CONTROLLER_PLAYER_7 = 6,
CONTROLLER_PLAYER_8 = 7,
CONTROLLER_HANDHELD = 8,
CONTROLLER_UNKNOWN = 9
}
public enum HidControllerJoystick
{
Joystick_Left = 0,
Joystick_Right = 1,
Joystick_Num_Sticks = 2
}
public enum HidControllerLayouts
{
Pro_Controller,
Handheld_Joined,
Joined,
Left,
Right,
Main_No_Analog,
Main
}
public enum HidControllerConnectionState
{
Controller_State_Connected = (1 << 0),
Controller_State_Wired = (1 << 1)
}
public enum HidControllerType
{
ControllerType_ProController = (1 << 0),
ControllerType_Handheld = (1 << 1),
ControllerType_JoyconPair = (1 << 2),
ControllerType_JoyconLeft = (1 << 3),
ControllerType_JoyconRight = (1 << 4)
}
public enum HidControllerColorDescription
{
ColorDesc_ColorsNonexistent = (1 << 1),
}
[StructLayout(LayoutKind.Sequential, Size = 0x8)]
public struct JoystickPosition
{
public int DX;
public int DY;
}
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
public struct HidControllerMAC
{
public ulong Timestamp;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] MAC;
public ulong Unknown;
public ulong Timestamp_2;
}
[StructLayout(LayoutKind.Sequential, Size = 0x28)]
public struct HidControllerHeader
{
public uint Type;
public uint IsHalf;
public uint SingleColorsDescriptor;
public uint SingleColorBody;
public uint SingleColorButtons;
public uint SplitColorsDescriptor;
public uint LeftColorBody;
public uint LeftColorButtons;
public uint RightColorBody;
public uint RightColorButtons;
}
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
public struct HidControllerLayoutHeader
{
public ulong TimestampTicks;
public ulong NumEntries;
public ulong LatestEntry;
public ulong MaxEntryIndex;
}
[StructLayout(LayoutKind.Sequential, Size = 0x30)]
public struct HidControllerInputEntry
{
public ulong Timestamp;
public ulong Timestamp_2;
public ulong Buttons;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)HidControllerJoystick.Joystick_Num_Sticks)]
public JoystickPosition[] Joysticks;
public ulong ConnectionState;
}
[StructLayout(LayoutKind.Sequential, Size = 0x350)]
public struct HidControllerLayout
{
public HidControllerLayoutHeader Header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
public HidControllerInputEntry[] Entries;
}
[StructLayout(LayoutKind.Sequential, Size = 0x5000)]
public struct HidController
{
public HidControllerHeader Header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
public HidControllerLayout[] Layouts;
/*
pro_controller
handheld_joined
joined
left
right
main_no_analog
main
*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x2A70)]
public byte[] Unknown_1;
public HidControllerMAC MacLeft;
public HidControllerMAC MacRight;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xDF8)]
public byte[] Unknown_2;
}
}

View File

@ -0,0 +1,33 @@
using System.Runtime.InteropServices;
namespace Ryujinx
{
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
public struct HidKeyboardHeader
{
public ulong TimestampTicks;
public ulong NumEntries;
public ulong LatestEntry;
public ulong MaxEntryIndex;
}
[StructLayout(LayoutKind.Sequential, Size = 0x38)]
public struct HidKeyboardEntry
{
public ulong Timestamp;
public ulong Timestamp_2;
public ulong Modifier;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public uint[] Keys;
}
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
public struct HidKeyboard
{
public HidKeyboardHeader Header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
public HidKeyboardEntry[] Entries;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x28)]
public byte[] Padding;
}
}

37
Ryujinx/Hid/HidMouse.cs Normal file
View File

@ -0,0 +1,37 @@
using System.Runtime.InteropServices;
namespace Ryujinx
{
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
public struct HidMouseHeader
{
public ulong TimestampTicks;
public ulong NumEntries;
public ulong LatestEntry;
public ulong MaxEntryIndex;
}
[StructLayout(LayoutKind.Sequential, Size = 0x30)]
public struct HidMouseEntry
{
public ulong Timestamp;
public ulong Timestamp_2;
public uint X;
public uint Y;
public uint VelocityX;
public uint VelocityY;
public uint ScrollVelocityX;
public uint ScrollVelocityY;
public ulong Buttons;
}
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
public struct HidMouse
{
public HidMouseHeader Header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
public HidMouseEntry[] Entries;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xB0)]
public byte[] Padding;
}
}

View File

@ -0,0 +1,54 @@
using System.Runtime.InteropServices;
namespace Ryujinx
{
[StructLayout(LayoutKind.Sequential, Size = 0x28)]
public struct HidTouchScreenHeader
{
public ulong TimestampTicks;
public ulong NumEntries;
public ulong LatestEntry;
public ulong MaxEntryIndex;
public ulong Timestamp;
}
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
public struct HidTouchScreenEntryHeader
{
public ulong Timestamp;
public ulong NumTouches;
}
[StructLayout(LayoutKind.Sequential, Size = 0x28)]
public struct HidTouchScreenEntryTouch
{
public ulong Timestamp;
public uint Padding;
public uint TouchIndex;
public uint X;
public uint Y;
public uint DiameterX;
public uint DiameterY;
public uint Angle;
public uint Padding_2;
}
[StructLayout(LayoutKind.Sequential, Size = 0x298)]
public struct HidTouchScreenEntry
{
public HidTouchScreenEntryHeader Header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public HidTouchScreenEntryTouch[] Touches;
public ulong Unknown;
}
[StructLayout(LayoutKind.Sequential, Size = 0x3000)]
public struct HidTouchScreen
{
public HidTouchScreenHeader Header;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
public HidTouchScreenEntry[] Entries;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3C0)]
public byte[] Padding;
}
}

81
Ryujinx/Hid/HidUnknown.cs Normal file
View File

@ -0,0 +1,81 @@
using System.Runtime.InteropServices;
namespace Ryujinx
{
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
public struct HidSharedMemHeader
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)]
public byte[] Padding;
}
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
public struct HidUnknownSection1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)]
public byte[] Padding;
}
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
public struct HidUnknownSection2
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)]
public byte[] Padding;
}
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
public struct HidUnknownSection3
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)]
public byte[] Padding;
}
[StructLayout(LayoutKind.Sequential, Size = 0x400)]
public struct HidUnknownSection4
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x400)]
public byte[] Padding;
}
[StructLayout(LayoutKind.Sequential, Size = 0x200)]
public struct HidUnknownSection5
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)]
public byte[] Padding;
}
[StructLayout(LayoutKind.Sequential, Size = 0x200)]
public struct HidUnknownSection6
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)]
public byte[] Padding;
}
[StructLayout(LayoutKind.Sequential, Size = 0x200)]
public struct HidUnknownSection7
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x200)]
public byte[] Padding;
}
[StructLayout(LayoutKind.Sequential, Size = 0x800)]
public struct HidUnknownSection8
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x800)]
public byte[] Padding;
}
[StructLayout(LayoutKind.Sequential, Size = 0x4000)]
public struct HidControllerSerials
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4000)]
public byte[] Padding;
}
[StructLayout(LayoutKind.Sequential, Size = 0x4600)]
public struct HidUnknownSection9
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4600)]
public byte[] Padding;
}
}

63
Ryujinx/Hid/JoyCon.cs Normal file
View File

@ -0,0 +1,63 @@
namespace Ryujinx
{
public enum JoyConColor //Thanks to CTCaer
{
Body_Grey = 0x828282,
Body_Neon_Blue = 0x0AB9E6,
Body_Neon_Red = 0xFF3C28,
Body_Neon_Yellow = 0xE6FF00,
Body_Neon_Pink = 0xFF3278,
Body_Neon_Green = 0x1EDC00,
Body_Red = 0xE10F00,
Buttons_Grey = 0x0F0F0F,
Buttons_Neon_Blue = 0x001E1E,
Buttons_Neon_Red = 0x1E0A0A,
Buttons_Neon_Yellow = 0x142800,
Buttons_Neon_Pink = 0x28001E,
Buttons_Neon_Green = 0x002800,
Buttons_Red = 0x280A0A
}
public struct JoyConLeft
{
public int StickUp;
public int StickDown;
public int StickLeft;
public int StickRight;
public int StickButton;
public int DPadUp;
public int DPadDown;
public int DPadLeft;
public int DPadRight;
public int ButtonMinus;
public int ButtonL;
public int ButtonZL;
public int ButtonSL;
public int ButtonSR;
}
public struct JoyConRight
{
public int StickUp;
public int StickDown;
public int StickLeft;
public int StickRight;
public int StickButton;
public int ButtonA;
public int ButtonB;
public int ButtonX;
public int ButtonY;
public int ButtonPlus;
public int ButtonR;
public int ButtonZR;
public int ButtonSL;
public int ButtonSR;
}
public struct JoyCon
{
public JoyConLeft Left;
public JoyConRight Right;
}
}

View File

@ -87,7 +87,7 @@ namespace Ryujinx.OsHle
continue; continue;
} }
Logging.Info($"Loding {Path.GetFileNameWithoutExtension(File)}..."); Logging.Info($"Loading {Path.GetFileNameWithoutExtension(File)}...");
using (FileStream Input = new FileStream(File, FileMode.Open)) using (FileStream Input = new FileStream(File, FileMode.Open))
{ {
@ -195,14 +195,8 @@ namespace Ryujinx.OsHle
if (SharedMem.TryGetLastVirtualPosition(out long Position)) if (SharedMem.TryGetLastVirtualPosition(out long Position))
{ {
Logging.Info($"HID shared memory successfully mapped to {Position:x16}!"); Logging.Info($"HID shared memory successfully mapped to {Position:x16}!");
Ns.Hid.Init(Position);
} }
} }
public long GetVirtHidOffset()
{
HidSharedMem.TryGetLastVirtualPosition(out long Position);
return Position;
}
} }
} }

View File

@ -18,3 +18,30 @@ Logging_Enable_Fatal = true
#Saved logs into Ryujinx.log #Saved logs into Ryujinx.log
Logging_Enable_LogFile = false Logging_Enable_LogFile = false
#https://github.com/opentk/opentk/blob/develop/src/OpenTK/Input/Key.cs
Controls_Left_FakeJoycon_Stick_Up = 91
Controls_Left_FakeJoycon_Stick_Down = 93
Controls_Left_FakeJoycon_Stick_Left = 92
Controls_Left_FakeJoycon_Stick_Right = 94
Controls_Left_FakeJoycon_Stick_Button = 0
Controls_Left_FakeJoycon_DPad_Up = 0
Controls_Left_FakeJoycon_DPad_Down = 0
Controls_Left_FakeJoycon_DPad_Left = 0
Controls_Left_FakeJoycon_DPad_Right = 0
Controls_Left_FakeJoycon_Button_Minus = 52
Controls_Left_FakeJoycon_Button_L = 0
Controls_Left_FakeJoycon_Button_ZL = 0
Controls_Right_FakeJoycon_Stick_Up = 45
Controls_Right_FakeJoycon_Stick_Down = 46
Controls_Right_FakeJoycon_Stick_Left = 47
Controls_Right_FakeJoycon_Stick_Right = 48
Controls_Right_FakeJoycon_Stick_Button = 0
Controls_Right_FakeJoycon_Button_A = 83
Controls_Right_FakeJoycon_Button_B = 101
Controls_Right_FakeJoycon_Button_X = 106
Controls_Right_FakeJoycon_Button_Y = 108
Controls_Right_FakeJoycon_Button_Plus = 49
Controls_Right_FakeJoycon_Button_R = 0
Controls_Right_FakeJoycon_Button_ZR = 0

View File

@ -14,6 +14,7 @@ namespace Ryujinx
internal NsGpu Gpu { get; private set; } internal NsGpu Gpu { get; private set; }
internal Horizon Os { get; private set; } internal Horizon Os { get; private set; }
internal VirtualFs VFs { get; private set; } internal VirtualFs VFs { get; private set; }
internal Hid Hid { get; private set; }
public event EventHandler Finish; public event EventHandler Finish;
@ -24,6 +25,7 @@ namespace Ryujinx
Gpu = new NsGpu(Renderer); Gpu = new NsGpu(Renderer);
Os = new Horizon(this); Os = new Horizon(this);
VFs = new VirtualFs(); VFs = new VirtualFs();
Hid = new Hid(this);
} }
internal virtual void OnFinish(EventArgs e) internal virtual void OnFinish(EventArgs e)

View File

@ -276,76 +276,62 @@ void main(void) {
protected override void OnUpdateFrame(FrameEventArgs e) protected override void OnUpdateFrame(FrameEventArgs e)
{ {
unsafe HidControllerKeys CurrentButton = 0;
JoystickPosition LeftJoystick;
JoystickPosition RightJoystick;
if (Keyboard[OpenTK.Input.Key.Escape]) this.Exit();
//RightJoystick
int LeftJoystickDX = 0;
int LeftJoystickDY = 0;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickUp]) LeftJoystickDY = short.MaxValue;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickDown]) LeftJoystickDY = -short.MaxValue;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickLeft]) LeftJoystickDX = -short.MaxValue;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickRight]) LeftJoystickDX = short.MaxValue;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.StickButton]) CurrentButton |= HidControllerKeys.KEY_LSTICK;
//LeftButtons
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadUp]) CurrentButton |= HidControllerKeys.KEY_DUP;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadDown]) CurrentButton |= HidControllerKeys.KEY_DDOWN;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadLeft]) CurrentButton |= HidControllerKeys.KEY_DLEFT;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.DPadRight]) CurrentButton |= HidControllerKeys.KEY_DRIGHT;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.ButtonMinus]) CurrentButton |= HidControllerKeys.KEY_MINUS;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.ButtonL]) CurrentButton |= HidControllerKeys.KEY_L;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Left.ButtonZL]) CurrentButton |= HidControllerKeys.KEY_ZL;
//RightJoystick
int RightJoystickDX = 0;
int RightJoystickDY = 0;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickUp]) RightJoystickDY = short.MaxValue;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickDown]) RightJoystickDY = -short.MaxValue;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickLeft]) RightJoystickDX = -short.MaxValue;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickRight]) RightJoystickDX = short.MaxValue;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.StickButton]) CurrentButton |= HidControllerKeys.KEY_RSTICK;
//RightButtons
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonA]) CurrentButton |= HidControllerKeys.KEY_A;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonB]) CurrentButton |= HidControllerKeys.KEY_B;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonX]) CurrentButton |= HidControllerKeys.KEY_X;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonY]) CurrentButton |= HidControllerKeys.KEY_Y;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonPlus]) CurrentButton |= HidControllerKeys.KEY_PLUS;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonR]) CurrentButton |= HidControllerKeys.KEY_R;
if (Keyboard[(OpenTK.Input.Key)Config.FakeJoyCon.Right.ButtonZR]) CurrentButton |= HidControllerKeys.KEY_ZR;
LeftJoystick = new JoystickPosition
{ {
long HidOffset = Ns.Os.GetVirtHidOffset(); DX = LeftJoystickDX,
DY = LeftJoystickDY
};
if (HidOffset == 0 || HidOffset + Horizon.HidSize > uint.MaxValue) RightJoystick = new JoystickPosition
{
return;
}
byte* Ptr = (byte*)Ns.Ram + (uint)HidOffset;
int State = 0;
if (Keyboard[OpenTK.Input.Key.Up])
{
State |= 0x2000;
}
if (Keyboard[OpenTK.Input.Key.Down])
{
State |= 0x8000;
}
if (Keyboard[OpenTK.Input.Key.Left])
{
State |= 0x1000;
}
if (Keyboard[OpenTK.Input.Key.Right])
{
State |= 0x4000;
}
if (Keyboard[OpenTK.Input.Key.A])
{
State |= 0x1;
}
if (Keyboard[OpenTK.Input.Key.S])
{
State |= 0x2;
}
if (Keyboard[OpenTK.Input.Key.Z])
{
State |= 0x4;
}
if (Keyboard[OpenTK.Input.Key.X])
{
State |= 0x8;
}
if (Keyboard[OpenTK.Input.Key.Enter])
{
State |= 0x400;
}
if (Keyboard[OpenTK.Input.Key.Tab])
{
State |= 0x800;
}
*((int*)(Ptr + 0xae38)) = (int)State;
}
if (Keyboard[OpenTK.Input.Key.Escape])
{ {
this.Exit(); DX = RightJoystickDX,
} DY = RightJoystickDY
};
//We just need one pair of JoyCon because it's emulate by the keyboard.
Ns.Hid.SendControllerButtons(HidControllerID.CONTROLLER_HANDHELD, HidControllerLayouts.Main, CurrentButton, LeftJoystick, RightJoystick);
} }
protected override void OnRenderFrame(FrameEventArgs e) protected override void OnRenderFrame(FrameEventArgs e)