[X11] Implemented high-resolution scroll events

This commit is contained in:
thefiddler 2014-05-13 23:23:51 +02:00
parent 9255fdcdb4
commit c6dafbccba
4 changed files with 158 additions and 28 deletions

View file

@ -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
}
}

View file

@ -132,6 +132,7 @@ namespace OpenTK.Platform.X11
readonly bool xi2_supported; readonly bool xi2_supported;
readonly int xi2_opcode; readonly int xi2_opcode;
readonly int xi2_version;
#endregion #endregion
@ -243,6 +244,7 @@ namespace OpenTK.Platform.X11
if (xi2_supported) if (xi2_supported)
{ {
xi2_opcode = XI2Mouse.XIOpCode; xi2_opcode = XI2Mouse.XIOpCode;
xi2_version = XI2Mouse.XIVersion;
} }
exists = true; exists = true;
@ -918,15 +920,29 @@ namespace OpenTK.Platform.X11
case XEventName.ButtonPress: case XEventName.ButtonPress:
{ {
int dx, dy; float dx, dy;
MouseButton button = X11KeyMap.TranslateButton(e.ButtonEvent.button, out dx, out dy); MouseButton button = X11KeyMap.TranslateButton(e.ButtonEvent.button, out dx, out dy);
if (button != MouseButton.LastButton) if (button != MouseButton.LastButton)
{ {
OnMouseDown(button); 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); OnMouseWheel(dx, dy);
} }
} }
@ -934,7 +950,7 @@ namespace OpenTK.Platform.X11
case XEventName.ButtonRelease: case XEventName.ButtonRelease:
{ {
int dx, dy; float dx, dy;
MouseButton button = X11KeyMap.TranslateButton(e.ButtonEvent.button, out dx, out dy); MouseButton button = X11KeyMap.TranslateButton(e.ButtonEvent.button, out dx, out dy);
if (button != MouseButton.LastButton) if (button != MouseButton.LastButton)
{ {
@ -1003,7 +1019,7 @@ namespace OpenTK.Platform.X11
// RefreshWindowBorders(); // RefreshWindowBorders();
//} //}
break; break;
default: default:
//Debug.WriteLine(String.Format("{0} event was not handled", e.type)); //Debug.WriteLine(String.Format("{0} event was not handled", e.type));
break; break;
@ -1499,11 +1515,8 @@ namespace OpenTK.Platform.X11
void GrabMouse() void GrabMouse()
{ {
Functions.XGrabPointer(window.Display, window.Handle, false, Functions.XGrabPointer(window.Display, window.Handle, false,
EventMask.PointerMotionMask | EventMask.PointerMotionMask | EventMask.ButtonPressMask |
EventMask.ButtonMotionMask | EventMask.Button1MotionMask | EventMask.ButtonReleaseMask,
EventMask.Button2MotionMask | EventMask.Button3MotionMask |
EventMask.Button4MotionMask | EventMask.Button5MotionMask |
EventMask.ButtonPressMask | EventMask.ButtonReleaseMask,
GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, GrabMode.GrabModeAsync,
window.Handle, EmptyCursor, IntPtr.Zero); window.Handle, EmptyCursor, IntPtr.Zero);
} }

View file

@ -388,7 +388,7 @@ namespace OpenTK.Platform.X11
return key != Key.Unknown; 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; wheelx = 0;
wheely = 0; wheely = 0;

View file

@ -73,6 +73,7 @@ namespace OpenTK.Platform.X11
internal readonly X11WindowInfo window; internal readonly X11WindowInfo window;
internal static int XIOpCode { get; private set; } internal static int XIOpCode { get; private set; }
internal static int XIVersion { get; private set; }
static readonly Functions.EventPredicate PredicateImpl = IsEventValid; static readonly Functions.EventPredicate PredicateImpl = IsEventValid;
readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl); readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl);
@ -172,6 +173,7 @@ namespace OpenTK.Platform.X11
{ {
if (XI.QueryVersion(display, ref major, ref minor) == ErrorCodes.Success) if (XI.QueryVersion(display, ref major, ref minor) == ErrorCodes.Success)
{ {
XIVersion = major * 100 + minor * 10;
return true; return true;
} }
minor--; minor--;
@ -385,15 +387,13 @@ namespace OpenTK.Platform.X11
case 1: d.State.EnableBit((int)MouseButton.Left); break; case 1: d.State.EnableBit((int)MouseButton.Left); break;
case 2: d.State.EnableBit((int)MouseButton.Middle); break; case 2: d.State.EnableBit((int)MouseButton.Middle); break;
case 3: d.State.EnableBit((int)MouseButton.Right); break; case 3: d.State.EnableBit((int)MouseButton.Right); break;
case 6: d.State.EnableBit((int)MouseButton.Button1); break; case 8: d.State.EnableBit((int)MouseButton.Button1); break;
case 7: d.State.EnableBit((int)MouseButton.Button2); break; case 9: d.State.EnableBit((int)MouseButton.Button2); break;
case 8: d.State.EnableBit((int)MouseButton.Button3); break; case 10: d.State.EnableBit((int)MouseButton.Button3); break;
case 9: d.State.EnableBit((int)MouseButton.Button4); break; case 11: d.State.EnableBit((int)MouseButton.Button4); break;
case 10: d.State.EnableBit((int)MouseButton.Button5); break; case 12: d.State.EnableBit((int)MouseButton.Button5); break;
case 11: d.State.EnableBit((int)MouseButton.Button6); break; case 13: d.State.EnableBit((int)MouseButton.Button6); break;
case 12: d.State.EnableBit((int)MouseButton.Button7); break; case 14: 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;
} }
break; break;
@ -403,15 +403,13 @@ namespace OpenTK.Platform.X11
case 1: d.State.DisableBit((int)MouseButton.Left); break; case 1: d.State.DisableBit((int)MouseButton.Left); break;
case 2: d.State.DisableBit((int)MouseButton.Middle); break; case 2: d.State.DisableBit((int)MouseButton.Middle); break;
case 3: d.State.DisableBit((int)MouseButton.Right); break; case 3: d.State.DisableBit((int)MouseButton.Right); break;
case 6: d.State.DisableBit((int)MouseButton.Button1); break; case 8: d.State.DisableBit((int)MouseButton.Button1); break;
case 7: d.State.DisableBit((int)MouseButton.Button2); break; case 9: d.State.DisableBit((int)MouseButton.Button2); break;
case 8: d.State.DisableBit((int)MouseButton.Button3); break; case 10: d.State.DisableBit((int)MouseButton.Button3); break;
case 9: d.State.DisableBit((int)MouseButton.Button4); break; case 11: d.State.DisableBit((int)MouseButton.Button4); break;
case 10: d.State.DisableBit((int)MouseButton.Button5); break; case 12: d.State.DisableBit((int)MouseButton.Button5); break;
case 11: d.State.DisableBit((int)MouseButton.Button6); break; case 13: d.State.DisableBit((int)MouseButton.Button6); break;
case 12: d.State.DisableBit((int)MouseButton.Button7); break; case 14: 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;
} }
break; break;
} }