Implemented KeyboardState.IsConnected property.

Implemented WinRawKeyboard.RefreshDevices().
General code clean-up and beautification.
This commit is contained in:
the_fiddler 2010-10-29 11:46:57 +00:00
parent eba9fef913
commit 2c5e7220c3
3 changed files with 210 additions and 217 deletions

View file

@ -43,6 +43,7 @@ namespace OpenTK.Input
const int NumInts = ((int)Key.LastKey + IntSize - 1) / IntSize; const int NumInts = ((int)Key.LastKey + IntSize - 1) / IntSize;
// The following line triggers bogus CS0214 in gmcs 2.0.1, sigh... // The following line triggers bogus CS0214 in gmcs 2.0.1, sigh...
unsafe fixed int Keys[NumInts]; unsafe fixed int Keys[NumInts];
bool is_connected;
#endregion #endregion
@ -84,6 +85,12 @@ namespace OpenTK.Input
return !ReadBit((int)key); return !ReadBit((int)key);
} }
public bool IsConnected
{
get { return is_connected; }
internal set { is_connected = value; }
}
/// <summary> /// <summary>
/// Checks whether two <see cref="KeyboardState" /> instances are equal. /// Checks whether two <see cref="KeyboardState" /> instances are equal.
/// </summary> /// </summary>
@ -219,6 +226,7 @@ namespace OpenTK.Input
*(k1 + i) |= *(k2 + i); *(k1 + i) |= *(k2 + i);
} }
} }
IsConnected |= other.IsConnected;
} }
#endregion #endregion

View file

@ -25,170 +25,103 @@
// //
#endregion #endregion
#region --- Using directives ---
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32; using Microsoft.Win32;
using OpenTK.Input; using OpenTK.Input;
#endregion
namespace OpenTK.Platform.Windows namespace OpenTK.Platform.Windows
{ {
internal class WinRawKeyboard : IKeyboardDriver2 sealed class WinRawKeyboard : IKeyboardDriver2
{ {
readonly List<KeyboardState> keyboards = new List<KeyboardState>(); readonly List<KeyboardState> keyboards = new List<KeyboardState>();
readonly List<string> names = new List<string>(); readonly List<string> names = new List<string>();
// ContextHandle instead of IntPtr for fast dictionary access
readonly Dictionary<ContextHandle, int> rawids = new Dictionary<ContextHandle, int>(); readonly Dictionary<ContextHandle, int> rawids = new Dictionary<ContextHandle, int>();
private List<KeyboardDevice> keyboards_old = new List<KeyboardDevice>(); readonly IntPtr window;
private IntPtr window;
readonly object UpdateLock = new object(); readonly object UpdateLock = new object();
#region --- Constructors --- #region Constructors
internal WinRawKeyboard() public WinRawKeyboard(IntPtr windowHandle)
: this(IntPtr.Zero)
{
}
internal WinRawKeyboard(IntPtr windowHandle)
{ {
Debug.WriteLine("Initializing keyboard driver (WinRawKeyboard)."); Debug.WriteLine("Initializing keyboard driver (WinRawKeyboard).");
Debug.Indent(); Debug.Indent();
this.window = windowHandle; this.window = windowHandle;
RefreshDevices();
UpdateKeyboardList();
Debug.Unindent(); Debug.Unindent();
} }
#endregion #endregion
#region UpdateKeyboardList #region Public Members
internal void UpdateKeyboardList() public void RefreshDevices()
{ {
int count = WinRawInput.DeviceCount; lock (UpdateLock)
RawInputDeviceList[] ridl = new RawInputDeviceList[count];
for (int i = 0; i < count; i++)
ridl[i] = new RawInputDeviceList();
Functions.GetRawInputDeviceList(ridl, ref count, API.RawInputDeviceListSize);
// Discover keyboard devices:
for (int i = 0; i < count; i++)
{ {
uint size = 0; for (int i = 0; i < keyboards.Count; i++)
Functions.GetRawInputDeviceInfo(ridl[i].Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size);
IntPtr name_ptr = Marshal.AllocHGlobal((IntPtr)size);
Functions.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. KeyboardState state = keyboards[i];
continue; state.IsConnected = false;
keyboards[i] = state;
} }
else if (ridl[i].Type == RawInputDeviceType.KEYBOARD || ridl[i].Type == RawInputDeviceType.HID)
int count = WinRawInput.DeviceCount;
RawInputDeviceList[] ridl = new RawInputDeviceList[count];
for (int i = 0; i < count; i++)
ridl[i] = new RawInputDeviceList();
Functions.GetRawInputDeviceList(ridl, ref count, API.RawInputDeviceListSize);
// Discover keyboard devices:
foreach (RawInputDeviceList dev in ridl)
{ {
// This is a keyboard or USB keyboard device. In the latter case, discover if it really is a string name = GetDeviceName(dev);
// keyboard device by qeurying the registry. if (name.ToLower().Contains("root"))
// 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("keyboard"))
{ {
KeyboardDevice kb = new KeyboardDevice(); // This is a terminal services device, skip it.
kb.Description = deviceDesc; continue;
}
else if (dev.Type == RawInputDeviceType.KEYBOARD || dev.Type == RawInputDeviceType.HID)
{
// This is a keyboard or USB keyboard device. In the latter case, discover if it really is a
// keyboard device by qeurying the registry.
RegistryKey regkey = GetRegistryKey(name);
string deviceDesc = (string)regkey.GetValue("DeviceDesc");
string deviceClass = (string)regkey.GetValue("Class");
deviceDesc = deviceDesc.Substring(deviceDesc.LastIndexOf(';') + 1);
// Register the keyboard: if (!String.IsNullOrEmpty(deviceClass) && deviceClass.ToLower().Equals("keyboard"))
RawInputDeviceInfo info = new RawInputDeviceInfo(); {
int devInfoSize = API.RawInputDeviceInfoSize; // Register the keyboard:
Functions.GetRawInputDeviceInfo(ridl[i].Device, RawInputDeviceInfoEnum.DEVICEINFO, RawInputDeviceInfo info = new RawInputDeviceInfo();
info, ref devInfoSize); int devInfoSize = API.RawInputDeviceInfoSize;
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICEINFO,
info, ref devInfoSize);
kb.NumberOfLeds = info.Device.Keyboard.NumberOfIndicators; //KeyboardDevice kb = new KeyboardDevice();
kb.NumberOfFunctionKeys = info.Device.Keyboard.NumberOfFunctionKeys; //kb.Description = deviceDesc;
kb.NumberOfKeys = info.Device.Keyboard.NumberOfKeysTotal; //kb.NumberOfLeds = info.Device.Keyboard.NumberOfIndicators;
//kb.DeviceID = (info.Device.Keyboard.Type << 32) + info.Device.Keyboard.SubType; //kb.NumberOfFunctionKeys = info.Device.Keyboard.NumberOfFunctionKeys;
kb.DeviceID = ridl[i].Device; //kb.NumberOfKeys = info.Device.Keyboard.NumberOfKeysTotal;
//kb.DeviceID = dev.Device;
//if (!keyboards.Contains(kb)) RegisterKeyboardDevice(window, deviceDesc);
//{ KeyboardState state = new KeyboardState();
this.RegisterKeyboardDevice(kb); state.IsConnected = true;
keyboards_old.Add(kb); keyboards.Add(state);
//} names.Add(deviceDesc);
rawids.Add(new ContextHandle(dev.Device), keyboards.Count - 1);
keyboards.Add(new KeyboardState()); }
names.Add(deviceDesc);
rawids.Add(new ContextHandle(ridl[i].Device), keyboards.Count - 1);
} }
} }
} }
} }
#endregion public bool ProcessKeyboardEvent(RawInput rin)
#region internal void RegisterKeyboardDevice(Keyboard kb)
internal void RegisterKeyboardDevice(KeyboardDevice kb)
{
RawInputDevice[] rid = new RawInputDevice[1];
// Keyboard is 1/6 (page/id). See http://www.microsoft.com/whdc/device/input/HID_HWID.mspx
rid[0] = new RawInputDevice();
rid[0].UsagePage = 1;
rid[0].Usage = 6;
rid[0].Flags = RawInputDeviceFlags.INPUTSINK;
rid[0].Target = window;
if (!Functions.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 keyboard {0}", kb.ToString());
}
}
#endregion
#region internal bool ProcessKeyboardEvent(API.RawInput rin)
/// <summary>
/// Processes raw input events.
/// </summary>
/// <param name="rin"></param>
/// <returns></returns>
internal bool ProcessKeyboardEvent(RawInput rin)
{ {
bool processed = false; bool processed = false;
@ -200,8 +133,7 @@ namespace OpenTK.Platform.Windows
KeyboardState keyboard; KeyboardState keyboard;
if (!rawids.ContainsKey(handle)) if (!rawids.ContainsKey(handle))
{ {
keyboards.Add(new KeyboardState()); RefreshDevices();
rawids.Add(handle, keyboards.Count - 1);
} }
keyboard = keyboards[rawids[handle]]; keyboard = keyboards[rawids[handle]];
@ -247,21 +179,63 @@ namespace OpenTK.Platform.Windows
#endregion #endregion
#region --- IInputDevice Members --- #region Private Members
public string Description static RegistryKey GetRegistryKey(string name)
{ {
get { throw new Exception("The method or operation is not implemented."); } // 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);
return regkey;
} }
public Input.InputDeviceType DeviceType static string GetDeviceName(RawInputDeviceList dev)
{ {
get { return Input.InputDeviceType.Keyboard; } uint size = 0;
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size);
IntPtr name_ptr = Marshal.AllocHGlobal((IntPtr)size);
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, name_ptr, ref size);
string name = Marshal.PtrToStringAnsi(name_ptr);
Marshal.FreeHGlobal(name_ptr);
return name;
}
static void RegisterKeyboardDevice(IntPtr window, string name)
{
RawInputDevice[] rid = new RawInputDevice[1];
// Keyboard is 1/6 (page/id). See http://www.microsoft.com/whdc/device/input/HID_HWID.mspx
rid[0] = new RawInputDevice();
rid[0].UsagePage = 1;
rid[0].Usage = 6;
rid[0].Flags = RawInputDeviceFlags.INPUTSINK;
rid[0].Target = window;
if (!Functions.RegisterRawInputDevices(rid, 1, API.RawInputDeviceSize))
{
Debug.Print("[Warning] Raw input registration failed with error: {0}. Device: {1}",
Marshal.GetLastWin32Error(), rid[0].ToString());
}
else
{
Debug.Print("Registered keyboard {0}", name);
}
} }
#endregion #endregion
#region --- IKeyboardDriver Members --- #region IKeyboardDriver2 Members
public KeyboardState GetState() public KeyboardState GetState()
{ {

View file

@ -28,7 +28,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Microsoft.Win32; using Microsoft.Win32;
using OpenTK.Input; using OpenTK.Input;
@ -39,7 +38,7 @@ namespace OpenTK.Platform.Windows
/// <summary> /// <summary>
/// Contains methods to register for and process mouse WM_INPUT messages. /// Contains methods to register for and process mouse WM_INPUT messages.
/// </summary> /// </summary>
internal class WinRawMouse : IMouseDriver2 sealed class WinRawMouse : IMouseDriver2
{ {
readonly List<MouseState> mice = new List<MouseState>(); readonly List<MouseState> mice = new List<MouseState>();
readonly List<string> names = new List<string>(); readonly List<string> names = new List<string>();
@ -47,6 +46,8 @@ namespace OpenTK.Platform.Windows
readonly IntPtr Window; readonly IntPtr Window;
readonly object UpdateLock = new object(); readonly object UpdateLock = new object();
#region Constructors
public WinRawMouse(IntPtr window) public WinRawMouse(IntPtr window)
{ {
Debug.WriteLine("Initializing mouse driver (WinRawMouse)."); Debug.WriteLine("Initializing mouse driver (WinRawMouse).");
@ -61,34 +62,10 @@ namespace OpenTK.Platform.Windows
Debug.Unindent(); Debug.Unindent();
} }
#region IMouseDriver Members
public MouseState GetState()
{
lock (UpdateLock)
{
MouseState master = new MouseState();
foreach (MouseState ms in mice)
{
master.MergeBits(ms);
}
return master;
}
}
public MouseState GetState(int index)
{
lock (UpdateLock)
{
if (mice.Count > index)
return mice[index];
else
return new MouseState();
}
}
#endregion #endregion
#region Public Members
public void RefreshDevices() public void RefreshDevices()
{ {
lock (UpdateLock) lock (UpdateLock)
@ -134,8 +111,8 @@ namespace OpenTK.Platform.Windows
// mouse device by qeurying the registry. // mouse device by qeurying the registry.
RegistryKey regkey = FindRegistryKey(name); RegistryKey regkey = FindRegistryKey(name);
string deviceDesc = (string)regkey.GetValue("DeviceDesc"); string deviceDesc = (string)regkey.GetValue("DeviceDesc");
deviceDesc = deviceDesc.Substring(deviceDesc.LastIndexOf(';') + 1);
string deviceClass = (string)regkey.GetValue("Class"); string deviceClass = (string)regkey.GetValue("Class");
deviceDesc = deviceDesc.Substring(deviceDesc.LastIndexOf(';') + 1);
if (!String.IsNullOrEmpty(deviceClass) && deviceClass.ToLower().Equals("mouse")) if (!String.IsNullOrEmpty(deviceClass) && deviceClass.ToLower().Equals("mouse"))
{ {
@ -147,7 +124,7 @@ namespace OpenTK.Platform.Windows
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICEINFO, Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICEINFO,
info, ref devInfoSize); info, ref devInfoSize);
RegisterRawDevice(deviceDesc, Window); RegisterRawDevice(Window, deviceDesc);
MouseState state = new MouseState(); MouseState state = new MouseState();
state.IsConnected = true; state.IsConnected = true;
mice.Add(state); mice.Add(state);
@ -160,62 +137,6 @@ namespace OpenTK.Platform.Windows
} }
} }
static string GetDeviceName(RawInputDeviceList dev)
{
// get name size
uint size = 0;
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size);
// get actual name
IntPtr name_ptr = Marshal.AllocHGlobal((IntPtr)size);
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, name_ptr, ref size);
string name = Marshal.PtrToStringAnsi(name_ptr);
Marshal.FreeHGlobal(name_ptr);
return name;
}
static RegistryKey FindRegistryKey(string name)
{
// 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);
return regkey;
}
static void RegisterRawDevice(string device, IntPtr window)
{
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 (!Functions.RegisterRawInputDevices(rid, 1, API.RawInputDeviceSize))
{
Debug.Print("[Warning] Raw input registration failed with error: {0}. Device: {1}",
Marshal.GetLastWin32Error(), rid[0].ToString());
}
else
{
Debug.Print("Registered mouse {0}", device);
}
}
public bool ProcessMouseEvent(RawInput rin) public bool ProcessMouseEvent(RawInput rin)
{ {
RawMouse raw = rin.Data.Mouse; RawMouse raw = rin.Data.Mouse;
@ -259,5 +180,95 @@ namespace OpenTK.Platform.Windows
return true; return true;
} }
} }
#endregion
#region Private Members
static string GetDeviceName(RawInputDeviceList dev)
{
// get name size
uint size = 0;
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size);
// get actual name
IntPtr name_ptr = Marshal.AllocHGlobal((IntPtr)size);
Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, name_ptr, ref size);
string name = Marshal.PtrToStringAnsi(name_ptr);
Marshal.FreeHGlobal(name_ptr);
return name;
}
static RegistryKey FindRegistryKey(string name)
{
// 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);
return regkey;
}
static void RegisterRawDevice(IntPtr window, string device)
{
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 (!Functions.RegisterRawInputDevices(rid, 1, API.RawInputDeviceSize))
{
Debug.Print("[Warning] Raw input registration failed with error: {0}. Device: {1}",
Marshal.GetLastWin32Error(), rid[0].ToString());
}
else
{
Debug.Print("Registered mouse {0}", device);
}
}
#endregion
#region IMouseDriver2 Members
public MouseState GetState()
{
lock (UpdateLock)
{
MouseState master = new MouseState();
foreach (MouseState ms in mice)
{
master.MergeBits(ms);
}
return master;
}
}
public MouseState GetState(int index)
{
lock (UpdateLock)
{
if (mice.Count > index)
return mice[index];
else
return new MouseState();
}
}
#endregion
} }
} }