test
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
|
||||
////REVIEW: generalize this to AnyButton and add to more devices?
|
||||
|
||||
namespace UnityEngine.InputSystem.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// A control that simply checks the entire state it's been assigned
|
||||
/// for whether there's any non-zero bytes. If there are, the control
|
||||
/// returns 1.0; otherwise it returns 0.0.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This control is used by <see cref="Keyboard.anyKey"/> to create a button
|
||||
/// that is toggled on as long as any of the keys on the keyboard is pressed.
|
||||
/// </remarks>
|
||||
/// <seealso cref="Keyboard.anyKey"/>
|
||||
[InputControlLayout(hideInUI = true)]
|
||||
public class AnyKeyControl : ButtonControl
|
||||
{
|
||||
////TODO: wasPressedThisFrame and wasReleasedThisFrame
|
||||
|
||||
/// <summary>
|
||||
/// Default initialization. Sets state size to 1 bit and format to
|
||||
/// <see cref="InputStateBlock.FormatBit"/>.
|
||||
/// </summary>
|
||||
public AnyKeyControl()
|
||||
{
|
||||
m_StateBlock.sizeInBits = 1; // Should be overridden by whoever uses the control.
|
||||
m_StateBlock.format = InputStateBlock.FormatBit;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override unsafe float ReadUnprocessedValueFromState(void* statePtr)
|
||||
{
|
||||
return this.CheckStateIsAtDefault(statePtr) ? 0.0f : 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e444fe6609243258e0a7746c163373a
|
||||
timeCreated: 1508369900
|
@@ -0,0 +1,334 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Processors;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
////REVIEW: change 'clampToConstant' to simply 'clampToMin'?
|
||||
|
||||
////TODO: if AxisControl fields where properties, we wouldn't need ApplyParameterChanges, maybe it's ok breaking change?
|
||||
|
||||
namespace UnityEngine.InputSystem.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// A floating-point axis control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Can optionally be configured to perform normalization.
|
||||
/// Stored as either a float, a short, a byte, or a single bit.
|
||||
/// </remarks>
|
||||
public class AxisControl : InputControl<float>
|
||||
{
|
||||
/// <summary>
|
||||
/// Clamping behavior for an axis control.
|
||||
/// </summary>
|
||||
public enum Clamp
|
||||
{
|
||||
/// <summary>
|
||||
/// Do not clamp values.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Clamp values to <see cref="clampMin"/> and <see cref="clampMax"/>
|
||||
/// before normalizing the value.
|
||||
/// </summary>
|
||||
BeforeNormalize = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Clamp values to <see cref="clampMin"/> and <see cref="clampMax"/>
|
||||
/// after normalizing the value.
|
||||
/// </summary>
|
||||
AfterNormalize = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Clamp values any value below <see cref="clampMin"/> or above <see cref="clampMax"/>
|
||||
/// to <see cref="clampConstant"/> before normalizing the value.
|
||||
/// </summary>
|
||||
ToConstantBeforeNormalize = 3,
|
||||
}
|
||||
|
||||
// These can be added as processors but they are so common that we
|
||||
// build the functionality right into AxisControl to save us an
|
||||
// additional object and an additional virtual call.
|
||||
|
||||
// NOTE: A number of the parameters here can be expressed in much simpler form.
|
||||
// E.g. 'scale', 'scaleFactor' and 'invert' could all be rolled into a single
|
||||
// multiplier. And maybe that's what we should do. However, the one advantage
|
||||
// of the current setup is that it allows to set these operations up individually.
|
||||
// For example, a given layout may want to have a very specific scale factor but
|
||||
// then a derived layout needs the value to be inverted. If it was a single setting,
|
||||
// the derived layout would have to know the specific scale factor in order to come
|
||||
// up with a valid multiplier.
|
||||
|
||||
/// <summary>
|
||||
/// Clamping behavior when reading values. <see cref="Clamp.None"/> by default.
|
||||
/// </summary>
|
||||
/// <value>Clamping behavior.</value>
|
||||
/// <remarks>
|
||||
/// When a value is read from the control's state, it is first converted
|
||||
/// to a floating-point number.
|
||||
/// </remarks>
|
||||
/// <seealso cref="clampMin"/>
|
||||
/// <seealso cref="clampMax"/>
|
||||
/// <seealso cref="clampConstant"/>
|
||||
public Clamp clamp;
|
||||
|
||||
/// <summary>
|
||||
/// Lower end of the clamping range when <see cref="clamp"/> is not
|
||||
/// <see cref="Clamp.None"/>.
|
||||
/// </summary>
|
||||
/// <value>Lower bound of clamping range. Inclusive.</value>
|
||||
public float clampMin;
|
||||
|
||||
/// <summary>
|
||||
/// Upper end of the clamping range when <see cref="clamp"/> is not
|
||||
/// <see cref="Clamp.None"/>.
|
||||
/// </summary>
|
||||
/// <value>Upper bound of clamping range. Inclusive.</value>
|
||||
public float clampMax;
|
||||
|
||||
/// <summary>
|
||||
/// When <see cref="clamp"/> is set to <see cref="Clamp.ToConstantBeforeNormalize"/>
|
||||
/// and the value is outside of the range defined by <see cref="clampMin"/> and
|
||||
/// <see cref="clampMax"/>, this value is returned.
|
||||
/// </summary>
|
||||
/// <value>Constant value to return when value is outside of clamping range.</value>
|
||||
public float clampConstant;
|
||||
|
||||
////REVIEW: why not just roll this into scaleFactor?
|
||||
/// <summary>
|
||||
/// If true, the input value will be inverted, i.e. multiplied by -1. Off by default.
|
||||
/// </summary>
|
||||
/// <value>Whether to invert the input value.</value>
|
||||
public bool invert;
|
||||
|
||||
/// <summary>
|
||||
/// If true, normalize the input value to [0..1] or [-1..1] (depending on the
|
||||
/// value of <see cref="normalizeZero"/>. Off by default.
|
||||
/// </summary>
|
||||
/// <value>Whether to normalize input values or not.</value>
|
||||
/// <seealso cref="normalizeMin"/>
|
||||
/// <seealso cref="normalizeMax"/>
|
||||
public bool normalize;
|
||||
|
||||
////REVIEW: shouldn't these come from the control min/max value by default?
|
||||
|
||||
/// <summary>
|
||||
/// If <see cref="normalize"/> is on, this is the input value that corresponds
|
||||
/// to 0 of the normalized [0..1] or [-1..1] range.
|
||||
/// </summary>
|
||||
/// <value>Input value that should become 0 or -1.</value>
|
||||
/// <remarks>
|
||||
/// In other words, with <see cref="normalize"/> on, input values are mapped from
|
||||
/// the range of [normalizeMin..normalizeMax] to [0..1] or [-1..1] (depending on
|
||||
/// <see cref="normalizeZero"/>).
|
||||
/// </remarks>
|
||||
public float normalizeMin;
|
||||
|
||||
/// <summary>
|
||||
/// If <see cref="normalize"/> is on, this is the input value that corresponds
|
||||
/// to 1 of the normalized [0..1] or [-1..1] range.
|
||||
/// </summary>
|
||||
/// <value>Input value that should become 1.</value>
|
||||
/// <remarks>
|
||||
/// In other words, with <see cref="normalize"/> on, input values are mapped from
|
||||
/// the range of [normalizeMin..normalizeMax] to [0..1] or [-1..1] (depending on
|
||||
/// <see cref="normalizeZero"/>).
|
||||
/// </remarks>
|
||||
public float normalizeMax;
|
||||
|
||||
/// <summary>
|
||||
/// Where to put the zero point of the normalization range. Only relevant
|
||||
/// if <see cref="normalize"/> is set to true. Defaults to 0.
|
||||
/// </summary>
|
||||
/// <value>Zero point of normalization range.</value>
|
||||
/// <remarks>
|
||||
/// The value of this property determines where the zero point is located in the
|
||||
/// range established by <see cref="normalizeMin"/> and <see cref="normalizeMax"/>.
|
||||
///
|
||||
/// If <c>normalizeZero</c> is placed at <see cref="normalizeMin"/>, the normalization
|
||||
/// returns a value in the [0..1] range mapped from the input value range of
|
||||
/// <see cref="normalizeMin"/> and <see cref="normalizeMax"/>.
|
||||
///
|
||||
/// If <c>normalizeZero</c> is placed in-between <see cref="normalizeMin"/> and
|
||||
/// <see cref="normalizeMax"/>, normalization returns a value in the [-1..1] mapped
|
||||
/// from the input value range of <see cref="normalizeMin"/> and <see cref="normalizeMax"/>
|
||||
/// and the zero point between the two established by <c>normalizeZero</c>.
|
||||
/// </remarks>
|
||||
public float normalizeZero;
|
||||
|
||||
////REVIEW: why not just have a default scaleFactor of 1?
|
||||
|
||||
/// <summary>
|
||||
/// Whether the scale the input value by <see cref="scaleFactor"/>. Off by default.
|
||||
/// </summary>
|
||||
/// <value>True if inputs should be scaled by <see cref="scaleFactor"/>.</value>
|
||||
public bool scale;
|
||||
|
||||
/// <summary>
|
||||
/// Value to multiple input values with. Only applied if <see cref="scale"/> is <c>true</c>.
|
||||
/// </summary>
|
||||
/// <value>Multiplier for input values.</value>
|
||||
public float scaleFactor;
|
||||
|
||||
/// <summary>
|
||||
/// Apply modifications to the given value according to the parameters configured
|
||||
/// on the control (<see cref="clamp"/>, <see cref="normalize"/>, etc).
|
||||
/// </summary>
|
||||
/// <param name="value">Input value.</param>
|
||||
/// <returns>A processed value (clamped, normalized, etc).</returns>
|
||||
/// <seealso cref="clamp"/>
|
||||
/// <seealso cref="normalize"/>
|
||||
/// <seealso cref="scale"/>
|
||||
/// <seealso cref="invert"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected float Preprocess(float value)
|
||||
{
|
||||
if (scale)
|
||||
value *= scaleFactor;
|
||||
if (clamp == Clamp.ToConstantBeforeNormalize)
|
||||
{
|
||||
if (value < clampMin || value > clampMax)
|
||||
value = clampConstant;
|
||||
}
|
||||
else if (clamp == Clamp.BeforeNormalize)
|
||||
value = Mathf.Clamp(value, clampMin, clampMax);
|
||||
if (normalize)
|
||||
value = NormalizeProcessor.Normalize(value, normalizeMin, normalizeMax, normalizeZero);
|
||||
if (clamp == Clamp.AfterNormalize)
|
||||
value = Mathf.Clamp(value, clampMin, clampMax);
|
||||
if (invert)
|
||||
value *= -1.0f;
|
||||
return value;
|
||||
}
|
||||
|
||||
private float Unpreprocess(float value)
|
||||
{
|
||||
// Does not reverse the effect of clamping (we don't know what the unclamped value should be).
|
||||
|
||||
if (invert)
|
||||
value *= -1f;
|
||||
if (normalize)
|
||||
value = NormalizeProcessor.Denormalize(value, normalizeMin, normalizeMax, normalizeZero);
|
||||
if (scale)
|
||||
value /= scaleFactor;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default-initialize the control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Defaults the format to <see cref="InputStateBlock.FormatFloat"/>.
|
||||
/// </remarks>
|
||||
public AxisControl()
|
||||
{
|
||||
m_StateBlock.format = InputStateBlock.FormatFloat;
|
||||
}
|
||||
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
base.FinishSetup();
|
||||
|
||||
// if we don't have any default state, and we are using normalizeZero, then the default value
|
||||
// should not be zero. Generate it from normalizeZero.
|
||||
if (!hasDefaultState && normalize && Mathf.Abs(normalizeZero) > Mathf.Epsilon)
|
||||
m_DefaultState = stateBlock.FloatToPrimitiveValue(normalizeZero);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override unsafe float ReadUnprocessedValueFromState(void* statePtr)
|
||||
{
|
||||
switch (m_OptimizedControlDataType)
|
||||
{
|
||||
case InputStateBlock.kFormatFloat:
|
||||
return *(float*)((byte*)statePtr + m_StateBlock.m_ByteOffset);
|
||||
case InputStateBlock.kFormatByte:
|
||||
return *((byte*)statePtr + m_StateBlock.m_ByteOffset) != 0 ? 1.0f : 0.0f;
|
||||
default:
|
||||
{
|
||||
var value = stateBlock.ReadFloat(statePtr);
|
||||
////REVIEW: this isn't very raw
|
||||
return Preprocess(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override unsafe void WriteValueIntoState(float value, void* statePtr)
|
||||
{
|
||||
switch (m_OptimizedControlDataType)
|
||||
{
|
||||
case InputStateBlock.kFormatFloat:
|
||||
*(float*)((byte*)statePtr + m_StateBlock.m_ByteOffset) = value;
|
||||
break;
|
||||
case InputStateBlock.kFormatByte:
|
||||
*((byte*)statePtr + m_StateBlock.m_ByteOffset) = (byte)(value >= 0.5f ? 1 : 0);
|
||||
break;
|
||||
default:
|
||||
value = Unpreprocess(value);
|
||||
stateBlock.WriteFloat(statePtr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override unsafe bool CompareValue(void* firstStatePtr, void* secondStatePtr)
|
||||
{
|
||||
var currentValue = ReadValueFromState(firstStatePtr);
|
||||
var valueInState = ReadValueFromState(secondStatePtr);
|
||||
return !Mathf.Approximately(currentValue, valueInState);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override unsafe float EvaluateMagnitude(void* statePtr)
|
||||
{
|
||||
return EvaluateMagnitude(ReadValueFromStateWithCaching(statePtr));
|
||||
}
|
||||
|
||||
private float EvaluateMagnitude(float value)
|
||||
{
|
||||
if (m_MinValue.isEmpty || m_MaxValue.isEmpty)
|
||||
return Mathf.Abs(value);
|
||||
|
||||
var min = m_MinValue.ToSingle();
|
||||
var max = m_MaxValue.ToSingle();
|
||||
|
||||
var clampedValue = Mathf.Clamp(value, min, max);
|
||||
|
||||
// If part of our range is in negative space, evaluate magnitude as two
|
||||
// separate subspaces.
|
||||
if (min < 0)
|
||||
{
|
||||
if (clampedValue < 0)
|
||||
return NormalizeProcessor.Normalize(Mathf.Abs(clampedValue), 0, Mathf.Abs(min), 0);
|
||||
return NormalizeProcessor.Normalize(clampedValue, 0, max, 0);
|
||||
}
|
||||
|
||||
return NormalizeProcessor.Normalize(clampedValue, min, max, 0);
|
||||
}
|
||||
|
||||
protected override FourCC CalculateOptimizedControlDataType()
|
||||
{
|
||||
var noProcessingNeeded =
|
||||
clamp == Clamp.None &&
|
||||
invert == false &&
|
||||
normalize == false &&
|
||||
scale == false;
|
||||
|
||||
if (noProcessingNeeded &&
|
||||
m_StateBlock.format == InputStateBlock.FormatFloat &&
|
||||
m_StateBlock.sizeInBits == 32 &&
|
||||
m_StateBlock.bitOffset == 0)
|
||||
return InputStateBlock.FormatFloat;
|
||||
if (noProcessingNeeded &&
|
||||
m_StateBlock.format == InputStateBlock.FormatBit &&
|
||||
// has to be 8, otherwise we might be mapping to a state which only represents first bit in the byte, while other bits might map to some other controls
|
||||
// like in the mouse where LMB/RMB map to the same byte, just LMB maps to first bit and RMB maps to second bit
|
||||
m_StateBlock.sizeInBits == 8 &&
|
||||
m_StateBlock.bitOffset == 0)
|
||||
return InputStateBlock.FormatByte;
|
||||
return InputStateBlock.FormatInvalid;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 551b733126e34f71a7294051cf2bfc0b
|
||||
timeCreated: 1506741161
|
@@ -0,0 +1,349 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
////REVIEW: introduce separate base class for ButtonControl and AxisControl instead of deriving ButtonControl from AxisControl?
|
||||
|
||||
namespace UnityEngine.InputSystem.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// An axis that has a trigger point beyond which it is considered to be pressed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default stored as a single bit. In that format, buttons will only yield 0
|
||||
/// and 1 as values. However, buttons return are <see cref="AxisControl"/>s and
|
||||
/// yield full floating-point values and may thus have a range of values. See
|
||||
/// <see cref="pressPoint"/> for how button presses on such buttons are handled.
|
||||
/// </remarks>
|
||||
public class ButtonControl : AxisControl
|
||||
{
|
||||
private bool m_NeedsToCheckFramePress = false;
|
||||
private uint m_UpdateCountLastPressed = uint.MaxValue;
|
||||
private uint m_UpdateCountLastReleased = uint.MaxValue;
|
||||
private bool m_LastUpdateWasPress;
|
||||
#if UNITY_EDITOR
|
||||
// Editor input updates have a separate block of state memory, so must be checked separately
|
||||
private uint m_UpdateCountLastPressedEditor = uint.MaxValue;
|
||||
private uint m_UpdateCountLastReleasedEditor = uint.MaxValue;
|
||||
private bool m_LastUpdateWasPressEditor;
|
||||
#endif
|
||||
|
||||
internal bool needsToCheckFramePress { get; private set; }
|
||||
|
||||
////REVIEW: are per-control press points really necessary? can we just drop them?
|
||||
/// <summary>
|
||||
/// The minimum value the button has to reach for it to be considered pressed.
|
||||
/// </summary>
|
||||
/// <value>Button press threshold.</value>
|
||||
/// <remarks>
|
||||
/// The button is considered pressed, if it has a value equal to or greater than
|
||||
/// this value.
|
||||
///
|
||||
/// By default, this property is set to -1. If the value of the property is negative,
|
||||
/// <see cref="InputSettings.defaultButtonPressPoint"/> is used.
|
||||
///
|
||||
/// The value can be configured as a parameter in a layout.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public class MyDevice : InputDevice
|
||||
/// {
|
||||
/// [InputControl(parameters = "pressPoint=0.234")]
|
||||
/// public ButtonControl button { get; private set; }
|
||||
///
|
||||
/// //...
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputSettings.defaultButtonPressPoint"/>
|
||||
/// <seealso cref="pressPointOrDefault"/>
|
||||
/// <seealso cref="isPressed"/>
|
||||
public float pressPoint = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Return <see cref="pressPoint"/> if set, otherwise return <see cref="InputSettings.defaultButtonPressPoint"/>.
|
||||
/// </summary>
|
||||
/// <value>Effective value to use for press point thresholds.</value>
|
||||
/// <seealso cref="InputSettings.defaultButtonPressPoint"/>
|
||||
public float pressPointOrDefault => pressPoint > 0 ? pressPoint : s_GlobalDefaultButtonPressPoint;
|
||||
|
||||
/// <summary>
|
||||
/// Default-initialize the control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default format for the control is <see cref="InputStateBlock.FormatBit"/>.
|
||||
/// The control's minimum value is set to 0 and the maximum value to 1.
|
||||
/// </remarks>
|
||||
public ButtonControl()
|
||||
{
|
||||
m_StateBlock.format = InputStateBlock.FormatBit;
|
||||
m_MinValue = 0f;
|
||||
m_MaxValue = 1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the given value would be considered pressed for this button.
|
||||
/// </summary>
|
||||
/// <param name="value">Value for the button.</param>
|
||||
/// <returns>True if <paramref name="value"/> crosses the threshold to be considered pressed.</returns>
|
||||
/// <seealso cref="pressPoint"/>
|
||||
/// <seealso cref="InputSettings.defaultButtonPressPoint"/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public new bool IsValueConsideredPressed(float value)
|
||||
{
|
||||
return value >= pressPointOrDefault;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the button is currently pressed.
|
||||
/// </summary>
|
||||
/// <value>True if button is currently pressed.</value>
|
||||
/// <remarks>
|
||||
/// A button is considered pressed if its value is equal to or greater
|
||||
/// than its button press threshold (<see cref="pressPointOrDefault"/>).
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para>You can use this to read whether specific keys are currently pressed by using isPressed on keys, as shown in the following examples:</para>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// // Using KeyControl property directly.
|
||||
/// Keyboard.current.spaceKey.isPressed
|
||||
/// Keyboard.current.aKey.isPressed // etc.
|
||||
///
|
||||
/// // Using Key enum.
|
||||
/// Keyboard.current[Key.Space].isPressed
|
||||
///
|
||||
/// // Using key name.
|
||||
/// ((KeyControl)Keyboard.current["space"]).isPressed
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// <para>Note: The Input System identifies keys by physical layout, not according to the current language mapping of the keyboard. To query the name of the key according to the language mapping, use <see cref="InputControl.displayName"/>.
|
||||
///
|
||||
/// You can also use this to read mouse buttons, as shown in the following examples:</para>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// bool leftPressed = Mouse.current.leftButton.isPressed;
|
||||
/// bool rightPressed = Mouse.current.rightButton.isPressed;
|
||||
/// bool middlePressed = Mouse.current.middleButton.isPressed;
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// <para>You can also check through all numbered buttons on the mouse: (this example does not cause allocations)</para>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// var controls = Mouse.current.allControls;
|
||||
/// for (var i = 0; i < controls.Count; ++i)
|
||||
/// {
|
||||
/// var button = controls[i] as ButtonControl;
|
||||
/// if (button != null && button.isPressed)
|
||||
/// {
|
||||
/// // respond to mouse button press here...
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// <para>Or you can look up controls by name, like this:</para>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// bool leftPressed = ((ButtonControl)Mouse.current["leftButton"]).isPressed;
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <seealso cref="InputSettings.defaultButtonPressPoint"/>
|
||||
/// <seealso cref="pressPoint"/>
|
||||
/// <seealso cref="InputSystem.onAnyButtonPress"/>
|
||||
public bool isPressed
|
||||
{
|
||||
get
|
||||
{
|
||||
// Take the old path if we don't have the speed gain from already testing wasPressedThisFrame/wasReleasedThisFrame.
|
||||
if (!needsToCheckFramePress)
|
||||
return IsValueConsideredPressed(value);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (InputUpdate.s_LatestUpdateType.IsEditorUpdate())
|
||||
return m_LastUpdateWasPressEditor;
|
||||
#endif
|
||||
|
||||
return m_LastUpdateWasPress;
|
||||
}
|
||||
}
|
||||
|
||||
// When we start caring about inter-frame presses, use the info we have to set up the alternate path.
|
||||
// If we don't do this, users could call wasPressedThisFrame/wasReleasedThisFrame twice for the first time in
|
||||
// a single frame, and the returned value may be incorrect until the next frame.
|
||||
private void BeginTestingForFramePresses(bool currentlyPressed, bool pressedLastFrame)
|
||||
{
|
||||
needsToCheckFramePress = true;
|
||||
device.m_ButtonControlsCheckingPressState.Add(this);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (InputUpdate.s_LatestUpdateType.IsEditorUpdate())
|
||||
{
|
||||
m_LastUpdateWasPressEditor = currentlyPressed;
|
||||
if (currentlyPressed && !pressedLastFrame)
|
||||
m_UpdateCountLastPressedEditor = device.m_CurrentUpdateStepCount;
|
||||
else if (pressedLastFrame && !currentlyPressed)
|
||||
m_UpdateCountLastReleasedEditor = device.m_CurrentUpdateStepCount;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_LastUpdateWasPress = currentlyPressed;
|
||||
if (currentlyPressed && !pressedLastFrame)
|
||||
m_UpdateCountLastPressed = device.m_CurrentUpdateStepCount;
|
||||
else if (pressedLastFrame && !currentlyPressed)
|
||||
m_UpdateCountLastReleased = device.m_CurrentUpdateStepCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the press started this frame.
|
||||
/// </summary>
|
||||
/// <value>True if the current press of the button started this frame.</value>
|
||||
/// <remarks>
|
||||
/// The first time this function - or wasReleasedThisFrame - are called, it's possible that extremely fast
|
||||
/// inputs (or very slow frame update times) will result in presses/releases being missed.
|
||||
/// Following the next input system update after either have been called, and from then on until the device is
|
||||
/// destroyed, this ceases to be an issue.
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // An example showing the use of this property on a gamepad button and a keyboard key.
|
||||
///
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.InputSystem;
|
||||
///
|
||||
/// public class ExampleScript : MonoBehaviour
|
||||
/// {
|
||||
/// void Update()
|
||||
/// {
|
||||
/// bool buttonPressed = Gamepad.current.aButton.wasPressedThisFrame;
|
||||
/// bool spaceKeyPressed = Keyboard.current.spaceKey.wasPressedThisFrame;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// _Note_: The Input System identifies keys by physical layout, not according to the current language mapping of the keyboard. To query the name of the key according to the language mapping, use <see cref="InputControl.displayName"/>.
|
||||
///
|
||||
/// You can also use this property to read mouse buttons. For example:
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// Mouse.current.leftButton.wasPressedThisFrame
|
||||
/// Mouse.current.rightButton.wasPressedThisFrame
|
||||
/// Mouse.current.middleButton.wasPressedThisFrame
|
||||
/// </code>
|
||||
/// </example>
|
||||
///
|
||||
///
|
||||
/// </remarks>
|
||||
public bool wasPressedThisFrame
|
||||
{
|
||||
get
|
||||
{
|
||||
// Take the old path if this is the first time calling.
|
||||
if (!needsToCheckFramePress)
|
||||
{
|
||||
var currentlyPressed = IsValueConsideredPressed(value);
|
||||
var pressedLastFrame = IsValueConsideredPressed(ReadValueFromPreviousFrame());
|
||||
BeginTestingForFramePresses(currentlyPressed, pressedLastFrame);
|
||||
|
||||
return device.wasUpdatedThisFrame && currentlyPressed && !pressedLastFrame;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (InputUpdate.s_LatestUpdateType.IsEditorUpdate())
|
||||
return InputUpdate.s_UpdateStepCount == m_UpdateCountLastPressedEditor;
|
||||
#endif
|
||||
return InputUpdate.s_UpdateStepCount == m_UpdateCountLastPressed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the press ended this frame.
|
||||
/// </summary>
|
||||
/// <value>True if the current press of the button ended this frame.</value>
|
||||
/// <remarks>
|
||||
/// _Note_: The Input System identifies keys by physical layout, not according to the current language mapping of the keyboard. To query the name of the key according to the language mapping, use <see cref="InputControl.displayName"/>.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para>An example showing the use of this property on a gamepad button and a keyboard key:</para>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.InputSystem;
|
||||
///
|
||||
/// public class ExampleScript : MonoBehaviour
|
||||
/// {
|
||||
/// void Update()
|
||||
/// {
|
||||
/// bool buttonPressed = Gamepad.current.aButton.wasReleasedThisFrame;
|
||||
/// bool spaceKeyPressed = Keyboard.current.spaceKey.wasReleasedThisFrame;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public bool wasReleasedThisFrame
|
||||
{
|
||||
get
|
||||
{
|
||||
// Take the old path if this is the first time calling.
|
||||
if (!needsToCheckFramePress)
|
||||
{
|
||||
var currentlyPressed = IsValueConsideredPressed(value);
|
||||
var pressedLastFrame = IsValueConsideredPressed(ReadValueFromPreviousFrame());
|
||||
BeginTestingForFramePresses(currentlyPressed, pressedLastFrame);
|
||||
|
||||
return device.wasUpdatedThisFrame && !currentlyPressed && pressedLastFrame;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (InputUpdate.s_LatestUpdateType.IsEditorUpdate())
|
||||
return InputUpdate.s_UpdateStepCount == m_UpdateCountLastReleasedEditor;
|
||||
#endif
|
||||
return InputUpdate.s_UpdateStepCount == m_UpdateCountLastReleased;
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateWasPressed()
|
||||
{
|
||||
var isNowPressed = IsValueConsideredPressed(value);
|
||||
|
||||
if (m_LastUpdateWasPress != isNowPressed)
|
||||
{
|
||||
if (isNowPressed)
|
||||
m_UpdateCountLastPressed = device.m_CurrentUpdateStepCount;
|
||||
else
|
||||
m_UpdateCountLastReleased = device.m_CurrentUpdateStepCount;
|
||||
|
||||
m_LastUpdateWasPress = isNowPressed;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal void UpdateWasPressedEditor()
|
||||
{
|
||||
var isNowPressed = IsValueConsideredPressed(value);
|
||||
|
||||
if (m_LastUpdateWasPressEditor != isNowPressed)
|
||||
{
|
||||
if (isNowPressed)
|
||||
m_UpdateCountLastPressedEditor = device.m_CurrentUpdateStepCount;
|
||||
else
|
||||
m_UpdateCountLastReleasedEditor = device.m_CurrentUpdateStepCount;
|
||||
|
||||
m_LastUpdateWasPressEditor = isNowPressed;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // UNITY_EDITOR
|
||||
|
||||
// We make the current global default button press point available as a static so that we don't have to
|
||||
// constantly make the hop from InputSystem.settings -> InputManager.m_Settings -> defaultButtonPressPoint.
|
||||
internal static float s_GlobalDefaultButtonPressPoint;
|
||||
internal static float s_GlobalDefaultButtonReleaseThreshold;
|
||||
|
||||
// We clamp button press points to this value as allowing 0 as the press point causes all buttons
|
||||
// to implicitly be pressed all the time. Not useful.
|
||||
internal const float kMinButtonPressPoint = 0.0001f;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d618f7e3781548c28836f39ae65d95e1
|
||||
timeCreated: 1506741155
|
@@ -0,0 +1,207 @@
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
namespace UnityEngine.InputSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of common usage string values as reported by <see cref="InputControl.usages"/>.
|
||||
/// </summary>
|
||||
public static class CommonUsages
|
||||
{
|
||||
/// <summary>
|
||||
/// Primary 2D motion control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: Left stick on a gamepad.
|
||||
/// </remarks>
|
||||
public static readonly InternedString Primary2DMotion = new InternedString("Primary2DMotion");
|
||||
|
||||
/// <summary>
|
||||
/// Secondary 2D motion control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: Right stick on a gamepad.
|
||||
/// </remarks>
|
||||
public static readonly InternedString Secondary2DMotion = new InternedString("Secondary2DMotion");
|
||||
|
||||
/// <summary>
|
||||
/// The primary action control on any input device, such as a gamepad, mouse, or keyboard.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: Primary mouse button (left button on right-handed configuration, right button on left-handed configuration),
|
||||
/// south-button on a gamepad.
|
||||
/// </remarks>
|
||||
public static readonly InternedString PrimaryAction = new InternedString("PrimaryAction");
|
||||
|
||||
/// <summary>
|
||||
/// Secondary action control on any input device, such as a gamepad, mouse, or keyboard.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: Secondary mouse button (right button on right-handed configuration, left button on left-handed configuration),
|
||||
/// east-button on a gamepad.
|
||||
/// </remarks>
|
||||
public static readonly InternedString SecondaryAction = new InternedString("SecondaryAction");
|
||||
|
||||
/// <summary>
|
||||
/// The primary trigger control on input devices with triggers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: Right trigger-button on a gamepad.
|
||||
/// </remarks>
|
||||
public static readonly InternedString PrimaryTrigger = new InternedString("PrimaryTrigger");
|
||||
|
||||
/// <summary>
|
||||
/// The secondary trigger control on input devices with triggers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: Left trigger-button on a gamepad.
|
||||
/// </remarks>
|
||||
public static readonly InternedString SecondaryTrigger = new InternedString("SecondaryTrigger");
|
||||
|
||||
/// <summary>
|
||||
/// A modifier action control that modifies usage of other controls.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: Keyboard modifier keys like CTRL, SHIFT, ALT, OPTION, etc.
|
||||
/// </remarks>
|
||||
public static readonly InternedString Modifier = new InternedString("Modifier");
|
||||
|
||||
/// <summary>
|
||||
/// The spatial position control on input devices with spatial tracking.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: User head position in tracking-space using e.g. a head-tracking system. This could for example be a VR tracking system or another user-facing tracking sensor.
|
||||
/// </remarks>
|
||||
public static readonly InternedString Position = new InternedString("Position");
|
||||
|
||||
/// <summary>
|
||||
/// The spatial orientation control on input devices with spatial tracking.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: User head-orientation in tracking-space using e.g. a head-tracking system. This could for example be a VR tracking system or another user-facing tracking sensor.
|
||||
/// </remarks>
|
||||
public static readonly InternedString Orientation = new InternedString("Orientation");
|
||||
|
||||
/// <summary>
|
||||
/// The primary hat-switch control on input devices with hat-switches such as joysticks or gamepads.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: Joystick or gamepad hat-switch.
|
||||
/// </remarks>
|
||||
public static readonly InternedString Hatswitch = new InternedString("Hatswitch");
|
||||
|
||||
/// <summary>
|
||||
/// Button to navigate to previous location.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: Escape on keyboard, B button on gamepad.
|
||||
///
|
||||
/// In general, the "Back" control is used for moving backwards in the navigation history
|
||||
/// of a UI. This is used, for example, in hierarchical menu structures to move back to parent menus
|
||||
/// (e.g. from the "Settings" menu back to the "Main" menu). Consoles generally have stringent requirements
|
||||
/// as to which button has to fulfill this role.
|
||||
/// </remarks>
|
||||
public static readonly InternedString Back = new InternedString("Back");
|
||||
|
||||
/// <summary>
|
||||
/// Button to navigate to next location.
|
||||
/// </summary>
|
||||
public static readonly InternedString Forward = new InternedString("Forward");
|
||||
|
||||
/// <summary>
|
||||
/// Button to bring up menu.
|
||||
/// </summary>
|
||||
public static readonly InternedString Menu = new InternedString("Menu");
|
||||
|
||||
/// <summary>
|
||||
/// Button to confirm the current choice.
|
||||
/// </summary>
|
||||
public static readonly InternedString Submit = new InternedString("Submit");
|
||||
|
||||
////REVIEW: isn't this the same as "Back"?
|
||||
/// <summary>
|
||||
/// Button to not accept the current choice.
|
||||
/// </summary>
|
||||
public static readonly InternedString Cancel = new InternedString("Cancel");
|
||||
|
||||
/// <summary>
|
||||
/// Horizontal motion axis.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: X axis on mouse.
|
||||
/// </remarks>
|
||||
public static readonly InternedString Horizontal = new InternedString("Horizontal");
|
||||
|
||||
/// <summary>
|
||||
/// Vertical motion axis.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: Y axis on mouse.
|
||||
/// </remarks>
|
||||
public static readonly InternedString Vertical = new InternedString("Vertical");
|
||||
|
||||
/// <summary>
|
||||
/// Rotation around single, fixed axis.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: twist on joystick or twist of pen (few pens support that).
|
||||
/// </remarks>
|
||||
public static readonly InternedString Twist = new InternedString("Twist");
|
||||
|
||||
/// <summary>
|
||||
/// Pressure level axis.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: pen pressure.
|
||||
/// </remarks>
|
||||
public static readonly InternedString Pressure = new InternedString("Pressure");
|
||||
|
||||
/// <summary>
|
||||
/// Axis to scroll horizontally.
|
||||
/// </summary>
|
||||
public static readonly InternedString ScrollHorizontal = new InternedString("ScrollHorizontal");
|
||||
|
||||
/// <summary>
|
||||
/// Axis to scroll vertically.
|
||||
/// </summary>
|
||||
public static readonly InternedString ScrollVertical = new InternedString("ScrollVertical");
|
||||
|
||||
/// <summary>
|
||||
/// A screen-space point.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: Touch contact point.
|
||||
/// </remarks>
|
||||
public static readonly InternedString Point = new InternedString("Point");
|
||||
|
||||
/// <summary>
|
||||
/// Low-frequency haptic motor for force-feedback.
|
||||
/// </summary>
|
||||
public static readonly InternedString LowFreqMotor = new InternedString("LowFreqMotor");
|
||||
|
||||
/// <summary>
|
||||
/// High-frequency haptic motor for force-feedback.
|
||||
/// </summary>
|
||||
public static readonly InternedString HighFreqMotor = new InternedString("HighFreqMotor");
|
||||
|
||||
/// <summary>
|
||||
/// Device in left hand.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: left hand XR controller.
|
||||
/// </remarks>
|
||||
public static readonly InternedString LeftHand = new InternedString("LeftHand");
|
||||
|
||||
/// <summary>
|
||||
/// Device in right hand.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: right hand XR controller.
|
||||
/// </remarks>
|
||||
public static readonly InternedString RightHand = new InternedString("RightHand");
|
||||
|
||||
/// <summary>
|
||||
/// Axis representing charge of battery (1=full, 0=empty).
|
||||
/// </summary>
|
||||
public static readonly InternedString BatteryStrength = new InternedString("BatteryStrength");
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf624ae4ff5e44cebdcba54ae1ff380a
|
||||
timeCreated: 1507150918
|
@@ -0,0 +1,70 @@
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
namespace UnityEngine.InputSystem.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Delta controls are a two-dimensional motion vector that accumulate within a frame
|
||||
/// and reset at the beginning of a frame. You can read the values from a delta control
|
||||
/// using the inherited members from Vector2Control or InputControl.
|
||||
/// </summary>
|
||||
/// <see cref="Pointer.delta"/>
|
||||
/// <seealso cref="Mouse.scroll"/>
|
||||
[Preserve]
|
||||
public class DeltaControl : Vector2Control
|
||||
{
|
||||
/// <summary>
|
||||
/// A synthetic axis representing the upper half of the Y axis value, i.e. the 0 to 1 range.
|
||||
/// </summary>
|
||||
/// <value>Control representing the control's upper half Y axis.</value>
|
||||
/// <remarks>
|
||||
/// The control is marked as <see cref="InputControl.synthetic"/>.
|
||||
/// </remarks>
|
||||
[InputControl(useStateFrom = "y", parameters = "clamp=1,clampMin=0,clampMax=3.402823E+38", synthetic = true, displayName = "Up")]
|
||||
[Preserve]
|
||||
public AxisControl up { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A synthetic axis representing the lower half of the Y axis value, i.e. the 0 to -1 range (inverted).
|
||||
/// </summary>
|
||||
/// <value>Control representing the control's lower half Y axis.</value>
|
||||
/// <remarks>
|
||||
/// The control is marked as <see cref="InputControl.synthetic"/>.
|
||||
/// </remarks>
|
||||
[InputControl(useStateFrom = "y", parameters = "clamp=1,clampMin=-3.402823E+38,clampMax=0,invert", synthetic = true, displayName = "Down")]
|
||||
[Preserve]
|
||||
public AxisControl down { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A synthetic axis representing the left half of the X axis value, i.e. the 0 to -1 range (inverted).
|
||||
/// </summary>
|
||||
/// <value>Control representing the control's left half X axis.</value>
|
||||
/// <remarks>
|
||||
/// The control is marked as <see cref="InputControl.synthetic"/>.
|
||||
/// </remarks>
|
||||
[InputControl(useStateFrom = "x", parameters = "clamp=1,clampMin=-3.402823E+38,clampMax=0,invert", synthetic = true, displayName = "Left")]
|
||||
[Preserve]
|
||||
public AxisControl left { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A synthetic axis representing the right half of the X axis value, i.e. the 0 to 1 range.
|
||||
/// </summary>
|
||||
/// <value>Control representing the control's right half X axis.</value>
|
||||
/// <remarks>
|
||||
/// The control is marked as <see cref="InputControl.synthetic"/>.
|
||||
/// </remarks>
|
||||
[InputControl(useStateFrom = "x", parameters = "clamp=1,clampMin=0,clampMax=3.402823E+38", synthetic = true, displayName = "Right")]
|
||||
[Preserve]
|
||||
public AxisControl right { get; set; }
|
||||
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
base.FinishSetup();
|
||||
|
||||
up = GetChildControl<AxisControl>("up");
|
||||
down = GetChildControl<AxisControl>("down");
|
||||
left = GetChildControl<AxisControl>("left");
|
||||
right = GetChildControl<AxisControl>("right");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 339c9c6bc0554ad79681e127d417ef3d
|
||||
timeCreated: 1630420986
|
@@ -0,0 +1,149 @@
|
||||
using System;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
////TODO: hide in UI
|
||||
|
||||
namespace UnityEngine.InputSystem.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// A button that is considered pressed if the underlying state has a value in the specific range.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This control is most useful for handling HID-style hat switches. Unlike <see cref="DpadControl"/>,
|
||||
/// which by default is stored as a bitfield of four bits that each represent a direction on the pad,
|
||||
/// these hat switches enumerate the possible directions that the switch can be moved in. For example,
|
||||
/// the value 1 could indicate that the switch is moved to the left whereas 3 could indicate it is
|
||||
/// moved up.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// [StructLayout(LayoutKind.Explicit, Size = 32)]
|
||||
/// internal struct DualShock4HIDInputReport : IInputStateTypeInfo
|
||||
/// {
|
||||
/// [FieldOffset(0)] public byte reportId;
|
||||
///
|
||||
/// [InputControl(name = "dpad", format = "BIT", layout = "Dpad", sizeInBits = 4, defaultState = 8)]
|
||||
/// [InputControl(name = "dpad/up", format = "BIT", layout = "DiscreteButton", parameters = "minValue=7,maxValue=1,nullValue=8,wrapAtValue=7", bit = 0, sizeInBits = 4)]
|
||||
/// [InputControl(name = "dpad/right", format = "BIT", layout = "DiscreteButton", parameters = "minValue=1,maxValue=3", bit = 0, sizeInBits = 4)]
|
||||
/// [InputControl(name = "dpad/down", format = "BIT", layout = "DiscreteButton", parameters = "minValue=3,maxValue=5", bit = 0, sizeInBits = 4)]
|
||||
/// [InputControl(name = "dpad/left", format = "BIT", layout = "DiscreteButton", parameters = "minValue=5, maxValue=7", bit = 0, sizeInBits = 4)]
|
||||
/// [FieldOffset(5)] public byte buttons1;
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public class DiscreteButtonControl : ButtonControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Value (inclusive) at which to start considering the button to be pressed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <see cref="minValue"/> is allowed to be larger than <see cref="maxValue"/>. This indicates
|
||||
/// a setup where the value wraps around beyond <see cref="minValue"/>, skips <see cref="nullValue"/>,
|
||||
/// and then goes all the way up to <see cref="maxValue"/>.
|
||||
///
|
||||
/// For example, if the underlying state represents a circular D-pad and enumerates its
|
||||
/// 9 possible positions (including null state) going clock-wise from 0 to 8 and with 1
|
||||
/// indicating that the D-pad is pressed to the left, then 1, 2, and 8 would indicate
|
||||
/// that the "left" button is held on the D-pad. To set this up, set <see cref="minValue"/>
|
||||
/// to 8, <see cref="maxValue"/> to 2, and <see cref="nullValue"/> to 0 (the default).
|
||||
/// </remarks>
|
||||
public int minValue;
|
||||
|
||||
/// <summary>
|
||||
/// Value (inclusive) beyond which to stop considering the button to be pressed.
|
||||
/// </summary>
|
||||
public int maxValue;
|
||||
|
||||
/// <summary>
|
||||
/// Value (inclusive) at which the values cut off and wrap back around. Considered to not be set if equal to <see cref="nullValue"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is useful if, for example, an enumeration has more bits than are used for "on" states of controls. For example,
|
||||
/// a bitfield of 4 bits where values 1-7 (i.e. 0001 to 0111) indicate "on" states of controls and value 8 indicating an
|
||||
/// "off" state. In that case, set <see cref="nullValue"/> to 8 and <see cref="wrapAtValue"/> to 7.
|
||||
/// </remarks>
|
||||
public int wrapAtValue;
|
||||
|
||||
/// <summary>
|
||||
/// Value at which the button is considered to not be pressed. Usually zero. Some devices, however,
|
||||
/// use non-zero default states.
|
||||
/// </summary>
|
||||
public int nullValue;
|
||||
|
||||
/// <summary>
|
||||
/// Determines the behavior of <see cref="WriteValueIntoState"/>. By default, attempting to write a <see cref="DiscreteButtonControl"/>
|
||||
/// will result in a <c>NotSupportedException</c>.
|
||||
/// </summary>
|
||||
public WriteMode writeMode;
|
||||
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
base.FinishSetup();
|
||||
|
||||
if (!stateBlock.format.IsIntegerFormat())
|
||||
throw new NotSupportedException(
|
||||
$"Non-integer format '{stateBlock.format}' is not supported for DiscreteButtonControl '{this}'");
|
||||
}
|
||||
|
||||
public override unsafe float ReadUnprocessedValueFromState(void* statePtr)
|
||||
{
|
||||
var valuePtr = (byte*)statePtr + (int)m_StateBlock.byteOffset;
|
||||
// Note that all signed data in state buffers is in excess-K format.
|
||||
var intValue = MemoryHelpers.ReadTwosComplementMultipleBitsAsInt(valuePtr, m_StateBlock.bitOffset, m_StateBlock.sizeInBits);
|
||||
|
||||
var value = 0.0f;
|
||||
if (minValue > maxValue)
|
||||
{
|
||||
// If no wrapping point is set, default to wrapping around exactly
|
||||
// at the point of minValue.
|
||||
if (wrapAtValue == nullValue)
|
||||
wrapAtValue = minValue;
|
||||
|
||||
if ((intValue >= minValue && intValue <= wrapAtValue)
|
||||
|| (intValue != nullValue && intValue <= maxValue))
|
||||
value = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = intValue >= minValue && intValue <= maxValue ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
return Preprocess(value);
|
||||
}
|
||||
|
||||
public override unsafe void WriteValueIntoState(float value, void* statePtr)
|
||||
{
|
||||
if (writeMode == WriteMode.WriteNullAndMaxValue)
|
||||
{
|
||||
var valuePtr = (byte*)statePtr + (int)m_StateBlock.byteOffset;
|
||||
var valueToWrite = value >= pressPointOrDefault ? maxValue : nullValue;
|
||||
MemoryHelpers.WriteIntAsTwosComplementMultipleBits(valuePtr, m_StateBlock.bitOffset, m_StateBlock.sizeInBits, valueToWrite);
|
||||
return;
|
||||
}
|
||||
|
||||
// The way these controls are usually used, the state is shared between multiple DiscreteButtons. So writing one
|
||||
// may have unpredictable effects on the value of other buttons.
|
||||
throw new NotSupportedException("Writing value states for DiscreteButtonControl is not supported as a single value may correspond to multiple states");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How <see cref="DiscreteButtonControl.WriteValueIntoState"/> should behave.
|
||||
/// </summary>
|
||||
public enum WriteMode
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="DiscreteButtonControl.WriteValueIntoState"/> will throw <c>NotSupportedException</c>.
|
||||
/// </summary>
|
||||
WriteDisabled = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Write <see cref="DiscreteButtonControl.nullValue"/> for when the button is considered not pressed and
|
||||
/// write <see cref="DiscreteButtonControl.maxValue"/> for when the button is considered pressed.
|
||||
/// </summary>
|
||||
WriteNullAndMaxValue = 1,
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ab470181bfe4ba891e0d1584730fc4c
|
||||
timeCreated: 1517190786
|
@@ -0,0 +1,30 @@
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
|
||||
namespace UnityEngine.InputSystem.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// A control reading a <see cref="double"/>.
|
||||
/// </summary>
|
||||
public class DoubleControl : InputControl<double>
|
||||
{
|
||||
/// <summary>
|
||||
/// Default-initialize the control.
|
||||
/// </summary>
|
||||
public DoubleControl()
|
||||
{
|
||||
m_StateBlock.format = InputStateBlock.FormatDouble;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override unsafe double ReadUnprocessedValueFromState(void* statePtr)
|
||||
{
|
||||
return m_StateBlock.ReadDouble(statePtr);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override unsafe void WriteValueIntoState(double value, void* statePtr)
|
||||
{
|
||||
m_StateBlock.WriteDouble(statePtr, value);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 72251f49d44478b4c93462938d7ce4cf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
|
||||
namespace UnityEngine.InputSystem.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// A control made up of four discrete, directional buttons. Forms a vector
|
||||
/// but can also be addressed as individual buttons.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Is stored as four bits by default.
|
||||
///
|
||||
/// The vector that is aggregated from the button states is normalized. I.e.
|
||||
/// even if pressing diagonally, the vector will have a length of 1 (instead
|
||||
/// of reading something like <c>(1,1)</c> for example).
|
||||
/// </remarks>
|
||||
public class DpadControl : Vector2Control
|
||||
{
|
||||
[InputControlLayout(hideInUI = true)]
|
||||
public class DpadAxisControl : AxisControl
|
||||
{
|
||||
public int component { get; set; }
|
||||
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
base.FinishSetup();
|
||||
component = name == "x" ? 0 : 1;
|
||||
|
||||
// Set the state block to be the parent's state block. We don't use that to read
|
||||
// the axis directly (we call the parent control to do that), but we need to set
|
||||
// it up the actions know to monitor this memory for changes to the control.
|
||||
m_StateBlock = m_Parent.m_StateBlock;
|
||||
}
|
||||
|
||||
public override unsafe float ReadUnprocessedValueFromState(void* statePtr)
|
||||
{
|
||||
var value = ((DpadControl)m_Parent).ReadUnprocessedValueFromState(statePtr);
|
||||
return value[component];
|
||||
}
|
||||
}
|
||||
|
||||
// The DpadAxisControl has it's own logic to read state from the parent dpad.
|
||||
// The useStateFrom argument here is not actually used by that. The only reason
|
||||
// it is set up here is to avoid any state bytes being reserved for the DpadAxisControl.
|
||||
[InputControl(name = "x", layout = "DpadAxis", useStateFrom = "right", synthetic = true)]
|
||||
[InputControl(name = "y", layout = "DpadAxis", useStateFrom = "up", synthetic = true)]
|
||||
|
||||
/// <summary>
|
||||
/// The button representing the vertical upwards state of the D-Pad.
|
||||
/// </summary>
|
||||
[InputControl(bit = (int)ButtonBits.Up, displayName = "Up")]
|
||||
public ButtonControl up { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The button representing the vertical downwards state of the D-Pad.
|
||||
/// </summary>
|
||||
[InputControl(bit = (int)ButtonBits.Down, displayName = "Down")]
|
||||
public ButtonControl down { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The button representing the horizontal left state of the D-Pad.
|
||||
/// </summary>
|
||||
[InputControl(bit = (int)ButtonBits.Left, displayName = "Left")]
|
||||
public ButtonControl left { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The button representing the horizontal right state of the D-Pad.
|
||||
/// </summary>
|
||||
[InputControl(bit = (int)ButtonBits.Right, displayName = "Right")]
|
||||
public ButtonControl right { get; set; }
|
||||
|
||||
////TODO: should have X and Y child controls as well
|
||||
|
||||
public DpadControl()
|
||||
{
|
||||
m_StateBlock.sizeInBits = 4;
|
||||
m_StateBlock.format = InputStateBlock.FormatBit;
|
||||
}
|
||||
|
||||
protected override void FinishSetup()
|
||||
{
|
||||
up = GetChildControl<ButtonControl>("up");
|
||||
down = GetChildControl<ButtonControl>("down");
|
||||
left = GetChildControl<ButtonControl>("left");
|
||||
right = GetChildControl<ButtonControl>("right");
|
||||
base.FinishSetup();
|
||||
}
|
||||
|
||||
public override unsafe Vector2 ReadUnprocessedValueFromState(void* statePtr)
|
||||
{
|
||||
var upIsPressed = up.ReadValueFromStateWithCaching(statePtr) >= up.pressPointOrDefault;
|
||||
var downIsPressed = down.ReadValueFromStateWithCaching(statePtr) >= down.pressPointOrDefault;
|
||||
var leftIsPressed = left.ReadValueFromStateWithCaching(statePtr) >= left.pressPointOrDefault;
|
||||
var rightIsPressed = right.ReadValueFromStateWithCaching(statePtr) >= right.pressPointOrDefault;
|
||||
|
||||
return MakeDpadVector(upIsPressed, downIsPressed, leftIsPressed, rightIsPressed);
|
||||
}
|
||||
|
||||
public override unsafe void WriteValueIntoState(Vector2 value, void* statePtr)
|
||||
{
|
||||
var upIsPressed = up.IsValueConsideredPressed(value.y);
|
||||
var downIsPressed = down.IsValueConsideredPressed(value.y * -1f);
|
||||
var leftIsPressed = left.IsValueConsideredPressed(value.x * -1f);
|
||||
var rightIsPressed = right.IsValueConsideredPressed(value.x);
|
||||
|
||||
up.WriteValueIntoState(upIsPressed && !downIsPressed ? value.y : 0f, statePtr);
|
||||
down.WriteValueIntoState(downIsPressed && !upIsPressed ? value.y * -1f : 0f, statePtr);
|
||||
left.WriteValueIntoState(leftIsPressed && !rightIsPressed ? value.x * -1f : 0f, statePtr);
|
||||
right.WriteValueIntoState(rightIsPressed && !leftIsPressed ? value.x : 0f, statePtr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a direction vector from the given four button states.
|
||||
/// </summary>
|
||||
/// <param name="up">Whether button representing the up direction is pressed.</param>
|
||||
/// <param name="down">Whether button representing the down direction is pressed.</param>
|
||||
/// <param name="left">Whether button representing the left direction is pressed.</param>
|
||||
/// <param name="right">Whether button representing the right direction is pressed.</param>
|
||||
/// <param name="normalize">Whether to normalize the resulting vector. If this is false, vectors in the diagonal
|
||||
/// directions will have a magnitude of greater than 1. For example, up-left will be (-1,1).</param>
|
||||
/// <returns>A 2D direction vector.</returns>
|
||||
public static Vector2 MakeDpadVector(bool up, bool down, bool left, bool right, bool normalize = true)
|
||||
{
|
||||
var upValue = up ? 1.0f : 0.0f;
|
||||
var downValue = down ? -1.0f : 0.0f;
|
||||
var leftValue = left ? -1.0f : 0.0f;
|
||||
var rightValue = right ? 1.0f : 0.0f;
|
||||
|
||||
var result = new Vector2(leftValue + rightValue, upValue + downValue);
|
||||
|
||||
if (normalize)
|
||||
{
|
||||
// If press is diagonal, adjust coordinates to produce vector of length 1.
|
||||
// pow(0.707107) is roughly 0.5 so sqrt(pow(0.707107)+pow(0.707107)) is ~1.
|
||||
const float diagonal = 0.707107f;
|
||||
if (result.x != 0 && result.y != 0)
|
||||
result = new Vector2(result.x * diagonal, result.y * diagonal);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a direction vector from the given axis states.
|
||||
/// </summary>
|
||||
/// <param name="up">Axis value representing the up direction.</param>
|
||||
/// <param name="down">Axis value representing the down direction.</param>
|
||||
/// <param name="left">Axis value representing the left direction.</param>
|
||||
/// <param name="right">Axis value representing the right direction.</param>
|
||||
/// <returns>A 2D direction vector.</returns>
|
||||
public static Vector2 MakeDpadVector(float up, float down, float left, float right)
|
||||
{
|
||||
return new Vector2(-left + right, up - down);
|
||||
}
|
||||
|
||||
internal enum ButtonBits
|
||||
{
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b00a605ae58d438baf0b80388b377972
|
||||
timeCreated: 1506743933
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d59a0dc8508f4cf1819f6ba99250cd8e
|
||||
timeCreated: 1506735383
|
@@ -0,0 +1,352 @@
|
||||
using System;
|
||||
using UnityEngine.InputSystem.Composites;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
|
||||
namespace UnityEngine.InputSystem.Layouts
|
||||
{
|
||||
/// <summary>
|
||||
/// Mark a field or property as representing/identifying an input control in some form.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This attribute is used in different places for different purposes.
|
||||
///
|
||||
/// When creating input control layouts (<see cref="InputControlLayout"/>) in C#, applying the
|
||||
/// attribute to fields in a state struct (see <see cref="IInputStateTypeInfo"/> or <see cref="GamepadState"/>
|
||||
/// for an example) or to properties in an input device (<see cref="InputDevice"/>), will cause an
|
||||
/// <see cref="InputControl"/> to be created from the field or property at runtime. The attribute
|
||||
/// can be applied multiple times to create multiple input controls (e.g. when having an int field
|
||||
/// that represents a bitfield where each bit is a separate button).
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public class MyDevice : InputDevice
|
||||
/// {
|
||||
/// // Adds an InputControl with name=myButton and layout=Button to the device.
|
||||
/// [InputControl]
|
||||
/// public ButtonControl myButton { get; set; }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
///
|
||||
/// Another use is for marking <c>string</c> type fields that represent input control paths. Applying
|
||||
/// the attribute to them will cause them to automatically use a custom inspector similar to the one
|
||||
/// found in the action editor. For this use, only the <see cref="layout"/> property is taken into
|
||||
/// account.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public class MyBehavior : MonoBehaviour
|
||||
/// {
|
||||
/// // In the inspector, shows a control selector that is restricted to
|
||||
/// // selecting buttons. As a result, controlPath will be set to path
|
||||
/// // representing the control that was picked (e.g. "<Gamepad>/buttonSouth").
|
||||
/// [InputControl(layout = "Button")]
|
||||
/// public string controlPath;
|
||||
///
|
||||
/// protected void OnEnable()
|
||||
/// {
|
||||
/// // Find controls by path.
|
||||
/// var controls = InputSystem.FindControl(controlPath);
|
||||
/// //...
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
///
|
||||
/// Finally, the attribute is also used in composite bindings (<see cref="InputBindingComposite"/>)
|
||||
/// to mark fields that reference parts of the composite. An example for this is <see cref="AxisComposite.negative"/>.
|
||||
/// In this use, also only the <see cref="layout"/> property is taken into account while other properties
|
||||
/// are ignored.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public class MyComposite : InputBindingComposite<float>
|
||||
/// {
|
||||
/// // Add a part to the composite called 'firstControl' which expects
|
||||
/// // AxisControls.
|
||||
/// [InputControl(layout = "Axis")]
|
||||
/// public int firstControl;
|
||||
///
|
||||
/// // Add a part to the composite called 'secondControl' which expects
|
||||
/// // Vector3Controls.
|
||||
/// [InputControl(layout = "Vector3")]
|
||||
/// public int secondControl;
|
||||
///
|
||||
/// //...
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControlLayout"/>
|
||||
/// <seealso cref="InputBindingComposite"/>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
|
||||
public sealed class InputControlAttribute : PropertyAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Layout to use for the control.
|
||||
/// </summary>
|
||||
/// <value>Layout to use for the control.</value>
|
||||
/// <remarks>
|
||||
/// If this is not set, the system tries to infer the layout type from the value type of
|
||||
/// the field or property. If the value type is itself registered as a layout, that layout
|
||||
/// will be used (e.g. when you have a property of type <see cref="Controls.ButtonControl"/>, the layout
|
||||
/// will be inferred to be "Button"). Otherwise, if a layout with the same name as the type is registered,
|
||||
/// that layout will be used (e.g. when you have a field of type <see cref="Vector3"/>, the layout
|
||||
/// will be inferred to be "Vector3").
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControlLayout"/>
|
||||
public string layout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Layout variant to use for the control.
|
||||
/// </summary>
|
||||
/// <value>Layout variant to use for the control.</value>
|
||||
public string variants { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name to give to the name. If null or empty, the name of the property or
|
||||
/// field the attribute is applied to will be used.
|
||||
/// </summary>
|
||||
/// <value>Name to give to the control.</value>
|
||||
/// <seealso cref="InputControl.name"/>
|
||||
public string name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Storage format to use for the control. If not set, default storage format
|
||||
/// for the given <see cref="layout"/> is used.
|
||||
/// </summary>
|
||||
/// <value>Memory storage format to use for the control.</value>
|
||||
/// <seealso cref="InputStateBlock.format"/>
|
||||
public string format { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Usage to apply to the control.
|
||||
/// </summary>
|
||||
/// <value>Usage for the control.</value>
|
||||
/// <remarks>
|
||||
/// This property can be used in place of <see cref="usages"/> to set just a single
|
||||
/// usage on the control.
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControl.usages"/>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.usages"/>
|
||||
/// <seealso cref="CommonUsages"/>
|
||||
public string usage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Usages to apply to the control.
|
||||
/// </summary>
|
||||
/// <value>Usages for the control.</value>
|
||||
/// <remarks>
|
||||
/// This property should be used instead of <see cref="usage"/> when a control has multiple usages.
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControl.usages"/>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.usages"/>
|
||||
/// <seealso cref="CommonUsages"/>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "According to MSDN, this message can be ignored for attribute parameters, as there are no better alternatives.")]
|
||||
public string[] usages { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional list of parameters to apply to the control.
|
||||
/// </summary>
|
||||
/// <value>Parameters to apply to the control.</value>
|
||||
/// <remarks>
|
||||
/// An <see cref="InputControl"/> may expose public fields which can be set as
|
||||
/// parameters. An example of this is <see cref="Controls.AxisControl.clamp"/>.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public struct MyStateStruct : IInputStateTypeInfo
|
||||
/// {
|
||||
/// [InputControl(parameters = "clamp,clampMin=-0.5,clampMax=0.5")]
|
||||
/// public float axis;
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.parameters"/>
|
||||
public string parameters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional list of processors to add to the control.
|
||||
/// </summary>
|
||||
/// <value>Processors to apply to the control.</value>
|
||||
/// <remarks>
|
||||
/// Each element in the list is a name of a processor (as registered with
|
||||
/// <see cref="InputSystem.RegisterProcessor{T}"/>) followed by an optional
|
||||
/// list of parameters.
|
||||
///
|
||||
/// For example, <c>"normalize(min=0,max=256)"</c> is one element that puts
|
||||
/// a <c>NormalizeProcessor</c> on the control and sets its <c>min</c> field
|
||||
/// to 0 and its its <c>max</c> field to 256.
|
||||
///
|
||||
/// Multiple processors can be put on a control by separating them with a comma.
|
||||
/// For example, <c>"normalize(max=256),scale(factor=2)"</c> puts both a <c>NormalizeProcessor</c>
|
||||
/// and a <c>ScaleProcessor</c> on the control. Processors are applied in the
|
||||
/// order they are listed.
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.processors"/>
|
||||
/// <seealso cref="InputBinding.processors"/>
|
||||
public string processors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An alternative name that can be used in place of <see cref="name"/> to find
|
||||
/// the control.
|
||||
/// </summary>
|
||||
/// <value>Alternative name for the control.</value>
|
||||
/// <remarks>
|
||||
/// This property can be used instead of <see cref="aliases"/> when there is only a
|
||||
/// single alias for the control.
|
||||
///
|
||||
/// Aliases, like names, are case-insensitive. Any control may have arbitrary many
|
||||
/// aliases.
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControl.aliases"/>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.aliases"/>
|
||||
public string alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of alternative names that can be used in place of <see cref="name"/> to
|
||||
/// find the control.
|
||||
/// </summary>
|
||||
/// <value>Alternative names for the control.</value>
|
||||
/// <remarks>
|
||||
/// This property should be used instead of <see cref="alias"/> when a control has
|
||||
/// multiple aliases.
|
||||
///
|
||||
/// Aliases, like names, are case-insensitive. Any control may have arbitrary many
|
||||
/// aliases.
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControl.aliases"/>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.aliases"/>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "According to MSDN, this message can be ignored for attribute parameters, as there are no better alternatives.")]
|
||||
public string[] aliases { get; set; }
|
||||
|
||||
public string useStateFrom { get; set; }
|
||||
|
||||
public uint bit { get; set; } = InputStateBlock.InvalidOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Offset in bytes to where the memory of the control starts. Relative to
|
||||
/// the offset of the parent control (which may be the device itself).
|
||||
/// </summary>
|
||||
/// <value>Byte offset of the control.</value>
|
||||
/// <remarks>
|
||||
/// If the attribute is applied to fields in an <see cref="InputControlLayout"/> and
|
||||
/// this property is not set, the offset of the field is used instead.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public struct MyStateStruct : IInputStateTypeInfo
|
||||
/// {
|
||||
/// public int buttons;
|
||||
///
|
||||
/// [InputControl] // Automatically uses the offset of 'axis'.
|
||||
/// public float axis;
|
||||
/// }
|
||||
///
|
||||
/// [InputControlLayout(stateType = typeof(MyStateStruct))]
|
||||
/// public class MyDevice : InputDevice
|
||||
/// {
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.offset"/>
|
||||
public uint offset { get; set; } = InputStateBlock.InvalidOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Size of the memory storage for the control in bits.
|
||||
/// </summary>
|
||||
/// <value>Size of the control in bits.</value>
|
||||
/// <remarks>
|
||||
/// If the attribute is applied to fields in an <see cref="InputControlLayout"/> and
|
||||
/// this property is not set, the size is taken from the field.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public struct MyStateStruct : IInputStateTypeInfo
|
||||
/// {
|
||||
/// public int buttons;
|
||||
///
|
||||
/// [InputControl] // Automatically uses sizeof(float).
|
||||
/// public float axis;
|
||||
/// }
|
||||
///
|
||||
/// [InputControlLayout(stateType = typeof(MyStateStruct))]
|
||||
/// public class MyDevice : InputDevice
|
||||
/// {
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.sizeInBits"/>
|
||||
/// <seealso cref="InputStateBlock.sizeInBits"/>
|
||||
public uint sizeInBits { get; set; }
|
||||
|
||||
public int arraySize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Display name to assign to the control.
|
||||
/// </summary>
|
||||
/// <value>Display name for the control.</value>
|
||||
/// <seealso cref="InputControl.displayName"/>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.displayName"/>
|
||||
public string displayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Short display name to assign to the control.
|
||||
/// </summary>
|
||||
/// <value>Short display name for the control.</value>
|
||||
/// <seealso cref="InputControl.shortDisplayName"/>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.shortDisplayName"/>
|
||||
public string shortDisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the control is noisy. Off by default.
|
||||
/// </summary>
|
||||
/// <value>Whether control is noisy.</value>
|
||||
/// <seealso cref="InputControl.noisy"/>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.isNoisy"/>
|
||||
public bool noisy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the control is synthetic. Off by default.
|
||||
/// </summary>
|
||||
/// <value>Whether control is synthetic.</value>
|
||||
/// <seealso cref="InputControl.synthetic"/>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.isSynthetic"/>
|
||||
public bool synthetic { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allows you to specify that a control should not be reset when its device is reset.
|
||||
/// </summary>
|
||||
/// <value>If true, resets of the device will leave the value of the control untouched except if a "hard" reset
|
||||
/// is explicitly enforced.</value>
|
||||
/// <seealso cref="InputSystem.ResetDevice"/>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.dontReset"/>
|
||||
public bool dontReset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default state to write into the control's memory.
|
||||
/// </summary>
|
||||
/// <value>Default memory state for the control.</value>
|
||||
/// <remarks>
|
||||
/// This is not the default <em>value</em> but rather the default memory state, i.e.
|
||||
/// the raw memory value read and the processed and returned as a value. By default
|
||||
/// this is <c>null</c> and result in a control's memory to be initialized with all
|
||||
/// zeroes.
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.defaultState"/>
|
||||
public object defaultState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Lower limit for values of the control.
|
||||
/// </summary>
|
||||
/// <value>Lower limit for values of the control.</value>
|
||||
/// <remarks>
|
||||
/// This is null by default in which case no lower bound is applied to the TODO
|
||||
/// </remarks>
|
||||
public object minValue { get; set; }
|
||||
public object maxValue { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f07d0a558a2d4f5c885936a3a1219008
|
||||
timeCreated: 1506739435
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8cfbe75f80984c1d9700ef41f6e2aeb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a2515c58b39ea24c8154ebc84f7c157
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
////REVIEW: should this *not* be inherited? inheritance can lead to surprises
|
||||
|
||||
namespace UnityEngine.InputSystem.Layouts
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute to control layout settings of a type used to generate an <see cref="InputControlLayout"/>.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||
public sealed class InputControlLayoutAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Associates a state representation with an input device and drives
|
||||
/// the control layout generated for the device from its state rather
|
||||
/// than from the device class.
|
||||
/// </summary>
|
||||
/// <remarks>This is *only* useful if you have a state struct dictating a specific
|
||||
/// state layout and you want the device layout to automatically take offsets from
|
||||
/// the fields annotated with <see cref="InputControlAttribute"/>.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public struct MyStateStruct : IInputStateTypeInfo
|
||||
/// {
|
||||
/// public FourCC format => new FourCC('M', 'Y', 'D', 'V');
|
||||
///
|
||||
/// [InputControl(name = "button1", layout = "Button", bit = 0)]
|
||||
/// [InputControl(name = "button2", layout = "Button", bit = 0)]
|
||||
/// public int buttons;
|
||||
/// }
|
||||
///
|
||||
/// [InputControlLayout(stateType = typeof(MyStateStruct)]
|
||||
/// public class MyDevice : InputDevice
|
||||
/// {
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
/// <seealso cref="LowLevel.InputStateBlock"/>
|
||||
/// <seealso cref="LowLevel.MouseState"/>
|
||||
public Type stateType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="FourCC"/> identifier for the memory format associated with the layout.
|
||||
/// </summary>
|
||||
/// <seealso cref="LowLevel.InputStateBlock.format"/>
|
||||
public string stateFormat { get; set; }
|
||||
|
||||
////TODO: rename this to just "usages"; "commonUsages" is such a weird name
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "According to MSDN, this message can be ignored for attribute parameters, as there are no better alternatives.")]
|
||||
public string[] commonUsages { get; set; }
|
||||
|
||||
public string variants { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allows marking a device as noisy regardless of control layout.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Controls can be individually marked as noisy using the <see cref="InputControlAttribute.noisy"/>
|
||||
/// attribute, but this property can be used to mark a device as noisy even when no control has been
|
||||
/// marked as such. This can be useful when a device state layout has only been partially implemented
|
||||
/// i.e. some data in the state memory has not been mapped to a control, and the unimplemented controls
|
||||
/// are noisy. Without doing this, the device will constantly be made current as the system has no way
|
||||
/// to know that the event data contains only noise.
|
||||
/// </remarks>
|
||||
public bool isNoisy { get; set; }
|
||||
|
||||
internal bool? canRunInBackgroundInternal;
|
||||
|
||||
public bool canRunInBackground
|
||||
{
|
||||
get => canRunInBackgroundInternal.Value;
|
||||
set => canRunInBackgroundInternal = value;
|
||||
}
|
||||
|
||||
internal bool? updateBeforeRenderInternal;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the device should receive events in <see cref="LowLevel.InputUpdateType.BeforeRender"/> updates.
|
||||
/// </summary>
|
||||
/// <seealso cref="InputDevice.updateBeforeRender"/>
|
||||
public bool updateBeforeRender
|
||||
{
|
||||
get => updateBeforeRenderInternal.Value;
|
||||
set => updateBeforeRenderInternal = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If true, the layout describes a generic class of devices such as "gamepads" or "mice".
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property also determines how the layout is presented in the UI. All the device layouts
|
||||
/// that are marked as generic kinds of devices are displayed with their own entry at the root level of
|
||||
/// the control picker (<see cref="UnityEngine.InputSystem.Editor.InputControlPicker"/>), for example.
|
||||
/// </remarks>
|
||||
public bool isGenericTypeOfDevice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gives a name to display in the UI. By default, the name is the same as the class the attribute
|
||||
/// is applied to.
|
||||
/// </summary>
|
||||
public string displayName { get; set; }
|
||||
|
||||
public string description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, don't include the layout when presenting picking options in the UI.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will keep device layouts out of the control picker and will keep control layouts out of
|
||||
/// action type dropdowns.
|
||||
/// </remarks>
|
||||
public bool hideInUI { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5256e0d1ebecc84d98a4001ab63d5b8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,12 @@
|
||||
namespace UnityEngine.InputSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum used to identity the change type for the <see cref="InputSystem.onLayoutChange"/> event.
|
||||
/// </summary>
|
||||
public enum InputControlLayoutChange
|
||||
{
|
||||
Added,
|
||||
Removed,
|
||||
Replaced
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5899dcacd4e3004eaa9107c97e75e09
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 543792e79adf14478b4a00527bbefce1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce150b9c1acd40e0a087ca3f3257831d
|
||||
timeCreated: 1507092303
|
@@ -0,0 +1,208 @@
|
||||
using System;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using UnityEngine.InputSystem.Layouts;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
////TODO: come up with a mechanism to allow (certain) processors to be stateful
|
||||
|
||||
////TODO: cache processors globally; there's no need to instantiate the same processor with the same parameters multiple times
|
||||
//// (except if they do end up being stateful)
|
||||
|
||||
namespace UnityEngine.InputSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// A processor that conditions/transforms input values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To define a custom processor, it is usable best to derive from <see cref="InputProcessor{TValue}"/>
|
||||
/// instead of from this class. Doing so will avoid having to deal with things such as the raw memory
|
||||
/// buffers of <see cref="Process"/>.
|
||||
///
|
||||
/// Note, however, that if you do want to define a processor that can process more than one type of
|
||||
/// value, you can derive directly from this class.
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputBinding.processors"/>
|
||||
/// <seealso cref="InputControlLayout.ControlItem.processors"/>
|
||||
/// <seealso cref="InputSystem.RegisterProcessor{T}"/>
|
||||
/// <seealso cref="InputActionRebindingExtensions.GetParameterValue(InputAction,string,InputBinding)"/>
|
||||
/// <seealso cref="InputActionRebindingExtensions.ApplyParameterOverride(InputActionMap,string,PrimitiveValue,InputBinding)"/>
|
||||
public abstract class InputProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// Process an input value, given as an object, and return the processed value as an object.
|
||||
/// </summary>
|
||||
/// <param name="value">A value matching the processor's value type.</param>
|
||||
/// <param name="control">Optional control that the value originated from. Must have the same value type
|
||||
/// that the processor has.</param>
|
||||
/// <returns>A processed value based on <paramref name="value"/>.</returns>
|
||||
/// <remarks>
|
||||
/// This method allocates GC heap memory. To process values without allocating GC memory, it is necessary to either know
|
||||
/// the value type of a processor at compile time and call <see cref="InputProcessor{TValue}.Process(TValue,UnityEngine.InputSystem.InputControl)"/>
|
||||
/// directly or to use <see cref="Process"/> instead and process values in raw memory buffers.
|
||||
/// </remarks>
|
||||
public abstract object ProcessAsObject(object value, InputControl control);
|
||||
|
||||
/// <summary>
|
||||
/// Process an input value stored in the given memory buffer.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Memory buffer containing the input value. Must be at least large enough
|
||||
/// to hold one full value as indicated by <paramref name="bufferSize"/>.</param>
|
||||
/// <param name="bufferSize">Size (in bytes) of the value inside <paramref name="buffer"/>.</param>
|
||||
/// <param name="control">Optional control that the value originated from. Must have the same value type
|
||||
/// that the processor has.</param>
|
||||
/// <remarks>
|
||||
/// This method allows processing values of arbitrary size without allocating memory on the GC heap.
|
||||
/// </remarks>
|
||||
public abstract unsafe void Process(void* buffer, int bufferSize, InputControl control);
|
||||
|
||||
internal static TypeTable s_Processors;
|
||||
|
||||
/// <summary>
|
||||
/// Get the value type of a processor without having to instantiate it and use <see cref="valueType"/>.
|
||||
/// </summary>
|
||||
/// <param name="processorType"></param>
|
||||
/// <returns>Value type of the given processor or null if it could not be determined statically.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="processorType"/> is null.</exception>
|
||||
/// <remarks>
|
||||
/// This method is reliant on the processor being based on <see cref="InputProcessor{TValue}"/>. It will return
|
||||
/// the <c>TValue</c> argument used with the class. If the processor is not based on <see cref="InputProcessor{TValue}"/>,
|
||||
/// this method returns null.
|
||||
/// </remarks>
|
||||
internal static Type GetValueTypeFromType(Type processorType)
|
||||
{
|
||||
if (processorType == null)
|
||||
throw new ArgumentNullException(nameof(processorType));
|
||||
|
||||
return TypeHelpers.GetGenericTypeArgumentFromHierarchy(processorType, typeof(InputProcessor<>), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caching policy regarding usage of return value from processors.
|
||||
/// </summary>
|
||||
public enum CachingPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache result value if unprocessed value has not been changed.
|
||||
/// </summary>
|
||||
CacheResult = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Process value every call to <see cref="InputControl{TValue}.ReadValue()"/> even if unprocessed value has not been changed.
|
||||
/// </summary>
|
||||
EvaluateOnEveryRead = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caching policy of the processor. Override this property to provide a different value.
|
||||
/// </summary>
|
||||
public virtual CachingPolicy cachingPolicy => CachingPolicy.CacheResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A processor that conditions/transforms input values.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">Type of value to be processed. Only InputControls that use the
|
||||
/// same value type will be compatible with the processor.</typeparam>
|
||||
/// <remarks>
|
||||
/// Each <see cref="InputControl"/> can have a stack of processors assigned to it.
|
||||
///
|
||||
/// Note that processors CANNOT be stateful. If you need processing that requires keeping
|
||||
/// mutating state over time, use InputActions. All mutable state needs to be
|
||||
/// kept in the central state buffers.
|
||||
///
|
||||
/// However, processors can have configurable parameters. Every public field on a processor
|
||||
/// object can be set using "parameters" in JSON or by supplying parameters through the
|
||||
/// <see cref="InputControlAttribute.processors"/> field.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public class ScalingProcessor : InputProcessor<float>
|
||||
/// {
|
||||
/// // This field can be set as a parameter. See examples below.
|
||||
/// // If not explicitly configured, will have its default value.
|
||||
/// public float factor = 2.0f;
|
||||
///
|
||||
/// public float Process(float value, InputControl control)
|
||||
/// {
|
||||
/// return value * factor;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Use processor in JSON:
|
||||
/// const string json = @"
|
||||
/// {
|
||||
/// ""name"" : ""MyDevice"",
|
||||
/// ""controls"" : [
|
||||
/// { ""name"" : ""axis"", ""layout"" : ""Axis"", ""processors"" : ""scale(factor=4)"" }
|
||||
/// ]
|
||||
/// }
|
||||
/// ";
|
||||
///
|
||||
/// // Use processor on C# state struct:
|
||||
/// public struct MyDeviceState : IInputStateTypeInfo
|
||||
/// {
|
||||
/// [InputControl(layout = "Axis", processors = "scale(factor=4)"]
|
||||
/// public float axis;
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
///
|
||||
/// See <see cref="Editor.InputParameterEditor{T}"/> for how to define custom parameter
|
||||
/// editing UIs for processors.
|
||||
/// </remarks>
|
||||
/// <seealso cref="InputSystem.RegisterProcessor"/>
|
||||
public abstract class InputProcessor<TValue> : InputProcessor
|
||||
where TValue : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Process the given value and return the result.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The implementation of this method must not be stateful.
|
||||
/// </remarks>
|
||||
/// <param name="value">Input value to process.</param>
|
||||
/// <param name="control">Control that the value originally came from. This can be null if the value did
|
||||
/// not originate from a control. This can be the case, for example, if the processor sits on a composite
|
||||
/// binding (<see cref="InputBindingComposite"/>) as composites are not directly associated with controls
|
||||
/// but rather source their values through their child bindings.</param>
|
||||
/// <returns>Processed input value.</returns>
|
||||
public abstract TValue Process(TValue value, InputControl control);
|
||||
|
||||
public override object ProcessAsObject(object value, InputControl control)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
|
||||
if (!(value is TValue))
|
||||
throw new ArgumentException(
|
||||
$"Expecting value of type '{typeof(TValue).Name}' but got value '{value}' of type '{value.GetType().Name}'",
|
||||
nameof(value));
|
||||
|
||||
var valueOfType = (TValue)value;
|
||||
|
||||
return Process(valueOfType, control);
|
||||
}
|
||||
|
||||
public override unsafe void Process(void* buffer, int bufferSize, InputControl control)
|
||||
{
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException(nameof(buffer));
|
||||
|
||||
var valueSize = UnsafeUtility.SizeOf<TValue>();
|
||||
if (bufferSize < valueSize)
|
||||
throw new ArgumentException(
|
||||
$"Expected buffer of at least {valueSize} bytes but got buffer with just {bufferSize} bytes",
|
||||
nameof(bufferSize));
|
||||
|
||||
var value = default(TValue);
|
||||
var valuePtr = UnsafeUtility.AddressOf(ref value);
|
||||
UnsafeUtility.MemCpy(valuePtr, buffer, valueSize);
|
||||
|
||||
value = Process(value, control);
|
||||
|
||||
valuePtr = UnsafeUtility.AddressOf(ref value);
|
||||
UnsafeUtility.MemCpy(buffer, valuePtr, valueSize);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c79fd316c31a2402692c908865404608
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,56 @@
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.InputSystem.Utilities;
|
||||
|
||||
////TODO: this or the layout system needs to detect when the format isn't supported by the control
|
||||
|
||||
namespace UnityEngine.InputSystem.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// A generic input control reading integer values.
|
||||
/// </summary>
|
||||
public class IntegerControl : InputControl<int>
|
||||
{
|
||||
/// <summary>
|
||||
/// Default-initialize an integer control.
|
||||
/// </summary>
|
||||
public IntegerControl()
|
||||
{
|
||||
m_StateBlock.format = InputStateBlock.FormatInt;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override unsafe int ReadUnprocessedValueFromState(void* statePtr)
|
||||
{
|
||||
switch (m_OptimizedControlDataType)
|
||||
{
|
||||
case InputStateBlock.kFormatInt:
|
||||
return *(int*)((byte*)statePtr + (int)m_StateBlock.byteOffset);
|
||||
default:
|
||||
return m_StateBlock.ReadInt(statePtr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override unsafe void WriteValueIntoState(int value, void* statePtr)
|
||||
{
|
||||
switch (m_OptimizedControlDataType)
|
||||
{
|
||||
case InputStateBlock.kFormatInt:
|
||||
*(int*)((byte*)statePtr + (int)m_StateBlock.byteOffset) = value;
|
||||
break;
|
||||
default:
|
||||
m_StateBlock.WriteInt(statePtr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override FourCC CalculateOptimizedControlDataType()
|
||||
{
|
||||
if (m_StateBlock.format == InputStateBlock.FormatInt &&
|
||||
m_StateBlock.sizeInBits == 32 &&
|
||||
m_StateBlock.bitOffset == 0)
|
||||
return InputStateBlock.FormatInt;
|
||||
return InputStateBlock.FormatInvalid;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7009ea2cce278c14d852537c8f40c8a0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,99 @@
|
||||
using System.Globalization;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
namespace UnityEngine.InputSystem.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// A key on a <see cref="Keyboard"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is an extended button control which adds various features to account for the fact that keys
|
||||
/// have symbols associated with them which may change depending on keyboard layout as well as in combination
|
||||
/// with other keys.
|
||||
///
|
||||
/// Note:
|
||||
/// Unity input system key codes and input manager key codes are designed with game controls in mind.
|
||||
///
|
||||
/// This means the way they are assigned is intended to preserve the location of keys on keyboards,
|
||||
/// so that pressing a key in the same location on different keyboards should result in the same action
|
||||
/// regardless of what is printed on a key or what current system language is set.
|
||||
///
|
||||
/// This means, for example, that <see cref="Key.A"/> is always the key to the right of <see cref="Key.CapsLock"/>,
|
||||
/// regardless of which key (if any) produces the "a" character on the current keyboard layout.
|
||||
///
|
||||
/// Unity relies on physical hardware in the keyboards to report same USB HID "usage" for the keys in
|
||||
/// the same location.This puts a practical limit on what can be achieved, because different keyboards
|
||||
/// might report different data, and this is outside of Unity's control.
|
||||
///
|
||||
/// For this reason, you should not use key codes to read text input.
|
||||
/// Instead, you should use the <see cref="Keyboard.onTextInput"/> callback.
|
||||
/// The `onTextInput` callback provides you with the actual text characters which correspond
|
||||
/// to the symbols printed on a keyboard, based on the end user's current system language layout.
|
||||
///
|
||||
/// To find the text character (if any) generated by a key according to the currently active keyboard
|
||||
/// layout, use the <see cref="InputControl.displayName"/> property of <see cref="KeyControl"/>.
|
||||
/// </remarks>
|
||||
public class KeyControl : ButtonControl
|
||||
{
|
||||
/// <summary>
|
||||
/// The code used in Unity to identify the key.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property must be initialized by <see cref="InputControl.FinishSetup"/> of
|
||||
/// the device owning the control.
|
||||
/// You should not use `keyCode` to read text input. For more information, <see cref="KeyControl"/>
|
||||
/// </remarks>
|
||||
public Key keyCode { get; set; }
|
||||
|
||||
////REVIEW: rename this to something like platformKeyCode? We're not really dealing with scan code here.
|
||||
/// <summary>
|
||||
/// The code that the underlying platform uses to identify the key.
|
||||
/// </summary>
|
||||
public int scanCode
|
||||
{
|
||||
get
|
||||
{
|
||||
RefreshConfigurationIfNeeded();
|
||||
return m_ScanCode;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RefreshConfiguration()
|
||||
{
|
||||
// Wipe our last cached set of data (if any).
|
||||
displayName = null;
|
||||
m_ScanCode = 0;
|
||||
|
||||
var command = QueryKeyNameCommand.Create(keyCode);
|
||||
if (device.ExecuteCommand(ref command) > 0)
|
||||
{
|
||||
m_ScanCode = command.scanOrKeyCode;
|
||||
|
||||
var rawKeyName = command.ReadKeyName();
|
||||
if (string.IsNullOrEmpty(rawKeyName))
|
||||
{
|
||||
displayName = rawKeyName;
|
||||
return;
|
||||
}
|
||||
|
||||
var textInfo = CultureInfo.InvariantCulture.TextInfo;
|
||||
// We need to lower case first because ToTitleCase preserves upper casing.
|
||||
// For example on Swedish Windows layout right shift display name is "HÖGER SKIFT".
|
||||
// Just passing it to ToTitleCase won't change anything. But passing "höger skift" will return "Höger Skift".
|
||||
var keyNameLowerCase = textInfo.ToLower(rawKeyName);
|
||||
if (string.IsNullOrEmpty(keyNameLowerCase))
|
||||
{
|
||||
displayName = rawKeyName;
|
||||
return;
|
||||
}
|
||||
|
||||
displayName = textInfo.ToTitleCase(keyNameLowerCase);
|
||||
}
|
||||
}
|
||||
|
||||
// Cached configuration data for the key. We fetch this from the
|
||||
// device on demand.
|
||||
private int m_ScanCode;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d7a42e3bb8b4c0f877cbe19718a4103
|
||||
timeCreated: 1510949927
|
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6fde91b0a4ee45cd86be18a8d829dc87
|
||||
folderAsset: yes
|
||||
timeCreated: 1506735469
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine.InputSystem.Editor;
|
||||
using UnityEngine.UIElements;
|
||||
#endif
|
||||
|
||||
namespace UnityEngine.InputSystem.Processors
|
||||
{
|
||||
/// <summary>
|
||||
/// Clamps values to the range given by <see cref="min"/> and <see cref="max"/> and re-normalizes the resulting
|
||||
/// value to [0..1].
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This processor is registered (see <see cref="InputSystem.RegisterProcessor{T}"/>) under the name "AxisDeadzone".
|
||||
///
|
||||
/// It acts like a combination of <see cref="ClampProcessor"/> and <see cref="NormalizeProcessor"/>.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// </code>
|
||||
/// // Bind to right trigger on gamepad such that the value is clamped and normalized between
|
||||
/// // 0.3 and 0.7.
|
||||
/// new InputAction(binding: "<Gamepad>/rightTrigger", processors: "axisDeadzone(min=0.3,max=0.7)");
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
/// <seealso cref="StickDeadzoneProcessor"/>
|
||||
public class AxisDeadzoneProcessor : InputProcessor<float>
|
||||
{
|
||||
/// <summary>
|
||||
/// Lower bound (inclusive) below which input values get clamped. Corresponds to 0 in the normalized range.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If this is equal to 0 (the default), <see cref="InputSettings.defaultDeadzoneMin"/> is used instead.
|
||||
/// </remarks>
|
||||
public float min;
|
||||
|
||||
/// <summary>
|
||||
/// Upper bound (inclusive) beyond which input values get clamped. Corresponds to 1 in the normalized range.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If this is equal to 0 (the default), <see cref="InputSettings.defaultDeadzoneMax"/> is used instead.
|
||||
/// </remarks>
|
||||
public float max;
|
||||
|
||||
private float minOrDefault => min == default ? InputSystem.settings.defaultDeadzoneMin : min;
|
||||
private float maxOrDefault => max == default ? InputSystem.settings.defaultDeadzoneMax : max;
|
||||
|
||||
/// <summary>
|
||||
/// Normalize <paramref name="value"/> according to <see cref="min"/> and <see cref="max"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">Input value.</param>
|
||||
/// <param name="control">Ignored.</param>
|
||||
/// <returns>Normalized value.</returns>
|
||||
public override float Process(float value, InputControl control = null)
|
||||
{
|
||||
var min = minOrDefault;
|
||||
var max = maxOrDefault;
|
||||
|
||||
var absValue = Mathf.Abs(value);
|
||||
if (absValue < min)
|
||||
return 0;
|
||||
if (absValue > max)
|
||||
return Mathf.Sign(value);
|
||||
|
||||
return Mathf.Sign(value) * ((absValue - min) / (max - min));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"AxisDeadzone(min={minOrDefault},max={maxOrDefault})";
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal class AxisDeadzoneProcessorEditor : InputParameterEditor<AxisDeadzoneProcessor>
|
||||
{
|
||||
protected override void OnEnable()
|
||||
{
|
||||
m_MinSetting.Initialize("Min",
|
||||
"Value below which input values will be clamped. After clamping, values will be renormalized to [0..1] between min and max.",
|
||||
"Default Deadzone Min",
|
||||
() => target.min, v => target.min = v,
|
||||
() => InputSystem.settings.defaultDeadzoneMin);
|
||||
m_MaxSetting.Initialize("Max",
|
||||
"Value above which input values will be clamped. After clamping, values will be renormalized to [0..1] between min and max.",
|
||||
"Default Deadzone Max",
|
||||
() => target.max, v => target.max = v,
|
||||
() => InputSystem.settings.defaultDeadzoneMax);
|
||||
}
|
||||
|
||||
public override void OnGUI()
|
||||
{
|
||||
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
|
||||
if (!InputSystem.settings.IsFeatureEnabled(InputFeatureNames.kUseIMGUIEditorForAssets)) return;
|
||||
#endif
|
||||
m_MinSetting.OnGUI();
|
||||
m_MaxSetting.OnGUI();
|
||||
}
|
||||
|
||||
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
|
||||
public override void OnDrawVisualElements(VisualElement root, Action onChangedCallback)
|
||||
{
|
||||
m_MinSetting.OnDrawVisualElements(root, onChangedCallback);
|
||||
m_MaxSetting.OnDrawVisualElements(root, onChangedCallback);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private CustomOrDefaultSetting m_MinSetting;
|
||||
private CustomOrDefaultSetting m_MaxSetting;
|
||||
}
|
||||
#endif
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 110e42b335c6744e482ada733cbda674
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,55 @@
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
////TODO: move clamping settings into struct and add process function; then embed both here and in AxisControl
|
||||
|
||||
namespace UnityEngine.InputSystem.Processors
|
||||
{
|
||||
/// <summary>
|
||||
/// Clamp a floating-point input to between <see cref="min"/> and <see cref="max"/>. This is equivalent
|
||||
/// to <c>Mathf.Clamp(value, min, max)</c>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This processor is registered (see <see cref="InputSystem.RegisterProcessor{T}"/>) under the name "clamp" by default.
|
||||
///
|
||||
/// Note that no normalization is performed. If you want to re-normalize the input value after clamping,
|
||||
/// add a <see cref="NormalizeProcessor"/>. Alternatively, add a <see cref="AxisDeadzoneProcessor"/> which
|
||||
/// both clamps and normalizes.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// </code>
|
||||
/// // Bind to right trigger on gamepad such that the value never drops below 0.3 and never goes
|
||||
/// // above 0.7.
|
||||
/// new InputAction(binding: "<Gamepad>/rightTrigger", processors: "clamp(min=0.3,max=0.7)");
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public class ClampProcessor : InputProcessor<float>
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimum value (inclusive!) of the accepted value range.
|
||||
/// </summary>
|
||||
public float min;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum value (inclusive!) of the accepted value range.
|
||||
/// </summary>
|
||||
public float max;
|
||||
|
||||
/// <summary>
|
||||
/// Clamp <paramref name="value"/> to the range of <see cref="min"/> and <see cref="max"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">Input value.</param>
|
||||
/// <param name="control">Ignored.</param>
|
||||
/// <returns>Clamped value.</returns>
|
||||
public override float Process(float value, InputControl control)
|
||||
{
|
||||
return Mathf.Clamp(value, min, max);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Clamp(min={min},max={max})";
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6887ac562f464a329bc468158dbbf18f
|
||||
timeCreated: 1506740041
|
@@ -0,0 +1,31 @@
|
||||
using System.ComponentModel;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
|
||||
namespace UnityEngine.InputSystem.Processors
|
||||
{
|
||||
[DesignTimeVisible(false)]
|
||||
internal class CompensateDirectionProcessor : InputProcessor<Vector3>
|
||||
{
|
||||
public override Vector3 Process(Vector3 value, InputControl control)
|
||||
{
|
||||
if (!InputSystem.settings.compensateForScreenOrientation)
|
||||
return value;
|
||||
|
||||
var rotation = Quaternion.identity;
|
||||
switch (InputRuntime.s_Instance.screenOrientation)
|
||||
{
|
||||
case ScreenOrientation.PortraitUpsideDown: rotation = Quaternion.Euler(0, 0, 180); break;
|
||||
case ScreenOrientation.LandscapeLeft: rotation = Quaternion.Euler(0, 0, 90); break;
|
||||
case ScreenOrientation.LandscapeRight: rotation = Quaternion.Euler(0, 0, 270); break;
|
||||
}
|
||||
return rotation * value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "CompensateDirection()";
|
||||
}
|
||||
|
||||
public override CachingPolicy cachingPolicy => CachingPolicy.EvaluateOnEveryRead;
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dbce6ac3ce95e4e28af8b2212171619a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,34 @@
|
||||
using System.ComponentModel;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
|
||||
namespace UnityEngine.InputSystem.Processors
|
||||
{
|
||||
[DesignTimeVisible(false)]
|
||||
internal class CompensateRotationProcessor : InputProcessor<Quaternion>
|
||||
{
|
||||
public override Quaternion Process(Quaternion value, InputControl control)
|
||||
{
|
||||
if (!InputSystem.settings.compensateForScreenOrientation)
|
||||
return value;
|
||||
|
||||
const float kSqrtOfTwo = 1.4142135623731f;
|
||||
var q = Quaternion.identity;
|
||||
|
||||
switch (InputRuntime.s_Instance.screenOrientation)
|
||||
{
|
||||
case ScreenOrientation.PortraitUpsideDown: q = new Quaternion(0.0f, 0.0f, 1.0f /*sin(pi/2)*/, 0.0f /*cos(pi/2)*/); break;
|
||||
case ScreenOrientation.LandscapeLeft: q = new Quaternion(0.0f, 0.0f, kSqrtOfTwo * 0.5f /*sin(pi/4)*/, -kSqrtOfTwo * 0.5f /*cos(pi/4)*/); break;
|
||||
case ScreenOrientation.LandscapeRight: q = new Quaternion(0.0f, 0.0f, -kSqrtOfTwo * 0.5f /*sin(3pi/4)*/, -kSqrtOfTwo * 0.5f /*cos(3pi/4)*/); break;
|
||||
}
|
||||
|
||||
return value * q;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "CompensateRotation()";
|
||||
}
|
||||
|
||||
public override CachingPolicy cachingPolicy => CachingPolicy.EvaluateOnEveryRead;
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ef7b744d03d44f2a82c38ac2f25b21f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,56 @@
|
||||
#if UNITY_EDITOR || PACKAGE_DOCS_GENERATION
|
||||
using System.ComponentModel;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
using UnityEditor;
|
||||
|
||||
namespace UnityEngine.InputSystem.Processors
|
||||
{
|
||||
/// <summary>
|
||||
/// If Unity is currently in an <see cref="EditorWindow"/> callback, transforms a 2D coordinate from
|
||||
/// player window space into window space of the current EditorWindow.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This processor is only available in the editor. Also, it only works on devices that
|
||||
/// support the <see cref="QueryEditorWindowCoordinatesCommand"/> request.
|
||||
///
|
||||
/// Outside of <see cref="EditorWindow"/> callbacks, this processor does nothing and just passes through
|
||||
/// the coordinates it receives.
|
||||
/// </remarks>
|
||||
/// <seealso cref="Pointer.position"/>
|
||||
[DesignTimeVisible(false)]
|
||||
public class EditorWindowSpaceProcessor : InputProcessor<Vector2>
|
||||
{
|
||||
/// <summary>
|
||||
/// Transform the given player screen-space coordinate into the coordinate space of the current
|
||||
/// <c>EditorWindow</c>.
|
||||
/// </summary>
|
||||
/// <param name="value">GameView screen space coordinate.</param>
|
||||
/// <param name="control">Ignored.</param>
|
||||
/// <returns>The given coordinate transformed into <c>EditorWindow</c> space.</returns>
|
||||
/// <remarks>
|
||||
/// This method will only succeed if the editor is currently in an <c>EditorWindow</c> callback such
|
||||
/// as <c>OnGUI</c>.
|
||||
/// </remarks>
|
||||
public override Vector2 Process(Vector2 value, InputControl control)
|
||||
{
|
||||
// We go and fire trigger QueryEditorWindowCoordinatesCommand regardless
|
||||
// of whether we are currently in EditorWindow code or not. The expectation
|
||||
// here is that the underlying editor code is in a better position than us
|
||||
// to judge whether the conversion should be performed or not. In native code,
|
||||
// the IOCTL implementations will early out if they detect that the current
|
||||
// EditorWindow is in fact a game view.
|
||||
|
||||
if (Mouse.s_PlatformMouseDevice != null)
|
||||
{
|
||||
var command = QueryEditorWindowCoordinatesCommand.Create(value);
|
||||
// Not all pointer devices implement the editor window position IOCTL,
|
||||
// so we try the global mouse device if available.
|
||||
if (Mouse.s_PlatformMouseDevice.ExecuteCommand(ref command) > 0)
|
||||
return command.inOutCoordinates;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // UNITY_EDITOR
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87ce818774f4c544882b249f32619300
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,37 @@
|
||||
using UnityEngine.Scripting;
|
||||
|
||||
namespace UnityEngine.InputSystem.Processors
|
||||
{
|
||||
/// <summary>
|
||||
/// An input processor that inverts its input value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This process is registered (see <see cref="InputSystem.RegisterProcessor{T}"/> as "invert" by default.
|
||||
///
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // Bind to the gamepad's left trigger such that it returns inverted values.
|
||||
/// new InputAction(binding: "<Gamepad>/leftTrigger", processors="invert");
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public class InvertProcessor : InputProcessor<float>
|
||||
{
|
||||
/// <summary>
|
||||
/// Return the inverted value of <paramref name="value"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">Input value.</param>
|
||||
/// <param name="control">Ignored.</param>
|
||||
/// <returns>Invert value.</returns>
|
||||
public override float Process(float value, InputControl control)
|
||||
{
|
||||
return value * -1.0f;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return "Invert()";
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user