mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-02-24 23:26:55 +00:00
* Input/Mouse.cs:
* Input/IMouseDriver2.cs: * Platform/X11/X11Mouse.cs: * Platform/X11/XI2Mouse.cs: * Platform/X11/Functions.cs: * Platform/Windows/WMInput.cs: * Platform/X11/X11GLNative.cs: * Platform/Windows/WinRawMouse.cs: Added ability to set the position of the mouse cursor. [X11] Avoid grabbing the pointer, as this causes unexpected side-effects (XInput2 stops working, debugging becomes difficult). We now use XWarpPointer and try to discard the spurious MouseMove events it generates. [X11] Make cursor visible when window loses focus, to make debugging easier. Restore previous state when it regains focus.
This commit is contained in:
parent
4fd279534b
commit
07cbb9dd8b
|
@ -1,4 +1,31 @@
|
||||||
using System;
|
#region License
|
||||||
|
//
|
||||||
|
// The Open Toolkit Library License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006 - 2010 the Open Toolkit library.
|
||||||
|
//
|
||||||
|
// 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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
@ -6,17 +33,8 @@ namespace OpenTK.Input
|
||||||
{
|
{
|
||||||
interface IMouseDriver2
|
interface IMouseDriver2
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the MouseState for the default keyboard device.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A <see cref="OpenTK.Input.MouseState"/> structure containing the state of the mouse device.</returns>
|
|
||||||
MouseState GetState();
|
MouseState GetState();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the MouseState for the specified keyboard device.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="index">The index of the keyboard device.</param>
|
|
||||||
/// <returns>A <see cref="OpenTK.Input.MouseState"/> structure containing the state of the mouse device.</returns>
|
|
||||||
MouseState GetState(int index);
|
MouseState GetState(int index);
|
||||||
|
void SetPosition(double x, double y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,23 @@ namespace OpenTK.Input
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///Moves the mouse cursor to the specified screen position.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">
|
||||||
|
/// A <see cref="System.Double"/> that represents the absolute x position of the cursor in screen coordinates.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="y">
|
||||||
|
/// A <see cref="System.Double"/> that represents the absolute y position of the cursor in screen coordinates.
|
||||||
|
/// </param>
|
||||||
|
public static void SetPosition(double x, double y)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
driver.SetPosition(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,11 @@ namespace OpenTK.Platform.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetPosition(double x, double y)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IKeyboardDriver2 Members
|
#region IKeyboardDriver2 Members
|
||||||
|
|
|
@ -278,6 +278,11 @@ namespace OpenTK.Platform.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetPosition(double x, double y)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -529,6 +529,12 @@ namespace OpenTK.Platform.X11
|
||||||
[DllImport("libXi")]
|
[DllImport("libXi")]
|
||||||
static extern Status XIUngrabDevice(IntPtr display, int deviceid, Time time);
|
static extern Status XIUngrabDevice(IntPtr display, int deviceid, Time time);
|
||||||
|
|
||||||
|
[DllImport("libXi")]
|
||||||
|
public static extern Bool XIWarpPointer(Display display,
|
||||||
|
int deviceid, Window src_w, Window dest_w,
|
||||||
|
double src_x, double src_y, int src_width, int src_height,
|
||||||
|
double dest_x, double dest_y);
|
||||||
|
|
||||||
static readonly IntPtr CopyFromParent = IntPtr.Zero;
|
static readonly IntPtr CopyFromParent = IntPtr.Zero;
|
||||||
|
|
||||||
public static void SendNetWMMessage(X11WindowInfo window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
|
public static void SendNetWMMessage(X11WindowInfo window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
|
||||||
|
|
|
@ -54,7 +54,10 @@ namespace OpenTK.Platform.X11
|
||||||
const int _min_width = 30, _min_height = 30;
|
const int _min_width = 30, _min_height = 30;
|
||||||
|
|
||||||
X11WindowInfo window = new X11WindowInfo();
|
X11WindowInfo window = new X11WindowInfo();
|
||||||
|
|
||||||
|
// Legacy input support
|
||||||
X11Input driver;
|
X11Input driver;
|
||||||
|
MouseDevice mouse;
|
||||||
|
|
||||||
// Window manager hints for fullscreen windows.
|
// Window manager hints for fullscreen windows.
|
||||||
// Not used right now (the code is written, but is not 64bit-correct), but could be useful for older WMs which
|
// Not used right now (the code is written, but is not 64bit-correct), but could be useful for older WMs which
|
||||||
|
@ -107,6 +110,8 @@ namespace OpenTK.Platform.X11
|
||||||
bool isExiting;
|
bool isExiting;
|
||||||
|
|
||||||
bool _decorations_hidden = false;
|
bool _decorations_hidden = false;
|
||||||
|
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];
|
||||||
|
@ -115,6 +120,8 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
readonly IntPtr EmptyCursor;
|
readonly IntPtr EmptyCursor;
|
||||||
|
|
||||||
|
public static bool MouseWarpActive = false;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
@ -196,6 +203,7 @@ namespace OpenTK.Platform.X11
|
||||||
RefreshWindowBounds(ref e);
|
RefreshWindowBounds(ref e);
|
||||||
|
|
||||||
driver = new X11Input(window);
|
driver = new X11Input(window);
|
||||||
|
mouse = driver.Mouse[0];
|
||||||
|
|
||||||
EmptyCursor = CreateEmptyCursor(window);
|
EmptyCursor = CreateEmptyCursor(window);
|
||||||
|
|
||||||
|
@ -692,6 +700,17 @@ namespace OpenTK.Platform.X11
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SetMouseClamped(MouseDevice mouse, int x, int y,
|
||||||
|
int left, int top, int width, int height)
|
||||||
|
{
|
||||||
|
// Clamp mouse to the specified rectangle.
|
||||||
|
x = Math.Max(x, left);
|
||||||
|
x = Math.Min(x, width);
|
||||||
|
y = Math.Max(y, top);
|
||||||
|
y = Math.Min(y, height);
|
||||||
|
mouse.Position = new Point(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region INativeWindow Members
|
#region INativeWindow Members
|
||||||
|
@ -794,6 +813,45 @@ namespace OpenTK.Platform.X11
|
||||||
break;
|
break;
|
||||||
|
|
||||||
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 y =e.MotionEvent.y;
|
||||||
|
int middle_x = (Bounds.Left + Bounds.Right) / 2;
|
||||||
|
int middle_y = (Bounds.Top + Bounds.Bottom) / 2;
|
||||||
|
Point screen_xy = PointToScreen(new Point(x, y));
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
SetMouseClamped(mouse,
|
||||||
|
mouse.X + x - mouse_rel_x,
|
||||||
|
mouse.Y + y - mouse_rel_y,
|
||||||
|
0, 0, Width, Height);
|
||||||
|
mouse_rel_x = x;
|
||||||
|
mouse_rel_y = y;
|
||||||
|
|
||||||
|
// Warp cursor to center of window.
|
||||||
|
MouseWarpActive = true;
|
||||||
|
Mouse.SetPosition(middle_x, middle_y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetMouseClamped(mouse, x, y, 0, 0, Width, Height);
|
||||||
|
mouse_rel_x = x;
|
||||||
|
mouse_rel_y = y;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case XEventName.ButtonPress:
|
case XEventName.ButtonPress:
|
||||||
case XEventName.ButtonRelease:
|
case XEventName.ButtonRelease:
|
||||||
driver.ProcessEvent(ref e);
|
driver.ProcessEvent(ref e);
|
||||||
|
@ -818,7 +876,10 @@ namespace OpenTK.Platform.X11
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XEventName.LeaveNotify:
|
case XEventName.LeaveNotify:
|
||||||
|
if (CursorVisible)
|
||||||
|
{
|
||||||
MouseLeave(this, EventArgs.Empty);
|
MouseLeave(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XEventName.EnterNotify:
|
case XEventName.EnterNotify:
|
||||||
|
@ -1291,15 +1352,15 @@ namespace OpenTK.Platform.X11
|
||||||
|
|
||||||
public bool CursorVisible
|
public bool CursorVisible
|
||||||
{
|
{
|
||||||
get { return true; } // Not used
|
get { return cursor_visible; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
using (new XLock(window.Display))
|
using (new XLock(window.Display))
|
||||||
{
|
{
|
||||||
Functions.XUngrabPointer(window.Display, IntPtr.Zero);
|
|
||||||
Functions.XUndefineCursor(window.Display, window.WindowHandle);
|
Functions.XUndefineCursor(window.Display, window.WindowHandle);
|
||||||
|
cursor_visible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1307,11 +1368,7 @@ namespace OpenTK.Platform.X11
|
||||||
using (new XLock(window.Display))
|
using (new XLock(window.Display))
|
||||||
{
|
{
|
||||||
Functions.XDefineCursor(window.Display, window.WindowHandle, EmptyCursor);
|
Functions.XDefineCursor(window.Display, window.WindowHandle, EmptyCursor);
|
||||||
Functions.XGrabPointer(window.Display, window.WindowHandle, true,
|
cursor_visible = false;
|
||||||
EventMask.PointerMotionMask | EventMask.ButtonPressMask | EventMask.ButtonReleaseMask,
|
|
||||||
GrabMode.GrabModeAsync, GrabMode.GrabModeAsync, window.WindowHandle, IntPtr.Zero,
|
|
||||||
IntPtr.Zero);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,11 @@ namespace OpenTK.Platform.X11
|
||||||
return new MouseState();
|
return new MouseState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetPosition(double x, double y)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
void WriteBit(MouseButton offset, int enabled)
|
void WriteBit(MouseButton offset, int enabled)
|
||||||
{
|
{
|
||||||
if (enabled != 0)
|
if (enabled != 0)
|
||||||
|
|
|
@ -39,12 +39,22 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
List<MouseState> mice = new List<MouseState>();
|
List<MouseState> mice = new List<MouseState>();
|
||||||
Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps raw ids to mouse ids
|
Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps raw ids to mouse ids
|
||||||
readonly X11WindowInfo window;
|
internal readonly X11WindowInfo window;
|
||||||
static int XIOpCode;
|
static int XIOpCode;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
public XI2Mouse()
|
public XI2Mouse()
|
||||||
{
|
{
|
||||||
Debug.WriteLine("Using XI2Mouse.");
|
Debug.WriteLine("Using XI2Mouse.");
|
||||||
|
@ -65,6 +75,7 @@ namespace OpenTK.Platform.X11
|
||||||
XIEventMasks.RawButtonReleaseMask | XIEventMasks.RawMotionMask))
|
XIEventMasks.RawButtonReleaseMask | XIEventMasks.RawMotionMask))
|
||||||
{
|
{
|
||||||
Functions.XISelectEvents(window.Display, window.WindowHandle, mask);
|
Functions.XISelectEvents(window.Display, window.WindowHandle, mask);
|
||||||
|
Functions.XISelectEvents(window.Display, window.RootWindow, mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,8 +121,40 @@ namespace OpenTK.Platform.X11
|
||||||
return new MouseState();
|
return new MouseState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetPosition(double x, double y)
|
||||||
|
{
|
||||||
|
using (new XLock(window.Display))
|
||||||
|
{
|
||||||
|
// Functions.XIWarpPointer(window.Display, 0,
|
||||||
|
// IntPtr.Zero, window.RootWindow, 0, 0, 0, 0, x, y);
|
||||||
|
Functions.XWarpPointer(window.Display,
|
||||||
|
IntPtr.Zero, window.RootWindow, 0, 0, 0, 0, (int)x, (int)y);
|
||||||
|
|
||||||
|
// Mark the expected warp-event so it can be ignored.
|
||||||
|
if (mouse_warp_event == null)
|
||||||
|
mouse_warp_event_count = 0;
|
||||||
|
mouse_warp_event_count++;
|
||||||
|
mouse_warp_event = new MouseWarp((int)x, (int)y);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessEvents();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
bool CheckMouseWarp(double x, double y)
|
||||||
|
{
|
||||||
|
// Check if a mouse warp with the specified destination exists.
|
||||||
|
bool is_warp =
|
||||||
|
mouse_warp_event.HasValue &&
|
||||||
|
mouse_warp_event.Value.Equals(new MouseWarp((int)x, (int)y));
|
||||||
|
|
||||||
|
if (is_warp && --mouse_warp_event_count <= 0)
|
||||||
|
mouse_warp_event = null;
|
||||||
|
|
||||||
|
return is_warp;
|
||||||
|
}
|
||||||
|
|
||||||
void ProcessEvents()
|
void ProcessEvents()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
|
@ -140,10 +183,21 @@ namespace OpenTK.Platform.X11
|
||||||
switch (raw.evtype)
|
switch (raw.evtype)
|
||||||
{
|
{
|
||||||
case XIEventType.RawMotion:
|
case XIEventType.RawMotion:
|
||||||
|
double x = 0, y = 0;
|
||||||
if (IsBitSet(raw.valuators.mask, 0))
|
if (IsBitSet(raw.valuators.mask, 0))
|
||||||
state.X += (int)BitConverter.Int64BitsToDouble(Marshal.ReadInt64(raw.raw_values, 0));
|
{
|
||||||
|
x = BitConverter.Int64BitsToDouble(Marshal.ReadInt64(raw.raw_values, 0));
|
||||||
|
}
|
||||||
if (IsBitSet(raw.valuators.mask, 1))
|
if (IsBitSet(raw.valuators.mask, 1))
|
||||||
state.Y += (int)BitConverter.Int64BitsToDouble(Marshal.ReadInt64(raw.raw_values, 8));
|
{
|
||||||
|
y = BitConverter.Int64BitsToDouble(Marshal.ReadInt64(raw.raw_values, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CheckMouseWarp(x, y))
|
||||||
|
{
|
||||||
|
state.X += (int)x;
|
||||||
|
state.Y += (int)y;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XIEventType.RawButtonPress:
|
case XIEventType.RawButtonPress:
|
||||||
|
|
Loading…
Reference in a new issue