mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-23 18:55:50 +00:00
* OpenTK.csproj:
* Input/MouseState.cs: * Platform/X11/Structs.cs: * Platform/X11/XI2Mouse.cs: * Platform/X11/Functions.cs: * Platform/X11/X11Factory.cs: Added XInput2 driver for mice. Multi-mouse support pending. * Platform/X11/X11Mouse.cs: Log the driver type for debugging purposes.
This commit is contained in:
parent
23ad81d12b
commit
80ee257777
|
@ -207,6 +207,44 @@ namespace OpenTK.Input
|
|||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares to an object instance for equality.
|
||||
/// </summary>
|
||||
/// <param name="obj">
|
||||
/// The <see cref="System.Object"/> to compare to.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if this instance is equal to obj; false otherwise.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is MouseState)
|
||||
{
|
||||
return this == (MouseState)obj;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hashcode for the current instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.Int32"/> represting the hashcode for this instance.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
fixed (int* b = Buttons)
|
||||
{
|
||||
return b->GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode() ^ WheelPrecise.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Members
|
||||
|
|
|
@ -762,6 +762,7 @@
|
|||
<Compile Include="Platform\X11\X11Keyboard.cs" />
|
||||
<Compile Include="Platform\X11\X11Mouse.cs" />
|
||||
<Compile Include="Input\ButtonState.cs" />
|
||||
<Compile Include="Platform\X11\XI2Mouse.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
|
|
|
@ -94,6 +94,15 @@ namespace OpenTK.Platform.X11
|
|||
public extern static Bool XCheckWindowEvent(Display display, Window w, EventMask event_mask, ref XEvent event_return);
|
||||
[DllImport("libX11")]
|
||||
public extern static Bool XCheckTypedWindowEvent(Display display, Window w, XEventName event_type, ref XEvent event_return);
|
||||
[DllImport("libX11")]
|
||||
public extern static Bool XCheckTypedEvent(Display display, XEventName event_type, out XEvent event_return);
|
||||
|
||||
|
||||
public delegate Bool EventPredicate(IntPtr display, ref XEvent e, IntPtr arg);
|
||||
[DllImport("libX11")]
|
||||
public extern static Bool XIfEvent(Display display, ref XEvent e, IntPtr predicate, IntPtr arg );
|
||||
[DllImport("libX11")]
|
||||
public extern static Bool XCheckIfEvent(Display display, ref XEvent e, IntPtr predicate, IntPtr arg );
|
||||
|
||||
[DllImport("libX11")]
|
||||
public extern static int XConnectionNumber(IntPtr diplay);
|
||||
|
@ -325,7 +334,7 @@ namespace OpenTK.Platform.X11
|
|||
public extern static int XQueryBestCursor(IntPtr display, IntPtr drawable, int width, int height, out int best_width, out int best_height);
|
||||
|
||||
[DllImport("libX11", EntryPoint = "XQueryExtension")]
|
||||
public extern static int XQueryExtension(IntPtr display, string extension_name, ref int major, ref int first_event, ref int first_error);
|
||||
public extern static int XQueryExtension(IntPtr display, string extension_name, out int major, out int first_event, out int first_error);
|
||||
|
||||
[DllImport("libX11", EntryPoint = "XWhitePixel")]
|
||||
public extern static IntPtr XWhitePixel(IntPtr display, int screen_no);
|
||||
|
@ -462,6 +471,27 @@ namespace OpenTK.Platform.X11
|
|||
[DllImport("libX11")]
|
||||
public static extern int XRefreshKeyboardMapping(ref XMappingEvent event_map);
|
||||
|
||||
[DllImport("libX11")]
|
||||
public static extern int XGetEventData(IntPtr display, ref XGenericEventCookie cookie);
|
||||
|
||||
[DllImport("libX11")]
|
||||
public static extern void XFreeEventData(IntPtr display, ref XGenericEventCookie cookie);
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
static readonly IntPtr CopyFromParent = IntPtr.Zero;
|
||||
|
||||
public static void SendNetWMMessage(X11WindowInfo window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
|
||||
|
|
|
@ -36,6 +36,10 @@ using System.Runtime.InteropServices;
|
|||
// X11 Version
|
||||
namespace OpenTK.Platform.X11
|
||||
{
|
||||
using Bool = System.Boolean;
|
||||
using Time = System.IntPtr;
|
||||
using Window = System.IntPtr;
|
||||
|
||||
//
|
||||
// In the structures below, fields of type long are mapped to IntPtr.
|
||||
// This will work on all platforms where sizeof(long)==sizeof(void*), which
|
||||
|
@ -545,6 +549,29 @@ namespace OpenTK.Platform.X11
|
|||
public IntPtr pad23;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct XGenericEvent
|
||||
{
|
||||
public int type; // of event. Always GenericEvent
|
||||
public IntPtr serial; // # of last request processed
|
||||
public bool send_event; // true if from SendEvent request
|
||||
public IntPtr display; // Display the event was read from
|
||||
public int extension; // major opcode of extension that caused the event
|
||||
public int evtype; // actual event type.
|
||||
}
|
||||
|
||||
internal struct XGenericEventCookie
|
||||
{
|
||||
public int type; // of event. Always GenericEvent
|
||||
public IntPtr serial; // # of last request processed
|
||||
public bool send_event; // true if from SendEvent request
|
||||
public IntPtr display; // Display the event was read from
|
||||
public int extension; // major opcode of extension that caused the event
|
||||
public int evtype; // actual event type.
|
||||
public uint cookie; // unique event cookie
|
||||
public IntPtr data; // actual event data
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
internal struct XEvent
|
||||
{
|
||||
|
@ -612,6 +639,10 @@ namespace OpenTK.Platform.X11
|
|||
public XErrorEvent ErrorEvent;
|
||||
[FieldOffset(0)]
|
||||
public XKeymapEvent KeymapEvent;
|
||||
[FieldOffset(0)]
|
||||
public XGenericEvent GenericEvent;
|
||||
[FieldOffset(0)]
|
||||
public XGenericEventCookie GenericEventCookie;
|
||||
|
||||
//[MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=24)]
|
||||
//[ FieldOffset(0) ] public int[] pad;
|
||||
|
@ -753,6 +784,7 @@ namespace OpenTK.Platform.X11
|
|||
ColormapNotify = 32,
|
||||
ClientMessage = 33,
|
||||
MappingNotify = 34,
|
||||
GenericEvent = 35,
|
||||
|
||||
LASTEvent
|
||||
}
|
||||
|
@ -1623,4 +1655,164 @@ namespace OpenTK.Platform.X11
|
|||
XYPixmap = 1,
|
||||
ZPixmap
|
||||
}
|
||||
|
||||
// XInput2 structures
|
||||
|
||||
struct XIDeviceInfo
|
||||
{
|
||||
public int deviceid;
|
||||
public IntPtr name; // byte*
|
||||
public int use;
|
||||
public int attachment;
|
||||
public Bool enabled;
|
||||
public int num_classes;
|
||||
public IntPtr classes; // XIAnyClassInfo **
|
||||
}
|
||||
|
||||
struct XIAnyClassInfo
|
||||
{
|
||||
public int type;
|
||||
public int sourceid;
|
||||
}
|
||||
|
||||
struct XIDeviceEvent
|
||||
{
|
||||
public int type; /* GenericEvent */
|
||||
public IntPtr serial; /* # of last request processed by server */
|
||||
public bool send_event; /* true if this came from a SendEvent request */
|
||||
public IntPtr display; /* Display the event was read from */
|
||||
public int extension; /* XI extension offset */
|
||||
public XIEventType evtype;
|
||||
public Time time;
|
||||
public int deviceid;
|
||||
public int sourceid;
|
||||
public int detail;
|
||||
public Window root;
|
||||
public Window @event;
|
||||
public Window child;
|
||||
public double root_x;
|
||||
public double root_y;
|
||||
public double event_x;
|
||||
public double event_y;
|
||||
public int flags;
|
||||
public XIButtonState buttons;
|
||||
public XIValuatorState valuators;
|
||||
public XIModifierState mods;
|
||||
public XIGroupState @group;
|
||||
}
|
||||
|
||||
struct XIRawEvent
|
||||
{
|
||||
public int type; /* GenericEvent */
|
||||
public IntPtr serial; /* # of last request processed by server */
|
||||
public Bool send_event; /* true if this came from a SendEvent request */
|
||||
public IntPtr display; /* Display the event was read from */
|
||||
public int extension; /* XI extension offset */
|
||||
public XIEventType evtype; /* XI_RawKeyPress, XI_RawKeyRelease, etc. */
|
||||
public Time time;
|
||||
public int deviceid;
|
||||
public int sourceid;
|
||||
public int detail;
|
||||
public int flags;
|
||||
public XIValuatorState valuators;
|
||||
public IntPtr raw_values; // double *
|
||||
}
|
||||
|
||||
struct XIButtonState
|
||||
{
|
||||
public int mask_len;
|
||||
public IntPtr mask; // byte*
|
||||
}
|
||||
|
||||
struct XIModifierState
|
||||
{
|
||||
public int @base;
|
||||
public int latched;
|
||||
public int locked;
|
||||
public int effective;
|
||||
}
|
||||
|
||||
struct XIGroupState
|
||||
{
|
||||
public int @base;
|
||||
public int latched;
|
||||
public int locked;
|
||||
public int effective;
|
||||
}
|
||||
|
||||
struct XIValuatorState
|
||||
{
|
||||
public int mask_len;
|
||||
public IntPtr mask; // byte*
|
||||
public IntPtr values; // double*
|
||||
}
|
||||
|
||||
struct XIEventMask : IDisposable
|
||||
{
|
||||
public int deviceid; // 0 = XIAllDevices, 1 = XIAllMasterDevices
|
||||
int mask_len;
|
||||
unsafe XIEventMasks* mask;
|
||||
|
||||
public XIEventMask(int id, XIEventMasks m)
|
||||
{
|
||||
deviceid = id;
|
||||
mask_len = sizeof(XIEventMasks);
|
||||
unsafe
|
||||
{
|
||||
mask = (XIEventMasks*)Marshal.AllocHGlobal(mask_len);
|
||||
*mask = m;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
Marshal.FreeHGlobal(new IntPtr((void*)mask));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum XIEventType
|
||||
{
|
||||
DeviceChanged = 1,
|
||||
KeyPress,
|
||||
KeyRelease,
|
||||
ButtonPress,
|
||||
ButtonRelease,
|
||||
Motion,
|
||||
Enter,
|
||||
Leave,
|
||||
FocusIn,
|
||||
FocusOut,
|
||||
HierarchyChanged,
|
||||
PropertyEvent,
|
||||
RawKeyPress,
|
||||
RawKeyRelease,
|
||||
RawButtonPress,
|
||||
RawButtonRelease,
|
||||
RawMotion,
|
||||
LastEvent = RawMotion
|
||||
}
|
||||
|
||||
enum XIEventMasks
|
||||
{
|
||||
DeviceChangedMask = (1 << (int)XIEventType.DeviceChanged),
|
||||
KeyPressMask = (1 << (int)XIEventType.KeyPress),
|
||||
KeyReleaseMask = (1 << (int)XIEventType.KeyRelease),
|
||||
ButtonPressMask = (1 << (int)XIEventType.ButtonPress),
|
||||
ButtonReleaseMask = (1 << (int)XIEventType.ButtonRelease),
|
||||
MotionMask = (1 << (int)XIEventType.Motion),
|
||||
EnterMask = (1 << (int)XIEventType.Enter),
|
||||
LeaveMask = (1 << (int)XIEventType.Leave),
|
||||
FocusInMask = (1 << (int)XIEventType.FocusIn),
|
||||
FocusOutMask = (1 << (int)XIEventType.FocusOut),
|
||||
HierarchyChangedMask = (1 << (int)XIEventType.HierarchyChanged),
|
||||
PropertyEventMask = (1 << (int)XIEventType.PropertyEvent),
|
||||
RawKeyPressMask = (1 << (int)XIEventType.RawKeyPress),
|
||||
RawKeyReleaseMask = (1 << (int)XIEventType.RawKeyRelease),
|
||||
RawButtonPressMask = (1 << (int)XIEventType.RawButtonPress),
|
||||
RawButtonReleaseMask = (1 << (int)XIEventType.RawButtonRelease),
|
||||
RawMotionMask = (1 << (int)XIEventType.RawMotion),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,14 @@ namespace OpenTK.Platform.X11
|
|||
|
||||
public virtual OpenTK.Input.IMouseDriver CreateMouseDriver()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Only supported on xorg 1.7 or higher.
|
||||
return new XI2Mouse(null);
|
||||
}
|
||||
catch (NotSupportedException) { }
|
||||
|
||||
// Should always be supported.
|
||||
return new X11Mouse(null);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace OpenTK.Platform.X11
|
||||
|
@ -60,6 +61,8 @@ namespace OpenTK.Platform.X11
|
|||
// IntPtr.Zero, IntPtr.Zero);
|
||||
//Functions.XSelectInput(window.Display, window.RootWindow, new IntPtr((int)window.EventMask));
|
||||
}
|
||||
|
||||
Debug.WriteLine("Using X11Mouse.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
188
Source/OpenTK/Platform/X11/XI2Mouse.cs
Normal file
188
Source/OpenTK/Platform/X11/XI2Mouse.cs
Normal file
|
@ -0,0 +1,188 @@
|
|||
#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.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenTK.Input;
|
||||
|
||||
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 : IMouseDriver
|
||||
{
|
||||
MouseState state = new MouseState();
|
||||
X11WindowInfo window;
|
||||
readonly int XIOpCode;
|
||||
|
||||
static readonly Functions.EventPredicate PredicateImpl = IsEventValid;
|
||||
readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl);
|
||||
|
||||
// Can either attach itself to the specified window or can hook the root window.
|
||||
public XI2Mouse(X11WindowInfo win)
|
||||
{
|
||||
if (win != null)
|
||||
{
|
||||
window = win;
|
||||
}
|
||||
else
|
||||
{
|
||||
using (new XLock(API.DefaultDisplay))
|
||||
{
|
||||
window = new X11WindowInfo();
|
||||
window.Display = API.DefaultDisplay;
|
||||
window.Screen = Functions.XDefaultScreen(window.Display);
|
||||
window.RootWindow = Functions.XRootWindow(window.Display, window.Screen);
|
||||
window.WindowHandle = window.RootWindow;
|
||||
}
|
||||
}
|
||||
|
||||
using (new XLock(window.Display))
|
||||
{
|
||||
int major, ev, error;
|
||||
if (Functions.XQueryExtension(window.Display, "XInputExtension", out major, out ev, out error) == 0)
|
||||
{
|
||||
Debug.WriteLine("XInput2 not supported.");
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
XIOpCode = major;
|
||||
|
||||
using (XIEventMask mask = new XIEventMask(1, XIEventMasks.RawButtonPressMask |
|
||||
XIEventMasks.RawButtonReleaseMask | XIEventMasks.RawMotionMask))
|
||||
{
|
||||
Functions.XISelectEvents(window.Display, window.WindowHandle, mask);
|
||||
}
|
||||
}
|
||||
Debug.WriteLine("Using XI2Mouse.");
|
||||
}
|
||||
|
||||
// Todo: remove this
|
||||
public IList<MouseDevice> Mouse { get { throw new NotSupportedException(); } }
|
||||
|
||||
public MouseState GetState()
|
||||
{
|
||||
ProcessEvents();
|
||||
return state;
|
||||
}
|
||||
|
||||
public MouseState GetState(int index)
|
||||
{
|
||||
ProcessEvents();
|
||||
return state;
|
||||
}
|
||||
|
||||
void ProcessEvents()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
XEvent e = new XEvent();
|
||||
XGenericEventCookie cookie;
|
||||
|
||||
using (new XLock(window.Display))
|
||||
{
|
||||
if (!Functions.XCheckIfEvent(window.Display, ref e, Predicate, new IntPtr(XIOpCode)))
|
||||
return;
|
||||
|
||||
cookie = e.GenericEventCookie;
|
||||
if (Functions.XGetEventData(window.Display, ref cookie) != 0)
|
||||
{
|
||||
XIRawEvent raw = (XIRawEvent)
|
||||
Marshal.PtrToStructure(cookie.data, typeof(XIRawEvent));
|
||||
|
||||
switch (raw.evtype)
|
||||
{
|
||||
case XIEventType.RawMotion:
|
||||
if (IsBitSet(raw.valuators.mask, 0))
|
||||
state.X += (int)BitConverter.Int64BitsToDouble(Marshal.ReadInt64(raw.raw_values, 0));
|
||||
if (IsBitSet(raw.valuators.mask, 1))
|
||||
state.Y += (int)BitConverter.Int64BitsToDouble(Marshal.ReadInt64(raw.raw_values, 8));
|
||||
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.WheelPrecise++; break;
|
||||
case 5: state.WheelPrecise--; 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;
|
||||
}
|
||||
}
|
||||
Functions.XFreeEventData(window.Display, ref cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsEventValid(IntPtr display, ref XEvent e, IntPtr arg)
|
||||
{
|
||||
return e.GenericEventCookie.extension == arg.ToInt32() &&
|
||||
(e.GenericEventCookie.evtype == (int)XIEventType.RawMotion ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.RawButtonPress ||
|
||||
e.GenericEventCookie.evtype == (int)XIEventType.RawButtonRelease);
|
||||
}
|
||||
|
||||
static bool IsBitSet(IntPtr mask, int bit)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
return (*((byte*)mask + (bit >> 3)) & (1 << (bit & 7))) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue