File size: 5,594 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Runtime.InteropServices;
using UnityEngine.InputSystem.Utilities;

namespace UnityEngine.InputSystem.LowLevel
{
    /// <summary>
    /// Query the ID and the name of the user paired to the device the command is sent to.
    /// </summary>
    /// <remarks>
    /// 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, <see
    /// cref="InitiateUserAccountPairingCommand"/> is supported but the platform does not store
    /// associations established between devices and users that way.
    /// </remarks>
    [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.

            /// <summary>
            /// The device is currently paired to a user account.
            /// </summary>
            DevicePairedToUserAccount = 1 << 1,

            /// <summary>
            /// The system is currently displaying a prompt for the user to select an account to
            /// use the device with.
            /// </summary>
            UserAccountSelectionInProgress = 1 << 2,

            /// <summary>
            /// User account selection completed.
            /// </summary>
            UserAccountSelectionComplete = 1 << 3,

            /// <summary>
            /// The system had been displaying a prompt
            /// </summary>
            UserAccountSelectionCanceled = 1 << 4,
        }

        [FieldOffset(0)]
        public InputDeviceCommand baseCommand;

        /// <summary>
        /// Handle of the user account at the platform level.
        /// </summary>
        /// <remarks>
        /// 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 <see cref="id"/>.
        /// </remarks>
        [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];

        /// <summary>
        /// Persistent ID of the user account the platform level.
        /// </summary>
        /// <remarks>
        /// 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.
        /// </remarks>
        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);
                }
            }
        }

        /// <summary>
        /// Name of the user account at the platform level.
        /// </summary>
        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),
            };
        }
    }
}