using System; using System.Runtime.InteropServices; using UnityEngine.InputSystem.Utilities; namespace UnityEngine.InputSystem.LowLevel { /// /// Query the ID and the name of the user paired to the device the command is sent to. /// /// /// This command is only supported on platforms where devices can be paired to user accounts /// at the platform level. Currently this is the case for Xbox and PS4. On Switch, is supported but the platform does not store /// associations established between devices and users that way. /// [StructLayout(LayoutKind.Explicit, Size = kSize)] public unsafe struct QueryPairedUserAccountCommand : IInputDeviceCommandInfo { public static FourCC Type => new FourCC('P', 'A', 'C', 'C'); internal const int kMaxNameLength = 256; internal const int kMaxIdLength = 256; ////REVIEW: is this too heavy to allocate on the stack? internal const int kSize = InputDeviceCommand.kBaseCommandSize + 8 + kMaxNameLength * 2 + kMaxIdLength * 2; [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1714:FlagsEnumsShouldHavePluralNames", Justification = "`Result` matches other command result names")] [Flags] public enum Result : long { // Leave bit #0 unused so as to not lead to possible confusion with GenericSuccess. /// /// The device is currently paired to a user account. /// DevicePairedToUserAccount = 1 << 1, /// /// The system is currently displaying a prompt for the user to select an account to /// use the device with. /// UserAccountSelectionInProgress = 1 << 2, /// /// User account selection completed. /// UserAccountSelectionComplete = 1 << 3, /// /// The system had been displaying a prompt /// UserAccountSelectionCanceled = 1 << 4, } [FieldOffset(0)] public InputDeviceCommand baseCommand; /// /// Handle of the user account at the platform level. /// /// /// Note that this is wide enough to store a pointer and does not necessarily need to be a plain integer. /// How the backend determines handles for user accounts is up to the backend. /// /// Be aware that a handle is not guaranteed to be valid beyond the current application run. For stable, /// persistent user account handles,use . /// [FieldOffset(InputDeviceCommand.kBaseCommandSize)] public ulong handle; [FieldOffset(InputDeviceCommand.kBaseCommandSize + 8)] internal fixed byte nameBuffer[kMaxNameLength * 2]; [FieldOffset(InputDeviceCommand.kBaseCommandSize + 8 + kMaxNameLength * 2)] internal fixed byte idBuffer[kMaxNameLength * 2]; /// /// Persistent ID of the user account the platform level. /// /// /// This ID is guaranteed to not change between application runs, device restarts, and the user /// changing user names on the account. /// /// Use this ID to associate persistent settings with. /// public string id { get { fixed(byte* idBufferPtr = idBuffer) return StringHelpers.ReadStringFromBuffer(new IntPtr(idBufferPtr), kMaxIdLength); } set { if (value == null) throw new ArgumentNullException(nameof(value)); var length = value.Length; if (length > kMaxIdLength) throw new ArgumentException($"ID '{value}' exceeds maximum supported length of {kMaxIdLength} characters", nameof(value)); fixed(byte* idBufferPtr = idBuffer) { StringHelpers.WriteStringToBuffer(value, new IntPtr(idBufferPtr), kMaxIdLength); } } } /// /// Name of the user account at the platform level. /// public string name { get { fixed(byte* nameBufferPtr = nameBuffer) return StringHelpers.ReadStringFromBuffer(new IntPtr(nameBufferPtr), kMaxNameLength); } set { if (value == null) throw new ArgumentNullException("value"); var length = value.Length; if (length > kMaxNameLength) throw new ArgumentException($"Name '{value}' exceeds maximum supported length of {kMaxNameLength} characters", nameof(value)); fixed(byte* nameBufferPtr = nameBuffer) { StringHelpers.WriteStringToBuffer(value, new IntPtr(nameBufferPtr), kMaxNameLength); } } } public FourCC typeStatic => Type; public static QueryPairedUserAccountCommand Create() { return new QueryPairedUserAccountCommand { baseCommand = new InputDeviceCommand(Type, kSize), }; } } }