public SteamControllerState GetState()
        {
            if (0 == Interlocked.Exchange(ref stateUsageLock, 1))
            {
                SteamControllerState newState = new SteamControllerState();
                newState.Buttons = (SteamControllerButtons)State.Buttons.Clone();

                newState.LeftTrigger  = State.LeftTrigger;
                newState.RightTrigger = State.RightTrigger;

                newState.LeftStickX = State.LeftStickX;
                newState.LeftStickY = State.LeftStickY;
                newState.LeftPadX   = State.LeftPadX;
                newState.LeftPadY   = State.LeftPadY;
                newState.RightPadX  = State.RightPadX;
                newState.RightPadY  = State.RightPadY;

                newState.AccelerometerX   = State.AccelerometerX;
                newState.AccelerometerY   = State.AccelerometerY;
                newState.AccelerometerZ   = State.AccelerometerZ;
                newState.AngularVelocityX = State.AngularVelocityX;
                newState.AngularVelocityY = State.AngularVelocityY;
                newState.AngularVelocityZ = State.AngularVelocityZ;
                newState.OrientationW     = State.OrientationW;
                newState.OrientationX     = State.OrientationX;
                newState.OrientationY     = State.OrientationY;
                newState.OrientationZ     = State.OrientationZ;

                //newState.DataStuck = State.DataStuck;

                State = newState;
                Interlocked.Exchange(ref stateUsageLock, 0);
            }
            return(State);
        }
        public bool GetControllerState(uint controllerIndex, out SteamControllerState state)
        {
            CheckIfUsable();

            using (NativeBuffer bufferKey = new NativeBuffer(Marshal.SizeOf(typeof(SteamControllerState))))
            {
                bool result = NativeMethods.SteamController_GetControllerState(controllerIndex, bufferKey.UnmanagedMemory);
                state = NativeHelpers.ConvertStruct <SteamControllerState>(bufferKey.UnmanagedMemory, bufferKey.UnmanagedSize);

                return(result);
            }
        }
        private void OnReport(HidReport report)
        {
            if (!Initalized)
            {
                return;
            }

            if (0 == Interlocked.Exchange(ref reportUsageLock, 1))
            {
                OldState = State;
                //if (_attached == false) { return; }

                switch (ConnectionType)
                {
                case EConnectionType.BT:
                {
                    byte         Unknown1  = report.Data[0]; // always 0xC0?
                    VSCEventType EventType = (VSCEventType)report.Data[1];

                    Console.WriteLine($"Unknown Packet {report.Data.Length}\t{BitConverter.ToString(report.Data)}");
                }
                break;

                default:
                {
                    byte         Unknown1  = report.Data[0]; // always 0x01?
                    byte         Unknown2  = report.Data[1]; // always 0x00?
                    VSCEventType EventType = (VSCEventType)report.Data[2];

                    switch (EventType)
                    {
                    case 0:             // not sure what this is but wired controllers do it
                        break;

                    case VSCEventType.CONTROL_UPDATE:
                    {
                        //report.Data[3] // 0x3C?

                        UInt32 PacketIndex = BitConverter.ToUInt32(report.Data, 4);

                        State.Buttons.A            = (report.Data[8] & 128) == 128;
                        State.Buttons.X            = (report.Data[8] & 64) == 64;
                        State.Buttons.B            = (report.Data[8] & 32) == 32;
                        State.Buttons.Y            = (report.Data[8] & 16) == 16;
                        State.Buttons.LeftBumper   = (report.Data[8] & 8) == 8;
                        State.Buttons.RightBumper  = (report.Data[8] & 4) == 4;
                        State.Buttons.LeftTrigger  = (report.Data[8] & 2) == 2;
                        State.Buttons.RightTrigger = (report.Data[8] & 1) == 1;

                        State.Buttons.LeftGrip = (report.Data[9] & 128) == 128;
                        State.Buttons.Start    = (report.Data[9] & 64) == 64;
                        State.Buttons.Steam    = (report.Data[9] & 32) == 32;
                        State.Buttons.Select   = (report.Data[9] & 16) == 16;

                        State.Buttons.Down  = (report.Data[9] & 8) == 8;
                        State.Buttons.Left  = (report.Data[9] & 4) == 4;
                        State.Buttons.Right = (report.Data[9] & 2) == 2;
                        State.Buttons.Up    = (report.Data[9] & 1) == 1;

                        bool LeftAnalogMultiplexMode = (report.Data[10] & 128) == 128;
                        State.Buttons.StickClick = (report.Data[10] & 64) == 64;
                        bool Unknown = (report.Data[10] & 32) == 32;                 // what is this?
                        State.Buttons.RightPadTouch = (report.Data[10] & 16) == 16;
                        bool LeftPadTouch = (report.Data[10] & 8) == 8;
                        State.Buttons.RightPadClick = (report.Data[10] & 4) == 4;
                        bool ThumbOrLeftPadPress = (report.Data[10] & 2) == 2;                 // what is this even for?
                        State.Buttons.RightGrip = (report.Data[10] & 1) == 1;

                        State.LeftTrigger  = report.Data[11];
                        State.RightTrigger = report.Data[12];

                        if (LeftAnalogMultiplexMode)
                        {
                            if (LeftPadTouch)
                            {
                                State.Buttons.LeftPadTouch = true;
                                State.Buttons.LeftPadClick = ThumbOrLeftPadPress;
                                State.LeftPadX             = BitConverter.ToInt16(report.Data, 16);
                                State.LeftPadY             = BitConverter.ToInt16(report.Data, 18);
                            }
                            else
                            {
                                State.LeftStickX = BitConverter.ToInt16(report.Data, 16);
                                State.LeftStickY = BitConverter.ToInt16(report.Data, 18);
                            }
                        }
                        else
                        {
                            if (LeftPadTouch)
                            {
                                State.Buttons.LeftPadTouch = true;
                                State.LeftPadX             = BitConverter.ToInt16(report.Data, 16);
                                State.LeftPadY             = BitConverter.ToInt16(report.Data, 18);
                            }
                            else
                            {
                                State.Buttons.LeftPadTouch = false;
                                State.LeftStickX           = BitConverter.ToInt16(report.Data, 16);
                                State.LeftStickY           = BitConverter.ToInt16(report.Data, 18);
                                State.LeftPadX             = 0;
                                State.LeftPadY             = 0;
                            }

                            State.Buttons.LeftPadClick = ThumbOrLeftPadPress && !State.Buttons.StickClick;
                        }

                        State.RightPadX = BitConverter.ToInt16(report.Data, 20);
                        State.RightPadY = BitConverter.ToInt16(report.Data, 22);

                        /*
                         * State.DataStuck = CheckSensorDataStuck();
                         * if (!SensorsEnabled || DataStuck) { EnableGyroSensors(); }
                         */

                        State.AccelerometerX   = BitConverter.ToInt16(report.Data, 28);
                        State.AccelerometerY   = BitConverter.ToInt16(report.Data, 30);
                        State.AccelerometerZ   = BitConverter.ToInt16(report.Data, 32);
                        State.AngularVelocityX = BitConverter.ToInt16(report.Data, 34);
                        State.AngularVelocityY = BitConverter.ToInt16(report.Data, 36);
                        State.AngularVelocityZ = BitConverter.ToInt16(report.Data, 38);
                        State.OrientationW     = BitConverter.ToInt16(report.Data, 40);
                        State.OrientationX     = BitConverter.ToInt16(report.Data, 42);
                        State.OrientationY     = BitConverter.ToInt16(report.Data, 44);
                        State.OrientationZ     = BitConverter.ToInt16(report.Data, 46);
                    }
                    break;

                    case VSCEventType.CONNECTION_DETAIL:
                    {
                        //report.Data[3] // 0x01?

                        // Connection detail. 0x01 for disconnect, 0x02 for connect, 0x03 for pairing request.
                        ConnectionState ConnectionStateV = (ConnectionState)report.Data[4];

                        if (report.Data[4] == 0x01)
                        {
                            byte[] tmpBytes = new byte[4];
                            tmpBytes[1] = report.Data[5];
                            tmpBytes[2] = report.Data[6];
                            tmpBytes[3] = report.Data[7];

                            //BitConverter.ToUInt32(tmpBytes, 0); // Timestamp
                        }
                    }
                    break;

                    case VSCEventType.BATTERY_UPDATE:
                    {
                        //report.Data[3] // 0x0B?

                        UInt32 PacketIndex = BitConverter.ToUInt32(report.Data, 4);

                        // only works if controller is configured to send this data

                        // millivolts
                        UInt16 BatteryVoltage = BitConverter.ToUInt16(report.Data, 8);
                        //BitConverter.ToUInt16(report.Data, 10); // UNKNOWN, stuck at 100
                    }
                    break;

                    default:
                    {
                        Console.WriteLine($"Unknown Packet Type {(int)EventType:D3} of length {report.Data.Length}\t{BitConverter.ToString(report.Data)}");
                    }
                    break;
                    }
                }
                break;;
                }

                SteamControllerState NewState = GetState();
                OnStateUpdated(NewState);
                Interlocked.Exchange(ref reportUsageLock, 0);

                _device.ReadReport(OnReport);
            }
        }
 protected virtual void OnStateUpdated(SteamControllerState e)
 {
     StateUpdated?.Invoke(this, e);
 }