[Platform] Improved mouse interface
authorthefiddler <stapostol@gmail.com>
Sat, 3 May 2014 23:29:55 +0000 (01:29 +0200)
committerthefiddler <stapostol@gmail.com>
Sat, 3 May 2014 23:29:55 +0000 (01:29 +0200)
- The complete mouse state is now available in mouse events
- Horizontal wheels are now supported
- MouseState now takes up less memory and has a simpler internal
implementation.

16 files changed:
Source/Examples/OpenTK/Test/GameWindowStates.cs
Source/OpenTK/Input/MouseDevice.cs
Source/OpenTK/Input/MouseEventArgs.cs [new file with mode: 0644]
Source/OpenTK/Input/MouseScrollWheel.cs [new file with mode: 0644]
Source/OpenTK/Input/MouseState.cs
Source/OpenTK/OpenTK.csproj
Source/OpenTK/Platform/LegacyInputDriver.cs
Source/OpenTK/Platform/MacOS/CocoaNativeWindow.cs
Source/OpenTK/Platform/MacOS/HIDInput.cs
Source/OpenTK/Platform/NativeWindowBase.cs
Source/OpenTK/Platform/SDL2/Sdl2Mouse.cs
Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs
Source/OpenTK/Platform/Windows/API.cs
Source/OpenTK/Platform/Windows/WinGLNative.cs
Source/OpenTK/Platform/Windows/WinRawMouse.cs
Source/OpenTK/Platform/X11/XI2Mouse.cs

index e75f897..703c608 100644 (file)
@@ -126,8 +126,8 @@ namespace Examples.Tests
         {
             mouse_pos.X = e.X;
             mouse_pos.Y = e.Y;
-            mouse_pos.Z = e.Wheel.X;
-            mouse_pos.W = e.Wheel.Y;
+            mouse_pos.Z = e.Mouse.Scroll.X;
+            mouse_pos.W = e.Mouse.Scroll.Y;
         }
 
         void MouseButtonHandler(object sender, MouseButtonEventArgs e)
@@ -149,8 +149,8 @@ namespace Examples.Tests
 
         void MouseWheelHandler(object sender, MouseWheelEventArgs e)
         {
-            mouse_pos.Z += e.Wheel.Y;
-            mouse_pos.W += e.Wheel.X;
+            mouse_pos.Z += e.Mouse.Scroll.Y;
+            mouse_pos.W += e.Mouse.Scroll.X;
         }
 
         static int Clamp(int val, int min, int max)
index ebcd7f7..85b9f83 100644 (file)
@@ -361,398 +361,4 @@ namespace OpenTK.Input
 
         #endregion
     }
