[Input] Added Mouse.GetCursorPos() (WIP)
This commit is contained in:
parent
cd7342b688
commit
f4a3cab0e0
12 changed files with 452 additions and 124 deletions
|
@ -301,6 +301,7 @@ namespace Examples.Tests
|
|||
static int DrawMice(Graphics gfx, int line)
|
||||
{
|
||||
line++;
|
||||
DrawString(gfx, String.Format("Cursor: {0}", OpenTK.Input.Mouse.GetCursorState()), line++);
|
||||
DrawString(gfx, "Mouse:", line++);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
|
|
|
@ -36,5 +36,6 @@ namespace OpenTK.Input
|
|||
MouseState GetState();
|
||||
MouseState GetState(int index);
|
||||
void SetPosition(double x, double y);
|
||||
MouseState GetCursorState();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,8 +48,14 @@ namespace OpenTK.Input
|
|||
|
||||
/// <summary>
|
||||
/// Retrieves the combined <see cref="OpenTK.Input.MouseState"/> for all specified mouse devices.
|
||||
/// The X, Y and wheel values are defined in a hardware-specific coordinate system.
|
||||
/// Pointer ballistics (acceleration) are NOT applied. Resolution is hardware-specific,
|
||||
/// typically between 200 and 2000 DPI.
|
||||
/// Use <see cref="OpenTK.Input.Mouse.GetState(int)"/> to retrieve the state of a specific mouse device.
|
||||
/// Use <see cref="OpenTK.Input.Mouse.GetCursorState()"/> to retrieve the absolute coordinates of the mouse cursor.
|
||||
/// Use <see cref="OpenTK.GameWindow.MouseMove"/> for event-based mouse input.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="OpenTK.Input.MouseState"/> structure containing the combined state of all mouse devices.</returns>
|
||||
/// <returns>A <see cref="OpenTK.Input.MouseState"/> structure representing the combined state of all mouse devices.</returns>
|
||||
public static MouseState GetState()
|
||||
{
|
||||
lock (SyncRoot)
|
||||
|
@ -60,9 +66,15 @@ namespace OpenTK.Input
|
|||
|
||||
/// <summary>
|
||||
/// Retrieves the <see cref="OpenTK.Input.MouseState"/> for the specified mouse device.
|
||||
/// The X, Y and wheel values are defined in a hardware-specific coordinate system.
|
||||
/// Pointer ballistics (acceleration) are NOT applied. Resolution is hardware-specific,
|
||||
/// typically between 200 and 2000 DPI.
|
||||
/// Use <see cref="OpenTK.Input.Mouse.GetState()"/> to retrieve the combined state of all mouse devices.
|
||||
/// Use <see cref="OpenTK.Input.Mouse.GetCursorState()"/> to retrieve the absolute coordinates of the mouse cursor.
|
||||
/// Use <see cref="OpenTK.GameWindow.MouseMove"/> for event-based mouse input.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the mouse device.</param>
|
||||
/// <returns>A <see cref="OpenTK.Input.MouseState"/> structure containing the state for the specified mouse device.</returns>
|
||||
/// <returns>A <see cref="OpenTK.Input.MouseState"/> structure representing the state for the specified mouse device.</returns>
|
||||
public static MouseState GetState(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
|
@ -74,6 +86,23 @@ namespace OpenTK.Input
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retreves the <see cref="OpenTK.Input.MouseState"/> for the mouse cursor.
|
||||
/// The X and Y coordinates are defined in absolute desktop points, with the origin
|
||||
/// placed at the top-left corner of <see cref="OpenTK.DisplayDevice.Default"/>.
|
||||
/// Pointer ballistics (acceleration) are applied. Resolution is limited to the
|
||||
/// resolution of the <see cref="OpenTK.DisplayDevice"/> containing the cursor,
|
||||
/// typically between 96 and 120 DPI.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="OpenTK.Input.MouseState"/> structure representing the state of the mouse cursor.</returns>
|
||||
public static MouseState GetCursorState()
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return driver.GetCursorState();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///Moves the mouse cursor to the specified screen position.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<ProjectType>Local</ProjectType>
|
||||
|
@ -167,6 +167,7 @@
|
|||
<Compile Include="Platform\Windows\WinInputBase.cs" />
|
||||
<Compile Include="Platform\Windows\XInputJoystick.cs" />
|
||||
<Compile Include="Platform\X11\Bindings\INotify.cs" />
|
||||
<Compile Include="Platform\X11\Bindings\XI.cs" />
|
||||
<Compile Include="ToolkitOptions.cs" />
|
||||
<Compile Include="WindowBorder.cs">
|
||||
<SubType>Code</SubType>
|
||||
|
|
|
@ -834,6 +834,14 @@ namespace OpenTK.Platform.MacOS
|
|||
return new MouseState();
|
||||
}
|
||||
|
||||
MouseState IMouseDriver2.GetCursorState()
|
||||
{
|
||||
var state = new MouseState();
|
||||
state.SetIsConnected(true);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void IMouseDriver2.SetPosition(double x, double y)
|
||||
{
|
||||
CG.SetLocalEventsSuppressionInterval(0.0);
|
||||
|
|
|
@ -119,6 +119,24 @@ namespace OpenTK.Platform.SDL2
|
|||
return new MouseState();
|
||||
}
|
||||
|
||||
public MouseState GetCursorState()
|
||||
{
|
||||
int x, y;
|
||||
var buttons = SDL.GetMouseState(out x, out y);
|
||||
|
||||
var state = new MouseState();
|
||||
state.SetIsConnected(true);
|
||||
state.X = x;
|
||||
state.Y = y;
|
||||
state[MouseButton.Left] = (buttons & ButtonFlags.Left) != 0;
|
||||
state[MouseButton.Middle] = (buttons & ButtonFlags.Middle) != 0;
|
||||
state[MouseButton.Right] = (buttons & ButtonFlags.Right) != 0;
|
||||
state[MouseButton.Button1] = (buttons & ButtonFlags.X1) != 0;
|
||||
state[MouseButton.Button2] = (buttons & ButtonFlags.X2) != 0;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public void SetPosition(double x, double y)
|
||||
{
|
||||
SDL.WarpMouseInWindow(IntPtr.Zero, (int)x, (int)y);
|
||||
|
|
|
@ -348,6 +348,30 @@ namespace OpenTK.Platform.Windows
|
|||
Functions.SetCursorPos((int)x, (int)y);
|
||||
}
|
||||
|
||||
public MouseState GetCursorState()
|
||||
{
|
||||
var state = new MouseState();
|
||||
state.SetIsConnected(true);
|
||||
|
||||
POINT p = new POINT();
|
||||
Functions.GetCursorPos(ref p);
|
||||
bool left = Functions.GetKeyState(VirtualKeys.LBUTTON) != 0;
|
||||
bool right = Functions.GetKeyState(VirtualKeys.RBUTTON) != 0;
|
||||
bool middle = Functions.GetKeyState(VirtualKeys.MBUTTON) != 0;
|
||||
bool x1 = Functions.GetKeyState(VirtualKeys.XBUTTON1) != 0;
|
||||
bool x2 = Functions.GetKeyState(VirtualKeys.XBUTTON2) != 0;
|
||||
|
||||
state.X = p.X;
|
||||
state.Y = p.Y;
|
||||
state[MouseButton.Left] = left;
|
||||
state[MouseButton.Right] = right;
|
||||
state[MouseButton.Middle] = middle;
|
||||
state[MouseButton.Button1] = x1;
|
||||
state[MouseButton.Button2] = x2;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
127
Source/OpenTK/Platform/X11/Bindings/XI.cs
Normal file
127
Source/OpenTK/Platform/X11/Bindings/XI.cs
Normal file
|
@ -0,0 +1,127 @@
|
|||
#region License
|
||||
//
|
||||
// The Open Toolkit Library License
|
||||
//
|
||||
// Copyright (c) 2006 - 2014 Stefanos Apostolopoulos for 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.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenTK.Platform.X11
|
||||
{
|
||||
using Bool = Boolean;
|
||||
using Cursor = IntPtr;
|
||||
using Display = IntPtr;
|
||||
using Status = ErrorCodes;
|
||||
using Time = IntPtr;
|
||||
using Window = IntPtr;
|
||||
|
||||
// Bindings for the XInput2 extension
|
||||
class XI
|
||||
{
|
||||
const string lib = "libXi";
|
||||
|
||||
// mouse
|
||||
internal static readonly IntPtr ButtonLeft = Functions.XInternAtom(API.DefaultDisplay, "Button Left", false);
|
||||
internal static readonly IntPtr ButtonMiddle = Functions.XInternAtom(API.DefaultDisplay, "Button Middle", false);
|
||||
internal static readonly IntPtr ButtonRight = Functions.XInternAtom(API.DefaultDisplay, "Button Right", false);
|
||||
internal static readonly IntPtr ButtonWheelUp = Functions.XInternAtom(API.DefaultDisplay, "Button Wheel Up", false);
|
||||
internal static readonly IntPtr ButtonWheelDown = Functions.XInternAtom(API.DefaultDisplay, "Button Wheel Down", false);
|
||||
internal static readonly IntPtr ButtonWheelLeft = Functions.XInternAtom(API.DefaultDisplay, "Button Horiz Wheel Left", false);
|
||||
internal static readonly IntPtr ButtonWheelRight = Functions.XInternAtom(API.DefaultDisplay, "Button Horiz Wheel Right", false);
|
||||
internal static readonly IntPtr RelativeX = Functions.XInternAtom(API.DefaultDisplay, "Rel X", false);
|
||||
internal static readonly IntPtr RelativeY = Functions.XInternAtom(API.DefaultDisplay, "Rel Y", false);
|
||||
internal static readonly IntPtr RelativeHWheel = Functions.XInternAtom(API.DefaultDisplay, "Rel Horiz Wheel", false);
|
||||
internal static readonly IntPtr RelativeVWheel = Functions.XInternAtom(API.DefaultDisplay, "Rel Vert Wheel", false);
|
||||
internal static readonly IntPtr RelativeHScroll = Functions.XInternAtom(API.DefaultDisplay, "Rel Horiz Scroll", false);
|
||||
internal static readonly IntPtr RelativeVScroll = Functions.XInternAtom(API.DefaultDisplay, "Rel Vert Scroll", false);
|
||||
|
||||
// multitouch
|
||||
internal static readonly IntPtr TouchX = Functions.XInternAtom(API.DefaultDisplay, "Abs MT Position X", false);
|
||||
internal static readonly IntPtr TouchY = Functions.XInternAtom(API.DefaultDisplay, "Abs MT Position Y", false);
|
||||
internal static readonly IntPtr TouchMajor = Functions.XInternAtom(API.DefaultDisplay, "Abs MT Touch Major", false);
|
||||
internal static readonly IntPtr TouchMinor = Functions.XInternAtom(API.DefaultDisplay, "Abs MT Touch Minor", false);
|
||||
internal static readonly IntPtr TouchPressure = Functions.XInternAtom(API.DefaultDisplay, "Abs MT Pressure", false);
|
||||
internal static readonly IntPtr TouchId = Functions.XInternAtom(API.DefaultDisplay, "Abs MT Tracking ID", false);
|
||||
internal static readonly IntPtr TouchMaxContacts = Functions.XInternAtom(API.DefaultDisplay, "Max Contacts", false);
|
||||
|
||||
// tablet
|
||||
internal static readonly IntPtr AbsoluteX = Functions.XInternAtom(API.DefaultDisplay, "Abs X", false);
|
||||
internal static readonly IntPtr AbsoluteY = Functions.XInternAtom(API.DefaultDisplay, "Abs Y", false);
|
||||
internal static readonly IntPtr AbsolutePressure = Functions.XInternAtom(API.DefaultDisplay, "Abs Pressure", false);
|
||||
internal static readonly IntPtr AbsoluteTiltX = Functions.XInternAtom(API.DefaultDisplay, "Abs Tilt X", false);
|
||||
internal static readonly IntPtr AbsoluteTiltY = Functions.XInternAtom(API.DefaultDisplay, "Abs Tilt Y", false);
|
||||
internal static readonly IntPtr AbsoluteWheel = Functions.XInternAtom(API.DefaultDisplay, "Abs Wheel", false);
|
||||
internal static readonly IntPtr AbsoluteDistance = Functions.XInternAtom(API.DefaultDisplay, "Abs Distance", false);
|
||||
|
||||
[DllImport(lib, EntryPoint = "XISelectEvents")]
|
||||
static extern int SelectEvents(IntPtr dpy, Window win, [In] XIEventMask[] masks, int num_masks);
|
||||
|
||||
[DllImport(lib, EntryPoint = "XISelectEvents")]
|
||||
static extern int SelectEvents(IntPtr dpy, Window win, [In] ref XIEventMask masks, int num_masks);
|
||||
|
||||
public static int SelectEvents(IntPtr dpy, Window win, XIEventMask[] masks)
|
||||
{
|
||||
return SelectEvents(dpy, win, masks, masks.Length);
|
||||
}
|
||||
|
||||
public static int SelectEvents(IntPtr dpy, Window win, XIEventMask mask)
|
||||
{
|
||||
return SelectEvents(dpy, win, ref mask, 1);
|
||||
}
|
||||
|
||||
[DllImport(lib, EntryPoint = "XIGrabDevice")]
|
||||
static extern Status GrabDevice(IntPtr display, int deviceid, Window grab_window, Time time,
|
||||
Cursor cursor, int grab_mode, int paired_device_mode, Bool owner_events, XIEventMask[] mask);
|
||||
|
||||
[DllImport(lib, EntryPoint = "XIUngrabDevice")]
|
||||
static extern Status UngrabDevice(IntPtr display, int deviceid, Time time);
|
||||
|
||||
[DllImport(lib, EntryPoint = "XIWarpPointer")]
|
||||
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);
|
||||
|
||||
[DllImport(lib, EntryPoint = "XIQueryDevice")]
|
||||
public static extern IntPtr QueryDevice(Display display, int id, out int count);
|
||||
|
||||
[DllImport(lib, EntryPoint = "XIFreeDeviceInfo")]
|
||||
public static extern void FreeDeviceInfo(IntPtr devices);
|
||||
|
||||
[DllImport(lib, EntryPoint = "XIQueryPointer")]
|
||||
public static extern Bool QueryPointer(Display display,
|
||||
int deviceid, Window win,
|
||||
out Window root_return, out Window child_return,
|
||||
out double root_x_return, out double root_y_return,
|
||||
out double win_x_return, out double win_y_return,
|
||||
out XIButtonState buttons_return, out XIModifierState modifiers_return,
|
||||
out XIGroupState group_return);
|
||||
|
||||
[DllImport(lib, EntryPoint = "XIQueryVersion")]
|
||||
internal static extern Status QueryVersion(Display display, ref int major, ref int minor);
|
||||
}
|
||||
}
|
|
@ -516,34 +516,6 @@ namespace OpenTK.Platform.X11
|
|||
[DllImport("libX11")]
|
||||
public static extern void XSetClassHint(IntPtr display, IntPtr window, ref XClassHint hint);
|
||||
|
||||
[DllImport("libXi")]
|
||||
static extern int XISelectEvents(IntPtr dpy, Window win, [In] XIEventMask[] masks, int num_masks);
|
||||
[DllImport("libXi")]
|
||||
static extern int XISelectEvents(IntPtr dpy, Window win, [In] ref XIEventMask masks, int num_masks);
|
||||
|
||||
public static int XISelectEvents(IntPtr dpy, Window win, XIEventMask[] masks)
|
||||
{
|
||||
return XISelectEvents(dpy, win, masks, masks.Length);
|
||||
}
|
||||
|
||||
public static int XISelectEvents(IntPtr dpy, Window win, XIEventMask mask)
|
||||
{
|
||||
return XISelectEvents(dpy, win, ref mask, 1);
|
||||
}
|
||||
|
||||
[DllImport("libXi")]
|
||||
static extern Status XIGrabDevice(IntPtr display, int deviceid, Window grab_window, Time time,
|
||||
Cursor cursor, int grab_mode, int paired_device_mode, Bool owner_events, XIEventMask[] mask);
|
||||
|
||||
[DllImport("libXi")]
|
||||
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;
|
||||
|
||||
public static void SendNetWMMessage(X11WindowInfo window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
|
||||
|
|
|
@ -1671,6 +1671,13 @@ namespace OpenTK.Platform.X11
|
|||
|
||||
// XInput2 structures
|
||||
|
||||
enum XIClassType
|
||||
{
|
||||
Button = 1,
|
||||
Valuator = 2,
|
||||
Scroll = 3,
|
||||
}
|
||||
|
||||
struct XIDeviceInfo
|
||||
{
|
||||
public int deviceid;
|
||||
|
@ -1684,10 +1691,33 @@ namespace OpenTK.Platform.X11
|
|||
|
||||
struct XIAnyClassInfo
|
||||
{
|
||||
public int type;
|
||||
public XIClassType type;
|
||||
public int sourceid;
|
||||
}
|
||||
|
||||
struct XIButtonClassInfo
|
||||
{
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct XIValuatorClassInfo
|
||||
{
|
||||
public Atom label;
|
||||
public double max;
|
||||
public double min;
|
||||
public int mode;
|
||||
public int number;
|
||||
public int resolution;
|
||||
public int sourceid;
|
||||
public int type;
|
||||
public double value;
|
||||
}
|
||||
|
||||
struct XIScrollClassInfo
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
struct XIDeviceEvent
|
||||
{
|
||||
public int type; /* GenericEvent */
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace OpenTK.Platform.X11
|
|||
readonly IntPtr display;
|
||||
readonly IntPtr root_window;
|
||||
MouseState mouse = new MouseState();
|
||||
MouseState cursor = new MouseState();
|
||||
|
||||
// When the mouse warps, "detach" the current location
|
||||
// from the pointer.
|
||||
|
@ -58,6 +59,7 @@ namespace OpenTK.Platform.X11
|
|||
{
|
||||
Debug.WriteLine("Using X11Mouse.");
|
||||
mouse.IsConnected = true;
|
||||
cursor.IsConnected = true;
|
||||
display = API.DefaultDisplay;
|
||||
root_window = Functions.XRootWindow(display, Functions.XDefaultScreen(display));
|
||||
}
|
||||
|
@ -78,6 +80,12 @@ namespace OpenTK.Platform.X11
|
|||
return new MouseState();
|
||||
}
|
||||
|
||||
public MouseState GetCursorState()
|
||||
{
|
||||
ProcessEvents();
|
||||
return cursor;
|
||||
}
|
||||
|
||||
public void SetPosition(double x, double y)
|
||||
{
|
||||
// Update the current location, otherwise the pointer
|
||||
|
@ -97,14 +105,6 @@ namespace OpenTK.Platform.X11
|
|||
}
|
||||
}
|
||||
|
||||
void WriteBit(MouseButton offset, int enabled)
|
||||
{
|
||||
if (enabled != 0)
|
||||
mouse.EnableBit((int)offset);
|
||||
else
|
||||
mouse.DisableBit((int)offset);
|
||||
}
|
||||
|
||||
void ProcessEvents()
|
||||
{
|
||||
IntPtr root, child;
|
||||
|
@ -117,6 +117,9 @@ namespace OpenTK.Platform.X11
|
|||
Functions.XQueryPointer(display, window, out root, out child,
|
||||
out root_x, out root_y, out win_x, out win_y, out buttons);
|
||||
|
||||
cursor.X = root_x;
|
||||
cursor.Y = root_y;
|
||||
|
||||
if (!mouse_detached)
|
||||
{
|
||||
mouse.X = root_x;
|
||||
|
@ -129,9 +132,9 @@ namespace OpenTK.Platform.X11
|
|||
mouse_detached_x = root_x;
|
||||
mouse_detached_y = root_y;
|
||||
}
|
||||
WriteBit(MouseButton.Left, buttons & (int)MouseMask.Button1Mask);
|
||||
WriteBit(MouseButton.Middle, buttons & (int)MouseMask.Button2Mask);
|
||||
WriteBit(MouseButton.Right, buttons & (int)MouseMask.Button3Mask);
|
||||
cursor[MouseButton.Left] = mouse[MouseButton.Left] = (buttons & (int)MouseMask.Button1Mask) != 0;
|
||||
cursor[MouseButton.Middle] = mouse[MouseButton.Middle] = (buttons & (int)MouseMask.Button2Mask) != 0;
|
||||
cursor[MouseButton.Right] = mouse[MouseButton.Right] = (buttons & (int)MouseMask.Button3Mask) != 0;
|
||||
// Note: this will never work right, wheel events have a duration of 0
|
||||
// (yes, zero). They are impposible to catch via polling.
|
||||
// After spending a week on this, I simply don't care anymore.
|
||||
|
@ -142,9 +145,9 @@ namespace OpenTK.Platform.X11
|
|||
// mouse.WheelPrecise++;
|
||||
//if ((buttons & (int)MouseMask.Button5Mask) != 0)
|
||||
// mouse.WheelPrecise--;
|
||||
WriteBit(MouseButton.Button1, buttons & (int)MouseMask.Button6Mask);
|
||||
WriteBit(MouseButton.Button2, buttons & (int)MouseMask.Button7Mask);
|
||||
WriteBit(MouseButton.Button3, buttons & (int)MouseMask.Button8Mask);
|
||||
cursor[MouseButton.Button1] = mouse[MouseButton.Button1] = (buttons & (int)MouseMask.Button6Mask) != 0;
|
||||
cursor[MouseButton.Button2] = mouse[MouseButton.Button2] = (buttons & (int)MouseMask.Button7Mask) != 0;
|
||||
cursor[MouseButton.Button3] = mouse[MouseButton.Button3] = (buttons & (int)MouseMask.Button8Mask) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,15 @@ namespace OpenTK.Platform.X11
|
|||
// This should be easy: just read the device id and route the data to the correct device.
|
||||
sealed class XI2Mouse : IMouseDriver2
|
||||
{
|
||||
List<MouseState> mice = new List<MouseState>();
|
||||
Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps raw ids to mouse ids
|
||||
class XIMouse
|
||||
{
|
||||
public MouseState State;
|
||||
public XIDeviceInfo Info;
|
||||
}
|
||||
XIMouse master; // XIMouse for the mouse cursor
|
||||
List<XIMouse> devices = new List<XIMouse>(); // List of connected mice
|
||||
Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps hardware device ids to XIMouse ids
|
||||
|
||||
internal readonly X11WindowInfo window;
|
||||
internal static int XIOpCode { get; private set; }
|
||||
static bool supported;
|
||||
|
@ -72,12 +79,20 @@ namespace OpenTK.Platform.X11
|
|||
if (!IsSupported(window.Display))
|
||||
throw new NotSupportedException("XInput2 not supported.");
|
||||
|
||||
using (XIEventMask mask = new XIEventMask(1, XIEventMasks.RawButtonPressMask |
|
||||
XIEventMasks.RawButtonReleaseMask | XIEventMasks.RawMotionMask))
|
||||
using (new XLock(API.DefaultDisplay))
|
||||
using (XIEventMask mask = new XIEventMask(1,
|
||||
XIEventMasks.RawButtonPressMask |
|
||||
XIEventMasks.RawButtonReleaseMask |
|
||||
XIEventMasks.RawMotionMask |
|
||||
XIEventMasks.MotionMask |
|
||||
XIEventMasks.ButtonPressMask |
|
||||
XIEventMasks.ButtonReleaseMask |
|
||||
XIEventMasks.DeviceChangedMask))
|
||||
{
|
||||
Functions.XISelectEvents(window.Display, window.Handle, mask);
|
||||
Functions.XISelectEvents(window.Display, window.RootWindow, mask);
|
||||
XI.SelectEvents(window.Display, window.Handle, mask);
|
||||
}
|
||||
|
||||
UpdateDevices();
|
||||
}
|
||||
|
||||
// Checks whether XInput2 is supported on the specified display.
|
||||
|
@ -90,14 +105,51 @@ namespace OpenTK.Platform.X11
|
|||
using (new XLock(display))
|
||||
{
|
||||
int major, ev, error;
|
||||
if (Functions.XQueryExtension(display, "XInputExtension", out major, out ev, out error) == 0)
|
||||
if (Functions.XQueryExtension(display, "XInputExtension", out major, out ev, out error) != 0)
|
||||
{
|
||||
return false;
|
||||
XIOpCode = major;
|
||||
|
||||
int minor = 2;
|
||||
while (minor >= 0)
|
||||
{
|
||||
if (XI.QueryVersion(display, ref major, ref minor) == ErrorCodes.Success)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
minor--;
|
||||
}
|
||||
}
|
||||
XIOpCode = major;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void UpdateDevices()
|
||||
{
|
||||
int count;
|
||||
unsafe
|
||||
{
|
||||
XIDeviceInfo* list = (XIDeviceInfo*)XI.QueryDevice(window.Display, 1, out count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (devices.Count < i)
|
||||
{
|
||||
devices.Add(new XIMouse());
|
||||
}
|
||||
XIMouse d = devices[i];
|
||||
d.State.SetIsConnected(true);
|
||||
d.Info = *(list + i);
|
||||
|
||||
// Map the hardware device id to the current XIMouse id
|
||||
if (!rawids.ContainsKey(d.Info.deviceid))
|
||||
{
|
||||
rawids.Add(d.Info.deviceid, 0);
|
||||
}
|
||||
rawids[d.Info.deviceid] = i;
|
||||
}
|
||||
XI.FreeDeviceInfo((IntPtr)list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#region IMouseDriver2 Members
|
||||
|
@ -106,9 +158,9 @@ namespace OpenTK.Platform.X11
|
|||
{
|
||||
ProcessEvents();
|
||||
MouseState master = new MouseState();
|
||||
foreach (MouseState ms in mice)
|
||||
foreach (var d in devices)
|
||||
{
|
||||
master.MergeBits(ms);
|
||||
master.MergeBits(d.State);
|
||||
}
|
||||
return master;
|
||||
}
|
||||
|
@ -116,12 +168,17 @@ namespace OpenTK.Platform.X11
|
|||
public MouseState GetState(int index)
|
||||
{
|
||||
ProcessEvents();
|
||||
if (mice.Count > index)
|
||||
return mice[index];
|
||||
if (devices.Count > index)
|
||||
return devices[index].State;
|
||||
else
|
||||
return new MouseState();
|
||||
}
|
||||
|
||||
public MouseState GetCursorState()
|
||||
{
|
||||
return master.State;
|
||||
}
|
||||
|
||||
public void SetPosition(double x, double y)
|
||||
{
|
||||
using (new XLock(window.Display))
|
||||
|
@ -169,79 +226,133 @@ namespace OpenTK.Platform.X11
|
|||
cookie = e.GenericEventCookie;
|
||||
if (Functions.XGetEventData(window.Display, ref cookie) != 0)
|
||||
{
|
||||
XIRawEvent raw = (XIRawEvent)
|
||||
Marshal.PtrToStructure(cookie.data, typeof(XIRawEvent));
|
||||
|
||||
if (!rawids.ContainsKey(raw.deviceid))
|
||||
{
|
||||
mice.Add(new MouseState());
|
||||
rawids.Add(raw.deviceid, mice.Count - 1);
|
||||
}
|
||||
MouseState state = mice[rawids[raw.deviceid]];
|
||||
|
||||
switch (raw.evtype)
|
||||
switch ((XIEventType)cookie.evtype)
|
||||
{
|
||||
case XIEventType.RawMotion:
|
||||
double x = 0, y = 0;
|
||||
if (IsBitSet(raw.valuators.mask, 0))
|
||||
{
|
||||
x = BitConverter.Int64BitsToDouble(Marshal.ReadInt64(raw.raw_values, 0));
|
||||
}
|
||||
if (IsBitSet(raw.valuators.mask, 1))
|
||||
{
|
||||
y = BitConverter.Int64BitsToDouble(Marshal.ReadInt64(raw.raw_values, 8));
|
||||
}
|
||||
|
||||
if (!CheckMouseWarp(x, y))
|
||||
{
|
||||
state.X += (int)x;
|
||||
state.Y += (int)y;
|
||||
}
|
||||
break;
|
||||
|
||||
case XIEventType.RawButtonPress:
|
||||
switch (raw.detail)
|
||||
{
|
||||
case 1: state.EnableBit((int)MouseButton.Left); break;
|
||||
case 2: state.EnableBit((int)MouseButton.Middle); break;
|
||||
case 3: state.EnableBit((int)MouseButton.Right); break;
|
||||
case 4: state.SetScrollRelative(0, 1); break;
|
||||
case 5: state.SetScrollRelative(0, -1); break;
|
||||
case 6: state.EnableBit((int)MouseButton.Button1); break;
|
||||
case 7: state.EnableBit((int)MouseButton.Button2); break;
|
||||
case 8: state.EnableBit((int)MouseButton.Button3); break;
|
||||
case 9: state.EnableBit((int)MouseButton.Button4); break;
|
||||
case 10: state.EnableBit((int)MouseButton.Button5); break;
|
||||
case 11: state.EnableBit((int)MouseButton.Button6); break;
|
||||
case 12: state.EnableBit((int)MouseButton.Button7); break;
|
||||
case 13: state.EnableBit((int)MouseButton.Button8); break;
|
||||
case 14: state.EnableBit((int)MouseButton.Button9); break;
|
||||
}
|
||||
case XIEventType.RawButtonRelease:
|
||||
// Delivered to all XIMouse instances
|
||||
ProcessRawEvent(ref cookie);
|
||||
break;
|
||||
|
||||
case XIEventType.RawButtonRelease:
|
||||
switch (raw.detail)
|
||||
{
|
||||
case 1: state.DisableBit((int)MouseButton.Left); break;
|
||||
case 2: state.DisableBit((int)MouseButton.Middle); break;
|
||||
case 3: state.DisableBit((int)MouseButton.Right); break;
|
||||
case 6: state.DisableBit((int)MouseButton.Button1); break;
|
||||
case 7: state.DisableBit((int)MouseButton.Button2); break;
|
||||
case 8: state.DisableBit((int)MouseButton.Button3); break;
|
||||
case 9: state.DisableBit((int)MouseButton.Button4); break;
|
||||
case 10: state.DisableBit((int)MouseButton.Button5); break;
|
||||
case 11: state.DisableBit((int)MouseButton.Button6); break;
|
||||
case 12: state.DisableBit((int)MouseButton.Button7); break;
|
||||
case 13: state.DisableBit((int)MouseButton.Button8); break;
|
||||
case 14: state.DisableBit((int)MouseButton.Button9); break;
|
||||
}
|
||||
case XIEventType.Motion:
|
||||
case XIEventType.ButtonPress:
|
||||
case XIEventType.ButtonRelease:
|
||||
// Delivered only to the actual mouse cursor XIMouse instance
|
||||
ProcessEvent(ref cookie);
|
||||
break;
|
||||
|
||||
case XIEventType.DeviceChanged:
|
||||
UpdateDevices();
|
||||
break;
|
||||
}
|
||||
mice[rawids[raw.deviceid]] = state;
|
||||
}
|
||||
Functions.XFreeEventData(window.Display, ref cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessEvent(ref XGenericEventCookie cookie)
|
||||
{
|
||||
XIDeviceEvent e = (XIDeviceEvent)
|
||||
Marshal.PtrToStructure(cookie.data, typeof(XIDeviceEvent));
|
||||
|
||||
master.State.SetIsConnected(true);
|
||||
master.State.X = (int)Math.Round(e.root_x);
|
||||
master.State.Y = (int)Math.Round(e.root_y);
|
||||
|
||||
}
|
||||
|
||||
void ProcessRawEvent(ref XGenericEventCookie cookie)
|
||||
{
|
||||
XIRawEvent raw = (XIRawEvent)
|
||||
Marshal.PtrToStructure(cookie.data, typeof(XIRawEvent));
|
||||
|
||||
if (!rawids.ContainsKey(raw.deviceid))
|
||||
{
|
||||
Debug.Print("Unknown mouse device {0} encountered, ignoring.", raw.deviceid);
|
||||
return;
|
||||
}
|
||||
|
||||
var d = devices[rawids[raw.deviceid]];
|
||||
|
||||
switch (raw.evtype)
|
||||
{
|
||||
case XIEventType.RawMotion:
|
||||
double x = 0, y = 0;
|
||||
double h = 0, v = 0;
|
||||
for (int i = 0; i < d.Info.num_classes; i++)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
XIAnyClassInfo* info = (XIAnyClassInfo*)d.Info.classes + i;
|
||||
switch (info->type)
|
||||
{
|
||||
case XIClassType.Valuator:
|
||||
{
|
||||
XIValuatorClassInfo* n = (XIValuatorClassInfo*)info;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsBitSet(raw.valuators.mask, 0))
|
||||
{
|
||||
x = BitConverter.Int64BitsToDouble(Marshal.ReadInt64(raw.raw_values, 0));
|
||||
}
|
||||
if (IsBitSet(raw.valuators.mask, 1))
|
||||
{
|
||||
y = BitConverter.Int64BitsToDouble(Marshal.ReadInt64(raw.raw_values, 8));
|
||||
}
|
||||
break;
|
||||
/*
|
||||
if (!CheckMouseWarp(x, y))
|
||||
{
|
||||
state.X += (int)x;
|
||||
state.Y += (int)y;
|
||||
}
|
||||
break;
|
||||
|
||||
case XIEventType.RawButtonPress:
|
||||
switch (raw.detail)
|
||||
{
|
||||
case 1: state.EnableBit((int)MouseButton.Left); break;
|
||||
case 2: state.EnableBit((int)MouseButton.Middle); break;
|
||||
case 3: state.EnableBit((int)MouseButton.Right); break;
|
||||
case 4: state.SetScrollRelative(0, 1); break;
|
||||
case 5: state.SetScrollRelative(0, -1); break;
|
||||
case 6: state.EnableBit((int)MouseButton.Button1); break;
|
||||
case 7: state.EnableBit((int)MouseButton.Button2); break;
|
||||
case 8: state.EnableBit((int)MouseButton.Button3); break;
|
||||
case 9: state.EnableBit((int)MouseButton.Button4); break;
|
||||
case 10: state.EnableBit((int)MouseButton.Button5); break;
|
||||
case 11: state.EnableBit((int)MouseButton.Button6); break;
|
||||
case 12: state.EnableBit((int)MouseButton.Button7); break;
|
||||
case 13: state.EnableBit((int)MouseButton.Button8); break;
|
||||
case 14: state.EnableBit((int)MouseButton.Button9); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case XIEventType.RawButtonRelease:
|
||||
switch (raw.detail)
|
||||
{
|
||||
case 1: state.DisableBit((int)MouseButton.Left); break;
|
||||
case 2: state.DisableBit((int)MouseButton.Middle); break;
|
||||
case 3: state.DisableBit((int)MouseButton.Right); break;
|
||||
case 6: state.DisableBit((int)MouseButton.Button1); break;
|
||||
case 7: state.DisableBit((int)MouseButton.Button2); break;
|
||||
case 8: state.DisableBit((int)MouseButton.Button3); break;
|
||||
case 9: state.DisableBit((int)MouseButton.Button4); break;
|
||||
case 10: state.DisableBit((int)MouseButton.Button5); break;
|
||||
case 11: state.DisableBit((int)MouseButton.Button6); break;
|
||||
case 12: state.DisableBit((int)MouseButton.Button7); break;
|
||||
case 13: state.DisableBit((int)MouseButton.Button8); break;
|
||||
case 14: state.DisableBit((int)MouseButton.Button9); break;
|
||||
}
|
||||
break;*/
|
||||
}
|
||||
//mice[rawids[raw.deviceid]] = state;
|
||||
}
|
||||
|
||||
static bool IsEventValid(IntPtr display, ref XEvent e, IntPtr arg)
|
||||
|
@ -249,7 +360,10 @@ namespace OpenTK.Platform.X11
|
|||
return e.GenericEventCookie.extension == arg.ToInt32() &&
|
||||
(e.GenericEventCookie.evtype == (int)XIEventType.RawMotion ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.RawButtonPress ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.RawButtonRelease);
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.RawButtonRelease ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.Motion ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.ButtonPress ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.ButtonRelease);
|
||||
}
|
||||
|
||||
static bool IsBitSet(IntPtr mask, int bit)
|
||||
|
|
Loading…
Reference in a new issue