123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- using System.Runtime.InteropServices;
- using UnityEngine.InputSystem.Controls;
- using UnityEngine.InputSystem.Layouts;
- using UnityEngine.InputSystem.LowLevel;
- using UnityEngine.InputSystem.Utilities;
- ////TODO: option to allow to constrain mouse input to the screen area (i.e. no input once mouse leaves player window)
- namespace UnityEngine.InputSystem.LowLevel
- {
- /// <summary>
- /// Combine a single pointer with buttons and a scroll wheel.
- /// </summary>
- // IMPORTANT: State layout must match with MouseInputState in native.
- [StructLayout(LayoutKind.Explicit, Size = 30)]
- public struct MouseState : IInputStateTypeInfo
- {
- /// <summary>
- /// Memory format identifier for MouseState.
- /// </summary>
- /// <value>Returns "MOUS".</value>
- /// <seealso cref="InputStateBlock.format"/>
- public static FourCC Format => new FourCC('M', 'O', 'U', 'S');
- /// <summary>
- /// Screen-space position of the mouse in pixels.
- /// </summary>
- /// <value>Position of mouse on screen.</value>
- /// <seealso cref="Mouse.position"/>
- [InputControl(usage = "Point")]
- [FieldOffset(0)]
- public Vector2 position;
- /// <summary>
- /// Screen-space motion delta of the mouse in pixels.
- /// </summary>
- /// <value>Mouse movement.</value>
- /// <seealso cref="Mouse.delta"/>
- [InputControl(usage = "Secondary2DMotion")]
- [FieldOffset(8)]
- public Vector2 delta;
- ////REVIEW: have half-axis buttons on the scroll axes? (up, down, left, right)
- /// <summary>
- /// Scroll-wheel delta of the mouse.
- /// </summary>
- /// <value>Scroll wheel delta.</value>
- /// <seealso cref="Mouse.scroll"/>
- [InputControl(displayName = "Scroll")]
- [InputControl(name = "scroll/x", aliases = new[] { "horizontal" }, usage = "ScrollHorizontal", displayName = "Left/Right")]
- [InputControl(name = "scroll/y", aliases = new[] { "vertical" }, usage = "ScrollVertical", displayName = "Up/Down", shortDisplayName = "Wheel")]
- [FieldOffset(16)]
- public Vector2 scroll;
- /// <summary>
- /// Button mask for which buttons on the mouse are currently pressed.
- /// </summary>
- /// <value>Button state mask.</value>
- /// <seealso cref="MouseButton"/>
- /// <seealso cref="Mouse.leftButton"/>
- /// <seealso cref="Mouse.middleButton"/>
- /// <seealso cref="Mouse.rightButton"/>
- /// <seealso cref="Mouse.forwardButton"/>
- /// <seealso cref="Mouse.backButton"/>
- [InputControl(name = "press", useStateFrom = "leftButton", synthetic = true, usages = new string[0])]
- [InputControl(name = "leftButton", layout = "Button", bit = (int)MouseButton.Left, usage = "PrimaryAction", displayName = "Left Button", shortDisplayName = "LMB")]
- [InputControl(name = "rightButton", layout = "Button", bit = (int)MouseButton.Right, usage = "SecondaryAction", displayName = "Right Button", shortDisplayName = "RMB")]
- [InputControl(name = "middleButton", layout = "Button", bit = (int)MouseButton.Middle, displayName = "Middle Button", shortDisplayName = "MMB")]
- [InputControl(name = "forwardButton", layout = "Button", bit = (int)MouseButton.Forward, usage = "Forward", displayName = "Forward")]
- [InputControl(name = "backButton", layout = "Button", bit = (int)MouseButton.Back, usage = "Back", displayName = "Back")]
- [FieldOffset(24)]
- // "Park" all the controls that are common to pointers but aren't use for mice such that they get
- // appended to the end of device state where they will always have default values.
- ////FIXME: InputDeviceBuilder will get fooled and set up an incorrect state layout if we don't force this to VEC2; InputControlLayout will
- //// "infer" USHT as the format which will then end up with a layout where two 4 byte float controls are "packed" into a 16bit sized parent;
- //// in other words, setting VEC2 here manually should *not* be necessary
- [InputControl(name = "pressure", layout = "Axis", usage = "Pressure", offset = InputStateBlock.AutomaticOffset, format = "FLT", sizeInBits = 32)]
- [InputControl(name = "radius", layout = "Vector2", usage = "Radius", offset = InputStateBlock.AutomaticOffset, format = "VEC2", sizeInBits = 64)]
- [InputControl(name = "pointerId", layout = "Digital", format = "BIT", sizeInBits = 1, offset = InputStateBlock.AutomaticOffset)] // Will stay at 0.
- public ushort buttons;
- // Not currently used, but still needed in this struct for padding,
- // as il2cpp does not implement FieldOffset.
- [FieldOffset(26)]
- ushort displayIndex;
- /// <summary>
- /// Number of clicks performed in succession.
- /// </summary>
- /// <value>Successive click count.</value>
- /// <seealso cref="Mouse.clickCount"/>
- [InputControl(layout = "Integer", displayName = "Click Count", synthetic = true)]
- [FieldOffset(28)]
- public ushort clickCount;
- /// <summary>
- /// Set the button mask for the given button.
- /// </summary>
- /// <param name="button">Button whose state to set.</param>
- /// <param name="state">Whether to set the bit on or off.</param>
- /// <returns>The same MouseState with the change applied.</returns>
- /// <seealso cref="buttons"/>
- public MouseState WithButton(MouseButton button, bool state = true)
- {
- var bit = 1 << (int)button;
- if (state)
- buttons |= (ushort)bit;
- else
- buttons &= (ushort)~bit;
- return this;
- }
- /// <summary>
- /// Returns <see cref="Format"/>.
- /// </summary>
- /// <seealso cref="InputStateBlock.format"/>
- public FourCC format => Format;
- }
- /// <summary>
- /// Button indices for <see cref="MouseState.buttons"/>.
- /// </summary>
- public enum MouseButton
- {
- /// <summary>
- /// Left mouse button.
- /// </summary>
- /// <seealso cref="Mouse.leftButton"/>
- Left,
- /// <summary>
- /// Right mouse button.
- /// </summary>
- /// <seealso cref="Mouse.rightButton"/>
- Right,
- /// <summary>
- /// Middle mouse button.
- /// </summary>
- /// <seealso cref="Mouse.middleButton"/>
- Middle,
- /// <summary>
- /// Second side button.
- /// </summary>
- /// <seealso cref="Mouse.forwardButton"/>
- Forward,
- /// <summary>
- /// First side button.
- /// </summary>
- /// <seealso cref="Mouse.backButton"/>
- Back
- }
- }
- namespace UnityEngine.InputSystem
- {
- /// <summary>
- /// An input device representing a mouse.
- /// </summary>
- /// <remarks>
- /// Adds a scroll wheel and a typical 3-button setup with a left, middle, and right
- /// button.
- ///
- /// To control cursor display and behavior, use <see cref="UnityEngine.Cursor"/>.
- /// </remarks>
- [InputControlLayout(stateType = typeof(MouseState), isGenericTypeOfDevice = true)]
- [Scripting.Preserve]
- public class Mouse : Pointer, IInputStateCallbackReceiver
- {
- /// <summary>
- /// The horizontal and vertical scroll wheels.
- /// </summary>
- /// <value>Control representing the mouse scroll wheels.</value>
- /// <remarks>
- /// The <c>x</c> component corresponds to the horizontal scroll wheel, the
- /// <c>y</c> component to the vertical scroll wheel. Most mice do not have
- /// horizontal scroll wheels and will thus only see activity on <c>y</c>.
- /// </remarks>
- public Vector2Control scroll { get; private set; }
- /// <summary>
- /// The left mouse button.
- /// </summary>
- /// <value>Control representing the left mouse button.</value>
- public ButtonControl leftButton { get; private set; }
- /// <summary>
- /// The middle mouse button.
- /// </summary>
- /// <value>Control representing the middle mouse button.</value>
- public ButtonControl middleButton { get; private set; }
- /// <summary>
- /// The right mouse button.
- /// </summary>
- /// <value>Control representing the right mouse button.</value>
- public ButtonControl rightButton { get; private set; }
- /// <summary>
- /// The first side button, often labeled/used as "back".
- /// </summary>
- /// <value>Control representing the back button on the mouse.</value>
- /// <remarks>
- /// On Windows, this corresponds to <c>RI_MOUSE_BUTTON_4</c>.
- /// </remarks>
- public ButtonControl backButton { get; private set; }
- /// <summary>
- /// The second side button, often labeled/used as "forward".
- /// </summary>
- /// <value>Control representing the forward button on the mouse.</value>
- /// <remarks>
- /// On Windows, this corresponds to <c>RI_MOUSE_BUTTON_5</c>.
- /// </remarks>
- public ButtonControl forwardButton { get; private set; }
- /// <summary>
- /// Number of times any of the mouse buttons has been clicked in succession within
- /// the system-defined click time threshold.
- /// </summary>
- /// <value>Control representing the mouse click count.</value>
- public IntegerControl clickCount { get; private set; }
- /// <summary>
- /// The mouse that was added or updated last or null if there is no mouse
- /// connected to the system.
- /// </summary>
- /// <seealso cref="InputDevice.MakeCurrent"/>
- public new static Mouse current { get; private set; }
- /// <summary>
- /// Called when the mouse becomes the current mouse.
- /// </summary>
- public override void MakeCurrent()
- {
- base.MakeCurrent();
- current = this;
- }
- /// <summary>
- /// Called when the mouse is added to the system.
- /// </summary>
- protected override void OnAdded()
- {
- base.OnAdded();
- if (native && s_PlatformMouseDevice == null)
- s_PlatformMouseDevice = this;
- }
- /// <summary>
- /// Called when the device is removed from the system.
- /// </summary>
- protected override void OnRemoved()
- {
- base.OnRemoved();
- if (current == this)
- current = null;
- }
- internal static Mouse s_PlatformMouseDevice;
- ////REVIEW: how should we handle this being called from EditorWindow's? (where the editor window space processor will turn coordinates automatically into editor window space)
- /// <summary>
- /// Move the operating system's mouse cursor.
- /// </summary>
- /// <param name="position">New position in player window space.</param>
- /// <remarks>
- /// The <see cref="Pointer.position"/> property will not update immediately but rather will update in the
- /// next input update.
- /// </remarks>
- public void WarpCursorPosition(Vector2 position)
- {
- var command = WarpMousePositionCommand.Create(position);
- ExecuteCommand(ref command);
- }
- /// <inheritdoc />
- protected override void FinishSetup()
- {
- scroll = GetChildControl<Vector2Control>("scroll");
- leftButton = GetChildControl<ButtonControl>("leftButton");
- middleButton = GetChildControl<ButtonControl>("middleButton");
- rightButton = GetChildControl<ButtonControl>("rightButton");
- forwardButton = GetChildControl<ButtonControl>("forwardButton");
- backButton = GetChildControl<ButtonControl>("backButton");
- clickCount = GetChildControl<IntegerControl>("clickCount");
- base.FinishSetup();
- }
- /// <summary>
- /// Implements <see cref="IInputStateCallbackReceiver.OnNextUpdate"/> for the mouse.
- /// </summary>
- protected new void OnNextUpdate()
- {
- base.OnNextUpdate();
- InputState.Change(scroll, Vector2.zero);
- }
- /// <summary>
- /// Implements <see cref="IInputStateCallbackReceiver.OnStateEvent"/> for the mouse.
- /// </summary>
- /// <param name="eventPtr"></param>
- protected new unsafe void OnStateEvent(InputEventPtr eventPtr)
- {
- var statePtr = currentStatePtr;
- scroll.x.AccumulateValueInEvent(statePtr, eventPtr);
- scroll.y.AccumulateValueInEvent(statePtr, eventPtr);
- base.OnStateEvent(eventPtr);
- }
- void IInputStateCallbackReceiver.OnNextUpdate()
- {
- OnNextUpdate();
- }
- void IInputStateCallbackReceiver.OnStateEvent(InputEventPtr eventPtr)
- {
- OnStateEvent(eventPtr);
- }
- }
- }
|