-
-    /// <summary>
-    /// Represents a mouse wheel.
-    /// </summary>
-    public sealed class MouseWheel
-    {
-        /// <summary>
-        /// Gets the X offset of the wheel.
-        /// </summary>
-        /// <value>The x.</value>
-        public float X { get; internal set; }
-
-        /// <summary>
-        /// Gets the Y offset of the wheel.
-        /// </summary>
-        /// <value>The y.</value>
-        public float Y { get; internal set; }
-    }
-
-    #region Event Arguments
-
-    /// <summary>
-    /// Defines the event data for <see cref="MouseDevice"/> events.
-    /// </summary>
-    /// <remarks>
-    /// <para>
-    /// Do not cache instances of this type outside their event handler.
-    /// If necessary, you can clone an instance using the 
-    /// <see cref="MouseEventArgs(MouseEventArgs)"/> constructor.
-    /// </para>
-    /// </remarks>
-    public class MouseEventArgs : EventArgs
-    {
-        #region Fields
-
-        int x, y;
-        int buttons;
-
-        #endregion
-
-        #region Constructors
-
-        /// <summary>
-        /// Constructs a new instance.
-        /// </summary>
-        public MouseEventArgs()
-        {
-            Wheel = new MouseWheel();
-        }
-
-        /// <summary>
-        /// Constructs a new instance.
-        /// </summary>
-        /// <param name="x">The X position.</param>
-        /// <param name="y">The Y position.</param>
-        public MouseEventArgs(int x, int y)
-        {
-            this.x = x;
-            this.y = y;
-        }
-
-        /// <summary>
-        /// Constructs a new instance.
-        /// </summary>
-        /// <param name="args">The <see cref="MouseEventArgs"/> instance to clone.</param>
-        public MouseEventArgs(MouseEventArgs args)
-            : this(args.x, args.y)
-        {
-        }
-
-        #endregion
-
-        #region Protected Members
-
-        internal void SetButton(MouseButton button, ButtonState state)
-        {
-            if (button < 0 || button > MouseButton.LastButton)
-                throw new ArgumentOutOfRangeException();
-
-            switch (state)
-            {
-                case ButtonState.Pressed:
-                    buttons |= 1 << (int)button;
-                    break;
-
-                case ButtonState.Released:
-                    buttons &= ~(1 << (int)button);
-                    break;
-            }
-        }
-
-        internal ButtonState GetButton(MouseButton button)
-        {
-            if (button < 0 || button > MouseButton.LastButton)
-                throw new ArgumentOutOfRangeException();
-
-            return
-                (buttons & (1 << (int)button)) != 0 ?
-                ButtonState.Pressed : ButtonState.Released;
-        }
-
-        #endregion
-
-        #region Public Members
-
-        /// <summary>
-        /// Gets the X position of the mouse for the event.
-        /// </summary>
-        public int X { get { return x; } internal set { x = value; } }
-
-        /// <summary>
-        /// Gets the Y position of the mouse for the event.
-        /// </summary>
-        public int Y { get { return y; } internal set { y = value; } }
-
-        /// <summary>
-        /// Gets the status of the mouse wheel.
-        /// </summary>
-        public MouseWheel Wheel { get; private set; }
-
-        /// <summary>
-        /// Gets the <see cref="ButtonState"/> of the left mouse button.
-        /// </summary>
-        public ButtonState LeftButton
-        {
-            get { return GetButton(MouseButton.Left); }
-            internal set { SetButton(MouseButton.Left, value); }
-        }
-
-        /// <summary>
-        /// Gets the <see cref="ButtonState"/> of the right mouse button.
-        /// </summary>
-        public ButtonState RightButton
-        {
-            get { return GetButton(MouseButton.Right); }
-            internal set { SetButton(MouseButton.Right, value); } 
-        }
-
-        /// <summary>
-        /// Gets the <see cref="ButtonState"/> of the middle mouse button.
-        /// </summary>
-        public ButtonState MiddleButton
-        {
-            get { return GetButton(MouseButton.Middle); }
-            internal set { SetButton(MouseButton.Middle, value); } 
-        }
-
-        /// <summary>
-        /// Gets the <see cref="ButtonState"/> of the first extra mouse button.
-        /// </summary>
-        public ButtonState X1Button
-        {
-            get { return GetButton(MouseButton.Button1); }
-            internal set { SetButton(MouseButton.Button1, value); } 
-        }
-
-        /// <summary>
-        /// Gets the <see cref="ButtonState"/> of the second extra mouse button.
-        /// </summary>
-        public ButtonState X2Button
-        {
-            get { return GetButton(MouseButton.Button2); }
-            internal set { SetButton(MouseButton.Button2, value); } 
-        }
-
-        /// <summary>
-        /// Gets a <see cref="System.Drawing.Point"/> representing the location of the mouse for the event.
-        /// </summary>
-        public Point Position
-        {
-            get { return new Point(x, y); }
-            set
-            {
-                X = value.X;
-                Y = value.Y;
-            }
-        }
-
-        #endregion
-    }
-
-    /// <summary>
-    /// Defines the event data for <see cref="MouseDevice.Move"/> events.
-    /// </summary>
-    /// <remarks>
-    /// <para>
-    /// Do not cache instances of this type outside their event handler.
-    /// If necessary, you can clone an instance using the 
-    /// <see cref="MouseMoveEventArgs(MouseMoveEventArgs)"/> constructor.
-    /// </para>
-    /// </remarks>
-    public class MouseMoveEventArgs : MouseEventArgs
-    {
-        #region Fields
-
-        int x_delta, y_delta;
-
-        #endregion
-
-        #region Constructors
-
-        /// <summary>
-        /// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
-        /// </summary>
-        public MouseMoveEventArgs() { }
-
-        /// <summary>
-        /// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
-        /// </summary>
-        /// <param name="x">The X position.</param>
-        /// <param name="y">The Y position.</param>
-        /// <param name="xDelta">The change in X position produced by this event.</param>
-        /// <param name="yDelta">The change in Y position produced by this event.</param>
-        public MouseMoveEventArgs(int x, int y, int xDelta, int yDelta)
-            : base(x, y)
-        {
-            XDelta = xDelta;
-            YDelta = yDelta;
-        }
-
-        /// <summary>
-        /// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
-        /// </summary>
-        /// <param name="args">The <see cref="MouseMoveEventArgs"/> instance to clone.</param>
-        public MouseMoveEventArgs(MouseMoveEventArgs args)
-            : this(args.X, args.Y, args.XDelta, args.YDelta)
-        {
-        }
-
-        #endregion
-
-        #region Public Members
-
-        /// <summary>
-        /// Gets the change in X position produced by this event.
-        /// </summary>
-        public int XDelta { get { return x_delta; } internal set { x_delta = value; } }
-
-        /// <summary>
-        /// Gets the change in Y position produced by this event.
-        /// </summary>
-        public int YDelta { get { return y_delta; } internal set { y_delta = value; } }
-
-        #endregion
-    }
-
-    /// <summary>
-    /// Defines the event data for <see cref="MouseDevice.ButtonDown"/> and <see cref="MouseDevice.ButtonUp"/> events.
-    /// </summary>
-    /// <remarks>
-    /// <para>
-    /// Do not cache instances of this type outside their event handler.
-    /// If necessary, you can clone an instance using the 
-    /// <see cref="MouseButtonEventArgs(MouseButtonEventArgs)"/> constructor.
-    /// </para>
-    /// </remarks>
-    public class MouseButtonEventArgs : MouseEventArgs
-    {
-        #region Fields
-
-        MouseButton button;
-        bool pressed;
-
-        #endregion
-
-        #region Constructors
-
-        /// <summary>
-        /// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
-        /// </summary>
-        public MouseButtonEventArgs() { }
-
-        /// <summary>
-        /// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
-        /// </summary>
-        /// <param name="x">The X position.</param>
-        /// <param name="y">The Y position.</param>
-        /// <param name="button">The mouse button for the event.</param>
-        /// <param name="pressed">The current state of the button.</param>
-        public MouseButtonEventArgs(int x, int y, MouseButton button, bool pressed)
-            : base(x, y)
-        {
-            this.button = button;
-            this.pressed = pressed;
-        }
-
-        /// <summary>
-        /// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
-        /// </summary>
-        /// <param name="args">The <see cref="MouseButtonEventArgs"/> instance to clone.</param>
-        public MouseButtonEventArgs(MouseButtonEventArgs args)
-            : this(args.X, args.Y, args.Button, args.IsPressed)
-        {
-        }
-
-        #endregion
-
-        #region Public Members
-
-        /// <summary>
-        /// Gets the <see cref="MouseButton"/> that triggered this event.
-        /// </summary>
-        public MouseButton Button { get { return button; } internal set { button = value; } }
-
-        /// <summary>
-        /// Gets a System.Boolean representing the state of the mouse button for the event.
-        /// </summary>
-        public bool IsPressed
-        {
-            get { return GetButton(Button) == ButtonState.Pressed; }
-            internal set { SetButton(Button, value ? ButtonState.Pressed : ButtonState.Released); }
-        }
-
-        #endregion
-    }
-
-    /// <summary>
-    /// Defines the event data for <see cref="MouseDevice.WheelChanged"/> events.
-    /// </summary>
-    /// <remarks>
-    /// <para>
-    /// Do not cache instances of this type outside their event handler.
-    /// If necessary, you can clone an instance using the 
-    /// <see cref="MouseWheelEventArgs(MouseWheelEventArgs)"/> constructor.
-    /// </para>
-    /// </remarks>
-    public class MouseWheelEventArgs : MouseEventArgs
-    {
-        #region Fields
-
-        float delta;
-
-        #endregion
-
-        #region Constructors
-
-        /// <summary>
-        /// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
-        /// </summary>
-        public MouseWheelEventArgs() { }
-
-        /// <summary>
-        /// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
-        /// </summary>
-        /// <param name="x">The X position.</param>
-        /// <param name="y">The Y position.</param>
-        /// <param name="value">The value of the wheel.</param>
-        /// <param name="delta">The change in value of the wheel for this event.</param>
-        public MouseWheelEventArgs(int x, int y, int value, int delta)
-            : base(x, y)
-        {
-            Wheel.Y = value;
-            this.delta = delta;
-        }
-
-        /// <summary>
-        /// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
-        /// </summary>
-        /// <param name="args">The <see cref="MouseWheelEventArgs"/> instance to clone.</param>
-        public MouseWheelEventArgs(MouseWheelEventArgs args)
-            : this(args.X, args.Y, args.Value, args.Delta)
-        {
-        }
-
-        #endregion
-
-        #region Public Members
-
-        /// <summary>
-        /// Gets the value of the wheel in integer units.
-        /// To support high-precision mice, it is recommended to use <see cref="ValuePrecise"/> instead.
-        /// </summary>
-        public int Value { get { return (int)Math.Round(Wheel.Y, MidpointRounding.AwayFromZero); } }
-
-        /// <summary>
-        /// Gets the change in value of the wheel for this event in integer units.
-        /// To support high-precision mice, it is recommended to use <see cref="DeltaPrecise"/> instead.
-        /// </summary>
-        public int Delta { get { return (int)Math.Round(delta, MidpointRounding.AwayFromZero); } }
-
-        /// <summary>
-        /// Gets the precise value of the wheel in floating-point units.
-        /// </summary>
-        public float ValuePrecise { get { return Wheel.Y; } internal set { Wheel.Y = value; } }
-
-        /// <summary>
-        /// Gets the precise change in value of the wheel for this event in floating-point units.
-        /// </summary>
-        public float DeltaPrecise { get { return delta; } internal set { delta = value; } }
-
-        #endregion
-    }
-
-    #endregion
 }
