Merge pull request #120 from thefiddler/xcursorfix
[X11] Improve mouse input
This commit is contained in:
commit
687fc90c95
7 changed files with 147 additions and 122 deletions
|
@ -34,7 +34,7 @@ namespace OpenTK.Input
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the state of a mouse wheel.
|
/// Represents the state of a mouse wheel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct MouseScrollWheel : IEquatable<MouseScrollWheel>
|
public struct MouseScroll : IEquatable<MouseScroll>
|
||||||
{
|
{
|
||||||
#region Public Members
|
#region Public Members
|
||||||
|
|
||||||
|
@ -52,31 +52,31 @@ namespace OpenTK.Input
|
||||||
/// <value>The y.</value>
|
/// <value>The y.</value>
|
||||||
public float Y { get; internal set; }
|
public float Y { get; internal set; }
|
||||||
|
|
||||||
/// <param name="left">A <see cref="MouseScrollWheel"/> instance to test for equality.</param>
|
/// <param name="left">A <see cref="MouseScroll"/> instance to test for equality.</param>
|
||||||
/// <param name="right">A <see cref="MouseScrollWheel"/> instance to test for equality.</param>
|
/// <param name="right">A <see cref="MouseScroll"/> instance to test for equality.</param>
|
||||||
public static bool operator ==(MouseScrollWheel left, MouseScrollWheel right)
|
public static bool operator ==(MouseScroll left, MouseScroll right)
|
||||||
{
|
{
|
||||||
return left.Equals(right);
|
return left.Equals(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <param name="left">A <see cref="MouseScrollWheel"/> instance to test for inequality.</param>
|
/// <param name="left">A <see cref="MouseScroll"/> instance to test for inequality.</param>
|
||||||
/// <param name="right">A <see cref="MouseScrollWheel"/> instance to test for inequality.</param>
|
/// <param name="right">A <see cref="MouseScroll"/> instance to test for inequality.</param>
|
||||||
public static bool operator !=(MouseScrollWheel left, MouseScrollWheel right)
|
public static bool operator !=(MouseScroll left, MouseScroll right)
|
||||||
{
|
{
|
||||||
return !left.Equals(right);
|
return !left.Equals(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.MouseScrollWheel"/>.
|
/// Returns a <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.MouseScroll"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.MouseScrollWheel"/>.</returns>
|
/// <returns>A <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.MouseScroll"/>.</returns>
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return string.Format("[X={0:0.00}, Y={1:0.00}]", X, Y);
|
return string.Format("[X={0:0.00}, Y={1:0.00}]", X, Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serves as a hash function for a <see cref="OpenTK.Input.MouseScrollWheel"/> object.
|
/// Serves as a hash function for a <see cref="OpenTK.Input.MouseScroll"/> object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
|
||||||
/// hash table.</returns>
|
/// hash table.</returns>
|
||||||
|
@ -86,16 +86,16 @@ namespace OpenTK.Input
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="OpenTK.Input.MouseScrollWheel"/>.
|
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="OpenTK.Input.MouseScroll"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="OpenTK.Input.MouseScrollWheel"/>.</param>
|
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="OpenTK.Input.MouseScroll"/>.</param>
|
||||||
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
|
/// <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>
|
/// <see cref="OpenTK.Input.MouseScroll"/>; otherwise, <c>false</c>.</returns>
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
obj is MouseScrollWheel &&
|
obj is MouseScroll &&
|
||||||
Equals((MouseScrollWheel)obj);
|
Equals((MouseScroll)obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -103,12 +103,12 @@ namespace OpenTK.Input
|
||||||
#region IEquatable Members
|
#region IEquatable Members
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the specified <see cref="OpenTK.Input.MouseScrollWheel"/> is equal to the current <see cref="OpenTK.Input.MouseScrollWheel"/>.
|
/// Determines whether the specified <see cref="OpenTK.Input.MouseScroll"/> is equal to the current <see cref="OpenTK.Input.MouseScroll"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="other">The <see cref="OpenTK.Input.MouseScrollWheel"/> to compare with the current <see cref="OpenTK.Input.MouseScrollWheel"/>.</param>
|
/// <param name="other">The <see cref="OpenTK.Input.MouseScroll"/> to compare with the current <see cref="OpenTK.Input.MouseScroll"/>.</param>
|
||||||
/// <returns><c>true</c> if the specified <see cref="OpenTK.Input.MouseScrollWheel"/> is equal to the current
|
/// <returns><c>true</c> if the specified <see cref="OpenTK.Input.MouseScroll"/> is equal to the current
|
||||||
/// <see cref="OpenTK.Input.MouseScrollWheel"/>; otherwise, <c>false</c>.</returns>
|
/// <see cref="OpenTK.Input.MouseScroll"/>; otherwise, <c>false</c>.</returns>
|
||||||
public bool Equals(MouseScrollWheel other)
|
public bool Equals(MouseScroll other)
|
||||||
{
|
{
|
||||||
return X == other.X && Y == other.Y;
|
return X == other.X && Y == other.Y;
|
||||||
}
|
}
|
|
@ -39,7 +39,7 @@ namespace OpenTK.Input
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
int x, y;
|
int x, y;
|
||||||
MouseScrollWheel scroll;
|
MouseScroll scroll;
|
||||||
ushort buttons;
|
ushort buttons;
|
||||||
bool is_connected;
|
bool is_connected;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ namespace OpenTK.Input
|
||||||
/// Gets a <see cref="OpenTK.Input.MouseScrollWheel"/> instance,
|
/// Gets a <see cref="OpenTK.Input.MouseScrollWheel"/> instance,
|
||||||
/// representing the current state of the mouse scroll wheel.
|
/// representing the current state of the mouse scroll wheel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MouseScrollWheel Scroll
|
public MouseScroll Scroll
|
||||||
{
|
{
|
||||||
get { return scroll; }
|
get { return scroll; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -790,7 +790,6 @@
|
||||||
<Compile Include="WindowIcon.cs" />
|
<Compile Include="WindowIcon.cs" />
|
||||||
<Compile Include="Platform\MacOS\Cocoa\NSBitmapFormat.cs" />
|
<Compile Include="Platform\MacOS\Cocoa\NSBitmapFormat.cs" />
|
||||||
<Compile Include="Platform\NativeWindowBase.cs" />
|
<Compile Include="Platform\NativeWindowBase.cs" />
|
||||||
<Compile Include="Input\MouseScrollWheel.cs" />
|
|
||||||
<Compile Include="Input\MouseEventArgs.cs" />
|
<Compile Include="Input\MouseEventArgs.cs" />
|
||||||
<Compile Include="Platform\MacOS\Quartz\EventServices.cs" />
|
<Compile Include="Platform\MacOS\Quartz\EventServices.cs" />
|
||||||
<Compile Include="Platform\MacOS\Quartz\DisplayServices.cs">
|
<Compile Include="Platform\MacOS\Quartz\DisplayServices.cs">
|
||||||
|
@ -799,6 +798,7 @@
|
||||||
<Compile Include="Platform\MacOS\Quartz\CoreFoundation.cs">
|
<Compile Include="Platform\MacOS\Quartz\CoreFoundation.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Input\MouseScroll.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|
|
@ -232,6 +232,8 @@ namespace OpenTK.Platform
|
||||||
MouseState[button] = true;
|
MouseState[button] = true;
|
||||||
|
|
||||||
var e = MouseDownArgs;
|
var e = MouseDownArgs;
|
||||||
|
e.Button = button;
|
||||||
|
e.IsPressed = true;
|
||||||
e.Mouse = MouseState;
|
e.Mouse = MouseState;
|
||||||
|
|
||||||
MouseDown(this, e);
|
MouseDown(this, e);
|
||||||
|
@ -242,6 +244,8 @@ namespace OpenTK.Platform
|
||||||
MouseState[button] = false;
|
MouseState[button] = false;
|
||||||
|
|
||||||
var e = MouseUpArgs;
|
var e = MouseUpArgs;
|
||||||
|
e.Button = button;
|
||||||
|
e.IsPressed = false;
|
||||||
e.Mouse = MouseState;
|
e.Mouse = MouseState;
|
||||||
|
|
||||||
MouseUp(this, e);
|
MouseUp(this, e);
|
||||||
|
|
|
@ -96,6 +96,8 @@ namespace OpenTK.Platform.X11
|
||||||
static readonly IntPtr _atom_add = (IntPtr)1;
|
static readonly IntPtr _atom_add = (IntPtr)1;
|
||||||
static readonly IntPtr _atom_toggle = (IntPtr)2;
|
static readonly IntPtr _atom_toggle = (IntPtr)2;
|
||||||
|
|
||||||
|
// Used by OpenTK to detect mouse warp events
|
||||||
|
|
||||||
Rectangle bounds, client_rectangle;
|
Rectangle bounds, client_rectangle;
|
||||||
int border_left, border_right, border_top, border_bottom;
|
int border_left, border_right, border_top, border_bottom;
|
||||||
Icon icon;
|
Icon icon;
|
||||||
|
@ -121,7 +123,6 @@ namespace OpenTK.Platform.X11
|
||||||
MouseCursor cursor = MouseCursor.Default;
|
MouseCursor cursor = MouseCursor.Default;
|
||||||
IntPtr cursorHandle;
|
IntPtr cursorHandle;
|
||||||
bool cursor_visible = true;
|
bool cursor_visible = true;
|
||||||
int mouse_rel_x, mouse_rel_y;
|
|
||||||
|
|
||||||
// Keyboard input
|
// Keyboard input
|
||||||
readonly byte[] ascii = new byte[16];
|
readonly byte[] ascii = new byte[16];
|
||||||
|
@ -129,10 +130,9 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
readonly IntPtr EmptyCursor;
|
readonly IntPtr EmptyCursor;
|
||||||
|
|
||||||
public static bool MouseWarpActive = false;
|
|
||||||
|
|
||||||
readonly bool xi2_supported;
|
readonly bool xi2_supported;
|
||||||
readonly int xi2_opcode;
|
readonly int xi2_opcode;
|
||||||
|
readonly int xi2_version;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -244,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;
|
||||||
|
@ -905,63 +906,43 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
case XEventName.MotionNotify:
|
case XEventName.MotionNotify:
|
||||||
{
|
{
|
||||||
// Try to detect and ignore events from XWarpPointer, below.
|
|
||||||
// This heuristic will fail if the user actually moves the pointer
|
|
||||||
// to the dead center of the window. Fortunately, this situation
|
|
||||||
// is very very uncommon. Todo: Can this be remedied?
|
|
||||||
int x = e.MotionEvent.x;
|
int x = e.MotionEvent.x;
|
||||||
int y = e.MotionEvent.y;
|
int y = e.MotionEvent.y;
|
||||||
// TODO: Have offset as a stored field, only update it when the window moves
|
|
||||||
// The middle point cannot be the average of the Bounds.left/right/top/bottom,
|
|
||||||
// because these fields take into account window decoration (borders, etc),
|
|
||||||
// which we do not want to account for.
|
|
||||||
Point offset = this.PointToClient(Point.Empty);
|
|
||||||
int middle_x = Width/2-offset.X;
|
|
||||||
int middle_y = Height/2-offset.Y;
|
|
||||||
|
|
||||||
Point screen_xy = PointToScreen(new Point(x, y));
|
if (x != 0 || y != 0)
|
||||||
if (!CursorVisible && MouseWarpActive &&
|
|
||||||
screen_xy.X == middle_x && screen_xy.Y == middle_y)
|
|
||||||
{
|
|
||||||
MouseWarpActive = false;
|
|
||||||
mouse_rel_x = x;
|
|
||||||
mouse_rel_y = y;
|
|
||||||
}
|
|
||||||
else if (!CursorVisible)
|
|
||||||
{
|
|
||||||
OnMouseMove(
|
|
||||||
MathHelper.Clamp(MouseState.X + x - mouse_rel_x, 0, Width),
|
|
||||||
MathHelper.Clamp(MouseState.Y + y - mouse_rel_y, 0, Height));
|
|
||||||
mouse_rel_x = x;
|
|
||||||
mouse_rel_y = y;
|
|
||||||
|
|
||||||
// Warp cursor to center of window.
|
|
||||||
MouseWarpActive = true;
|
|
||||||
Mouse.SetPosition(middle_x, middle_y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
OnMouseMove(
|
OnMouseMove(
|
||||||
MathHelper.Clamp(x, 0, Width),
|
MathHelper.Clamp(x, 0, Width),
|
||||||
MathHelper.Clamp(y, 0, Height));
|
MathHelper.Clamp(y, 0, Height));
|
||||||
mouse_rel_x = x;
|
|
||||||
mouse_rel_y = y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -969,9 +950,8 @@ 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)
|
||||||
{
|
{
|
||||||
OnMouseUp(button);
|
OnMouseUp(button);
|
||||||
|
@ -985,6 +965,11 @@ namespace OpenTK.Platform.X11
|
||||||
has_focus = true;
|
has_focus = true;
|
||||||
if (has_focus != previous_focus)
|
if (has_focus != previous_focus)
|
||||||
OnFocusedChanged(EventArgs.Empty);
|
OnFocusedChanged(EventArgs.Empty);
|
||||||
|
|
||||||
|
if (Focused && !CursorVisible)
|
||||||
|
{
|
||||||
|
GrabMouse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1000,6 +985,12 @@ namespace OpenTK.Platform.X11
|
||||||
case XEventName.LeaveNotify:
|
case XEventName.LeaveNotify:
|
||||||
if (CursorVisible)
|
if (CursorVisible)
|
||||||
{
|
{
|
||||||
|
int x = MathHelper.Clamp(e.CrossingEvent.x, 0, Width);
|
||||||
|
int y = MathHelper.Clamp(e.CrossingEvent.y, 0, Height);
|
||||||
|
if (x != MouseState.X || y != MouseState.Y)
|
||||||
|
{
|
||||||
|
OnMouseMove(x, y);
|
||||||
|
}
|
||||||
OnMouseLeave(EventArgs.Empty);
|
OnMouseLeave(EventArgs.Empty);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1441,11 +1432,18 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
|
if (value == cursor)
|
||||||
|
return;
|
||||||
|
|
||||||
using (new XLock(window.Display))
|
using (new XLock(window.Display))
|
||||||
{
|
{
|
||||||
if (value == MouseCursor.Default)
|
if (value == MouseCursor.Default)
|
||||||
{
|
{
|
||||||
Functions.XUndefineCursor(window.Display, window.Handle);
|
cursorHandle = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
else if (value == MouseCursor.Empty)
|
||||||
|
{
|
||||||
|
cursorHandle = EmptyCursor;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1457,10 +1455,17 @@ namespace OpenTK.Platform.X11
|
||||||
xcursorimage->pixels = (uint*)pixels;
|
xcursorimage->pixels = (uint*)pixels;
|
||||||
xcursorimage->delay = 0;
|
xcursorimage->delay = 0;
|
||||||
cursorHandle = Functions.XcursorImageLoadCursor(window.Display, xcursorimage);
|
cursorHandle = Functions.XcursorImageLoadCursor(window.Display, xcursorimage);
|
||||||
Functions.XDefineCursor(window.Display, window.Handle, cursorHandle);
|
|
||||||
Functions.XcursorImageDestroy(xcursorimage);
|
Functions.XcursorImageDestroy(xcursorimage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the cursor is visible set it now.
|
||||||
|
// Otherwise, it will be set in CursorVisible = true.
|
||||||
|
if (CursorVisible)
|
||||||
|
{
|
||||||
|
Functions.XDefineCursor(window.Display, window.Handle, cursorHandle);
|
||||||
|
}
|
||||||
|
|
||||||
cursor = value;
|
cursor = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1480,6 +1485,13 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
using (new XLock(window.Display))
|
using (new XLock(window.Display))
|
||||||
{
|
{
|
||||||
|
UngrabMouse();
|
||||||
|
|
||||||
|
Point p = PointToScreen(new Point(MouseState.X, MouseState.Y));
|
||||||
|
Mouse.SetPosition(p.X, p.Y);
|
||||||
|
|
||||||
|
// Note: if cursorHandle = IntPtr.Zero, this restores the default cursor
|
||||||
|
// (equivalent to calling XUndefineCursor)
|
||||||
Functions.XDefineCursor(window.Display, window.Handle, cursorHandle);
|
Functions.XDefineCursor(window.Display, window.Handle, cursorHandle);
|
||||||
cursor_visible = true;
|
cursor_visible = true;
|
||||||
}
|
}
|
||||||
|
@ -1488,13 +1500,27 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
using (new XLock(window.Display))
|
using (new XLock(window.Display))
|
||||||
{
|
{
|
||||||
Functions.XDefineCursor(window.Display, window.Handle, EmptyCursor);
|
GrabMouse();
|
||||||
cursor_visible = false;
|
cursor_visible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GrabMouse()
|
||||||
|
{
|
||||||
|
Functions.XGrabPointer(window.Display, window.Handle, false,
|
||||||
|
EventMask.PointerMotionMask | EventMask.ButtonPressMask |
|
||||||
|
EventMask.ButtonReleaseMask,
|
||||||
|
GrabMode.GrabModeAsync, GrabMode.GrabModeAsync,
|
||||||
|
window.Handle, EmptyCursor, IntPtr.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UngrabMouse()
|
||||||
|
{
|
||||||
|
Functions.XUngrabPointer(window.Display, IntPtr.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -34,8 +34,6 @@ using OpenTK.Input;
|
||||||
|
|
||||||
namespace OpenTK.Platform.X11
|
namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
// Todo: multi-mouse support. Right now we aggregate all data into a single mouse device.
|
|
||||||
// This should be easy: just read the device id and route the data to the correct device.
|
|
||||||
sealed class XI2Mouse : IMouseDriver2, IDisposable
|
sealed class XI2Mouse : IMouseDriver2, IDisposable
|
||||||
{
|
{
|
||||||
const XEventName ExitEvent = XEventName.LASTEvent + 1;
|
const XEventName ExitEvent = XEventName.LASTEvent + 1;
|
||||||
|
@ -73,20 +71,11 @@ 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);
|
||||||
|
|
||||||
// Store information on a mouse warp event, so it can be ignored.
|
|
||||||
struct MouseWarp : IEquatable<MouseWarp>
|
|
||||||
{
|
|
||||||
public MouseWarp(double x, double y) { X = x; Y = y; }
|
|
||||||
double X, Y;
|
|
||||||
public bool Equals(MouseWarp warp) { return X == warp.X && Y == warp.Y; }
|
|
||||||
}
|
|
||||||
MouseWarp? mouse_warp_event;
|
|
||||||
int mouse_warp_event_count;
|
|
||||||
|
|
||||||
static XI2Mouse()
|
static XI2Mouse()
|
||||||
{
|
{
|
||||||
using (new XLock(API.DefaultDisplay))
|
using (new XLock(API.DefaultDisplay))
|
||||||
|
@ -138,6 +127,7 @@ namespace OpenTK.Platform.X11
|
||||||
XIEventMasks.RawButtonPressMask |
|
XIEventMasks.RawButtonPressMask |
|
||||||
XIEventMasks.RawButtonReleaseMask |
|
XIEventMasks.RawButtonReleaseMask |
|
||||||
XIEventMasks.RawMotionMask |
|
XIEventMasks.RawMotionMask |
|
||||||
|
XIEventMasks.MotionMask |
|
||||||
XIEventMasks.DeviceChangedMask |
|
XIEventMasks.DeviceChangedMask |
|
||||||
(XIEventMasks)(1 << (int)ExitEvent)))
|
(XIEventMasks)(1 << (int)ExitEvent)))
|
||||||
{
|
{
|
||||||
|
@ -154,6 +144,8 @@ namespace OpenTK.Platform.X11
|
||||||
// Checks whether XInput2 is supported on the specified display.
|
// Checks whether XInput2 is supported on the specified display.
|
||||||
// If a display is not specified, the default display is used.
|
// If a display is not specified, the default display is used.
|
||||||
internal static bool IsSupported(IntPtr display)
|
internal static bool IsSupported(IntPtr display)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (display == IntPtr.Zero)
|
if (display == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
|
@ -172,12 +164,19 @@ 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--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (DllNotFoundException e)
|
||||||
|
{
|
||||||
|
Debug.Print(e.ToString());
|
||||||
|
Debug.Print("XInput2 extension not supported. Mouse support will suffer.");
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -303,12 +302,8 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
Functions.XWarpPointer(API.DefaultDisplay,
|
Functions.XWarpPointer(API.DefaultDisplay,
|
||||||
IntPtr.Zero, window.RootWindow, 0, 0, 0, 0, (int)x, (int)y);
|
IntPtr.Zero, window.RootWindow, 0, 0, 0, 0, (int)x, (int)y);
|
||||||
|
Interlocked.Exchange(ref cursor_x, (long)x);
|
||||||
// Mark the expected warp-event so it can be ignored.
|
Interlocked.Exchange(ref cursor_y, (long)y);
|
||||||
if (mouse_warp_event == null)
|
|
||||||
mouse_warp_event_count = 0;
|
|
||||||
mouse_warp_event_count++;
|
|
||||||
mouse_warp_event = new MouseWarp((int)x, (int)y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +337,10 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
switch ((XIEventType)cookie.evtype)
|
switch ((XIEventType)cookie.evtype)
|
||||||
{
|
{
|
||||||
|
case XIEventType.Motion:
|
||||||
|
// Nothing to do
|
||||||
|
break;
|
||||||
|
|
||||||
case XIEventType.RawMotion:
|
case XIEventType.RawMotion:
|
||||||
case XIEventType.RawButtonPress:
|
case XIEventType.RawButtonPress:
|
||||||
case XIEventType.RawButtonRelease:
|
case XIEventType.RawButtonRelease:
|
||||||
|
@ -385,15 +384,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 +400,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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue