Use a struct for HID shared memory (based on libnx struct)
This commit is contained in:
parent
f9847590d9
commit
77293d77ce
22 changed files with 410 additions and 424 deletions
|
@ -113,7 +113,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
public int GlobalAccessLogMode { get; set; }
|
||||
|
||||
internal long HidBaseAddress { get; private set; }
|
||||
internal ulong HidBaseAddress { get; private set; }
|
||||
|
||||
internal FileSystemServer FsServer { get; private set; }
|
||||
internal EmulatedGameCard GameCard { get; private set; }
|
||||
|
@ -172,7 +172,7 @@ namespace Ryujinx.HLE.HOS
|
|||
ulong iirsPa = region.Address + HidSize + FontSize;
|
||||
ulong timePa = region.Address + HidSize + FontSize + IirsSize;
|
||||
|
||||
HidBaseAddress = (long)(hidPa - DramMemoryMap.DramBase);
|
||||
HidBaseAddress = hidPa - DramMemoryMap.DramBase;
|
||||
|
||||
KPageList hidPageList = new KPageList();
|
||||
KPageList fontPageList = new KPageList();
|
||||
|
|
|
@ -2,141 +2,100 @@
|
|||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public abstract class BaseController : IHidDevice
|
||||
public class BaseController
|
||||
{
|
||||
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; }
|
||||
protected ControllerStatus ControllerType;
|
||||
|
||||
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; }
|
||||
private ControllerId _controllerId;
|
||||
private ControllerLayouts _currentLayout;
|
||||
|
||||
private HidControllerHeader _header;
|
||||
private HidControllerMisc _misc;
|
||||
|
||||
protected ControllerConnectionState ConnectionState;
|
||||
|
||||
public BaseController(Switch device, ControllerStatus controllerType)
|
||||
{
|
||||
Device = device;
|
||||
HidControllerType = controllerType;
|
||||
Device = device;
|
||||
ControllerType = controllerType;
|
||||
}
|
||||
|
||||
protected void Initialize(
|
||||
bool isHalf,
|
||||
(NpadColor left, NpadColor right) bodyColors,
|
||||
(NpadColor left, NpadColor right) buttonColors,
|
||||
(NpadColor Left, NpadColor Right) bodyColors,
|
||||
(NpadColor Left, NpadColor Right) buttonColors,
|
||||
ControllerColorDescription singleColorDesc = 0,
|
||||
ControllerColorDescription splitColorDesc = 0,
|
||||
NpadColor singleBodyColor = 0,
|
||||
NpadColor singleButtonColor = 0
|
||||
)
|
||||
NpadColor singleButtonColor = 0)
|
||||
{
|
||||
Header = new ControllerHeader()
|
||||
_header = new HidControllerHeader()
|
||||
{
|
||||
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,
|
||||
Type = ControllerType,
|
||||
IsHalf = isHalf,
|
||||
LeftColorBody = bodyColors.Left,
|
||||
LeftColorButtons = buttonColors.Left,
|
||||
RightColorBody = bodyColors.Right,
|
||||
RightColorButtons = buttonColors.Right,
|
||||
SingleColorBody = singleBodyColor,
|
||||
SingleColorButtons = singleButtonColor,
|
||||
SplitColorsDescriptor = splitColorDesc,
|
||||
SingleColorsDescriptor = singleColorDesc
|
||||
};
|
||||
|
||||
CurrentStateHeader = new ControllerStateHeader
|
||||
{
|
||||
EntryCount = HidEntryCount,
|
||||
MaxEntryCount = HidEntryCount - 1,
|
||||
CurrentEntryIndex = -1
|
||||
};
|
||||
|
||||
DeviceState = new ControllerDeviceState()
|
||||
_misc = new HidControllerMisc()
|
||||
{
|
||||
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
|
||||
DeviceFlags = DeviceFlags.PowerInfo0Connected |
|
||||
DeviceFlags.PowerInfo1Connected |
|
||||
DeviceFlags.PowerInfo2Connected
|
||||
};
|
||||
}
|
||||
|
||||
public virtual void Connect(ControllerId controllerId)
|
||||
{
|
||||
ControllerId = controllerId;
|
||||
_controllerId = controllerId;
|
||||
|
||||
Offset = Device.Hid.HidPosition + HidControllersOffset + (int)controllerId * HidControllerSize;
|
||||
ref HidSharedMemory sharedMemory = ref Device.Hid.SharedMemory;
|
||||
|
||||
_mainLayoutOffset = Offset + HidControllerHeaderSize
|
||||
+ ((int)ControllerLayouts.Main * HidControllerLayoutsSize);
|
||||
ref HidController controller = ref sharedMemory.Controllers[(int)controllerId];
|
||||
|
||||
Device.Memory.ZeroFill((ulong)Offset, 0x5000);
|
||||
Device.Memory.Write((ulong)Offset, Header);
|
||||
Device.Memory.Write((ulong)DeviceStateOffset, DeviceState);
|
||||
|
||||
Connected = true;
|
||||
controller.Header = _header;
|
||||
controller.Misc = _misc;
|
||||
}
|
||||
|
||||
public void SetLayout(ControllerLayouts controllerLayout)
|
||||
{
|
||||
CurrentLayout = controllerLayout;
|
||||
|
||||
_currentLayoutOffset = Offset + HidControllerHeaderSize
|
||||
+ ((int)controllerLayout * HidControllerLayoutsSize);
|
||||
_currentLayout = controllerLayout;
|
||||
}
|
||||
|
||||
public void SendInput(
|
||||
ControllerButtons buttons,
|
||||
JoystickPosition leftStick,
|
||||
JoystickPosition rightStick)
|
||||
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
|
||||
};
|
||||
ref HidSharedMemory sharedMemory = ref Device.Hid.SharedMemory;
|
||||
|
||||
ControllerStateHeader newInputStateHeader = new ControllerStateHeader
|
||||
{
|
||||
EntryCount = HidEntryCount,
|
||||
MaxEntryCount = HidEntryCount - 1,
|
||||
CurrentEntryIndex = (CurrentStateHeader.CurrentEntryIndex + 1) % HidEntryCount,
|
||||
Timestamp = GetTimestamp(),
|
||||
};
|
||||
ref HidControllerLayout layout = ref sharedMemory.Controllers[(int)_controllerId].Layouts[(int)_currentLayout];
|
||||
|
||||
Device.Memory.Write((ulong)_currentLayoutOffset, newInputStateHeader);
|
||||
Device.Memory.Write((ulong)_mainLayoutOffset, newInputStateHeader);
|
||||
layout.Header.NumEntries = 17;
|
||||
layout.Header.MaxEntryIndex = 16;
|
||||
|
||||
long currentInputStateOffset = HidControllersLayoutHeaderSize
|
||||
+ newInputStateHeader.CurrentEntryIndex * HidControllersInputEntrySize;
|
||||
layout.Header.LatestEntry = (layout.Header.LatestEntry + 1) % 17;
|
||||
|
||||
Device.Memory.Write((ulong)(_currentLayoutOffset + currentInputStateOffset), currentInput);
|
||||
Device.Memory.Write((ulong)(_mainLayoutOffset + currentInputStateOffset), currentInput);
|
||||
layout.Header.TimestampTicks = GetTimestamp();
|
||||
|
||||
LastInputState = currentInput;
|
||||
CurrentStateHeader = newInputStateHeader;
|
||||
ref HidControllerInputEntry entry = ref layout.Entries[(int)layout.Header.LatestEntry];
|
||||
|
||||
entry.Timestamp++;
|
||||
entry.Timestamp2++;
|
||||
|
||||
entry.Buttons = buttons;
|
||||
entry.ConnectionState = ConnectionState;
|
||||
entry.Joysticks[0] = leftStick;
|
||||
entry.Joysticks[1] = rightStick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
public override void Connect(ControllerId controllerId)
|
||||
{
|
||||
if (HidControllerType != ControllerStatus.NpadLeft && HidControllerType != ControllerStatus.NpadRight)
|
||||
if (ControllerType != ControllerStatus.NpadLeft && ControllerType != ControllerStatus.NpadRight)
|
||||
{
|
||||
_isHalf = false;
|
||||
}
|
||||
|
@ -27,7 +27,9 @@
|
|||
ConnectionState = ControllerConnectionState.ControllerStateConnected;
|
||||
|
||||
if (controllerId == ControllerId.ControllerHandheld)
|
||||
{
|
||||
ConnectionState |= ControllerConnectionState.ControllerStateWired;
|
||||
}
|
||||
|
||||
ControllerColorDescription singleColorDesc =
|
||||
ControllerColorDescription.ColorDescriptionColorsNonexistent;
|
||||
|
@ -37,32 +39,33 @@
|
|||
NpadColor singleBodyColor = NpadColor.Black;
|
||||
NpadColor singleButtonColor = NpadColor.Black;
|
||||
|
||||
Initialize(_isHalf,
|
||||
Initialize(
|
||||
_isHalf,
|
||||
(_npadBodyColors.Left, _npadBodyColors.Right),
|
||||
(_npadButtonColors.Left, _npadButtonColors.Right),
|
||||
singleColorDesc,
|
||||
splitColorDesc,
|
||||
singleBodyColor,
|
||||
singleButtonColor );
|
||||
singleButtonColor);
|
||||
|
||||
base.Connect(controllerId);
|
||||
|
||||
var _currentLayout = ControllerLayouts.HandheldJoined;
|
||||
var currentLayout = ControllerLayouts.HandheldJoined;
|
||||
|
||||
switch (HidControllerType)
|
||||
switch (ControllerType)
|
||||
{
|
||||
case ControllerStatus.NpadLeft:
|
||||
_currentLayout = ControllerLayouts.Left;
|
||||
currentLayout = ControllerLayouts.Left;
|
||||
break;
|
||||
case ControllerStatus.NpadRight:
|
||||
_currentLayout = ControllerLayouts.Right;
|
||||
currentLayout = ControllerLayouts.Right;
|
||||
break;
|
||||
case ControllerStatus.NpadPair:
|
||||
_currentLayout = ControllerLayouts.Joined;
|
||||
currentLayout = ControllerLayouts.Joined;
|
||||
break;
|
||||
}
|
||||
|
||||
SetLayout(_currentLayout);
|
||||
SetLayout(currentLayout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,17 +2,11 @@
|
|||
{
|
||||
public class ProController : BaseController
|
||||
{
|
||||
private bool _wired = false;
|
||||
private readonly NpadColor _bodyColor;
|
||||
private readonly NpadColor _buttonColor;
|
||||
|
||||
private NpadColor _bodyColor;
|
||||
private NpadColor _buttonColor;
|
||||
|
||||
public ProController(Switch device,
|
||||
NpadColor bodyColor,
|
||||
NpadColor buttonColor) : base(device, ControllerStatus.ProController)
|
||||
public ProController(Switch device, NpadColor bodyColor, NpadColor buttonColor) : base(device, ControllerStatus.ProController)
|
||||
{
|
||||
_wired = true;
|
||||
|
||||
_bodyColor = bodyColor;
|
||||
_buttonColor = buttonColor;
|
||||
}
|
||||
|
@ -26,7 +20,8 @@
|
|||
|
||||
ConnectionState = ControllerConnectionState.ControllerStateConnected | ControllerConnectionState.ControllerStateWired;
|
||||
|
||||
Initialize(false,
|
||||
Initialize(
|
||||
false,
|
||||
(0, 0),
|
||||
(0, 0),
|
||||
singleColorDesc,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{
|
||||
public enum BatteryState : int
|
||||
{
|
||||
// TODO : Check if these are the correct states
|
||||
// TODO: Check if these are the correct states
|
||||
Percent0 = 0,
|
||||
Percent25 = 1,
|
||||
Percent50 = 2,
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
|
@ -7,6 +7,6 @@ namespace Ryujinx.HLE.Input
|
|||
{
|
||||
ProController = 1 << 0,
|
||||
NPadLeftController = 1 << 4,
|
||||
NPadRightController = 1 << 5,
|
||||
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,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,6 +1,6 @@
|
|||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
public enum NpadColor : int //Thanks to CTCaer
|
||||
public enum NpadColor : int
|
||||
{
|
||||
Black = 0,
|
||||
|
||||
|
|
|
@ -7,59 +7,33 @@ namespace Ryujinx.HLE.Input
|
|||
{
|
||||
public partial class Hid
|
||||
{
|
||||
private Switch _device;
|
||||
private readonly Switch _device;
|
||||
|
||||
private long _touchScreenOffset;
|
||||
private long _touchEntriesOffset;
|
||||
private long _keyboardOffset;
|
||||
private ulong _sharedMemoryAddress;
|
||||
|
||||
private TouchHeader _currentTouchHeader;
|
||||
private KeyboardHeader _currentKeyboardHeader;
|
||||
private KeyboardEntry _currentKeyboardEntry;
|
||||
internal ref HidSharedMemory SharedMemory => ref _device.Memory.GetRef<HidSharedMemory>(_sharedMemoryAddress);
|
||||
|
||||
public BaseController PrimaryController { get; private set; }
|
||||
|
||||
internal long HidPosition;
|
||||
|
||||
public Hid(Switch device, long hidPosition)
|
||||
public Hid(Switch device, ulong sharedMemoryAddress)
|
||||
{
|
||||
_device = device;
|
||||
HidPosition = hidPosition;
|
||||
_device = device;
|
||||
_sharedMemoryAddress = sharedMemoryAddress;
|
||||
|
||||
device.Memory.ZeroFill((ulong)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;
|
||||
device.Memory.ZeroFill(sharedMemoryAddress, Horizon.HidSize);
|
||||
}
|
||||
|
||||
private static ControllerStatus ConvertControllerTypeToState(ControllerType controllerType)
|
||||
{
|
||||
switch (controllerType)
|
||||
return controllerType switch
|
||||
{
|
||||
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();
|
||||
}
|
||||
ControllerType.Handheld => ControllerStatus.Handheld,
|
||||
ControllerType.NpadLeft => ControllerStatus.NpadLeft,
|
||||
ControllerType.NpadRight => ControllerStatus.NpadRight,
|
||||
ControllerType.NpadPair => ControllerStatus.NpadPair,
|
||||
ControllerType.ProController => ControllerStatus.ProController,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
public void InitializePrimaryController(ControllerType controllerType)
|
||||
|
@ -73,18 +47,17 @@ namespace Ryujinx.HLE.Input
|
|||
}
|
||||
else
|
||||
{
|
||||
PrimaryController = new NpadController(ConvertControllerTypeToState(controllerType),
|
||||
_device,
|
||||
(NpadColor.BodyNeonRed, NpadColor.BodyNeonRed),
|
||||
(NpadColor.ButtonsNeonBlue, NpadColor.ButtonsNeonBlue));
|
||||
PrimaryController = new NpadController(
|
||||
ConvertControllerTypeToState(controllerType),
|
||||
_device,
|
||||
(NpadColor.BodyNeonRed, NpadColor.BodyNeonRed),
|
||||
(NpadColor.ButtonsNeonBlue, NpadColor.ButtonsNeonBlue));
|
||||
}
|
||||
|
||||
PrimaryController.Connect(controllerId);
|
||||
}
|
||||
|
||||
public ControllerButtons UpdateStickButtons(
|
||||
JoystickPosition leftStick,
|
||||
JoystickPosition rightStick)
|
||||
public static ControllerButtons UpdateStickButtons(JoystickPosition leftStick, JoystickPosition rightStick)
|
||||
{
|
||||
ControllerButtons result = 0;
|
||||
|
||||
|
@ -130,93 +103,71 @@ namespace Ryujinx.HLE.Input
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetTouchPoints(params TouchPoint[] points)
|
||||
{
|
||||
long timestamp = GetTimestamp();
|
||||
long sampleCounter = _currentTouchHeader.SamplesTimestamp + 1;
|
||||
ref HidSharedMemory sharedMemory = ref SharedMemory;
|
||||
|
||||
var newTouchHeader = new TouchHeader
|
||||
ref HidTouchScreen touchScreen = ref sharedMemory.Touchscreen;
|
||||
|
||||
touchScreen.Header.NumEntries = 17;
|
||||
touchScreen.Header.MaxEntryIndex = 16;
|
||||
|
||||
touchScreen.Header.LatestEntry = (touchScreen.Header.LatestEntry + 1) % 17;
|
||||
|
||||
touchScreen.Header.TimestampTicks = GetTimestamp();
|
||||
|
||||
ulong timestamp = touchScreen.Header.Timestamp + 1;
|
||||
|
||||
touchScreen.Header.Timestamp = timestamp;
|
||||
|
||||
ref HidTouchScreenEntry entry = ref touchScreen.Entries[(int)touchScreen.Header.LatestEntry];
|
||||
|
||||
entry.Header.Timestamp = timestamp;
|
||||
entry.Header.NumTouches = (ulong)points.Length;
|
||||
|
||||
for (int index = 0; index < points.Length; index++)
|
||||
{
|
||||
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.Write((ulong)currentTouchEntryOffset, touchEntry);
|
||||
|
||||
currentTouchEntryOffset += HidTouchEntryHeaderSize;
|
||||
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
TouchData touch = new TouchData()
|
||||
entry.Touches[index] = new HidTouchScreenEntryTouch()
|
||||
{
|
||||
Angle = points[i].Angle,
|
||||
DiameterX = points[i].DiameterX,
|
||||
DiameterY = points[i].DiameterY,
|
||||
Index = i,
|
||||
SampleTimestamp = sampleCounter,
|
||||
X = points[i].X,
|
||||
Y = points[i].Y
|
||||
Timestamp = timestamp,
|
||||
TouchIndex = (uint)index,
|
||||
X = points[index].X,
|
||||
Y = points[index].Y,
|
||||
DiameterX = points[index].DiameterX,
|
||||
DiameterY = points[index].DiameterY,
|
||||
Angle = points[index].Angle
|
||||
};
|
||||
|
||||
_device.Memory.Write((ulong)currentTouchEntryOffset, touch);
|
||||
|
||||
currentTouchEntryOffset += HidTouchEntryTouchSize;
|
||||
}
|
||||
|
||||
_device.Memory.Write((ulong)_touchScreenOffset, newTouchHeader);
|
||||
|
||||
_currentTouchHeader = newTouchHeader;
|
||||
}
|
||||
|
||||
public unsafe void WriteKeyboard(Keyboard keyboard)
|
||||
{
|
||||
long timestamp = GetTimestamp();
|
||||
ref HidSharedMemory sharedMemory = ref SharedMemory;
|
||||
|
||||
var newKeyboardHeader = new KeyboardHeader()
|
||||
{
|
||||
CurrentEntryIndex = (_currentKeyboardHeader.CurrentEntryIndex + 1) % HidEntryCount,
|
||||
EntryCount = HidEntryCount,
|
||||
MaxEntries = HidEntryCount - 1,
|
||||
Timestamp = timestamp,
|
||||
};
|
||||
ref HidKeyboard kbd = ref sharedMemory.Keyboard;
|
||||
|
||||
_device.Memory.Write((ulong)_keyboardOffset, newKeyboardHeader);
|
||||
kbd.Header.NumEntries = 17;
|
||||
kbd.Header.MaxEntryIndex = 16;
|
||||
|
||||
long keyboardEntryOffset = _keyboardOffset + HidKeyboardHeaderSize;
|
||||
keyboardEntryOffset += newKeyboardHeader.CurrentEntryIndex * HidKeyboardEntrySize;
|
||||
kbd.Header.LatestEntry = (kbd.Header.LatestEntry + 1) % 17;
|
||||
|
||||
var newkeyboardEntry = new KeyboardEntry()
|
||||
{
|
||||
SamplesTimestamp = _currentKeyboardEntry.SamplesTimestamp + 1,
|
||||
SamplesTimestamp2 = _currentKeyboardEntry.SamplesTimestamp2 + 1,
|
||||
Modifier = keyboard.Modifier,
|
||||
};
|
||||
kbd.Header.TimestampTicks = GetTimestamp();
|
||||
|
||||
kbd.Entries[(int)kbd.Header.LatestEntry].Timestamp++;
|
||||
kbd.Entries[(int)kbd.Header.LatestEntry].Timestamp2++;
|
||||
|
||||
for (int index = 0; index < keyboard.Keys.Length; index++)
|
||||
{
|
||||
newkeyboardEntry.Keys[index] = keyboard.Keys[index];
|
||||
kbd.Entries[(int)kbd.Header.LatestEntry].Keys[index] = keyboard.Keys[index];
|
||||
}
|
||||
|
||||
_device.Memory.Write((ulong)keyboardEntryOffset, newkeyboardEntry);
|
||||
|
||||
_currentKeyboardEntry = newkeyboardEntry;
|
||||
_currentKeyboardHeader = newKeyboardHeader;
|
||||
|
||||
kbd.Entries[(int)kbd.Header.LatestEntry].Modifier = keyboard.Modifier;
|
||||
}
|
||||
|
||||
internal static long GetTimestamp()
|
||||
internal static ulong GetTimestamp()
|
||||
{
|
||||
return PerformanceCounter.ElapsedMilliseconds * 19200;
|
||||
return (ulong)PerformanceCounter.ElapsedMilliseconds * 19200;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
259
Ryujinx.HLE/Input/HidSharedMemory.cs
Normal file
259
Ryujinx.HLE/Input/HidSharedMemory.cs
Normal file
|
@ -0,0 +1,259 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
struct Array2<T> where T : unmanaged { T _e0; T _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 2)[index]; }
|
||||
struct Array3<T> where T : unmanaged { T _e0; Array2<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 3)[index]; }
|
||||
struct Array4<T> where T : unmanaged { T _e0; Array3<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 4)[index]; }
|
||||
struct Array5<T> where T : unmanaged { T _e0; Array4<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 5)[index]; }
|
||||
struct Array6<T> where T : unmanaged { T _e0; Array5<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 6)[index]; }
|
||||
struct Array7<T> where T : unmanaged { T _e0; Array6<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 7)[index]; }
|
||||
struct Array8<T> where T : unmanaged { T _e0; Array7<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 8)[index]; }
|
||||
struct Array9<T> where T : unmanaged { T _e0; Array8<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 9)[index]; }
|
||||
struct Array10<T> where T : unmanaged { T _e0; Array9<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 10)[index]; }
|
||||
struct Array11<T> where T : unmanaged { T _e0; Array10<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 11)[index]; }
|
||||
struct Array12<T> where T : unmanaged { T _e0; Array11<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 12)[index]; }
|
||||
struct Array13<T> where T : unmanaged { T _e0; Array12<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 13)[index]; }
|
||||
struct Array14<T> where T : unmanaged { T _e0; Array13<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 14)[index]; }
|
||||
struct Array15<T> where T : unmanaged { T _e0; Array14<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 15)[index]; }
|
||||
struct Array16<T> where T : unmanaged { T _e0; Array15<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 16)[index]; }
|
||||
struct Array17<T> where T : unmanaged { T _e0; Array16<T> _e1; public ref T this[int index] => ref MemoryMarshal.CreateSpan(ref _e0, 17)[index]; }
|
||||
|
||||
struct HidBool
|
||||
{
|
||||
private uint _value;
|
||||
|
||||
public static implicit operator bool(HidBool value)
|
||||
{
|
||||
return (value._value & 1) != 0;
|
||||
}
|
||||
|
||||
public static implicit operator HidBool(bool value)
|
||||
{
|
||||
return new HidBool() { _value = value ? 1u : 0u };
|
||||
}
|
||||
}
|
||||
|
||||
struct MousePosition
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
public int VelocityX;
|
||||
public int VelocityY;
|
||||
public int ScrollVelocityX;
|
||||
public int ScrollVelocityY;
|
||||
}
|
||||
|
||||
struct HidVector
|
||||
{
|
||||
public float X;
|
||||
public float Y;
|
||||
public float Z;
|
||||
}
|
||||
|
||||
struct SixAxisSensorValues
|
||||
{
|
||||
public HidVector Accelerometer;
|
||||
public HidVector Gyroscope;
|
||||
public HidVector Unk;
|
||||
public Array3<HidVector> Orientation;
|
||||
}
|
||||
|
||||
struct HidTouchScreenHeader
|
||||
{
|
||||
public ulong TimestampTicks;
|
||||
public ulong NumEntries;
|
||||
public ulong LatestEntry;
|
||||
public ulong MaxEntryIndex;
|
||||
public ulong Timestamp;
|
||||
}
|
||||
|
||||
struct HidTouchScreenEntryHeader
|
||||
{
|
||||
public ulong Timestamp;
|
||||
public ulong NumTouches;
|
||||
}
|
||||
|
||||
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 Padding2;
|
||||
}
|
||||
|
||||
struct HidTouchScreenEntry
|
||||
{
|
||||
public HidTouchScreenEntryHeader Header;
|
||||
public Array16<HidTouchScreenEntryTouch> Touches;
|
||||
public ulong Unk;
|
||||
}
|
||||
|
||||
unsafe struct HidTouchScreen
|
||||
{
|
||||
public HidTouchScreenHeader Header;
|
||||
public Array17<HidTouchScreenEntry> Entries;
|
||||
public fixed byte Padding[0x3c0];
|
||||
}
|
||||
|
||||
struct HidMouseHeader
|
||||
{
|
||||
public ulong TimestampTicks;
|
||||
public ulong NumEntries;
|
||||
public ulong LatestEntry;
|
||||
public ulong MaxEntryIndex;
|
||||
}
|
||||
|
||||
struct HidMouseEntry
|
||||
{
|
||||
public ulong Timestamp;
|
||||
public ulong Timestamp_2;
|
||||
public MousePosition Position;
|
||||
public ulong Buttons;
|
||||
}
|
||||
|
||||
unsafe struct HidMouse
|
||||
{
|
||||
public HidMouseHeader Header;
|
||||
public Array17<HidMouseEntry> Entries;
|
||||
public fixed byte Padding[0xB0];
|
||||
}
|
||||
|
||||
struct HidKeyboardHeader
|
||||
{
|
||||
public ulong TimestampTicks;
|
||||
public ulong NumEntries;
|
||||
public ulong LatestEntry;
|
||||
public ulong MaxEntryIndex;
|
||||
}
|
||||
|
||||
unsafe struct HidKeyboardEntry
|
||||
{
|
||||
public ulong Timestamp;
|
||||
public ulong Timestamp2;
|
||||
public ulong Modifier;
|
||||
public fixed uint Keys[8];
|
||||
}
|
||||
|
||||
unsafe struct HidKeyboard
|
||||
{
|
||||
public HidKeyboardHeader Header;
|
||||
public Array17<HidKeyboardEntry> Entries;
|
||||
public fixed byte Padding[0x28];
|
||||
}
|
||||
|
||||
unsafe struct HidControllerMAC
|
||||
{
|
||||
public ulong Timestamp;
|
||||
public fixed byte Mac[0x8];
|
||||
public ulong Unk;
|
||||
public ulong Timestamp2;
|
||||
}
|
||||
|
||||
struct HidControllerHeader
|
||||
{
|
||||
public ControllerStatus Type;
|
||||
public HidBool IsHalf;
|
||||
public ControllerColorDescription SingleColorsDescriptor;
|
||||
public NpadColor SingleColorBody;
|
||||
public NpadColor SingleColorButtons;
|
||||
public ControllerColorDescription SplitColorsDescriptor;
|
||||
public NpadColor LeftColorBody;
|
||||
public NpadColor LeftColorButtons;
|
||||
public NpadColor RightColorBody;
|
||||
public NpadColor RightColorButtons;
|
||||
}
|
||||
|
||||
struct HidControllerLayoutHeader
|
||||
{
|
||||
public ulong TimestampTicks;
|
||||
public ulong NumEntries;
|
||||
public ulong LatestEntry;
|
||||
public ulong MaxEntryIndex;
|
||||
}
|
||||
|
||||
struct HidControllerInputEntry
|
||||
{
|
||||
public ulong Timestamp;
|
||||
public ulong Timestamp2;
|
||||
public ControllerButtons Buttons;
|
||||
public Array2<JoystickPosition> Joysticks;
|
||||
public ControllerConnectionState ConnectionState;
|
||||
}
|
||||
|
||||
struct HidControllerLayout
|
||||
{
|
||||
public HidControllerLayoutHeader Header;
|
||||
public Array17<HidControllerInputEntry> Entries;
|
||||
}
|
||||
|
||||
struct HidControllerSixAxisHeader
|
||||
{
|
||||
public ulong Timestamp;
|
||||
public ulong NumEntries;
|
||||
public ulong LatestEntry;
|
||||
public ulong MaxEntryIndex;
|
||||
}
|
||||
|
||||
struct HidControllerSixAxisEntry
|
||||
{
|
||||
public ulong Timestamp;
|
||||
public ulong Unk1;
|
||||
public ulong Timestamp2;
|
||||
public SixAxisSensorValues Values;
|
||||
public ulong Unk3;
|
||||
}
|
||||
|
||||
struct HidControllerSixAxisLayout
|
||||
{
|
||||
public HidControllerSixAxisHeader Header;
|
||||
public Array17<HidControllerSixAxisEntry> Entries;
|
||||
}
|
||||
|
||||
unsafe struct HidControllerMisc
|
||||
{
|
||||
public ControllerDeviceType DeviceType;
|
||||
public uint Padding;
|
||||
public DeviceFlags DeviceFlags;
|
||||
public uint UnintendedHomeButtonInputProtectionEnabled;
|
||||
public BatteryState PowerInfo0BatteryState;
|
||||
public BatteryState PowerInfo1BatteryState;
|
||||
public BatteryState PowerInfo2BatteryState;
|
||||
public fixed byte Unk1[0x20];
|
||||
HidControllerMAC MacLeft;
|
||||
HidControllerMAC MacRight;
|
||||
}
|
||||
|
||||
unsafe struct HidController
|
||||
{
|
||||
public HidControllerHeader Header;
|
||||
public Array7<HidControllerLayout> Layouts;
|
||||
public Array6<HidControllerSixAxisLayout> Sixaxis;
|
||||
public HidControllerMisc Misc;
|
||||
public fixed byte Unk2[0xDF8];
|
||||
}
|
||||
|
||||
unsafe struct HidSharedMemory
|
||||
{
|
||||
public fixed byte Header[0x400];
|
||||
public HidTouchScreen Touchscreen;
|
||||
public HidMouse Mouse;
|
||||
public HidKeyboard Keyboard;
|
||||
public fixed byte UnkSection1[0x400];
|
||||
public fixed byte UnkSection2[0x400];
|
||||
public fixed byte UnkSection3[0x400];
|
||||
public fixed byte UnkSection4[0x400];
|
||||
public fixed byte UnkSection5[0x200];
|
||||
public fixed byte UnkSection6[0x200];
|
||||
public fixed byte UnkSection7[0x200];
|
||||
public fixed byte UnkSection8[0x800];
|
||||
public fixed byte ControllerSerials[0x4000];
|
||||
public Array10<HidController> Controllers;
|
||||
public fixed byte UnkSection9[0x4600];
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ namespace Ryujinx.HLE.Input
|
|||
{
|
||||
public struct Keyboard
|
||||
{
|
||||
public int Modifier;
|
||||
public int[] Keys;
|
||||
public uint Modifier;
|
||||
public uint[] Keys;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.Input
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct KeyboardEntry
|
||||
{
|
||||
public long SamplesTimestamp;
|
||||
public long SamplesTimestamp2;
|
||||
public long Modifier;
|
||||
public fixed int Keys[8];
|
||||
}
|
||||
}
|
|
@ -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,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;
|
||||
}
|
||||
}
|
|
@ -2,10 +2,10 @@ namespace Ryujinx.HLE.Input
|
|||
{
|
||||
public struct TouchPoint
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
public int DiameterX;
|
||||
public int DiameterY;
|
||||
public int Angle;
|
||||
public uint X;
|
||||
public uint Y;
|
||||
public uint DiameterX;
|
||||
public uint DiameterY;
|
||||
public uint Angle;
|
||||
}
|
||||
}
|
|
@ -185,7 +185,7 @@ namespace Ryujinx.Ui
|
|||
hidKeyboard = new HLE.Input.Keyboard
|
||||
{
|
||||
Modifier = 0,
|
||||
Keys = new int[0x8]
|
||||
Keys = new uint[0x8]
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -214,7 +214,7 @@ namespace Ryujinx.Ui
|
|||
Dy = rightJoystickDy
|
||||
};
|
||||
|
||||
currentButton |= _device.Hid.UpdateStickButtons(leftJoystick, rightJoystick);
|
||||
currentButton |= Hid.UpdateStickButtons(leftJoystick, rightJoystick);
|
||||
|
||||
bool hasTouch = false;
|
||||
|
||||
|
@ -255,8 +255,8 @@ namespace Ryujinx.Ui
|
|||
|
||||
TouchPoint currentPoint = new TouchPoint
|
||||
{
|
||||
X = mX,
|
||||
Y = mY,
|
||||
X = (uint)mX,
|
||||
Y = (uint)mY,
|
||||
|
||||
// Placeholder values till more data is acquired
|
||||
DiameterX = 10,
|
||||
|
|
|
@ -221,21 +221,21 @@ namespace Ryujinx.Ui
|
|||
HLE.Input.Keyboard hidKeyboard = new HLE.Input.Keyboard
|
||||
{
|
||||
Modifier = 0,
|
||||
Keys = new int[0x8]
|
||||
Keys = new uint[0x8]
|
||||
};
|
||||
|
||||
foreach (KeyMappingEntry entry in KeyMapping)
|
||||
{
|
||||
int value = keyboard[entry.TargetKey] ? 1 : 0;
|
||||
|
||||
hidKeyboard.Keys[entry.Target / 0x20] |= (value << (entry.Target % 0x20));
|
||||
hidKeyboard.Keys[entry.Target / 0x20] |= (uint)value << (entry.Target % 0x20);
|
||||
}
|
||||
|
||||
foreach (KeyMappingEntry entry in KeyModifierMapping)
|
||||
{
|
||||
int value = keyboard[entry.TargetKey] ? 1 : 0;
|
||||
|
||||
hidKeyboard.Modifier |= value << entry.Target;
|
||||
hidKeyboard.Modifier |= (uint)value << entry.Target;
|
||||
}
|
||||
|
||||
return hidKeyboard;
|
||||
|
|
Loading…
Add table
Reference in a new issue