diff --git a/Source/OpenTK/Input/MouseEventArgs.cs b/Source/OpenTK/Input/MouseEventArgs.cs
new file mode 100644 (file)
index 0000000..9770e43
--- /dev/null
@@ -0,0 +1,370 @@
+#region License
+//
+// MouseEventArgs.cs
+//
+// Author:
+//       Stefanos A. <stapostol@gmail.com>
+//
+// Copyright (c) 2006-2014 Stefanos Apostolopoulos
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+#endregion
+
+using System;
+using System.Drawing;
+
+namespace OpenTK.Input
+{
+    /// <summary>
+    /// Defines the event data for <see cref="MouseDevice"/> events.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Do not cache instances of this type outside their event handler.
+    /// If necessary, you can clone an instance using the 
+    /// <see cref="MouseEventArgs(MouseEventArgs)"/> constructor.
+    /// </para>
+    /// </remarks>
+    public class MouseEventArgs : EventArgs
+    {
+        #region Fields
+
+        MouseState state;
+
+        #endregion
+
+        #region Constructors
+
+        /// <summary>
+        /// Constructs a new instance.
+        /// </summary>
+        public MouseEventArgs()
+        {
+            state.SetIsConnected(true);
+        }
+
+        /// <summary>
+        /// Constructs a new instance.
+        /// </summary>
+        /// <param name="x">The X position.</param>
+        /// <param name="y">The Y position.</param>
+        public MouseEventArgs(int x, int y)
+            : this()
+        {
+            state.X = x;
+            state.Y = y;
+        }
+
+        /// <summary>
+        /// Constructs a new instance.
+        /// </summary>
+        /// <param name="args">The <see cref="MouseEventArgs"/> instance to clone.</param>
+        public MouseEventArgs(MouseEventArgs args)
+            : this(args.X, args.Y)
+        {
+        }
+
+        #endregion
+
+        #region Protected Members
+
+        internal void SetButton(MouseButton button, ButtonState state)
+        {
+            if (button < 0 || button > MouseButton.LastButton)
+                throw new ArgumentOutOfRangeException();
+
+            switch (state)
+            {
+                case ButtonState.Pressed:
+                    this.state.EnableBit((int)button);
+                    break;
+
+                case ButtonState.Released:
+                    this.state.DisableBit((int)button);
+                    break;
+            }
+        }
+
+        internal ButtonState GetButton(MouseButton button)
+        {
+            if (button < 0 || button > MouseButton.LastButton)
+                throw new ArgumentOutOfRangeException();
+
+            return
+                state.ReadBit((int)button) ?
+                ButtonState.Pressed : ButtonState.Released;
+        }
+
+        #endregion
+
+        #region Public Members
+
+        /// <summary>
+        /// Gets the X position of the mouse for the event.
+        /// </summary>
+        public int X { get { return state.X; } internal set { state.X = value; } }
+
+        /// <summary>
+        /// Gets the Y position of the mouse for the event.
+        /// </summary>
+        public int Y { get { return state.Y; } internal set { state.Y = value; } }
+
+        /// <summary>
+        /// Gets a <see cref="System.Drawing.Point"/> representing the location of the mouse for the event.
+        /// </summary>
+        public Point Position
+        {
+            get { return new Point(state.X, state.Y); }
+            set
+            {
+                X = value.X;
+                Y = value.Y;
+            }
+        }
+
+        /// <summary>
+        /// Gets the current <see cref="OpenTK.Input.MouseState"/>.
+        /// </summary>
+        public MouseState Mouse
+        {
+            get { return state; }
+            internal set { state = value; }
+        }
+
+        #endregion
+    }
+
+    /// <summary>
+    /// Defines the event data for <see cref="MouseDevice.Move"/> events.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Do not cache instances of this type outside their event handler.
+    /// If necessary, you can clone an instance using the 
+    /// <see cref="MouseMoveEventArgs(MouseMoveEventArgs)"/> constructor.
+    /// </para>
+    /// </remarks>
+    public class MouseMoveEventArgs : MouseEventArgs
+    {
+        #region Fields
+
+        int x_delta, y_delta;
+
+        #endregion
+
+        #region Constructors
+
+        /// <summary>
+        /// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
+        /// </summary>
+        public MouseMoveEventArgs() { }
+
+        /// <summary>
+        /// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
+        /// </summary>
+        /// <param name="x">The X position.</param>
+        /// <param name="y">The Y position.</param>
+        /// <param name="xDelta">The change in X position produced by this event.</param>
+        /// <param name="yDelta">The change in Y position produced by this event.</param>
+        public MouseMoveEventArgs(int x, int y, int xDelta, int yDelta)
+            : base(x, y)
+        {
+            XDelta = xDelta;
+            YDelta = yDelta;
+        }
+
+        /// <summary>
+        /// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
+        /// </summary>
+        /// <param name="args">The <see cref="MouseMoveEventArgs"/> instance to clone.</param>
+        public MouseMoveEventArgs(MouseMoveEventArgs args)
+            : this(args.X, args.Y, args.XDelta, args.YDelta)
+        {
+        }
+
+        #endregion
+
+        #region Public Members
+
+        /// <summary>
+        /// Gets the change in X position produced by this event.
+        /// </summary>
+        public int XDelta { get { return x_delta; } internal set { x_delta = value; } }
+
+        /// <summary>
+        /// Gets the change in Y position produced by this event.
+        /// </summary>
+        public int YDelta { get { return y_delta; } internal set { y_delta = value; } }
+
+        #endregion
+    }
+
+    /// <summary>
+    /// Defines the event data for <see cref="MouseDevice.ButtonDown"/> and <see cref="MouseDevice.ButtonUp"/> events.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Do not cache instances of this type outside their event handler.
+    /// If necessary, you can clone an instance using the 
+    /// <see cref="MouseButtonEventArgs(MouseButtonEventArgs)"/> constructor.
+    /// </para>
+    /// </remarks>
+    public class MouseButtonEventArgs : MouseEventArgs
+    {
+        #region Fields
+
+        MouseButton button;
+        bool pressed;
+
+        #endregion
+
+        #region Constructors
+
+        /// <summary>
+        /// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
+        /// </summary>
+        public MouseButtonEventArgs() { }
+
+        /// <summary>
+        /// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
+        /// </summary>
+        /// <param name="x">The X position.</param>
+        /// <param name="y">The Y position.</param>
+        /// <param name="button">The mouse button for the event.</param>
+        /// <param name="pressed">The current state of the button.</param>
+        public MouseButtonEventArgs(int x, int y, MouseButton button, bool pressed)
+            : base(x, y)
+        {
+            this.button = button;
+            this.pressed = pressed;
+        }
+
+        /// <summary>
+        /// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
+        /// </summary>
+        /// <param name="args">The <see cref="MouseButtonEventArgs"/> instance to clone.</param>
+        public MouseButtonEventArgs(MouseButtonEventArgs args)
+            : this(args.X, args.Y, args.Button, args.IsPressed)
+        {
+        }
+
+        #endregion
+
+        #region Public Members
+
+        /// <summary>
+        /// Gets the <see cref="MouseButton"/> that triggered this event.
+        /// </summary>
+        public MouseButton Button { get { return button; } internal set { button = value; } }
+
+        /// <summary>
+        /// Gets a System.Boolean representing the state of the mouse button for the event.
+        /// </summary>
+        public bool IsPressed
+        {
+            get { return GetButton(Button) == ButtonState.Pressed; }
+            internal set { SetButton(Button, value ? ButtonState.Pressed : ButtonState.Released); }
+        }
+
+        #endregion
+    }
+
+    /// <summary>
+    /// Defines the event data for <see cref="MouseDevice.WheelChanged"/> events.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// Do not cache instances of this type outside their event handler.
+    /// If necessary, you can clone an instance using the 
+    /// <see cref="MouseWheelEventArgs(MouseWheelEventArgs)"/> constructor.
+    /// </para>
+    /// </remarks>
+    public class MouseWheelEventArgs : MouseEventArgs
+    {
+        #region Fields
+
+        float delta;
+
+        #endregion
+
+        #region Constructors
+
+        /// <summary>
+        /// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
+        /// </summary>
+        public MouseWheelEventArgs() { }
+
+        /// <summary>
+        /// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
+        /// </summary>
+        /// <param name="x">The X position.</param>
+        /// <param name="y">The Y position.</param>
+        /// <param name="value">The value of the wheel.</param>
+        /// <param name="delta">The change in value of the wheel for this event.</param>
+        public MouseWheelEventArgs(int x, int y, int value, int delta)
+            : base(x, y)
+        {
+            Mouse.SetScrollAbsolute(Mouse.Scroll.X, value);
+            this.delta = delta;
+        }
+
+        /// <summary>
+        /// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
+        /// </summary>
+        /// <param name="args">The <see cref="MouseWheelEventArgs"/> instance to clone.</param>
+        public MouseWheelEventArgs(MouseWheelEventArgs args)
+            : this(args.X, args.Y, args.Value, args.Delta)
+        {
+        }
+
+        #endregion
+
+        #region Public Members
+
+        /// <summary>
+        /// Gets the value of the wheel in integer units.
+        /// To support high-precision mice, it is recommended to use <see cref="ValuePrecise"/> instead.
+        /// </summary>
+        public int Value { get { return (int)Math.Round(Mouse.Scroll.Y, MidpointRounding.AwayFromZero); } }
+
+        /// <summary>
+        /// Gets the change in value of the wheel for this event in integer units.
+        /// To support high-precision mice, it is recommended to use <see cref="DeltaPrecise"/> instead.
+        /// </summary>
+        public int Delta { get { return (int)Math.Round(delta, MidpointRounding.AwayFromZero); } }
+
+        /// <summary>
+        /// Gets the precise value of the wheel in floating-point units.
+        /// </summary>
+        public float ValuePrecise
+        {
+            get { return Mouse.Scroll.Y; }
+            internal set { Mouse.SetScrollAbsolute(Mouse.Scroll.X, value); }
+        }
+
+        /// <summary>
+        /// Gets the precise change in value of the wheel for this event in floating-point units.
+        /// </summary>
+        public float DeltaPrecise { get { return delta; } internal set { delta = value; } }
+
+        #endregion
+    }
+}
+
diff --git a/Source/OpenTK/Input/MouseScrollWheel.cs b/Source/OpenTK/Input/MouseScrollWheel.cs
new file mode 100644 (file)
index 0000000..69fd17f
--- /dev/null
@@ -0,0 +1,119 @@
+#region License
+//
+// MouseWheel.cs
+//
+// Author:
+//       Stefanos A. <stapostol@gmail.com>
+//
+// Copyright (c) 2006-2014 Stefanos Apostolopoulos
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+#endregion
+
+using System;
+
+namespace OpenTK.Input
+{
+    /// <summary>
+    /// Represents the state of a mouse wheel.
+    /// </summary>
+    public struct MouseScrollWheel : IEquatable<MouseScrollWheel>
+    {
+        #region Public Members
+
+        /// <summary>
+        /// Gets the absolute horizontal offset of the wheel,
+        /// or 0 if no horizontal scroll wheel exists.
+        /// </summary>
+        /// <value>The x.</value>
+        public float X { get; internal set; }
+
+        /// <summary>
+        /// Gets the absolute vertical offset of the wheel,
+        /// or 0 if no vertical scroll wheel exists.
+        /// </summary>
+        /// <value>The y.</value>
+        public float Y { get; internal set; }
+
+        /// <param name="left">A <see cref="MouseScrollWheel"/> instance to test for equality.</param>
+        /// <param name="right">A <see cref="MouseScrollWheel"/> instance to test for equality.</param>
+        public static bool operator ==(MouseScrollWheel left, MouseScrollWheel right)
+        {
+            return left.Equals(right);
+        }
+
+        /// <param name="left">A <see cref="MouseScrollWheel"/> instance to test for inequality.</param>
+        /// <param name="right">A <see cref="MouseScrollWheel"/> instance to test for inequality.</param>
+        public static bool operator !=(MouseScrollWheel left, MouseScrollWheel right)
+        {
+            return !left.Equals(right);
+        }
+
+        /// <summary>
+        /// Returns a <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.MouseScrollWheel"/>.
+        /// </summary>
+        /// <returns>A <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.MouseScrollWheel"/>.</returns>
+        public override string ToString()
+        {
+            return string.Format("[MouseScrollWheel: X={0}, Y={1}]", X, Y);
+        }
+
+        /// <summary>
+        /// Serves as a hash function for a <see cref="OpenTK.Input.MouseScrollWheel"/> object.
+        /// </summary>
+        /// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
+        /// hash table.</returns>
+        public override int GetHashCode()
+        {
+            return X.GetHashCode() ^ Y.GetHashCode();
+        }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="OpenTK.Input.MouseScrollWheel"/>.
+        /// </summary>
+        /// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="OpenTK.Input.MouseScrollWheel"/>.</param>
+        /// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
+        /// <see cref="OpenTK.Input.MouseScrollWheel"/>; otherwise, <c>false</c>.</returns>
+        public override bool Equals(object obj)
+        {
+            return
+                obj is MouseScrollWheel &&
+                Equals((MouseScrollWheel)obj);
+        }
+
+        #endregion
+
+        #region IEquatable Members
+
+        /// <summary>
+        /// Determines whether the specified <see cref="OpenTK.Input.MouseScrollWheel"/> is equal to the current <see cref="OpenTK.Input.MouseScrollWheel"/>.
+        /// </summary>
+        /// <param name="other">The <see cref="OpenTK.Input.MouseScrollWheel"/> to compare with the current <see cref="OpenTK.Input.MouseScrollWheel"/>.</param>
+        /// <returns><c>true</c> if the specified <see cref="OpenTK.Input.MouseScrollWheel"/> is equal to the current
+        /// <see cref="OpenTK.Input.MouseScrollWheel"/>; otherwise, <c>false</c>.</returns>
+        public bool Equals(MouseScrollWheel other)
+        {
+            return X == other.X && Y == other.Y;
+        }
+
+        #endregion
+    }
+}
+
index 7fa48a8..5b12fe2 100644 (file)
@@ -38,13 +38,9 @@ namespace OpenTK.Input
     {
         #region Fields
 
-        // Allocate enough ints to store all mouse buttons
-        const int IntSize = sizeof(int);
-        const int NumInts = ((int)MouseButton.LastButton + IntSize - 1) / IntSize;
-        // The following line triggers bogus CS0214 in gmcs 2.0.1, sigh...
-        unsafe fixed int Buttons[NumInts];
         int x, y;
-        float wheel;
+        MouseScrollWheel scroll;
+        ushort buttons;
         bool is_connected;
 
         #endregion
@@ -93,7 +89,7 @@ namespace OpenTK.Input
         /// </summary>
         public int Wheel
         {
-            get { return (int)Math.Round(wheel, MidpointRounding.AwayFromZero); }
+            get { return (int)Math.Round(scroll.Y, MidpointRounding.AwayFromZero); }
         }
 
         /// <summary>
@@ -101,11 +97,16 @@ namespace OpenTK.Input
         /// </summary>
         public float WheelPrecise
         {
-            get { return wheel; }
-            internal set
-            {
-                wheel = value;
-            }
+            get { return scroll.Y; }
+        }
+
+        /// <summary>
+        /// Gets a <see cref="OpenTK.Input.MouseScrollWheel"/> instance,
+        /// representing the current state of the mouse scroll wheel.
+        /// </summary>
+        public MouseScrollWheel Scroll
+        {
+            get { return scroll; }
         }
 
         /// <summary>
@@ -253,13 +254,7 @@ namespace OpenTK.Input
         /// </returns>
         public override int GetHashCode()
         {
-            unsafe
-            {
-                fixed (int* b = Buttons)
-                {
-                    return b->GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode() ^ WheelPrecise.GetHashCode();
-                }
-            }
+            return buttons.GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode() ^ scroll.GetHashCode();
         }
 
         #endregion
@@ -269,60 +264,27 @@ namespace OpenTK.Input
         internal bool ReadBit(int offset)
         {
             ValidateOffset(offset);
-
-            int int_offset = offset / 32;
-            int bit_offset = offset % 32;
-            unsafe
-            {
-                fixed (int* b = Buttons)
-                {
-                    return (*(b + int_offset) & (1 << bit_offset)) != 0u;
-                }
-            }
+            return (buttons & (1 << offset)) != 0;
         }
 
         internal void EnableBit(int offset)
         {
             ValidateOffset(offset);
-
-            int int_offset = offset / 32;
-            int bit_offset = offset % 32;
-            unsafe
-            {
-                fixed (int* b = Buttons)
-                {
-                    *(b + int_offset) |= 1 << bit_offset;
-                }
-            }
+            buttons |= unchecked((ushort)(1 << offset));
         }
 
         internal void DisableBit(int offset)
         {
             ValidateOffset(offset);
-
-            int int_offset = offset / 32;
-            int bit_offset = offset % 32;
-            unsafe
-            {
-                fixed (int* b = Buttons)
-                {
-                    *(b + int_offset) &= ~(1 << bit_offset);
-                }
-            }
+            buttons &= unchecked((ushort)(~(1 << offset)));
         }
 
         internal void MergeBits(MouseState other)
         {
             unsafe
             {
-                int* b2 = other.Buttons;
-                fixed (int* b1 = Buttons)
-                {
-                    for (int i = 0; i < NumInts; i++)
-                        *(b1 + i) |= *(b2 + i);
-                }
-
-                WheelPrecise += other.WheelPrecise;
+                buttons |= other.buttons;
+                SetScrollRelative(other.scroll.X, other.scroll.Y);
                 X += other.X;
                 Y += other.Y;
                 IsConnected |= other.IsConnected;
@@ -334,13 +296,29 @@ namespace OpenTK.Input
             IsConnected = value;
         }
 
+        #region Internal Members
+
+        internal void SetScrollAbsolute(float x, float y)
+        {
+            scroll.X = x;
+            scroll.Y = y;
+        }
+
+        internal void SetScrollRelative(float x, float y)
+        {
+            scroll.X += x;
+            scroll.Y += y;
+        }
+
+        #endregion
+
         #endregion
 
         #region Private Members
 
         static void ValidateOffset(int offset)
         {
-            if (offset < 0 || offset >= NumInts * IntSize)
+            if (offset < 0 || offset >= 16)
                 throw new ArgumentOutOfRangeException("offset");
         }
 
@@ -355,18 +333,11 @@ namespace OpenTK.Input
         /// <returns>True, if both instances are equal; false otherwise.</returns>
         public bool Equals(MouseState other)
         {
-            bool equal = true;
-            unsafe
-            {
-                int* b2 = other.Buttons;
-                fixed (int* b1 = Buttons)
-                {
-                    for (int i = 0; equal && i < NumInts; i++)
-                        equal &= *(b1 + i) == *(b2 + i);
-                }
-                equal &= X == other.X && Y == other.Y && WheelPrecise == other.WheelPrecise;
-            }
-            return equal;
+            return
+                buttons == other.buttons &&
+                X == other.X &&
+                Y == other.Y &&
+                Scroll == other.Scroll;
         }
 
         #endregion
index 7d2cbda..f82f699 100644 (file)
     <Compile Include="WindowIcon.cs" />
     <Compile Include="Platform\MacOS\Cocoa\NSBitmapFormat.cs" />
     <Compile Include="Platform\NativeWindowBase.cs" />
+    <Compile Include="Input\MouseScrollWheel.cs" />
+    <Compile Include="Input\MouseEventArgs.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
index 96d0a02..96596e5 100644 (file)
@@ -78,7 +78,7 @@ namespace OpenTK.Platform
 
             window.MouseWheel += (sender, e) =>
             {
-                mouse.WheelPrecise = e.Wheel.Y;
+                mouse.WheelPrecise = e.Mouse.Scroll.Y;
             };
 
             // Hook keyboard events
index 2d95a33..e632415 100644 (file)
@@ -517,7 +517,9 @@ namespace OpenTK.Platform.MacOS
                                     MathHelper.Clamp((int)Math.Round(p.Y + dy), 0, Height));
                             }
 
