From 980e7138d260166e17dc1962f91204a0f67773ab Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Fri, 21 Sep 2007 20:34:07 +0000 Subject: [PATCH] Work on MouseDriver. Windows raw driver works. --- Source/OpenTK/Input/IMouse.cs | 18 +- Source/OpenTK/Input/IMouseDriver.cs | 12 +- Source/OpenTK/Input/Mouse.cs | 179 +++++++++++++++- Source/OpenTK/Platform/Windows/WinRawInput.cs | 24 ++- Source/OpenTK/Platform/Windows/WinRawMouse.cs | 201 +++++++++++++++++- Source/OpenTK/Platform/X11/X11Input.cs | 18 +- Source/OpenTK/Platform/X11/X11Mouse.cs | 16 +- 7 files changed, 445 insertions(+), 23 deletions(-) diff --git a/Source/OpenTK/Input/IMouse.cs b/Source/OpenTK/Input/IMouse.cs index 3e7e43df..71478c1e 100644 --- a/Source/OpenTK/Input/IMouse.cs +++ b/Source/OpenTK/Input/IMouse.cs @@ -10,7 +10,23 @@ using System.Text; namespace OpenTK.Input { - interface IMouse : IInputDevice + public interface IMouse : IInputDevice { + int NumberOfButtons { get; } + int NumberOfWheels { get; } + IntPtr DeviceID { get; } + int Wheel { get; } + int X { get; } + int Y { get; } + int DeltaX { get; } + int DeltaY { get; } + + event MouseMoveEvent Move; + event MouseButtonDownEvent ButtonDown; + event MouseButtonUpEvent ButtonUp; } + + public delegate void MouseMoveEvent(IMouse sender, MouseMoveData key); + public delegate void MouseButtonDownEvent(IMouse sender, MouseButton button); + public delegate void MouseButtonUpEvent(IMouse sender, MouseButton button); } diff --git a/Source/OpenTK/Input/IMouseDriver.cs b/Source/OpenTK/Input/IMouseDriver.cs index 1f4de18a..d0a8902f 100644 --- a/Source/OpenTK/Input/IMouseDriver.cs +++ b/Source/OpenTK/Input/IMouseDriver.cs @@ -12,6 +12,16 @@ namespace OpenTK.Input { public interface IMouseDriver { - IList Mouse { get; } + /// + /// Gets the list of available mouse devices. + /// + IList Mouse { get; } + /* + /// + /// Registers available mouse devices. + /// + /// The number of devices registered. + int RegisterDevices(); + */ } } diff --git a/Source/OpenTK/Input/Mouse.cs b/Source/OpenTK/Input/Mouse.cs index e505fbf8..71c56233 100644 --- a/Source/OpenTK/Input/Mouse.cs +++ b/Source/OpenTK/Input/Mouse.cs @@ -10,13 +10,20 @@ using System.Text; namespace OpenTK.Input { - public class Mouse : IMouse + public sealed class Mouse : IMouse { + private string description; + private int numButtons, numWheels; + private IntPtr id; + private bool[] button = new bool[(int)MouseButton.LastButton]; + private int wheel, x, y, delta_x, delta_y; + #region --- IInputDevice Members --- public string Description { - get { throw new Exception("The method or operation is not implemented."); } + get { return description; } + internal set { description = value; } } public InputDeviceType DeviceType @@ -25,5 +32,173 @@ namespace OpenTK.Input } #endregion + + #region --- IMouse Members --- + + public int NumberOfButtons + { + get { return numButtons; } + internal set { numButtons = value; } + } + + public int NumberOfWheels + { + get { return numWheels; } + internal set { numWheels = value; } + } + + public IntPtr DeviceID + { + get { return id; } + internal set { id = value; } + } + + public int Wheel + { + get { return wheel; } + internal set { wheel = value; } + } + + public int X + { + get { return x; } + internal set { x = value; } + } + + public int Y + { + get { return y; } + internal set { y = value; } + } + + public int DeltaX + { + get { return delta_x; } + internal set { delta_x = value; } + } + + public int DeltaY + { + get { return delta_y; } + internal set { delta_y = value; } + } + + public event MouseMoveEvent Move; + public event MouseButtonDownEvent ButtonDown; + public event MouseButtonUpEvent ButtonUp; + + #endregion + + #region public bool this[MouseButton b] + + public bool this[MouseButton b] + { + internal set + { + button[(int)b] = value; + } + + get + { + return button[(int)b]; + } + } + + #endregion + } + + public enum MouseButton + { + Left = 0, + Middle, + Right, + Button1, + Button2, + Button3, + Button4, + Button5, + Button6, + Button7, + Button8, + Button9, + LastButton + } + + public class MouseWheel + { + private int position; + private int delta; + + /// + /// Gets the absolute position of the mouse wheel. + /// + public int Position + { + get { return position; } + internal set { position = value; } + } + + /// + /// Gets the relative movement of the mouse wheel. + /// + public int Delta + { + get { return delta; } + internal set { delta = value; } + } + } + + public class MouseMoveData + { + private int x; + private int y; + private int deltaX; + private int deltaY; + private MouseWheel wheel; + + /// + /// Gets the absolute X position of the mouse in screen pixel coordinates. + /// + public int X + { + get { return x; } + internal set { x = value; } + } + + /// + /// Gets the absolute Y position of the mouse in screen pixel coordinates. + /// + public int Y + { + get { return y; } + internal set { y = value; } + } + + /// + /// Gets the relative movement of the mouse in the X direction, in pixels. + /// + public int DeltaX + { + get { return deltaX; } + internal set { deltaX = value; } + } + + /// + /// Gets the relative movement of the mouse in the Y direction, in pixels. + /// + public int DeltaY + { + get { return deltaY; } + internal set { deltaY = value; } + } + + /// + /// Gets data relevant to the mouse wheel. + /// + public MouseWheel Wheel + { + get { return wheel; } + internal set { wheel = value; } + } } } diff --git a/Source/OpenTK/Platform/Windows/WinRawInput.cs b/Source/OpenTK/Platform/Windows/WinRawInput.cs index 72c0c6e1..4238771b 100644 --- a/Source/OpenTK/Platform/Windows/WinRawInput.cs +++ b/Source/OpenTK/Platform/Windows/WinRawInput.cs @@ -30,10 +30,11 @@ namespace OpenTK.Platform.Windows private static int deviceCount; private WinRawKeyboard keyboardDriver; + private WinRawMouse mouseDriver; #region --- Constructors --- - internal WinRawInput(WindowInfo parent) + internal WinRawInput(IWindowInfo parent) { Debug.WriteLine("Initalizing windows raw input driver."); Debug.Indent(); @@ -41,6 +42,7 @@ namespace OpenTK.Platform.Windows AssignHandle(parent.Handle); Debug.Print("Input window attached to parent {0}", parent); keyboardDriver = new WinRawKeyboard(this.Handle); + mouseDriver = new WinRawMouse(this.Handle); Debug.Unindent(); } @@ -89,17 +91,21 @@ namespace OpenTK.Platform.Windows switch (data.Header.Type) { case RawInputDeviceType.KEYBOARD: - if (!keyboardDriver.ProcessKeyboardEvent(data)) - API.DefRawInputProc(ref data, 1, (uint)API.RawInputHeaderSize); - return; + if (!keyboardDriver.ProcessKeyboardEvent(data)) + API.DefRawInputProc(ref data, 1, (uint)API.RawInputHeaderSize); + return; case RawInputDeviceType.MOUSE: - API.DefRawInputProc(ref data, 1, (uint)API.RawInputHeaderSize); - return; + if (!mouseDriver.ProcessEvent(data)) + API.DefRawInputProc(ref data, 1, (uint)API.RawInputHeaderSize); + return; case RawInputDeviceType.HID: - API.DefRawInputProc(ref data, 1, (uint)API.RawInputHeaderSize); - return; + API.DefRawInputProc(ref data, 1, (uint)API.RawInputHeaderSize); + return; + + default: + break; } } else @@ -141,7 +147,7 @@ namespace OpenTK.Platform.Windows public IList Mouse { - get { throw new Exception("The method or operation is not implemented."); } + get { return mouseDriver.Mouse; } } public void ProcessEvents() diff --git a/Source/OpenTK/Platform/Windows/WinRawMouse.cs b/Source/OpenTK/Platform/Windows/WinRawMouse.cs index 41380aba..56e3d6d3 100644 --- a/Source/OpenTK/Platform/Windows/WinRawMouse.cs +++ b/Source/OpenTK/Platform/Windows/WinRawMouse.cs @@ -7,10 +7,209 @@ using System; using System.Collections.Generic; using System.Text; +using OpenTK.Input; +using System.Diagnostics; +using System.Runtime.InteropServices; +using Microsoft.Win32; namespace OpenTK.Platform.Windows { - class WinRawMouse + internal class WinRawMouse : IMouseDriver, IDisposable { + private List mice = new List(); + private IntPtr window; + + #region --- Constructors --- + + internal WinRawMouse() + : this(IntPtr.Zero) + { + } + + internal WinRawMouse(IntPtr windowHandle) + { + Debug.WriteLine("Initializing mouse driver (WinRawMouse)."); + Debug.Indent(); + + this.window = windowHandle; + + RegisterDevices(); + + Debug.Unindent(); + } + + #endregion + + #region --- IMouseDriver Members --- + + public IList Mouse + { + get { return mice; } + } + + public int RegisterDevices() + { + int count = WinRawInput.DeviceCount; + RawInputDeviceList[] ridl = new RawInputDeviceList[count]; + for (int i = 0; i < count; i++) + ridl[i] = new RawInputDeviceList(); + API.GetRawInputDeviceList(ridl, ref count, API.RawInputDeviceListSize); + + // Discover mouse devices: + for (int i = 0; i < count; i++) + { + uint size = 0; + API.GetRawInputDeviceInfo(ridl[i].Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size); + IntPtr name_ptr = Marshal.AllocHGlobal((IntPtr)size); + API.GetRawInputDeviceInfo(ridl[i].Device, RawInputDeviceInfoEnum.DEVICENAME, name_ptr, ref size); + string name = Marshal.PtrToStringAnsi(name_ptr); + Marshal.FreeHGlobal(name_ptr); + + if (name.ToLower().Contains("root")) + { + // This is a terminal services device, skip it. + continue; + } + else if (ridl[i].Type == RawInputDeviceType.MOUSE || ridl[i].Type == RawInputDeviceType.HID) + { + // This is a mouse or a USB mouse device. In the latter case, discover if it really is a + // mouse device by qeurying the registry. + + // remove the \??\ + name = name.Substring(4); + + string[] split = name.Split('#'); + + string id_01 = split[0]; // ACPI (Class code) + string id_02 = split[1]; // PNP0303 (SubClass code) + string id_03 = split[2]; // 3&13c0b0c5&0 (Protocol code) + // The final part is the class GUID and is not needed here + + string findme = string.Format( + @"System\CurrentControlSet\Enum\{0}\{1}\{2}", + id_01, id_02, id_03); + + RegistryKey regkey = Registry.LocalMachine.OpenSubKey(findme); + + string deviceDesc = + (string)regkey.GetValue("DeviceDesc"); + string deviceClass = + (string)regkey.GetValue("Class"); + if (!String.IsNullOrEmpty(deviceClass) && deviceClass.ToLower().Equals("mouse")) + { + OpenTK.Input.Mouse mouse = new OpenTK.Input.Mouse(); + mouse.Description = deviceDesc; + + // Register the keyboard: + RawInputDeviceInfo info = new RawInputDeviceInfo(); + int devInfoSize = API.RawInputDeviceInfoSize; + API.GetRawInputDeviceInfo(ridl[i].Device, RawInputDeviceInfoEnum.DEVICEINFO, + info, ref devInfoSize); + + mouse.NumberOfButtons = info.Device.Mouse.NumberOfButtons; + mouse.NumberOfWheels = info.Device.Mouse.HasHorizontalWheel ? 1 : 0; + + mouse.DeviceID = ridl[i].Device;//(IntPtr)info.Device.Mouse.Id; + + this.RegisterRawDevice(mouse); + mice.Add(mouse); + } + } + } + + return count; + } + + #endregion + + #region internal void RegisterRawDevice(OpenTK.Input.Mouse mouse) + + internal void RegisterRawDevice(OpenTK.Input.Mouse mouse) + { + RawInputDevice[] rid = new RawInputDevice[1]; + // Mouse is 1/2 (page/id). See http://www.microsoft.com/whdc/device/input/HID_HWID.mspx + rid[0] = new RawInputDevice(); + rid[0].UsagePage = 1; + rid[0].Usage = 2; + rid[0].Flags = RawInputDeviceFlags.INPUTSINK; + rid[0].Target = window; + + if (!API.RegisterRawInputDevices(rid, 1, API.RawInputDeviceSize)) + { + throw new ApplicationException( + String.Format( + "Raw input registration failed with error: {0}. Device: {1}", + Marshal.GetLastWin32Error(), + rid[0].ToString()) + ); + } + else + { + Debug.Print("Registered mouse {0}", mouse.ToString()); + } + } + + #endregion + + #region internal bool ProcessEvent(API.RawInput rin) + + /// + /// Processes raw input events. + /// + /// + /// + internal bool ProcessEvent(RawInput rin) + { + Mouse mouse = mice.Find(delegate(Mouse m) + { + return m.DeviceID == rin.Header.Device; + }); + + switch (rin.Header.Type) + { + case RawInputDeviceType.MOUSE: + mouse[MouseButton.Left] = rin.Data.Mouse.ButtonFlags == RawInputMouseState.LEFT_BUTTON_DOWN; + mouse[MouseButton.Right] = rin.Data.Mouse.ButtonFlags == RawInputMouseState.RIGHT_BUTTON_DOWN; + mouse[MouseButton.Middle] = rin.Data.Mouse.ButtonFlags == RawInputMouseState.MIDDLE_BUTTON_DOWN; + mouse[MouseButton.Button1] = rin.Data.Mouse.ButtonFlags == RawInputMouseState.BUTTON_4_DOWN; + mouse[MouseButton.Button2] = rin.Data.Mouse.ButtonFlags == RawInputMouseState.BUTTON_5_DOWN; + + if (rin.Data.Mouse.ButtonFlags == RawInputMouseState.WHEEL) + { + mouse.Wheel += rin.Data.Mouse.ButtonData; + } + + if (rin.Data.Mouse.Flags == RawMouseFlags.MOUSE_MOVE_ABSOLUTE) + { + mouse.DeltaX = mouse.X - rin.Data.Mouse.LastX; + mouse.DeltaY = mouse.Y - rin.Data.Mouse.LastY; + mouse.X = rin.Data.Mouse.LastX; + mouse.Y = rin.Data.Mouse.LastY; + } + else if (rin.Data.Mouse.Flags == RawMouseFlags.MOUSE_MOVE_RELATIVE) + { + mouse.DeltaX = rin.Data.Mouse.LastX; + mouse.DeltaY = rin.Data.Mouse.LastY; + mouse.X += mouse.DeltaX; + mouse.Y += mouse.DeltaY; + } + + return false; + + default: + throw new ApplicationException("WinRawMouse driver received keyboard data."); + } + } + + #endregion + + #region --- IDisposable Members --- + + public void Dispose() + { + //throw new Exception("The method or operation is not implemented."); + } + + #endregion } } diff --git a/Source/OpenTK/Platform/X11/X11Input.cs b/Source/OpenTK/Platform/X11/X11Input.cs index cd869bfe..bb7f2256 100644 --- a/Source/OpenTK/Platform/X11/X11Input.cs +++ b/Source/OpenTK/Platform/X11/X11Input.cs @@ -20,7 +20,8 @@ namespace OpenTK.Platform.X11 internal sealed class X11Input : IInputDriver { private X11Keyboard keyboardDriver; - private WindowInfo window; + private X11Mouse mouseDriver; + private X11.WindowInfo window; XEvent e = new XEvent(); @@ -31,13 +32,13 @@ namespace OpenTK.Platform.X11 /// the main application window, which selects input events and routes them to /// the device specific drivers (Keyboard, Mouse, Hid). /// - /// - public X11Input(WindowInfo parent) + /// The window which the InputDriver will attach itself on. + public X11Input(IWindowInfo attach) { Debug.WriteLine("Initalizing X11 input driver."); Debug.Indent(); - if (parent == null) + if (attach == null) { throw new ArgumentException("A valid parent window must be defined, in order to create an X11Input driver."); } @@ -82,10 +83,11 @@ namespace OpenTK.Platform.X11 keyboardDriver = new X11Keyboard(window); */ - window = new WindowInfo(parent); - keyboardDriver = new X11Keyboard(parent); - // Todo: donparent's mask is now specified by hand, hard to keep in sync. - API.SelectInput(parent.Display, parent.Handle, EventMask.StructureNotifyMask | + window = attach as Platform.WindowInfo ?? attach as X11.WindowInfo; + + keyboardDriver = new X11Keyboard(window); + // Todo: mask is now specified by hand, hard to keep in sync. + API.SelectInput(window.Display, window.Handle, EventMask.StructureNotifyMask | EventMask.SubstructureNotifyMask | EventMask.ExposureMask | EventMask.KeyReleaseMask | EventMask.KeyPressMask); diff --git a/Source/OpenTK/Platform/X11/X11Mouse.cs b/Source/OpenTK/Platform/X11/X11Mouse.cs index 684f5ff5..04e2fc55 100644 --- a/Source/OpenTK/Platform/X11/X11Mouse.cs +++ b/Source/OpenTK/Platform/X11/X11Mouse.cs @@ -7,10 +7,24 @@ using System; using System.Collections.Generic; using System.Text; +using OpenTK.Input; namespace OpenTK.Platform.X11 { - class X11Mouse + class X11Mouse : IMouseDriver { + #region --- IMouseDriver Members --- + + public IList Mouse + { + get { throw new Exception("The method or operation is not implemented."); } + } + + public int RegisterDevices() + { + throw new Exception("The method or operation is not implemented."); + } + + #endregion } }