From 2c5e7220c3c1b17670b8f864fd7c5c70d83ff5d4 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Fri, 29 Oct 2010 11:46:57 +0000 Subject: [PATCH] Implemented KeyboardState.IsConnected property. Implemented WinRawKeyboard.RefreshDevices(). General code clean-up and beautification. --- Source/OpenTK/Input/KeyboardState.cs | 8 + .../OpenTK/Platform/Windows/WinRawKeyboard.cs | 236 ++++++++---------- Source/OpenTK/Platform/Windows/WinRawMouse.cs | 183 +++++++------- 3 files changed, 210 insertions(+), 217 deletions(-) diff --git a/Source/OpenTK/Input/KeyboardState.cs b/Source/OpenTK/Input/KeyboardState.cs index 2d5c2e68..ee1ddfd7 100644 --- a/Source/OpenTK/Input/KeyboardState.cs +++ b/Source/OpenTK/Input/KeyboardState.cs @@ -43,6 +43,7 @@ namespace OpenTK.Input const int NumInts = ((int)Key.LastKey + IntSize - 1) / IntSize; // The following line triggers bogus CS0214 in gmcs 2.0.1, sigh... unsafe fixed int Keys[NumInts]; + bool is_connected; #endregion @@ -84,6 +85,12 @@ namespace OpenTK.Input return !ReadBit((int)key); } + public bool IsConnected + { + get { return is_connected; } + internal set { is_connected = value; } + } + /// /// Checks whether two instances are equal. /// @@ -219,6 +226,7 @@ namespace OpenTK.Input *(k1 + i) |= *(k2 + i); } } + IsConnected |= other.IsConnected; } #endregion diff --git a/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs b/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs index 4747ecb2..e2d39286 100644 --- a/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs +++ b/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs @@ -25,170 +25,103 @@ // #endregion -#region --- Using directives --- - using System; using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; using System.Diagnostics; +using System.Runtime.InteropServices; using Microsoft.Win32; using OpenTK.Input; -#endregion - namespace OpenTK.Platform.Windows { - internal class WinRawKeyboard : IKeyboardDriver2 + sealed class WinRawKeyboard : IKeyboardDriver2 { readonly List keyboards = new List(); readonly List names = new List(); - // ContextHandle instead of IntPtr for fast dictionary access readonly Dictionary rawids = new Dictionary(); - private List keyboards_old = new List(); - private IntPtr window; + readonly IntPtr window; readonly object UpdateLock = new object(); - #region --- Constructors --- + #region Constructors - internal WinRawKeyboard() - : this(IntPtr.Zero) - { - } - - internal WinRawKeyboard(IntPtr windowHandle) + public WinRawKeyboard(IntPtr windowHandle) { Debug.WriteLine("Initializing keyboard driver (WinRawKeyboard)."); Debug.Indent(); this.window = windowHandle; - - UpdateKeyboardList(); + RefreshDevices(); Debug.Unindent(); } #endregion - #region UpdateKeyboardList + #region Public Members - internal void UpdateKeyboardList() + public void RefreshDevices() { - 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: - for (int i = 0; i < count; i++) + lock (UpdateLock) { - uint size = 0; - 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")) + for (int i = 0; i < keyboards.Count; i++) { - // This is a terminal services device, skip it. - continue; + KeyboardState state = keyboards[i]; + 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 - // keyboard 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("keyboard")) + string name = GetDeviceName(dev); + if (name.ToLower().Contains("root")) { - KeyboardDevice kb = new KeyboardDevice(); - kb.Description = deviceDesc; + // This is a terminal services device, skip it. + 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: - RawInputDeviceInfo info = new RawInputDeviceInfo(); - int devInfoSize = API.RawInputDeviceInfoSize; - Functions.GetRawInputDeviceInfo(ridl[i].Device, RawInputDeviceInfoEnum.DEVICEINFO, - info, ref devInfoSize); + if (!String.IsNullOrEmpty(deviceClass) && deviceClass.ToLower().Equals("keyboard")) + { + // Register the keyboard: + RawInputDeviceInfo info = new RawInputDeviceInfo(); + int devInfoSize = API.RawInputDeviceInfoSize; + Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICEINFO, + info, ref devInfoSize); - kb.NumberOfLeds = info.Device.Keyboard.NumberOfIndicators; - kb.NumberOfFunctionKeys = info.Device.Keyboard.NumberOfFunctionKeys; - kb.NumberOfKeys = info.Device.Keyboard.NumberOfKeysTotal; - //kb.DeviceID = (info.Device.Keyboard.Type << 32) + info.Device.Keyboard.SubType; - kb.DeviceID = ridl[i].Device; + //KeyboardDevice kb = new KeyboardDevice(); + //kb.Description = deviceDesc; + //kb.NumberOfLeds = info.Device.Keyboard.NumberOfIndicators; + //kb.NumberOfFunctionKeys = info.Device.Keyboard.NumberOfFunctionKeys; + //kb.NumberOfKeys = info.Device.Keyboard.NumberOfKeysTotal; + //kb.DeviceID = dev.Device; - //if (!keyboards.Contains(kb)) - //{ - this.RegisterKeyboardDevice(kb); - keyboards_old.Add(kb); - //} - - keyboards.Add(new KeyboardState()); - names.Add(deviceDesc); - rawids.Add(new ContextHandle(ridl[i].Device), keyboards.Count - 1); + RegisterKeyboardDevice(window, deviceDesc); + KeyboardState state = new KeyboardState(); + state.IsConnected = true; + keyboards.Add(state); + names.Add(deviceDesc); + rawids.Add(new ContextHandle(dev.Device), keyboards.Count - 1); + } } } } } - #endregion - - #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) - - /// - /// Processes raw input events. - /// - /// - /// - internal bool ProcessKeyboardEvent(RawInput rin) + public bool ProcessKeyboardEvent(RawInput rin) { bool processed = false; @@ -200,8 +133,7 @@ namespace OpenTK.Platform.Windows KeyboardState keyboard; if (!rawids.ContainsKey(handle)) { - keyboards.Add(new KeyboardState()); - rawids.Add(handle, keyboards.Count - 1); + RefreshDevices(); } keyboard = keyboards[rawids[handle]]; @@ -247,21 +179,63 @@ namespace OpenTK.Platform.Windows #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 - #region --- IKeyboardDriver Members --- + #region IKeyboardDriver2 Members public KeyboardState GetState() { diff --git a/Source/OpenTK/Platform/Windows/WinRawMouse.cs b/Source/OpenTK/Platform/Windows/WinRawMouse.cs index 3c16d48f..ce3bc374 100644 --- a/Source/OpenTK/Platform/Windows/WinRawMouse.cs +++ b/Source/OpenTK/Platform/Windows/WinRawMouse.cs @@ -28,7 +28,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Drawing; using System.Runtime.InteropServices; using Microsoft.Win32; using OpenTK.Input; @@ -39,7 +38,7 @@ namespace OpenTK.Platform.Windows /// /// Contains methods to register for and process mouse WM_INPUT messages. /// - internal class WinRawMouse : IMouseDriver2 + sealed class WinRawMouse : IMouseDriver2 { readonly List mice = new List(); readonly List names = new List(); @@ -47,6 +46,8 @@ namespace OpenTK.Platform.Windows readonly IntPtr Window; readonly object UpdateLock = new object(); + #region Constructors + public WinRawMouse(IntPtr window) { Debug.WriteLine("Initializing mouse driver (WinRawMouse)."); @@ -61,34 +62,10 @@ namespace OpenTK.Platform.Windows 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 + #region Public Members + public void RefreshDevices() { lock (UpdateLock) @@ -134,8 +111,8 @@ namespace OpenTK.Platform.Windows // mouse device by qeurying the registry. RegistryKey regkey = FindRegistryKey(name); string deviceDesc = (string)regkey.GetValue("DeviceDesc"); - deviceDesc = deviceDesc.Substring(deviceDesc.LastIndexOf(';') + 1); string deviceClass = (string)regkey.GetValue("Class"); + deviceDesc = deviceDesc.Substring(deviceDesc.LastIndexOf(';') + 1); if (!String.IsNullOrEmpty(deviceClass) && deviceClass.ToLower().Equals("mouse")) { @@ -147,7 +124,7 @@ namespace OpenTK.Platform.Windows Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICEINFO, info, ref devInfoSize); - RegisterRawDevice(deviceDesc, Window); + RegisterRawDevice(Window, deviceDesc); MouseState state = new MouseState(); state.IsConnected = true; 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) { RawMouse raw = rin.Data.Mouse; @@ -259,5 +180,95 @@ namespace OpenTK.Platform.Windows 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 } }