-                            InputDriver.Mouse[0].Position = p;
+                            MouseState.X = p.X;
+                            MouseState.Y = p.Y;
+                            OnMouseMove();
                         }
                         break;
 
@@ -534,7 +536,8 @@ namespace OpenTK.Platform.MacOS
                                 factor = 1.0f / scrollFactor; // Problem: Don't know what factor to use here, but this seems to work.
                             }
 
-                            InputDriver.Mouse[0].WheelPrecise += scrollingDelta * factor;
+                            MouseState.SetScrollRelative(0, scrollingDelta * factor);
+                            OnMouseWheel();
                         }
                         break;
 
@@ -543,7 +546,8 @@ namespace OpenTK.Platform.MacOS
                     case NSEventType.OtherMouseDown:
                         {
                             var buttonNumber = Cocoa.SendInt(e, selButtonNumber);
-                            InputDriver.Mouse[0][GetMouseButton(buttonNumber)] = true;
+                            MouseState[GetMouseButton(buttonNumber)] = true;
+                            OnMouseDown();
                         }
                         break;
 
@@ -552,7 +556,8 @@ namespace OpenTK.Platform.MacOS
                     case NSEventType.OtherMouseUp:
                         {
                             var buttonNumber = Cocoa.SendInt(e, selButtonNumber);
-                            InputDriver.Mouse[0][GetMouseButton(buttonNumber)] = false;
+                            MouseState[GetMouseButton(buttonNumber)] = false;
+                            OnMouseUp();
                         }
                         break;
                 }
