From c6dafbccbaf07b9234ea4617dc7a5e242f17e832 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Tue, 13 May 2014 23:23:51 +0200 Subject: [PATCH] [X11] Implemented high-resolution scroll events --- Source/OpenTK/Input/MouseScroll.cs | 119 ++++++++++++++++++++++++++++++ Source/OpenTK/Platform/X11/X11GLNative.cs | 31 +++++--- Source/OpenTK/Platform/X11/X11KeyMap.cs | 2 +- Source/OpenTK/Platform/X11/XI2Mouse.cs | 34 ++++----- 4 files changed, 158 insertions(+), 28 deletions(-) create mode 100644 Source/OpenTK/Input/MouseScroll.cs diff --git a/Source/OpenTK/Input/MouseScroll.cs b/Source/OpenTK/Input/MouseScroll.cs new file mode 100644 index 0000000..2be06b6 --- /dev/null +++ b/Source/OpenTK/Input/MouseScroll.cs @@ -0,0 +1,119 @@ +#region License +// +// MouseWheel.cs +// +// Author: +// Stefanos A. +// +// 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 +{ + /// + /// Represents the state of a mouse wheel. + /// + public struct MouseScrollWheel : IEquatable + { + #region Public Members + + /// + /// Gets the absolute horizontal offset of the wheel, + /// or 0 if no horizontal scroll wheel exists. + /// + /// The x. + public float X { get; internal set; } + + /// + /// Gets the absolute vertical offset of the wheel, + /// or 0 if no vertical scroll wheel exists. + /// + /// The y. + public float Y { get; internal set; } + + /// A instance to test for equality. + /// A instance to test for equality. + public static bool operator ==(MouseScrollWheel left, MouseScrollWheel right) + { + return left.Equals(right); + } + + /// A instance to test for inequality. + /// A instance to test for inequality. + public static bool operator !=(MouseScrollWheel left, MouseScrollWheel right) + { + return !left.Equals(right); + } + + /// + /// Returns a that represents the current . + /// + /// A that represents the current . + public override string ToString() + { + return string.Format("[X={0:0.00}, Y={1:0.00}]", X, Y); + } + + /// + /// Serves as a hash function for a object. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode(); + } + + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. + public override bool Equals(object obj) + { + return + obj is MouseScrollWheel && + Equals((MouseScrollWheel)obj); + } + + #endregion + + #region IEquatable Members + + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. + public bool Equals(MouseScrollWheel other) + { + return X == other.X && Y == other.Y; + } + + #endregion + } +} + diff --git a/Source/OpenTK/Platform/X11/X11GLNative.cs b/Source/OpenTK/Platform/X11/X11GLNative.cs index 29dc683..3c3df46 100644 --- a/Source/OpenTK/Platform/X11/X11GLNative.cs +++ b/Source/OpenTK/Platform/X11/X11GLNative.cs @@ -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); } diff --git a/Source/OpenTK/Platform/X11/X11KeyMap.cs b/Source/OpenTK/Platform/X11/X11KeyMap.cs index 29e9693..216671e 100644 --- a/Source/OpenTK/Platform/X11/X11KeyMap.cs +++ b/Source/OpenTK/Platform/X11/X11KeyMap.cs @@ -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; diff --git a/Source/OpenTK/Platform/X11/XI2Mouse.cs b/Source/OpenTK/Platform/X11/XI2Mouse.cs index 9042227..97f6a5a 100644 --- a/Source/OpenTK/Platform/X11/XI2Mouse.cs +++ b/Source/OpenTK/Platform/X11/XI2Mouse.cs @@ -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; } -- 2.7.4