ryujinx/Ryujinx.HLE/Hid/Hid.cs
Thomas Guillemard eeb626947e Implement Shared Fonts (#215)
* Implement Shared Fonts

This fully implements shared fonts.
This commit is provided without fonts.
This commit also add Size to HSharedMem.Positions to be able to add fonts to shared zones when RequestLoad is called.

* Require the user to provide fonts in RyuFS/system

* Use File.Exits instead of relying ona try/catch and change system resource exception format a bit

* Make sure that font sum doesn't exceed 17MB

Also rename font data dictionary for coherence.
2018-08-04 18:38:49 -03:00

278 lines
12 KiB
C#

using ChocolArm64.Memory;
using Ryujinx.HLE.Logging;
using Ryujinx.HLE.OsHle;
using Ryujinx.HLE.OsHle.Handles;
using System;
namespace Ryujinx.HLE.Input
{
public 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
*/
private const int HidHeaderSize = 0x400;
private const int HidTouchScreenSize = 0x3000;
private const int HidMouseSize = 0x400;
private const int HidKeyboardSize = 0x400;
private const int HidUnkSection1Size = 0x400;
private const int HidUnkSection2Size = 0x400;
private const int HidUnkSection3Size = 0x400;
private const int HidUnkSection4Size = 0x400;
private const int HidUnkSection5Size = 0x200;
private const int HidUnkSection6Size = 0x200;
private const int HidUnkSection7Size = 0x200;
private const int HidUnkSection8Size = 0x800;
private const int HidControllerSerialsSize = 0x4000;
private const int HidControllersSize = 0x32000;
private const int HidUnkSection9Size = 0x800;
private const int HidTouchHeaderSize = 0x28;
private const int HidTouchEntrySize = 0x298;
private const int HidTouchEntryHeaderSize = 0x10;
private const int HidTouchEntryTouchSize = 0x28;
private const int HidControllerSize = 0x5000;
private const int HidControllerHeaderSize = 0x28;
private const int HidControllerLayoutsSize = 0x350;
private const int HidControllersLayoutHeaderSize = 0x20;
private const int HidControllersInputEntrySize = 0x30;
private const int HidHeaderOffset = 0;
private const int HidTouchScreenOffset = HidHeaderOffset + HidHeaderSize;
private const int HidMouseOffset = HidTouchScreenOffset + HidTouchScreenSize;
private const int HidKeyboardOffset = HidMouseOffset + HidMouseSize;
private const int HidUnkSection1Offset = HidKeyboardOffset + HidKeyboardSize;
private const int HidUnkSection2Offset = HidUnkSection1Offset + HidUnkSection1Size;
private const int HidUnkSection3Offset = HidUnkSection2Offset + HidUnkSection2Size;
private const int HidUnkSection4Offset = HidUnkSection3Offset + HidUnkSection3Size;
private const int HidUnkSection5Offset = HidUnkSection4Offset + HidUnkSection4Size;
private const int HidUnkSection6Offset = HidUnkSection5Offset + HidUnkSection5Size;
private const int HidUnkSection7Offset = HidUnkSection6Offset + HidUnkSection6Size;
private const int HidUnkSection8Offset = HidUnkSection7Offset + HidUnkSection7Size;
private const int HidControllerSerialsOffset = HidUnkSection8Offset + HidUnkSection8Size;
private const int HidControllersOffset = HidControllerSerialsOffset + HidControllerSerialsSize;
private const int HidUnkSection9Offset = HidControllersOffset + HidControllersSize;
private const int HidEntryCount = 17;
private Logger Log;
private object ShMemLock;
private (AMemory, long, long)[] ShMemPositions;
public Hid(Logger Log)
{
this.Log = Log;
ShMemLock = new object();
ShMemPositions = new (AMemory, long, long)[0];
}
internal void ShMemMap(object sender, EventArgs e)
{
HSharedMem SharedMem = (HSharedMem)sender;
lock (ShMemLock)
{
ShMemPositions = SharedMem.GetVirtualPositions();
(AMemory Memory, long Position, long Size) = ShMemPositions[ShMemPositions.Length - 1];
for (long Offset = 0; Offset < Horizon.HidSize; Offset += 8)
{
Memory.WriteInt64Unchecked(Position + Offset, 0);
}
Log.PrintInfo(LogClass.Hid, $"HID shared memory successfully mapped to 0x{Position:x16}!");
Init(Memory, Position);
}
}
internal void ShMemUnmap(object sender, EventArgs e)
{
HSharedMem SharedMem = (HSharedMem)sender;
lock (ShMemLock)
{
ShMemPositions = SharedMem.GetVirtualPositions();
}
}
private void Init(AMemory Memory, long Position)
{
InitializeJoyconPair(
Memory,
Position,
JoyConColor.Body_Neon_Red,
JoyConColor.Buttons_Neon_Red,
JoyConColor.Body_Neon_Blue,
JoyConColor.Buttons_Neon_Blue);
}
private void InitializeJoyconPair(
AMemory Memory,
long Position,
JoyConColor LeftColorBody,
JoyConColor LeftColorButtons,
JoyConColor RightColorBody,
JoyConColor RightColorButtons)
{
long BaseControllerOffset = Position + HidControllersOffset + 8 * HidControllerSize;
HidControllerType Type = HidControllerType.ControllerType_Handheld;
bool IsHalf = false;
HidControllerColorDesc SingleColorDesc =
HidControllerColorDesc.ColorDesc_ColorsNonexistent;
JoyConColor SingleColorBody = JoyConColor.Black;
JoyConColor SingleColorButtons = JoyConColor.Black;
HidControllerColorDesc SplitColorDesc = 0;
Memory.WriteInt32Unchecked(BaseControllerOffset + 0x0, (int)Type);
Memory.WriteInt32Unchecked(BaseControllerOffset + 0x4, IsHalf ? 1 : 0);
Memory.WriteInt32Unchecked(BaseControllerOffset + 0x8, (int)SingleColorDesc);
Memory.WriteInt32Unchecked(BaseControllerOffset + 0xc, (int)SingleColorBody);
Memory.WriteInt32Unchecked(BaseControllerOffset + 0x10, (int)SingleColorButtons);
Memory.WriteInt32Unchecked(BaseControllerOffset + 0x14, (int)SplitColorDesc);
Memory.WriteInt32Unchecked(BaseControllerOffset + 0x18, (int)LeftColorBody);
Memory.WriteInt32Unchecked(BaseControllerOffset + 0x1c, (int)LeftColorButtons);
Memory.WriteInt32Unchecked(BaseControllerOffset + 0x20, (int)RightColorBody);
Memory.WriteInt32Unchecked(BaseControllerOffset + 0x24, (int)RightColorButtons);
}
public void SetJoyconButton(
HidControllerId ControllerId,
HidControllerLayouts ControllerLayout,
HidControllerButtons Buttons,
HidJoystickPosition LeftStick,
HidJoystickPosition RightStick)
{
lock (ShMemLock)
{
foreach ((AMemory Memory, long Position, long Size) in ShMemPositions)
{
long ControllerOffset = Position + HidControllersOffset;
ControllerOffset += (int)ControllerId * HidControllerSize;
ControllerOffset += HidControllerHeaderSize;
ControllerOffset += (int)ControllerLayout * HidControllerLayoutsSize;
long LastEntry = Memory.ReadInt64Unchecked(ControllerOffset + 0x10);
long CurrEntry = (LastEntry + 1) % HidEntryCount;
long Timestamp = GetTimestamp();
Memory.WriteInt64Unchecked(ControllerOffset + 0x0, Timestamp);
Memory.WriteInt64Unchecked(ControllerOffset + 0x8, HidEntryCount);
Memory.WriteInt64Unchecked(ControllerOffset + 0x10, CurrEntry);
Memory.WriteInt64Unchecked(ControllerOffset + 0x18, HidEntryCount - 1);
ControllerOffset += HidControllersLayoutHeaderSize;
long LastEntryOffset = ControllerOffset + LastEntry * HidControllersInputEntrySize;
ControllerOffset += CurrEntry * HidControllersInputEntrySize;
long SampleCounter = Memory.ReadInt64Unchecked(LastEntryOffset) + 1;
Memory.WriteInt64Unchecked(ControllerOffset + 0x0, SampleCounter);
Memory.WriteInt64Unchecked(ControllerOffset + 0x8, SampleCounter);
Memory.WriteInt64Unchecked(ControllerOffset + 0x10, (uint)Buttons);
Memory.WriteInt32Unchecked(ControllerOffset + 0x18, LeftStick.DX);
Memory.WriteInt32Unchecked(ControllerOffset + 0x1c, LeftStick.DY);
Memory.WriteInt32Unchecked(ControllerOffset + 0x20, RightStick.DX);
Memory.WriteInt32Unchecked(ControllerOffset + 0x24, RightStick.DY);
Memory.WriteInt64Unchecked(ControllerOffset + 0x28,
(uint)HidControllerConnState.Controller_State_Connected |
(uint)HidControllerConnState.Controller_State_Wired);
}
}
}
public void SetTouchPoints(params HidTouchPoint[] Points)
{
lock (ShMemLock)
{
foreach ((AMemory Memory, long Position, long Size) in ShMemPositions)
{
long TouchScreenOffset = Position + HidTouchScreenOffset;
long LastEntry = Memory.ReadInt64Unchecked(TouchScreenOffset + 0x10);
long CurrEntry = (LastEntry + 1) % HidEntryCount;
long Timestamp = GetTimestamp();
Memory.WriteInt64Unchecked(TouchScreenOffset + 0x0, Timestamp);
Memory.WriteInt64Unchecked(TouchScreenOffset + 0x8, HidEntryCount);
Memory.WriteInt64Unchecked(TouchScreenOffset + 0x10, CurrEntry);
Memory.WriteInt64Unchecked(TouchScreenOffset + 0x18, HidEntryCount - 1);
Memory.WriteInt64Unchecked(TouchScreenOffset + 0x20, Timestamp);
long TouchEntryOffset = TouchScreenOffset + HidTouchHeaderSize;
long LastEntryOffset = TouchEntryOffset + LastEntry * HidTouchEntrySize;
long SampleCounter = Memory.ReadInt64Unchecked(LastEntryOffset) + 1;
TouchEntryOffset += CurrEntry * HidTouchEntrySize;
Memory.WriteInt64Unchecked(TouchEntryOffset + 0x0, SampleCounter);
Memory.WriteInt64Unchecked(TouchEntryOffset + 0x8, Points.Length);
TouchEntryOffset += HidTouchEntryHeaderSize;
const int Padding = 0;
int Index = 0;
foreach (HidTouchPoint Point in Points)
{
Memory.WriteInt64Unchecked(TouchEntryOffset + 0x0, Timestamp);
Memory.WriteInt32Unchecked(TouchEntryOffset + 0x8, Padding);
Memory.WriteInt32Unchecked(TouchEntryOffset + 0xc, Index++);
Memory.WriteInt32Unchecked(TouchEntryOffset + 0x10, Point.X);
Memory.WriteInt32Unchecked(TouchEntryOffset + 0x14, Point.Y);
Memory.WriteInt32Unchecked(TouchEntryOffset + 0x18, Point.DiameterX);
Memory.WriteInt32Unchecked(TouchEntryOffset + 0x1c, Point.DiameterY);
Memory.WriteInt32Unchecked(TouchEntryOffset + 0x20, Point.Angle);
Memory.WriteInt32Unchecked(TouchEntryOffset + 0x24, Padding);
TouchEntryOffset += HidTouchEntryTouchSize;
}
}
}
}
private static long GetTimestamp()
{
return (long)((ulong)Environment.TickCount * 19_200);
}
}
}