index 49103d5..64a185c 100755 (executable)
@@ -324,7 +324,7 @@ namespace OpenTK.Platform.MacOS
                             break;
 
                         case HIDUsageGD.Wheel:
-                            mouse.State.WheelPrecise += v_int;
+                            mouse.State.SetScrollRelative(0, v_int);
                             break;
                     }
                     break;
@@ -332,6 +332,15 @@ namespace OpenTK.Platform.MacOS
                 case HIDPage.Button:
                     mouse.State[OpenTK.Input.MouseButton.Left + usage - 1] = v_int == 1;
                     break;
+
+                case HIDPage.Consumer:
+                    switch ((HIDUsageCD)usage)
+                    {
+                        case HIDUsageCD.ACPan:
+                            mouse.State.SetScrollRelative(v_int, 0);
+                            break;
+                    }
+                    break;
             }
         }
 
@@ -1107,6 +1116,12 @@ namespace OpenTK.Platform.MacOS
             VendorDefinedStart = 0xFF00
         }
 
+        // Consumer electronic devices
+        enum HIDUsageCD
+        {
+            ACPan = 0x0238
+        }
+
         // Generic desktop usage
         enum HIDUsageGD
         {
index 64e6bee..da7e7b0 100644 (file)
@@ -40,22 +40,25 @@ namespace OpenTK.Platform
     {
         readonly LegacyInputDriver LegacyInputDriver;
 
-        readonly protected MouseButtonEventArgs MouseDownArgs = new MouseButtonEventArgs();
-        readonly protected MouseButtonEventArgs MouseUpArgs = new MouseButtonEventArgs();
-        readonly protected MouseMoveEventArgs MouseMoveArgs = new MouseMoveEventArgs();
-        readonly protected MouseWheelEventArgs MouseWheelArgs = new MouseWheelEventArgs();
+        readonly MouseButtonEventArgs MouseDownArgs = new MouseButtonEventArgs();
+        readonly MouseButtonEventArgs MouseUpArgs = new MouseButtonEventArgs();
+        readonly MouseMoveEventArgs MouseMoveArgs = new MouseMoveEventArgs();
+        readonly MouseWheelEventArgs MouseWheelArgs = new MouseWheelEventArgs();
 
-        readonly protected KeyboardKeyEventArgs KeyDownArgs = new KeyboardKeyEventArgs();
-        readonly protected KeyboardKeyEventArgs KeyUpArgs = new KeyboardKeyEventArgs();
-        readonly protected KeyPressEventArgs KeyPressArgs = new KeyPressEventArgs((char)0);
+        protected readonly KeyboardKeyEventArgs KeyDownArgs = new KeyboardKeyEventArgs();
+        protected readonly KeyboardKeyEventArgs KeyUpArgs = new KeyboardKeyEventArgs();
+        protected readonly KeyPressEventArgs KeyPressArgs = new KeyPressEventArgs((char)0);
 
         // In order to simplify mouse event implementation,
         // we can store the current mouse state here.
         protected MouseState MouseState = new MouseState();
+        MouseState PreviousMouseState = new MouseState();
 
         internal NativeWindowBase()
         {
             LegacyInputDriver = new LegacyInputDriver(this);
+            MouseState.SetIsConnected(true);
+            PreviousMouseState.SetIsConnected(true);
         }
 
         #region Protected Members
@@ -140,23 +143,75 @@ namespace OpenTK.Platform
             MouseEnter(this, e);
         }
 
-        protected void OnMouseDown(MouseButtonEventArgs e)
+        protected void OnMouseDown()
         {
-            MouseDown(this, e);
+            var e = MouseDownArgs;
+            e.Mouse = MouseState;
+
+            // Find which button caused this event
+            for (MouseButton b = MouseButton.Left; b < MouseButton.LastButton; b++)
+            {
+                if (!PreviousMouseState[b] && MouseState[b])
+                {
+                    e.Button = b;
+                    PreviousMouseState = MouseState;
+                    MouseDown(this, e);
+                    return;
+                }
+            }
+
+            Debug.WriteLine("OnMouseDown called without pressing a button");
         }
 
-        protected void OnMouseUp(MouseButtonEventArgs e)
+        protected void OnMouseUp()
         {
-            MouseUp(this, e);
+            var e = MouseUpArgs;
+            e.Mouse = MouseState;
+
+            // Find which button caused this event
+            for (MouseButton b = MouseButton.Left; b < MouseButton.LastButton; b++)
+            {
+                if (PreviousMouseState[b] && !MouseState[b])
+                {
+                    e.Button = b;
+                    PreviousMouseState = MouseState;
+                    MouseUp(this, e);
+                    return;
+                }
+            }
+
+            Debug.WriteLine("OnMouseUp called without pressing a button");
         }
 
-        protected void OnMouseMove(MouseMoveEventArgs e)
+        protected void OnMouseMove()
         {
+            var e = MouseMoveArgs;
+            e.Mouse = MouseState;
+            e.XDelta = MouseState.X - PreviousMouseState.X;
+            e.YDelta = MouseState.Y - PreviousMouseState.Y;
+
+            if (e.XDelta == 0 && e.YDelta == 0)
+            {
+                Debug.WriteLine("OnMouseMove called without moving the mouse");
+            }
+
+            PreviousMouseState = MouseState;
             MouseMove(this, e);
         }
 
-        protected void OnMouseWheel(MouseWheelEventArgs e)
+        protected void OnMouseWheel()
         {
+            var e = MouseWheelArgs;
+            e.Mouse = MouseState;
+            e.ValuePrecise = MouseState.Scroll.Y;
+            e.DeltaPrecise = MouseState.Scroll.Y - PreviousMouseState.Scroll.Y;
+
+            if (e.DeltaPrecise == 0)
+            {
+                Debug.WriteLine("OnMouseWheel called without moving the mouse wheel.");
+            }
+
+            PreviousMouseState = MouseState;
             MouseWheel(this, e);
         }
 
index 887ad7a..934096e 100644 (file)
@@ -87,7 +87,7 @@ namespace OpenTK.Platform.SDL2
 
         public void ProcessWheelEvent(MouseWheelEvent wheel)
         {
-            state.WheelPrecise += wheel.Y;
+            state.SetScrollRelative(0, wheel.Y);
         }
 
         public void ProcessMouseEvent(MouseMotionEvent motion)
index 8c3367f..1283e4c 100644 (file)
@@ -221,21 +221,17 @@ namespace OpenTK.Platform.SDL2
                     button_pressed ? true : false);
             }
 
-            var e = button_pressed ? window.MouseDownArgs : window.MouseUpArgs;
-            e.Button = Sdl2Mouse.TranslateButton(ev.Button);
-            e.IsPressed = button_pressed;
-            e.X = ev.X;
-            e.Y = ev.Y;
-            e.Wheel.X = window.MouseWheelArgs.Wheel.X;
-            e.Wheel.Y = window.MouseWheelArgs.Wheel.Y;
+            window.MouseState[Sdl2Mouse.TranslateButton(ev.Button)] = button_pressed;
+            window.MouseState.X = ev.X;
+            window.MouseState.Y = ev.Y;
 
             if (button_pressed)
             {
-                window.OnMouseDown(e);
+                window.OnMouseDown();
             }
             else
             {
-                window.OnMouseUp(e);
+                window.OnMouseUp();
             }
         }
 
@@ -293,29 +289,15 @@ namespace OpenTK.Platform.SDL2
         static void ProcessMouseMotionEvent(Sdl2NativeWindow window, MouseMotionEvent ev)
         {
             //float scale = window.ClientSize.Width / (float)window.Size.Width;
-            var e = window.MouseMoveArgs;
-            e.X = ev.X;
-            e.Y = ev.Y;
-            SetMouseButtons(e, ev.State);
-            window.OnMouseMove(e);
-        }
-
-        static void SetMouseButtons(MouseEventArgs e, ButtonFlags buttons)
-        {
-            for (int i = 0; i < 5; i++)
-            {
-                // Note: OpenTK MouseButton is identical to SDL2 Button
-                bool pressed = ((int)buttons & (1 << i)) != 0;
-                e.SetButton((MouseButton)i, pressed ? ButtonState.Pressed : ButtonState.Released);
-            }
+            window.MouseState.X = ev.X;
+            window.MouseState.Y = ev.Y;
+            window.OnMouseMove();
         }
 
         static void ProcessMouseWheelEvent(Sdl2NativeWindow window, MouseWheelEvent ev)
         {
-            var e = window.MouseWheelArgs;
-            e.Wheel.Y = ev.Y;
-            e.Wheel.X = ev.X;
-            window.OnMouseWheel(e);
+            window.MouseState.SetScrollRelative(ev.X, ev.Y);
+            window.OnMouseWheel();
         }
 
         static void ProcessWindowEvent(Sdl2NativeWindow window, WindowEvent e)
index 3a0fd54..167dcb5 100644 (file)
@@ -3591,7 +3591,8 @@ namespace OpenTK.Platform.Windows
         BUTTON_5_DOWN    = 0x0100,
         BUTTON_5_UP      = 0x0200,
 
-        WHEEL            = 0x0400
+        WHEEL            = 0x0400,
+        HWHEEL            = 0x0800,
     }
 
     #endregion
index da56089..fdf1166 100644 (file)
@@ -437,8 +437,9 @@ namespace OpenTK.Platform.Windows
                 if (points == 0 || (points == -1 && lastError == Constants.ERROR_POINT_NOT_FOUND))
                 {
                     // Just use the mouse move position
-                    MouseMoveArgs.Position = point;
-                    OnMouseMove(MouseMoveArgs);
+                    MouseState.X = point.X;
+                    MouseState.Y = point.Y;
+                    OnMouseMove();
                 }
                 else if (points == -1)
                 {
@@ -476,8 +477,9 @@ namespace OpenTK.Platform.Windows
                             position.Y -= 65536;
                         }
                         Functions.ScreenToClient(handle, ref position);
-                        MouseMoveArgs.Position = position;
-                        OnMouseMove(MouseMoveArgs);
+                        MouseState.X = position.X;
+                        MouseState.Y = position.Y;
+                        OnMouseMove();
                     }
                 }
                 mouse_last_timestamp = timestamp;
