#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX || PACKAGE_DOCS_GENERATION using System.Runtime.InteropServices; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.LowLevel; using UnityEngine.InputSystem.XInput.LowLevel; using UnityEngine.InputSystem.Utilities; using UnityEngine.Scripting; namespace UnityEngine.InputSystem.XInput.LowLevel { // Xbox one controller on OSX. State layout can be found here: // https://github.com/360Controller/360Controller/blob/master/360Controller/ControlStruct.h // struct InputReport // { // byte command; // byte size; // short buttons; // byte triggerLeft; // byte triggerRight; // short leftX; // short leftY; // short rightX; // short rightY; // } // Report size is 14 bytes. First two bytes are header information for the report. [StructLayout(LayoutKind.Explicit)] internal struct XInputControllerOSXState : IInputStateTypeInfo { public static FourCC kFormat => new FourCC('H', 'I', 'D'); public enum Button { DPadUp = 0, DPadDown = 1, DPadLeft = 2, DPadRight = 3, Start = 4, Select = 5, LeftThumbstickPress = 6, RightThumbstickPress = 7, LeftShoulder = 8, RightShoulder = 9, A = 12, B = 13, X = 14, Y = 15, } [FieldOffset(0)] private ushort padding; [InputControl(name = "dpad", layout = "Dpad", sizeInBits = 4, bit = 0)] [InputControl(name = "dpad/up", bit = (uint)Button.DPadUp)] [InputControl(name = "dpad/down", bit = (uint)Button.DPadDown)] [InputControl(name = "dpad/left", bit = (uint)Button.DPadLeft)] [InputControl(name = "dpad/right", bit = (uint)Button.DPadRight)] [InputControl(name = "start", bit = (uint)Button.Start, displayName = "Start")] [InputControl(name = "select", bit = (uint)Button.Select, displayName = "Select")] [InputControl(name = "leftStickPress", bit = (uint)Button.LeftThumbstickPress)] [InputControl(name = "rightStickPress", bit = (uint)Button.RightThumbstickPress)] [InputControl(name = "leftShoulder", bit = (uint)Button.LeftShoulder)] [InputControl(name = "rightShoulder", bit = (uint)Button.RightShoulder)] [InputControl(name = "buttonSouth", bit = (uint)Button.A, displayName = "A")] [InputControl(name = "buttonEast", bit = (uint)Button.B, displayName = "B")] [InputControl(name = "buttonWest", bit = (uint)Button.X, displayName = "X")] [InputControl(name = "buttonNorth", bit = (uint)Button.Y, displayName = "Y")] [FieldOffset(2)] public ushort buttons; [InputControl(name = "leftTrigger", format = "BYTE")] [FieldOffset(4)] public byte leftTrigger; [InputControl(name = "rightTrigger", format = "BYTE")] [FieldOffset(5)] public byte rightTrigger; [InputControl(name = "leftStick", layout = "Stick", format = "VC2S")] [InputControl(name = "leftStick/x", offset = 0, format = "SHRT", parameters = "")] [InputControl(name = "leftStick/left", offset = 0, format = "SHRT", parameters = "")] [InputControl(name = "leftStick/right", offset = 0, format = "SHRT", parameters = "")] [InputControl(name = "leftStick/y", offset = 2, format = "SHRT", parameters = "invert")] [InputControl(name = "leftStick/up", offset = 2, format = "SHRT", parameters = "clamp=1,clampMin=-1,clampMax=0,invert=true")] [InputControl(name = "leftStick/down", offset = 2, format = "SHRT", parameters = "clamp=1,clampMin=0,clampMax=1,invert=false")] [FieldOffset(6)] public short leftStickX; [FieldOffset(8)] public short leftStickY; [InputControl(name = "rightStick", layout = "Stick", format = "VC2S")] [InputControl(name = "rightStick/x", offset = 0, format = "SHRT", parameters = "")] [InputControl(name = "rightStick/left", offset = 0, format = "SHRT", parameters = "")] [InputControl(name = "rightStick/right", offset = 0, format = "SHRT", parameters = "")] [InputControl(name = "rightStick/y", offset = 2, format = "SHRT", parameters = "invert")] [InputControl(name = "rightStick/up", offset = 2, format = "SHRT", parameters = "clamp=1,clampMin=-1,clampMax=0,invert=true")] [InputControl(name = "rightStick/down", offset = 2, format = "SHRT", parameters = "clamp=1,clampMin=0,clampMax=1,invert=false")] [FieldOffset(10)] public short rightStickX; [FieldOffset(12)] public short rightStickY; public FourCC format => kFormat; public XInputControllerOSXState WithButton(Button button) { Debug.Assert((int)button < 16, $"Expected button < 16, so we fit into the 16 bit wide bitmask"); buttons |= (ushort)(1U << (int)button); return this; } } [StructLayout(LayoutKind.Explicit)] internal struct XInputControllerWirelessOSXState : IInputStateTypeInfo { public static FourCC kFormat => new FourCC('H', 'I', 'D'); public enum Button { Start = 11, Select = 16, LeftThumbstickPress = 13, RightThumbstickPress = 14, LeftShoulder = 6, RightShoulder = 7, A = 0, B = 1, X = 3, Y = 4, } [FieldOffset(0)] private byte padding; [InputControl(name = "leftStick", layout = "Stick", format = "VC2S")] [InputControl(name = "leftStick/x", offset = 0, format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5")] [InputControl(name = "leftStick/left", offset = 0, format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=1,clampMin=0,clampMax=0.5,invert")] [InputControl(name = "leftStick/right", offset = 0, format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=1,clampMin=0.5,clampMax=1")] [InputControl(name = "leftStick/y", offset = 2, format = "USHT", parameters = "invert,normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5")] [InputControl(name = "leftStick/up", offset = 2, format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=1,clampMin=0,clampMax=0.5,invert")] [InputControl(name = "leftStick/down", offset = 2, format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=1,clampMin=0.5,clampMax=1,invert=false")] [FieldOffset(1)] public ushort leftStickX; [FieldOffset(3)] public ushort leftStickY; [InputControl(name = "rightStick", layout = "Stick", format = "VC2S")] [InputControl(name = "rightStick/x", offset = 0, format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5")] [InputControl(name = "rightStick/left", offset = 0, format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=1,clampMin=0,clampMax=0.5,invert")] [InputControl(name = "rightStick/right", offset = 0, format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=1,clampMin=0.5,clampMax=1")] [InputControl(name = "rightStick/y", offset = 2, format = "USHT", parameters = "invert,normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5")] [InputControl(name = "rightStick/up", offset = 2, format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=1,clampMin=0,clampMax=0.5,invert")] [InputControl(name = "rightStick/down", offset = 2, format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=1,normalizeZero=0.5,clamp=1,clampMin=0.5,clampMax=1,invert=false")] [FieldOffset(5)] public ushort rightStickX; [FieldOffset(7)] public ushort rightStickY; [InputControl(name = "leftTrigger", format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=0.01560998")] [FieldOffset(9)] public ushort leftTrigger; [InputControl(name = "rightTrigger", format = "USHT", parameters = "normalize,normalizeMin=0,normalizeMax=0.01560998")] [FieldOffset(11)] public ushort rightTrigger; [InputControl(name = "dpad", format = "BIT", layout = "Dpad", sizeInBits = 4, defaultState = 8)] [InputControl(name = "dpad/up", format = "BIT", layout = "DiscreteButton", parameters = "minValue=8,maxValue=2,nullValue=0,wrapAtValue=9", bit = 0, sizeInBits = 4)] [InputControl(name = "dpad/right", format = "BIT", layout = "DiscreteButton", parameters = "minValue=2,maxValue=4", bit = 0, sizeInBits = 4)] [InputControl(name = "dpad/down", format = "BIT", layout = "DiscreteButton", parameters = "minValue=4,maxValue=6", bit = 0, sizeInBits = 4)] [InputControl(name = "dpad/left", format = "BIT", layout = "DiscreteButton", parameters = "minValue=6, maxValue=8", bit = 0, sizeInBits = 4)] [FieldOffset(13)] public byte dpad; [InputControl(name = "start", bit = (uint)Button.Start, displayName = "Start")] [InputControl(name = "select", bit = (uint)Button.Select, displayName = "Select")] [InputControl(name = "leftStickPress", bit = (uint)Button.LeftThumbstickPress)] [InputControl(name = "rightStickPress", bit = (uint)Button.RightThumbstickPress)] [InputControl(name = "leftShoulder", bit = (uint)Button.LeftShoulder)] [InputControl(name = "rightShoulder", bit = (uint)Button.RightShoulder)] [InputControl(name = "buttonSouth", bit = (uint)Button.A, displayName = "A")] [InputControl(name = "buttonEast", bit = (uint)Button.B, displayName = "B")] [InputControl(name = "buttonWest", bit = (uint)Button.X, displayName = "X")] [InputControl(name = "buttonNorth", bit = (uint)Button.Y, displayName = "Y")] [FieldOffset(14)] public uint buttons; public FourCC format => kFormat; public XInputControllerWirelessOSXState WithButton(Button button) { Debug.Assert((int)button < 32, $"Expected button < 32, so we fit into the 32 bit wide bitmask"); buttons |= 1U << (int)button; return this; } public XInputControllerWirelessOSXState WithDpad(byte value) { dpad = value; return this; } public static XInputControllerWirelessOSXState defaultState => new XInputControllerWirelessOSXState { rightStickX = 32767, rightStickY = 32767, leftStickX = 32767, leftStickY = 32767 }; } } namespace UnityEngine.InputSystem.XInput { /// /// A wired Xbox Gamepad connected to a macOS computer. /// /// /// An Xbox 360 or Xbox one wired gamepad connected to a mac. /// These controllers don't work on a mac out of the box, but require a driver like https://github.com/360Controller/ /// to work. /// [InputControlLayout(displayName = "Xbox Controller", stateType = typeof(XInputControllerOSXState), hideInUI = true)] public class XboxGamepadMacOS : XInputController { } /// /// A wireless Xbox One Gamepad connected to a macOS computer. /// /// /// An Xbox One wireless gamepad connected to a mac using Bluetooth. /// Note: only the latest version of Xbox One wireless gamepads support Bluetooth. Older models only work /// with a proprietary Xbox wireless protocol, and cannot be used on a Mac. /// Unlike wired controllers, bluetooth-cabable Xbox One controllers do not need a custom driver to work on macOS. /// [InputControlLayout(displayName = "Wireless Xbox Controller", stateType = typeof(XInputControllerWirelessOSXState), hideInUI = true)] public class XboxOneGampadMacOSWireless : XInputController { } } #endif // UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX