123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639 |
- #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
- /// <summary>
- /// Structure of HID input reports for Switch Pro controllers.
- /// </summary>
- [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, usages = new[] { "Back", "Cancel" })]
- [InputControl(name = "buttonEast", displayName = "A", shortDisplayName = "A", bit = (int)Button.A, usages = new[] { "PrimaryAction", "Submit" })]
- [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
- /// <summary>
- /// A Nintendo Switch Pro controller connected to a desktop mac/windows PC using the HID interface.
- /// </summary>
- [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<ButtonControl>("capture");
- homeButton = GetChildControl<ButtonControl>("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();
- }
-
- // filter out three lower bits as jitter noise
- internal const byte JitterMaskLow = 0b01111000;
- internal const byte JitterMaskHigh = 0b10000111;
-
- public unsafe void OnStateEvent(InputEventPtr eventPtr)
- {
- if (eventPtr.type == StateEvent.Type && eventPtr.stateFormat == SwitchProControllerHIDInputState.Format)
- {
- var currentState = (SwitchProControllerHIDInputState*)((byte*)currentStatePtr + m_StateBlock.byteOffset);
- var newState = (SwitchProControllerHIDInputState*)StateEvent.FromUnchecked(eventPtr)->state;
-
- var actuated =
- // we need to make device current if axes are outside of deadzone specifying hardware jitter of sticks around zero point
- newState->leftStickX<JitterMaskLow
- || newState->leftStickX> JitterMaskHigh
- || newState->leftStickY<JitterMaskLow
- || newState->leftStickY> JitterMaskHigh
- || newState->rightStickX<JitterMaskLow
- || newState->rightStickX> JitterMaskHigh
- || newState->rightStickY<JitterMaskLow
- || newState->rightStickY> JitterMaskHigh
- // we need to make device current if buttons state change
- || newState->buttons1 != currentState->buttons1
- || newState->buttons2 != currentState->buttons2;
-
- if (!actuated)
- InputSystem.s_Manager.DontMakeCurrentlyUpdatingDeviceCurrent();
- }
-
- 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
|