@@ -506,40 +508,37 @@ namespace OpenTK.Platform.Windows
         {
             // This is due to inconsistent behavior of the WParam value on 64bit arch, whese
             // wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000
-            MouseWheelArgs.Wheel.Y += ((long)wParam << 32 >> 48) / 120.0f;
-            OnMouseWheel(MouseWheelArgs);
+            MouseState.SetScrollRelative(0, ((long)wParam << 32 >> 48) / 120.0f);
+            OnMouseWheel();
         }
 
         void HandleMouseHWheel(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
         {
             // This is due to inconsistent behavior of the WParam value on 64bit arch, whese
             // wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000
-            MouseWheelArgs.Wheel.X += ((long)wParam << 32 >> 48) / 120.0f;
-            OnMouseWheel(MouseWheelArgs);
+            MouseState.SetScrollRelative(((long)wParam << 32 >> 48) / 120.0f, 0);
+            OnMouseWheel();
         }
 
         void HandleLButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
         {
             Functions.SetCapture(window.Handle);
-            MouseDownArgs.Button = MouseButton.Left;
-            MouseDownArgs.IsPressed = true;
-            OnMouseDown(MouseDownArgs);
+            MouseState[MouseButton.Left] = true;
+            OnMouseDown();
         }
 
         void HandleMButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
         {
             Functions.SetCapture(window.Handle);
-            MouseDownArgs.Button = MouseButton.Middle;
-            MouseDownArgs.IsPressed = true;
-            OnMouseDown(MouseDownArgs);
+            MouseState[MouseButton.Middle] = true;
+            OnMouseDown();
         }
 
         void HandleRButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
         {
             Functions.SetCapture(window.Handle);
-            MouseDownArgs.Button = MouseButton.Right;
-            MouseDownArgs.IsPressed = true;
-            OnMouseDown(MouseDownArgs);
+            MouseState[MouseButton.Right] = true;
+            OnMouseDown();
         }
 
         void HandleXButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
@@ -548,33 +547,29 @@ namespace OpenTK.Platform.Windows
             MouseButton button =
                 ((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
                 MouseButton.Button1 : MouseButton.Button2;
-            MouseDownArgs.Button = button;
-            MouseDownArgs.IsPressed = true;
-            OnMouseDown(MouseDownArgs);
+            MouseState[button] = true;
+            OnMouseDown();
         }
 
         void HandleLButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
         {
             Functions.ReleaseCapture();
-            MouseDownArgs.Button = MouseButton.Left;
-            MouseDownArgs.IsPressed = false;
-            OnMouseUp(MouseUpArgs);
+            MouseState[MouseButton.Left] = false;
+            OnMouseUp();
         }
 
         void HandleMButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
         {
             Functions.ReleaseCapture();
-            MouseDownArgs.Button = MouseButton.Middle;
-            MouseDownArgs.IsPressed = false;
-            OnMouseUp(MouseUpArgs);
+            MouseState[MouseButton.Middle] = false;
+            OnMouseUp();
         }
 
         void HandleRButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
         {
             Functions.ReleaseCapture();
-            MouseDownArgs.Button = MouseButton.Right;
-            MouseDownArgs.IsPressed = false;
-            OnMouseUp(MouseUpArgs);
+            MouseState[MouseButton.Right] = false;
+            OnMouseUp();
         }
 
         void HandleXButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
@@ -583,9 +578,8 @@ namespace OpenTK.Platform.Windows
             MouseButton button =
                 ((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
                 MouseButton.Button1 : MouseButton.Button2;
-            MouseDownArgs.Button = button;
-            MouseDownArgs.IsPressed = false;
-            OnMouseUp(MouseUpArgs);
+            MouseState[button] = false;
+            OnMouseUp();
         }
 
         void HandleKeyboard(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
index 15ae043..c904ea1 100644 (file)
@@ -227,7 +227,10 @@ namespace OpenTK.Platform.Windows
             }
 
             if ((raw.ButtonFlags & RawInputMouseState.WHEEL) != 0)
-                mouse.WheelPrecise += (short)raw.ButtonData / 120.0f;
+                mouse.SetScrollRelative(0, (short)raw.ButtonData / 120.0f);
+
+            if ((raw.ButtonFlags & RawInputMouseState.HWHEEL) != 0)
+                mouse.SetScrollRelative((short)raw.ButtonData / 120.0f, 0);
 
             if ((raw.Flags & RawMouseFlags.MOUSE_MOVE_ABSOLUTE) != 0)
             {
index bb93c75..96090e5 100644 (file)
@@ -204,8 +204,8 @@ namespace OpenTK.Platform.X11
                                     case 1: state.EnableBit((int)MouseButton.Left); break;
                                     case 2: state.EnableBit((int)MouseButton.Middle); break;
                                     case 3: state.EnableBit((int)MouseButton.Right); break;
-                                    case 4: state.WheelPrecise++; break;
-                                    case 5: state.WheelPrecise--; break;
+                                    case 4: state.SetScrollRelative(0, 1); break;
+                                    case 5: state.SetScrollRelative(0, -1); break;
                                     case 6: state.EnableBit((int)MouseButton.Button1); break;
                                     case 7: state.EnableBit((int)MouseButton.Button2); break;
                                     case 8: state.EnableBit((int)MouseButton.Button3); break;