[X11] Implemented high-resolution scroll events
authorthefiddler <stapostol@gmail.com>
Tue, 13 May 2014 21:23:51 +0000 (23:23 +0200)
committerthefiddler <stapostol@gmail.com>
Tue, 13 May 2014 21:23:51 +0000 (23:23 +0200)
Source/OpenTK/Input/MouseScroll.cs [new file with mode: 0644]
Source/OpenTK/Platform/X11/X11GLNative.cs
Source/OpenTK/Platform/X11/X11KeyMap.cs
Source/OpenTK/Platform/X11/XI2Mouse.cs

diff --git a/Source/OpenTK/Input/MouseScroll.cs b/Source/OpenTK/Input/MouseScroll.cs
new file mode 100644 (file)
index 0000000..2be06b6
--- /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("[X={0:0.00}, Y={1:0.00}]", 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 29dc683..3c3df46 100644 (file)
@@ -132,6 +132,7 @@ namespace OpenTK.Platform.X11
 
         readonly bool xi2_supported;
         readonly int xi2_opcode;
+        readonly int xi2_version;
 
         #endregion
 
@@ -243,6 +244,7 @@ namespace OpenTK.Platform.X11
             if (xi2_supported)
             {
                 xi2_opcode = XI2Mouse.XIOpCode;
+                xi2_version = XI2Mouse.XIVersion;
             }
 
             exists = true;
@@ -918,15 +920,29 @@ namespace OpenTK.Platform.X11
 
                     case XEventName.ButtonPress:
                         {
-                            int dx, dy;
+                            float dx, dy;
                             MouseButton button = X11KeyMap.TranslateButton(e.ButtonEvent.button, out dx, out dy);
 
                             if (button != MouseButton.LastButton)
                             {
                                 OnMouseDown(button);
                             }
-                            else if (dx != 0 || dy != 0)
+
+                            if (xi2_version >= 210)
                             {
+                                // High resolution scroll events supported.
+                                // This code is implemented in XI2Mouse.GetCursorState().
+                                // Instead of reimplementing this functionality, just
+                                // use the values from there.
+                                MouseState state = Mouse.GetCursorState();
+                                dx = state.Scroll.X - MouseState.Scroll.X;
+                                dy = state.Scroll.Y - MouseState.Scroll.Y;
+                            }
+
+                            if (dx != 0 || dy != 0)
+                            {
+                                // High resolution scroll events not supported
+                                // fallback to the old Button4-7 scroll buttons
                                 OnMouseWheel(dx, dy);
                             }
                         }
@@ -934,7 +950,7 @@ namespace OpenTK.Platform.X11
 
                     case XEventName.ButtonRelease:
                         {
-                            int dx, dy;
+                            float dx, dy;
                             MouseButton button = X11KeyMap.TranslateButton(e.ButtonEvent.button, out dx, out dy);
                             if (button != MouseButton.LastButton)
                             {
@@ -1003,7 +1019,7 @@ namespace OpenTK.Platform.X11
                         //    RefreshWindowBorders();
                         //}
                         break;
-                       
+
                     default:
                         //Debug.WriteLine(String.Format("{0} event was not handled", e.type));
                         break;
@@ -1499,11 +1515,8 @@ namespace OpenTK.Platform.X11
         void GrabMouse()
         {
             Functions.XGrabPointer(window.Display, window.Handle, false,
-                EventMask.PointerMotionMask |
-                EventMask.ButtonMotionMask | EventMask.Button1MotionMask |
-                EventMask.Button2MotionMask | EventMask.Button3MotionMask |
-                EventMask.Button4MotionMask | EventMask.Button5MotionMask |
-                EventMask.ButtonPressMask | EventMask.ButtonReleaseMask,
+                EventMask.PointerMotionMask | EventMask.ButtonPressMask |
+                EventMask.ButtonReleaseMask,
                 GrabMode.GrabModeAsync, GrabMode.GrabModeAsync,
                 window.Handle, EmptyCursor, IntPtr.Zero);
         }
index 29e9693..216671e 100644 (file)
@@ -388,7 +388,7 @@ namespace OpenTK.Platform.X11
             return key != Key.Unknown;
         }
 
-        internal static MouseButton TranslateButton(int button, out int wheelx, out int wheely)
+        internal static MouseButton TranslateButton(int button, out float wheelx, out float wheely)
         {
             wheelx = 0;
             wheely = 0;
index 9042227..97f6a5a 100644 (file)
@@ -73,6 +73,7 @@ namespace OpenTK.Platform.X11
 
         internal readonly X11WindowInfo window;
         internal static int XIOpCode { get; private set; }
+        internal static int XIVersion { get; private set; }
 
         static readonly Functions.EventPredicate PredicateImpl = IsEventValid;
         readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl);
@@ -172,6 +173,7 @@ namespace OpenTK.Platform.X11
                     {
                         if (XI.QueryVersion(display, ref major, ref minor) == ErrorCodes.Success)
                         {
+                            XIVersion = major * 100 + minor * 10;
                             return true;
                         }
                         minor--;
@@ -385,15 +387,13 @@ namespace OpenTK.Platform.X11
                             case 1: d.State.EnableBit((int)MouseButton.Left); break;
                             case 2: d.State.EnableBit((int)MouseButton.Middle); break;
                             case 3: d.State.EnableBit((int)MouseButton.Right); break;
-                            case 6: d.State.EnableBit((int)MouseButton.Button1); break;
-                            case 7: d.State.EnableBit((int)MouseButton.Button2); break;
-                            case 8: d.State.EnableBit((int)MouseButton.Button3); break;
-                            case 9: d.State.EnableBit((int)MouseButton.Button4); break;
-                            case 10: d.State.EnableBit((int)MouseButton.Button5); break;
-                            case 11: d.State.EnableBit((int)MouseButton.Button6); break;
-                            case 12: d.State.EnableBit((int)MouseButton.Button7); break;
-                            case 13: d.State.EnableBit((int)MouseButton.Button8); break;
-                            case 14: d.State.EnableBit((int)MouseButton.Button9); break;
+                            case 8: d.State.EnableBit((int)MouseButton.Button1); break;
+                            case 9: d.State.EnableBit((int)MouseButton.Button2); break;
+                            case 10: d.State.EnableBit((int)MouseButton.Button3); break;
+                            case 11: d.State.EnableBit((int)MouseButton.Button4); break;
+                            case 12: d.State.EnableBit((int)MouseButton.Button5); break;
+                            case 13: d.State.EnableBit((int)MouseButton.Button6); break;
+                            case 14: d.State.EnableBit((int)MouseButton.Button7); break;
                         }
                         break;
 
@@ -403,15 +403,13 @@ namespace OpenTK.Platform.X11
                             case 1: d.State.DisableBit((int)MouseButton.Left); break;
                             case 2: d.State.DisableBit((int)MouseButton.Middle); break;
                             case 3: d.State.DisableBit((int)MouseButton.Right); break;
-                            case 6: d.State.DisableBit((int)MouseButton.Button1); break;
-                            case 7: d.State.DisableBit((int)MouseButton.Button2); break;
-                            case 8: d.State.DisableBit((int)MouseButton.Button3); break;
-                            case 9: d.State.DisableBit((int)MouseButton.Button4); break;
-                            case 10: d.State.DisableBit((int)MouseButton.Button5); break;
-                            case 11: d.State.DisableBit((int)MouseButton.Button6); break;
-                            case 12: d.State.DisableBit((int)MouseButton.Button7); break;
-                            case 13: d.State.DisableBit((int)MouseButton.Button8); break;
-                            case 14: d.State.DisableBit((int)MouseButton.Button9); break;
+                            case 8: d.State.DisableBit((int)MouseButton.Button1); break;
+                            case 9: d.State.DisableBit((int)MouseButton.Button2); break;
+                            case 10: d.State.DisableBit((int)MouseButton.Button3); break;
+                            case 11: d.State.DisableBit((int)MouseButton.Button4); break;
+                            case 12: d.State.DisableBit((int)MouseButton.Button5); break;
+                            case 13: d.State.DisableBit((int)MouseButton.Button6); break;
+                            case 14: d.State.DisableBit((int)MouseButton.Button7); break;
                         }
                         break;
                 }