#if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_WSA || PACKAGE_DOCS_GENERATION
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.Switch.LowLevel;
using UnityEngine.InputSystem.Utilities;
////REVIEW: The Switch controller can be used to point at things; can we somehow help leverage that?
namespace UnityEngine.InputSystem.Switch.LowLevel
{
#if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_WSA
///
/// Structure of HID input reports for Switch Pro controllers.
///
[StructLayout(LayoutKind.Explicit, Size = 7)]
internal struct SwitchProControllerHIDInputState : IInputStateTypeInfo
{
public static FourCC Format = new FourCC('S', 'P', 'V', 'S'); // Switch Pro Virtual State
public FourCC format => Format;
[InputControl(name = "leftStick", layout = "Stick", format = "VC2B")]
[InputControl(name = "leftStick/x", offset = 0, format = "BYTE", parameters = "normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5")]
[InputControl(name = "leftStick/left", offset = 0, format = "BYTE", parameters = "normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5,clamp=1,clampMin=0.15,clampMax=0.5,invert")]
[InputControl(name = "leftStick/right", offset = 0, format = "BYTE", parameters = "normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5,clamp=1,clampMin=0.5,clampMax=0.85")]
[InputControl(name = "leftStick/y", offset = 1, format = "BYTE", parameters = "invert,normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5")]
[InputControl(name = "leftStick/up", offset = 1, format = "BYTE", parameters = "normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5,clamp=1,clampMin=0.15,clampMax=0.5,invert")]
[InputControl(name = "leftStick/down", offset = 1, format = "BYTE", parameters = "normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5,clamp=1,clampMin=0.5,clampMax=0.85,invert=false")]
[FieldOffset(0)] public byte leftStickX;
[FieldOffset(1)] public byte leftStickY;
[InputControl(name = "rightStick", layout = "Stick", format = "VC2B")]
[InputControl(name = "rightStick/x", offset = 0, format = "BYTE", parameters = "normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5")]
[InputControl(name = "rightStick/left", offset = 0, format = "BYTE", parameters = "normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5,clamp=1,clampMin=0,clampMax=0.5,invert")]
[InputControl(name = "rightStick/right", offset = 0, format = "BYTE", parameters = "normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5,clamp=1,clampMin=0.5,clampMax=1")]
[InputControl(name = "rightStick/y", offset = 1, format = "BYTE", parameters = "invert,normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5")]
[InputControl(name = "rightStick/up", offset = 1, format = "BYTE", parameters = "normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5,clamp=1,clampMin=0.15,clampMax=0.5,invert")]
[InputControl(name = "rightStick/down", offset = 1, format = "BYTE", parameters = "normalize,normalizeMin=0.15,normalizeMax=0.85,normalizeZero=0.5,clamp=1,clampMin=0.5,clampMax=0.85,invert=false")]
[FieldOffset(2)] public byte rightStickX;
[FieldOffset(3)] public byte rightStickY;
[InputControl(name = "dpad", format = "BIT", bit = 0, sizeInBits = 4)]
[InputControl(name = "dpad/up", bit = (int)Button.Up)]
[InputControl(name = "dpad/right", bit = (int)Button.Right)]
[InputControl(name = "dpad/down", bit = (int)Button.Down)]
[InputControl(name = "dpad/left", bit = (int)Button.Left)]
[InputControl(name = "buttonWest", displayName = "Y", shortDisplayName = "Y", bit = (int)Button.Y, usage = "SecondaryAction")]
[InputControl(name = "buttonNorth", displayName = "X", shortDisplayName = "X", bit = (int)Button.X)]
[InputControl(name = "buttonSouth", displayName = "B", shortDisplayName = "B", bit = (int)Button.B, usage = "Back")]
[InputControl(name = "buttonEast", displayName = "A", shortDisplayName = "A", bit = (int)Button.A, usage = "PrimaryAction")]
[InputControl(name = "leftShoulder", displayName = "L", shortDisplayName = "L", bit = (uint)Button.L)]
[InputControl(name = "rightShoulder", displayName = "R", shortDisplayName = "R", bit = (uint)Button.R)]
[InputControl(name = "leftStickPress", displayName = "Left Stick", bit = (uint)Button.StickL)]
[InputControl(name = "rightStickPress", displayName = "Right Stick", bit = (uint)Button.StickR)]
[InputControl(name = "leftTrigger", displayName = "ZL", shortDisplayName = "ZL", format = "BIT", bit = (uint)Button.ZL)]
[InputControl(name = "rightTrigger", displayName = "ZR", shortDisplayName = "ZR", format = "BIT", bit = (uint)Button.ZR)]
[InputControl(name = "start", displayName = "Plus", bit = (uint)Button.Plus, usage = "Menu")]
[InputControl(name = "select", displayName = "Minus", bit = (uint)Button.Minus)]
[FieldOffset(4)] public ushort buttons1;
[InputControl(name = "capture", layout = "Button", displayName = "Capture", bit = (uint)Button.Capture - 16)]
[InputControl(name = "home", layout = "Button", displayName = "Home", bit = (uint)Button.Home - 16)]
[FieldOffset(6)] public byte buttons2;
public enum Button
{
Up = 0,
Right = 1,
Down = 2,
Left = 3,
West = 4,
North = 5,
South = 6,
East = 7,
L = 8,
R = 9,
StickL = 10,
StickR = 11,
ZL = 12,
ZR = 13,
Plus = 14,
Minus = 15,
Capture = 16,
Home = 17,
X = North,
B = South,
Y = West,
A = East,
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public SwitchProControllerHIDInputState WithButton(Button button, bool value = true)
{
Set(button, value);
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Set(Button button, bool state)
{
Debug.Assert((int)button < 18, $"Expected button < 18");
if ((int)button < 16)
{
var bit = (ushort)(1U << (int)button);
if (state)
buttons1 = (ushort)(buttons1 | bit);
else
buttons1 &= (ushort)~bit;
}
else if ((int)button < 18)
{
var bit = (byte)(1U << ((int)button - 16));
if (state)
buttons2 = (byte)(buttons2 | bit);
else
buttons2 &= (byte)~bit;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Press(Button button)
{
Set(button, true);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Release(Button button)
{
Set(button, false);
}
}
#endif
}
namespace UnityEngine.InputSystem.Switch
{
#if UNITY_EDITOR || UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || UNITY_WSA || PACKAGE_DOCS_GENERATION
///
/// A Nintendo Switch Pro controller connected to a desktop mac/windows PC using the HID interface.
///
[InputControlLayout(stateType = typeof(SwitchProControllerHIDInputState), displayName = "Switch Pro Controller")]
public class SwitchProControllerHID : Gamepad, IInputStateCallbackReceiver, IEventPreProcessor
{
[InputControl(name = "capture", displayName = "Capture")]
public ButtonControl captureButton { get; protected set; }
[InputControl(name = "home", displayName = "Home")]
public ButtonControl homeButton { get; protected set; }
protected override void OnAdded()
{
base.OnAdded();
captureButton = GetChildControl("capture");
homeButton = GetChildControl("home");
HandshakeRestart();
}
private static readonly SwitchMagicOutputReport.CommandIdType[] s_HandshakeSequence = new[]
{
SwitchMagicOutputReport.CommandIdType.Status,
SwitchMagicOutputReport.CommandIdType.Handshake,
SwitchMagicOutputReport.CommandIdType.Highspeed,
SwitchMagicOutputReport.CommandIdType.Handshake,
SwitchMagicOutputReport.CommandIdType.ForceUSB
////TODO: Should we add a step to revert back to simple interface?
//// Because currently full reports don't work in old input system.
};
private int m_HandshakeStepIndex;
private double m_HandshakeTimer;
private void HandshakeRestart()
{
// Delay first command issue until some time into the future
m_HandshakeStepIndex = -1;
m_HandshakeTimer = InputRuntime.s_Instance.currentTime;
}
private void HandshakeTick()
{
const double handshakeRestartTimeout = 2.0;
const double handshakeNextStepTimeout = 0.1;
var currentTime = InputRuntime.s_Instance.currentTime;
// There were no events for last few seconds, restart handshake
if (currentTime >= m_LastUpdateTimeInternal + handshakeRestartTimeout &&
currentTime >= m_HandshakeTimer + handshakeRestartTimeout)
m_HandshakeStepIndex = 0;
// If handshake is complete, ignore the tick.
else if (m_HandshakeStepIndex + 1 >= s_HandshakeSequence.Length)
return;
// If we timeout, proceed to next step after some time is elapsed.
else if (currentTime > m_HandshakeTimer + handshakeNextStepTimeout)
m_HandshakeStepIndex++;
// If we haven't timed out on handshake step, skip the tick.
else
return;
m_HandshakeTimer = currentTime;
var command = s_HandshakeSequence[m_HandshakeStepIndex];
// Native backend rejects one of the commands based on size of descriptor.
// So just report both at a same time.
////TODO: fix this.
var commandBt = SwitchMagicOutputHIDBluetooth.Create(command);
if (ExecuteCommand(ref commandBt) > 0)
return;
var commandUsb = SwitchMagicOutputHIDUSB.Create(command);
ExecuteCommand(ref commandUsb);
}
public void OnNextUpdate()
{
HandshakeTick();
}
public void OnStateEvent(InputEventPtr eventPtr)
{
InputState.Change(this, eventPtr);
}
public bool GetStateOffsetForEvent(InputControl control, InputEventPtr eventPtr, ref uint offset)
{
return false;
}
public unsafe bool PreProcessEvent(InputEventPtr eventPtr)
{
if (eventPtr.type == DeltaStateEvent.Type)
// if someone queued delta state SPVS directly, just use as-is
// otherwise skip all delta state events
return DeltaStateEvent.FromUnchecked(eventPtr)->stateFormat == SwitchProControllerHIDInputState.Format;
// use all other non-state/non-delta-state events
if (eventPtr.type != StateEvent.Type)
return true;
var stateEvent = StateEvent.FromUnchecked(eventPtr);
var size = stateEvent->stateSizeInBytes;
if (stateEvent->stateFormat == SwitchProControllerHIDInputState.Format)
return true; // if someone queued SPVS directly, just use as-is
if (stateEvent->stateFormat != SwitchHIDGenericInputReport.Format || size < sizeof(SwitchHIDGenericInputReport))
return false; // skip unrecognized state events otherwise they will corrupt control states
var genericReport = (SwitchHIDGenericInputReport*)stateEvent->state;
if (genericReport->reportId == SwitchSimpleInputReport.ExpectedReportId && size >= SwitchSimpleInputReport.kSize)
{
var data = ((SwitchSimpleInputReport*)stateEvent->state)->ToHIDInputReport();
*((SwitchProControllerHIDInputState*)stateEvent->state) = data;
stateEvent->stateFormat = SwitchProControllerHIDInputState.Format;
return true;
}
else if (genericReport->reportId == SwitchFullInputReport.ExpectedReportId && size >= SwitchFullInputReport.kSize)
{
var data = ((SwitchFullInputReport*)stateEvent->state)->ToHIDInputReport();
*((SwitchProControllerHIDInputState*)stateEvent->state) = data;
stateEvent->stateFormat = SwitchProControllerHIDInputState.Format;
return true;
}
else if (size == 8 || size == 9) // official accessories send 8 byte reports
{
// On Windows HID stack we somehow get 1 byte extra prepended, so if we get 9 bytes, subtract one, see ISX-993
// This is written in such way that if we fix it in backend, we wont break the package (Unity will report 8 bytes instead of 9 bytes).
var bugOffset = size == 9 ? 1 : 0;
var data = ((SwitchInputOnlyReport*)((byte*)stateEvent->state + bugOffset))->ToHIDInputReport();
*((SwitchProControllerHIDInputState*)stateEvent->state) = data;
stateEvent->stateFormat = SwitchProControllerHIDInputState.Format;
return true;
}
else
return false; // skip unrecognized reportId
}
[StructLayout(LayoutKind.Explicit, Size = kSize)]
private struct SwitchInputOnlyReport
{
public const int kSize = 7;
[FieldOffset(0)] public byte buttons0;
[FieldOffset(1)] public byte buttons1;
[FieldOffset(2)] public byte hat;
[FieldOffset(3)] public byte leftX;
[FieldOffset(4)] public byte leftY;
[FieldOffset(5)] public byte rightX;
[FieldOffset(6)] public byte rightY;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public SwitchProControllerHIDInputState ToHIDInputReport()
{
var state = new SwitchProControllerHIDInputState
{
leftStickX = leftX,
leftStickY = leftY,
rightStickX = rightX,
rightStickY = rightY
};
state.Set(SwitchProControllerHIDInputState.Button.Y, (buttons0 & 0x01) != 0);
state.Set(SwitchProControllerHIDInputState.Button.B, (buttons0 & 0x02) != 0);
state.Set(SwitchProControllerHIDInputState.Button.A, (buttons0 & 0x04) != 0);
state.Set(SwitchProControllerHIDInputState.Button.X, (buttons0 & 0x08) != 0);
state.Set(SwitchProControllerHIDInputState.Button.L, (buttons0 & 0x10) != 0);
state.Set(SwitchProControllerHIDInputState.Button.R, (buttons0 & 0x20) != 0);
state.Set(SwitchProControllerHIDInputState.Button.ZL, (buttons0 & 0x40) != 0);
state.Set(SwitchProControllerHIDInputState.Button.ZR, (buttons0 & 0x80) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Minus, (buttons1 & 0x01) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Plus, (buttons1 & 0x02) != 0);
state.Set(SwitchProControllerHIDInputState.Button.StickL, (buttons1 & 0x04) != 0);
state.Set(SwitchProControllerHIDInputState.Button.StickR, (buttons1 & 0x08) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Home, (buttons1 & 0x10) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Capture, (buttons1 & 0x20) != 0);
var left = false;
var up = false;
var right = false;
var down = false;
switch (hat)
{
case 0:
up = true;
break;
case 1:
up = true;
right = true;
break;
case 2:
right = true;
break;
case 3:
down = true;
right = true;
break;
case 4:
down = true;
break;
case 5:
down = true;
left = true;
break;
case 6:
left = true;
break;
case 7:
up = true;
left = true;
break;
}
state.Set(SwitchProControllerHIDInputState.Button.Left, left);
state.Set(SwitchProControllerHIDInputState.Button.Up, up);
state.Set(SwitchProControllerHIDInputState.Button.Right, right);
state.Set(SwitchProControllerHIDInputState.Button.Down, down);
return state;
}
}
[StructLayout(LayoutKind.Explicit, Size = kSize)]
private struct SwitchSimpleInputReport
{
public const int kSize = 12;
public const byte ExpectedReportId = 0x3f;
[FieldOffset(0)] public byte reportId;
[FieldOffset(1)] public byte buttons0;
[FieldOffset(2)] public byte buttons1;
[FieldOffset(3)] public byte hat;
[FieldOffset(4)] public ushort leftX;
[FieldOffset(6)] public ushort leftY;
[FieldOffset(8)] public ushort rightX;
[FieldOffset(10)] public ushort rightY;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public SwitchProControllerHIDInputState ToHIDInputReport()
{
var leftXByte = (byte)NumberHelpers.RemapUIntBitsToNormalizeFloatToUIntBits(leftX, 16, 8);
var leftYByte = (byte)NumberHelpers.RemapUIntBitsToNormalizeFloatToUIntBits(leftY, 16, 8);
var rightXByte = (byte)NumberHelpers.RemapUIntBitsToNormalizeFloatToUIntBits(rightX, 16, 8);
var rightYByte = (byte)NumberHelpers.RemapUIntBitsToNormalizeFloatToUIntBits(rightY, 16, 8);
var state = new SwitchProControllerHIDInputState
{
leftStickX = leftXByte,
leftStickY = leftYByte,
rightStickX = rightXByte,
rightStickY = rightYByte
};
state.Set(SwitchProControllerHIDInputState.Button.B, (buttons0 & 0x01) != 0);
state.Set(SwitchProControllerHIDInputState.Button.A, (buttons0 & 0x02) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Y, (buttons0 & 0x04) != 0);
state.Set(SwitchProControllerHIDInputState.Button.X, (buttons0 & 0x08) != 0);
state.Set(SwitchProControllerHIDInputState.Button.L, (buttons0 & 0x10) != 0);
state.Set(SwitchProControllerHIDInputState.Button.R, (buttons0 & 0x20) != 0);
state.Set(SwitchProControllerHIDInputState.Button.ZL, (buttons0 & 0x40) != 0);
state.Set(SwitchProControllerHIDInputState.Button.ZR, (buttons0 & 0x80) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Minus, (buttons1 & 0x01) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Plus, (buttons1 & 0x02) != 0);
state.Set(SwitchProControllerHIDInputState.Button.StickL, (buttons1 & 0x04) != 0);
state.Set(SwitchProControllerHIDInputState.Button.StickR, (buttons1 & 0x08) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Home, (buttons1 & 0x10) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Capture, (buttons1 & 0x20) != 0);
var left = false;
var up = false;
var right = false;
var down = false;
switch (hat)
{
case 0:
up = true;
break;
case 1:
up = true;
right = true;
break;
case 2:
right = true;
break;
case 3:
down = true;
right = true;
break;
case 4:
down = true;
break;
case 5:
down = true;
left = true;
break;
case 6:
left = true;
break;
case 7:
up = true;
left = true;
break;
}
state.Set(SwitchProControllerHIDInputState.Button.Left, left);
state.Set(SwitchProControllerHIDInputState.Button.Up, up);
state.Set(SwitchProControllerHIDInputState.Button.Right, right);
state.Set(SwitchProControllerHIDInputState.Button.Down, down);
return state;
}
}
[StructLayout(LayoutKind.Explicit, Size = kSize)]
private struct SwitchFullInputReport
{
public const int kSize = 25;
public const byte ExpectedReportId = 0x30;
[FieldOffset(0)] public byte reportId;
[FieldOffset(3)] public byte buttons0;
[FieldOffset(4)] public byte buttons1;
[FieldOffset(5)] public byte buttons2;
[FieldOffset(6)] public byte left0;
[FieldOffset(7)] public byte left1;
[FieldOffset(8)] public byte left2;
[FieldOffset(9)] public byte right0;
[FieldOffset(10)] public byte right1;
[FieldOffset(11)] public byte right2;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public SwitchProControllerHIDInputState ToHIDInputReport()
{
////TODO: calibration curve
var leftXRaw = (uint)(left0 | ((left1 & 0x0F) << 8));
var leftYRaw = (uint)(((left1 & 0xF0) >> 4) | (left2 << 4));
var rightXRaw = (uint)(right0 | ((right1 & 0x0F) << 8));
var rightYRaw = (uint)(((right1 & 0xF0) >> 4) | (right2 << 4));
var leftXByte = (byte)NumberHelpers.RemapUIntBitsToNormalizeFloatToUIntBits(leftXRaw, 12, 8);
var leftYByte = (byte)(0xff - (byte)NumberHelpers.RemapUIntBitsToNormalizeFloatToUIntBits(leftYRaw, 12, 8));
var rightXByte = (byte)NumberHelpers.RemapUIntBitsToNormalizeFloatToUIntBits(rightXRaw, 12, 8);
var rightYByte = (byte)(0xff - (byte)NumberHelpers.RemapUIntBitsToNormalizeFloatToUIntBits(rightYRaw, 12, 8));
var state = new SwitchProControllerHIDInputState
{
leftStickX = leftXByte,
leftStickY = leftYByte,
rightStickX = rightXByte,
rightStickY = rightYByte
};
state.Set(SwitchProControllerHIDInputState.Button.Y, (buttons0 & 0x01) != 0);
state.Set(SwitchProControllerHIDInputState.Button.X, (buttons0 & 0x02) != 0);
state.Set(SwitchProControllerHIDInputState.Button.B, (buttons0 & 0x04) != 0);
state.Set(SwitchProControllerHIDInputState.Button.A, (buttons0 & 0x08) != 0);
state.Set(SwitchProControllerHIDInputState.Button.R, (buttons0 & 0x40) != 0);
state.Set(SwitchProControllerHIDInputState.Button.ZR, (buttons0 & 0x80) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Minus, (buttons1 & 0x01) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Plus, (buttons1 & 0x02) != 0);
state.Set(SwitchProControllerHIDInputState.Button.StickR, (buttons1 & 0x04) != 0);
state.Set(SwitchProControllerHIDInputState.Button.StickL, (buttons1 & 0x08) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Home, (buttons1 & 0x10) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Capture, (buttons1 & 0x20) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Down, (buttons2 & 0x01) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Up, (buttons2 & 0x02) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Right, (buttons2 & 0x04) != 0);
state.Set(SwitchProControllerHIDInputState.Button.Left, (buttons2 & 0x08) != 0);
state.Set(SwitchProControllerHIDInputState.Button.L, (buttons2 & 0x40) != 0);
state.Set(SwitchProControllerHIDInputState.Button.ZL, (buttons2 & 0x80) != 0);
return state;
}
}
[StructLayout(LayoutKind.Explicit)]
private struct SwitchHIDGenericInputReport
{
public static FourCC Format => new FourCC('H', 'I', 'D');
[FieldOffset(0)] public byte reportId;
}
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal struct SwitchMagicOutputReport
{
public const int kSize = 49;
public const byte ExpectedReplyInputReportId = 0x81;
[FieldOffset(0)] public byte reportType;
[FieldOffset(1)] public byte commandId;
internal enum ReportType
{
Magic = 0x80
}
public enum CommandIdType
{
Status = 0x01,
Handshake = 0x02,
Highspeed = 0x03,
ForceUSB = 0x04,
}
}
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal struct SwitchMagicOutputHIDBluetooth : IInputDeviceCommandInfo
{
public static FourCC Type => new FourCC('H', 'I', 'D', 'O');
public FourCC typeStatic => Type;
public const int kSize = InputDeviceCommand.kBaseCommandSize + 49;
[FieldOffset(0)] public InputDeviceCommand baseCommand;
[FieldOffset(InputDeviceCommand.kBaseCommandSize + 0)] public SwitchMagicOutputReport report;
public static SwitchMagicOutputHIDBluetooth Create(SwitchMagicOutputReport.CommandIdType type)
{
return new SwitchMagicOutputHIDBluetooth
{
baseCommand = new InputDeviceCommand(Type, kSize),
report = new SwitchMagicOutputReport
{
reportType = (byte)SwitchMagicOutputReport.ReportType.Magic,
commandId = (byte)type
}
};
}
}
[StructLayout(LayoutKind.Explicit, Size = kSize)]
internal struct SwitchMagicOutputHIDUSB : IInputDeviceCommandInfo
{
public static FourCC Type => new FourCC('H', 'I', 'D', 'O');
public FourCC typeStatic => Type;
public const int kSize = InputDeviceCommand.kBaseCommandSize + 64;
[FieldOffset(0)] public InputDeviceCommand baseCommand;
[FieldOffset(InputDeviceCommand.kBaseCommandSize + 0)] public SwitchMagicOutputReport report;
public static SwitchMagicOutputHIDUSB Create(SwitchMagicOutputReport.CommandIdType type)
{
return new SwitchMagicOutputHIDUSB
{
baseCommand = new InputDeviceCommand(Type, kSize),
report = new SwitchMagicOutputReport
{
reportType = (byte)SwitchMagicOutputReport.ReportType.Magic,
commandId = (byte)type
}
};
}
}
}
#endif
}
#endif // UNITY_EDITOR || UNITY_SWITCH