diff --git a/Source/OpenTK/Platform/Windows/API.cs b/Source/OpenTK/Platform/Windows/API.cs
index 20cb38a7..94081054 100644
--- a/Source/OpenTK/Platform/Windows/API.cs
+++ b/Source/OpenTK/Platform/Windows/API.cs
@@ -851,6 +851,9 @@ namespace OpenTK.Platform.Windows
[DllImport("user32.dll", SetLastError = true)]
public static extern BOOL BringWindowToTop(HWND hWnd);
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern BOOL SetParent(HWND child, HWND newParent);
+
#endregion
#region Display settings
@@ -1353,17 +1356,6 @@ namespace OpenTK.Platform.Windows
///
/// GetRawInputData gets the raw input one RawInput structure at a time. In contrast, GetRawInputBuffer gets an array of RawInput structures.
///
- [CLSCompliant(false)]
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("user32.dll", SetLastError = true)]
- internal static extern UINT GetRawInputData(
- HRAWINPUT RawInput,
- GetRawInputDataEnum Command,
- [Out] LPVOID Data,
- [In, Out] ref UINT Size,
- UINT SizeHeader
- );
-
[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport("user32.dll", SetLastError = true)]
internal static extern INT GetRawInputData(
@@ -1395,17 +1387,6 @@ namespace OpenTK.Platform.Windows
///
/// GetRawInputData gets the raw input one RawInput structure at a time. In contrast, GetRawInputBuffer gets an array of RawInput structures.
///
- [CLSCompliant(false)]
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("user32.dll", SetLastError = true)]
- internal static extern UINT GetRawInputData(
- HRAWINPUT RawInput,
- GetRawInputDataEnum Command,
- /*[MarshalAs(UnmanagedType.LPStruct)]*/ [Out] out RawInput Data,
- [In, Out] ref UINT Size,
- UINT SizeHeader
- );
-
[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport("user32.dll", SetLastError = true)]
internal static extern INT GetRawInputData(
@@ -1416,6 +1397,16 @@ namespace OpenTK.Platform.Windows
INT SizeHeader
);
+ [System.Security.SuppressUnmanagedCodeSecurity]
+ [DllImport("user32.dll", SetLastError = true)]
+ unsafe internal static extern INT GetRawInputData(
+ HRAWINPUT RawInput,
+ GetRawInputDataEnum Command,
+ RawInput* Data,
+ [In, Out] ref INT Size,
+ INT SizeHeader
+ );
+
#endregion
#region IntPtr NextRawInputStructure(IntPtr data)
@@ -1487,7 +1478,7 @@ namespace OpenTK.Platform.Windows
#region --- Constants ---
- internal struct Constants
+ static class Constants
{
// Found in winuser.h
internal const int KEYBOARD_OVERRUN_MAKE_CODE = 0xFF;
@@ -1574,6 +1565,8 @@ namespace OpenTK.Platform.Windows
// (found in winuser.h)
internal const int ENUM_REGISTRY_SETTINGS = -2;
internal const int ENUM_CURRENT_SETTINGS = -1;
+
+ internal static readonly IntPtr MESSAGE_ONLY = new IntPtr(-3);
}
#endregion
@@ -2231,25 +2224,11 @@ namespace OpenTK.Platform.Windows
/// To get device specific information, call GetRawInputDeviceInfo with the hDevice from RAWINPUTHEADER.
/// Raw input is available only when the application calls RegisterRawInputDevices with valid device specifications.
///
- [StructLayout(LayoutKind.Sequential)]
- internal struct RawInput
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct RawInput
{
- internal RawInputHeader Header;
- internal RawInputData Data;
-
- internal byte[] ToByteArray()
- {
- unsafe
- {
- byte[] dump = new byte[API.RawInputSize];
- fixed (RawInputDeviceType* ptr = &Header.Type)
- {
- for (int i = 0; i < API.RawInputSize; i++)
- dump[i] = *((byte*)ptr + i);
- return dump;
- }
- }
- }
+ public RawInputHeader Header;
+ public RawInputData Data;
}
[StructLayout(LayoutKind.Explicit)]
@@ -2350,38 +2329,9 @@ namespace OpenTK.Platform.Windows
///
/// Contains information about the state of the mouse.
///
- [StructLayout(LayoutKind.Sequential, Pack=1)]
+ [StructLayout(LayoutKind.Explicit)]
internal struct RawMouse
{
- //internal RawMouseFlags Flags; // USHORT in winuser.h, but only INT works -- USHORT returns 0.
- USHORT flags;
- byte for_alignment; // Not used -- used for alignment
- ///
- /// Reserved.
- ///
- //ULONG Buttons;
- internal USHORT buttonFlags;
- ///
- /// If usButtonFlags is RI_MOUSE_WHEEL, this member is a signed value that specifies the wheel delta.
- ///
- internal USHORT ButtonData;// { get { return (USHORT)((Buttons & 0xFFFF0000) >> 16); } }
- ///
- /// Raw state of the mouse buttons.
- ///
- internal ULONG RawButtons;
- ///
- /// Motion in the X direction. This is signed relative motion or absolute motion, depending on the value of usFlags.
- ///
- internal LONG LastX;
- ///
- /// Motion in the Y direction. This is signed relative motion or absolute motion, depending on the value of usFlags.
- ///
- internal LONG LastY;
- ///
- /// Device-specific additional information for the event.
- ///
- internal ULONG ExtraInformation;
-
///
/// Mouse state. This member can be any reasonable combination of the following.
/// MOUSE_ATTRIBUTES_CHANGED
@@ -2393,12 +2343,34 @@ namespace OpenTK.Platform.Windows
/// MOUSE_VIRTUAL_DESKTOP
/// Mouse coordinates are mapped to the virtual desktop (for a multiple monitor system).
///
- internal RawMouseFlags Flags { get { return (RawMouseFlags)(flags); } }
+ [FieldOffset(0)] public RawMouseFlags Flags; // USHORT in winuser.h, but only INT works -- USHORT returns 0.
+
+ [FieldOffset(4)] public RawInputMouseState ButtonFlags;
///
- /// Transition state of the mouse buttons.
+ /// If usButtonFlags is RI_MOUSE_WHEEL, this member is a signed value that specifies the wheel delta.
///
- internal RawInputMouseState ButtonFlags { get { return (RawInputMouseState)(buttonFlags); } }
+ [FieldOffset(6)] public USHORT ButtonData;
+
+ ///
+ /// Raw state of the mouse buttons.
+ ///
+ [FieldOffset(8)] public ULONG RawButtons;
+
+ ///
+ /// Motion in the X direction. This is signed relative motion or absolute motion, depending on the value of usFlags.
+ ///
+ [FieldOffset(12)] public LONG LastX;
+
+ ///
+ /// Motion in the Y direction. This is signed relative motion or absolute motion, depending on the value of usFlags.
+ ///
+ [FieldOffset(16)] public LONG LastY;
+
+ ///
+ /// Device-specific additional information for the event.
+ ///
+ [FieldOffset(20)] public ULONG ExtraInformation;
}
#endregion
@@ -2483,10 +2455,11 @@ namespace OpenTK.Platform.Windows
/// Number of HID inputs in bRawData.
///
internal DWORD Count;
- ///
- /// Raw input data as an array of bytes.
- ///
- internal BYTE RawData;
+ // The RawData field must be marshalled manually.
+ /////
+ ///// Raw input data as an array of bytes.
+ /////
+ //internal IntPtr RawData;
}
#endregion
@@ -3239,6 +3212,7 @@ namespace OpenTK.Platform.Windows
///
/// Mouse indicator flags (found in winuser.h).
///
+ [Flags]
internal enum RawMouseFlags : ushort
{
///
diff --git a/Source/OpenTK/Platform/Windows/WinFactory.cs b/Source/OpenTK/Platform/Windows/WinFactory.cs
index 30b25b74..2616e770 100644
--- a/Source/OpenTK/Platform/Windows/WinFactory.cs
+++ b/Source/OpenTK/Platform/Windows/WinFactory.cs
@@ -83,7 +83,10 @@ namespace OpenTK.Platform.Windows
public virtual OpenTK.Input.IMouseDriver CreateMouseDriver()
{
- throw new NotImplementedException();
+ if (System.Environment.OSVersion.Version.Major >= 5)
+ return new WinRawMouse();
+ else
+ return new WMInput(null);
}
#endregion
diff --git a/Source/OpenTK/Platform/Windows/WinRawInput.cs b/Source/OpenTK/Platform/Windows/WinRawInput.cs
index 3cd04ec6..4d4a2f77 100644
--- a/Source/OpenTK/Platform/Windows/WinRawInput.cs
+++ b/Source/OpenTK/Platform/Windows/WinRawInput.cs
@@ -38,9 +38,10 @@ namespace OpenTK.Platform.Windows
Debug.Indent();
AssignHandle(parent.WindowHandle);
+ WinWindowInfo win = new WinWindowInfo(this.Handle, parent);
Debug.Print("Input window attached to parent {0}", parent);
keyboardDriver = new WinRawKeyboard(this.Handle);
- mouseDriver = new WinRawMouse(this.Handle);
+ mouseDriver = new WinRawMouse();
Debug.Unindent();
@@ -93,9 +94,7 @@ namespace OpenTK.Platform.Windows
return;
case RawInputDeviceType.MOUSE:
- if (!mouseDriver.ProcessEvent(data))
- Functions.DefRawInputProc(ref data, 1, (uint)API.RawInputHeaderSize);
- return;
+ throw new NotSupportedException();
case RawInputDeviceType.HID:
Functions.DefRawInputProc(ref data, 1, (uint)API.RawInputHeaderSize);
diff --git a/Source/OpenTK/Platform/Windows/WinRawMouse.cs b/Source/OpenTK/Platform/Windows/WinRawMouse.cs
index 46ab54f4..f242bd89 100644
--- a/Source/OpenTK/Platform/Windows/WinRawMouse.cs
+++ b/Source/OpenTK/Platform/Windows/WinRawMouse.cs
@@ -6,12 +6,11 @@
using System;
using System.Collections.Generic;
-using System.Text;
-using OpenTK.Input;
using System.Diagnostics;
+using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.Win32;
-using System.Drawing;
+using OpenTK.Input;
namespace OpenTK.Platform.Windows
{
@@ -19,54 +18,64 @@ namespace OpenTK.Platform.Windows
///
/// Contains methods to register for and process mouse WM_INPUT messages.
///
- internal class WinRawMouse : IMouseDriver, IDisposable
+ internal class WinRawMouse : IMouseDriver
{
- private List mice = new List();
- private IntPtr window;
-
- #region --- Constructors ---
+ List mice;
+ Dictionary rawids; // ContextHandle instead of IntPtr for fast dictionary access
+ readonly INativeWindow native;
+ readonly IntPtr window;
+ readonly WindowProcedure WndProc;
+ readonly IntPtr OldWndProc;
internal WinRawMouse()
- : this(IntPtr.Zero)
- {
- }
-
- internal WinRawMouse(IntPtr windowHandle)
{
Debug.WriteLine("Initializing mouse driver (WinRawMouse).");
Debug.Indent();
- this.window = windowHandle;
+ // Create a new message-only window to retrieve WM_INPUT messages.
+ native = new NativeWindow();
+ window = (native.WindowInfo as WinWindowInfo).WindowHandle;
+ //Functions.SetParent(window, Constants.MESSAGE_ONLY);
+ // Subclass the window to retrieve the events we are interested in.
+ WndProc = WindowProcedure;
+ OldWndProc = Functions.SetWindowLong(window, WndProc);
+ native.ProcessEvents();
- RegisterDevices();
+ RegisterDevices(window, out mice, out rawids);
Debug.Unindent();
}
- #endregion
+ #region IMouseDriver Members
- #region --- IMouseDriver Members ---
-
- public IList Mouse
- {
- get { return mice; }
- }
+ public IList Mouse { get { throw new NotImplementedException(); } }
public MouseState GetState()
{
- throw new NotImplementedException();
+ native.ProcessEvents();
+ if (mice.Count > 0)
+ return mice[0];
+ else
+ return new MouseState();
}
public MouseState GetState(int index)
{
- throw new NotImplementedException();
+ native.ProcessEvents();
+ if (index < mice.Count)
+ return mice[index];
+ else
+ return new MouseState();
}
- #region public int RegisterDevices()
+ #endregion
- public int RegisterDevices()
+ static int RegisterDevices(IntPtr window, out List mice, out Dictionary rawids)
{
int count = WinRawInput.DeviceCount;
+ mice = new List();
+ rawids = new Dictionary();
+
RawInputDeviceList[] ridl = new RawInputDeviceList[count];
for (int i = 0; i < count; i++)
ridl[i] = new RawInputDeviceList();
@@ -114,22 +123,14 @@ namespace OpenTK.Platform.Windows
if (!String.IsNullOrEmpty(deviceClass) && deviceClass.ToLower().Equals("mouse"))
{
- OpenTK.Input.MouseDevice mouse = new OpenTK.Input.MouseDevice();
- mouse.Description = deviceDesc;
-
- // Register the keyboard:
+ // Register the device:
RawInputDeviceInfo info = new RawInputDeviceInfo();
int devInfoSize = API.RawInputDeviceInfoSize;
Functions.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);
+ mice.Add(RegisterRawDevice(deviceDesc, window));
+ rawids.Add(new ContextHandle(ridl[i].Device), mice.Count - 1);
}
}
}
@@ -137,14 +138,9 @@ namespace OpenTK.Platform.Windows
return count;
}
- #endregion
-
- #endregion
-
- #region internal void RegisterRawDevice(OpenTK.Input.Mouse mouse)
-
- internal void RegisterRawDevice(OpenTK.Input.MouseDevice mouse)
+ static MouseState RegisterRawDevice(string device, IntPtr window)
{
+ MouseState state = new MouseState();
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();
@@ -164,106 +160,96 @@ namespace OpenTK.Platform.Windows
}
else
{
- Debug.Print("Registered mouse {0}", mouse.ToString());
+ Debug.Print("Registered mouse {0}", device);
Point p = new Point();
if (Functions.GetCursorPos(ref p))
- mouse.Position = p;
+ {
+ state.X = p.X;
+ state.Y = p.Y;
+ }
}
+
+ return state;
}
- #endregion
-
- #region internal bool ProcessEvent(API.RawInput rin)
-
- ///
- /// Processes raw input events.
- ///
- ///
- ///
- internal bool ProcessEvent(RawInput rin)
+ IntPtr WindowProcedure(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
- //MouseDevice mouse = mice.Find(delegate(MouseDevice m)
- //{
- // return m.DeviceID == rin.Header.Device;
- //});
- MouseDevice mouse;
- if (mice.Count > 0) mouse = mice[0];
- else return false;
-
- switch (rin.Header.Type)
+ switch (message)
{
- case RawInputDeviceType.MOUSE:
- if ((rin.Data.Mouse.ButtonFlags & RawInputMouseState.LEFT_BUTTON_DOWN) != 0) mouse[MouseButton.Left] = true;
- if ((rin.Data.Mouse.ButtonFlags & RawInputMouseState.LEFT_BUTTON_UP) != 0) mouse[MouseButton.Left] = false;
- if ((rin.Data.Mouse.ButtonFlags & RawInputMouseState.RIGHT_BUTTON_DOWN) != 0) mouse[MouseButton.Right] = true;
- if ((rin.Data.Mouse.ButtonFlags & RawInputMouseState.RIGHT_BUTTON_UP) != 0) mouse[MouseButton.Right] = false;
- if ((rin.Data.Mouse.ButtonFlags & RawInputMouseState.MIDDLE_BUTTON_DOWN) != 0) mouse[MouseButton.Middle] = true;
- if ((rin.Data.Mouse.ButtonFlags & RawInputMouseState.MIDDLE_BUTTON_UP) != 0) mouse[MouseButton.Middle] = false;
- if ((rin.Data.Mouse.ButtonFlags & RawInputMouseState.BUTTON_4_DOWN) != 0) mouse[MouseButton.Button1] = true;
- if ((rin.Data.Mouse.ButtonFlags & RawInputMouseState.BUTTON_4_UP) != 0) mouse[MouseButton.Button1] = false;
- if ((rin.Data.Mouse.ButtonFlags & RawInputMouseState.BUTTON_5_DOWN) != 0) mouse[MouseButton.Button2] = true;
- if ((rin.Data.Mouse.ButtonFlags & RawInputMouseState.BUTTON_5_UP) != 0) mouse[MouseButton.Button2] = false;
+ case WindowMessage.INPUT:
+ int expected_size = 0, real_size = 0;
+ RawInput data = new RawInput();
- if ((rin.Data.Mouse.ButtonFlags & RawInputMouseState.WHEEL) != 0)
- mouse.Wheel += (short)rin.Data.Mouse.ButtonData / 120;
-
- if ((rin.Data.Mouse.Flags & RawMouseFlags.MOUSE_MOVE_ABSOLUTE) != 0)
- {
- mouse.Position = new Point(rin.Data.Mouse.LastX, rin.Data.Mouse.LastY);
- }
- else
- { // Seems like MOUSE_MOVE_RELATIVE is the default, unless otherwise noted.
- mouse.Position = new Point(mouse.X + rin.Data.Mouse.LastX,
- mouse.Y + rin.Data.Mouse.LastY);
- }
-
- if ((rin.Data.Mouse.Flags & RawMouseFlags.MOUSE_VIRTUAL_DESKTOP) != 0)
- Debug.WriteLine(String.Format("Mouse {0} defines MOUSE_VIRTUAL_DESKTOP flag, please report at http://www.opentk.com", mouse.ToString()));
+ // Get the size of the input buffer
+ Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
+ IntPtr.Zero, ref expected_size, API.RawInputHeaderSize);
- return true;
+ // Read the actual data
+ unsafe
+ {
+ real_size = Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
+ &data, ref expected_size, API.RawInputHeaderSize);
+ }
+
+ if (real_size == expected_size)
+ {
+ if (data.Header.Type == RawInputDeviceType.MOUSE)
+ {
+ if (ProcessEvent(data.Header.Device, data.Data.Mouse))
+ {
+ return IntPtr.Zero;
+ }
+ }
+ }
+ // We didn't handle this message after all, give it back to the old WndProc.
+ goto default;
default:
- throw new ApplicationException("WinRawMouse driver received invalid data.");
+ return Functions.CallWindowProc(OldWndProc, handle, message, wParam, lParam);
}
}
- #endregion
-
- #region public void Poll()
-
- public void Poll()
+ bool ProcessEvent(IntPtr device, RawMouse raw)
{
- }
+ if (mice.Count == 0)
+ return false;
- #endregion
+ ContextHandle handle = new ContextHandle(device);
+ MouseState mouse;
+ if (rawids.ContainsKey(handle))
+ mouse = mice[rawids[handle]];
+ else
+ return false;
- #region --- IDisposable Members ---
+ if ((raw.ButtonFlags & RawInputMouseState.LEFT_BUTTON_DOWN) != 0) mouse.EnableBit((int)MouseButton.Left);
+ if ((raw.ButtonFlags & RawInputMouseState.LEFT_BUTTON_UP) != 0) mouse.DisableBit((int)MouseButton.Left);
+ if ((raw.ButtonFlags & RawInputMouseState.RIGHT_BUTTON_DOWN) != 0) mouse.EnableBit((int)MouseButton.Right);
+ if ((raw.ButtonFlags & RawInputMouseState.RIGHT_BUTTON_UP) != 0) mouse.DisableBit((int)MouseButton.Right);
+ if ((raw.ButtonFlags & RawInputMouseState.MIDDLE_BUTTON_DOWN) != 0) mouse.EnableBit((int)MouseButton.Middle);
+ if ((raw.ButtonFlags & RawInputMouseState.MIDDLE_BUTTON_UP) != 0) mouse.DisableBit((int)MouseButton.Middle);
+ if ((raw.ButtonFlags & RawInputMouseState.BUTTON_4_DOWN) != 0) mouse.EnableBit((int)MouseButton.Button1);
+ if ((raw.ButtonFlags & RawInputMouseState.BUTTON_4_UP) != 0) mouse.DisableBit((int)MouseButton.Button1);
+ if ((raw.ButtonFlags & RawInputMouseState.BUTTON_5_DOWN) != 0) mouse.EnableBit((int)MouseButton.Button2);
+ if ((raw.ButtonFlags & RawInputMouseState.BUTTON_5_UP) != 0) mouse.DisableBit((int)MouseButton.Button2);
- private bool disposed;
+ if ((raw.ButtonFlags & RawInputMouseState.WHEEL) != 0)
+ mouse.WheelPrecise += (short)raw.ButtonData / 120.0f;
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private void Dispose(bool manual)
- {
- if (!disposed)
+ if ((raw.Flags & RawMouseFlags.MOUSE_MOVE_ABSOLUTE) != 0)
{
- if (manual)
- {
- mice.Clear();
- }
- disposed = true;
+ mouse.X = raw.LastX;
+ mouse.Y = raw.LastY;
}
+ else
+ { // Seems like MOUSE_MOVE_RELATIVE is the default, unless otherwise noted.
+ mouse.X += raw.LastX;
+ mouse.Y += raw.LastY;
+ }
+
+ mice[rawids[handle]] = mouse;
+ return true;
}
- ~WinRawMouse()
- {
- Dispose(false);
- }
- #endregion
}
}