PageRenderTime 69ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/GoliatEditor/OpenTK/1.1/Source/OpenTK/Platform/Windows/WinRawMouse.cs

https://gitlab.com/gonzague.defraiteur/GoliatEditor
C# | 366 lines | 266 code | 47 blank | 53 comment | 53 complexity | 466e3453c567d9f895945a59fc338ceb MD5 | raw file
  1. #region License
  2. //
  3. // The Open Toolkit Library License
  4. //
  5. // Copyright (c) 2006 - 2010 the Open Toolkit library.
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights to
  10. // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  11. // the Software, and to permit persons to whom the Software is furnished to do
  12. // so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in all
  15. // copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  19. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  24. // OTHER DEALINGS IN THE SOFTWARE.
  25. //
  26. #endregion
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Diagnostics;
  30. using System.Runtime.InteropServices;
  31. using Microsoft.Win32;
  32. using OpenTK.Input;
  33. namespace OpenTK.Platform.Windows
  34. {
  35. /// \internal
  36. /// <summary>
  37. /// Contains methods to register for and process mouse WM_INPUT messages.
  38. /// </summary>
  39. sealed class WinRawMouse : IMouseDriver2
  40. {
  41. readonly List<MouseState> mice = new List<MouseState>();
  42. readonly List<string> names = new List<string>();
  43. readonly Dictionary<ContextHandle, int> rawids = new Dictionary<ContextHandle, int>();
  44. readonly IntPtr Window;
  45. readonly object UpdateLock = new object();
  46. #region Constructors
  47. public WinRawMouse(IntPtr window)
  48. {
  49. Debug.WriteLine("Using WinRawMouse.");
  50. Debug.Indent();
  51. if (window == IntPtr.Zero)
  52. throw new ArgumentNullException("window");
  53. Window = window;
  54. RefreshDevices();
  55. Debug.Unindent();
  56. }
  57. #endregion
  58. #region Public Members
  59. public void RefreshDevices()
  60. {
  61. lock (UpdateLock)
  62. {
  63. // Mark all devices as disconnected. We will check which of those
  64. // are connected later on.
  65. for (int i = 0; i < mice.Count; i++)
  66. {
  67. MouseState state = mice[i];
  68. state.IsConnected = false;
  69. mice[i] = state;
  70. }
  71. int count = WinRawInput.DeviceCount;
  72. RawInputDeviceList[] ridl = new RawInputDeviceList[count];
  73. for (int i = 0; i < count; i++)
  74. ridl[i] = new RawInputDeviceList();
  75. Functions.GetRawInputDeviceList(ridl, ref count, API.RawInputDeviceListSize);
  76. // Discover mouse devices
  77. foreach (RawInputDeviceList dev in ridl)
  78. {
  79. ContextHandle id = new ContextHandle(dev.Device);
  80. if (rawids.ContainsKey(id))
  81. {
  82. // Device already registered, mark as connected
  83. MouseState state = mice[rawids[id]];
  84. state.IsConnected = true;
  85. mice[rawids[id]] = state;
  86. continue;
  87. }
  88. // Unregistered device, find what it is
  89. string name = GetDeviceName(dev);
  90. if (name.ToLower().Contains("root"))
  91. {
  92. // This is a terminal services device, skip it.
  93. continue;
  94. }
  95. else if (dev.Type == RawInputDeviceType.MOUSE || dev.Type == RawInputDeviceType.HID)
  96. {
  97. // This is a mouse or a USB mouse device. In the latter case, discover if it really is a
  98. // mouse device by qeurying the registry.
  99. RegistryKey regkey = FindRegistryKey(name);
  100. if (regkey == null)
  101. continue;
  102. string deviceDesc = (string)regkey.GetValue("DeviceDesc");
  103. string deviceClass = (string)regkey.GetValue("Class") as string;
  104. if(deviceClass == null)
  105. {
  106. // Added to address OpenTK issue 3198 with mouse on Windows 8
  107. string deviceClassGUID = (string)regkey.GetValue("ClassGUID");
  108. RegistryKey classGUIDKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Class\" + deviceClassGUID);
  109. deviceClass = classGUIDKey != null ? (string) classGUIDKey.GetValue("Class") : string.Empty;
  110. }
  111. // deviceDesc remained null on a new Win7 system - not sure why.
  112. // Since the description is not vital information, use a dummy description
  113. // when that happens.
  114. if (String.IsNullOrEmpty(deviceDesc))
  115. deviceDesc = "Windows Mouse " + mice.Count;
  116. else
  117. deviceDesc = deviceDesc.Substring(deviceDesc.LastIndexOf(';') + 1);
  118. if (!String.IsNullOrEmpty(deviceClass) && deviceClass.ToLower().Equals("mouse"))
  119. {
  120. if (!rawids.ContainsKey(new ContextHandle(dev.Device)))
  121. {
  122. // Register the device:
  123. RawInputDeviceInfo info = new RawInputDeviceInfo();
  124. int devInfoSize = API.RawInputDeviceInfoSize;
  125. Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICEINFO,
  126. info, ref devInfoSize);
  127. RegisterRawDevice(Window, deviceDesc);
  128. MouseState state = new MouseState();
  129. state.IsConnected = true;
  130. mice.Add(state);
  131. names.Add(deviceDesc);
  132. rawids.Add(new ContextHandle(dev.Device), mice.Count - 1);
  133. }
  134. }
  135. }
  136. }
  137. }
  138. }
  139. public bool ProcessMouseEvent(RawInput rin)
  140. {
  141. RawMouse raw = rin.Data.Mouse;
  142. ContextHandle handle = new ContextHandle(rin.Header.Device);
  143. MouseState mouse;
  144. if (!rawids.ContainsKey(handle))
  145. {
  146. RefreshDevices();
  147. }
  148. if (mice.Count == 0)
  149. return false;
  150. // Note:For some reason, my Microsoft Digital 3000 keyboard reports 0
  151. // as rin.Header.Device for the "zoom-in/zoom-out" buttons.
  152. // That's problematic, because no device has a "0" id.
  153. // As a workaround, we'll add those buttons to the first device (if any).
  154. int mouse_handle = rawids.ContainsKey(handle) ? rawids[handle] : 0;
  155. mouse = mice[mouse_handle];
  156. // Set and release capture of the mouse to fix http://www.opentk.com/node/2133, Patch by Artfunkel
  157. if ((raw.ButtonFlags & RawInputMouseState.LEFT_BUTTON_DOWN) != 0){
  158. mouse.EnableBit((int)MouseButton.Left);
  159. Functions.SetCapture(Window);
  160. }
  161. if ((raw.ButtonFlags & RawInputMouseState.LEFT_BUTTON_UP) != 0)
  162. {
  163. mouse.DisableBit((int)MouseButton.Left);
  164. Functions.ReleaseCapture();
  165. }
  166. if ((raw.ButtonFlags & RawInputMouseState.RIGHT_BUTTON_DOWN) != 0)
  167. {
  168. mouse.EnableBit((int)MouseButton.Right);
  169. Functions.SetCapture(Window);
  170. }
  171. if ((raw.ButtonFlags & RawInputMouseState.RIGHT_BUTTON_UP) != 0)
  172. {
  173. mouse.DisableBit((int)MouseButton.Right);
  174. Functions.ReleaseCapture();
  175. }
  176. if ((raw.ButtonFlags & RawInputMouseState.MIDDLE_BUTTON_DOWN) != 0)
  177. {
  178. mouse.EnableBit((int)MouseButton.Middle);
  179. Functions.SetCapture(Window);
  180. }
  181. if ((raw.ButtonFlags & RawInputMouseState.MIDDLE_BUTTON_UP) != 0)
  182. {
  183. mouse.DisableBit((int)MouseButton.Middle);
  184. Functions.ReleaseCapture();
  185. }
  186. if ((raw.ButtonFlags & RawInputMouseState.BUTTON_4_DOWN) != 0)
  187. {
  188. mouse.EnableBit((int)MouseButton.Button1);
  189. Functions.SetCapture(Window);
  190. }
  191. if ((raw.ButtonFlags & RawInputMouseState.BUTTON_4_UP) != 0)
  192. {
  193. mouse.DisableBit((int)MouseButton.Button1);
  194. Functions.ReleaseCapture();
  195. }
  196. if ((raw.ButtonFlags & RawInputMouseState.BUTTON_5_DOWN) != 0)
  197. {
  198. mouse.EnableBit((int)MouseButton.Button2);
  199. Functions.SetCapture(Window);
  200. }
  201. if ((raw.ButtonFlags & RawInputMouseState.BUTTON_5_UP) != 0)
  202. {
  203. mouse.DisableBit((int)MouseButton.Button2);
  204. Functions.ReleaseCapture();
  205. }
  206. if ((raw.ButtonFlags & RawInputMouseState.WHEEL) != 0)
  207. mouse.SetScrollRelative(0, (short)raw.ButtonData / 120.0f);
  208. if ((raw.ButtonFlags & RawInputMouseState.HWHEEL) != 0)
  209. mouse.SetScrollRelative((short)raw.ButtonData / 120.0f, 0);
  210. if ((raw.Flags & RawMouseFlags.MOUSE_MOVE_ABSOLUTE) != 0)
  211. {
  212. mouse.X = raw.LastX;
  213. mouse.Y = raw.LastY;
  214. }
  215. else
  216. { // Seems like MOUSE_MOVE_RELATIVE is the default, unless otherwise noted.
  217. mouse.X += raw.LastX;
  218. mouse.Y += raw.LastY;
  219. }
  220. lock (UpdateLock)
  221. {
  222. mice[mouse_handle] = mouse;
  223. return true;
  224. }
  225. }
  226. #endregion
  227. #region Private Members
  228. static string GetDeviceName(RawInputDeviceList dev)
  229. {
  230. // get name size
  231. uint size = 0;
  232. Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, IntPtr.Zero, ref size);
  233. // get actual name
  234. IntPtr name_ptr = Marshal.AllocHGlobal((IntPtr)size);
  235. Functions.GetRawInputDeviceInfo(dev.Device, RawInputDeviceInfoEnum.DEVICENAME, name_ptr, ref size);
  236. string name = Marshal.PtrToStringAnsi(name_ptr);
  237. Marshal.FreeHGlobal(name_ptr);
  238. return name;
  239. }
  240. static RegistryKey FindRegistryKey(string name)
  241. {
  242. if (name.Length < 4)
  243. return null;
  244. // remove the \??\
  245. name = name.Substring(4);
  246. string[] split = name.Split('#');
  247. if (split.Length < 3)
  248. return null;
  249. string id_01 = split[0]; // ACPI (Class code)
  250. string id_02 = split[1]; // PNP0303 (SubClass code)
  251. string id_03 = split[2]; // 3&13c0b0c5&0 (Protocol code)
  252. // The final part is the class GUID and is not needed here
  253. string findme = string.Format(
  254. @"System\CurrentControlSet\Enum\{0}\{1}\{2}",
  255. id_01, id_02, id_03);
  256. RegistryKey regkey = Registry.LocalMachine.OpenSubKey(findme);
  257. return regkey;
  258. }
  259. static void RegisterRawDevice(IntPtr window, string device)
  260. {
  261. RawInputDevice[] rid = new RawInputDevice[1];
  262. // Mouse is 1/2 (page/id). See http://www.microsoft.com/whdc/device/input/HID_HWID.mspx
  263. rid[0] = new RawInputDevice();
  264. rid[0].UsagePage = 1;
  265. rid[0].Usage = 2;
  266. rid[0].Flags = RawInputDeviceFlags.INPUTSINK;
  267. rid[0].Target = window;
  268. if (!Functions.RegisterRawInputDevices(rid, 1, API.RawInputDeviceSize))
  269. {
  270. Debug.Print("[Warning] Raw input registration failed with error: {0}. Device: {1}",
  271. Marshal.GetLastWin32Error(), rid[0].ToString());
  272. }
  273. else
  274. {
  275. Debug.Print("Registered mouse {0}", device);
  276. }
  277. }
  278. #endregion
  279. #region IMouseDriver2 Members
  280. public MouseState GetState()
  281. {
  282. lock (UpdateLock)
  283. {
  284. MouseState master = new MouseState();
  285. foreach (MouseState ms in mice)
  286. {
  287. master.MergeBits(ms);
  288. }
  289. return master;
  290. }
  291. }
  292. public MouseState GetState(int index)
  293. {
  294. lock (UpdateLock)
  295. {
  296. if (mice.Count > index)
  297. return mice[index];
  298. else
  299. return new MouseState();
  300. }
  301. }
  302. public void SetPosition(double x, double y)
  303. {
  304. Functions.SetCursorPos((int)x, (int)y);
  305. }
  306. public MouseState GetCursorState()
  307. {
  308. // For simplicity, get hardware state
  309. // and simply overwrite its x and y location
  310. POINT p = new POINT();
  311. Functions.GetCursorPos(ref p);
  312. var state = GetState();
  313. state.X = p.X;
  314. state.Y = p.Y;
  315. return state;
  316. }
  317. #endregion
  318. }
  319. }