diff --git a/Packages/com.unity.inputsystem/InputSystem/Controls/InputControl.cs b/Packages/com.unity.inputsystem/InputSystem/Controls/InputControl.cs index 5cfa3b49b8..4634d67af7 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Controls/InputControl.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Controls/InputControl.cs @@ -119,11 +119,8 @@ public abstract class InputControl /// Lookup of names is case-insensitive. /// /// This is set from the name of the control in the layout. + /// See , , and . /// - /// - /// - /// - /// public string name => m_Name; ////TODO: protect against empty strings @@ -143,8 +140,9 @@ public abstract class InputControl /// For nested controls, the display name will include the display names of all parent controls, /// i.e. the display name will fully identify the control on the device. For example, the display /// name for the left D-Pad button on a gamepad is "D-Pad Left" and not just "Left". + /// + /// There is a short name version, see . /// - /// public string displayName { get @@ -173,9 +171,8 @@ public string displayName /// For nested controls, the short display name will include the short display names of all parent controls, /// that is, the display name will fully identify the control on the device. For example, the display /// name for the left D-Pad button on a gamepad is "D-Pad \u2190" and not just "\u2190". Note that if a parent - /// control has no short name, its long name will be used instead. + /// control has no short name, its long name will be used instead. See . /// - /// public string shortDisplayName { get @@ -202,11 +199,11 @@ public string shortDisplayName /// /// Allocates on first hit. Paths are not created until someone asks for them. /// + /// For more details on the path see . + /// /// /// Example: "/gamepad/leftStick/x" /// - /// - /// public string path { get @@ -218,7 +215,7 @@ public string path } /// - /// Layout the control is based on. + /// Layout name for the control it is based on. /// /// /// This is the layout name rather than a reference to an as @@ -240,25 +237,27 @@ public string path /// /// /// This is the root of the control hierarchy. For the device at the root, this - /// will point to itself. + /// will point to itself (See ). /// - /// public InputDevice device => m_Device; /// - /// The immediate parent of the control or null if the control has no parent - /// (which, once fully constructed) will only be the case for InputDevices). + /// The immediate parent of the control. /// - /// + /// + /// The immediate parent of the control or null if the control has no parent + /// (which, once fully constructed, will only be the case for InputDevices). + /// See the related field. + /// public InputControl parent => m_Parent; /// - /// List of immediate children. + /// List of immediate child controls below this. /// /// /// Does not allocate. + /// See the related field. /// - /// public ReadOnlyArray children => new ReadOnlyArray(m_Device.m_ChildrenForEachControl, m_ChildStartIndex, m_ChildCount); @@ -278,34 +277,38 @@ public string path /// control to use for certain standardized situation without having to know the particulars of /// the device or platform. /// - /// - /// - /// // Bind to any control which is tagged with the "Back" usage on any device. - /// var backAction = new InputAction(binding: "*/{Back}"); - /// - /// - /// /// Note that usages on devices work slightly differently than usages of controls on devices. /// They are also queried through this property but unlike the usages of controls, the set of /// usages of a device can be changed dynamically as the role of the device changes. For details, /// see . Controls, on the other hand, /// can currently only be assigned usages through layouts ( /// or ). + /// + /// can be used to add a device. + /// can be used to remove a device. /// - /// - /// - /// - /// - /// - /// + /// + /// + /// // Bind to any control which is tagged with the "Back" usage on any device. + /// var backAction = new InputAction(binding: "*/{Back}"); + /// + /// public ReadOnlyArray usages => new ReadOnlyArray(m_Device.m_UsagesForEachControl, m_UsageStartIndex, m_UsageCount); - // List of alternate names for the control. + /// + /// List of alternate names for the control. + /// + /// + /// List of aliased alternate names for the control. + /// An example of an alias would be 'North' for the 'Triangle' button on a Playstation pad (or 'Y' button on Xbox pad). + /// public ReadOnlyArray aliases => new ReadOnlyArray(m_Device.m_AliasesForEachControl, m_AliasStartIndex, m_AliasCount); - // Information about where the control stores its state. + /// + /// Information about where the control stores its state, such as format, offset and size. + /// public InputStateBlock stateBlock => m_StateBlock; /// @@ -377,9 +380,10 @@ internal set /// input from an actual physical control whereas "<Gamepad>/leftStick/left" /// represents input from a made-up control. If, however, the "left" button is the only /// viable pick, it will be accepted. + /// + /// A control layout will specify if it is synthetic using . + /// See . /// - /// - /// public bool synthetic { get => (m_ControlFlags & ControlFlags.IsSynthetic) != 0; @@ -395,8 +399,11 @@ internal set /// /// Fetch a control from the control's hierarchy by name. /// + /// A control path. See . /// - /// Note that path matching is case-insensitive. + /// Note that matching is case-insensitive. + /// (see ). + /// An alternative method is . /// /// /// @@ -406,9 +413,6 @@ internal set /// /// /// cannot be found. - /// - /// - /// public InputControl this[string path] { get @@ -427,30 +431,34 @@ public InputControl this[string path] /// Type of values produced by the control. /// /// This is the type of values that are returned when reading the current value of a control - /// or when reading a value of a control from an event. + /// or when reading a value of a control from an event with . + /// The size can be determined with . /// - /// - /// public abstract Type valueType { get; } /// /// Size in bytes of values that the control returns. /// - /// + /// + /// The type can be determined with . + /// public abstract int valueSizeInBytes { get; } /// /// Compute an absolute, normalized magnitude value that indicates the extent to which the control /// is actuated. Shortcut for . /// - /// Amount of actuation of the control or -1 if it cannot be determined. - /// - /// + /// + /// Amount of actuation of the control or -1 if it cannot be determined. + /// public float magnitude => EvaluateMagnitude(); /// - /// Return a string representation of the control useful for debugging. + /// Return a string representation of the control. /// + /// + /// Return a string representation of the control. Useful for debugging. + /// /// A string representation of the control. public override string ToString() { @@ -500,23 +508,48 @@ public unsafe float EvaluateMagnitude() /// Compute an absolute, normalized magnitude value that indicates the extent to which the control /// is actuated in the given state. /// + /// + /// Magnitudes do not make sense for all types of controls. For example, for a control that represents + /// an enumeration of values (such as ), there is no meaningful + /// linear ordering of values (one could derive a linear ordering through the actual enum values but + /// their assignment may be entirely arbitrary; it is unclear whether a state of + /// has a higher or lower "magnitude" as a state of ). + /// + /// Controls that have no meaningful magnitude will return -1 when calling this method. Any negative + /// return value should be considered an invalid value. + /// /// State containing the control's . /// Amount of actuation of the control or -1 if it cannot be determined. /// - /// public virtual unsafe float EvaluateMagnitude(void* statePtr) { return -1; } + /// + /// Read the control's final, processed value from the given buffer and return the value as an object. + /// + /// Buffer to read the value from. + /// Size of in bytes, which must be large enough to store the value. + /// The control's value as stored in . + /// + /// Read the control's final, processed value from the given buffer and return the value as an object. + /// + /// This method allocates GC memory and should not be used during normal gameplay operation. + /// + /// is null. + /// is smaller than the size of the value to be read. + /// public abstract unsafe object ReadValueFromBufferAsObject(void* buffer, int bufferSize); /// /// Read the control's final, processed value from the given state and return the value as an object. /// - /// + /// State to read the value for the control from. /// The control's value as stored in . /// + /// Read the control's final, processed value from the given state and return the value as an object. + /// /// This method allocates GC memory and should not be used during normal gameplay operation. /// /// is null. @@ -539,7 +572,7 @@ public virtual unsafe float EvaluateMagnitude(void* statePtr) /// /// Read a value from the given memory and store it as state. /// - /// Memory containing value. + /// Memory containing value, to store into the state. /// Size of in bytes. Must be at least . /// State containing the control's . Will receive the state /// as converted from the given value. @@ -561,9 +594,9 @@ public virtual unsafe void WriteValueFromBufferIntoState(void* bufferPtr, int bu /// /// Read a value object and store it as state in the given memory. /// - /// Value for the control. + /// Value for the control to store in the state. /// State containing the control's . Will receive - /// the state state as converted from the given value. + /// the state as converted from the given value. /// /// Writing values will NOT apply processors to the given value. This can mean that when reading a value /// from a control after it has been written to its state, the resulting value differs from what was @@ -631,6 +664,19 @@ public InputControl TryGetChildControl(string path) return InputControlPath.TryFindChild(this, path); } + /// + /// Try to find a child control matching the given path. + /// + /// A control path. See . + /// The type of control to locate. + /// The first direct or indirect child control that matches the given + /// or null if no control was found to match. + /// is null or empty. + /// No control found with the specified type. + /// + /// Note that if the given path matches multiple child controls, only the first control + /// encountered in the search will be returned. + /// public TControl TryGetChildControl(string path) where TControl : InputControl { @@ -649,6 +695,19 @@ public TControl TryGetChildControl(string path) return controlOfType; } + /// + /// Find a child control matching the given path. + /// + /// A control path. See . + /// The first direct or indirect child control that matches the given + /// or null if no control was found to match. + /// is null or empty. + /// No control found with the specified type. + /// The control cannot be found. + /// + /// Note that if the given path matches multiple child controls, only the first control + /// encountered in the search will be returned. + /// public InputControl GetChildControl(string path) { if (string.IsNullOrEmpty(path)) @@ -661,6 +720,20 @@ public InputControl GetChildControl(string path) return control; } + /// + /// Find a child control matching the given path. + /// + /// A control path. See . + /// The type of control to locate. + /// The first direct or indirect child control that matches the given + /// or null if no control was found to match. + /// is null or empty. + /// No control found with the specified type. + /// The control cannot be found. + /// + /// Note that if the given path matches multiple child controls, only the first control + /// encountered in the search will be returned. + /// public TControl GetChildControl(string path) where TControl : InputControl { @@ -673,6 +746,12 @@ public TControl GetChildControl(string path) return controlOfType; } + /// + /// Constructor for the InputControl + /// + /// + /// Constructor for the InputControl + /// protected InputControl() { // Set defaults for state block setup. Subclasses may override. @@ -792,6 +871,10 @@ protected void RefreshConfigurationIfNeeded() /// /// /// The system will call this method automatically whenever a change is made to one of the control's configuration properties. + /// This method is only relevant if you are implementing your own devices or new + /// types of controls which are fetching configuration data from the devices (such + /// as which is fetching display names for individual keys + /// from the underlying platform). /// See . /// /// @@ -847,13 +930,34 @@ protected virtual void RefreshConfiguration() } ////TODO: drop protected access + /// + /// Information about a memory region storing input state. + /// protected internal InputStateBlock m_StateBlock; ////REVIEW: shouldn't these sit on the device? + /// + /// The state data buffer for the device. + /// + /// + /// The state data buffer for the device. + /// protected internal unsafe void* currentStatePtr => InputStateBuffers.GetFrontBufferForDevice(GetDeviceIndex()); + /// + /// The state data buffer for the device from the previous frame. + /// + /// + /// The state data buffer for the device from the previous frame. + /// protected internal unsafe void* previousFrameStatePtr => InputStateBuffers.GetBackBufferForDevice(GetDeviceIndex()); + /// + /// The default state data buffer + /// + /// + /// Buffer that has state for each device initialized with default values. + /// protected internal unsafe void* defaultStatePtr => InputStateBuffers.s_DefaultStateBuffer; /// @@ -868,8 +972,9 @@ protected virtual void RefreshConfiguration() /// that is noise will be masked out whereas all state that isn't will come through unmodified. In other words, /// any bit that is set in the noise mask indicates that the corresponding bit in the control's state memory /// is noise. + /// + /// A control can be marked as . /// - /// protected internal unsafe void* noiseMaskPtr => InputStateBuffers.s_NoiseMaskBuffer; /// @@ -878,7 +983,7 @@ protected virtual void RefreshConfiguration() /// /// Once a device has been added to the system, its state block will get allocated /// in the global state buffers and the offset of the device's state block will - /// get baked into all of the controls on the device. This property always returns + /// get baked into all the controls on the device. This property always returns /// the "unbaked" offset. /// protected internal uint stateOffsetRelativeToDeviceRoot @@ -924,13 +1029,15 @@ protected internal uint stateOffsetRelativeToDeviceRoot internal FourCC m_OptimizedControlDataType; /// + /// The type of the state memory associated with the control. + /// + /// /// For some types of control you can safely read/write state memory directly /// which is much faster than calling ReadUnprocessedValueFromState/WriteValueIntoState. /// This method returns a type that you can use for reading/writing the control directly, - /// or it returns InputStateBlock.kFormatInvalid if it's not possible for this type of control. - /// - /// - /// For example, AxisControl might be a "float" in state memory, and if no processing is applied during reading (e.g. no invert/scale/etc), + /// or it returns if it's not possible for this type of control. + /// + /// For example, AxisControl might be a "float" in state memory, and if no processing is applied during reading (e.g. no invert/scale/etc), /// then you could read it as float in memory directly without calling ReadUnprocessedValueFromState, which is faster. /// Additionally, if you have a Vector3Control which uses 3 AxisControls as consecutive floats in memory, /// you can cast the Vector3Control state memory directly to Vector3 without calling ReadUnprocessedValueFromState on x/y/z axes. @@ -942,18 +1049,33 @@ protected internal uint stateOffsetRelativeToDeviceRoot public FourCC optimizedControlDataType => m_OptimizedControlDataType; /// - /// Calculates and returns a optimized data type that can represent a control's value in memory directly. + /// Calculates and returns an optimized data type that can represent a control's value in memory directly. + /// + /// /// The value then is cached in . /// This method is for internal use only, you should not call this from your own code. - /// + /// + /// + /// An optimized data type that can represent a control's value in memory directly. + /// protected virtual FourCC CalculateOptimizedControlDataType() { return InputStateBlock.kFormatInvalid; } /// - /// Apply built-in parameters changes (e.g. , others), recompute for impacted controls and clear cached value. + /// Apply built-in parameters changes. /// + /// + /// Apply built-in parameters changes (e.g. , others). + /// Recompute for impacted controls and clear cached value + /// + /// + /// + /// Gamepad.all[0].leftTrigger.WriteValueIntoState(0.5f, Gamepad.all[0].currentStatePtr); + /// Gamepad.all[0].ApplyParameterChanges(); + /// + /// public void ApplyParameterChanges() { // First we go through all children of our own hierarchy @@ -1194,14 +1316,16 @@ internal virtual IEnumerable GetProcessors() public abstract class InputControl : InputControl where TValue : struct { + /// public override Type valueType => typeof(TValue); + /// public override int valueSizeInBytes => UnsafeUtility.SizeOf(); /// /// Returns the current value of the control after processors have been applied. /// - /// The controls current value. + /// The controls current value. /// /// This can only be called on devices that have been added to the system (). /// @@ -1218,7 +1342,7 @@ public abstract class InputControl : InputControl /// /// Also note that this property returns the result as ref readonly. If custom control states are in use, i.e. /// any controls not shipped with the Input System package, be careful of accidental defensive copies - /// . + /// https://docs.microsoft.com/en-us/dotnet/csharp/write-safe-efficient-code#avoid-defensive-copies. /// /// public ref readonly TValue value @@ -1340,7 +1464,7 @@ internal unsafe ref readonly TValue unprocessedValue /// in the processor and set it to . /// /// To improve debugging try setting "PARANOID_READ_VALUE_CACHING_CHECKS" internal feature flag to check if cache value is still consistent. - /// . + /// https://docs.microsoft.com/en-us/dotnet/csharp/write-safe-efficient-code#avoid-defensive-copies. /// /// public TValue ReadValue() @@ -1378,6 +1502,16 @@ public TValue ReadDefaultValue() } } + /// + /// Get the control's default value. + /// + /// State containing the control's . + /// The control's default value. + /// + /// This is not necessarily equivalent to default(TValue). A control's default value is determined + /// by reading its value from the default state () which in turn + /// is determined from settings in the control's registered layout (). + /// public unsafe TValue ReadValueFromState(void* statePtr) { if (statePtr == null) @@ -1413,11 +1547,28 @@ public unsafe TValue ReadUnprocessedValueFromStateWithCaching(void* statePtr) return statePtr == currentStatePtr ? unprocessedValue : ReadUnprocessedValueFromState(statePtr); } + /// + /// Read value from control + /// + /// The controls current value. + /// + /// This is the locally cached value. Use to get the uncached version. + /// + /// public TValue ReadUnprocessedValue() { return unprocessedValue; } + /// + /// Read value from provided . + /// + /// State pointer to read from. + /// The controls current value. + /// + /// Read value from provided without any caching. + /// + /// public abstract unsafe TValue ReadUnprocessedValueFromState(void* statePtr); /// @@ -1445,6 +1596,7 @@ public override unsafe void ReadValueFromStateIntoBuffer(void* statePtr, void* b UnsafeUtility.MemCpy(bufferPtr, valuePtr, numBytes); } + /// public override unsafe void WriteValueFromBufferIntoState(void* bufferPtr, int bufferSize, void* statePtr) { if (bufferPtr == null) @@ -1482,6 +1634,20 @@ public override unsafe void WriteValueFromObjectIntoState(object value, void* st WriteValueIntoState(valueOfType, statePtr); } + /// + /// Write a value into state at the given memory. + /// + /// Value for the control to store in the state. + /// State containing the control's . Will receive + /// the state as converted from the given value. + /// + /// Writing values will NOT apply processors to the given value. This can mean that when reading a value + /// from a control after it has been written to its state, the resulting value differs from what was + /// written. + /// + /// The control does not support writing. This is the case, for + /// example, that compute values (such as the magnitude of a vector). + /// public virtual unsafe void WriteValueIntoState(TValue value, void* statePtr) { ////REVIEW: should we be able to even tell from layouts which controls support writing and which don't? @@ -1520,6 +1686,12 @@ private static unsafe bool CompareValue(ref TValue firstValue, ref TValue second return UnsafeUtility.MemCmp(firstValuePtr, secondValuePtr, UnsafeUtility.SizeOf()) != 0; } + /// + /// Compared values in state buffers. + /// + /// The first state buffer to read value from. + /// The second state buffer to read value from. + /// True if the buffer values match. False if they differ. public override unsafe bool CompareValue(void* firstStatePtr, void* secondStatePtr) { ////REVIEW: should we first compare state here? if there's no change in state, there can be no change in value and we can skip the rest @@ -1530,6 +1702,14 @@ public override unsafe bool CompareValue(void* firstStatePtr, void* secondStateP return CompareValue(ref firstValue, ref secondValue); } + /// + /// Applies all control processors to the passed value. + /// + /// value to run processors on. + /// The processed value. + /// + /// Applies all control processors to the passed value. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public TValue ProcessValue(TValue value) { @@ -1540,7 +1720,7 @@ public TValue ProcessValue(TValue value) /// /// Applies all control processors to the passed value. /// - /// + /// value to run processors on. /// /// Use this overload when your state struct is large to avoid creating copies of the state. /// @@ -1622,6 +1802,7 @@ internal override IEnumerable GetProcessors() internal bool evaluateProcessorsEveryRead = false; + /// protected override void FinishSetup() { foreach (var processor in m_ProcessorStack)