Ver código fonte

add all files in the folder

add all files in the folder
zhiqiang.yu 10 meses atrás
pai
commit
be6b6a6bdd
100 arquivos alterados com 10173 adições e 0 exclusões
  1. BIN
      deployment/DreamCheeky.BigRedButton.dll
  2. BIN
      deployment/DreamCheeky.BigRedButton.pdb
  3. BIN
      deployment/HidLibrary.dll
  4. BIN
      deployment/HidLibrary.pdb
  5. BIN
      deployment/Test.Application.exe
  6. 6 0
      deployment/Test.Application.exe.config
  7. BIN
      deployment/Test.Application.pdb
  8. BIN
      deployment/WindowsInput.dll
  9. 2220 0
      deployment/WindowsInput.xml
  10. BIN
      deployment/nssm.exe
  11. 174 0
      dreamcheeky-big-red-button-dotnet/.gitignore
  12. 6 0
      dreamcheeky-big-red-button-dotnet/.nuget/NuGet.Config
  13. BIN
      dreamcheeky-big-red-button-dotnet/.nuget/NuGet.exe
  14. 144 0
      dreamcheeky-big-red-button-dotnet/.nuget/NuGet.targets
  15. BIN
      dreamcheeky-big-red-button-dotnet/.vs/DreamCheeky.BigRedButton/FileContentIndex/345b6fbc-d86e-4e93-b361-b1c53c42b6d2.vsidx
  16. BIN
      dreamcheeky-big-red-button-dotnet/.vs/DreamCheeky.BigRedButton/FileContentIndex/b78291ad-c800-4347-8632-b79d59a12a51.vsidx
  17. BIN
      dreamcheeky-big-red-button-dotnet/.vs/DreamCheeky.BigRedButton/FileContentIndex/c0639b96-b395-4948-94d6-05b2b3840688.vsidx
  18. 37 0
      dreamcheeky-big-red-button-dotnet/.vs/DreamCheeky.BigRedButton/v17/DocumentLayout.backup.json
  19. 37 0
      dreamcheeky-big-red-button-dotnet/.vs/DreamCheeky.BigRedButton/v17/DocumentLayout.json
  20. 35 0
      dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton.sln
  21. 0 0
      dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/.vs/DreamCheeky.BigRedButton.csproj.dtbcache.json
  22. 93 0
      dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/BigRedButton.cs
  23. 54 0
      dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/Device.cs
  24. 11 0
      dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/DeviceStatus.cs
  25. 72 0
      dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/DreamCheeky.BigRedButton.csproj
  26. 18 0
      dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/DreamCheeky.BigRedButton.nuspec
  27. 36 0
      dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/Properties/AssemblyInfo.cs
  28. 4 0
      dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/packages.config
  29. 21 0
      dreamcheeky-big-red-button-dotnet/LICENSE
  30. 33 0
      dreamcheeky-big-red-button-dotnet/README.md
  31. 0 0
      dreamcheeky-big-red-button-dotnet/Test.Application/.vs/Test.Application.csproj.dtbcache.json
  32. 6 0
      dreamcheeky-big-red-button-dotnet/Test.Application/App.config
  33. 57 0
      dreamcheeky-big-red-button-dotnet/Test.Application/Program.cs
  34. 36 0
      dreamcheeky-big-red-button-dotnet/Test.Application/Properties/AssemblyInfo.cs
  35. 70 0
      dreamcheeky-big-red-button-dotnet/Test.Application/Test.Application.csproj
  36. 4 0
      dreamcheeky-big-red-button-dotnet/Test.Application/packages.config
  37. 22 0
      dreamcheekyusb/.gitattributes
  38. 165 0
      dreamcheekyusb/.gitignore
  39. BIN
      dreamcheekyusb/.vs/DreamCheekyUSB/FileContentIndex/9e2b2be3-3b87-41bd-96ad-5624c44d72ab.vsidx
  40. 88 0
      dreamcheekyusb/.vs/DreamCheekyUSB/v17/DocumentLayout.backup.json
  41. 86 0
      dreamcheekyusb/.vs/DreamCheekyUSB/v17/DocumentLayout.json
  42. 7 0
      dreamcheekyusb/Documentation.md
  43. 57 0
      dreamcheekyusb/DreamCheekyBTN.md
  44. BIN
      dreamcheekyusb/DreamCheekyBTN/1347052316_system-red.ico
  45. 14 0
      dreamcheekyusb/DreamCheekyBTN/AutoHotkey.ahk
  46. 178 0
      dreamcheekyusb/DreamCheekyBTN/DreamCheekyBTN.cs
  47. 130 0
      dreamcheekyusb/DreamCheekyBTN/DreamCheekyBTN.csproj
  48. 50 0
      dreamcheekyusb/DreamCheekyBTN/DreamCheekyBigRedBTN.cs
  49. 121 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/AsyncResult.cs
  50. 153 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/HidDevice.cs
  51. 96 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/HidDeviceLoader.cs
  52. 107 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/HidSharp.csproj
  53. 334 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/HidStream.cs
  54. 119 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/HidManager.cs
  55. 51 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/HidSelector.cs
  56. 26 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Libusb/LibusbHidManager.cs
  57. 230 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Libusb/NativeMethods.cs
  58. 196 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Linux/LinuxHidDevice.cs
  59. 109 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Linux/LinuxHidManager.cs
  60. 269 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Linux/LinuxHidStream.cs
  61. 254 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Linux/NativeMethods.cs
  62. 109 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/MacOS/MacHidDevice.cs
  63. 95 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/MacOS/MacHidManager.cs
  64. 235 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/MacOS/MacHidStream.cs
  65. 318 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/MacOS/NativeMethods.cs
  66. 43 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Unsupported/UnsupportedHidManager.cs
  67. 73 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Utf8Marshaler.cs
  68. 401 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Windows/NativeMethods.cs
  69. 153 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Windows/WinHidDevice.cs
  70. 108 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Windows/WinHidManager.cs
  71. 185 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Windows/WinHidStream.cs
  72. 29 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/CollectionType.cs
  73. 63 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/DataMainItemFlags.cs
  74. 207 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/EncodedItem.cs
  75. 34 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/GlobalItemTag.cs
  76. 45 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/ItemType.cs
  77. 32 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/LocalItemTag.cs
  78. 27 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/MainItemTag.cs
  79. 45 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/IndexBase.cs
  80. 60 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/IndexList.cs
  81. 67 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/IndexRange.cs
  82. 48 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/LocalIndexes.cs
  83. 117 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/Report.cs
  84. 66 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/ReportCollection.cs
  85. 446 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/ReportDescriptorParser.cs
  86. 53 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/ReportMainItem.cs
  87. 209 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/ReportSegment.cs
  88. 25 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/ReportType.cs
  89. 34 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/CurrentUnit.cs
  90. 49 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/LengthUnit.cs
  91. 34 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/LuminousIntensityUnit.cs
  92. 39 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/MassUnit.cs
  93. 39 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/TemperatureUnit.cs
  94. 34 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/TimeUnit.cs
  95. 242 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/Unit.cs
  96. 53 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/UnitSystem.cs
  97. 50 0
      dreamcheekyusb/DreamCheekyBTN/HidSharp/Throw.cs
  98. 176 0
      dreamcheekyusb/DreamCheekyBTN/Program.cs
  99. 36 0
      dreamcheekyusb/DreamCheekyBTN/Properties/AssemblyInfo.cs
  100. 58 0
      dreamcheekyusb/DreamCheekyBTN/Readme.txt

BIN
deployment/DreamCheeky.BigRedButton.dll


BIN
deployment/DreamCheeky.BigRedButton.pdb


BIN
deployment/HidLibrary.dll


BIN
deployment/HidLibrary.pdb


BIN
deployment/Test.Application.exe


+ 6 - 0
deployment/Test.Application.exe.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
+    </startup>
+</configuration>

BIN
deployment/Test.Application.pdb


BIN
deployment/WindowsInput.dll


+ 2220 - 0
deployment/WindowsInput.xml

@@ -0,0 +1,2220 @@
+<?xml version="1.0"?>
+<doc>
+    <assembly>
+        <name>WindowsInput</name>
+    </assembly>
+    <members>
+        <member name="T:WindowsInput.IInputSimulator">
+            <summary>
+            The contract for a service that simulates Keyboard and Mouse input and Hardware Input Device state detection for the Windows Platform.
+            </summary>
+        </member>
+        <member name="P:WindowsInput.IInputSimulator.Keyboard">
+            <summary>
+            Gets the <see cref="T:WindowsInput.IKeyboardSimulator"/> instance for simulating Keyboard input.
+            </summary>
+            <value>The <see cref="T:WindowsInput.IKeyboardSimulator"/> instance.</value>
+        </member>
+        <member name="P:WindowsInput.IInputSimulator.Mouse">
+            <summary>
+            Gets the <see cref="T:WindowsInput.IMouseSimulator"/> instance for simulating Mouse input.
+            </summary>
+            <value>The <see cref="T:WindowsInput.IMouseSimulator"/> instance.</value>
+        </member>
+        <member name="P:WindowsInput.IInputSimulator.InputDeviceState">
+            <summary>
+            Gets the <see cref="T:WindowsInput.IInputDeviceStateAdaptor"/> instance for determining the state of the various input devices.
+            </summary>
+            <value>The <see cref="T:WindowsInput.IInputDeviceStateAdaptor"/> instance.</value>
+        </member>
+        <member name="T:WindowsInput.IMouseSimulator">
+            <summary>
+            The service contract for a mouse simulator for the Windows platform.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.MoveMouseBy(System.Int32,System.Int32)">
+            <summary>
+            Simulates mouse movement by the specified distance measured as a delta from the current mouse location in pixels.
+            </summary>
+            <param name="pixelDeltaX">The distance in pixels to move the mouse horizontally.</param>
+            <param name="pixelDeltaY">The distance in pixels to move the mouse vertically.</param>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.MoveMouseTo(System.Double,System.Double)">
+            <summary>
+            Simulates mouse movement to the specified location on the primary display device.
+            </summary>
+            <param name="absoluteX">The destination's absolute X-coordinate on the primary display device where 0 is the extreme left hand side of the display device and 65535 is the extreme right hand side of the display device.</param>
+            <param name="absoluteY">The destination's absolute Y-coordinate on the primary display device where 0 is the top of the display device and 65535 is the bottom of the display device.</param>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.MoveMouseToPositionOnVirtualDesktop(System.Double,System.Double)">
+            <summary>
+            Simulates mouse movement to the specified location on the Virtual Desktop which includes all active displays.
+            </summary>
+            <param name="absoluteX">The destination's absolute X-coordinate on the virtual desktop where 0 is the left hand side of the virtual desktop and 65535 is the extreme right hand side of the virtual desktop.</param>
+            <param name="absoluteY">The destination's absolute Y-coordinate on the virtual desktop where 0 is the top of the virtual desktop and 65535 is the bottom of the virtual desktop.</param>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.LeftButtonDown">
+            <summary>
+            Simulates a mouse left button down gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.LeftButtonUp">
+            <summary>
+            Simulates a mouse left button up gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.LeftButtonClick">
+            <summary>
+            Simulates a mouse left button click gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.LeftButtonDoubleClick">
+            <summary>
+            Simulates a mouse left button double-click gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.RightButtonDown">
+            <summary>
+            Simulates a mouse right button down gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.RightButtonUp">
+            <summary>
+            Simulates a mouse right button up gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.RightButtonClick">
+            <summary>
+            Simulates a mouse right button click gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.RightButtonDoubleClick">
+            <summary>
+            Simulates a mouse right button double-click gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.XButtonDown(System.Int32)">
+            <summary>
+            Simulates a mouse X button down gesture.
+            </summary>
+            <param name="buttonId">The button id.</param>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.XButtonUp(System.Int32)">
+            <summary>
+            Simulates a mouse X button up gesture.
+            </summary>
+            <param name="buttonId">The button id.</param>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.XButtonClick(System.Int32)">
+            <summary>
+            Simulates a mouse X button click gesture.
+            </summary>
+            <param name="buttonId">The button id.</param>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.XButtonDoubleClick(System.Int32)">
+            <summary>
+            Simulates a mouse X button double-click gesture.
+            </summary>
+            <param name="buttonId">The button id.</param>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.VerticalScroll(System.Int32)">
+            <summary>
+            Simulates mouse vertical wheel scroll gesture.
+            </summary>
+            <param name="scrollAmountInClicks">The amount to scroll in clicks. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user.</param>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.HorizontalScroll(System.Int32)">
+            <summary>
+            Simulates a mouse horizontal wheel scroll gesture. Supported by Windows Vista and later.
+            </summary>
+            <param name="scrollAmountInClicks">The amount to scroll in clicks. A positive value indicates that the wheel was rotated to the right; a negative value indicates that the wheel was rotated to the left.</param>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.Sleep(System.Int32)">
+            <summary>
+            Sleeps the executing thread to create a pause between simulated inputs.
+            </summary>
+            <param name="millsecondsTimeout">The number of milliseconds to wait.</param>
+        </member>
+        <member name="M:WindowsInput.IMouseSimulator.Sleep(System.TimeSpan)">
+            <summary>
+            Sleeps the executing thread to create a pause between simulated inputs.
+            </summary>
+            <param name="timeout">The time to wait.</param>
+        </member>
+        <member name="P:WindowsInput.IMouseSimulator.Keyboard">
+            <summary>
+            Gets the <see cref="T:WindowsInput.IKeyboardSimulator"/> instance for simulating Keyboard input.
+            </summary>
+            <value>The <see cref="T:WindowsInput.IKeyboardSimulator"/> instance.</value>
+        </member>
+        <member name="T:WindowsInput.InputSimulator">
+            <summary>
+            Implements the <see cref="T:WindowsInput.IInputSimulator"/> interface to simulate Keyboard and Mouse input and provide the state of those input devices.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.InputSimulator._keyboardSimulator">
+            <summary>
+            The <see cref="T:WindowsInput.IKeyboardSimulator"/> instance to use for simulating keyboard input.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.InputSimulator._mouseSimulator">
+            <summary>
+            The <see cref="T:WindowsInput.IMouseSimulator"/> instance to use for simulating mouse input.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.InputSimulator._inputDeviceState">
+            <summary>
+            The <see cref="T:WindowsInput.IInputDeviceStateAdaptor"/> instance to use for interpreting the state of the input devices.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.InputSimulator.#ctor(WindowsInput.IKeyboardSimulator,WindowsInput.IMouseSimulator,WindowsInput.IInputDeviceStateAdaptor)">
+            <summary>
+            Initializes a new instance of the <see cref="T:WindowsInput.InputSimulator"/> class using the specified <see cref="T:WindowsInput.IKeyboardSimulator"/>, <see cref="T:WindowsInput.IMouseSimulator"/> and <see cref="T:WindowsInput.IInputDeviceStateAdaptor"/> instances.
+            </summary>
+            <param name="keyboardSimulator">The <see cref="T:WindowsInput.IKeyboardSimulator"/> instance to use for simulating keyboard input.</param>
+            <param name="mouseSimulator">The <see cref="T:WindowsInput.IMouseSimulator"/> instance to use for simulating mouse input.</param>
+            <param name="inputDeviceStateAdaptor">The <see cref="T:WindowsInput.IInputDeviceStateAdaptor"/> instance to use for interpreting the state of input devices.</param>
+        </member>
+        <member name="M:WindowsInput.InputSimulator.#ctor">
+            <summary>
+            Initializes a new instance of the <see cref="T:WindowsInput.InputSimulator"/> class using the default <see cref="T:WindowsInput.KeyboardSimulator"/>, <see cref="T:WindowsInput.MouseSimulator"/> and <see cref="T:WindowsInput.WindowsInputDeviceStateAdaptor"/> instances.
+            </summary>
+        </member>
+        <member name="P:WindowsInput.InputSimulator.Keyboard">
+            <summary>
+            Gets the <see cref="T:WindowsInput.IKeyboardSimulator"/> instance for simulating Keyboard input.
+            </summary>
+            <value>The <see cref="T:WindowsInput.IKeyboardSimulator"/> instance.</value>
+        </member>
+        <member name="P:WindowsInput.InputSimulator.Mouse">
+            <summary>
+            Gets the <see cref="T:WindowsInput.IMouseSimulator"/> instance for simulating Mouse input.
+            </summary>
+            <value>The <see cref="T:WindowsInput.IMouseSimulator"/> instance.</value>
+        </member>
+        <member name="P:WindowsInput.InputSimulator.InputDeviceState">
+            <summary>
+            Gets the <see cref="T:WindowsInput.IInputDeviceStateAdaptor"/> instance for determining the state of the various input devices.
+            </summary>
+            <value>The <see cref="T:WindowsInput.IInputDeviceStateAdaptor"/> instance.</value>
+        </member>
+        <member name="T:WindowsInput.MouseButton">
+            <summary>
+            The mouse button
+            </summary>
+        </member>
+        <member name="F:WindowsInput.MouseButton.LeftButton">
+            <summary>
+            Left mouse button
+            </summary>
+        </member>
+        <member name="F:WindowsInput.MouseButton.MiddleButton">
+            <summary>
+            Middle mouse button
+            </summary>
+        </member>
+        <member name="F:WindowsInput.MouseButton.RightButton">
+            <summary>
+            Right moust button
+            </summary>
+        </member>
+        <member name="T:WindowsInput.MouseSimulator">
+            <summary>
+            Implements the <see cref="T:WindowsInput.IMouseSimulator"/> interface by calling the an <see cref="T:WindowsInput.IInputMessageDispatcher"/> to simulate Mouse gestures.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.MouseSimulator._messageDispatcher">
+            <summary>
+            The instance of the <see cref="T:WindowsInput.IInputMessageDispatcher"/> to use for dispatching <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.#ctor(WindowsInput.IInputSimulator)">
+            <summary>
+            Initializes a new instance of the <see cref="T:WindowsInput.MouseSimulator"/> class using an instance of a <see cref="T:WindowsInput.WindowsInputMessageDispatcher"/> for dispatching <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+            <param name="inputSimulator">The <see cref="T:WindowsInput.IInputSimulator"/> that owns this instance.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.#ctor(WindowsInput.IInputSimulator,WindowsInput.IInputMessageDispatcher)">
+            <summary>
+            Initializes a new instance of the <see cref="T:WindowsInput.MouseSimulator"/> class using the specified <see cref="T:WindowsInput.IInputMessageDispatcher"/> for dispatching <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+            <param name="inputSimulator">The <see cref="T:WindowsInput.IInputSimulator"/> that owns this instance.</param>
+            <param name="messageDispatcher">The <see cref="T:WindowsInput.IInputMessageDispatcher"/> to use for dispatching <see cref="T:WindowsInput.Native.INPUT"/> messages.</param>
+            <exception cref="T:System.InvalidOperationException">If null is passed as the <paramref name="messageDispatcher"/>.</exception>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.SendSimulatedInput(WindowsInput.Native.INPUT[])">
+            <summary>
+            Sends the list of <see cref="T:WindowsInput.Native.INPUT"/> messages using the <see cref="T:WindowsInput.IInputMessageDispatcher"/> instance.
+            </summary>
+            <param name="inputList">The <see cref="T:System.Array"/> of <see cref="T:WindowsInput.Native.INPUT"/> messages to send.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.MoveMouseBy(System.Int32,System.Int32)">
+            <summary>
+            Simulates mouse movement by the specified distance measured as a delta from the current mouse location in pixels.
+            </summary>
+            <param name="pixelDeltaX">The distance in pixels to move the mouse horizontally.</param>
+            <param name="pixelDeltaY">The distance in pixels to move the mouse vertically.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.MoveMouseTo(System.Double,System.Double)">
+            <summary>
+            Simulates mouse movement to the specified location on the primary display device.
+            </summary>
+            <param name="absoluteX">The destination's absolute X-coordinate on the primary display device where 0 is the extreme left hand side of the display device and 65535 is the extreme right hand side of the display device.</param>
+            <param name="absoluteY">The destination's absolute Y-coordinate on the primary display device where 0 is the top of the display device and 65535 is the bottom of the display device.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.MoveMouseToPositionOnVirtualDesktop(System.Double,System.Double)">
+            <summary>
+            Simulates mouse movement to the specified location on the Virtual Desktop which includes all active displays.
+            </summary>
+            <param name="absoluteX">The destination's absolute X-coordinate on the virtual desktop where 0 is the left hand side of the virtual desktop and 65535 is the extreme right hand side of the virtual desktop.</param>
+            <param name="absoluteY">The destination's absolute Y-coordinate on the virtual desktop where 0 is the top of the virtual desktop and 65535 is the bottom of the virtual desktop.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.LeftButtonDown">
+            <summary>
+            Simulates a mouse left button down gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.LeftButtonUp">
+            <summary>
+            Simulates a mouse left button up gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.LeftButtonClick">
+            <summary>
+            Simulates a mouse left-click gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.LeftButtonDoubleClick">
+            <summary>
+            Simulates a mouse left button double-click gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.RightButtonDown">
+            <summary>
+            Simulates a mouse right button down gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.RightButtonUp">
+            <summary>
+            Simulates a mouse right button up gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.RightButtonClick">
+            <summary>
+            Simulates a mouse right button click gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.RightButtonDoubleClick">
+            <summary>
+            Simulates a mouse right button double-click gesture.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.XButtonDown(System.Int32)">
+            <summary>
+            Simulates a mouse X button down gesture.
+            </summary>
+            <param name="buttonId">The button id.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.XButtonUp(System.Int32)">
+            <summary>
+            Simulates a mouse X button up gesture.
+            </summary>
+            <param name="buttonId">The button id.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.XButtonClick(System.Int32)">
+            <summary>
+            Simulates a mouse X button click gesture.
+            </summary>
+            <param name="buttonId">The button id.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.XButtonDoubleClick(System.Int32)">
+            <summary>
+            Simulates a mouse X button double-click gesture.
+            </summary>
+            <param name="buttonId">The button id.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.VerticalScroll(System.Int32)">
+            <summary>
+            Simulates mouse vertical wheel scroll gesture.
+            </summary>
+            <param name="scrollAmountInClicks">The amount to scroll in clicks. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.HorizontalScroll(System.Int32)">
+            <summary>
+            Simulates a mouse horizontal wheel scroll gesture. Supported by Windows Vista and later.
+            </summary>
+            <param name="scrollAmountInClicks">The amount to scroll in clicks. A positive value indicates that the wheel was rotated to the right; a negative value indicates that the wheel was rotated to the left.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.Sleep(System.Int32)">
+            <summary>
+            Sleeps the executing thread to create a pause between simulated inputs.
+            </summary>
+            <param name="millsecondsTimeout">The number of milliseconds to wait.</param>
+        </member>
+        <member name="M:WindowsInput.MouseSimulator.Sleep(System.TimeSpan)">
+            <summary>
+            Sleeps the executing thread to create a pause between simulated inputs.
+            </summary>
+            <param name="timeout">The time to wait.</param>
+        </member>
+        <member name="P:WindowsInput.MouseSimulator.Keyboard">
+            <summary>
+            Gets the <see cref="T:WindowsInput.IKeyboardSimulator"/> instance for simulating Keyboard input.
+            </summary>
+            <value>The <see cref="T:WindowsInput.IKeyboardSimulator"/> instance.</value>
+        </member>
+        <member name="T:WindowsInput.Native.NativeMethods">
+            <summary>
+            References all of the Native Windows API methods for the WindowsInput functionality.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.Native.NativeMethods.GetAsyncKeyState(System.UInt16)">
+            <summary>
+            The GetAsyncKeyState function determines whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyState. (See: http://msdn.microsoft.com/en-us/library/ms646293(VS.85).aspx)
+            </summary>
+            <param name="virtualKeyCode">Specifies one of 256 possible virtual-key codes. For more information, see Virtual Key Codes. Windows NT/2000/XP: You can use left- and right-distinguishing constants to specify certain keys. See the Remarks section for further information.</param>
+            <returns>
+            If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState. However, you should not rely on this last behavior; for more information, see the Remarks. 
+            
+            Windows NT/2000/XP: The return value is zero for the following cases: 
+            - The current desktop is not the active desktop
+            - The foreground thread belongs to another process and the desktop does not allow the hook or the journal record.
+            
+            Windows 95/98/Me: The return value is the global asynchronous key state for each virtual key. The system does not check which thread has the keyboard focus.
+            
+            Windows 95/98/Me: Windows 95 does not support the left- and right-distinguishing constants. If you call GetAsyncKeyState with these constants, the return value is zero. 
+            </returns>
+            <remarks>
+            The GetAsyncKeyState function works with mouse buttons. However, it checks on the state of the physical mouse buttons, not on the logical mouse buttons that the physical buttons are mapped to. For example, the call GetAsyncKeyState(VK_LBUTTON) always returns the state of the left physical mouse button, regardless of whether it is mapped to the left or right logical mouse button. You can determine the system's current mapping of physical mouse buttons to logical mouse buttons by calling 
+            Copy CodeGetSystemMetrics(SM_SWAPBUTTON) which returns TRUE if the mouse buttons have been swapped.
+            
+            Although the least significant bit of the return value indicates whether the key has been pressed since the last query, due to the pre-emptive multitasking nature of Windows, another application can call GetAsyncKeyState and receive the "recently pressed" bit instead of your application. The behavior of the least significant bit of the return value is retained strictly for compatibility with 16-bit Windows applications (which are non-preemptive) and should not be relied upon.
+            
+            You can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the vKey parameter. This gives the state of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. 
+            
+            Windows NT/2000/XP: You can use the following virtual-key code constants as values for vKey to distinguish between the left and right instances of those keys. 
+            
+            Code Meaning 
+            VK_LSHIFT Left-shift key. 
+            VK_RSHIFT Right-shift key. 
+            VK_LCONTROL Left-control key. 
+            VK_RCONTROL Right-control key. 
+            VK_LMENU Left-menu key. 
+            VK_RMENU Right-menu key. 
+            
+            These left- and right-distinguishing constants are only available when you call the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 
+            </remarks>
+        </member>
+        <member name="M:WindowsInput.Native.NativeMethods.GetKeyState(System.UInt16)">
+            <summary>
+            The GetKeyState function retrieves the status of the specified virtual key. The status specifies whether the key is up, down, or toggled (on, off alternating each time the key is pressed). (See: http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx)
+            </summary>
+            <param name="virtualKeyCode">
+            Specifies a virtual key. If the desired virtual key is a letter or digit (A through Z, a through z, or 0 through 9), nVirtKey must be set to the ASCII value of that character. For other keys, it must be a virtual-key code. 
+            If a non-English keyboard layout is used, virtual keys with values in the range ASCII A through Z and 0 through 9 are used to specify most of the character keys. For example, for the German keyboard layout, the virtual key of value ASCII O (0x4F) refers to the "o" key, whereas VK_OEM_1 refers to the "o with umlaut" key.
+            </param>
+            <returns>
+            The return value specifies the status of the specified virtual key, as follows: 
+            If the high-order bit is 1, the key is down; otherwise, it is up.
+            If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled.
+            </returns>
+            <remarks>
+            The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information. 
+            An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated. 
+            To retrieve state information for all the virtual keys, use the GetKeyboardState function. 
+            An application can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the nVirtKey parameter. This gives the status of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. An application can also use the following virtual-key code constants as values for nVirtKey to distinguish between the left and right instances of those keys. 
+            VK_LSHIFT
+            VK_RSHIFT
+            VK_LCONTROL
+            VK_RCONTROL
+            VK_LMENU
+            VK_RMENU
+            
+            These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 
+            </remarks>
+        </member>
+        <member name="M:WindowsInput.Native.NativeMethods.SendInput(System.UInt32,WindowsInput.Native.INPUT[],System.Int32)">
+            <summary>
+            The SendInput function synthesizes keystrokes, mouse motions, and button clicks.
+            </summary>
+            <param name="numberOfInputs">Number of structures in the Inputs array.</param>
+            <param name="inputs">Pointer to an array of INPUT structures. Each structure represents an event to be inserted into the keyboard or mouse input stream.</param>
+            <param name="sizeOfInputStructure">Specifies the size, in bytes, of an INPUT structure. If cbSize is not the size of an INPUT structure, the function fails.</param>
+            <returns>The function returns the number of events that it successfully inserted into the keyboard or mouse input stream. If the function returns zero, the input was already blocked by another thread. To get extended error information, call GetLastError.Microsoft Windows Vista. This function fails when it is blocked by User Interface Privilege Isolation (UIPI). Note that neither GetLastError nor the return value will indicate the failure was caused by UIPI blocking.</returns>
+            <remarks>
+            Microsoft Windows Vista. This function is subject to UIPI. Applications are permitted to inject input only into applications that are at an equal or lesser integrity level.
+            The SendInput function inserts the events in the INPUT structures serially into the keyboard or mouse input stream. These events are not interspersed with other keyboard or mouse input events inserted either by the user (with the keyboard or mouse) or by calls to keybd_event, mouse_event, or other calls to SendInput.
+            This function does not reset the keyboard's current state. Any keys that are already pressed when the function is called might interfere with the events that this function generates. To avoid this problem, check the keyboard's state with the GetAsyncKeyState function and correct as necessary.
+            </remarks>
+        </member>
+        <member name="M:WindowsInput.Native.NativeMethods.GetMessageExtraInfo">
+            <summary>
+            The GetMessageExtraInfo function retrieves the extra message information for the current thread. Extra message information is an application- or driver-defined value associated with the current thread's message queue. 
+            </summary>
+            <returns></returns>
+            <remarks>To set a thread's extra message information, use the SetMessageExtraInfo function. </remarks>
+        </member>
+        <member name="T:WindowsInput.Native.HARDWAREINPUT">
+            <summary>
+            The HARDWAREINPUT structure contains information about a simulated message generated by an input device other than a keyboard or mouse.  (see: http://msdn.microsoft.com/en-us/library/ms646269(VS.85).aspx)
+            Declared in Winuser.h, include Windows.h
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.HARDWAREINPUT.Msg">
+            <summary>
+            Value specifying the message generated by the input hardware. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.HARDWAREINPUT.ParamL">
+            <summary>
+            Specifies the low-order word of the lParam parameter for uMsg. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.HARDWAREINPUT.ParamH">
+            <summary>
+            Specifies the high-order word of the lParam parameter for uMsg. 
+            </summary>
+        </member>
+        <member name="T:WindowsInput.IInputDeviceStateAdaptor">
+            <summary>
+            The contract for a service that interprets the state of input devices.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IInputDeviceStateAdaptor.IsKeyDown(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Determines whether the specified key is up or down.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+            <returns>
+            	<c>true</c> if the key is down; otherwise, <c>false</c>.
+            </returns>
+        </member>
+        <member name="M:WindowsInput.IInputDeviceStateAdaptor.IsKeyUp(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Determines whether the specified key is up or down.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+            <returns>
+            	<c>true</c> if the key is up; otherwise, <c>false</c>.
+            </returns>
+        </member>
+        <member name="M:WindowsInput.IInputDeviceStateAdaptor.IsHardwareKeyDown(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Determines whether the physical key is up or down at the time the function is called regardless of whether the application thread has read the keyboard event from the message pump.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+            <returns>
+            	<c>true</c> if the key is down; otherwise, <c>false</c>.
+            </returns>
+        </member>
+        <member name="M:WindowsInput.IInputDeviceStateAdaptor.IsHardwareKeyUp(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Determines whether the physical key is up or down at the time the function is called regardless of whether the application thread has read the keyboard event from the message pump.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+            <returns>
+            	<c>true</c> if the key is up; otherwise, <c>false</c>.
+            </returns>
+        </member>
+        <member name="M:WindowsInput.IInputDeviceStateAdaptor.IsTogglingKeyInEffect(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Determines whether the toggling key is toggled on (in-effect) or not.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+            <returns>
+            	<c>true</c> if the toggling key is toggled on (in-effect); otherwise, <c>false</c>.
+            </returns>
+        </member>
+        <member name="T:WindowsInput.IInputMessageDispatcher">
+            <summary>
+            The contract for a service that dispatches <see cref="T:WindowsInput.Native.INPUT"/> messages to the appropriate destination.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IInputMessageDispatcher.DispatchInput(WindowsInput.Native.INPUT[])">
+            <summary>
+            Dispatches the specified list of <see cref="T:WindowsInput.Native.INPUT"/> messages in their specified order.
+            </summary>
+            <param name="inputs">The list of <see cref="T:WindowsInput.Native.INPUT"/> messages to be dispatched.</param>
+            <exception cref="T:System.ArgumentException">If the <paramref name="inputs"/> array is empty.</exception>
+            <exception cref="T:System.ArgumentNullException">If the <paramref name="inputs"/> array is null.</exception>
+            <exception cref="T:System.Exception">If the any of the commands in the <paramref name="inputs"/> array could not be sent successfully.</exception>
+        </member>
+        <member name="T:WindowsInput.IKeyboardSimulator">
+            <summary>
+            The service contract for a keyboard simulator for the Windows platform.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.KeyDown(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Simulates the key down gesture for the specified key.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.KeyPress(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Simulates the key press gesture for the specified key.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.KeyPress(WindowsInput.Native.VirtualKeyCode[])">
+            <summary>
+            Simulates a key press for each of the specified key codes in the order they are specified.
+            </summary>
+            <param name="keyCodes"></param>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.KeyUp(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Simulates the key up gesture for the specified key.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.ModifiedKeyStroke(System.Collections.Generic.IEnumerable{WindowsInput.Native.VirtualKeyCode},System.Collections.Generic.IEnumerable{WindowsInput.Native.VirtualKeyCode})">
+            <summary>
+            Simulates a modified keystroke where there are multiple modifiers and multiple keys like CTRL-ALT-K-C where CTRL and ALT are the modifierKeys and K and C are the keys.
+            The flow is Modifiers KeyDown in order, Keys Press in order, Modifiers KeyUp in reverse order.
+            </summary>
+            <param name="modifierKeyCodes">The list of <see cref="T:WindowsInput.Native.VirtualKeyCode"/>s for the modifier keys.</param>
+            <param name="keyCodes">The list of <see cref="T:WindowsInput.Native.VirtualKeyCode"/>s for the keys to simulate.</param>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.ModifiedKeyStroke(System.Collections.Generic.IEnumerable{WindowsInput.Native.VirtualKeyCode},WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Simulates a modified keystroke where there are multiple modifiers and one key like CTRL-ALT-C where CTRL and ALT are the modifierKeys and C is the key.
+            The flow is Modifiers KeyDown in order, Key Press, Modifiers KeyUp in reverse order.
+            </summary>
+            <param name="modifierKeyCodes">The list of <see cref="T:WindowsInput.Native.VirtualKeyCode"/>s for the modifier keys.</param>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.ModifiedKeyStroke(WindowsInput.Native.VirtualKeyCode,System.Collections.Generic.IEnumerable{WindowsInput.Native.VirtualKeyCode})">
+            <summary>
+            Simulates a modified keystroke where there is one modifier and multiple keys like CTRL-K-C where CTRL is the modifierKey and K and C are the keys.
+            The flow is Modifier KeyDown, Keys Press in order, Modifier KeyUp.
+            </summary>
+            <param name="modifierKey">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the modifier key.</param>
+            <param name="keyCodes">The list of <see cref="T:WindowsInput.Native.VirtualKeyCode"/>s for the keys to simulate.</param>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.ModifiedKeyStroke(WindowsInput.Native.VirtualKeyCode,WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Simulates a simple modified keystroke like CTRL-C where CTRL is the modifierKey and C is the key.
+            The flow is Modifier KeyDown, Key Press, Modifier KeyUp.
+            </summary>
+            <param name="modifierKeyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the  modifier key.</param>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.TextEntry(System.String)">
+            <summary>
+            Simulates uninterrupted text entry via the keyboard.
+            </summary>
+            <param name="text">The text to be simulated.</param>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.TextEntry(System.Char)">
+            <summary>
+            Simulates a single character text entry via the keyboard.
+            </summary>
+            <param name="character">The unicode character to be simulated.</param>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.Sleep(System.Int32)">
+            <summary>
+            Sleeps the executing thread to create a pause between simulated inputs.
+            </summary>
+            <param name="millsecondsTimeout">The number of milliseconds to wait.</param>
+        </member>
+        <member name="M:WindowsInput.IKeyboardSimulator.Sleep(System.TimeSpan)">
+            <summary>
+            Sleeps the executing thread to create a pause between simulated inputs.
+            </summary>
+            <param name="timeout">The time to wait.</param>
+        </member>
+        <member name="P:WindowsInput.IKeyboardSimulator.Mouse">
+            <summary>
+            Gets the <see cref="T:WindowsInput.IMouseSimulator"/> instance for simulating Mouse input.
+            </summary>
+            <value>The <see cref="T:WindowsInput.IMouseSimulator"/> instance.</value>
+        </member>
+        <member name="T:WindowsInput.Native.INPUT">
+            <summary>
+            The INPUT structure is used by SendInput to store information for synthesizing input events such as keystrokes, mouse movement, and mouse clicks. (see: http://msdn.microsoft.com/en-us/library/ms646270(VS.85).aspx)
+            Declared in Winuser.h, include Windows.h
+            </summary>
+            <remarks>
+            This structure contains information identical to that used in the parameter list of the keybd_event or mouse_event function.
+            Windows 2000/XP: INPUT_KEYBOARD supports nonkeyboard input methods, such as handwriting recognition or voice recognition, as if it were text input by using the KEYEVENTF_UNICODE flag. For more information, see the remarks section of KEYBDINPUT.
+            </remarks>
+        </member>
+        <member name="F:WindowsInput.Native.INPUT.Type">
+            <summary>
+            Specifies the type of the input event. This member can be one of the following values. 
+            <see cref="F:WindowsInput.Native.InputType.Mouse"/> - The event is a mouse event. Use the mi structure of the union.
+            <see cref="F:WindowsInput.Native.InputType.Keyboard"/> - The event is a keyboard event. Use the ki structure of the union.
+            <see cref="F:WindowsInput.Native.InputType.Hardware"/> - Windows 95/98/Me: The event is from input hardware other than a keyboard or mouse. Use the hi structure of the union.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.INPUT.Data">
+            <summary>
+            The data structure that contains information about the simulated Mouse, Keyboard or Hardware event.
+            </summary>
+        </member>
+        <member name="T:WindowsInput.InputBuilder">
+            <summary>
+            A helper class for building a list of <see cref="T:WindowsInput.Native.INPUT"/> messages ready to be sent to the native Windows API.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.InputBuilder._inputList">
+            <summary>
+            The public list of <see cref="T:WindowsInput.Native.INPUT"/> messages being built by this instance.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.#ctor">
+            <summary>
+            Initializes a new instance of the <see cref="T:WindowsInput.InputBuilder"/> class.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.ToArray">
+            <summary>
+            Returns the list of <see cref="T:WindowsInput.Native.INPUT"/> messages as a <see cref="T:System.Array"/> of <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+            <returns>The <see cref="T:System.Array"/> of <see cref="T:WindowsInput.Native.INPUT"/> messages.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.GetEnumerator">
+            <summary>
+            Returns an enumerator that iterates through the list of <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+            <returns>
+            A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the list of <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </returns>
+            <filterpriority>1</filterpriority>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.System#Collections#IEnumerable#GetEnumerator">
+            <summary>
+            Returns an enumerator that iterates through the list of <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+            <returns>
+            An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the list of <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </returns>
+            <filterpriority>2</filterpriority>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.IsExtendedKey(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Determines if the <see cref="T:WindowsInput.Native.VirtualKeyCode"/> is an ExtendedKey
+            </summary>
+            <param name="keyCode">The key code.</param>
+            <returns>true if the key code is an extended key; otherwise, false.</returns>
+            <remarks>
+            The extended keys consist of the ALT and CTRL keys on the right-hand side of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN, and arrow keys in the clusters to the left of the numeric keypad; the NUM LOCK key; the BREAK (CTRL+PAUSE) key; the PRINT SCRN key; and the divide (/) and ENTER keys in the numeric keypad.
+            
+            See http://msdn.microsoft.com/en-us/library/ms646267(v=vs.85).aspx Section "Extended-Key Flag"
+            </remarks>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddKeyDown(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Adds a key down to the list of <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/>.</param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddKeyUp(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Adds a key up to the list of <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/>.</param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddKeyPress(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Adds a key press to the list of <see cref="T:WindowsInput.Native.INPUT"/> messages which is equivalent to a key down followed by a key up.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/>.</param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddCharacter(System.Char)">
+            <summary>
+            Adds the character to the list of <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+            <param name="character">The <see cref="T:System.Char"/> to be added to the list of <see cref="T:WindowsInput.Native.INPUT"/> messages.</param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddCharacters(System.Collections.Generic.IEnumerable{System.Char})">
+            <summary>
+            Adds all of the characters in the specified <see cref="T:System.Collections.Generic.IEnumerable`1"/> of <see cref="T:System.Char"/>.
+            </summary>
+            <param name="characters">The characters to add.</param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddCharacters(System.String)">
+            <summary>
+            Adds the characters in the specified <see cref="T:System.String"/>.
+            </summary>
+            <param name="characters">The string of <see cref="T:System.Char"/> to add.</param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddRelativeMouseMovement(System.Int32,System.Int32)">
+            <summary>
+            Moves the mouse relative to its current position.
+            </summary>
+            <param name="x"></param>
+            <param name="y"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddAbsoluteMouseMovement(System.Int32,System.Int32)">
+            <summary>
+            Move the mouse to an absolute position.
+            </summary>
+            <param name="absoluteX"></param>
+            <param name="absoluteY"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddAbsoluteMouseMovementOnVirtualDesktop(System.Int32,System.Int32)">
+            <summary>
+            Move the mouse to the absolute position on the virtual desktop.
+            </summary>
+            <param name="absoluteX"></param>
+            <param name="absoluteY"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddMouseButtonDown(WindowsInput.MouseButton)">
+            <summary>
+            Adds a mouse button down for the specified button.
+            </summary>
+            <param name="button"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddMouseXButtonDown(System.Int32)">
+            <summary>
+            Adds a mouse button down for the specified button.
+            </summary>
+            <param name="xButtonId"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddMouseButtonUp(WindowsInput.MouseButton)">
+            <summary>
+            Adds a mouse button up for the specified button.
+            </summary>
+            <param name="button"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddMouseXButtonUp(System.Int32)">
+            <summary>
+            Adds a mouse button up for the specified button.
+            </summary>
+            <param name="xButtonId"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddMouseButtonClick(WindowsInput.MouseButton)">
+            <summary>
+            Adds a single click of the specified button.
+            </summary>
+            <param name="button"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddMouseXButtonClick(System.Int32)">
+            <summary>
+            Adds a single click of the specified button.
+            </summary>
+            <param name="xButtonId"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddMouseButtonDoubleClick(WindowsInput.MouseButton)">
+            <summary>
+            Adds a double click of the specified button.
+            </summary>
+            <param name="button"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddMouseXButtonDoubleClick(System.Int32)">
+            <summary>
+            Adds a double click of the specified button.
+            </summary>
+            <param name="xButtonId"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddMouseVerticalWheelScroll(System.Int32)">
+            <summary>
+            Scroll the vertical mouse wheel by the specified amount.
+            </summary>
+            <param name="scrollAmount"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="M:WindowsInput.InputBuilder.AddMouseHorizontalWheelScroll(System.Int32)">
+            <summary>
+            Scroll the horizontal mouse wheel by the specified amount.
+            </summary>
+            <param name="scrollAmount"></param>
+            <returns>This <see cref="T:WindowsInput.InputBuilder"/> instance.</returns>
+        </member>
+        <member name="P:WindowsInput.InputBuilder.Item(System.Int32)">
+            <summary>
+            Gets the <see cref="T:WindowsInput.Native.INPUT"/> at the specified position.
+            </summary>
+            <value>The <see cref="T:WindowsInput.Native.INPUT"/> message at the specified position.</value>
+        </member>
+        <member name="T:WindowsInput.KeyboardSimulator">
+            <summary>
+            Implements the <see cref="T:WindowsInput.IKeyboardSimulator"/> interface by calling the an <see cref="T:WindowsInput.IInputMessageDispatcher"/> to simulate Keyboard gestures.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.KeyboardSimulator._messageDispatcher">
+            <summary>
+            The instance of the <see cref="T:WindowsInput.IInputMessageDispatcher"/> to use for dispatching <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.#ctor(WindowsInput.IInputSimulator)">
+            <summary>
+            Initializes a new instance of the <see cref="T:WindowsInput.KeyboardSimulator"/> class using an instance of a <see cref="T:WindowsInput.WindowsInputMessageDispatcher"/> for dispatching <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+            <param name="inputSimulator">The <see cref="T:WindowsInput.IInputSimulator"/> that owns this instance.</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.#ctor(WindowsInput.IInputSimulator,WindowsInput.IInputMessageDispatcher)">
+            <summary>
+            Initializes a new instance of the <see cref="T:WindowsInput.KeyboardSimulator"/> class using the specified <see cref="T:WindowsInput.IInputMessageDispatcher"/> for dispatching <see cref="T:WindowsInput.Native.INPUT"/> messages.
+            </summary>
+            <param name="inputSimulator">The <see cref="T:WindowsInput.IInputSimulator"/> that owns this instance.</param>
+            <param name="messageDispatcher">The <see cref="T:WindowsInput.IInputMessageDispatcher"/> to use for dispatching <see cref="T:WindowsInput.Native.INPUT"/> messages.</param>
+            <exception cref="T:System.InvalidOperationException">If null is passed as the <paramref name="messageDispatcher"/>.</exception>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.SendSimulatedInput(WindowsInput.Native.INPUT[])">
+            <summary>
+            Sends the list of <see cref="T:WindowsInput.Native.INPUT"/> messages using the <see cref="T:WindowsInput.IInputMessageDispatcher"/> instance.
+            </summary>
+            <param name="inputList">The <see cref="T:System.Array"/> of <see cref="T:WindowsInput.Native.INPUT"/> messages to send.</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.KeyDown(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Calls the Win32 SendInput method to simulate a KeyDown.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> to press</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.KeyUp(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Calls the Win32 SendInput method to simulate a KeyUp.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> to lift up</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.KeyPress(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Calls the Win32 SendInput method with a KeyDown and KeyUp message in the same input sequence in order to simulate a Key PRESS.
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> to press</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.KeyPress(WindowsInput.Native.VirtualKeyCode[])">
+            <summary>
+            Simulates a key press for each of the specified key codes in the order they are specified.
+            </summary>
+            <param name="keyCodes"></param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.ModifiedKeyStroke(WindowsInput.Native.VirtualKeyCode,WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Simulates a simple modified keystroke like CTRL-C where CTRL is the modifierKey and C is the key.
+            The flow is Modifier KeyDown, Key Press, Modifier KeyUp.
+            </summary>
+            <param name="modifierKeyCode">The modifier key</param>
+            <param name="keyCode">The key to simulate</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.ModifiedKeyStroke(System.Collections.Generic.IEnumerable{WindowsInput.Native.VirtualKeyCode},WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Simulates a modified keystroke where there are multiple modifiers and one key like CTRL-ALT-C where CTRL and ALT are the modifierKeys and C is the key.
+            The flow is Modifiers KeyDown in order, Key Press, Modifiers KeyUp in reverse order.
+            </summary>
+            <param name="modifierKeyCodes">The list of modifier keys</param>
+            <param name="keyCode">The key to simulate</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.ModifiedKeyStroke(WindowsInput.Native.VirtualKeyCode,System.Collections.Generic.IEnumerable{WindowsInput.Native.VirtualKeyCode})">
+            <summary>
+            Simulates a modified keystroke where there is one modifier and multiple keys like CTRL-K-C where CTRL is the modifierKey and K and C are the keys.
+            The flow is Modifier KeyDown, Keys Press in order, Modifier KeyUp.
+            </summary>
+            <param name="modifierKey">The modifier key</param>
+            <param name="keyCodes">The list of keys to simulate</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.ModifiedKeyStroke(System.Collections.Generic.IEnumerable{WindowsInput.Native.VirtualKeyCode},System.Collections.Generic.IEnumerable{WindowsInput.Native.VirtualKeyCode})">
+            <summary>
+            Simulates a modified keystroke where there are multiple modifiers and multiple keys like CTRL-ALT-K-C where CTRL and ALT are the modifierKeys and K and C are the keys.
+            The flow is Modifiers KeyDown in order, Keys Press in order, Modifiers KeyUp in reverse order.
+            </summary>
+            <param name="modifierKeyCodes">The list of modifier keys</param>
+            <param name="keyCodes">The list of keys to simulate</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.TextEntry(System.String)">
+            <summary>
+            Calls the Win32 SendInput method with a stream of KeyDown and KeyUp messages in order to simulate uninterrupted text entry via the keyboard.
+            </summary>
+            <param name="text">The text to be simulated.</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.TextEntry(System.Char)">
+            <summary>
+            Simulates a single character text entry via the keyboard.
+            </summary>
+            <param name="character">The unicode character to be simulated.</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.Sleep(System.Int32)">
+            <summary>
+            Sleeps the executing thread to create a pause between simulated inputs.
+            </summary>
+            <param name="millsecondsTimeout">The number of milliseconds to wait.</param>
+        </member>
+        <member name="M:WindowsInput.KeyboardSimulator.Sleep(System.TimeSpan)">
+            <summary>
+            Sleeps the executing thread to create a pause between simulated inputs.
+            </summary>
+            <param name="timeout">The time to wait.</param>
+        </member>
+        <member name="P:WindowsInput.KeyboardSimulator.Mouse">
+            <summary>
+            Gets the <see cref="T:WindowsInput.IMouseSimulator"/> instance for simulating Mouse input.
+            </summary>
+            <value>The <see cref="T:WindowsInput.IMouseSimulator"/> instance.</value>
+        </member>
+        <member name="T:WindowsInput.Native.InputType">
+            <summary>
+            Specifies the type of the input event. This member can be one of the following values. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.InputType.Mouse">
+            <summary>
+            INPUT_MOUSE = 0x00 (The event is a mouse event. Use the mi structure of the union.)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.InputType.Keyboard">
+            <summary>
+            INPUT_KEYBOARD = 0x01 (The event is a keyboard event. Use the ki structure of the union.)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.InputType.Hardware">
+            <summary>
+            INPUT_HARDWARE = 0x02 (Windows 95/98/Me: The event is from input hardware other than a keyboard or mouse. Use the hi structure of the union.)
+            </summary>
+        </member>
+        <member name="T:WindowsInput.Native.KEYBDINPUT">
+            <summary>
+            The KEYBDINPUT structure contains information about a simulated keyboard event.  (see: http://msdn.microsoft.com/en-us/library/ms646271(VS.85).aspx)
+            Declared in Winuser.h, include Windows.h
+            </summary>
+            <remarks>
+            Windows 2000/XP: INPUT_KEYBOARD supports nonkeyboard-input methods—such as handwriting recognition or voice recognition—as if it were text input by using the KEYEVENTF_UNICODE flag. If KEYEVENTF_UNICODE is specified, SendInput sends a WM_KEYDOWN or WM_KEYUP message to the foreground thread's message queue with wParam equal to VK_PACKET. Once GetMessage or PeekMessage obtains this message, passing the message to TranslateMessage posts a WM_CHAR message with the Unicode character originally specified by wScan. This Unicode character will automatically be converted to the appropriate ANSI value if it is posted to an ANSI window.
+            Windows 2000/XP: Set the KEYEVENTF_SCANCODE flag to define keyboard input in terms of the scan code. This is useful to simulate a physical keystroke regardless of which keyboard is currently being used. The virtual key value of a key may alter depending on the current keyboard layout or what other keys were pressed, but the scan code will always be the same.
+            </remarks>
+        </member>
+        <member name="F:WindowsInput.Native.KEYBDINPUT.KeyCode">
+            <summary>
+            Specifies a virtual-key code. The code must be a value in the range 1 to 254. The Winuser.h header file provides macro definitions (VK_*) for each value. If the dwFlags member specifies KEYEVENTF_UNICODE, wVk must be 0. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.KEYBDINPUT.Scan">
+            <summary>
+            Specifies a hardware scan code for the key. If dwFlags specifies KEYEVENTF_UNICODE, wScan specifies a Unicode character which is to be sent to the foreground application. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.KEYBDINPUT.Flags">
+            <summary>
+            Specifies various aspects of a keystroke. This member can be certain combinations of the following values.
+            KEYEVENTF_EXTENDEDKEY - If specified, the scan code was preceded by a prefix byte that has the value 0xE0 (224).
+            KEYEVENTF_KEYUP - If specified, the key is being released. If not specified, the key is being pressed.
+            KEYEVENTF_SCANCODE - If specified, wScan identifies the key and wVk is ignored. 
+            KEYEVENTF_UNICODE - Windows 2000/XP: If specified, the system synthesizes a VK_PACKET keystroke. The wVk parameter must be zero. This flag can only be combined with the KEYEVENTF_KEYUP flag. For more information, see the Remarks section. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.KEYBDINPUT.Time">
+            <summary>
+            Time stamp for the event, in milliseconds. If this parameter is zero, the system will provide its own time stamp. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.KEYBDINPUT.ExtraInfo">
+            <summary>
+            Specifies an additional value associated with the keystroke. Use the GetMessageExtraInfo function to obtain this information. 
+            </summary>
+        </member>
+        <member name="T:WindowsInput.Native.KeyboardFlag">
+            <summary>
+            Specifies various aspects of a keystroke. This member can be certain combinations of the following values.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.KeyboardFlag.ExtendedKey">
+            <summary>
+            KEYEVENTF_EXTENDEDKEY = 0x0001 (If specified, the scan code was preceded by a prefix byte that has the value 0xE0 (224).)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.KeyboardFlag.KeyUp">
+            <summary>
+            KEYEVENTF_KEYUP = 0x0002 (If specified, the key is being released. If not specified, the key is being pressed.)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.KeyboardFlag.Unicode">
+            <summary>
+            KEYEVENTF_UNICODE = 0x0004 (If specified, wScan identifies the key and wVk is ignored.)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.KeyboardFlag.ScanCode">
+            <summary>
+            KEYEVENTF_SCANCODE = 0x0008 (Windows 2000/XP: If specified, the system synthesizes a VK_PACKET keystroke. The wVk parameter must be zero. This flag can only be combined with the KEYEVENTF_KEYUP flag. For more information, see the Remarks section.)
+            </summary>
+        </member>
+        <member name="T:WindowsInput.Native.MouseFlag">
+            <summary>
+            The set of MouseFlags for use in the Flags property of the <see cref="T:WindowsInput.Native.MOUSEINPUT"/> structure. (See: http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.Move">
+            <summary>
+            Specifies that movement occurred.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.LeftDown">
+            <summary>
+            Specifies that the left button was pressed.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.LeftUp">
+            <summary>
+            Specifies that the left button was released.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.RightDown">
+            <summary>
+            Specifies that the right button was pressed.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.RightUp">
+            <summary>
+            Specifies that the right button was released.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.MiddleDown">
+            <summary>
+            Specifies that the middle button was pressed.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.MiddleUp">
+            <summary>
+            Specifies that the middle button was released.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.XDown">
+            <summary>
+            Windows 2000/XP: Specifies that an X button was pressed.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.XUp">
+            <summary>
+            Windows 2000/XP: Specifies that an X button was released.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.VerticalWheel">
+            <summary>
+            Windows NT/2000/XP: Specifies that the wheel was moved, if the mouse has a wheel. The amount of movement is specified in mouseData. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.HorizontalWheel">
+            <summary>
+            Specifies that the wheel was moved horizontally, if the mouse has a wheel. The amount of movement is specified in mouseData. Windows 2000/XP:  Not supported.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.VirtualDesk">
+            <summary>
+            Windows 2000/XP: Maps coordinates to the entire desktop. Must be used with MOUSEEVENTF_ABSOLUTE.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MouseFlag.Absolute">
+            <summary>
+            Specifies that the dx and dy members contain normalized absolute coordinates. If the flag is not set, dxand dy contain relative data (the change in position since the last reported position). This flag can be set, or not set, regardless of what kind of mouse or other pointing device, if any, is connected to the system. For further information about relative mouse motion, see the following Remarks section.
+            </summary>
+        </member>
+        <member name="T:WindowsInput.Native.MOUSEINPUT">
+            <summary>
+            The MOUSEINPUT structure contains information about a simulated mouse event. (see: http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx)
+            Declared in Winuser.h, include Windows.h
+            </summary>
+            <remarks>
+            If the mouse has moved, indicated by MOUSEEVENTF_MOVE, dx and dy specify information about that movement. The information is specified as absolute or relative integer values. 
+            If MOUSEEVENTF_ABSOLUTE value is specified, dx and dy contain normalized absolute coordinates between 0 and 65,535. The event procedure maps these coordinates onto the display surface. Coordinate (0,0) maps onto the upper-left corner of the display surface; coordinate (65535,65535) maps onto the lower-right corner. In a multimonitor system, the coordinates map to the primary monitor. 
+            Windows 2000/XP: If MOUSEEVENTF_VIRTUALDESK is specified, the coordinates map to the entire virtual desktop.
+            If the MOUSEEVENTF_ABSOLUTE value is not specified, dx and dy specify movement relative to the previous mouse event (the last reported position). Positive values mean the mouse moved right (or down); negative values mean the mouse moved left (or up). 
+            Relative mouse motion is subject to the effects of the mouse speed and the two-mouse threshold values. A user sets these three values with the Pointer Speed slider of the Control Panel's Mouse Properties sheet. You can obtain and set these values using the SystemParametersInfo function. 
+            The system applies two tests to the specified relative mouse movement. If the specified distance along either the x or y axis is greater than the first mouse threshold value, and the mouse speed is not zero, the system doubles the distance. If the specified distance along either the x or y axis is greater than the second mouse threshold value, and the mouse speed is equal to two, the system doubles the distance that resulted from applying the first threshold test. It is thus possible for the system to multiply specified relative mouse movement along the x or y axis by up to four times.
+            </remarks>
+        </member>
+        <member name="F:WindowsInput.Native.MOUSEINPUT.X">
+            <summary>
+            Specifies the absolute position of the mouse, or the amount of motion since the last mouse event was generated, depending on the value of the dwFlags member. Absolute data is specified as the x coordinate of the mouse; relative data is specified as the number of pixels moved. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MOUSEINPUT.Y">
+            <summary>
+            Specifies the absolute position of the mouse, or the amount of motion since the last mouse event was generated, depending on the value of the dwFlags member. Absolute data is specified as the y coordinate of the mouse; relative data is specified as the number of pixels moved. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MOUSEINPUT.MouseData">
+            <summary>
+            If dwFlags contains MOUSEEVENTF_WHEEL, then mouseData specifies the amount of wheel movement. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user. One wheel click is defined as WHEEL_DELTA, which is 120. 
+            Windows Vista: If dwFlags contains MOUSEEVENTF_HWHEEL, then dwData specifies the amount of wheel movement. A positive value indicates that the wheel was rotated to the right; a negative value indicates that the wheel was rotated to the left. One wheel click is defined as WHEEL_DELTA, which is 120.
+            Windows 2000/XP: IfdwFlags does not contain MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, or MOUSEEVENTF_XUP, then mouseData should be zero. 
+            If dwFlags contains MOUSEEVENTF_XDOWN or MOUSEEVENTF_XUP, then mouseData specifies which X buttons were pressed or released. This value may be any combination of the following flags. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MOUSEINPUT.Flags">
+            <summary>
+            A set of bit flags that specify various aspects of mouse motion and button clicks. The bits in this member can be any reasonable combination of the following values. 
+            The bit flags that specify mouse button status are set to indicate changes in status, not ongoing conditions. For example, if the left mouse button is pressed and held down, MOUSEEVENTF_LEFTDOWN is set when the left button is first pressed, but not for subsequent motions. Similarly, MOUSEEVENTF_LEFTUP is set only when the button is first released. 
+            You cannot specify both the MOUSEEVENTF_WHEEL flag and either MOUSEEVENTF_XDOWN or MOUSEEVENTF_XUP flags simultaneously in the dwFlags parameter, because they both require use of the mouseData field. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MOUSEINPUT.Time">
+            <summary>
+            Time stamp for the event, in milliseconds. If this parameter is 0, the system will provide its own time stamp. 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MOUSEINPUT.ExtraInfo">
+            <summary>
+            Specifies an additional value associated with the mouse event. An application calls GetMessageExtraInfo to obtain this extra information. 
+            </summary>
+        </member>
+        <member name="T:WindowsInput.Native.MOUSEKEYBDHARDWAREINPUT">
+            <summary>
+            The combined/overlayed structure that includes Mouse, Keyboard and Hardware Input message data (see: http://msdn.microsoft.com/en-us/library/ms646270(VS.85).aspx)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MOUSEKEYBDHARDWAREINPUT.Mouse">
+            <summary>
+            The <see cref="T:WindowsInput.Native.MOUSEINPUT"/> definition.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MOUSEKEYBDHARDWAREINPUT.Keyboard">
+            <summary>
+            The <see cref="T:WindowsInput.Native.KEYBDINPUT"/> definition.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.MOUSEKEYBDHARDWAREINPUT.Hardware">
+            <summary>
+            The <see cref="T:WindowsInput.Native.HARDWAREINPUT"/> definition.
+            </summary>
+        </member>
+        <member name="T:WindowsInput.WindowsInputDeviceStateAdaptor">
+            <summary>
+            An implementation of <see cref="T:WindowsInput.IInputDeviceStateAdaptor"/> for Windows by calling the native <see cref="M:WindowsInput.Native.NativeMethods.GetKeyState(System.UInt16)"/> and <see cref="M:WindowsInput.Native.NativeMethods.GetAsyncKeyState(System.UInt16)"/> methods.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.WindowsInputDeviceStateAdaptor.IsKeyDown(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Determines whether the specified key is up or down by calling the GetKeyState function. (See: http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx)
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+            <returns>
+            	<c>true</c> if the key is down; otherwise, <c>false</c>.
+            </returns>
+            <remarks>
+            The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information. 
+            An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated. 
+            To retrieve state information for all the virtual keys, use the GetKeyboardState function. 
+            An application can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for Bthe nVirtKey parameter. This gives the status of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. An application can also use the following virtual-key code constants as values for nVirtKey to distinguish between the left and right instances of those keys. 
+            VK_LSHIFT
+            VK_RSHIFT
+            VK_LCONTROL
+            VK_RCONTROL
+            VK_LMENU
+            VK_RMENU
+            
+            These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 
+            </remarks>
+        </member>
+        <member name="M:WindowsInput.WindowsInputDeviceStateAdaptor.IsKeyUp(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Determines whether the specified key is up or downby calling the <see cref="M:WindowsInput.Native.NativeMethods.GetKeyState(System.UInt16)"/> function. (See: http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx)
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+            <returns>
+            	<c>true</c> if the key is up; otherwise, <c>false</c>.
+            </returns>
+            <remarks>
+            The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information. 
+            An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated. 
+            To retrieve state information for all the virtual keys, use the GetKeyboardState function. 
+            An application can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for Bthe nVirtKey parameter. This gives the status of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. An application can also use the following virtual-key code constants as values for nVirtKey to distinguish between the left and right instances of those keys. 
+            VK_LSHIFT
+            VK_RSHIFT
+            VK_LCONTROL
+            VK_RCONTROL
+            VK_LMENU
+            VK_RMENU
+            
+            These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 
+            </remarks>
+        </member>
+        <member name="M:WindowsInput.WindowsInputDeviceStateAdaptor.IsHardwareKeyDown(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Determines whether the physical key is up or down at the time the function is called regardless of whether the application thread has read the keyboard event from the message pump by calling the <see cref="M:WindowsInput.Native.NativeMethods.GetAsyncKeyState(System.UInt16)"/> function. (See: http://msdn.microsoft.com/en-us/library/ms646293(VS.85).aspx)
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+            <returns>
+            	<c>true</c> if the key is down; otherwise, <c>false</c>.
+            </returns>
+            <remarks>
+            The GetAsyncKeyState function works with mouse buttons. However, it checks on the state of the physical mouse buttons, not on the logical mouse buttons that the physical buttons are mapped to. For example, the call GetAsyncKeyState(VK_LBUTTON) always returns the state of the left physical mouse button, regardless of whether it is mapped to the left or right logical mouse button. You can determine the system's current mapping of physical mouse buttons to logical mouse buttons by calling 
+            Copy CodeGetSystemMetrics(SM_SWAPBUTTON) which returns TRUE if the mouse buttons have been swapped.
+            
+            Although the least significant bit of the return value indicates whether the key has been pressed since the last query, due to the pre-emptive multitasking nature of Windows, another application can call GetAsyncKeyState and receive the "recently pressed" bit instead of your application. The behavior of the least significant bit of the return value is retained strictly for compatibility with 16-bit Windows applications (which are non-preemptive) and should not be relied upon.
+            
+            You can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the vKey parameter. This gives the state of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. 
+            
+            Windows NT/2000/XP: You can use the following virtual-key code constants as values for vKey to distinguish between the left and right instances of those keys. 
+            
+            Code Meaning 
+            VK_LSHIFT Left-shift key. 
+            VK_RSHIFT Right-shift key. 
+            VK_LCONTROL Left-control key. 
+            VK_RCONTROL Right-control key. 
+            VK_LMENU Left-menu key. 
+            VK_RMENU Right-menu key. 
+            
+            These left- and right-distinguishing constants are only available when you call the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 
+            </remarks>
+        </member>
+        <member name="M:WindowsInput.WindowsInputDeviceStateAdaptor.IsHardwareKeyUp(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Determines whether the physical key is up or down at the time the function is called regardless of whether the application thread has read the keyboard event from the message pump by calling the <see cref="M:WindowsInput.Native.NativeMethods.GetAsyncKeyState(System.UInt16)"/> function. (See: http://msdn.microsoft.com/en-us/library/ms646293(VS.85).aspx)
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+            <returns>
+            	<c>true</c> if the key is up; otherwise, <c>false</c>.
+            </returns>
+            <remarks>
+            The GetAsyncKeyState function works with mouse buttons. However, it checks on the state of the physical mouse buttons, not on the logical mouse buttons that the physical buttons are mapped to. For example, the call GetAsyncKeyState(VK_LBUTTON) always returns the state of the left physical mouse button, regardless of whether it is mapped to the left or right logical mouse button. You can determine the system's current mapping of physical mouse buttons to logical mouse buttons by calling 
+            Copy CodeGetSystemMetrics(SM_SWAPBUTTON) which returns TRUE if the mouse buttons have been swapped.
+            
+            Although the least significant bit of the return value indicates whether the key has been pressed since the last query, due to the pre-emptive multitasking nature of Windows, another application can call GetAsyncKeyState and receive the "recently pressed" bit instead of your application. The behavior of the least significant bit of the return value is retained strictly for compatibility with 16-bit Windows applications (which are non-preemptive) and should not be relied upon.
+            
+            You can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the vKey parameter. This gives the state of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. 
+            
+            Windows NT/2000/XP: You can use the following virtual-key code constants as values for vKey to distinguish between the left and right instances of those keys. 
+            
+            Code Meaning 
+            VK_LSHIFT Left-shift key. 
+            VK_RSHIFT Right-shift key. 
+            VK_LCONTROL Left-control key. 
+            VK_RCONTROL Right-control key. 
+            VK_LMENU Left-menu key. 
+            VK_RMENU Right-menu key. 
+            
+            These left- and right-distinguishing constants are only available when you call the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 
+            </remarks>
+        </member>
+        <member name="M:WindowsInput.WindowsInputDeviceStateAdaptor.IsTogglingKeyInEffect(WindowsInput.Native.VirtualKeyCode)">
+            <summary>
+            Determines whether the toggling key is toggled on (in-effect) or not by calling the <see cref="M:WindowsInput.Native.NativeMethods.GetKeyState(System.UInt16)"/> function.  (See: http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx)
+            </summary>
+            <param name="keyCode">The <see cref="T:WindowsInput.Native.VirtualKeyCode"/> for the key.</param>
+            <returns>
+            	<c>true</c> if the toggling key is toggled on (in-effect); otherwise, <c>false</c>.
+            </returns>
+            <remarks>
+            The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information. 
+            An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated. 
+            To retrieve state information for all the virtual keys, use the GetKeyboardState function. 
+            An application can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the nVirtKey parameter. This gives the status of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. An application can also use the following virtual-key code constants as values for nVirtKey to distinguish between the left and right instances of those keys. 
+            VK_LSHIFT
+            VK_RSHIFT
+            VK_LCONTROL
+            VK_RCONTROL
+            VK_LMENU
+            VK_RMENU
+            
+            These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 
+            </remarks>
+        </member>
+        <member name="T:WindowsInput.WindowsInputMessageDispatcher">
+            <summary>
+            Implements the <see cref="T:WindowsInput.IInputMessageDispatcher"/> by calling <see cref="M:WindowsInput.Native.NativeMethods.SendInput(System.UInt32,WindowsInput.Native.INPUT[],System.Int32)"/>.
+            </summary>
+        </member>
+        <member name="M:WindowsInput.WindowsInputMessageDispatcher.DispatchInput(WindowsInput.Native.INPUT[])">
+            <summary>
+            Dispatches the specified list of <see cref="T:WindowsInput.Native.INPUT"/> messages in their specified order by issuing a single called to <see cref="M:WindowsInput.Native.NativeMethods.SendInput(System.UInt32,WindowsInput.Native.INPUT[],System.Int32)"/>.
+            </summary>
+            <param name="inputs">The list of <see cref="T:WindowsInput.Native.INPUT"/> messages to be dispatched.</param>
+            <exception cref="T:System.ArgumentException">If the <paramref name="inputs"/> array is empty.</exception>
+            <exception cref="T:System.ArgumentNullException">If the <paramref name="inputs"/> array is null.</exception>
+            <exception cref="T:System.Exception">If the any of the commands in the <paramref name="inputs"/> array could not be sent successfully.</exception>
+        </member>
+        <member name="T:WindowsInput.Native.VirtualKeyCode">
+            <summary>
+            The list of VirtualKeyCodes (see: http://msdn.microsoft.com/en-us/library/ms645540(VS.85).aspx)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.LBUTTON">
+            <summary>
+            Left mouse button
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.RBUTTON">
+            <summary>
+            Right mouse button
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.CANCEL">
+            <summary>
+            Control-break processing
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.MBUTTON">
+            <summary>
+            Middle mouse button (three-button mouse) - NOT contiguous with LBUTTON and RBUTTON
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.XBUTTON1">
+            <summary>
+            Windows 2000/XP: X1 mouse button - NOT contiguous with LBUTTON and RBUTTON
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.XBUTTON2">
+            <summary>
+            Windows 2000/XP: X2 mouse button - NOT contiguous with LBUTTON and RBUTTON
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.BACK">
+            <summary>
+            BACKSPACE key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.TAB">
+            <summary>
+            TAB key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.CLEAR">
+            <summary>
+            CLEAR key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.RETURN">
+            <summary>
+            ENTER key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.SHIFT">
+            <summary>
+            SHIFT key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.CONTROL">
+            <summary>
+            CTRL key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.MENU">
+            <summary>
+            ALT key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.PAUSE">
+            <summary>
+            PAUSE key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.CAPITAL">
+            <summary>
+            CAPS LOCK key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.KANA">
+            <summary>
+            Input Method Editor (IME) Kana mode
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.HANGEUL">
+            <summary>
+            IME Hanguel mode (maintained for compatibility; use HANGUL)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.HANGUL">
+            <summary>
+            IME Hangul mode
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.JUNJA">
+            <summary>
+            IME Junja mode
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.FINAL">
+            <summary>
+            IME final mode
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.HANJA">
+            <summary>
+            IME Hanja mode
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.KANJI">
+            <summary>
+            IME Kanji mode
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.ESCAPE">
+            <summary>
+            ESC key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.CONVERT">
+            <summary>
+            IME convert
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NONCONVERT">
+            <summary>
+            IME nonconvert
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.ACCEPT">
+            <summary>
+            IME accept
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.MODECHANGE">
+            <summary>
+            IME mode change request
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.SPACE">
+            <summary>
+            SPACEBAR
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.PRIOR">
+            <summary>
+            PAGE UP key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NEXT">
+            <summary>
+            PAGE DOWN key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.END">
+            <summary>
+            END key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.HOME">
+            <summary>
+            HOME key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.LEFT">
+            <summary>
+            LEFT ARROW key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.UP">
+            <summary>
+            UP ARROW key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.RIGHT">
+            <summary>
+            RIGHT ARROW key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.DOWN">
+            <summary>
+            DOWN ARROW key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.SELECT">
+            <summary>
+            SELECT key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.PRINT">
+            <summary>
+            PRINT key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.EXECUTE">
+            <summary>
+            EXECUTE key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.SNAPSHOT">
+            <summary>
+            PRINT SCREEN key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.INSERT">
+            <summary>
+            INS key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.DELETE">
+            <summary>
+            DEL key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.HELP">
+            <summary>
+            HELP key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_0">
+            <summary>
+            0 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_1">
+            <summary>
+            1 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_2">
+            <summary>
+            2 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_3">
+            <summary>
+            3 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_4">
+            <summary>
+            4 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_5">
+            <summary>
+            5 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_6">
+            <summary>
+            6 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_7">
+            <summary>
+            7 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_8">
+            <summary>
+            8 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_9">
+            <summary>
+            9 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_A">
+            <summary>
+            A key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_B">
+            <summary>
+            B key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_C">
+            <summary>
+            C key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_D">
+            <summary>
+            D key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_E">
+            <summary>
+            E key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_F">
+            <summary>
+            F key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_G">
+            <summary>
+            G key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_H">
+            <summary>
+            H key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_I">
+            <summary>
+            I key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_J">
+            <summary>
+            J key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_K">
+            <summary>
+            K key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_L">
+            <summary>
+            L key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_M">
+            <summary>
+            M key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_N">
+            <summary>
+            N key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_O">
+            <summary>
+            O key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_P">
+            <summary>
+            P key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_Q">
+            <summary>
+            Q key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_R">
+            <summary>
+            R key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_S">
+            <summary>
+            S key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_T">
+            <summary>
+            T key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_U">
+            <summary>
+            U key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_V">
+            <summary>
+            V key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_W">
+            <summary>
+            W key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_X">
+            <summary>
+            X key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_Y">
+            <summary>
+            Y key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VK_Z">
+            <summary>
+            Z key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.LWIN">
+            <summary>
+            Left Windows key (Microsoft Natural keyboard)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.RWIN">
+            <summary>
+            Right Windows key (Natural keyboard)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.APPS">
+            <summary>
+            Applications key (Natural keyboard)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.SLEEP">
+            <summary>
+            Computer Sleep key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NUMPAD0">
+            <summary>
+            Numeric keypad 0 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NUMPAD1">
+            <summary>
+            Numeric keypad 1 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NUMPAD2">
+            <summary>
+            Numeric keypad 2 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NUMPAD3">
+            <summary>
+            Numeric keypad 3 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NUMPAD4">
+            <summary>
+            Numeric keypad 4 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NUMPAD5">
+            <summary>
+            Numeric keypad 5 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NUMPAD6">
+            <summary>
+            Numeric keypad 6 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NUMPAD7">
+            <summary>
+            Numeric keypad 7 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NUMPAD8">
+            <summary>
+            Numeric keypad 8 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NUMPAD9">
+            <summary>
+            Numeric keypad 9 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.MULTIPLY">
+            <summary>
+            Multiply key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.ADD">
+            <summary>
+            Add key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.SEPARATOR">
+            <summary>
+            Separator key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.SUBTRACT">
+            <summary>
+            Subtract key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.DECIMAL">
+            <summary>
+            Decimal key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.DIVIDE">
+            <summary>
+            Divide key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F1">
+            <summary>
+            F1 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F2">
+            <summary>
+            F2 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F3">
+            <summary>
+            F3 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F4">
+            <summary>
+            F4 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F5">
+            <summary>
+            F5 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F6">
+            <summary>
+            F6 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F7">
+            <summary>
+            F7 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F8">
+            <summary>
+            F8 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F9">
+            <summary>
+            F9 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F10">
+            <summary>
+            F10 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F11">
+            <summary>
+            F11 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F12">
+            <summary>
+            F12 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F13">
+            <summary>
+            F13 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F14">
+            <summary>
+            F14 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F15">
+            <summary>
+            F15 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F16">
+            <summary>
+            F16 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F17">
+            <summary>
+            F17 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F18">
+            <summary>
+            F18 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F19">
+            <summary>
+            F19 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F20">
+            <summary>
+            F20 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F21">
+            <summary>
+            F21 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F22">
+            <summary>
+            F22 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F23">
+            <summary>
+            F23 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.F24">
+            <summary>
+            F24 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NUMLOCK">
+            <summary>
+            NUM LOCK key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.SCROLL">
+            <summary>
+            SCROLL LOCK key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.LSHIFT">
+            <summary>
+            Left SHIFT key - Used only as parameters to GetAsyncKeyState() and GetKeyState()
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.RSHIFT">
+            <summary>
+            Right SHIFT key - Used only as parameters to GetAsyncKeyState() and GetKeyState()
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.LCONTROL">
+            <summary>
+            Left CONTROL key - Used only as parameters to GetAsyncKeyState() and GetKeyState()
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.RCONTROL">
+            <summary>
+            Right CONTROL key - Used only as parameters to GetAsyncKeyState() and GetKeyState()
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.LMENU">
+            <summary>
+            Left MENU key - Used only as parameters to GetAsyncKeyState() and GetKeyState()
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.RMENU">
+            <summary>
+            Right MENU key - Used only as parameters to GetAsyncKeyState() and GetKeyState()
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.BROWSER_BACK">
+            <summary>
+            Windows 2000/XP: Browser Back key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.BROWSER_FORWARD">
+            <summary>
+            Windows 2000/XP: Browser Forward key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.BROWSER_REFRESH">
+            <summary>
+            Windows 2000/XP: Browser Refresh key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.BROWSER_STOP">
+            <summary>
+            Windows 2000/XP: Browser Stop key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.BROWSER_SEARCH">
+            <summary>
+            Windows 2000/XP: Browser Search key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.BROWSER_FAVORITES">
+            <summary>
+            Windows 2000/XP: Browser Favorites key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.BROWSER_HOME">
+            <summary>
+            Windows 2000/XP: Browser Start and Home key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VOLUME_MUTE">
+            <summary>
+            Windows 2000/XP: Volume Mute key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VOLUME_DOWN">
+            <summary>
+            Windows 2000/XP: Volume Down key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.VOLUME_UP">
+            <summary>
+            Windows 2000/XP: Volume Up key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.MEDIA_NEXT_TRACK">
+            <summary>
+            Windows 2000/XP: Next Track key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.MEDIA_PREV_TRACK">
+            <summary>
+            Windows 2000/XP: Previous Track key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.MEDIA_STOP">
+            <summary>
+            Windows 2000/XP: Stop Media key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.MEDIA_PLAY_PAUSE">
+            <summary>
+            Windows 2000/XP: Play/Pause Media key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.LAUNCH_MAIL">
+            <summary>
+            Windows 2000/XP: Start Mail key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.LAUNCH_MEDIA_SELECT">
+            <summary>
+            Windows 2000/XP: Select Media key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.LAUNCH_APP1">
+            <summary>
+            Windows 2000/XP: Start Application 1 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.LAUNCH_APP2">
+            <summary>
+            Windows 2000/XP: Start Application 2 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_1">
+            <summary>
+            Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_PLUS">
+            <summary>
+            Windows 2000/XP: For any country/region, the '+' key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_COMMA">
+            <summary>
+            Windows 2000/XP: For any country/region, the ',' key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_MINUS">
+            <summary>
+            Windows 2000/XP: For any country/region, the '-' key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_PERIOD">
+            <summary>
+            Windows 2000/XP: For any country/region, the '.' key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_2">
+            <summary>
+            Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_3">
+            <summary>
+            Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key 
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_4">
+            <summary>
+            Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_5">
+            <summary>
+            Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_6">
+            <summary>
+            Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_7">
+            <summary>
+            Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_8">
+            <summary>
+            Used for miscellaneous characters; it can vary by keyboard.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_102">
+            <summary>
+            Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.PROCESSKEY">
+            <summary>
+            Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.PACKET">
+            <summary>
+            Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.ATTN">
+            <summary>
+            Attn key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.CRSEL">
+            <summary>
+            CrSel key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.EXSEL">
+            <summary>
+            ExSel key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.EREOF">
+            <summary>
+            Erase EOF key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.PLAY">
+            <summary>
+            Play key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.ZOOM">
+            <summary>
+            Zoom key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.NONAME">
+            <summary>
+            Reserved
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.PA1">
+            <summary>
+            PA1 key
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.VirtualKeyCode.OEM_CLEAR">
+            <summary>
+            Clear key
+            </summary>
+        </member>
+        <member name="T:WindowsInput.Native.XButton">
+            <summary>
+            XButton definitions for use in the MouseData property of the <see cref="T:WindowsInput.Native.MOUSEINPUT"/> structure. (See: http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx)
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.XButton.XButton1">
+            <summary>
+            Set if the first X button is pressed or released.
+            </summary>
+        </member>
+        <member name="F:WindowsInput.Native.XButton.XButton2">
+            <summary>
+            Set if the second X button is pressed or released.
+            </summary>
+        </member>
+    </members>
+</doc>

BIN
deployment/nssm.exe


+ 174 - 0
dreamcheeky-big-red-button-dotnet/.gitignore

@@ -0,0 +1,174 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+x64/
+build/
+bld/
+[Bb]in/
+[Oo]bj/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+#NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding addin-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+*.ncrunch*
+_NCrunch_*
+.*crunch*.local.xml
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+
+# NuGet Packages Directory
+packages/
+## TODO: If the tool you use requires repositories.config uncomment the next line
+#!packages/repositories.config
+
+# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
+# This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented)
+!packages/build/
+
+# Windows Azure Build Output
+csx/
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/

+ 6 - 0
dreamcheeky-big-red-button-dotnet/.nuget/NuGet.Config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <solution>
+    <add key="disableSourceControlIntegration" value="true" />
+  </solution>
+</configuration>

BIN
dreamcheeky-big-red-button-dotnet/.nuget/NuGet.exe


+ 144 - 0
dreamcheeky-big-red-button-dotnet/.nuget/NuGet.targets

@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
+
+        <!-- Enable the restore command to run before builds -->
+        <RestorePackages Condition="  '$(RestorePackages)' == '' ">false</RestorePackages>
+
+        <!-- Property that enables building a package from a project -->
+        <BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage>
+
+        <!-- Determines if package restore consent is required to restore packages -->
+        <RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">true</RequireRestoreConsent>
+
+        <!-- Download NuGet.exe if it does not already exist -->
+        <DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">false</DownloadNuGetExe>
+    </PropertyGroup>
+
+    <ItemGroup Condition=" '$(PackageSources)' == '' ">
+        <!-- Package sources used to restore packages. By default, registered sources under %APPDATA%\NuGet\NuGet.Config will be used -->
+        <!-- The official NuGet package source (https://www.nuget.org/api/v2/) will be excluded if package sources are specified and it does not appear in the list -->
+        <!--
+            <PackageSource Include="https://www.nuget.org/api/v2/" />
+            <PackageSource Include="https://my-nuget-source/nuget/" />
+        -->
+    </ItemGroup>
+
+    <PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
+        <!-- Windows specific commands -->
+        <NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
+    </PropertyGroup>
+
+    <PropertyGroup Condition=" '$(OS)' != 'Windows_NT'">
+        <!-- We need to launch nuget.exe with the mono command if we're not on windows -->
+        <NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath>
+    </PropertyGroup>
+
+    <PropertyGroup>
+        <PackagesProjectConfig Condition=" '$(OS)' == 'Windows_NT'">$(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config</PackagesProjectConfig>
+        <PackagesProjectConfig Condition=" '$(OS)' != 'Windows_NT'">$(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config</PackagesProjectConfig>
+    </PropertyGroup>
+
+    <PropertyGroup>
+      <PackagesConfig Condition="Exists('$(MSBuildProjectDirectory)\packages.config')">$(MSBuildProjectDirectory)\packages.config</PackagesConfig>
+      <PackagesConfig Condition="Exists('$(PackagesProjectConfig)')">$(PackagesProjectConfig)</PackagesConfig>
+    </PropertyGroup>
+    
+    <PropertyGroup>
+        <!-- NuGet command -->
+        <NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(NuGetToolsPath)\NuGet.exe</NuGetExePath>
+        <PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources>
+
+        <NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
+        <NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 "$(NuGetExePath)"</NuGetCommand>
+
+        <PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
+
+        <RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch>
+        <NonInteractiveSwitch Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' ">-NonInteractive</NonInteractiveSwitch>
+
+        <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$(SolutionDir) "</PaddedSolutionDir>
+        <PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir>
+
+        <!-- Commands -->
+        <RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)"  $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)</RestoreCommand>
+        <BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols</BuildCommand>
+
+        <!-- We need to ensure packages are restored prior to assembly resolve -->
+        <BuildDependsOn Condition="$(RestorePackages) == 'true'">
+            RestorePackages;
+            $(BuildDependsOn);
+        </BuildDependsOn>
+
+        <!-- Make the build depend on restore packages -->
+        <BuildDependsOn Condition="$(BuildPackage) == 'true'">
+            $(BuildDependsOn);
+            BuildPackage;
+        </BuildDependsOn>
+    </PropertyGroup>
+
+    <Target Name="CheckPrerequisites">
+        <!-- Raise an error if we're unable to locate nuget.exe  -->
+        <Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
+        <!--
+        Take advantage of MsBuild's build dependency tracking to make sure that we only ever download nuget.exe once.
+        This effectively acts as a lock that makes sure that the download operation will only happen once and all
+        parallel builds will have to wait for it to complete.
+        -->
+        <MsBuild Targets="_DownloadNuGet" Projects="$(MSBuildThisFileFullPath)" Properties="Configuration=NOT_IMPORTANT;DownloadNuGetExe=$(DownloadNuGetExe)" />
+    </Target>
+
+    <Target Name="_DownloadNuGet">
+        <DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" />
+    </Target>
+
+    <Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">        
+        <Exec Command="$(RestoreCommand)"
+              Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />
+
+        <Exec Command="$(RestoreCommand)"
+              LogStandardErrorAsError="true"
+              Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
+    </Target>
+
+    <Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
+        <Exec Command="$(BuildCommand)"
+              Condition=" '$(OS)' != 'Windows_NT' " />
+
+        <Exec Command="$(BuildCommand)"
+              LogStandardErrorAsError="true"
+              Condition=" '$(OS)' == 'Windows_NT' " />
+    </Target>
+
+    <UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
+        <ParameterGroup>
+            <OutputFilename ParameterType="System.String" Required="true" />
+        </ParameterGroup>
+        <Task>
+            <Reference Include="System.Core" />
+            <Using Namespace="System" />
+            <Using Namespace="System.IO" />
+            <Using Namespace="System.Net" />
+            <Using Namespace="Microsoft.Build.Framework" />
+            <Using Namespace="Microsoft.Build.Utilities" />
+            <Code Type="Fragment" Language="cs">
+                <![CDATA[
+                try {
+                    OutputFilename = Path.GetFullPath(OutputFilename);
+
+                    Log.LogMessage("Downloading latest version of NuGet.exe...");
+                    WebClient webClient = new WebClient();
+                    webClient.DownloadFile("https://www.nuget.org/nuget.exe", OutputFilename);
+
+                    return true;
+                }
+                catch (Exception ex) {
+                    Log.LogErrorFromException(ex);
+                    return false;
+                }
+            ]]>
+            </Code>
+        </Task>
+    </UsingTask>
+</Project>

BIN
dreamcheeky-big-red-button-dotnet/.vs/DreamCheeky.BigRedButton/FileContentIndex/345b6fbc-d86e-4e93-b361-b1c53c42b6d2.vsidx


BIN
dreamcheeky-big-red-button-dotnet/.vs/DreamCheeky.BigRedButton/FileContentIndex/b78291ad-c800-4347-8632-b79d59a12a51.vsidx


BIN
dreamcheeky-big-red-button-dotnet/.vs/DreamCheeky.BigRedButton/FileContentIndex/c0639b96-b395-4948-94d6-05b2b3840688.vsidx


+ 37 - 0
dreamcheeky-big-red-button-dotnet/.vs/DreamCheeky.BigRedButton/v17/DocumentLayout.backup.json

@@ -0,0 +1,37 @@
+{
+  "Version": 1,
+  "WorkspaceRootPath": "C:\\Git\\dreamcheeky-big-red-button-dotnet\\",
+  "Documents": [
+    {
+      "AbsoluteMoniker": "D:0:0:{1409DF36-AABC-4E31-9DCF-1694A4685138}|Test.Application\\Test.Application.csproj|c:\\git\\dreamcheeky-big-red-button-dotnet\\test.application\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{1409DF36-AABC-4E31-9DCF-1694A4685138}|Test.Application\\Test.Application.csproj|solutionrelative:test.application\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    }
+  ],
+  "DocumentGroupContainers": [
+    {
+      "Orientation": 0,
+      "VerticalTabListWidth": 256,
+      "DocumentGroups": [
+        {
+          "DockedWidth": 200,
+          "SelectedChildIndex": 0,
+          "Children": [
+            {
+              "$type": "Document",
+              "DocumentIndex": 0,
+              "Title": "Program.cs",
+              "DocumentMoniker": "C:\\Git\\dreamcheeky-big-red-button-dotnet\\Test.Application\\Program.cs",
+              "RelativeDocumentMoniker": "Test.Application\\Program.cs",
+              "ToolTip": "C:\\Git\\dreamcheeky-big-red-button-dotnet\\Test.Application\\Program.cs",
+              "RelativeToolTip": "Test.Application\\Program.cs",
+              "ViewState": "AgIAACMAAAAAAAAAAAAAwDcAAAABAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-12-23T09:19:33.124Z",
+              "EditorCaption": ""
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}

+ 37 - 0
dreamcheeky-big-red-button-dotnet/.vs/DreamCheeky.BigRedButton/v17/DocumentLayout.json

@@ -0,0 +1,37 @@
+{
+  "Version": 1,
+  "WorkspaceRootPath": "C:\\Git\\dreamcheeky-big-red-button-dotnet\\",
+  "Documents": [
+    {
+      "AbsoluteMoniker": "D:0:0:{1409DF36-AABC-4E31-9DCF-1694A4685138}|Test.Application\\Test.Application.csproj|c:\\git\\dreamcheeky-big-red-button-dotnet\\test.application\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{1409DF36-AABC-4E31-9DCF-1694A4685138}|Test.Application\\Test.Application.csproj|solutionrelative:test.application\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    }
+  ],
+  "DocumentGroupContainers": [
+    {
+      "Orientation": 0,
+      "VerticalTabListWidth": 256,
+      "DocumentGroups": [
+        {
+          "DockedWidth": 200,
+          "SelectedChildIndex": 0,
+          "Children": [
+            {
+              "$type": "Document",
+              "DocumentIndex": 0,
+              "Title": "Program.cs",
+              "DocumentMoniker": "C:\\Git\\dreamcheeky-big-red-button-dotnet\\Test.Application\\Program.cs",
+              "RelativeDocumentMoniker": "Test.Application\\Program.cs",
+              "ToolTip": "C:\\Git\\dreamcheeky-big-red-button-dotnet\\Test.Application\\Program.cs",
+              "RelativeToolTip": "Test.Application\\Program.cs",
+              "ViewState": "AgIAACMAAAAAAAAAAAAAwDcAAAABAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-12-23T09:19:33.124Z",
+              "EditorCaption": ""
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}

+ 35 - 0
dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton.sln

@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30501.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DreamCheeky.BigRedButton", "DreamCheeky.BigRedButton\DreamCheeky.BigRedButton.csproj", "{C24D8F95-9973-4941-86DF-ADD4212DEAA3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.Application", "Test.Application\Test.Application.csproj", "{1409DF36-AABC-4E31-9DCF-1694A4685138}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1A9C6A81-57CE-49F1-A160-0251F83A8480}"
+	ProjectSection(SolutionItems) = preProject
+		.nuget\NuGet.Config = .nuget\NuGet.Config
+		.nuget\NuGet.exe = .nuget\NuGet.exe
+		.nuget\NuGet.targets = .nuget\NuGet.targets
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{C24D8F95-9973-4941-86DF-ADD4212DEAA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C24D8F95-9973-4941-86DF-ADD4212DEAA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C24D8F95-9973-4941-86DF-ADD4212DEAA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C24D8F95-9973-4941-86DF-ADD4212DEAA3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1409DF36-AABC-4E31-9DCF-1694A4685138}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1409DF36-AABC-4E31-9DCF-1694A4685138}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1409DF36-AABC-4E31-9DCF-1694A4685138}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1409DF36-AABC-4E31-9DCF-1694A4685138}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/.vs/DreamCheeky.BigRedButton.csproj.dtbcache.json


+ 93 - 0
dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/BigRedButton.cs

@@ -0,0 +1,93 @@
+using System;
+using System.Threading;
+
+namespace DreamCheeky
+{
+    public class BigRedButton : IDisposable
+    {
+        private readonly Device device;
+
+        private volatile bool terminated;
+        private Thread thread;
+
+        public BigRedButton()
+        {
+            device = new Device();
+        }
+
+        public void Start()
+        {
+            device.Open();
+            thread = new Thread(ThreadCallback);
+            thread.Start();
+        }
+
+        private void ThreadCallback()
+        {
+            var lastStatus = DeviceStatus.Unknown;
+
+            while (!terminated)
+            {
+                DeviceStatus status = device.GetStatus();
+                if (status != DeviceStatus.Errored)
+                {
+                    if (status == DeviceStatus.LidClosed && lastStatus == DeviceStatus.LidOpen)
+                    {
+                        OnLidClosed();
+                    }
+                    else if (status == DeviceStatus.ButtonPressed && lastStatus != DeviceStatus.ButtonPressed)
+                    {
+                        OnButtonPressed();
+                    }
+                    else if (status == DeviceStatus.LidOpen && lastStatus == DeviceStatus.LidClosed)
+                    {
+                        OnLidOpen();
+                    }
+                    
+                    lastStatus = status;
+                }
+                Thread.Sleep(100);
+            }
+        }
+
+        public void Stop()
+        {
+            terminated = true;
+            thread.Join();
+            device.Close();
+        }
+
+        public void Dispose()
+        {
+            Stop();
+        }
+
+        private void OnLidOpen()
+        {
+            if (LidOpen != null)
+            {
+                LidOpen(this, EventArgs.Empty);
+            }
+        }
+
+        private void OnLidClosed()
+        {
+            if (LidClosed != null)
+            {
+                LidClosed(this, EventArgs.Empty);
+            }
+        }
+
+        private void OnButtonPressed()
+        {
+            if (ButtonPressed != null)
+            {
+                ButtonPressed(this, EventArgs.Empty);
+            }
+        }
+
+        public EventHandler LidOpen;
+        public EventHandler LidClosed;
+        public EventHandler ButtonPressed;
+    }
+}

+ 54 - 0
dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/Device.cs

@@ -0,0 +1,54 @@
+using System;
+using System.Linq;
+using HidLibrary;
+
+namespace DreamCheeky
+{
+    class Device : IDisposable
+    {
+        private readonly byte[] statusCommand = { 0, 0, 0, 0, 0, 0, 0, 0, 2 };
+
+        private readonly int vendorId = 0x1D34;
+        private readonly int productId = 0x000D;
+        private readonly HidDevice device;
+
+        public Device()
+        {
+            device = HidDevices.Enumerate(vendorId, productId).FirstOrDefault();
+
+            if (device == null)
+                throw new InvalidOperationException("Device not found");
+        }
+
+        public void Open()
+        {
+            device.OpenDevice();
+        }
+
+        public void Close()
+        {
+            device.CloseDevice();
+        }
+
+        public DeviceStatus GetStatus()
+        {
+            if (!device.Write(statusCommand, 100))
+            {
+                return DeviceStatus.Errored;
+            }
+
+            HidDeviceData data = device.Read(100);
+            if (data.Status != HidDeviceData.ReadStatus.Success)
+            {
+                return DeviceStatus.Errored;
+            }
+
+            return (DeviceStatus)data.Data[1];
+        }
+
+        public void Dispose()
+        {
+            Close();
+        }
+    }
+}

+ 11 - 0
dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/DeviceStatus.cs

@@ -0,0 +1,11 @@
+namespace DreamCheeky
+{
+    public enum DeviceStatus
+    {
+        Unknown = 0,
+        Errored = 1,
+        LidClosed = 21,
+        ButtonPressed = 22,
+        LidOpen = 23
+    }
+}

+ 72 - 0
dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/DreamCheeky.BigRedButton.csproj

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{C24D8F95-9973-4941-86DF-ADD4212DEAA3}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>DreamCheeky</RootNamespace>
+    <AssemblyName>DreamCheeky.BigRedButton</AssemblyName>
+    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+    <RestorePackages>true</RestorePackages>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="HidLibrary">
+      <HintPath>..\packages\hidlibrary.3.2.28.0\lib\HidLibrary.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Device.cs" />
+    <Compile Include="DeviceStatus.cs" />
+    <Compile Include="BigRedButton.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="DreamCheeky.BigRedButton.nuspec" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
+  </Target>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 18 - 0
dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/DreamCheeky.BigRedButton.nuspec

@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<package>
+  <metadata>
+    <id>DreamCheeky.BigRedButton</id>
+    <version>$version$</version>
+    <authors>Michael Benford</authors>
+    <owners>Michael Benford</owners>
+    <licenseUrl>https://github.com/mbenford/dreamcheeky-big-red-button-dotnet/blob/master/LICENSE</licenseUrl>
+    <projectUrl>https://github.com/mbenford/dreamcheeky-big-red-button-dotnet</projectUrl>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <description>.NET class for Dream Cheeky's Big Red Button toy</description>
+    <copyright>Copyright 2014 Michael Benford</copyright>
+    <tags>DreamCheeky BigRedButton</tags>
+    <dependencies>
+      <dependency id="hidlibrary" version="3.2.28.0" />
+    </dependencies>
+  </metadata>
+</package>

+ 36 - 0
dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("DreamCheeky.BigRedButton")]
+[assembly: AssemblyDescription(".NET class for Dream Cheeky's Big Red Button toy")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("DreamCheeky.BigRedButton")]
+[assembly: AssemblyCopyright("Copyright © 2014 Michael Benford")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f06acd32-3bb1-45f8-a36e-5c05dc1dacb7")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 4 - 0
dreamcheeky-big-red-button-dotnet/DreamCheeky.BigRedButton/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="hidlibrary" version="3.2.28.0" targetFramework="net45" />
+</packages>

+ 21 - 0
dreamcheeky-big-red-button-dotnet/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Michael Benford
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 33 - 0
dreamcheeky-big-red-button-dotnet/README.md

@@ -0,0 +1,33 @@
+# Dream Cheeky's Big Red Button class for .NET
+
+## Installing
+
+To install DreamCheeky.BigRedButton package, run the following command in the Package Manager Console inside Visual Studio:
+
+    Install-Package DreamCheeky.BigRedButton
+    
+The package currently depends on [hidlibrary](https://www.nuget.org/packages/hidlibrary/) (≥ 3.2.28).
+
+## Usage
+
+```csharp
+using DreamCheeky;
+
+class Program
+{
+    static void Main()
+    {
+        using (var bigRedButton = new BigRedButton())
+        {
+            bigRedButton.LidClosed += (sender, args) => Console.WriteLine("Lid closed");
+            bigRedButton.LidOpen += (sender, args) => Console.WriteLine("Lid open");
+            bigRedButton.ButtonPressed += (sender, args) => Console.WriteLine("Button pressed");
+
+            bigRedButton.Start();
+
+            Console.WriteLine("Press ENTER to exit");
+            Console.ReadLine();
+        }
+    }
+}
+```

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
dreamcheeky-big-red-button-dotnet/Test.Application/.vs/Test.Application.csproj.dtbcache.json


+ 6 - 0
dreamcheeky-big-red-button-dotnet/Test.Application/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
+    </startup>
+</configuration>

+ 57 - 0
dreamcheeky-big-red-button-dotnet/Test.Application/Program.cs

@@ -0,0 +1,57 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+using DreamCheeky;
+using WindowsInput;
+using WindowsInput.Native;
+
+namespace Test.Application
+{
+    class Program
+    {
+        [DllImport("user32.dll")]
+        private static extern bool SetForegroundWindow(IntPtr hWnd);
+        static void Main()
+        {
+            InputSimulator inputSimulator = new InputSimulator();
+            using (var bigRedButton = new BigRedButton())
+            {
+                bigRedButton.LidOpen += (sender, args) => {
+                    var prc = Process.GetProcessesByName("idea64");
+                    if (prc.Length > 0)
+                    {
+                        SetForegroundWindow(prc[0].MainWindowHandle);
+                    }
+                };
+                bigRedButton.ButtonPressed += (sender, args) =>
+                {
+                    var prc = Process.GetProcessesByName("idea64");
+                    if (prc.Length > 0)
+                    {
+                        SetForegroundWindow(prc[0].MainWindowHandle);
+                        inputSimulator.Keyboard.KeyDown(VirtualKeyCode.SHIFT);
+                        inputSimulator.Keyboard.KeyPress(VirtualKeyCode.F9);
+                        inputSimulator.Keyboard.KeyUp(VirtualKeyCode.SHIFT);
+                    }
+                    
+                };
+                bigRedButton.LidClosed += (sender, args) =>
+                {
+                    var prc = Process.GetProcessesByName("idea64");
+                    if (prc.Length > 0)
+                    {
+                        inputSimulator.Keyboard.KeyDown(VirtualKeyCode.CONTROL);
+                        inputSimulator.Keyboard.KeyPress(VirtualKeyCode.F2);
+                        inputSimulator.Keyboard.KeyUp(VirtualKeyCode.CONTROL);
+                    }
+                };
+                bigRedButton.Start();
+
+                Console.WriteLine("Press ENTER to exit");
+                Console.ReadLine();
+            }
+        }
+    }
+ 
+}

+ 36 - 0
dreamcheeky-big-red-button-dotnet/Test.Application/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Test.Application")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Test.Application")]
+[assembly: AssemblyCopyright("Copyright ©  2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("d1128fd2-391e-44ec-9784-4d1f7d87e9b1")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 70 - 0
dreamcheeky-big-red-button-dotnet/Test.Application/Test.Application.csproj

@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{1409DF36-AABC-4E31-9DCF-1694A4685138}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Test.Application</RootNamespace>
+    <AssemblyName>Test.Application</AssemblyName>
+    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+    <Reference Include="WindowsInput, Version=1.0.4.0, Culture=neutral, PublicKeyToken=9b287f7dc5073cad, processorArchitecture=MSIL">
+      <HintPath>..\packages\InputSimulator.1.0.4.0\lib\net20\WindowsInput.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\DreamCheeky.BigRedButton\DreamCheeky.BigRedButton.csproj">
+      <Project>{C24D8F95-9973-4941-86DF-ADD4212DEAA3}</Project>
+      <Name>DreamCheeky.BigRedButton</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 4 - 0
dreamcheeky-big-red-button-dotnet/Test.Application/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="InputSimulator" version="1.0.4.0" targetFramework="net48" />
+</packages>

+ 22 - 0
dreamcheekyusb/.gitattributes

@@ -0,0 +1,22 @@
+# Auto detect text files and perform LF normalization
+* text=auto
+
+# Custom for Visual Studio
+*.cs     diff=csharp
+*.sln    merge=union
+*.csproj merge=union
+*.vbproj merge=union
+*.fsproj merge=union
+*.dbproj merge=union
+
+# Standard to msysgit
+*.doc	 diff=astextplain
+*.DOC	 diff=astextplain
+*.docx diff=astextplain
+*.DOCX diff=astextplain
+*.dot  diff=astextplain
+*.DOT  diff=astextplain
+*.pdf  diff=astextplain
+*.PDF	 diff=astextplain
+*.rtf	 diff=astextplain
+*.RTF	 diff=astextplain

+ 165 - 0
dreamcheekyusb/.gitignore

@@ -0,0 +1,165 @@
+#################
+## Eclipse
+#################
+
+*.pydevproject
+.project
+.metadata
+#bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.classpath
+.settings/
+.loadpath
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+
+#################
+## Visual Studio
+#################
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+#[Dd]ebug/
+#[Rr]elease/
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.vspscc
+.builds
+*.dotCover
+*.vshost.exe
+*.vshost.exe.manifest
+
+## TODO: If you have NuGet Package Restore enabled, uncomment this
+#packages/
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+
+# Visual Studio profiler
+*.psess
+*.vsp
+
+# ReSharper is a .NET coding add-in
+_ReSharper*
+
+# Installshield output folder
+[Ee]xpress
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish
+
+# Others
+#[Bb]in
+[Oo]bj
+sql
+TestResults
+*.Cache
+ClientBin
+stylecop.*
+~$*
+*.dbmdl
+Generated_Code #added for RIA/Silverlight projects
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+
+
+
+############
+## Windows
+############
+
+# Windows image file caches
+Thumbs.db
+
+# Folder config file
+Desktop.ini
+
+
+#############
+## Python
+#############
+
+*.py[co]
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+#bin
+var
+sdist
+develop-eggs
+.installed.cfg
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+
+#Translations
+*.mo
+
+#Mr Developer
+.mr.developer.cfg
+
+# Mac crap
+.DS_Store

BIN
dreamcheekyusb/.vs/DreamCheekyUSB/FileContentIndex/9e2b2be3-3b87-41bd-96ad-5624c44d72ab.vsidx


+ 88 - 0
dreamcheekyusb/.vs/DreamCheekyUSB/v17/DocumentLayout.backup.json

@@ -0,0 +1,88 @@
+{
+  "Version": 1,
+  "WorkspaceRootPath": "C:\\Git\\dreamcheekyusb\\",
+  "Documents": [
+    {
+      "AbsoluteMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|c:\\git\\dreamcheekyusb\\dreamcheekyled\\dreamcheekyled_outlook.ps1||{3B902123-F8A7-4915-9F01-361F908088D0}",
+      "RelativeMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|solutionrelative:dreamcheekyled\\dreamcheekyled_outlook.ps1||{3B902123-F8A7-4915-9F01-361F908088D0}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|c:\\git\\dreamcheekyusb\\dreamcheekyled\\dreamcheekyled.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|solutionrelative:dreamcheekyled\\dreamcheekyled.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|c:\\git\\dreamcheekyusb\\dreamcheekyled\\dreamcheekyled.ps1||{3B902123-F8A7-4915-9F01-361F908088D0}",
+      "RelativeMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|solutionrelative:dreamcheekyled\\dreamcheekyled.ps1||{3B902123-F8A7-4915-9F01-361F908088D0}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|c:\\git\\dreamcheekyusb\\dreamcheekyled\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|solutionrelative:dreamcheekyled\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    }
+  ],
+  "DocumentGroupContainers": [
+    {
+      "Orientation": 0,
+      "VerticalTabListWidth": 256,
+      "DocumentGroups": [
+        {
+          "DockedWidth": 200,
+          "SelectedChildIndex": 0,
+          "Children": [
+            {
+              "$type": "Document",
+              "DocumentIndex": 0,
+              "Title": "DreamCheekyLED_Outlook.ps1",
+              "DocumentMoniker": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED_Outlook.ps1",
+              "RelativeDocumentMoniker": "DreamCheekyLED\\DreamCheekyLED_Outlook.ps1",
+              "ToolTip": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED_Outlook.ps1",
+              "RelativeToolTip": "DreamCheekyLED\\DreamCheekyLED_Outlook.ps1",
+              "ViewState": "AgIAACoAAAAAAAAAAAAAAA0AAAAWAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
+              "WhenOpened": "2024-12-26T05:48:20.756Z",
+              "EditorCaption": ""
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 1,
+              "Title": "DreamCheekyLED.cs",
+              "DocumentMoniker": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED.cs",
+              "RelativeDocumentMoniker": "DreamCheekyLED\\DreamCheekyLED.cs",
+              "ToolTip": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED.cs",
+              "RelativeToolTip": "DreamCheekyLED\\DreamCheekyLED.cs",
+              "ViewState": "AgIAAJIAAAAAAAAAAAAcwKMAAAA8AAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-12-26T05:31:25.572Z",
+              "EditorCaption": ""
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 2,
+              "Title": "DreamCheekyLED.ps1",
+              "DocumentMoniker": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED.ps1",
+              "RelativeDocumentMoniker": "DreamCheekyLED\\DreamCheekyLED.ps1",
+              "ToolTip": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED.ps1",
+              "RelativeToolTip": "DreamCheekyLED\\DreamCheekyLED.ps1",
+              "ViewState": "AgIAAAwAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
+              "WhenOpened": "2024-12-26T05:08:14.863Z",
+              "EditorCaption": ""
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 3,
+              "Title": "Program.cs",
+              "DocumentMoniker": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\Program.cs",
+              "RelativeDocumentMoniker": "DreamCheekyLED\\Program.cs",
+              "ToolTip": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\Program.cs",
+              "RelativeToolTip": "DreamCheekyLED\\Program.cs",
+              "ViewState": "AgIAACMAAAAAAAAAAAAuwDQAAAApAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-12-26T05:07:46.634Z",
+              "EditorCaption": ""
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}

+ 86 - 0
dreamcheekyusb/.vs/DreamCheekyUSB/v17/DocumentLayout.json

@@ -0,0 +1,86 @@
+{
+  "Version": 1,
+  "WorkspaceRootPath": "C:\\Git\\dreamcheekyusb\\",
+  "Documents": [
+    {
+      "AbsoluteMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|C:\\Git\\dreamcheekyusb\\dreamcheekyled\\dreamcheekyled.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|solutionrelative:dreamcheekyled\\dreamcheekyled.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|c:\\git\\dreamcheekyusb\\dreamcheekyled\\dreamcheekyled_outlook.ps1||{3B902123-F8A7-4915-9F01-361F908088D0}",
+      "RelativeMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|solutionrelative:dreamcheekyled\\dreamcheekyled_outlook.ps1||{3B902123-F8A7-4915-9F01-361F908088D0}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|C:\\Git\\dreamcheekyusb\\dreamcheekyled\\dreamcheekyled.ps1||{3B902123-F8A7-4915-9F01-361F908088D0}",
+      "RelativeMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|solutionrelative:dreamcheekyled\\dreamcheekyled.ps1||{3B902123-F8A7-4915-9F01-361F908088D0}"
+    },
+    {
+      "AbsoluteMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|C:\\Git\\dreamcheekyusb\\dreamcheekyled\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+      "RelativeMoniker": "D:0:0:{BC275517-0578-42CB-951B-3B7C3ABBF842}|DreamCheekyLED\\DreamCheekyLED.csproj|solutionrelative:dreamcheekyled\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+    }
+  ],
+  "DocumentGroupContainers": [
+    {
+      "Orientation": 0,
+      "VerticalTabListWidth": 256,
+      "DocumentGroups": [
+        {
+          "DockedWidth": 200,
+          "SelectedChildIndex": 1,
+          "Children": [
+            {
+              "$type": "Document",
+              "DocumentIndex": 1,
+              "Title": "DreamCheekyLED_Outlook.ps1",
+              "DocumentMoniker": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED_Outlook.ps1",
+              "RelativeDocumentMoniker": "DreamCheekyLED\\DreamCheekyLED_Outlook.ps1",
+              "ToolTip": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED_Outlook.ps1",
+              "RelativeToolTip": "DreamCheekyLED\\DreamCheekyLED_Outlook.ps1",
+              "ViewState": "AgIAABkAAAAAAAAAAAAQwD8AAAABAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
+              "WhenOpened": "2024-12-26T05:48:20.756Z",
+              "EditorCaption": ""
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 0,
+              "Title": "DreamCheekyLED.cs",
+              "DocumentMoniker": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED.cs",
+              "RelativeDocumentMoniker": "DreamCheekyLED\\DreamCheekyLED.cs",
+              "ToolTip": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED.cs",
+              "RelativeToolTip": "DreamCheekyLED\\DreamCheekyLED.cs",
+              "ViewState": "AgIAAHMAAAAAAAAAAAAkwIsAAAAPAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-12-26T05:31:25.572Z",
+              "EditorCaption": ""
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 2,
+              "Title": "DreamCheekyLED.ps1",
+              "DocumentMoniker": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED.ps1",
+              "RelativeDocumentMoniker": "DreamCheekyLED\\DreamCheekyLED.ps1",
+              "ToolTip": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\DreamCheekyLED.ps1",
+              "RelativeToolTip": "DreamCheekyLED\\DreamCheekyLED.ps1",
+              "ViewState": "AgIAAAwAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
+              "WhenOpened": "2024-12-26T05:08:14.863Z"
+            },
+            {
+              "$type": "Document",
+              "DocumentIndex": 3,
+              "Title": "Program.cs",
+              "DocumentMoniker": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\Program.cs",
+              "RelativeDocumentMoniker": "DreamCheekyLED\\Program.cs",
+              "ToolTip": "C:\\Git\\dreamcheekyusb\\DreamCheekyLED\\Program.cs",
+              "RelativeToolTip": "DreamCheekyLED\\Program.cs",
+              "ViewState": "AgIAACMAAAAAAAAAAAAuwDQAAAApAAAAAAAAAA==",
+              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+              "WhenOpened": "2024-12-26T05:07:46.634Z"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}

+ 7 - 0
dreamcheekyusb/Documentation.md

@@ -0,0 +1,7 @@
+DreamCheekyUSB provides .NET drivers for the Dream Cheeky Webmail Notifier (http://www.dreamcheeky.com/webmail-notifier) and the Dream Cheeky Iron Man USB Stress Button (http://www.amazon.com/Iron-Mann-USB-Power-Button/dp/B0041HQQVA)
+
+It was created using the [https://github.com/mikeobrien/HidLibrary/](https://github.com/mikeobrien/HidLibrary/) and is released under the Apache License V2.0
+
+You can control the LED using either DreamCheekyLED.exe with command line arguments or via C#/VB/Powershell using the DreamCheekyUSB.DreamCheekyLED object. The code supports multiple devices and has options for blinking and fading. See [DreamCheekyLED](DreamCheekyLED) for command line examples or the DreamCheekyLED*.ps1 files for powershell examples.
+
+The DreamCheekyBTN.exe has command line arguments that will let you run a program whenever the button is pressed or convert the button press events into a keyboard macro that can perform an action or be picked up by other programs like AutoHotKey. The code should also support multiple devices, and can be run multiple times for additional triggers. See [DreamCheekyBTN](DreamCheekyBTN) for command line examples or the AutoHotKey.ahk file for a sample AutoHotKey script.

+ 57 - 0
dreamcheekyusb/DreamCheekyBTN.md

@@ -0,0 +1,57 @@
+DreamCheekyBTN is a Console based utility for the Dream Cheeky USB "Big Red Stress" buttons. Specifically this was created for the Iron Man button, but I assume it works with other Dream Cheeky USB buttons as well. It was created using the [http://github.com/mikeobrien/HidLibrary/](http://github.com/mikeobrien/HidLibrary/) and is released under the Apache License V2.0
+
+The DreamCheekyBTN.exe has command line arguments that will let you run a program whenever the button is pressed or convert the button press events into a keyboard macro that can perform an action or be picked up by other programs like AutoHotKey. The code should also support multiple devices, and can be run multiple times for additional triggers. See below for command line examples or the AutoHotKey.ahk file for a sample AutoHotKey script.
+
+**If you are interested in how this works at a high level the general process is:**
+
+1. Create HidDevice object using HidLibrary.HidDevices.Enumerate (default VendorID=0x1D34 and ProductID=0x0008)
+
+2. Use a System.Timers.Timer to poll the device every 100ms.
+
+3. First it sends the following command to get the device status:
+{"	public static readonly byte[]() cmd_status = new byte[9](9) { 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; "}
+
+4. Then it reads from the device one of the following two results:
+{" 
+byte[]() btn_Active =   new byte[9](9) { 0, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 };
+byte[]() btn_InActive = new byte[9](9) { 0, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 };
+NOTE: these values were found using the SimpleHIDWrite (http://www.lvr.com/hidpage.htm) and USBTrace programs 
+"}
+
+5. If the button is active, it will perform the requested action. The event then cannot be triggered again until after the button is released and pressed a second time. 
+
+
+## Command Line Usage:
+{"  DreamCheekyBTN.exe [device=...](device=...) [options](options) "}
+
+Examples:
+{"  DreamCheekyBTN.exe debug MACRO=ASDF~  (ASDF then Enter)
+  DreamCheekyBTN.exe MACRO=%+{F1}       (ALT+SHIFT+F1)
+  DreamCheekyBTN.exe CMD=c:\temp\test.bat
+  DreamCheekyBTN.exe CMD=powershell ARG="-noexit -executionpolicy unrestricted -File c:\test.ps1"
+"}
+
+Device Path:
+  Optional, Defaults to first USB device with VID=0x1D34 and PID=0x0008
+  Example (VID,PID,Index): device="0x1D34,0x0008,0"
+  Example (Path): device="\\?\hid#vid_1d34&pid_0008#6&1067c3dc&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+Options:
+  debug = Print trace statements to Console.Out
+
+CMD: will run specified command when button is pressed
+ARG: can be used to specified command arguments
+  Example (open calculator): CMD=calc
+  Example (run Powershell commands):
+     CMD="%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe"
+     ARG="-Command \"& {write-host 'BEEP!'; [console](console)::beep(440,1000);}\""
+  NOTE: use ^& instead of & if running from command prompt as & is special character
+
+{"
+MACRO: will send specified key sequense to active window via C# Sendkeys
+NOTE: +=Shift, ^=CTRL, %=ALT, ~=Return, use () to group characters.
+  Example: MACRO="%^g"        (ALT + CTRL + g)
+  Example: MACRO="%(asdf)"    (ALT + asdf)
+"}
+
+

BIN
dreamcheekyusb/DreamCheekyBTN/1347052316_system-red.ico


+ 14 - 0
dreamcheekyusb/DreamCheekyBTN/AutoHotkey.ahk

@@ -0,0 +1,14 @@
+;Sample AutoHotKey script for DreamCheekyBTN.exe
+;Author: Greg Bray 2012SEP07
+;Usage: Copy to your My Documents folder and then start AutoHotKey
+;See http://www.autohotkey.com/docs/ for full details
+;!=Alt, ^=Ctrl, +=Shift, #=Win
+Process, Close, DreamCheekyBTN.exe		;Kill any existing DreamCheekyBTN process whenever this script is loaded/reloaded
+
+Run, D:\Projects\DreamCheekyUSB\DreamCheekyBTN\bin\Release\DreamCheekyBTN.exe MACRO=`%+{F1} ;,,Hide
+;Above will start the DreamCheekyBTN program to listen for button presses and convert them to Alt+Shift+F1
+;Change ;,,Hide to just ,,Hide to start program in hidden mode.
+
+;^!r::Reload		;Ctrl+Alt+r = Reload this AutoHotKey script. Uncomment to enable fast debugging
+
+!+F1::Run www.google.com		;Alt+Shift+F1 from DreamCheekyBTN opens google.com

+ 178 - 0
dreamcheekyusb/DreamCheekyBTN/DreamCheekyBTN.cs

@@ -0,0 +1,178 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+using HidSharp;
+
+namespace DreamCheekyUSB {
+	public class DreamCheekyBTN : IDisposable {
+		#region Constant and readonly values
+
+		protected HidDeviceLoader Loader;
+		protected HidStream Stream;
+		public HidDevice HidBTN;
+		public const int DEFAULT_VENDOR_ID = 0x1D34;
+		//Default Vendor ID for Dream Cheeky devices
+		public const int DEFAULT_PRODUCT_ID = 0x0008;
+		//Default for Ironman USB stress button
+		public static class Messages {
+			public const byte BUTTON_PRESSED = 0x1C;
+		}
+		//Initialization values and test colors
+		public static readonly byte[] CmdStatus = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 };
+
+		#endregion
+
+		private AutoResetEvent WriteEvent = new AutoResetEvent(false);
+		private System.Timers.Timer t = new System.Timers.Timer(100);
+		//Timer for checking USB status every 100ms
+		private Action Timer_Callback;
+		private bool LidOpen;
+		protected byte ActivatedMessage;
+
+		#region Constructors
+
+		/// <summary>
+		/// Default constructor. Will used VendorID=0x1D34 and ProductID=0x0008. Will throw exception if no device is found.
+		/// </summary>
+		/// <param name="deviceIndex">Zero based device index if you have multiple devices plugged in.</param>
+		public DreamCheekyBTN(int deviceIndex = 0) : this(DEFAULT_VENDOR_ID, DEFAULT_PRODUCT_ID, deviceIndex) {
+		}
+
+		/// <summary>
+		/// Create object using VendorID and ProductID. Will throw exception if no USBLED is found.
+		/// </summary>
+		/// <param name="vendorID">Example to 0x1D34</param>
+		/// <param name="productID">Example to 0x0008</param>
+		/// <param name="deviceIndex">Zero based device index if you have multiple devices plugged in.</param>
+		public DreamCheekyBTN(int vendorID, int productID, int deviceIndex = 0) {
+			var loader = new HidDeviceLoader();
+			var devices = new List<HidDevice>(loader.GetDevices(vendorID, productID));
+			if (deviceIndex >= devices.Count) {
+				throw new ArgumentOutOfRangeException("deviceIndex", String.Format("VID={0},PID={1},DeviceIndex={2} is invalid. There are only {3} devices connected.", vendorID, productID, deviceIndex, devices.Count));
+			}
+			HidBTN = devices[deviceIndex];
+			if (!init()) {
+				throw new Exception(String.Format("Cannot find USB HID Device with VendorID=0x{0:X4} and ProductID=0x{1:X4}", vendorID, productID));
+			}
+			ActivatedMessage = Messages.BUTTON_PRESSED;
+		}
+
+		/// <summary>
+		/// Create object using Device path. Example: DreamCheekyBTN(@"\\?\hid#vid_1d34&pid_0008#6&1067c3dc&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}").
+		/// </summary>
+		/// <param name="devicePath">Example: @"\\?\hid#vid_1d34&pid_0008#6&1067c3dc&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"</param>
+		public DreamCheekyBTN(string devicePath) {
+			var loader = new HidDeviceLoader();
+			var devices = loader.GetDevices();
+			foreach (var device in devices) {
+				if (device.DevicePath == devicePath) {
+					HidBTN = device;
+				}
+			}
+			if (!init()) {
+				throw new Exception(String.Format("Cannot find USB HID Device with DevicePath={0}", devicePath));
+			}
+			ActivatedMessage = Messages.BUTTON_PRESSED;
+		}
+
+		/// <summary>
+		/// Private init function for constructors.
+		/// </summary>
+		/// <returns>True if success, false otherwise.</returns>
+		private bool init() {
+			WriteEvent.Reset();
+			t.AutoReset = true;
+			t.Elapsed += t_Elapsed;
+			t.Enabled = false;
+			t.Stop();
+			if (HidBTN == default(HidDevice)) {
+				return false; //Device not found, return false.
+			}
+
+			Stream = HidBTN.Open();
+			//Device is valid
+			Trace.WriteLine("Init HID device: " + HidBTN.ProductName + "\r\n");
+			return true;
+		}
+
+		public void Dispose() {
+			if (t != null) {
+				t.Dispose();
+				t = null;
+			}
+			Timer_Callback = null;
+
+			if (Stream != default(HidStream)) {
+				Stream.Close();
+				Stream.Dispose();
+				Stream = default(HidStream);
+			}
+		}
+
+		~DreamCheekyBTN() {
+			Dispose();
+		}
+
+		#endregion
+
+		public bool ButtonState { get; private set; }
+
+		private static bool IsUnix() {
+			var platform = Environment.OSVersion.Platform;
+			return (platform == PlatformID.MacOSX) || (platform == PlatformID.Unix);
+		}
+
+		public void Write(byte[] data) {
+			//Trace.WriteLine("\r\nWriteing Data=" + BitConverter.ToString(data));
+			if (IsUnix()) {
+				Stream.Write(data);
+			} else {
+				var windowsData = new byte[9];
+				data.CopyTo(windowsData, 1);
+				Stream.Write(windowsData);
+			}
+		}
+
+		public byte[] Read() {
+			return Stream.Read();
+		}
+
+		public bool GetStatus() {
+			Write(CmdStatus);
+			var data = Read();
+
+			var bigRedBtn = this as DreamCheekyBigRedBTN;
+			if (bigRedBtn != null) {
+				if (LidOpen && bigRedBtn.LidIsClosed()) {
+					LidOpen = false;
+					Console.WriteLine("{0}: Lid closed...", DateTime.Now.ToLongTimeString());
+				}
+				if (!LidOpen && bigRedBtn.LidIsOpen()) {
+					LidOpen = true;
+					Console.WriteLine("{0}: Lid opened...", DateTime.Now.ToLongTimeString());
+				}
+			}
+
+			return data[0] == ActivatedMessage;
+		}
+
+		public void RegisterCallback(Action callback) {
+			Timer_Callback = callback;
+			t.Enabled = true;
+			t.Start();
+		}
+
+		void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
+			if (GetStatus()) {
+				if (!ButtonState) { //Only toggle if button not already set
+					ButtonState = true;
+					Timer_Callback();
+				}
+			} else {
+				ButtonState = false; //Reset state
+			}
+		}
+	}
+}
+

+ 130 - 0
dreamcheekyusb/DreamCheekyBTN/DreamCheekyBTN.csproj

@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{3AC3E8E6-F4BE-4EC9-BBC3-3C1BFD8D213E}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>DreamCheekyUSB</RootNamespace>
+    <AssemblyName>DreamCheekyBTN</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <PropertyGroup>
+    <ApplicationIcon>1347052316_system-red.ico</ApplicationIcon>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="DreamCheekyBTN.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="DreamCheekyBigRedBTN.cs" />
+    <Compile Include="HidSharp\AsyncResult.cs" />
+    <Compile Include="HidSharp\HidDevice.cs" />
+    <Compile Include="HidSharp\HidDeviceLoader.cs" />
+    <Compile Include="HidSharp\HidStream.cs" />
+    <Compile Include="HidSharp\Throw.cs" />
+    <Compile Include="HidSharp\Platform\HidManager.cs" />
+    <Compile Include="HidSharp\Platform\HidSelector.cs" />
+    <Compile Include="HidSharp\Platform\Utf8Marshaler.cs" />
+    <Compile Include="HidSharp\Platform\Libusb\LibusbHidManager.cs" />
+    <Compile Include="HidSharp\Platform\Libusb\NativeMethods.cs" />
+    <Compile Include="HidSharp\Platform\Linux\LinuxHidDevice.cs" />
+    <Compile Include="HidSharp\Platform\Linux\LinuxHidManager.cs" />
+    <Compile Include="HidSharp\Platform\Linux\LinuxHidStream.cs" />
+    <Compile Include="HidSharp\Platform\Linux\NativeMethods.cs" />
+    <Compile Include="HidSharp\Platform\MacOS\MacHidDevice.cs" />
+    <Compile Include="HidSharp\Platform\MacOS\MacHidManager.cs" />
+    <Compile Include="HidSharp\Platform\MacOS\MacHidStream.cs" />
+    <Compile Include="HidSharp\Platform\MacOS\NativeMethods.cs" />
+    <Compile Include="HidSharp\Platform\Unsupported\UnsupportedHidManager.cs" />
+    <Compile Include="HidSharp\Platform\Windows\NativeMethods.cs" />
+    <Compile Include="HidSharp\Platform\Windows\WinHidDevice.cs" />
+    <Compile Include="HidSharp\Platform\Windows\WinHidManager.cs" />
+    <Compile Include="HidSharp\Platform\Windows\WinHidStream.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\CollectionType.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\DataMainItemFlags.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\EncodedItem.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\GlobalItemTag.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\ItemType.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\LocalItemTag.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\MainItemTag.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Parser\IndexBase.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Parser\IndexList.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Parser\IndexRange.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Parser\LocalIndexes.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Parser\Report.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Parser\ReportCollection.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Parser\ReportDescriptorParser.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Parser\ReportMainItem.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Parser\ReportSegment.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Parser\ReportType.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Units\CurrentUnit.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Units\LengthUnit.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Units\LuminousIntensityUnit.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Units\MassUnit.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Units\TemperatureUnit.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Units\TimeUnit.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Units\Unit.cs" />
+    <Compile Include="HidSharp\ReportDescriptors\Units\UnitSystem.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="1347052316_system-red.ico" />
+    <Content Include="Readme.txt">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="AutoHotkey.ahk">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="HidSharp\HidSharp.csproj" />
+    <None Include="HidSharp\obj\Debug\HidSharp.csproj.FilesWrittenAbsolute.txt" />
+    <None Include="HidSharp\obj\Debug\HidSharp.dll" />
+    <None Include="HidSharp\obj\Debug\HidSharp.dll.mdb" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <ItemGroup>
+    <Folder Include="HidSharp\" />
+  </ItemGroup>
+</Project>

+ 50 - 0
dreamcheekyusb/DreamCheekyBTN/DreamCheekyBigRedBTN.cs

@@ -0,0 +1,50 @@
+namespace DreamCheekyUSB {
+	public class DreamCheekyBigRedBTN : DreamCheekyBTN {
+		#region Constant and readonly values
+
+		new public const int DEFAULT_VENDOR_ID = 0x1D34;
+		new public const int DEFAULT_PRODUCT_ID = 0x000D;
+		//Default for USB Big Red Button
+		new public static class Messages {
+			public const byte LID_CLOSED = 0x15;
+			public const byte BUTTON_PRESSED = 0x16;
+			public const byte LID_OPEN = 0x17;
+		}
+
+		public const string PID = "000d";
+
+		#endregion
+
+		#region Constructors
+
+		public DreamCheekyBigRedBTN() {
+			ActivatedMessage = Messages.BUTTON_PRESSED;
+		}
+
+		public DreamCheekyBigRedBTN(int deviceIndex = 0) : base(DEFAULT_VENDOR_ID, DEFAULT_PRODUCT_ID, deviceIndex) {
+			ActivatedMessage = Messages.BUTTON_PRESSED;
+		}
+
+		public DreamCheekyBigRedBTN(int vendorID, int productID, int deviceIndex = 0) : base(vendorID, productID, deviceIndex) {
+			ActivatedMessage = Messages.BUTTON_PRESSED;
+		}
+
+		public DreamCheekyBigRedBTN(string devicePath) : base(devicePath) {
+			ActivatedMessage = Messages.BUTTON_PRESSED;
+		}
+
+		#endregion
+
+		public bool LidIsOpen() {
+			Write(CmdStatus);
+			var data = Read();
+			return data[0] == Messages.LID_OPEN;
+		}
+
+		public bool LidIsClosed() {
+			Write(CmdStatus);
+			var data = Read();
+			return data[0] == Messages.LID_CLOSED;
+		}
+	}
+}

+ 121 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/AsyncResult.cs

@@ -0,0 +1,121 @@
+#region License
+/* Copyright 2012 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Threading;
+
+namespace HidSharp
+{
+    class AsyncResult<T> : IAsyncResult
+    {
+        volatile bool _isCompleted;
+        ManualResetEvent _waitHandle;
+
+        AsyncResult(AsyncCallback callback, object state)
+        {
+            AsyncCallback = callback; AsyncState = state;
+        }
+
+        void Complete()
+        {
+            lock (this)
+            {
+                if (_isCompleted) { return; } _isCompleted = true;
+                if (_waitHandle != null) { _waitHandle.Set(); }
+            }
+
+            if (AsyncCallback != null) { AsyncCallback(this); }
+        }
+
+        internal delegate T OperationCallback();
+
+        internal static IAsyncResult BeginOperation(OperationCallback operation,
+            AsyncCallback callback, object state)
+        {
+            var ar = new AsyncResult<T>(callback, state);
+            ThreadPool.QueueUserWorkItem(delegate(object self)
+            {
+                try { ar.Result = operation(); }
+                catch (Exception e) { ar.Exception = e; }
+                ar.Complete();
+            }, ar);
+            return ar;
+        }
+
+        internal T EndOperation()
+        {
+            while (true)
+            {
+                if (IsCompleted)
+                {
+                    if (Exception != null) { throw Exception; }
+                    return Result;
+                }
+                AsyncWaitHandle.WaitOne();
+            }
+        }
+
+        public AsyncCallback AsyncCallback
+        {
+            get;
+            private set;
+        }
+
+        public object AsyncState
+        {
+            get;
+            private set;
+        }
+
+        public WaitHandle AsyncWaitHandle
+        {
+            get
+            {
+                lock (this)
+                {
+                    if (_waitHandle == null)
+                    {
+                        _waitHandle = new ManualResetEvent(_isCompleted);
+                    }
+                }
+
+                return _waitHandle;
+            }
+        }
+
+        public bool CompletedSynchronously
+        {
+            get { return false; }
+        }
+
+        public bool IsCompleted
+        {
+            get { return _isCompleted; }
+        }
+
+        Exception Exception
+        {
+            get;
+            set;
+        }
+
+        T Result
+        {
+            get;
+            set;
+        }
+    }
+}

+ 153 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/HidDevice.cs

@@ -0,0 +1,153 @@
+#region License
+/* Copyright 2010-2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Globalization;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace HidSharp
+{
+    /// <summary>
+    /// Represents a USB HID class device.
+    /// </summary>
+    [ComVisible(true), Guid("4D8A9A1A-D5CC-414e-8356-5A025EDA098D")]
+    public abstract class HidDevice
+    {
+        /// <summary>
+        /// Makes a connection to the USB HID class device, or throws an exception if the connection cannot be made.
+        /// </summary>
+        /// <returns>The stream to use to communicate with the device.</returns>
+        public abstract HidStream Open();
+
+        /// <summary>
+        /// Returns the raw report descriptor of the USB device.
+        /// Currently this is only supported on Linux.
+        /// </summary>
+        /// <returns>The report descriptor.</returns>
+        public virtual byte[] GetReportDescriptor()
+        {
+            throw new NotSupportedException(); // Windows without libusb can't... Linux can.
+        }
+
+        /// <summary>
+        /// Tries to make a connection to the USB HID class device.
+        /// </summary>
+        /// <param name="stream">The stream to use to communicate with the device.</param>
+        /// <returns>True if the connetion was successful.</returns>
+        public bool TryOpen(out HidStream stream)
+        {
+            try
+			{
+				stream = Open();
+				return true;
+			}
+            catch (Exception e)
+			{
+#if DEBUG
+				Console.WriteLine(e);
+#endif
+				stream = null; return false;
+			}
+		}
+
+        /// <summary>
+        /// The operating system's name for the device.
+        /// 
+        /// If you have multiple devices with the same Vendor ID, Product ID, Serial Number. etc.,
+        /// this may be useful for differentiating them.
+        /// </summary>
+        public abstract string DevicePath
+        {
+            get;
+        }
+
+        /// <summary>
+        /// The maximum input report length, including the Report ID byte.
+        /// If the device does not use Report IDs, the first byte will always be 0.
+        /// </summary>
+        public abstract int MaxInputReportLength { get; }
+
+        /// <summary>
+        /// The maximum output report length, including the Report ID byte.
+        /// If the device does not use Report IDs, use 0 for the first byte.
+        /// </summary>
+        public abstract int MaxOutputReportLength { get; }
+
+        /// <summary>
+        /// The maximum feature report length, including the Report ID byte.
+        /// If the device does not use Report IDs, use 0 for the first byte.
+        /// </summary>
+        public abstract int MaxFeatureReportLength { get; }
+
+        /// <summary>
+        /// The manufacturer name.
+        /// </summary>
+        public abstract string Manufacturer
+        {
+            get;
+        }
+
+        /// <summary>
+        /// The USB product ID. These are listed at: http://usb-ids.gowdy.us
+        /// </summary>
+        public abstract int ProductID
+        {
+            get;
+        }
+
+        /// <summary>
+        /// The product name.
+        /// </summary>
+        public abstract string ProductName
+        {
+            get;
+        }
+
+        /// <summary>
+        /// The product version.
+        /// This is a 16-bit number encoding the major and minor versions in the upper and lower 8 bits, respectively.
+        /// </summary>
+        public abstract int ProductVersion
+        {
+            get;
+        }
+
+        /// <summary>
+        /// The device serial number.
+        /// </summary>
+        public abstract string SerialNumber
+        {
+            get;
+        }
+
+        /// <summary>
+        /// The USB vendor ID. These are listed at: http://usb-ids.gowdy.us
+        /// </summary>
+        public abstract int VendorID
+        {
+            get;
+        }
+
+        /// <inheritdoc />
+        public override string ToString()
+        {
+            return string.Format(CultureInfo.InvariantCulture, "{0} ({1}VID {2}, PID {3}, version {4})",
+                Manufacturer.Length > 0 || ProductName.Length > 0 ? Manufacturer.Trim() + " " + ProductName.Trim() : "(unnamed)",
+                SerialNumber.Length > 0 ? "serial " + SerialNumber.Trim() + ", " : "", VendorID, ProductID, ProductVersion);
+        }
+    }
+}

+ 96 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/HidDeviceLoader.cs

@@ -0,0 +1,96 @@
+#region License
+/* Copyright 2010, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+namespace HidSharp
+{
+    /// <summary>
+    /// Detects USB HID class devices connected to the system.
+    /// </summary>
+    [ComVisible(true), Guid("CD7CBD7D-7204-473c-AA2A-2B9622CFC6CC")]
+    public class HidDeviceLoader
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="HidDeviceLoader"/> class.
+        /// </summary>
+        public HidDeviceLoader()
+        {
+
+        }
+
+        /// <summary>
+        /// Gets a list of connected USB devices.
+        /// This overload is meant for Visual Basic 6 and COM clients.
+        /// </summary>
+        /// <returns>The device list.</returns>
+        public IEnumerable GetDevicesVB()
+        {
+            return GetDevices();
+        }
+
+        /// <summary>
+        /// Gets a list of connected USB devices.
+        /// </summary>
+        /// <returns>The device list.</returns>
+        public IEnumerable<HidDevice> GetDevices()
+        {
+            return Platform.HidSelector.Instance.GetDevices();
+        }
+
+        /// <summary>
+        /// Gets a list of connected USB devices, filtered by some criteria.
+        /// </summary>
+        /// <param name="vendorID">The vendor ID, or null to not filter by vendor ID.</param>
+        /// <param name="productID">The product ID, or null to not filter by product ID.</param>
+        /// <param name="productVersion">The product version, or null to not filter by product version.</param>
+        /// <param name="serialNumber">The serial number, or null to not filter by serial number.</param>
+        /// <returns>The filtered device list.</returns>
+        public IEnumerable<HidDevice> GetDevices
+            (int? vendorID = null, int? productID = null, int? productVersion = null, string serialNumber = null)
+        {
+            int vid = vendorID ?? -1, pid = productID ?? -1, ver = productVersion ?? -1;
+            foreach (HidDevice hid in GetDevices())
+            {
+                if ((hid.VendorID == vendorID || vid < 0) &&
+                    (hid.ProductID == productID || pid < 0) &&
+                    (hid.ProductVersion == productVersion || ver < 0) &&
+                    (hid.SerialNumber == serialNumber || string.IsNullOrEmpty(serialNumber)))
+                {
+                    yield return hid;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the first connected USB device that matches specified criteria.
+        /// </summary>
+        /// <param name="vendorID">The vendor ID, or null to not filter by vendor ID.</param>
+        /// <param name="productID">The product ID, or null to not filter by product ID.</param>
+        /// <param name="productVersion">The product version, or null to not filter by product version.</param>
+        /// <param name="serialNumber">The serial number, or null to not filter by serial number.</param>
+        /// <returns>The device, or null if none was found.</returns>
+        public HidDevice GetDeviceOrDefault
+            (int? vendorID = null, int? productID = null, int? productVersion = null, string serialNumber = null)
+        {
+            return GetDevices(vendorID, productID, productVersion, serialNumber).FirstOrDefault();
+        }
+    }
+}

+ 107 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/HidSharp.csproj

@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{0DB86674-2A7B-4BDC-93C1-3F7DC771426C}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HidSharp</RootNamespace>
+    <AssemblyName>HidSharp</AssemblyName>
+    <FileAlignment>512</FileAlignment>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <UpgradeBackupLocation>
+    </UpgradeBackupLocation>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <RegisterForComInterop>false</RegisterForComInterop>
+    <DocumentationFile>..\bin\HidSharp.XML</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <RegisterForComInterop>true</RegisterForComInterop>
+    <DocumentationFile>..\bin\HidSharp.XML</DocumentationFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AsyncResult.cs" />
+    <Compile Include="Throw.cs" />
+    <Compile Include="HidDevice.cs" />
+    <Compile Include="HidDeviceLoader.cs" />
+    <Compile Include="HidStream.cs" />
+    <Compile Include="Platform\HidSelector.cs" />
+    <Compile Include="Platform\HidManager.cs" />
+    <Compile Include="Platform\Utf8Marshaler.cs" />
+    <Compile Include="Platform\Windows\NativeMethods.cs" />
+    <Compile Include="Platform\Windows\WinHidDevice.cs" />
+    <Compile Include="Platform\Windows\WinHidManager.cs" />
+    <Compile Include="Platform\Windows\WinHidStream.cs" />
+    <Compile Include="Platform\Linux\NativeMethods.cs" />
+    <Compile Include="Platform\Linux\LinuxHidDevice.cs" />
+    <Compile Include="Platform\Linux\LinuxHidManager.cs" />
+    <Compile Include="Platform\Linux\LinuxHidStream.cs" />
+    <Compile Include="Platform\MacOS\NativeMethods.cs" />
+    <Compile Include="Platform\MacOS\MacHidDevice.cs" />
+    <Compile Include="Platform\MacOS\MacHidManager.cs" />
+    <Compile Include="Platform\MacOS\MacHidStream.cs" />
+    <Compile Include="Platform\Libusb\NativeMethods.cs" />
+    <Compile Include="Platform\Libusb\LibusbHidManager.cs" />
+    <Compile Include="Platform\Unsupported\UnsupportedHidManager.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ReportDescriptors\CollectionType.cs" />
+    <Compile Include="ReportDescriptors\DataMainItemFlags.cs" />
+    <Compile Include="ReportDescriptors\GlobalItemTag.cs" />
+    <Compile Include="ReportDescriptors\Parser\LocalIndexes.cs" />
+    <Compile Include="ReportDescriptors\LocalItemTag.cs" />
+    <Compile Include="ReportDescriptors\EncodedItem.cs" />
+    <Compile Include="ReportDescriptors\MainItemTag.cs" />
+    <Compile Include="ReportDescriptors\ItemType.cs" />
+    <Compile Include="ReportDescriptors\Parser\IndexBase.cs" />
+    <Compile Include="ReportDescriptors\Parser\IndexList.cs" />
+    <Compile Include="ReportDescriptors\Parser\IndexRange.cs" />
+    <Compile Include="ReportDescriptors\Parser\Report.cs" />
+    <Compile Include="ReportDescriptors\Parser\ReportCollection.cs" />
+    <Compile Include="ReportDescriptors\Parser\ReportDescriptorParser.cs" />
+    <Compile Include="ReportDescriptors\Parser\ReportMainItem.cs" />
+    <Compile Include="ReportDescriptors\Parser\ReportSegment.cs" />
+    <Compile Include="ReportDescriptors\Parser\ReportType.cs" />
+    <Compile Include="ReportDescriptors\Units\CurrentUnit.cs" />
+    <Compile Include="ReportDescriptors\Units\LengthUnit.cs" />
+    <Compile Include="ReportDescriptors\Units\LuminousIntensityUnit.cs" />
+    <Compile Include="ReportDescriptors\Units\MassUnit.cs" />
+    <Compile Include="ReportDescriptors\Units\TemperatureUnit.cs" />
+    <Compile Include="ReportDescriptors\Units\TimeUnit.cs" />
+    <Compile Include="ReportDescriptors\Units\Unit.cs" />
+    <Compile Include="ReportDescriptors\Units\UnitSystem.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <ItemGroup />
+</Project>

+ 334 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/HidStream.cs

@@ -0,0 +1,334 @@
+#region License
+/* Copyright 2012-2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+#pragma warning disable 420
+
+namespace HidSharp {
+	/// <summary>
+	/// Communicates with a USB HID class device.
+	/// </summary>
+	[ComVisible(true), Guid("0C263D05-0D58-4c6c-AEA7-EB9E0C5338A2")]
+	public abstract class HidStream : Stream {
+		int _opened, _closed;
+		volatile int _refCount;
+
+		internal class CommonOutputReport {
+			public byte[] Bytes;
+			public bool DoneOK, Feature;
+			public volatile bool Done;
+		}
+
+		internal HidStream() {
+			ReadTimeout = 3000;
+			WriteTimeout = 3000;
+		}
+
+		internal static int GetTimeout(int startTime, int timeout) {
+			return Math.Min(timeout, Math.Max(0, startTime + timeout - Environment.TickCount));
+		}
+
+		internal int CommonRead(byte[] buffer, int offset, int count, Queue<byte[]> queue) {
+			Throw.If.OutOfRange(buffer, offset, count);
+			if (count == 0) {
+				return 0;
+			}
+
+			int readTimeout = ReadTimeout;
+			int startTime = Environment.TickCount;
+			int timeout;
+
+			HandleAcquireIfOpenOrFail();
+			try {
+				lock (queue) {
+					while (true) {
+						if (queue.Count > 0) {
+							byte[] packet = queue.Dequeue();
+							count = Math.Min(count, packet.Length);
+							Array.Copy(packet, 0, buffer, offset, count);
+							return count;
+						}
+	
+						timeout = GetTimeout(startTime, readTimeout);
+						if (!Monitor.Wait(queue, timeout)) {
+							throw new TimeoutException();
+						}
+					}
+				}
+			} finally {
+				HandleRelease();
+			}
+		}
+
+		internal void CommonWrite(byte[] buffer, int offset, int count,
+		                          Queue<CommonOutputReport> queue,
+		                          bool feature, int maxOutputReportLength) {
+			Throw.If.OutOfRange(buffer, offset, count);
+			count = Math.Min(count, maxOutputReportLength);
+			if (count == 0) {
+				return;
+			}
+
+			int writeTimeout = WriteTimeout;
+			int startTime = Environment.TickCount;
+			int timeout;
+			
+			HandleAcquireIfOpenOrFail();
+			try {
+				lock (queue) {
+					while (true) {
+						if (queue.Count == 0) {
+							byte[] packet = new byte[count];
+							Array.Copy(buffer, offset, packet, 0, count);
+							var outputReport = new CommonOutputReport { Bytes = packet, Feature = feature };
+							queue.Enqueue(outputReport);
+							Monitor.PulseAll(queue);
+	
+							while (true) {
+								if (outputReport.Done) {
+									if (!outputReport.DoneOK) {
+										throw new IOException();
+									}
+									return;
+								}
+	
+								timeout = GetTimeout(startTime, writeTimeout);
+								if (!Monitor.Wait(queue, timeout)) {
+									throw new TimeoutException();
+								}
+							}
+						}
+	
+						timeout = GetTimeout(startTime, writeTimeout);
+						if (!Monitor.Wait(queue, timeout)) {
+							throw new TimeoutException();
+						}
+					}
+				}
+			} finally {
+				HandleRelease();
+			}
+		}
+
+		/// <exclude />
+		public override void Flush() {
+            
+		}
+
+		/// <summary>
+		/// Sends a Get Feature setup request.
+		/// </summary>
+		/// <param name="buffer">The buffer to fill. Place the Report ID in the first byte.</param>
+		public void GetFeature(byte[] buffer) {
+			Throw.If.Null(buffer, "buffer");
+			GetFeature(buffer, 0, buffer.Length);
+		}
+
+		/// <summary>
+		/// Sends a Get Feature setup request.
+		/// </summary>
+		/// <param name="buffer">The buffer to fill. Place the Report ID in the byte at index <paramref name="offset"/>.</param>
+		/// <param name="offset">The index in the buffer to begin filling with data.</param>
+		/// <param name="count">The number of bytes in the feature request.</param>
+		public abstract void GetFeature(byte[] buffer, int offset, int count);
+
+		public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {
+			Throw.If.OutOfRange(buffer, offset, count);
+			return AsyncResult<int>.BeginOperation(() => Read(buffer, offset, count), callback, state);
+		}
+
+		/// <summary>
+		/// Reads HID Input Reports.
+		/// </summary>
+		/// <returns>The data read.</returns>
+		public byte[] Read() {
+			byte[] buffer = new byte[Device.MaxInputReportLength];
+			int bytes = Read(buffer);
+			Array.Resize(ref buffer, bytes);
+			return buffer;
+		}
+
+		/// <summary>
+		/// Reads HID Input Reports.
+		/// </summary>
+		/// <param name="buffer">The buffer to place the reports into.</param>
+		/// <returns>The number of bytes read.</returns>
+		public int Read(byte[] buffer) {
+			Throw.If.Null(buffer, "buffer");
+			return Read(buffer, 0, buffer.Length);
+		}
+
+		/// <inheritdoc />
+		public override int EndRead(IAsyncResult asyncResult) {
+			Throw.If.Null(asyncResult, "asyncResult");
+			return ((AsyncResult<int>)asyncResult).EndOperation();
+		}
+
+		/// <exclude />
+		public override long Seek(long offset, SeekOrigin origin) {
+			throw new NotSupportedException();
+		}
+
+		/// <summary>
+		/// Sends a Set Feature setup request.
+		/// </summary>
+		/// <param name="buffer">The buffer of data to send. Place the Report ID in the first byte.</param>
+		public void SetFeature(byte[] buffer) {
+			Throw.If.Null(buffer, "buffer");
+			SetFeature(buffer, 0, buffer.Length);
+		}
+
+		/// <summary>
+		/// Sends a Set Feature setup request.
+		/// </summary>
+		/// <param name="buffer">The buffer of data to send. Place the Report ID in the byte at index <paramref name="offset"/>.</param>
+		/// <param name="offset">The index in the buffer to start the write from.</param>
+		/// <param name="count">The number of bytes in the feature request.</param>
+		public abstract void SetFeature(byte[] buffer, int offset, int count);
+
+		/// <exclude />
+		public override void SetLength(long value) {
+			throw new NotSupportedException();
+		}
+
+		public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {
+			Throw.If.OutOfRange(buffer, offset, count);
+			return AsyncResult<int>.BeginOperation(delegate {
+				Write(buffer, offset, count);
+				return 0;
+			}, callback, state);
+		}
+
+		internal void HandleInitAndOpen() {
+			_opened = 1;
+			_refCount = 1;
+		}
+
+		internal bool HandleClose() {
+			return 0 == Interlocked.CompareExchange(ref _closed, 1, 0) && _opened != 0;
+		}
+
+		internal bool HandleAcquire() {
+			while (true) {
+				int refCount = _refCount;
+				if (refCount == 0) {
+					return false;
+				}
+				
+				if (refCount == Interlocked.CompareExchange
+				    (ref _refCount, refCount + 1, refCount)) {
+					return true;
+				}
+			}
+		}
+
+		internal void HandleAcquireIfOpenOrFail() {
+			if (_closed != 0 || !HandleAcquire()) {
+				throw new IOException("Closed.");
+			}
+		}
+
+		internal void HandleRelease() {
+			if (0 == Interlocked.Decrement(ref _refCount)) {
+				if (_opened != 0) {
+					HandleFree();
+				}
+			}
+		}
+
+		internal abstract void HandleFree();
+
+		/// <summary>
+		/// Writes an HID Output Report to the device.
+		/// </summary>
+		/// <param name="buffer">The buffer containing the report. Place the Report ID in the first byte.</param>
+		public void Write(byte[] buffer) {
+			Throw.If.Null(buffer, "buffer");
+			Write(buffer, 0, buffer.Length);
+		}
+
+		/// <inheritdoc />
+		public override void EndWrite(IAsyncResult asyncResult) {
+			Throw.If.Null(asyncResult, "asyncResult");
+			((AsyncResult<int>)asyncResult).EndOperation();
+		}
+
+		/// <exclude />
+		public override bool CanRead {
+			get { return true; }
+		}
+
+		/// <exclude />
+		public override bool CanSeek {
+			get { return false; }
+		}
+
+		/// <exclude />
+		public override bool CanWrite {
+			get { return true; }
+		}
+
+		/// <exclude />
+		public override bool CanTimeout {
+			get { return true; }
+		}
+
+		/// <summary>
+		/// Gets the <see cref="HidDevice"/> associated with this stream.
+		/// </summary>
+		public abstract HidDevice Device {
+			get;
+		}
+
+		/// <exclude />
+		public override long Length {
+			get { throw new NotSupportedException(); }
+		}
+
+		/// <exclude />
+		public override long Position {
+			get { throw new NotSupportedException(); }
+			set { throw new NotSupportedException(); }
+		}
+
+		/// <summary>
+		/// The maximum amount of time, in milliseconds, to wait for to receive a HID report.
+		/// 
+		/// The default is 3000 milliseconds.
+		/// To disable the timeout, set this to <see cref="Timeout.Infinite"/>.
+		/// </summary>
+		public sealed override int ReadTimeout {
+			get;
+			set;
+		}
+
+		/// <summary>
+		/// The maximum amount of time, in milliseconds, to wait for the device to acknowledge a HID report.
+		/// 
+		/// The default is 3000 milliseconds.
+		/// To disable the timeout, set this to <see cref="Timeout.Infinite"/>.
+		/// </summary>
+		public sealed override int WriteTimeout {
+			get;
+			set;
+		}
+	}
+}

+ 119 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/HidManager.cs

@@ -0,0 +1,119 @@
+#region License
+/* Copyright 2012-2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+
+namespace HidSharp.Platform
+{
+    abstract class HidManager
+    {
+        Dictionary<object, HidDevice> _deviceList;
+        object _syncRoot;
+
+        protected HidManager()
+        {
+            _deviceList = new Dictionary<object, HidDevice>();
+            _syncRoot = new object();
+        }
+
+        public virtual void Init()
+        {
+
+        }
+
+        public virtual void Run()
+        {
+            while (true) { Thread.Sleep(Timeout.Infinite); }
+        }
+
+        internal void RunImpl(object readyEvent)
+        {
+            Init();
+            ((ManualResetEvent)readyEvent).Set();
+            Run();
+        }
+
+        public IEnumerable<HidDevice> GetDevices()
+        {
+            lock (SyncRoot)
+            {
+                object[] devices = Refresh();
+                object[] additions = devices.Except(_deviceList.Keys).ToArray();
+                object[] removals = _deviceList.Keys.Except(devices).ToArray();
+
+                if (additions.Length > 0)
+                {
+                    int completedAdditions = 0;
+
+                    foreach (object addition in additions)
+                    {
+                        ThreadPool.QueueUserWorkItem(new WaitCallback(addition_ =>
+                            {
+                                HidDevice device; object creationState;
+                                bool created = TryCreateDevice(addition_, out device, out creationState);
+
+                                if (created)
+                                {
+                                    // By not adding on failure, we'll end up retrying every time.
+                                    lock (_deviceList) { _deviceList.Add(addition_, device); }
+                                }
+
+                                lock (_deviceList)
+                                {
+                                    completedAdditions++; Monitor.Pulse(_deviceList);
+                                }
+
+                                if (created)
+                                {
+                                    CompleteDevice(addition_, device, creationState);
+                                }
+                            }), addition);
+                    }
+
+                    lock (_deviceList)
+                    {
+                        while (completedAdditions != additions.Length) { Monitor.Wait(_deviceList); }
+                    }
+                }
+
+                foreach (object removal in removals)
+                {
+                    _deviceList.Remove(removal);
+                }
+
+                return _deviceList.Values.ToArray();
+            }
+        }
+
+        protected abstract object[] Refresh();
+
+        protected abstract bool TryCreateDevice(object key, out HidDevice device, out object creationState);
+
+        protected abstract void CompleteDevice(object key, HidDevice device, object creationState);
+
+        public abstract bool IsSupported
+        {
+            get;
+        }
+
+        protected object SyncRoot
+        {
+            get { return _syncRoot; }
+        }
+    }
+}

+ 51 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/HidSelector.cs

@@ -0,0 +1,51 @@
+#region License
+/* Copyright 2012-2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System.Threading;
+
+namespace HidSharp.Platform
+{
+    sealed class HidSelector
+    {
+        public static readonly HidManager Instance;
+        static readonly Thread ManagerThread; 
+
+        static HidSelector()
+        {
+            foreach (var hidManager in new HidManager[]
+                {
+                    new Windows.WinHidManager(),
+                    new Linux.LinuxHidManager(),
+                    new MacOS.MacHidManager(),
+                    new Unsupported.UnsupportedHidManager()
+                })
+            {
+                if (hidManager.IsSupported)
+                {
+                    var readyEvent = new ManualResetEvent(false);
+
+                    Instance = hidManager;
+                    ManagerThread = new Thread(Instance.RunImpl);
+                    ManagerThread.IsBackground = true;
+                    ManagerThread.Start(readyEvent);
+                    readyEvent.WaitOne();
+
+                    break;
+                }
+            }
+        }
+    }
+}

+ 26 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Libusb/LibusbHidManager.cs

@@ -0,0 +1,26 @@
+#region License
+/* Copyright 2012 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+
+namespace HidSharp.Platform.Libusb
+{
+	class LibusbHidManager
+	{
+		// TODO
+	}
+}
+

+ 230 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Libusb/NativeMethods.cs

@@ -0,0 +1,230 @@
+#region License
+/* Copyright 2012 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace HidSharp.Platform.Libusb
+{
+	static class NativeMethods
+	{
+		const string Libusb = "libusb-1.0";
+		
+		public struct DeviceDescriptor
+		{
+			public byte bLength, bDescriptorType;
+			public ushort bcdUSB;
+			public byte bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0;
+			public ushort idVendor, idProduct, bcdDevice;
+			public byte iManufacturer, iProduct, iSerialNumber, bNumConfigurations;
+		}
+	
+		public enum DeviceClass : byte
+		{
+			HID = 0x03,
+			MassStorage = 0x08,
+			VendorSpecific = 0xff
+		}
+		
+		public enum DescriptorType : byte
+		{
+			Device = 0x01,
+			Configuration = 0x02,
+			String = 0x03,
+			Interface = 0x04,
+			Endpoint = 0x05,
+			HID = 0x21,
+			Report = 0x22,
+			Physical = 0x23,
+			Hub = 0x29
+		}
+		
+		public enum EndpointDirection : byte
+		{
+			In = 0x80,
+			Out = 0,
+		}
+		
+		public enum Request : byte
+		{
+			GetDescriptor = 0x06
+		}
+		
+		public enum RequestRecipient : byte
+		{
+			Device = 0,
+			Interface = 1,
+			Endpoint = 2,
+			Other = 3
+		}
+		
+		public enum RequestType : byte
+		{
+			Standard = 0x00,
+			Class = 0x20,
+			Vendor = 0x40
+		}
+		
+		public enum TransferType : byte
+		{
+			Control = 0,
+			Isochronous,
+			Bulk,
+			Interrupt	
+		}
+		
+		public struct Version
+		{
+			public ushort Major, Minor, Micro, Nano;
+		}
+		
+		public enum Error
+		{
+			None = 0,
+			IO = -1,
+			InvalidParameter = -2,
+			AccessDenied = -3,
+			NoDevice = -4,
+			NotFound = -5,
+			Busy = -6,
+			Timeout = -7,
+			Overflow = -8,
+			Pipe = -9,
+			Interrupted = -10,
+			OutOfMemory = -11,
+			NotSupported = -12
+		}
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_init(out IntPtr context);
+		
+		[DllImport(Libusb)]
+		public static extern void libusb_set_debug(IntPtr context, int level);
+		
+		[DllImport(Libusb)]
+		public static extern void libusb_exit(IntPtr context);
+		
+		[DllImport(Libusb)]
+		public static extern IntPtr libusb_get_device_list(IntPtr context, out IntPtr list);
+		
+		[DllImport(Libusb)]
+		public static extern void libusb_free_device_list(IntPtr context, IntPtr list);
+		
+		[DllImport(Libusb)]
+		public static extern IntPtr libusb_ref_device(IntPtr device);
+		
+		[DllImport(Libusb)]
+		public static extern void libusb_unref_device(IntPtr device);
+		
+		[DllImport(Libusb)]
+		public static extern int libusb_get_max_packet_size(IntPtr device, byte endpoint);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_open(IntPtr device, out IntPtr deviceHandle);
+		
+		[DllImport(Libusb)]
+		public static extern void libusb_close(IntPtr deviceHandle);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_get_configuration(IntPtr deviceHandle, out int configuration);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_set_configuration(IntPtr deviceHandle, int configuration);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_claim_interface(IntPtr deviceHandle, int @interface);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_release_interface(IntPtr deviceHandle, int @interface);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_set_interface_alt_setting(IntPtr deviceHandle, int @interface, int altSetting);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_clear_halt(IntPtr deviceHandle, byte endpoint);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_reset_device(IntPtr deviceHandle);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_kernel_driver_active(IntPtr deviceHandle, int @interface);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_detach_kernel_driver(IntPtr deviceHandle, int @interface);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_attach_kernel_driver(IntPtr deviceHandle, int @interface);
+		
+		[DllImport(Libusb)]
+		public static extern IntPtr libusb_get_version();
+				
+		[DllImport(Libusb)]
+		public static extern Error libusb_get_device_descriptor(IntPtr device, out DeviceDescriptor descriptor);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_get_active_config_descriptor(IntPtr device, out IntPtr configuration);
+
+		[DllImport(Libusb)]
+		public static extern Error libusb_get_config_descriptor_by_value(IntPtr device, byte index, out IntPtr configuration);
+		
+		[DllImport(Libusb)]
+		public static extern void libusb_free_config_descriptor(IntPtr configuration);
+
+		static Error libusb_get_descriptor_core(IntPtr deviceHandle, DescriptorType type, byte index, byte[] data, ushort wLength, ushort wIndex)
+		{
+			return libusb_control_transfer(deviceHandle,
+			                               (byte)EndpointDirection.In, (byte)Request.GetDescriptor,
+			                               (ushort)((byte)DescriptorType.String << 8 | index),
+			                               wIndex, data, wLength, 1000);
+		}
+
+		public static Error libusb_get_descriptor(IntPtr deviceHandle, DescriptorType type, byte index, byte[] data, ushort wLength)
+		{
+			return libusb_get_descriptor_core(deviceHandle,
+			                                  type, index, data, wLength, 0);
+		}
+		
+		public static Error libusb_get_string_descriptor(IntPtr deviceHandle, DescriptorType type, byte index, ushort languageID, byte[] data, ushort wLength)
+		{
+			return libusb_get_descriptor_core(deviceHandle,
+			                                  DescriptorType.String, index,
+			                                  data, wLength, languageID);	
+		}
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_control_transfer(IntPtr deviceHandle,
+		                                            	   byte bmRequestType, byte bRequest,
+		                                            	   ushort wValue, ushort wIndex,
+		                                            	   byte[] data, ushort wLength,
+		                                            	   uint timeout);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_bulk_transfer(IntPtr deviceHandle,
+		                                         	    byte endpoint,
+		                                         	    byte[] data, int length,
+		                                         	    out int transferred,
+		                                         	    uint timeout);
+		
+		[DllImport(Libusb)]
+		public static extern Error libusb_interrupt_transfer(IntPtr deviceHandle,
+		                                         	  	     byte endpoint,
+		                                         	  	     byte[] data, int length,
+		                                         	  	     out int transferred,
+		                                         	  	     uint timeout);
+	}
+}
+

+ 196 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Linux/LinuxHidDevice.cs

@@ -0,0 +1,196 @@
+#region License
+/* Copyright 2012-2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+
+namespace HidSharp.Platform.Linux
+{
+    class LinuxHidDevice : HidDevice
+    {
+        string _manufacturer;
+        string _productName;
+        string _serialNumber;
+        byte[] _reportDescriptor;
+        int _vid, _pid, _version;
+        int _maxInput, _maxOutput, _maxFeature;
+        bool _reportsUseID;
+        string _path;
+
+        public LinuxHidDevice(string path)
+        {
+            _path = path;
+        }
+
+        public override HidStream Open()
+        {
+            var stream = new LinuxHidStream();
+            try { stream.Init(_path, this); return stream; }
+            catch { stream.Close(); throw; }
+        }
+
+        public override byte[] GetReportDescriptor()
+        {
+            return (byte[])_reportDescriptor.Clone();
+        }
+
+        static bool TryParseReportDescriptor(IntPtr device, out ReportDescriptors.Parser.ReportDescriptorParser parser, out byte[] reportDescriptor)
+        {
+            parser = null; reportDescriptor = null;
+			string devnode = NativeMethods.udev_device_get_devnode(device);
+            if (null == devnode) { return false; }
+            
+            int handle = NativeMethods.retry(() => NativeMethods.open
+                                        (devnode, NativeMethods.oflag.NONBLOCK));
+            if (handle < 0) { return false; }
+
+            try
+            {
+                uint descsize;
+                if (NativeMethods.ioctl(handle, NativeMethods.HIDIOCGRDESCSIZE, out descsize) < 0) { return false; }
+                if (descsize > NativeMethods.HID_MAX_DESCRIPTOR_SIZE) { return false; }
+
+                var desc = new NativeMethods.hidraw_report_descriptor() { size = descsize };
+                if (NativeMethods.ioctl(handle, NativeMethods.HIDIOCGRDESC, ref desc) < 0) { return false; }
+
+                Array.Resize(ref desc.value, (int)descsize);
+                parser = new ReportDescriptors.Parser.ReportDescriptorParser();
+                parser.Parse(desc.value); reportDescriptor = desc.value; return true;
+            }
+            finally
+            {
+                NativeMethods.retry(() => NativeMethods.close(handle));
+            }
+        }
+
+        internal unsafe bool GetInfo()
+        {
+            IntPtr udev = NativeMethods.udev_new();
+            if (IntPtr.Zero != udev)
+            {
+                try
+                {
+                    IntPtr device = NativeMethods.udev_device_new_from_syspath(udev, _path);
+                    if (device != IntPtr.Zero)
+                    {
+                        try
+                        {
+                            IntPtr parent = NativeMethods.udev_device_get_parent_with_subsystem_devtype(device, "usb", "usb_device");
+                            if (IntPtr.Zero != parent)
+                            {
+                                string manufacturer = NativeMethods.udev_device_get_sysattr_value(parent, "manufacturer") ?? "";
+                                string productName = NativeMethods.udev_device_get_sysattr_value(parent, "product") ?? "";
+                                string serialNumber = NativeMethods.udev_device_get_sysattr_value(parent, "serial") ?? "";
+                                string idVendor = NativeMethods.udev_device_get_sysattr_value(parent, "idVendor");
+                                string idProduct = NativeMethods.udev_device_get_sysattr_value(parent, "idProduct");
+                                string version = NativeMethods.udev_device_get_sysattr_value(parent, "version");
+
+                                int vid, pid, verMajor, verMinor;
+                                if (NativeMethods.TryParseHex(idVendor, out vid) &&
+                                    NativeMethods.TryParseHex(idProduct, out pid) &&
+                                    NativeMethods.TryParseVersion(version, out verMajor, out verMinor))
+                                {
+                                    _vid = vid;
+                                    _pid = pid;
+                                    _version = verMajor << 8 | verMinor;
+                                    _manufacturer = manufacturer;
+                                    _productName = productName;
+                                    _serialNumber = serialNumber;
+
+                                    ReportDescriptors.Parser.ReportDescriptorParser parser;
+                                    if (TryParseReportDescriptor(device, out parser, out _reportDescriptor))
+                                    {
+                                        // Follow the Windows convention: No Report ID? Report ID is 0.
+                                        // So, it's always one byte above the parser's result.
+                                        _maxInput = parser.InputReportMaxLength; if (_maxInput > 0) { _maxInput++; }
+                                        _maxOutput = parser.OutputReportMaxLength; if (_maxOutput > 0) { _maxOutput++; }
+                                        _maxFeature = parser.FeatureReportMaxLength; if (_maxFeature > 0) { _maxFeature++; }
+                                        _reportsUseID = parser.ReportsUseID;
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+                        finally
+                        {
+                            NativeMethods.udev_device_unref(device);
+                        }
+                    }
+                }
+                finally
+                {
+                    NativeMethods.udev_unref(udev);
+                }
+            }
+
+            return false;
+        }
+
+        public override string DevicePath
+        {
+            get { return _path; }
+        }
+
+        public override int MaxInputReportLength
+        {
+            get { return _maxInput; }
+        }
+
+        public override int MaxOutputReportLength
+        {
+            get { return _maxOutput; }
+        }
+
+        public override int MaxFeatureReportLength
+        {
+            get { return _maxFeature; }
+        }
+
+        internal bool ReportsUseID
+        {
+            get { return _reportsUseID; }
+        }
+
+        public override string Manufacturer
+        {
+            get { return _manufacturer; }
+        }
+
+        public override int ProductID
+        {
+            get { return _pid; }
+        }
+
+        public override string ProductName
+        {
+            get { return _productName; }
+        }
+
+        public override int ProductVersion
+        {
+            get { return _version; }
+        }
+
+        public override string SerialNumber
+        {
+            get { return _serialNumber; }
+        }
+
+        public override int VendorID
+        {
+            get { return _vid; }
+        }
+    }
+}

+ 109 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Linux/LinuxHidManager.cs

@@ -0,0 +1,109 @@
+#region License
+/* Copyright 2012 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HidSharp.Platform.Linux
+{
+    class LinuxHidManager : HidManager
+    {
+        protected override object[] Refresh()
+        {
+            var paths = new List<string>();
+
+	        IntPtr udev = NativeMethods.udev_new();
+            if (IntPtr.Zero != udev)
+            {
+                try
+                {
+                    IntPtr enumerate = NativeMethods.udev_enumerate_new(udev);
+                    if (IntPtr.Zero != enumerate)
+                    {
+                        try
+                        {
+                            if (0 == NativeMethods.udev_enumerate_add_match_subsystem(enumerate, "hidraw") &&
+                                0 == NativeMethods.udev_enumerate_scan_devices(enumerate))
+                            {
+                                IntPtr entry;
+                                for (entry = NativeMethods.udev_enumerate_get_list_entry(enumerate); entry != IntPtr.Zero;
+                                     entry = NativeMethods.udev_list_entry_get_next(entry))
+                                {
+                                    string syspath = NativeMethods.udev_list_entry_get_name(entry);
+                                    if (syspath != null) { paths.Add(syspath); }
+                                }
+                            }
+                        }
+                        finally
+                        {
+                            NativeMethods.udev_enumerate_unref(enumerate);
+                        }
+                    }
+                }
+                finally
+                {
+                    NativeMethods.udev_unref(udev);
+                }
+            }
+
+            return paths.Cast<object>().ToArray();
+        }
+
+        protected override bool TryCreateDevice(object key, out HidDevice device, out object creationState)
+        {
+            creationState = null;
+            string syspath = (string)key; var hidDevice = new LinuxHidDevice(syspath);
+            if (!hidDevice.GetInfo()) { device = null; return false; }
+            device = hidDevice; return true;
+        }
+
+        protected override void CompleteDevice(object key, HidDevice device, object creationState)
+        {
+            
+        }
+
+        public override bool IsSupported
+        {
+            get
+            {
+                try
+                {
+					string sysname; Version release; string machine;
+					if (NativeMethods.uname(out sysname, out release, out machine))
+					{
+						IntPtr udev = NativeMethods.udev_new();
+						if (IntPtr.Zero != udev)
+						{
+							NativeMethods.udev_unref(udev);
+							return sysname == "Linux" && release >= new Version(2, 6, 36);
+						}
+					}
+                }
+				catch
+				{
+					
+				}
+                finally
+                {
+
+                }
+
+                return false;
+            }
+        }
+    }
+}

+ 269 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Linux/LinuxHidStream.cs

@@ -0,0 +1,269 @@
+#region License
+/* Copyright 2012 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace HidSharp.Platform.Linux
+{
+    class LinuxHidStream : HidStream
+    {
+		Queue<byte[]> _inputQueue;
+		Queue<CommonOutputReport> _outputQueue;
+		
+		LinuxHidDevice _device;
+		int _handle;
+		Thread _readThread, _writeThread;
+		volatile bool _shutdown;
+		
+        internal LinuxHidStream()
+        {
+			_inputQueue = new Queue<byte[]>();
+			_outputQueue = new Queue<CommonOutputReport>();
+			_handle = -1;
+			_readThread = new Thread(ReadThread);
+			_readThread.IsBackground = true;
+			_writeThread = new Thread(WriteThread);
+			_writeThread.IsBackground = true;
+        }
+		
+		static int DeviceHandleFromPath(string path)
+		{
+			IntPtr udev = NativeMethods.udev_new();
+			if (IntPtr.Zero != udev)
+			{
+				try
+				{
+					IntPtr device = NativeMethods.udev_device_new_from_syspath(udev, path);
+					if (IntPtr.Zero != device)
+					{
+						try
+						{
+							string devnode = NativeMethods.udev_device_get_devnode(device);
+							if (devnode != null)
+							{
+								int handle = NativeMethods.retry(() => NativeMethods.open
+								                            (devnode, NativeMethods.oflag.RDWR | NativeMethods.oflag.NONBLOCK));
+								if (handle < 0)
+								{
+									var error = (NativeMethods.error)Marshal.GetLastWin32Error();
+									if (error == NativeMethods.error.EACCES)
+									{
+										throw new UnauthorizedAccessException("Not permitted to open HID class device at " + devnode + ".");
+									}
+									else
+									{
+										throw new IOException("Unable to open HID class device (" + error.ToString() + ").");
+									}
+								}
+								return handle;
+							}
+						}
+						finally
+						{
+							NativeMethods.udev_device_unref(device);
+						}
+					}
+				}
+				finally
+				{
+					NativeMethods.udev_unref(udev);
+				}
+			}
+			
+			throw new FileNotFoundException("HID class device not found.");
+		}
+		
+        internal void Init(string path, LinuxHidDevice device)
+        {
+			int handle;
+			handle = DeviceHandleFromPath(path);
+			
+			_device = device;
+			_handle = handle;
+			HandleInitAndOpen();
+			
+			_readThread.Start();
+			_writeThread.Start();
+        }
+		
+        protected override void Dispose(bool disposing)
+        {
+            base.Dispose(disposing);
+			if (!HandleClose()) { return; }
+			
+            _shutdown = true;
+            try { lock (_inputQueue) { Monitor.PulseAll(_inputQueue); } } catch { }
+			try { lock (_outputQueue) { Monitor.PulseAll(_outputQueue); } } catch { }
+
+            try { _readThread.Join(); } catch { }
+            try { _writeThread.Join(); } catch { }
+
+			HandleRelease();
+		}
+		
+		internal override void HandleFree()
+		{
+			NativeMethods.retry(() => NativeMethods.close(_handle)); _handle = -1;
+		}
+		
+		unsafe void ReadThread()
+		{
+			if (!HandleAcquire()) { return; }
+			
+			try
+			{
+				lock (_inputQueue)
+				{
+					while (true)
+					{
+						var fds = new NativeMethods.pollfd[1];
+						fds[0].fd = _handle;
+						fds[0].events = NativeMethods.pollev.IN;
+						
+						while (!_shutdown)
+						{
+						tryReadAgain:
+							int ret;
+							Monitor.Exit(_inputQueue);
+							try { ret = NativeMethods.retry(() => NativeMethods.poll(fds, (IntPtr)1, 250)); }
+							finally { Monitor.Enter(_inputQueue); }
+							if (ret != 1) { continue; }
+							
+							if (0 != (fds[0].revents & (NativeMethods.pollev.ERR | NativeMethods.pollev.HUP))) { break; }
+							if (0 != (fds[0].revents & NativeMethods.pollev.IN))
+							{
+                                // Linux doesn't provide a Report ID if the device doesn't use one.
+                                int inputLength = _device.MaxInputReportLength;
+                                if (inputLength > 0 && !_device.ReportsUseID) { inputLength--; }
+
+                                byte[] inputReport = new byte[inputLength];
+								fixed (byte* inputBytes = inputReport)
+								{
+                                    var inputBytesPtr = (IntPtr)inputBytes;
+									IntPtr length = NativeMethods.retry(() => NativeMethods.read
+									                               (_handle, inputBytesPtr, (IntPtr)inputReport.Length));
+									if ((long)length < 0)
+									{
+                                        var error = (NativeMethods.error)Marshal.GetLastWin32Error();
+										if (error != NativeMethods.error.EAGAIN) { break; }
+										goto tryReadAgain;
+									}
+
+									Array.Resize(ref inputReport, (int)length); // No Report ID? First byte becomes Report ID 0.
+                                    if (!_device.ReportsUseID) { inputReport = new byte[1].Concat(inputReport).ToArray(); }
+									_inputQueue.Enqueue(inputReport); Monitor.PulseAll(_inputQueue);
+								}
+							}
+						}
+						while (!_shutdown && _inputQueue.Count == 0) { Monitor.Wait(_inputQueue); }
+						if (_shutdown) { break; }
+						
+						_inputQueue.Dequeue();
+					}
+				}
+			}
+			finally
+			{
+				HandleRelease();
+			}
+		}
+		
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            return CommonRead(buffer, offset, count, _inputQueue);
+        }
+
+        public override void GetFeature(byte[] buffer, int offset, int count)
+        {
+            throw new NotSupportedException(); // TODO
+        }
+
+		unsafe void WriteThread()
+		{
+			if (!HandleAcquire()) { return; }
+			
+			try
+			{
+				lock (_outputQueue)
+				{
+					while (true)
+					{
+						while (!_shutdown && _outputQueue.Count == 0) { Monitor.Wait(_outputQueue); }
+						if (_shutdown) { break; }
+
+						CommonOutputReport outputReport = _outputQueue.Peek();
+
+                        // Linux doesn't expect a Report ID if the device doesn't use one.
+                        byte[] outputBytesRaw = outputReport.Bytes;
+                        if (!_device.ReportsUseID && outputBytesRaw.Length > 0) { outputBytesRaw = outputBytesRaw.Skip(1).ToArray(); }
+
+						try
+						{
+							fixed (byte* outputBytes = outputBytesRaw)
+							{
+								// hidraw is apparently blocking for output, even when O_NONBLOCK is used.
+								// See for yourself at drivers/hid/hidraw.c...
+                                IntPtr length;
+                                Monitor.Exit(_outputQueue);
+                                try
+                                {
+                                    var outputBytesPtr = (IntPtr)outputBytes;
+                                    length = NativeMethods.retry(() => NativeMethods.write
+                                                            (_handle, outputBytesPtr, (IntPtr)outputBytesRaw.Length));
+                                    if ((long)length == outputBytesRaw.Length) { outputReport.DoneOK = true; }
+                                }
+                                finally
+                                {
+                                    Monitor.Enter(_outputQueue);
+                                }
+							}
+						}
+						finally
+						{
+							_outputQueue.Dequeue();
+                            outputReport.Done = true;
+							Monitor.PulseAll(_outputQueue);
+						}	
+					}
+				}
+			}
+			finally
+			{
+				HandleRelease();
+			}
+		}
+		
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            CommonWrite(buffer, offset, count, _outputQueue, false, _device.MaxOutputReportLength);
+        }
+
+        public override void SetFeature(byte[] buffer, int offset, int count)
+        {
+            throw new NotSupportedException(); // TODO
+        }
+
+        public override HidDevice Device
+        {
+            get { return _device; }
+        }
+    }
+}

+ 254 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Linux/NativeMethods.cs

@@ -0,0 +1,254 @@
+#region License
+/* Copyright 2012-2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+namespace HidSharp.Platform.Linux
+{
+    static class NativeMethods
+    {
+		const string libc = "libc";
+		const string libudev = "libudev.so.0";
+
+		public enum error
+		{
+			OK = 0,
+			EPERM = 1,
+			EINTR = 4,
+			EIO = 5,
+			ENXIO = 6,
+			EBADF = 9,
+			EAGAIN = 11,
+			EACCES = 13,
+			EBUSY = 16,
+			ENODEV = 19,
+			EINVAL = 22
+		}
+			
+		[Flags]
+		public enum oflag
+		{
+			RDONLY = 0x000,
+			WRONLY = 0x001,
+			RDWR = 0x002,
+			CREAT = 0x040,
+			EXCL = 0x080,
+			TRUNC = 0x200,
+			APPEND = 0x400,
+			NONBLOCK = 0x800
+		}
+	
+		[Flags]
+		public enum pollev : short
+		{
+			IN = 0x01,
+			PRI = 0x02,
+			OUT = 0x04,
+			ERR = 0x08,
+			HUP = 0x10,
+			NVAL = 0x20
+		}
+
+		public struct pollfd
+		{
+			public int fd;
+			public pollev events;
+			public pollev revents;
+		}
+
+		public static int retry(Func<int> sysfunc)
+		{
+			while (true)
+			{
+                int ret = sysfunc(); var error = (error)Marshal.GetLastWin32Error();
+                if (ret >= 0 || error != error.EINTR) { return ret; }
+			}
+		}
+
+		public static IntPtr retry(Func<IntPtr> sysfunc)
+		{
+			while (true)
+			{
+                IntPtr ret = sysfunc(); var error = (error)Marshal.GetLastWin32Error();
+                if ((long)ret >= 0 || error != error.EINTR) { return ret; }
+			}
+		}
+
+		public static bool uname(out string sysname, out Version release, out string machine)
+		{
+			string releaseStr; release = null;
+			if (!uname(out sysname, out releaseStr, out machine)) { return false; }
+            releaseStr = new string(releaseStr.Trim().TakeWhile(ch => (ch >= '0' && ch <= '9') || ch == '.').ToArray());
+			release = new Version(releaseStr);
+			return true;
+		}
+		
+        public static bool uname(out string sysname, out string release, out string machine)
+        {
+            sysname = null; release = null; machine = null;
+
+            string syscallPath = "Mono.Unix.Native.Syscall, Mono.Posix, PublicKeyToken=0738eb9f132ed756";
+            var syscall = Type.GetType(syscallPath);
+            if (syscall == null) { return false; }
+
+            var unameArgs = new object[1];
+            int unameRet = (int)syscall.InvokeMember("uname",
+                                                     BindingFlags.InvokeMethod | BindingFlags.Static, null, null, unameArgs,
+                                                     CultureInfo.InvariantCulture);
+            if (unameRet < 0) { return false; }
+
+            var uname = unameArgs[0];
+			Func<string, string> getMember = s => (string)uname.GetType().InvokeMember(s,
+                                                                                       BindingFlags.GetField, null, uname, new object[0],
+                                                                                       CultureInfo.InvariantCulture);
+            sysname = getMember("sysname"); release = getMember("release"); machine = getMember("machine");
+            return true;
+        }
+		
+		[DllImport(libc, SetLastError = true)]
+		public static extern int open(
+			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string filename,
+			 oflag oflag);
+		
+		[DllImport(libc, SetLastError = true)]
+		public static extern int close(int filedes);
+
+		[DllImport(libc, SetLastError = true)]
+		public static extern IntPtr read(int filedes, IntPtr buffer, IntPtr size);
+		
+		[DllImport(libc, SetLastError = true)]
+		public static extern IntPtr write(int filedes, IntPtr buffer, IntPtr size);
+
+		[DllImport(libc, SetLastError = true)]
+		public static extern int poll(pollfd[] fds, IntPtr nfds, int timeout);
+		
+        [DllImport(libudev)]
+        public static extern IntPtr udev_new();
+
+        [DllImport(libudev)]
+        public static extern IntPtr udev_ref(IntPtr udev);
+
+        [DllImport(libudev)]
+        public static extern void udev_unref(IntPtr udev);
+
+        [DllImport(libudev)]
+        public static extern IntPtr udev_enumerate_new(IntPtr udev);
+
+        [DllImport(libudev)]
+        public static extern IntPtr udev_enumerate_ref(IntPtr enumerate);
+
+        [DllImport(libudev)]
+        public static extern void udev_enumerate_unref(IntPtr enumerate);
+
+        [DllImport(libudev)]
+        public static extern int udev_enumerate_add_match_subsystem(IntPtr enumerate,
+			[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string subsystem);
+
+        [DllImport(libudev)]
+        public static extern int udev_enumerate_scan_devices(IntPtr enumerate);
+
+        [DllImport(libudev)]
+        public static extern IntPtr udev_enumerate_get_list_entry(IntPtr enumerate);
+
+        [DllImport(libudev)]
+        public static extern IntPtr udev_list_entry_get_next(IntPtr entry);
+
+        [DllImport(libudev)]
+        [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
+        public static extern string udev_list_entry_get_name(IntPtr entry);
+
+        [DllImport(libudev)]
+        public static extern IntPtr udev_device_new_from_syspath(IntPtr udev,
+            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string syspath);
+
+        [DllImport(libudev)]
+        public static extern IntPtr udev_device_ref(IntPtr device);
+
+        [DllImport(libudev)]
+        public static extern void udev_device_unref(IntPtr device);
+
+        [DllImport(libudev)]
+        [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
+        public static extern string udev_device_get_devnode(IntPtr device);
+
+        [DllImport(libudev)]
+        public static extern IntPtr udev_device_get_parent_with_subsystem_devtype(IntPtr device,
+            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string subsystem,
+            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string devtype);
+
+        [DllImport(libudev)]
+        [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]
+        public static extern string udev_device_get_sysattr_value(IntPtr device,
+            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string sysattr);
+
+        public static bool TryParseHex(string hex, out int result)
+        {
+            return int.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out result);
+        }
+
+        public static bool TryParseVersion(string version, out int major, out int minor)
+        {
+            major = 0; minor = 0; if (version == null) { return false; }
+            string[] parts = version.Split(new[] { '.' }, 2); if (parts.Length != 2) { return false; }
+            return int.TryParse(parts[0], out major) && int.TryParse(parts[1], out minor);
+        }
+
+        #region ioctl
+        // TODO: Linux changes these up depending on platform. Eventually we'll handle it.
+        //       For now, x86 and ARM are safe with this definition.
+        public const int IOC_NONE = 0;
+        public const int IOC_WRITE = 1;
+        public const int IOC_READ = 2;
+        public const int IOC_NRBITS = 8;
+        public const int IOC_TYPEBITS = 8;
+        public const int IOC_SIZEBITS = 14;
+        public const int IOC_DIRBITS = 2;
+        public const int IOC_NRSHIFT = 0;
+        public const int IOC_TYPESHIFT = IOC_NRSHIFT + IOC_NRBITS;
+        public const int IOC_SIZESHIFT = IOC_TYPESHIFT + IOC_TYPEBITS;
+        public const int IOC_DIRSHIFT = IOC_SIZESHIFT + IOC_SIZEBITS;
+
+        public static int IOC(int dir, int type, int nr, int size)
+        {
+            return dir << IOC_DIRSHIFT | type << IOC_TYPESHIFT | nr << IOC_NRSHIFT | size << IOC_SIZESHIFT;
+        }
+
+        #region hidraw
+        public const int HID_MAX_DESCRIPTOR_SIZE = 4096;
+        public static readonly int HIDIOCGRDESCSIZE = IOC(IOC_READ, (byte)'H', 1, 4);
+        public static readonly int HIDIOCGRDESC = IOC(IOC_READ, (byte)'H', 2, Marshal.SizeOf(typeof(hidraw_report_descriptor)));
+
+        public struct hidraw_report_descriptor
+        {
+            public uint size;
+
+            [MarshalAs(UnmanagedType.ByValArray, SizeConst = HID_MAX_DESCRIPTOR_SIZE)]
+            public byte[] value;
+        }
+
+        [DllImport(libc, SetLastError = true)]
+        public static extern int ioctl(int filedes, int command, out uint value);
+
+        [DllImport(libc, SetLastError = true)]
+        public static extern int ioctl(int filedes, int command, ref hidraw_report_descriptor value);
+        #endregion
+        #endregion
+    }
+}

+ 109 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/MacOS/MacHidDevice.cs

@@ -0,0 +1,109 @@
+#region License
+/* Copyright 2012-2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.Platform.MacOS
+{
+    class MacHidDevice : HidDevice
+    {
+        string _manufacturer;
+        string _productName;
+        string _serialNumber;
+        int _vid, _pid, _version;
+        int _maxInput, _maxOutput, _maxFeature;
+        NativeMethods.io_string_t _path;
+
+        internal MacHidDevice(NativeMethods.io_string_t path)
+        {
+            _path = path;
+        }
+
+        public override HidStream Open()
+        {
+            var stream = new MacHidStream();
+            try { stream.Init(_path, this); return stream; }
+            catch { stream.Close(); throw; }
+        }
+
+        internal bool GetInfo(int handle)
+        {
+            int? vid = NativeMethods.IORegistryEntryGetCFProperty_Int(handle, NativeMethods.kIOHIDVendorIDKey);
+            int? pid = NativeMethods.IORegistryEntryGetCFProperty_Int(handle, NativeMethods.kIOHIDProductIDKey);
+            int? version = NativeMethods.IORegistryEntryGetCFProperty_Int(handle, NativeMethods.kIOHIDVersionNumberKey);
+            if (vid == null || pid == null || version == null) { return false; }
+
+            _vid = (int)vid;
+            _pid = (int)pid;
+            _version = (int)version;
+            _maxInput = NativeMethods.IORegistryEntryGetCFProperty_Int(handle, NativeMethods.kIOHIDMaxInputReportSizeKey) ?? 0;
+            _maxOutput = NativeMethods.IORegistryEntryGetCFProperty_Int(handle, NativeMethods.kIOHIDMaxOutputReportSizeKey) ?? 0;
+            _maxFeature = NativeMethods.IORegistryEntryGetCFProperty_Int(handle, NativeMethods.kIOHIDMaxFeatureReportSizeKey) ?? 0;
+            _manufacturer = NativeMethods.IORegistryEntryGetCFProperty_String(handle, NativeMethods.kIOHIDManufacturerKey) ?? "";
+            _productName = NativeMethods.IORegistryEntryGetCFProperty_String(handle, NativeMethods.kIOHIDProductKey) ?? "";
+            _serialNumber = NativeMethods.IORegistryEntryGetCFProperty_String(handle, NativeMethods.kIOHIDSerialNumberKey) ?? "";
+            return true;
+        }
+
+        public override string DevicePath
+        {
+            get { return _path.ToString(); }
+        }
+
+        public override int MaxInputReportLength
+        {
+            get { return _maxInput; }
+        }
+
+        public override int MaxOutputReportLength
+        {
+            get { return _maxOutput; }
+        }
+
+        public override int MaxFeatureReportLength
+        {
+            get { return _maxFeature; }
+        }
+
+        public override string Manufacturer
+        {
+            get { return _manufacturer; }
+        }
+
+        public override int ProductID
+        {
+            get { return _pid; }
+        }
+
+        public override string ProductName
+        {
+            get { return _productName; }
+        }
+
+        public override int ProductVersion
+        {
+            get { return _version; }
+        }
+
+        public override string SerialNumber
+        {
+            get { return _serialNumber; }
+        }
+
+        public override int VendorID
+        {
+            get { return _vid; }
+        }
+    }
+}

+ 95 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/MacOS/MacHidManager.cs

@@ -0,0 +1,95 @@
+#region License
+/* Copyright 2012 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HidSharp.Platform.MacOS
+{
+    class MacHidManager : HidManager
+    {
+        protected override object[] Refresh()
+        {
+            var paths = new List<NativeMethods.io_string_t>();
+
+            var matching = NativeMethods.IOServiceMatching("IOHIDDevice").ToCFType(); // Consumed by IOServiceGetMatchingServices, so DON'T Dispose().
+            if (matching.IsSet)
+            {
+                int iteratorObj;
+                if (NativeMethods.IOReturn.Success == NativeMethods.IOServiceGetMatchingServices(0, matching, out iteratorObj))
+                {
+                    using (var iterator = iteratorObj.ToIOObject())
+                    {
+                        while (true)
+                        {
+                            using (var handle = NativeMethods.IOIteratorNext(iterator).ToIOObject())
+                            {
+                                if (!handle.IsSet) { break; }
+
+                                NativeMethods.io_string_t path;
+                                if (NativeMethods.IOReturn.Success == NativeMethods.IORegistryEntryGetPath(handle, "IOService", out path))
+                                {
+                                    paths.Add(path);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            return paths.Cast<object>().ToArray();
+        }
+
+        protected override bool TryCreateDevice(object key, out HidDevice device, out object creationState)
+        {
+            creationState = null;
+            var path = (NativeMethods.io_string_t)key; var hidDevice = new MacHidDevice(path);
+            using (var handle = NativeMethods.IORegistryEntryFromPath(0, ref path).ToIOObject())
+            {
+                if (!handle.IsSet || !hidDevice.GetInfo(handle)) { device = null; return false; }
+                device = hidDevice; return true;
+            }
+        }
+
+        protected override void CompleteDevice(object key, HidDevice device, object creationState)
+        {
+            
+        }
+
+        public override bool IsSupported
+        {
+            get
+            {
+                try
+                {
+                    IntPtr major; NativeMethods.OSErr majorErr = NativeMethods.Gestalt(NativeMethods.OSType.gestaltSystemVersionMajor, out major);
+                    IntPtr minor; NativeMethods.OSErr minorErr = NativeMethods.Gestalt(NativeMethods.OSType.gestaltSystemVersionMinor, out minor);
+                    if (majorErr == NativeMethods.OSErr.noErr && minorErr == NativeMethods.OSErr.noErr)
+                    {
+                        return (long)major >= 10 || ((long)major == 10 && (long)minor >= 5);
+                    }
+                }
+                catch
+                {
+
+                }
+
+                return false;
+            }
+        }
+    }
+}

+ 235 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/MacOS/MacHidStream.cs

@@ -0,0 +1,235 @@
+#region License
+/* Copyright 2012 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace HidSharp.Platform.MacOS
+{
+    class MacHidStream : HidStream
+    {
+        Queue<byte[]> _inputQueue;
+        Queue<CommonOutputReport> _outputQueue;
+
+        MacHidDevice _device;
+        IntPtr _handle;
+        IntPtr _readRunLoop;
+        Thread _readThread, _writeThread;
+        volatile bool _shutdown;
+
+        internal MacHidStream()
+        {
+            _inputQueue = new Queue<byte[]>();
+            _outputQueue = new Queue<CommonOutputReport>();
+            _readThread = new Thread(ReadThread);
+			_readThread.IsBackground = true;
+            _writeThread = new Thread(WriteThread);
+			_writeThread.IsBackground = true;
+        }
+		
+		internal void Init(NativeMethods.io_string_t path, MacHidDevice device)
+		{
+            IntPtr handle;
+            using (var service = NativeMethods.IORegistryEntryFromPath(0, ref path).ToIOObject())
+            {
+                handle = NativeMethods.IOHIDDeviceCreate(IntPtr.Zero, service);
+                if (handle == IntPtr.Zero) { throw new IOException("HID class device not found."); }
+
+                if (NativeMethods.IOReturn.Success != NativeMethods.IOHIDDeviceOpen(handle)) { NativeMethods.CFRelease(handle); throw new IOException("Unable to open HID class device."); }
+            }
+            _device = device;
+            _handle = handle;
+			HandleInitAndOpen();
+
+            _readThread.Start();
+            _writeThread.Start();
+		}
+		
+        protected override void Dispose(bool disposing)
+        {
+            base.Dispose(disposing);
+			if (!HandleClose()) { return; }
+			
+            _shutdown = true;
+            try { lock (_outputQueue) { Monitor.PulseAll(_outputQueue); } } catch { }
+
+            NativeMethods.CFRunLoopStop(_readRunLoop);
+            try { _readThread.Join(); } catch { }
+            try { _writeThread.Join(); } catch { }
+			
+			HandleRelease();
+        }
+
+		internal override void HandleFree()
+		{
+			NativeMethods.CFRelease(_handle); _handle = IntPtr.Zero;
+		}
+		
+        static void ReadThreadEnqueue(Queue<byte[]> queue, byte[] report)
+        {
+            lock (queue)
+            {
+                if (queue.Count < 100) { queue.Enqueue(report); Monitor.PulseAll(queue); }
+            }
+        }
+
+        void ReadThreadCallback(IntPtr context, NativeMethods.IOReturn result, IntPtr sender,
+                                	   NativeMethods.IOHIDReportType type,
+		                               uint reportID, IntPtr report, IntPtr reportLength)
+        {
+            byte[] reportBytes = new byte[(int)reportLength];
+            Marshal.Copy(report, reportBytes, 0, reportBytes.Length);
+
+            if (result == NativeMethods.IOReturn.Success && reportLength != IntPtr.Zero)
+            {
+                if (type == NativeMethods.IOHIDReportType.Input)
+                {
+                    ReadThreadEnqueue(_inputQueue, reportBytes);
+                }
+            }
+        }
+
+        unsafe void ReadThread()
+        {			
+			if (!HandleAcquire()) { return; }
+			_readRunLoop = NativeMethods.CFRunLoopGetCurrent();
+			
+            try
+            {
+				var callback = new NativeMethods.IOHIDReportCallback(ReadThreadCallback);
+
+                byte[] inputReport = new byte[_device.MaxInputReportLength];
+                fixed (byte* inputReportBytes = inputReport)
+                {
+                    NativeMethods.IOHIDDeviceRegisterInputReportCallback(_handle,
+                                                                  (IntPtr)inputReportBytes, (IntPtr)inputReport.Length,
+                                                                  callback, IntPtr.Zero);
+                    NativeMethods.IOHIDDeviceScheduleWithRunLoop(_handle, _readRunLoop, NativeMethods.kCFRunLoopDefaultMode);
+                    NativeMethods.CFRunLoopRun();
+                    NativeMethods.IOHIDDeviceUnscheduleFromRunLoop(_handle, _readRunLoop, NativeMethods.kCFRunLoopDefaultMode);
+                }
+				
+				GC.KeepAlive(this);
+				GC.KeepAlive(callback);
+                GC.KeepAlive(_inputQueue);
+            }
+            finally
+            {
+                HandleRelease();
+            }
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            return CommonRead(buffer, offset, count, _inputQueue);
+        }
+
+        public unsafe override void GetFeature(byte[] buffer, int offset, int count)
+        {
+            Throw.If.OutOfRange(buffer, offset, count);
+			
+			HandleAcquireIfOpenOrFail();
+			try
+			{
+	            fixed (byte* bufferBytes = buffer)
+	            {
+	                IntPtr reportLength = (IntPtr)count;
+	                if (NativeMethods.IOReturn.Success != NativeMethods.IOHIDDeviceGetReport(_handle, NativeMethods.IOHIDReportType.Feature,
+	                                                                           (IntPtr)buffer[offset],
+	                                                                           (IntPtr)(bufferBytes + offset),
+	                                                                           ref reportLength))
+	
+	                {
+	                    throw new IOException("GetFeature failed.");
+	                }
+	            }
+			}
+			finally
+			{
+				HandleRelease();
+			}
+        }
+
+        unsafe void WriteThread()
+        {
+			if (!HandleAcquire()) { return; }
+			
+			try
+	        {	
+				lock (_outputQueue)
+				{								
+	                while (true)
+	                {
+	                    while (!_shutdown && _outputQueue.Count == 0) { Monitor.Wait(_outputQueue); }
+						if (_shutdown) { break; }
+	
+						NativeMethods.IOReturn ret;
+	                    CommonOutputReport outputReport = _outputQueue.Peek();
+	                    try
+	                    {
+	                        fixed (byte* outputReportBytes = outputReport.Bytes)
+	                        {
+	                            Monitor.Exit(_outputQueue);
+	
+	                            try
+	                            {
+	                                ret = NativeMethods.IOHIDDeviceSetReport(_handle,
+									                                  outputReport.Feature ? NativeMethods.IOHIDReportType.Feature : NativeMethods.IOHIDReportType.Output,
+	                                                                  (IntPtr)outputReport.Bytes[0],
+	                                                                  (IntPtr)outputReportBytes,
+	                                                                  (IntPtr)outputReport.Bytes.Length);
+	                                if (ret == NativeMethods.IOReturn.Success) { outputReport.DoneOK = true; }
+	                            }
+	                            finally
+	                            {
+	                                Monitor.Enter(_outputQueue);
+	                            }
+	                        }
+	                    }
+	                    finally
+	                    {
+							_outputQueue.Dequeue();
+	                        outputReport.Done = true;
+	                        Monitor.PulseAll(_outputQueue);
+	                    }
+	                }
+	            }
+			}
+            finally
+            {
+                HandleRelease();
+            }
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            CommonWrite(buffer, offset, count, _outputQueue, false, _device.MaxOutputReportLength);
+        }
+
+        public override void SetFeature(byte[] buffer, int offset, int count)
+        {
+            CommonWrite(buffer, offset, count, _outputQueue, true, _device.MaxFeatureReportLength);
+        }
+
+        public override HidDevice Device
+        {
+            get { return _device; }
+        }
+    }
+}

+ 318 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/MacOS/NativeMethods.cs

@@ -0,0 +1,318 @@
+#region License
+/* Copyright 2012-2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace HidSharp.Platform.MacOS
+{
+    static class NativeMethods
+    {
+        const string CoreFoundation = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
+        const string CoreServices = "/System/Library/Frameworks/CoreServices.framework/CoreServices";
+        const string IOKit = "/System/Library/Frameworks/IOKit.framework/IOKit";
+
+        public static readonly IntPtr kCFRunLoopDefaultMode = CFStringCreateWithCharacters("kCFRunLoopDefaultMode");
+        public static readonly IntPtr kIOHIDVendorIDKey = CFStringCreateWithCharacters("VendorID");
+        public static readonly IntPtr kIOHIDProductIDKey = CFStringCreateWithCharacters("ProductID");
+        public static readonly IntPtr kIOHIDVersionNumberKey = CFStringCreateWithCharacters("VersionNumber");
+        public static readonly IntPtr kIOHIDManufacturerKey = CFStringCreateWithCharacters("Manufacturer");
+        public static readonly IntPtr kIOHIDProductKey = CFStringCreateWithCharacters("Product");
+        public static readonly IntPtr kIOHIDSerialNumberKey = CFStringCreateWithCharacters("SerialNumber");
+        public static readonly IntPtr kIOHIDLocationIDKey = CFStringCreateWithCharacters("LocationID");
+        public static readonly IntPtr kIOHIDMaxInputReportSizeKey = CFStringCreateWithCharacters("MaxInputReportSize");
+        public static readonly IntPtr kIOHIDMaxOutputReportSizeKey = CFStringCreateWithCharacters("MaxOutputReportSize");
+        public static readonly IntPtr kIOHIDMaxFeatureReportSizeKey = CFStringCreateWithCharacters("MaxFeatureReportSize");
+
+        public delegate void IOHIDCallback(IntPtr context, IOReturn result, IntPtr sender);
+        public delegate void IOHIDDeviceCallback(IntPtr context, IOReturn result, IntPtr sender, IntPtr device);
+        public delegate void IOHIDReportCallback(IntPtr context, IOReturn result, IntPtr sender,
+                                                 IOHIDReportType type, uint reportID, IntPtr report, IntPtr reportLength);
+
+        public enum OSErr : short
+        {
+            noErr = 0,
+            gestaltUnknownErr = -5550,
+            gestaltUndefSelectorErr = -5551,
+            gestaltDupSelectorErr = -5552,
+            gestaltLocationErr = -5553
+        }
+
+        public enum OSType : uint
+        {
+            gestaltSystemVersion = (byte)'s' << 24 | (byte)'y' << 16 | (byte)'s' << 8 | (byte)'v' << 0,
+            gestaltSystemVersionMajor = (byte)'s' << 24 | (byte)'y' << 16 | (byte)'s' << 8 | (byte)'1' << 0,
+            gestaltSystemVersionMinor = (byte)'s' << 24 | (byte)'y' << 16 | (byte)'s' << 8 | (byte)'2' << 0,
+            gestaltSystemVersionBugFix = (byte)'s' << 24 | (byte)'y' << 16 | (byte)'s' << 8 | (byte)'3' << 0
+        }
+
+        public enum IOOptionBits
+        {
+            None = 0
+        }
+
+        public enum IOHIDReportType
+        {
+            Input = 0,
+            Output,
+            Feature
+        }
+
+        public enum IOReturn
+        {
+            Success = 0
+        }
+
+        public struct io_string_t
+        {
+            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
+            public byte[] Value;
+
+            public override bool Equals(object obj)
+            {
+                return obj is io_string_t && this == (io_string_t)obj;
+            }
+
+            public override int GetHashCode()
+            {
+                return Value.Length >= 1 ? Value[0] : -1;
+            }
+
+            public override string ToString()
+            {
+                return Encoding.UTF8.GetString(Value.TakeWhile(ch => ch != 0).ToArray());
+            }
+
+            public static bool operator ==(io_string_t io1, io_string_t io2)
+            {
+                return io1.Value.SequenceEqual(io2.Value);
+            }
+
+            public static bool operator !=(io_string_t io1, io_string_t io2)
+            {
+                return !(io1 == io2);
+            }
+        }
+
+        public enum CFNumberType
+        {
+            Int = 9
+        }
+
+        public struct CFRange
+        {
+            public IntPtr Start, Length;
+        }
+
+        public struct IOObject : IDisposable
+        {
+            public int Handle { get; set; }
+            public bool IsSet { get { return Handle != 0; } }
+
+            void IDisposable.Dispose()
+            {
+                if (IsSet) { IOObjectRelease(Handle); Handle = 0; }
+            }
+
+            public static implicit operator int(IOObject self)
+            {
+                return self.Handle;
+            }
+        }
+
+        public struct CFType : IDisposable
+        {
+            public IntPtr Handle { get; set; }
+            public bool IsSet { get { return Handle != IntPtr.Zero; } }
+
+            void IDisposable.Dispose()
+            {
+                if (IsSet) { CFRelease(Handle); Handle = IntPtr.Zero; }
+            }
+
+            public static implicit operator IntPtr(CFType self)
+            {
+                return self.Handle;
+            }
+        }
+
+        public static CFType ToCFType(this IntPtr handle)
+        {
+            return new CFType() { Handle = handle };
+        }
+
+        public static IOObject ToIOObject(this int handle)
+        {
+            return new IOObject() { Handle = handle };
+        }
+
+        [DllImport(CoreServices)]
+        public static extern OSErr Gestalt(OSType selector, out IntPtr response);
+		
+		[DllImport(CoreFoundation)]
+		public static extern uint CFGetTypeID(IntPtr type);
+		
+		[DllImport(CoreFoundation)]
+		public static extern uint CFNumberGetTypeID();
+		
+		[DllImport(CoreFoundation)]
+		public static extern uint CFStringGetTypeID();
+		
+        [DllImport(CoreFoundation)]
+        public static extern IntPtr CFDictionaryCreateMutable(IntPtr allocator, IntPtr capacity,
+                                                       		  IntPtr keyCallbacks, IntPtr valueCallbacks);
+
+        public static IntPtr CFDictionaryCreateMutable()
+        {
+            return CFDictionaryCreateMutable(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+        }
+		
+        [DllImport(CoreFoundation)]
+        public static extern void CFDictionarySetValue(IntPtr dict, IntPtr key, IntPtr value);
+		
+        [DllImport(CoreFoundation)]
+        public static extern IntPtr CFNumberCreate(IntPtr allocator, CFNumberType type, ref int value);
+
+        public static IntPtr CFNumberCreate(int value)
+        {
+            return CFNumberCreate(IntPtr.Zero, CFNumberType.Int, ref value);
+        }
+
+        [DllImport(CoreFoundation)]
+        [return: MarshalAs(UnmanagedType.I1)]
+        public static extern bool CFNumberGetValue(IntPtr number, CFNumberType type, out int value);
+
+        public static int? CFNumberGetValue(IntPtr number)
+        {
+            int value;
+            return number != IntPtr.Zero && CFGetTypeID(number) == CFNumberGetTypeID() &&
+				CFNumberGetValue(number, CFNumberType.Int, out value) ? (int?)value : null;
+        }
+
+        [DllImport(CoreFoundation, CharSet=CharSet.Unicode)]
+        public static extern IntPtr CFStringCreateWithCharacters(IntPtr allocator, char[] buffer, IntPtr length);
+
+        public static IntPtr CFStringCreateWithCharacters(string str)
+        {
+            return CFStringCreateWithCharacters(IntPtr.Zero, str.ToCharArray(), (IntPtr)str.Length);
+        }
+
+        [DllImport(CoreFoundation, CharSet=CharSet.Unicode)]
+        public static extern void CFStringGetCharacters(IntPtr str, CFRange range, char[] buffer);
+
+        public static string CFStringGetCharacters(IntPtr str)
+        {
+            if (str == IntPtr.Zero || CFGetTypeID(str) != CFStringGetTypeID()) { return null; }
+            char[] buffer = new char[(int)CFStringGetLength(str)];
+            CFStringGetCharacters(str, new CFRange() { Start = (IntPtr)0, Length = (IntPtr)buffer.Length }, buffer);
+            return new string(buffer);
+        }
+
+        [DllImport(CoreFoundation)]
+        public static extern IntPtr CFStringGetLength(IntPtr str);
+
+        [DllImport(CoreFoundation)]
+        public static extern void CFRunLoopRun();
+
+        [DllImport(CoreFoundation)]
+        public static extern IntPtr CFRunLoopGetCurrent();
+
+        [DllImport(CoreFoundation)]
+        public static extern void CFRunLoopStop(IntPtr runLoop);
+
+        [DllImport(CoreFoundation)]
+        public static extern void CFRelease(IntPtr obj);
+
+        [DllImport(CoreFoundation)]
+        public static extern void CFRetain(IntPtr obj);
+
+        [DllImport(CoreFoundation)]
+        public static extern IntPtr CFSetGetCount(IntPtr set);
+
+        [DllImport(CoreFoundation)]
+        public static extern void CFSetGetValues(IntPtr set, IntPtr[] values);
+
+        [DllImport(IOKit)]
+        public static extern IntPtr IOHIDDeviceCreate(IntPtr allocator, int service);
+
+        [DllImport(IOKit)]
+        public static extern IOReturn IOHIDDeviceOpen(IntPtr device, IOOptionBits options = IOOptionBits.None);
+
+        [DllImport(IOKit)]
+        public static extern void IOHIDDeviceRegisterInputReportCallback(IntPtr device, IntPtr report, IntPtr reportLength,
+                                                                         IOHIDReportCallback callback, IntPtr context);
+
+        [DllImport(IOKit)]
+        public static extern void IOHIDDeviceRegisterRemovalCallback(IntPtr device, IOHIDCallback callback, IntPtr context);
+
+        [DllImport(IOKit)]
+        public static extern IOReturn IOHIDDeviceGetReport(IntPtr device, IOHIDReportType type, IntPtr reportID, IntPtr report, ref IntPtr reportLength);
+
+        [DllImport(IOKit)]
+        public static extern IOReturn IOHIDDeviceSetReport(IntPtr device, IOHIDReportType type, IntPtr reportID, IntPtr report, IntPtr reportLength);
+
+        [DllImport(IOKit)]
+        public static extern void IOHIDDeviceScheduleWithRunLoop(IntPtr device, IntPtr runLoop, IntPtr runLoopMode);
+
+        [DllImport(IOKit)]
+        public static extern void IOHIDDeviceUnscheduleFromRunLoop(IntPtr device, IntPtr runLoop, IntPtr runLoopMode);
+
+        [DllImport(IOKit)]
+        public static extern IOReturn IOHIDDeviceClose(IntPtr device, IOOptionBits options = IOOptionBits.None);
+
+        [DllImport(IOKit)]
+        public static extern int IOIteratorNext(int iterator);
+
+        [DllImport(IOKit)]
+        public static extern IOReturn IOObjectRetain(int @object);
+
+        [DllImport(IOKit)]
+        public static extern IOReturn IOObjectRelease(int @object);
+
+        [DllImport(IOKit)]
+        public static extern IntPtr IORegistryEntryCreateCFProperty(int entry, IntPtr strKey, IntPtr allocator, IOOptionBits options = IOOptionBits.None);
+
+        public static int? IORegistryEntryGetCFProperty_Int(int entry, IntPtr strKey)
+        {
+            using (var property = IORegistryEntryCreateCFProperty(entry, strKey, IntPtr.Zero).ToCFType())
+            {
+                return CFNumberGetValue(property);
+            }
+        }
+
+        public static string IORegistryEntryGetCFProperty_String(int entry, IntPtr strKey)
+        {
+            using (var property = IORegistryEntryCreateCFProperty(entry, strKey, IntPtr.Zero).ToCFType())
+            {
+                return CFStringGetCharacters(property);
+            }
+        }
+
+        [DllImport(IOKit)]
+        public static extern int IORegistryEntryFromPath(int masterPort, ref io_string_t path);
+
+        [DllImport(IOKit)] // plane = IOService
+        public static extern IOReturn IORegistryEntryGetPath(int entry, [MarshalAs(UnmanagedType.LPStr)] string plane, out io_string_t path);
+
+        [DllImport(IOKit)]
+        public static extern IOReturn IOServiceGetMatchingServices(int masterPort, IntPtr matching, out int iterator);
+
+        [DllImport(IOKit)] // name = IOHIDDevice
+        public static extern IntPtr IOServiceMatching([MarshalAs(UnmanagedType.LPStr)] string name);
+    }
+}

+ 43 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Unsupported/UnsupportedHidManager.cs

@@ -0,0 +1,43 @@
+#region License
+/* Copyright 2012 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+
+namespace HidSharp.Platform.Unsupported
+{
+    class UnsupportedHidManager : HidManager
+    {
+        protected override object[] Refresh()
+        {
+            return new object[0];
+        }
+
+        protected override bool TryCreateDevice(object key, out HidDevice device, out object creationState)
+        {
+            throw new NotImplementedException();
+        }
+
+        protected override void CompleteDevice(object key, HidDevice device, object creationState)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override bool IsSupported
+        {
+            get { return true; }
+        }
+    }
+}

+ 73 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Utf8Marshaler.cs

@@ -0,0 +1,73 @@
+#region License
+/* Copyright 2012 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace HidSharp.Platform
+{
+    sealed class Utf8Marshaler : ICustomMarshaler
+    {
+        bool _allocated; // workaround for Mono bug 4722
+
+        public void CleanUpManagedData(object obj)
+        {
+
+        }
+
+        public void CleanUpNativeData(IntPtr ptr)
+        {
+			if (IntPtr.Zero == ptr || !_allocated) { return; }
+            Marshal.FreeHGlobal(ptr); _allocated = false;
+        }
+
+        public int GetNativeDataSize()
+        {
+            return -1;
+        }
+
+        public IntPtr MarshalManagedToNative(object obj)
+        {
+            string str = obj as string;
+            if (str == null) { return IntPtr.Zero; }
+
+            byte[] bytes = Encoding.UTF8.GetBytes(str);
+            IntPtr ptr = Marshal.AllocHGlobal(bytes.Length + 1);
+            Marshal.Copy(bytes, 0, ptr, bytes.Length);
+            Marshal.WriteByte(ptr, bytes.Length, 0);
+            _allocated = true; return ptr;
+        }
+
+        public object MarshalNativeToManaged(IntPtr ptr)
+        {
+            if (ptr == IntPtr.Zero) { return null; }
+
+            int length;
+            for (length = 0; Marshal.ReadByte(ptr, length) != 0; length++) ;
+
+            byte[] bytes = new byte[length];
+            Marshal.Copy(ptr, bytes, 0, bytes.Length);
+            string str = Encoding.UTF8.GetString(bytes);
+            return str;
+        }
+		
+		public static ICustomMarshaler GetInstance(string cookie)
+		{
+			return new Utf8Marshaler();
+		}
+    }
+}

+ 401 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Windows/NativeMethods.cs

@@ -0,0 +1,401 @@
+#region License
+/* Copyright 2010-2012 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+#pragma warning disable 169, 649
+
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace HidSharp.Platform.Windows
+{
+    unsafe static class NativeMethods
+    {
+        // For constants, see PInvoke.Net,
+        //  http://doxygen.reactos.org/de/d2a/hidclass_8h_source.html
+        //  http://www.rpi.edu/dept/cis/software/g77-mingw32/include/winioctl.h
+        // and Google.
+        public const int ERROR_HANDLE_EOF = 38;
+        public const int ERROR_INSUFFICIENT_BUFFER = 122;
+        public const int ERROR_OPERATION_ABORTED = 995;
+        public const int ERROR_IO_PENDING = 997;
+        public const uint FILE_ANY_ACCESS = 0;
+        public const uint FILE_DEVICE_KEYBOARD = 11;
+        public const uint METHOD_NEITHER = 3;
+        public const uint WAIT_OBJECT_0 = 0;
+        public const uint WAIT_OBJECT_1 = 1;
+        public const uint WAIT_TIMEOUT = 258;
+
+        public static uint CTL_CODE(uint devType, uint func, uint method, uint access)
+        {
+            return devType << 16 | access << 14 | func << 2 | method;
+        }
+
+        public static uint HID_CTL_CODE(uint id)
+        {
+            return CTL_CODE(FILE_DEVICE_KEYBOARD, id, METHOD_NEITHER, FILE_ANY_ACCESS);
+        }
+
+        public static readonly uint IOCTL_HID_GET_REPORT_DESCRIPTOR = HID_CTL_CODE(1);
+
+        public static int HIDP_ERROR_CODES(int sev, ushort code)
+        {
+            return sev << 28 | 0x11 << 16 | code;
+        }
+
+        public static readonly int HIDP_STATUS_SUCCESS = HIDP_ERROR_CODES(0, 0);
+        public static readonly int HIDP_STATUS_INVALID_PREPARSED_DATA = HIDP_ERROR_CODES(12, 1);
+
+        [Flags]
+        public enum EFileAccess : uint
+        {
+            None = 0,
+            Read = 0x80000000,
+            Write = 0x40000000,
+            Execute = 0x20000000,
+            All = 0x10000000
+        }
+
+        [Flags]
+        public enum EFileShare : uint
+        {
+            None = 0x00000000,
+            Read = 0x00000001,
+            Write = 0x00000002,
+            Delete = 0x00000004,
+            All = Read | Write | Delete
+        }
+
+        public enum ECreationDisposition : uint
+        {
+            New = 1,
+            CreateAlways = 2,
+            OpenExisting = 3,
+            OpenAlways = 4,
+            TruncateExisting = 5
+        }
+
+        [Flags]
+        public enum EFileAttributes : uint
+        {
+            Readonly = 0x00000001,
+            Hidden = 0x00000002,
+            System = 0x00000004,
+            Directory = 0x00000010,
+            Archive = 0x00000020,
+            Device = 0x00000040,
+            Normal = 0x00000080,
+            Temporary = 0x00000100,
+            SparseFile = 0x00000200,
+            ReparsePoint = 0x00000400,
+            Compressed = 0x00000800,
+            Offline = 0x00001000,
+            NotContentIndexed = 0x00002000,
+            Encrypted = 0x00004000,
+            Writethrough = 0x80000000,
+            Overlapped = 0x40000000,
+            NoBuffering = 0x20000000,
+            RandomAccess = 0x10000000,
+            SequentialScan = 0x08000000,
+            DeleteOnClose = 0x04000000,
+            BackupSemantics = 0x02000000,
+            PosixSemantics = 0x01000000,
+            OpenReparsePoint = 0x00200000,
+            OpenNoRecall = 0x00100000,
+            FirstPipeInstance = 0x00080000
+        }
+
+        [Flags]
+        public enum DIGCF
+        {
+            None = 0,
+            Default = 1,
+            Present = 2,
+            AllClasses = 4,
+            Profile = 8,
+            DeviceInterface = 16
+        }
+
+        [Flags]
+        public enum SPINT
+        {
+            None = 0,
+            Active = 1,
+            Default = 2,
+            Removed = 4
+        }
+
+        public struct HDEVINFO
+        {
+            IntPtr Value;
+
+            public void Invalidate()
+            {
+                Value = (IntPtr)(-1);
+            }
+
+            public bool IsValid
+            {
+                get { return Value != (IntPtr)(-1); }
+            }
+        }
+
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+        public struct OSVERSIONINFO
+        {
+            public int OSVersionInfoSize;
+            public uint MajorVersion, MinorVersion, BuildNumber, PlatformID;
+
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
+            public string CSDVersion;
+        }
+
+        public struct SP_DEVINFO_DATA
+        {
+            public int Size;
+            public Guid ClassGuid;
+            public uint DevInst;
+            IntPtr Reserved;
+        }
+
+        public struct SP_DEVICE_INTERFACE_DATA
+        {
+            public int Size;
+            public Guid InterfaceClassGuid;
+            public SPINT Flags;
+            IntPtr Reserved;
+        }
+
+        [Obfuscation(Feature = "preserve-name-binding")]
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+        public struct SP_DEVICE_INTERFACE_DETAIL_DATA
+        {
+            public int Size;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst=1024)] public string DevicePath;
+        }
+
+        public struct HIDD_ATTRIBUTES
+        {
+            public int Size;
+            public ushort VendorID, ProductID, VersionNumber;
+        }
+
+        public unsafe struct HIDP_CAPS
+        {
+            public ushort Usage, UsagePage;
+            public ushort InputReportByteLength, OutputReportByteLength, FeatureReportByteLength;
+            fixed ushort Reserved[17];
+            public ushort NumberLinkCollectionNodes,
+                NumberInputButtonCaps, NumberInputValueCaps, NumberInputDataIndices,
+                NumberOutputButtonCaps, NumberOutputValueCaps, NumberOutputDataIndices,
+                NumberFeatureButtonCaps, NumberFeatureValueCaps, NumberFeatureDataIndices;
+        }
+
+        public static IntPtr CreateManualResetEventOrThrow()
+        {
+            IntPtr @event = NativeMethods.CreateEvent(IntPtr.Zero, true, false, IntPtr.Zero);
+            if (@event == IntPtr.Zero) { throw new IOException("Event creation failed."); }
+            return @event;
+        }
+
+        public unsafe static void OverlappedOperation(IntPtr ioHandle,
+            IntPtr eventHandle, int eventTimeout, IntPtr closeEventHandle,
+            bool overlapResult,
+            NativeOverlapped* overlapped, out uint bytesTransferred)
+        {
+            bool closed = false;
+
+            if (!overlapResult)
+            {
+                int win32Error = Marshal.GetLastWin32Error();
+                if (win32Error != NativeMethods.ERROR_IO_PENDING)
+                {
+                    throw new IOException("Operation failed early.", new Win32Exception());
+                }
+
+                IntPtr* handles = stackalloc IntPtr[2];
+                handles[0] = eventHandle; handles[1] = closeEventHandle;
+                uint timeout = eventTimeout < 0 ? ~(uint)0 : (uint)eventTimeout;
+                uint waitResult = NativeMethods.WaitForMultipleObjects(2, handles, false, timeout);
+                switch (waitResult)
+                {
+                    case NativeMethods.WAIT_OBJECT_0: break;
+                    case NativeMethods.WAIT_OBJECT_1: closed = true; goto default;
+                    default: CancelIo(ioHandle); break;
+                }
+            }
+
+            if (!NativeMethods.GetOverlappedResult(ioHandle, overlapped, out bytesTransferred, true))
+            {
+                int win32Error = Marshal.GetLastWin32Error();
+                if (win32Error != NativeMethods.ERROR_HANDLE_EOF)
+                {
+                    if (closed)
+                    {
+                        throw new IOException("Connection closed.");
+                    }
+
+                    if (win32Error == NativeMethods.ERROR_OPERATION_ABORTED)
+                    {
+                        throw new TimeoutException("Operation timed out.");
+                    }
+
+                    throw new IOException("Operation failed after some time.", new Win32Exception());
+                }
+
+                bytesTransferred = 0;
+            }
+        }
+        
+        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool GetVersionEx(ref OSVERSIONINFO version);
+         
+        [DllImport("hid.dll")]
+        public static extern void HidD_GetHidGuid(out Guid hidGuid);
+
+        [DllImport("hid.dll")]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public static extern bool HidD_GetAttributes(IntPtr handle, ref HIDD_ATTRIBUTES attributes);
+
+        [DllImport("hid.dll", CharSet = CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public static extern bool HidD_GetManufacturerString(IntPtr handle, char[] buffer, int bufferLengthInBytes);
+
+        [DllImport("hid.dll", CharSet = CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public static extern bool HidD_GetProductString(IntPtr handle, char[] buffer, int bufferLengthInBytes);
+
+        [DllImport("hid.dll", CharSet = CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public static extern bool HidD_GetSerialNumberString(IntPtr handle, char[] buffer, int bufferLengthInBytes);
+
+        [DllImport("hid.dll", CharSet = CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public unsafe static extern bool HidD_GetFeature(IntPtr handle, byte* buffer, int bufferLength);
+
+        [DllImport("hid.dll", CharSet = CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public unsafe static extern bool HidD_SetFeature(IntPtr handle, byte* buffer, int bufferLength);
+
+        [DllImport("hid.dll", CharSet = CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public unsafe static extern bool HidD_GetPreparsedData(IntPtr handle, out IntPtr preparsed);
+
+        [DllImport("hid.dll", CharSet = CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.U1)]
+        public unsafe static extern bool HidD_FreePreparsedData(IntPtr preparsed);
+
+        [DllImport("hid.dll", CharSet = CharSet.Auto)]
+        public unsafe static extern int HidP_GetCaps(IntPtr preparsed, out HIDP_CAPS caps);
+
+        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+        public static extern HDEVINFO SetupDiGetClassDevs
+            ([MarshalAs(UnmanagedType.LPStruct)] Guid classGuid, string enumerator, IntPtr hwndParent, DIGCF flags);
+
+        [DllImport("setupapi.dll", SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool SetupDiDestroyDeviceInfoList(HDEVINFO deviceInfoSet);
+
+        [DllImport("setupapi.dll", SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool SetupDiEnumDeviceInterfaces(HDEVINFO deviceInfoSet, IntPtr deviceInfoData,
+            [MarshalAs(UnmanagedType.LPStruct)] Guid interfaceClassGuid, int memberIndex,
+            ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData);
+
+        [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool SetupDiGetDeviceInterfaceDetail(HDEVINFO deviceInfoSet,
+            ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
+            ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData,
+            int deviceInterfaceDetailDataSize, IntPtr requiredSize, IntPtr deviceInfoData);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern IntPtr CreateEvent(IntPtr eventAttributes,
+            [MarshalAs(UnmanagedType.Bool)] bool manualReset,
+            [MarshalAs(UnmanagedType.Bool)] bool initialState,
+            IntPtr name);
+
+        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+        public static extern IntPtr CreateFile(string filename, EFileAccess desiredAccess, EFileShare shareMode, IntPtr securityAttributes,
+            ECreationDisposition creationDisposition, EFileAttributes attributes, IntPtr template);
+
+        public static IntPtr CreateFileFromDevice(string filename, EFileAccess desiredAccess, EFileShare shareMode)
+        {
+            return CreateFile(filename, desiredAccess, shareMode, IntPtr.Zero,
+                ECreationDisposition.OpenExisting,
+                EFileAttributes.Device | EFileAttributes.Overlapped,
+                IntPtr.Zero);
+        }
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool CloseHandle(IntPtr handle);
+
+		public static bool CloseHandle(ref IntPtr handle)
+		{
+			if (!CloseHandle(handle)) { return false; }
+			handle = IntPtr.Zero; return true;
+		}
+		
+        [DllImport("kernel32.dll", SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public unsafe static extern bool ReadFile(IntPtr handle, byte* buffer, int bytesToRead,
+            IntPtr bytesRead, NativeOverlapped* overlapped);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public unsafe static extern bool WriteFile(IntPtr handle, byte* buffer, int bytesToWrite,
+            IntPtr bytesWritten, NativeOverlapped* overlapped);
+
+        public static string NTString(char[] buffer)
+        {
+            int index = Array.IndexOf(buffer, '\0');
+            return new string(buffer, 0, index >= 0 ? index : buffer.Length);
+        }
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool CancelIo(IntPtr handle);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public unsafe static extern bool DeviceIoControl(IntPtr handle,
+            uint ioControlCode, byte* inBuffer, uint inBufferSize, byte* outBuffer, uint outBufferSize,
+            IntPtr bytesReturned, NativeOverlapped* overlapped);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool GetOverlappedResult(IntPtr handle,
+            NativeOverlapped* overlapped, out uint bytesTransferred,
+            [MarshalAs(UnmanagedType.Bool)] bool wait);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool ResetEvent(IntPtr handle);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool SetEvent(IntPtr handle);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public unsafe static extern uint WaitForMultipleObjects(uint count, IntPtr* handles,
+            [MarshalAs(UnmanagedType.Bool)] bool waitAll, uint milliseconds);
+    }
+}

+ 153 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Windows/WinHidDevice.cs

@@ -0,0 +1,153 @@
+#region License
+/* Copyright 2010, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+#pragma warning disable 618
+
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace HidSharp.Platform.Windows
+{
+    sealed class WinHidDevice : HidDevice
+    {
+        string _path;
+        string _manufacturer;
+        string _productName;
+        string _serialNumber;
+        int _vid, _pid, _version;
+        int _maxInput, _maxOutput, _maxFeature;
+
+        object _completeSync = new object();
+        volatile bool _complete;
+
+        internal WinHidDevice(string path)
+        {
+            _path = path;
+        }
+
+        void WaitForCompletion()
+        {
+            lock (_completeSync)
+            {
+                while (!_complete) { Monitor.Wait(_completeSync); }
+            }
+        }
+
+        public override HidStream Open()
+        {
+            WaitForCompletion();
+            var stream = new WinHidStream();
+            try { stream.Init(_path, this); return stream; }
+            catch { stream.Close(); throw; }
+        }
+
+        internal bool GetInfo(IntPtr handle)
+        {
+            NativeMethods.HIDD_ATTRIBUTES attributes = new NativeMethods.HIDD_ATTRIBUTES();
+            attributes.Size = Marshal.SizeOf(attributes);
+            if (!NativeMethods.HidD_GetAttributes(handle, ref attributes)) { return false; }
+            
+            _pid = attributes.ProductID;
+            _vid = attributes.VendorID;
+            _version = attributes.VersionNumber;
+            return true;
+        }
+
+        internal void GetInfoComplete(IntPtr handle)
+        {
+            try
+            {
+                char[] buffer = new char[128];
+
+                _manufacturer = NativeMethods.HidD_GetManufacturerString(handle, buffer, 256) ? NativeMethods.NTString(buffer) : "";
+                _productName = NativeMethods.HidD_GetProductString(handle, buffer, 256) ? NativeMethods.NTString(buffer) : "";
+                _serialNumber = NativeMethods.HidD_GetSerialNumberString(handle, buffer, 256) ? NativeMethods.NTString(buffer) : "";
+
+                IntPtr preparsed;
+                if (NativeMethods.HidD_GetPreparsedData(handle, out preparsed))
+                {
+                    NativeMethods.HIDP_CAPS caps;
+                    int statusCaps = NativeMethods.HidP_GetCaps(preparsed, out caps);
+                    if (statusCaps == NativeMethods.HIDP_STATUS_SUCCESS)
+                    {
+                        _maxInput = caps.InputReportByteLength;
+                        _maxOutput = caps.OutputReportByteLength;
+                        _maxFeature = caps.FeatureReportByteLength;
+                    }
+                    NativeMethods.HidD_FreePreparsedData(preparsed);
+                }
+            }
+            finally
+            {
+                NativeMethods.CloseHandle(handle);
+            }
+
+            lock (_completeSync) { _complete = true; Monitor.PulseAll(_completeSync); }
+        }
+
+        public override string DevicePath
+        {
+            get { return _path; }
+        }
+
+        public override int MaxInputReportLength
+        {
+            get { WaitForCompletion(); return _maxInput; }
+        }
+
+        public override int MaxOutputReportLength
+        {
+            get { WaitForCompletion(); return _maxOutput; }
+        }
+
+        public override int MaxFeatureReportLength
+        {
+            get { WaitForCompletion(); return _maxFeature; }
+        }
+
+        public override string Manufacturer
+        {
+            get { WaitForCompletion(); return _manufacturer; }
+        }
+
+        public override int ProductID
+        {
+            get { return _pid; }
+        }
+
+        public override string ProductName
+        {
+            get { WaitForCompletion(); return _productName; }
+        }
+
+        public override int ProductVersion
+        {
+            get { return _version; }
+        }
+
+        public override string SerialNumber
+        {
+            get { WaitForCompletion(); return _serialNumber; }
+        }
+
+        public override int VendorID
+        {
+            get { return _vid; }
+        }
+    }
+}

+ 108 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Windows/WinHidManager.cs

@@ -0,0 +1,108 @@
+#region License
+/* Copyright 2012-2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+namespace HidSharp.Platform.Windows
+{
+    class WinHidManager : HidManager
+    {
+        protected override object[] Refresh()
+        {
+            var paths = new List<string>();
+
+            Guid hidGuid; NativeMethods.HidD_GetHidGuid(out hidGuid);
+            NativeMethods.HDEVINFO devInfo = NativeMethods.SetupDiGetClassDevs(hidGuid, null, IntPtr.Zero, 
+                /*NativeMethods.DIGCF.AllClasses |*/ NativeMethods.DIGCF.DeviceInterface | NativeMethods.DIGCF.Present);
+
+            if (devInfo.IsValid)
+            {
+                try   
+                {
+                    NativeMethods.SP_DEVICE_INTERFACE_DATA did = new NativeMethods.SP_DEVICE_INTERFACE_DATA();
+                    did.Size = Marshal.SizeOf(did);
+
+                    for (int i = 0; NativeMethods.SetupDiEnumDeviceInterfaces(devInfo, IntPtr.Zero, hidGuid, i, ref did); i ++)
+                    {
+                        NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA didetail = new NativeMethods.SP_DEVICE_INTERFACE_DETAIL_DATA();
+                        didetail.Size = IntPtr.Size == 8 ? 8 : (4 + Marshal.SystemDefaultCharSize);
+                        if (NativeMethods.SetupDiGetDeviceInterfaceDetail(devInfo, ref did, ref didetail,
+                            Marshal.SizeOf(didetail) - (int)Marshal.OffsetOf(didetail.GetType(), "DevicePath"),
+                            IntPtr.Zero, IntPtr.Zero))
+                        {
+                            paths.Add(didetail.DevicePath);
+                        }
+                    }
+                }
+                finally
+                {
+                    NativeMethods.SetupDiDestroyDeviceInfoList(devInfo);
+                }
+            }
+
+            return paths.Cast<object>().ToArray();
+        }
+
+        protected override bool TryCreateDevice(object key, out HidDevice device, out object completionState)
+        {
+            string path = (string)key; var hidDevice = new WinHidDevice(path);
+            IntPtr handle = NativeMethods.CreateFileFromDevice(path, NativeMethods.EFileAccess.None, NativeMethods.EFileShare.All);
+            device = null; completionState = null; if (handle == (IntPtr)(-1)) { return false; }
+
+            bool ok = false;
+            try { ok = hidDevice.GetInfo(handle); } catch { }
+            if (!ok) { NativeMethods.CloseHandle(handle); return false; }
+
+            device = hidDevice; completionState = handle;
+            return true;
+        }
+
+        protected override void CompleteDevice(object key, HidDevice device, object creationState)
+        {
+            var hidDevice = (WinHidDevice)device; var handle = (IntPtr)creationState;
+            hidDevice.GetInfoComplete(handle);
+        }
+
+        public override bool IsSupported
+        {
+            get
+            {
+                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
+                {
+                    var version = new NativeMethods.OSVERSIONINFO();
+                    version.OSVersionInfoSize = Marshal.SizeOf(typeof(NativeMethods.OSVERSIONINFO));
+
+                    try
+                    {
+                        if (NativeMethods.GetVersionEx(ref version) && version.PlatformID == 2)
+                        {
+                            return true;
+                        }
+                    }
+                    catch
+                    {
+                        // Apparently we have no P/Invoke access.
+                    }
+                }
+
+                return false;
+            }
+        }
+    }
+}

+ 185 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Platform/Windows/WinHidStream.cs

@@ -0,0 +1,185 @@
+#region License
+/* Copyright 2012-2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace HidSharp.Platform.Windows
+{
+    class WinHidStream : HidStream
+    {
+        object _readSync = new object(), _writeSync = new object();
+        byte[] _readBuffer, _writeBuffer;
+        IntPtr _handle, _closeEventHandle;
+        WinHidDevice _device;
+
+        internal WinHidStream()
+        {
+            _closeEventHandle = NativeMethods.CreateManualResetEventOrThrow();
+        }
+
+        ~WinHidStream()
+        {
+			Close();
+            NativeMethods.CloseHandle(_closeEventHandle);
+        }
+
+        internal void Init(string path, WinHidDevice device)
+        {
+            IntPtr handle = NativeMethods.CreateFileFromDevice(path, NativeMethods.EFileAccess.Read | NativeMethods.EFileAccess.Write, NativeMethods.EFileShare.All);
+            if (handle == (IntPtr)(-1)) { throw new IOException("Unable to open HID class device."); }
+
+            _device = device;
+			_handle = handle;
+			HandleInitAndOpen();
+        }
+		
+        protected override void Dispose(bool disposing)
+        {
+            base.Dispose(disposing);
+			if (!HandleClose()) { return; }
+			
+			NativeMethods.SetEvent(_closeEventHandle);
+			HandleRelease();
+		}
+		
+		internal override void HandleFree()
+		{
+			NativeMethods.CloseHandle(ref _handle);
+			NativeMethods.CloseHandle(ref _closeEventHandle);
+		}
+
+        public unsafe override void GetFeature(byte[] buffer, int offset, int count)
+        {
+            Throw.If.OutOfRange(buffer, offset, count);
+			
+			HandleAcquireIfOpenOrFail();
+			try
+			{
+	            fixed (byte* ptr = buffer)
+	            {
+	                if (!NativeMethods.HidD_GetFeature(_handle, ptr + offset, count))
+	                    { throw new IOException("GetFeature failed.", new Win32Exception()); }
+	            }
+			}
+			finally
+			{
+				HandleRelease();
+			}
+        }
+
+        // Buffer needs to be big enough for the largest report, plus a byte
+        // for the Report ID.
+        public unsafe override int Read(byte[] buffer, int offset, int count)
+        {
+            Throw.If.OutOfRange(buffer, offset, count); uint bytesTransferred;
+            IntPtr @event = NativeMethods.CreateManualResetEventOrThrow();
+			
+			HandleAcquireIfOpenOrFail();
+            try
+            {
+				lock (_readSync)
+				{
+	                int maxIn = _device.MaxInputReportLength;
+	                Array.Resize(ref _readBuffer, maxIn); if (count > maxIn) { count = maxIn; }
+	
+	                fixed (byte* ptr = _readBuffer)
+	                {
+                        var overlapped = stackalloc NativeOverlapped[1];
+                        overlapped[0].EventHandle = @event;
+
+                        NativeMethods.OverlappedOperation(_handle, @event, ReadTimeout, _closeEventHandle,
+                            NativeMethods.ReadFile(_handle, ptr, maxIn, IntPtr.Zero, overlapped),
+                            overlapped, out bytesTransferred);
+
+	                    if (count > (int)bytesTransferred) { count = (int)bytesTransferred; }
+	                    Array.Copy(_readBuffer, 0, buffer, offset, count);
+	                    return count;
+	                }
+				}
+            }
+            finally
+            {
+				HandleRelease();
+                NativeMethods.CloseHandle(@event);
+            }
+        }
+
+        public unsafe override void SetFeature(byte[] buffer, int offset, int count)
+        {
+            Throw.If.OutOfRange(buffer, offset, count);
+			
+			HandleAcquireIfOpenOrFail();
+			try
+			{
+	            fixed (byte* ptr = buffer)
+	            {
+	                if (!NativeMethods.HidD_SetFeature(_handle, ptr + offset, count))
+	                    { throw new IOException("SetFeature failed.", new Win32Exception()); }
+	            }
+			}
+			finally
+			{
+				HandleRelease();
+			}
+        }
+
+        public unsafe override void Write(byte[] buffer, int offset, int count)
+        {
+            Throw.If.OutOfRange(buffer, offset, count); uint bytesTransferred;
+            IntPtr @event = NativeMethods.CreateManualResetEventOrThrow();
+
+			HandleAcquireIfOpenOrFail();
+            try
+            {
+				lock (_writeSync)
+				{
+	                int maxOut = _device.MaxOutputReportLength;
+	                Array.Resize(ref _writeBuffer, maxOut); if (count > maxOut) { count = maxOut; }
+	                Array.Copy(buffer, offset, _writeBuffer, 0, count); count = maxOut;
+	
+	                fixed (byte* ptr = _writeBuffer)
+	                {
+	                    int offset0 = 0;
+	                    while (count > 0)
+	                    {
+                            var overlapped = stackalloc NativeOverlapped[1];
+                            overlapped[0].EventHandle = @event;
+
+                            NativeMethods.OverlappedOperation(_handle, @event, WriteTimeout, _closeEventHandle,
+	                            NativeMethods.WriteFile(_handle, ptr + offset0, count, IntPtr.Zero, overlapped),
+	                            overlapped, out bytesTransferred);
+	                        count -= (int)bytesTransferred; offset0 += (int)bytesTransferred;
+	                    }
+	                }
+				}
+            }
+            finally
+            {
+				HandleRelease();
+                NativeMethods.CloseHandle(@event);
+            }
+        }
+
+        public override HidDevice Device
+        {
+            get { return _device; }
+        }
+    }
+}

+ 29 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/CollectionType.cs

@@ -0,0 +1,29 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors
+{
+    public enum CollectionType : byte
+    {
+        Physical = 0,
+        Application,
+        Logical,
+        Report,
+        NamedArray,
+        UsageSwitch,
+        UsageModifier
+    }
+}

+ 63 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/DataMainItemFlags.cs

@@ -0,0 +1,63 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+
+namespace HidSharp.ReportDescriptors
+{
+    [Flags]
+    public enum DataMainItemFlags : uint
+    {
+        /// <summary>
+        /// No flags are set.
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// Constant values cannot be changed.
+        /// </summary>
+        Constant = 1 << 0,
+
+        /// <summary>
+        /// Each variable field corresponds to a particular value.
+        /// The alternative is an array, where each field specifies an index.
+        /// For example, with eight buttons, a variable field would have eight bits.
+        /// An array would have an index of which button is pressed.
+        /// </summary>
+        Variable = 1 << 1,
+
+        /// <summary>
+        /// Mouse motion is in relative coordinates.
+        /// Most sensors -- joysticks, accelerometers, etc. -- output absolute coordinates.
+        /// </summary>
+        Relative = 1 << 2,
+
+        /// <summary>
+        /// The value wraps around in a continuous manner.
+        /// </summary>
+        Wrap = 1 << 3,
+
+        Nonlinear = 1 << 4,
+
+        NoPreferred = 1 << 5,
+
+        NullState = 1 << 6,
+
+        Volatile = 1 << 7,
+
+        BufferedBytes = 1 << 8
+    }
+}

+ 207 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/EncodedItem.cs

@@ -0,0 +1,207 @@
+#region License
+/* Copyright 2011, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HidSharp.ReportDescriptors
+{
+    public class EncodedItem
+    {
+        public EncodedItem()
+        {
+            Data = new List<byte>();
+        }
+
+        public void Clear()
+        {
+            Data.Clear(); Tag = 0; Type = ItemType.Main;
+        }
+
+        public byte DataAt(int index)
+        {
+            return index >= 0 && index < Data.Count ? Data[index] : (byte)0;
+        }
+
+        static byte GetByte(IList<byte> buffer, ref int offset, ref int count)
+        {
+            if (count <= 0) { return 0; } else { count--; }
+            return offset >= 0 && offset < buffer.Count ? buffer[offset++] : (byte)0;
+        }
+
+        public int Decode(IList<byte> buffer, int offset, int count)
+        {
+            Throw.If.OutOfRange(buffer, offset, count);
+
+            Clear(); int startCount = count;
+            byte header = GetByte(buffer, ref offset, ref count);
+
+            int size = header & 0x3; if (size == 3) { size = 4; }
+            Type = (ItemType)((header >> 2) & 0x3); Tag = (byte)(header >> 4);
+            for (int i = 0; i < size; i++) { Data.Add(GetByte(buffer, ref offset, ref count)); }
+            return startCount - count;
+        }
+
+        public static IEnumerable<EncodedItem> DecodeRaw(IList<byte> buffer, int offset, int count)
+        {
+            Throw.If.OutOfRange(buffer, offset, count);
+
+            while (count > 0)
+            {
+                EncodedItem item = new EncodedItem();
+                int bytes = item.Decode(buffer, offset, count);
+                offset += bytes; count -= bytes;
+                yield return item;
+            }
+        }
+
+        public static IEnumerable<EncodedItem> DecodeHIDDT(IList<byte> buffer, int offset, int count)
+        {
+            Throw.If.OutOfRange(buffer, offset, count);
+
+            while (count > 34)
+            {
+                EncodedItem item = new EncodedItem();
+                int bytes = item.Decode(buffer, offset + 34, count - 34);
+                offset += 10; count -= 10;
+                yield return item;
+            }
+        }
+
+        public void Encode(IList<byte> buffer)
+        {
+            Throw.If.Null(buffer, "buffer");
+
+            if (buffer == null) { throw new ArgumentNullException("buffer"); }
+            if (!IsShortTag) { return; }
+
+            byte size = DataSize;
+            buffer.Add((byte)((size == 4 ? (byte)3 : size) | (byte)Type << 2 | Tag << 4));
+            foreach (byte @byte in Data) { buffer.Add(@byte); }
+        }
+
+        public static void EncodeRaw(IList<byte> buffer, IEnumerable<EncodedItem> items)
+        {
+            Throw.If.Null(buffer, "buffer").Null(items, "items");
+            foreach (EncodedItem item in items) { item.Encode(buffer); }
+        }
+
+        public IList<byte> Data
+        {
+            get;
+            private set;
+        }
+
+        public byte DataSize
+        {
+            get { return (byte)(IsShortTag ? Data.Count : 0); }
+        }
+
+        public uint DataValue
+        {
+            get
+            {
+                if (!IsShortTag) { return 0; }
+                return (uint)(DataAt(0) | DataAt(1) << 8 | DataAt(2) << 16 | DataAt(3) << 24);
+            }
+
+            set
+            {
+                Data.Clear();
+                Data.Add((byte)value);
+                if (value > 0xff) { Data.Add((byte)(value >> 8)); }
+                if (value > 0xffff) { Data.Add((byte)(value >> 16)); Data.Add((byte)(value >> 24)); }
+            }
+        }
+
+        public bool DataValueMayBeNegative
+        {
+            get { return IsShortTag && Data.Count > 0 && (Data[Data.Count - 1] & 0x80) != 0; }
+        }
+
+        public int DataValueSigned
+        {
+            get
+            {
+                if (!IsShortTag) { return 0; }
+                return Data.Count == 4 ? (int)DataValue :
+                    Data.Count == 2 ? (short)DataValue :
+                    Data.Count == 1 ? (sbyte)DataValue : (sbyte)0;
+            }
+
+            set
+            {
+                if (value == 0)
+                    { DataValue = (uint)value; }
+                else if (value >= sbyte.MinValue && value <= sbyte.MaxValue)
+                    { DataValue = (uint)(sbyte)value; if (value < 0) { Data.Add(0); } }
+                else if (value >= short.MinValue && value <= short.MaxValue)
+                    { DataValue = (uint)(short)value; if (value < 0) { Data.Add(0); Data.Add(0); } }
+                else
+                    { DataValue = (uint)value; }
+            }
+        }
+
+        public int EncodedSize
+        {
+            get { return IsShortTag ? (DataSize + 1) : 0; }
+        }
+
+        public byte Tag
+        {
+            get;
+            set;
+        }
+
+        public GlobalItemTag TagForGlobal
+        {
+            get { return (GlobalItemTag)Tag; }
+        }
+
+        public LocalItemTag TagForLocal
+        {
+            get { return (LocalItemTag)Tag; }
+        }
+
+        public MainItemTag TagForMain
+        {
+            get { return (MainItemTag)Tag; }
+        }
+
+        public ItemType Type
+        {
+            get;
+            set;
+        }
+
+        public bool IsShortTag
+        {
+            get
+            {
+                return !IsLongTag &&
+                    (Data.Count == 0 || Data.Count == 1 || Data.Count == 2 || Data.Count == 4);
+            }
+        }
+
+        public bool IsLongTag
+        {
+            get
+            {
+                return Tag == 15 && Type == ItemType.Reserved && Data.Count >= 2;
+            }
+        }
+    }
+}

+ 34 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/GlobalItemTag.cs

@@ -0,0 +1,34 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors
+{
+    public enum GlobalItemTag : byte
+    {
+        UsagePage = 0,
+        LogicalMinimum,
+        LogicalMaximum,
+        PhysicalMinimum,
+        PhysicalMaximum,
+        UnitExponent,
+        Unit,
+        ReportSize,
+        ReportID,
+        ReportCount,
+        Push,
+        Pop
+    }
+}

+ 45 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/ItemType.cs

@@ -0,0 +1,45 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors
+{
+    /// <summary>
+    /// Describes the manner in which an item affects the descriptor.
+    /// </summary>
+    public enum ItemType : byte
+    {
+        /// <summary>
+        /// Main items determine the report being described.
+        /// For example, a main item switches between Input and Output reports.
+        /// </summary>
+        Main = 0,
+
+        /// <summary>
+        /// Global items affect all reports later in the descriptor.
+        /// </summary>
+        Global,
+
+        /// <summary>
+        /// Local items only affect the current report.
+        /// </summary>
+        Local,
+
+        /// <summary>
+        /// Long items use this type.
+        /// </summary>
+        Reserved
+    }
+}

+ 32 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/LocalItemTag.cs

@@ -0,0 +1,32 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors
+{
+    public enum LocalItemTag : byte
+    {
+        Usage = 0,
+        UsageMinimum,
+        UsageMaximum,
+        DesignatorIndex,
+        DesignatorMinimum,
+        DesignatorMaximum,
+        StringIndex = 7,
+        StringMinimum,
+        StringMaximum,
+        Delimiter
+    }
+}

+ 27 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/MainItemTag.cs

@@ -0,0 +1,27 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors
+{
+    public enum MainItemTag : byte
+    {
+        Input = 8,
+        Output,
+        Collection,
+        Feature,
+        EndCollection
+    }
+}

+ 45 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/IndexBase.cs

@@ -0,0 +1,45 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HidSharp.ReportDescriptors.Parser
+{
+    public class IndexBase
+    {
+        public static readonly IndexBase Unset = new IndexBase();
+
+        public bool ContainsValue(uint value)
+        {
+            int index; return IndexFromValue(value, out index);
+        }
+
+        public virtual bool IndexFromValue(uint value, out int index)
+        {
+            index = -1; return false;
+        }
+
+        public virtual IEnumerable<uint> ValuesFromIndex(int index)
+        {
+            yield break;
+        }
+
+        public virtual int Count
+        {
+            get { return 0; }
+        }
+    }
+}

+ 60 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/IndexList.cs

@@ -0,0 +1,60 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HidSharp.ReportDescriptors.Parser
+{
+    public class IndexList : IndexBase
+    {
+        public IndexList()
+        {
+            Indices = new List<IList<uint>>();
+        }
+
+        public override bool IndexFromValue(uint value, out int index)
+        {
+            for (int i = 0; i < Indices.Count; i ++)
+            {
+                foreach (uint thisValue in Indices[i])
+                {
+                    if (thisValue == value) { index = i; return true; }
+                }
+            }
+
+            return base.IndexFromValue(value, out index);
+        }
+
+        public override IEnumerable<uint> ValuesFromIndex(int index)
+        {
+            if (index < 0 || Indices.Count == 0) { yield break; }
+            foreach (uint value in Indices[Math.Min(Count - 1, index)])
+                { yield return value; }
+        }
+
+        public override int Count
+        {
+            get { return Indices.Count; }
+        }
+
+        public IList<IList<uint>> Indices
+        {
+            get;
+            private set;
+        }
+    }
+}

+ 67 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/IndexRange.cs

@@ -0,0 +1,67 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HidSharp.ReportDescriptors.Parser
+{
+    public class IndexRange : IndexBase
+    {
+        public IndexRange()
+        {
+            
+        }
+
+        public IndexRange(uint minimum, uint maximum)
+        {
+            Minimum = minimum; Maximum = maximum;
+        }
+
+        public override bool IndexFromValue(uint value, out int index)
+        {
+            if (value >= Minimum && value <= Maximum)
+            {
+                index = (int)(value - Minimum); return true;
+            }
+
+            return base.IndexFromValue(value, out index);
+        }
+
+        public override IEnumerable<uint> ValuesFromIndex(int index)
+        {
+            if (index < 0) { yield break; }
+            yield return index >= Count ? Maximum : (uint)(Minimum + index);
+        }
+
+        public override int Count
+        {
+            get { return (int)(Maximum - Minimum + 1); }
+        }
+
+        public uint Minimum
+        {
+            get;
+            set;
+        }
+
+        public uint Maximum
+        {
+            get;
+            set;
+        }
+    }
+}

+ 48 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/LocalIndexes.cs

@@ -0,0 +1,48 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HidSharp.ReportDescriptors.Parser
+{
+    public class LocalIndexes
+    {
+        IndexBase _designator, _string, _usage;
+
+        public void Clear()
+        {
+            Designator = null; String = null; Usage = null;
+        }
+
+        public IndexBase Designator
+        {
+            get { return _designator ?? IndexBase.Unset; }
+            set { _designator = value; }
+        }
+
+        public IndexBase String
+        {
+            get { return _string ?? IndexBase.Unset; }
+            set { _string = value; }
+        }
+
+        public IndexBase Usage
+        {
+            get { return _usage ?? IndexBase.Unset; }
+            set { _usage = value; }
+        }
+    }
+}

+ 117 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/Report.cs

@@ -0,0 +1,117 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HidSharp.ReportDescriptors.Parser
+{
+    public delegate void ReportScanCallback
+        (byte[] buffer, int bitOffset, ReportSegment segment);
+
+    /// <summary>
+    /// Reads and writes HID reports.
+    /// </summary>
+    public class Report
+    {
+        internal List<ReportSegment> _segments;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Report"/> class.
+        /// </summary>
+        public Report()
+        {
+            _segments = new List<ReportSegment>();
+        }
+
+        /// <summary>
+        /// Resets the instance to its initial state.
+        /// </summary>
+        public void Clear()
+        {
+            List<ReportSegment> segments = new List<ReportSegment>(_segments);
+            foreach (ReportSegment segment in segments) { segment.Report = null; }
+            ID = 0; Type = 0;
+        }
+
+        /// <summary>
+        /// Reads a HID report, calling back a provided function for each segment.
+        /// </summary>
+        /// <param name="buffer">The buffer containing the report.</param>
+        /// <param name="offset">The offset to begin reading the report at.</param>
+        /// <param name="callback">
+        ///     This callback will be called for each report segment.
+        ///     Use this to read every value you need.
+        /// </param>
+        public void Scan(byte[] buffer, int offset, ReportScanCallback callback)
+        {
+            int bitOffset = offset * 8;
+
+            foreach (ReportSegment segment in Segments)
+            {
+                callback(buffer, bitOffset, segment);
+                bitOffset += segment.BitCount;
+            }
+        }
+
+        /// <summary>
+        /// Writes a HID report, calling back a provided function for each segment.
+        /// </summary>
+        /// <param name="callback">
+        ///     This callback will be called for each report segment.
+        ///     Write to each segment to write a complete HID report.
+        /// </param>
+        public byte[] Write(ReportScanCallback callback)
+        {
+            byte[] buffer = new byte[1 + Length];
+            buffer[0] = ID; Scan(buffer, 1, callback);
+            return buffer;
+        }
+
+        /// <summary>
+        /// The Report ID.
+        /// </summary>
+        public byte ID
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// The length of this particular report.
+        /// The Report ID is not included in this length.
+        /// </summary>
+        public int Length
+        {
+            get
+            {
+                int bits = 0;
+                foreach (ReportSegment segment in _segments) { bits += segment.BitCount; }
+                return (bits + 7) / 8;
+            }
+        }
+
+        public IEnumerable<ReportSegment> Segments
+        {
+            get { foreach (ReportSegment segment in _segments) { yield return segment; } }
+        }
+
+        public ReportType Type
+        {
+            get;
+            set;
+        }
+    }
+}

+ 66 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/ReportCollection.cs

@@ -0,0 +1,66 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HidSharp.ReportDescriptors.Parser
+{
+    public class ReportCollection : ReportMainItem
+    {
+        internal List<ReportMainItem> _children;
+
+        public ReportCollection()
+        {
+            _children = new List<ReportMainItem>();
+        }
+
+        public void Clear()
+        {
+            List<ReportMainItem> children = new List<ReportMainItem>(_children);
+            foreach (ReportMainItem child in children) { child.Parent = null; }
+            Type = 0;
+        }
+
+        public IEnumerable<ReportMainItem> Children
+        {
+            get { foreach (ReportMainItem item in _children) { yield return item; } }
+        }
+
+        public IEnumerable<ReportCollection> Collections
+        {
+            get
+            {
+                foreach (ReportMainItem item in _children)
+                    { if (item is ReportCollection) { yield return (ReportCollection)item; } }
+            }
+        }
+
+        public IEnumerable<ReportSegment> Segments
+        {
+            get
+            {
+                foreach (ReportMainItem item in _children)
+                    { if (item is ReportSegment) { yield return (ReportSegment)item; } }
+            }
+        }
+
+        public CollectionType Type
+        {
+            get;
+            set;
+        }
+    }
+}

+ 446 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/ReportDescriptorParser.cs

@@ -0,0 +1,446 @@
+#region License
+/* Copyright 2011, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HidSharp.ReportDescriptors.Parser
+{
+    /// <summary>
+    /// Parses HID report descriptors.
+    /// </summary>
+    public class ReportDescriptorParser
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ReportDescriptorParser"/> class.
+        /// </summary>
+        public ReportDescriptorParser()
+        {
+            RootCollection = new ReportCollection();
+            GlobalItemStateStack = new List<IDictionary<GlobalItemTag, EncodedItem>>();
+            LocalItemState = new List<KeyValuePair<LocalItemTag, uint>>();
+            Reports = new List<Report>();
+            Clear();
+        }
+
+        /// <summary>
+        /// Resets the parser to its initial state.
+        /// </summary>
+        public void Clear()
+        {
+            CurrentCollection = RootCollection;
+            RootCollection.Clear();
+
+            GlobalItemStateStack.Clear();
+            GlobalItemStateStack.Add(new Dictionary<GlobalItemTag, EncodedItem>());
+            LocalItemState.Clear();
+            Reports.Clear();
+            ReportsUseID = false;
+        }
+
+        public EncodedItem GetGlobalItem(GlobalItemTag tag)
+        {
+            EncodedItem value;
+            GlobalItemState.TryGetValue(tag, out value);
+            return value;
+        }
+
+        public uint GetGlobalItemValue(GlobalItemTag tag)
+        {
+            EncodedItem item = GetGlobalItem(tag);
+            return item != null ? item.DataValue : 0;
+        }
+
+        public Report GetReport(ReportType type, byte id)
+        {
+            Report report;
+            if (!TryGetReport(type, id, out report)) { throw new ArgumentException("Report not found."); }
+            return report;
+        }
+
+        public bool TryGetReport(ReportType type, byte id, out Report report)
+        {
+            for (int i = 0; i < Reports.Count; i++)
+            {
+                report = Reports[i];
+                if (report.Type == type && report.ID == id) { return true; }
+            }
+
+            report = null; return false;
+        }
+
+        static int GetMaxLengthOfReports(IEnumerable<Report> reports)
+        {
+            int length = 0;
+            foreach (Report report in reports) { length = Math.Max(length, report.Length); }
+            return length;
+        }
+
+        public bool IsGlobalItemSet(GlobalItemTag tag)
+        {
+            return GlobalItemState.ContainsKey(tag);
+        }
+
+        /// <summary>
+        /// Parses a raw HID report descriptor.
+        /// </summary>
+        /// <param name="buffer">The buffer containing the report descriptor.</param>
+        public void Parse(byte[] buffer)
+        {
+            if (buffer == null) { throw new ArgumentNullException("buffer"); }
+            Parse(buffer, 0, buffer.Length);
+        }
+
+        /// <summary>
+        /// Parses a raw HID report descriptor.
+        /// </summary>
+        /// <param name="buffer">The buffer containing the report descriptor.</param>
+        /// <param name="offset">The offset into the buffer to begin parsing from.</param>
+        /// <param name="count">The number of bytes to parse.</param>
+        public void Parse(byte[] buffer, int offset, int count)
+        {
+            var items = ReportDescriptors.EncodedItem.DecodeRaw(buffer, offset, count);
+            Parse(items);
+        }
+
+        /// <summary>
+        /// Parses all of the <see cref="EncodedItem"/> elements in a report descriptor.
+        /// </summary>
+        /// <param name="items">The items to parse.</param>
+        public void Parse(IEnumerable<EncodedItem> items)
+        {
+            if (items == null) { throw new ArgumentNullException("items"); }
+            foreach (EncodedItem item in items) { Parse(item); }
+        }
+
+        /// <summary>
+        /// Parses a single <see cref="EncodedItem"/>.
+        /// Call this repeatedly for every item to completely decode a report descriptor.
+        /// </summary>
+        /// <param name="item">The item to parse.</param>
+        public void Parse(EncodedItem item)
+        {
+            if (item == null) { throw new ArgumentNullException("item"); }
+            uint value = item.DataValue;
+
+            switch (item.Type)
+            {
+                case ItemType.Main:
+                    ParseMain(item.TagForMain, value);
+                    LocalItemState.Clear();
+                    break;
+
+                case ItemType.Local:
+                    switch (item.TagForLocal)
+                    {
+                        case LocalItemTag.Usage:
+                        case LocalItemTag.UsageMinimum:
+                        case LocalItemTag.UsageMaximum:
+                            if (value <= 0xffff) { value |= GetGlobalItemValue(GlobalItemTag.UsagePage) << 16; }
+                            break;
+                    }
+                    LocalItemState.Add(new KeyValuePair<LocalItemTag, uint>(item.TagForLocal, value));
+                    break;
+
+                case ItemType.Global:
+                    switch (item.TagForGlobal)
+                    {
+                        case GlobalItemTag.Push:
+                            GlobalItemStateStack.Add(new Dictionary<GlobalItemTag, EncodedItem>(GlobalItemState));
+                            break;
+
+                        case GlobalItemTag.Pop:
+                            GlobalItemStateStack.RemoveAt(GlobalItemState.Count - 1);
+                            break;
+
+                        default:
+                            switch (item.TagForGlobal)
+                            {
+                                case GlobalItemTag.ReportID:
+                                    ReportsUseID = true; break;
+                            }
+
+                            GlobalItemState[item.TagForGlobal] = item;
+                            break;
+                    }
+                    break;
+            }
+        }
+
+        void ParseMain(MainItemTag tag, uint value)
+        {
+            LocalIndexes indexes = null;
+
+            switch (tag)
+            {
+                case MainItemTag.Collection:
+                    ReportCollection collection = new ReportCollection();
+                    collection.Parent = CurrentCollection;
+                    collection.Type = (CollectionType)value;
+                    CurrentCollection = collection;
+                    indexes = collection.Indexes; break;
+
+                case MainItemTag.EndCollection:
+                    CurrentCollection = CurrentCollection.Parent; break;
+
+                case MainItemTag.Input:
+                case MainItemTag.Output:
+                case MainItemTag.Feature:
+                    ParseDataMain(tag, value, out indexes); break;
+            }
+
+            if (indexes != null) { ParseMainIndexes(indexes); }
+        }
+
+        static void AddIndex(List<KeyValuePair<int, uint>> list, int action, uint value)
+        {
+            list.Add(new KeyValuePair<int, uint>(action, value));
+        }
+
+        static void UpdateIndexMinimum(ref IndexBase index, uint value)
+        {
+            if (!(index is IndexRange)) { index = new IndexRange(); }
+            ((IndexRange)index).Minimum = value;
+        }
+
+        static void UpdateIndexMaximum(ref IndexBase index, uint value)
+        {
+            if (!(index is IndexRange)) { index = new IndexRange(); }
+            ((IndexRange)index).Maximum = value;
+        }
+
+        static void UpdateIndexList(List<uint> values, int delimiter,
+                                    ref IndexBase index, uint value)
+        {
+            values.Add(value);
+            UpdateIndexListCommit(values, delimiter, ref index);
+        }
+
+        static void UpdateIndexListCommit(List<uint> values, int delimiter,
+                                          ref IndexBase index)
+        {
+            if (delimiter != 0 || values.Count == 0) { return; }
+            if (!(index is IndexList)) { index = new IndexList(); }
+            ((IndexList)index).Indices.Add(new List<uint>(values));
+            values.Clear();
+        }
+
+        void ParseMainIndexes(LocalIndexes indexes)
+        {
+            int delimiter = 0;
+            List<uint> designatorValues = new List<uint>(); IndexBase designator = IndexBase.Unset;
+            List<uint> stringValues = new List<uint>(); IndexBase @string = IndexBase.Unset;
+            List<uint> usageValues = new List<uint>(); IndexBase usage = IndexBase.Unset;
+
+            foreach (KeyValuePair<LocalItemTag, uint> kvp in LocalItemState)
+            {
+                switch (kvp.Key)
+                {
+                    case LocalItemTag.DesignatorMinimum: UpdateIndexMinimum(ref designator, kvp.Value); break;
+                    case LocalItemTag.StringMinimum: UpdateIndexMinimum(ref @string, kvp.Value); break;
+                    case LocalItemTag.UsageMinimum: UpdateIndexMinimum(ref usage, kvp.Value); break;
+
+                    case LocalItemTag.DesignatorMaximum: UpdateIndexMaximum(ref designator, kvp.Value); break;
+                    case LocalItemTag.StringMaximum: UpdateIndexMaximum(ref @string, kvp.Value); break;
+                    case LocalItemTag.UsageMaximum: UpdateIndexMaximum(ref usage, kvp.Value); break;
+
+                    case LocalItemTag.DesignatorIndex: UpdateIndexList(designatorValues, delimiter, ref designator, kvp.Value); break;
+                    case LocalItemTag.StringIndex: UpdateIndexList(stringValues, delimiter, ref @string, kvp.Value); break;
+                    case LocalItemTag.Usage: UpdateIndexList(usageValues, delimiter, ref usage, kvp.Value); break;
+
+                    case LocalItemTag.Delimiter:
+                        if (kvp.Value == 1)
+                        {
+                            if (delimiter++ == 0)
+                            {
+                                designatorValues.Clear();
+                                stringValues.Clear();
+                                usageValues.Clear();
+                            }
+                        }
+                        else if (kvp.Value == 0)
+                        {
+                            delimiter--;
+                            UpdateIndexListCommit(designatorValues, delimiter, ref designator);
+                            UpdateIndexListCommit(stringValues, delimiter, ref @string);
+                            UpdateIndexListCommit(usageValues, delimiter, ref usage);
+                        }
+                        break;
+                }
+            }
+
+            indexes.Designator = designator;
+            indexes.String = @string;
+            indexes.Usage = usage;
+        }
+
+        void ParseDataMain(MainItemTag tag, uint value, out LocalIndexes indexes)
+        {
+            ReportSegment segment = new ReportSegment();
+            segment.Flags = (DataMainItemFlags)value;
+            segment.Parent = CurrentCollection;
+            segment.ElementCount = (int)GetGlobalItemValue(GlobalItemTag.ReportCount);
+            segment.ElementSize = (int)GetGlobalItemValue(GlobalItemTag.ReportSize);
+            segment.Unit = new Units.Unit(GetGlobalItemValue(GlobalItemTag.Unit));
+            segment.UnitExponent = Units.Unit.DecodeExponent(GetGlobalItemValue(GlobalItemTag.UnitExponent));
+            indexes = segment.Indexes;
+
+            EncodedItem logicalMinItem = GetGlobalItem(GlobalItemTag.LogicalMinimum);
+            EncodedItem logicalMaxItem = GetGlobalItem(GlobalItemTag.LogicalMaximum);
+            segment.LogicalIsSigned =
+                (logicalMinItem != null && logicalMinItem.DataValueMayBeNegative) ||
+                (logicalMaxItem != null && logicalMaxItem.DataValueMayBeNegative);
+            int logicalMinimum = logicalMinItem == null ? 0 : segment.LogicalIsSigned ? logicalMinItem.DataValueSigned : (int)logicalMinItem.DataValue;
+            int logicalMaximum = logicalMaxItem == null ? 0 : segment.LogicalIsSigned ? logicalMaxItem.DataValueSigned : (int)logicalMaxItem.DataValue;
+            int physicalMinimum = (int)GetGlobalItemValue(GlobalItemTag.PhysicalMinimum);
+            int physicalMaximum = (int)GetGlobalItemValue(GlobalItemTag.PhysicalMaximum);
+            if (!IsGlobalItemSet(GlobalItemTag.PhysicalMinimum) ||
+                !IsGlobalItemSet(GlobalItemTag.PhysicalMaximum) ||
+                (physicalMinimum == 0 && physicalMaximum == 0))
+            {
+                physicalMinimum = logicalMinimum; physicalMaximum = logicalMaximum;
+            }
+
+            segment.LogicalMinimum = logicalMinimum; segment.LogicalMaximum = logicalMaximum;
+            segment.PhysicalMinimum = physicalMinimum; segment.PhysicalMaximum = physicalMaximum;
+
+            Report report;
+            ReportType reportType
+                = tag == MainItemTag.Output ? ReportType.Output
+                : tag == MainItemTag.Feature ? ReportType.Feature
+                : ReportType.Input;
+            uint reportID = GetGlobalItemValue(GlobalItemTag.ReportID);
+            if (!TryGetReport(reportType, (byte)reportID, out report))
+            {
+                report = new Report() { ID = (byte)reportID, Type = reportType };
+                Reports.Add(report);
+            }
+            segment.Report = report;
+        }
+
+        public ReportCollection CurrentCollection
+        {
+            get;
+            set;
+        }
+
+        public ReportCollection RootCollection
+        {
+            get;
+            private set;
+        }
+
+        public IDictionary<GlobalItemTag, EncodedItem> GlobalItemState
+        {
+            get { return GlobalItemStateStack[GlobalItemStateStack.Count - 1]; }
+        }
+
+        public IList<IDictionary<GlobalItemTag, EncodedItem>> GlobalItemStateStack
+        {
+            get;
+            private set;
+        }
+
+        public IList<KeyValuePair<LocalItemTag, uint>> LocalItemState
+        {
+            get;
+            private set;
+        }
+
+        IEnumerable<Report> FilterReports(ReportType reportType)
+        {
+            foreach (Report report in Reports)
+            {
+                if (report.Type == reportType) { yield return report; }
+            }
+        }
+
+        public IEnumerable<Report> InputReports
+        {
+            get { return FilterReports(ReportType.Input); }
+        }
+
+        /// <summary>
+        /// The maximum input report length.
+        /// The Report ID is not included in this length.
+        /// </summary>
+        public int InputReportMaxLength
+        {
+            get { return GetMaxLengthOfReports(InputReports); }
+        }
+
+        public IEnumerable<Report> OutputReports
+        {
+            get { return FilterReports(ReportType.Output); }
+        }
+
+        /// <summary>
+        /// The maximum output report length.
+        /// The Report ID is not included in this length.
+        /// </summary>
+        public int OutputReportMaxLength
+        {
+            get { return GetMaxLengthOfReports(OutputReports); }
+        }
+
+        public IEnumerable<Report> FeatureReports
+        {
+            get { return FilterReports(ReportType.Feature); }
+        }
+
+        /// <summary>
+        /// The maximum feature report length.
+        /// The Report ID is not included in this length.
+        /// </summary>
+        public int FeatureReportMaxLength
+        {
+            get { return GetMaxLengthOfReports(FeatureReports); }
+        }
+
+        public IList<Report> Reports
+        {
+            get;
+            private set;
+        }
+
+        /// <summary>
+        /// True if the device sends Report IDs.
+        /// </summary>
+        public bool ReportsUseID
+        {
+            get;
+            set;
+        }
+
+        public IEnumerable<IEnumerable<uint>> InputUsages
+        {
+            get
+            {
+                foreach (Report report in InputReports)
+                {
+                    foreach (ReportSegment segment in report.Segments)
+                    {
+                        IndexBase usages = segment.Indexes.Usage;
+                        for (int i = 0; i < usages.Count; i++)
+                        {
+                            yield return usages.ValuesFromIndex(i);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 53 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/ReportMainItem.cs

@@ -0,0 +1,53 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+
+namespace HidSharp.ReportDescriptors.Parser
+{
+    public class ReportMainItem
+    {
+        ReportCollection _parent;
+
+        public ReportMainItem()
+        {
+            Indexes = new LocalIndexes();
+        }
+
+        public LocalIndexes Indexes
+        {
+            get;
+            private set;
+        }
+
+        public ReportCollection Parent
+        {
+            get { return _parent; }
+            set
+            {
+                if (_parent == value) { return; }
+
+                ReportCollection check = value;
+                while (check != null && check != this) { check = check.Parent; }
+                if (check == this) { throw new ArgumentException("Can't set up a loop."); }
+
+                if (_parent != null) { _parent._children.Remove(this); }
+                _parent = value;
+                if (_parent != null) { _parent._children.Add(this); }
+            }
+        }
+    }
+}

+ 209 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/ReportSegment.cs

@@ -0,0 +1,209 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HidSharp.ReportDescriptors.Parser
+{
+    public class ReportSegment : ReportMainItem
+    {
+        Report _report;
+
+        public int ConvertArbitraryRangeToValue(double quantity, double minimum, double maximum)
+        {
+            return Math.Max(LogicalMinimum, Math.Min(LogicalMaximum,
+                (int)((quantity - minimum) * LogicalRange / (maximum - minimum))));
+        }
+
+        public int ConvertPhysicalQuantityToValue(double quantity)
+        {
+            double exp = Math.Pow(10, UnitExponent);
+            return ConvertArbitraryRangeToValue(quantity,
+                PhysicalMinimum * exp, PhysicalMaximum * exp);
+        }
+
+        public double ConvertValueToArbitraryRange(int value,
+            double minimum, double maximum)
+        {
+            return minimum + (value - LogicalMinimum) * (maximum - minimum) / LogicalRange;
+        }
+
+        public double ConvertValueToPhysicalQuantity(int value)
+        {
+            double exp = Math.Pow(10, UnitExponent);
+            return ConvertValueToArbitraryRange(value,
+                PhysicalMinimum * exp, PhysicalRange * exp);
+        }
+
+        public int DecodeSigned(uint value)
+        {
+            uint signBit = 1u << (ElementSize - 1), mask = signBit - 1;
+            return (value & signBit) != 0 ? (int)(value | ~mask) : (int)value;
+        }
+
+        public uint EncodeSigned(int value)
+        {
+            uint usValue = (uint)value;
+            uint signBit = 1u << (ElementSize - 1), mask = signBit - 1;
+            return (usValue & mask) | (value < 0 ? signBit : 0);
+        }
+
+        public bool IsValueOutOfRange(int value)
+        {
+            return LogicalIsSigned
+                ? value < LogicalMinimum || value > LogicalMaximum
+                : ((uint)value < (uint)LogicalMinimum || (uint)value > (uint)LogicalMaximum)
+                ;
+        }
+
+        public int Read(byte[] buffer, int bitOffset, int element)
+        {
+            uint rawValue = ReadRaw(buffer, bitOffset, element);
+            return LogicalIsSigned ? DecodeSigned(rawValue) : (int)rawValue;
+        }
+
+        public uint ReadRaw(byte[] buffer, int bitOffset, int element)
+        {
+            uint value = 0; int totalBits = Math.Min(ElementSize, 32);
+            bitOffset += element * ElementSize;
+
+            for (int i = 0; i < totalBits; i++, bitOffset ++)
+            {
+                int byteStart = bitOffset >> 3; byte bitStart = (byte)(1u << (bitOffset & 7));
+                value |= (buffer[byteStart] & bitStart) != 0 ? (1u << i) : 0;
+            }
+
+            return value;
+        }
+
+        public void Write(byte[] buffer, int bitOffset, int element, int value)
+        {
+            WriteRaw(buffer, bitOffset, element,
+                LogicalIsSigned ? EncodeSigned(value) : (uint)value);
+        }
+
+        public void WriteRaw(byte[] buffer, int bitOffset, int element, uint value)
+        {
+            int totalBits = Math.Min(ElementSize, 32);
+            bitOffset += element * ElementSize;
+
+            for (int i = 0; i < totalBits; i++, bitOffset++)
+            {
+                int byteStart = bitOffset >> 3; uint bitStart = 1u << (bitOffset & 7);
+                if ((value & (1 << i)) != 0) { buffer[byteStart] |= (byte)bitStart; } else { buffer[byteStart] &= (byte)(~bitStart); }
+            }
+        }
+
+        public int BitCount
+        {
+            get { return ElementCount * ElementSize; }
+        }
+
+        public int ElementCount
+        {
+            get;
+            set;
+        }
+
+        public int ElementSize
+        {
+            get;
+            set;
+        }
+
+        public DataMainItemFlags Flags
+        {
+            get;
+            set;
+        }
+
+        public bool LogicalIsSigned
+        {
+            get;
+            set;
+        }
+
+        public int LogicalMinimum
+        {
+            get;
+            set;
+        }
+
+        public int LogicalMaximum
+        {
+            get;
+            set;
+        }
+
+        public int LogicalRange
+        {
+            get { return LogicalMaximum - LogicalMinimum; }
+        }
+
+        public int PhysicalMinimum
+        {
+            get;
+            set;
+        }
+
+        public int PhysicalMaximum
+        {
+            get;
+            set;
+        }
+
+        public int PhysicalRange
+        {
+            get { return PhysicalMaximum - PhysicalMinimum; }
+        }
+
+        public Report Report
+        {
+            get { return _report; }
+            set
+            {
+                if (_report == value) { return; }
+
+                if (_report != null) { _report._segments.Remove(this); }
+                _report = value;
+                if (_report != null) { _report._segments.Add(this); }
+            }
+        }
+
+        public double Resolution
+        {
+            get
+            {
+                return (double)LogicalRange /
+                    ((double)PhysicalRange *
+                    Math.Pow(10, UnitExponent));
+            }
+        }
+
+        public Units.Unit Unit
+        {
+            get;
+            set;
+        }
+
+        public int UnitExponent
+        {
+            get;
+            set;
+        }
+    }
+}

+ 25 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Parser/ReportType.cs

@@ -0,0 +1,25 @@
+#region License
+/* Copyright 2011 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors.Parser
+{
+    public enum ReportType
+    {
+        Input,
+        Output,
+        Feature
+    }
+}

+ 34 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/CurrentUnit.cs

@@ -0,0 +1,34 @@
+#region License
+/* Copyright 2011, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors.Units
+{
+    /// <summary>
+    /// Defines the possible units of current.
+    /// </summary>
+    public enum CurrentUnit
+    {
+        /// <summary>
+        /// The unit system has no unit of current.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// The unit of current is the Ampere.
+        /// </summary>
+        Ampere
+    }
+}

+ 49 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/LengthUnit.cs

@@ -0,0 +1,49 @@
+#region License
+/* Copyright 2011, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors.Units
+{
+    /// <summary>
+    /// Defines the possible units of length.
+    /// </summary>
+    public enum LengthUnit
+    {
+        /// <summary>
+        /// The unit system has no unit of length.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// The unit of length is the centimeter (occurs in the SI Linear unit system).
+        /// </summary>
+        Centimeter,
+
+        /// <summary>
+        /// The unit of length is the radian (occurs in the SI Rotation unit system).
+        /// </summary>
+        Radians,
+
+        /// <summary>
+        /// The unit of length is the inch (occurs in the English Linear unit system).
+        /// </summary>
+        Inch,
+
+        /// <summary>
+        /// The unit of length is the degree (occurs in the English Rotation unit system).
+        /// </summary>
+        Degrees
+    }
+}

+ 34 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/LuminousIntensityUnit.cs

@@ -0,0 +1,34 @@
+#region License
+/* Copyright 2011, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors.Units
+{
+    /// <summary>
+    /// Defines the possible units of luminous intensity.
+    /// </summary>
+    public enum LuminousIntensityUnit
+    {
+        /// <summary>
+        /// The unit system has no unit of luminous intensity.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// The unit of luminous intensity is the candela.
+        /// </summary>
+        Candela
+    }
+}

+ 39 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/MassUnit.cs

@@ -0,0 +1,39 @@
+#region License
+/* Copyright 2011, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors.Units
+{
+    /// <summary>
+    /// Defines the possible units of mass.
+    /// </summary>
+    public enum MassUnit
+    {
+        /// <summary>
+        /// The unit system has no unit of mass.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// The unit of mass is the gram (occurs in the SI Linear and Rotation unit systems).
+        /// </summary>
+        Gram,
+
+        /// <summary>
+        /// The unit of mass is the slug (occurs in the English Linear and Rotation unit systems).
+        /// </summary>
+        Slug
+    }
+}

+ 39 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/TemperatureUnit.cs

@@ -0,0 +1,39 @@
+#region License
+/* Copyright 2011, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors.Units
+{
+    /// <summary>
+    /// Defines the possible units of temperature.
+    /// </summary>
+    public enum TemperatureUnit
+    {
+        /// <summary>
+        /// The unit system has no unit of temperature.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// The unit of temperature is Kelvin (occurs in SI Linear and Rotation unit systems).
+        /// </summary>
+        Kelvin,
+
+        /// <summary>
+        /// The unit of temperature is Fahrenheit (occurs in English Linear and Rotation unit systems).
+        /// </summary>
+        Fahrenheit
+    }
+}

+ 34 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/TimeUnit.cs

@@ -0,0 +1,34 @@
+#region License
+/* Copyright 2011, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors.Units
+{
+    /// <summary>
+    /// Defines the possible units of time.
+    /// </summary>
+    public enum TimeUnit
+    {
+        /// <summary>
+        /// The unit system has no unit of time.
+        /// </summary>
+        None,
+
+        /// <summary>
+        /// The unit of time is seconds.
+        /// </summary>
+        Seconds
+    }
+}

+ 242 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/Unit.cs

@@ -0,0 +1,242 @@
+#region License
+/* Copyright 2011, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+
+namespace HidSharp.ReportDescriptors.Units
+{
+    /// <summary>
+    /// Describes the units of a report value.
+    /// </summary>
+    public class Unit
+    {
+        uint _value;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Unit"/> class.
+        /// </summary>
+        /// <param name="value">The raw HID value describing the units.</param>
+        public Unit(uint value)
+        {
+            _value = value;
+        }
+
+        uint Element(int index)
+        {
+            return (Value >> (index << 2)) & 0xf;
+        }
+
+        int Exponent(int index)
+        {
+            return DecodeExponent(Element(index));
+        }
+
+        /// <summary>
+        /// Decodes an encoded HID unit exponent.
+        /// </summary>
+        /// <param name="value">The encoded exponent.</param>
+        /// <returns>The exponent.</returns>
+        public static int DecodeExponent(uint value)
+        {
+            if (value > 15) { throw new ArgumentOutOfRangeException("value", "Value range is [0, 15]."); }
+            return value >= 8 ? (int)value - 16 : (int)value;
+        }
+
+        void Element(int index, uint value)
+        {
+            Value &= 0xfu << (index << 2); Value |= (value & 0xfu) << (index << 2);
+        }
+
+        /// <summary>
+        /// Encodes an exponent in HID unit form.
+        /// </summary>
+        /// <param name="value">The exponent.</param>
+        /// <returns>The encoded exponent.</returns>
+        public static uint EncodeExponent(int value)
+        {
+            if (value < -8 || value > 7)
+                { throw new ArgumentOutOfRangeException("value", "Exponent range is [-8, 7]."); }
+            return (uint)(value < 0 ? value + 16 : value);
+        }
+
+        void Exponent(int index, int value)
+        {
+            Element(index, EncodeExponent(value));
+        }
+
+        /// <summary>
+        /// Gets or sets the unit system.
+        /// </summary>
+        public UnitSystem System
+        {
+            get { return (UnitSystem)Element(0); }
+            set { Element(0, (uint)value); }
+        }
+
+        /// <summary>
+        /// Gets or sets the exponent of the report value's units of length.
+        /// </summary>
+        public int LengthExponent
+        {
+            get { return Exponent(1); }
+            set { Exponent(1, value); }
+        }
+
+        /// <summary>
+        /// Gets the units of length corresponding to <see cref="System"/>.
+        /// </summary>
+        public LengthUnit LengthUnit
+        {
+            get
+            {
+                switch (System)
+                {
+                    case UnitSystem.SILinear: return LengthUnit.Centimeter;
+                    case UnitSystem.SIRotation: return LengthUnit.Radians;
+                    case UnitSystem.EnglishLinear: return LengthUnit.Inch;
+                    case UnitSystem.EnglishRotation: return LengthUnit.Degrees;
+                    default: return LengthUnit.None;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the exponent of the report value's units of mass.
+        /// </summary>
+        public int MassExponent
+        {
+            get { return Exponent(2); }
+            set { Exponent(2, value); }
+        }
+
+        /// <summary>
+        /// Gets the units of mass corresponding to <see cref="System"/>.
+        /// </summary>
+        public MassUnit MassUnit
+        {
+            get
+            {
+                switch (System)
+                {
+                    case UnitSystem.SILinear:
+                    case UnitSystem.SIRotation: return MassUnit.Gram;
+                    case UnitSystem.EnglishLinear:
+                    case UnitSystem.EnglishRotation: return MassUnit.Slug;
+                    default: return MassUnit.None;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the exponent of the report value's units of time.
+        /// </summary>
+        public int TimeExponent
+        {
+            get { return Exponent(3); }
+            set { Exponent(3, value); }
+        }
+
+        /// <summary>
+        /// Gets the units of time corresponding to <see cref="System"/>.
+        /// </summary>
+        public TimeUnit TimeUnit
+        {
+            get
+            {
+                return System != UnitSystem.None
+                    ? TimeUnit.Seconds : TimeUnit.None;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the exponent of the report value's units of temperature.
+        /// </summary>
+        public int TemperatureExponent
+        {
+            get { return Exponent(4); }
+            set { Exponent(4, value); }
+        }
+
+        /// <summary>
+        /// Gets the units of temperature corresponding to <see cref="System"/>.
+        /// </summary>
+        public TemperatureUnit TemperatureUnit
+        {
+            get
+            {
+                switch (System)
+                {
+                    case UnitSystem.SILinear:
+                    case UnitSystem.SIRotation: return TemperatureUnit.Kelvin;
+                    case UnitSystem.EnglishLinear:
+                    case UnitSystem.EnglishRotation: return TemperatureUnit.Fahrenheit;
+                    default: return TemperatureUnit.None;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the exponent of the report value's units of current.
+        /// </summary>
+        public int CurrentExponent
+        {
+            get { return Exponent(5); }
+            set { Exponent(5, value); }
+        }
+
+        /// <summary>
+        /// Gets the units of current corresponding to <see cref="System"/>.
+        /// </summary>
+        public CurrentUnit CurrentUnit
+        {
+            get
+            {
+                return System != UnitSystem.None
+                    ? CurrentUnit.Ampere : CurrentUnit.None;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the exponent of the report value's units of luminous intensity.
+        /// </summary>
+        public int LuminousIntensityExponent
+        {
+            get { return Exponent(6); }
+            set { Exponent(6, value); }
+        }
+
+        /// <summary>
+        /// Gets the units of luminous intensity corresponding to <see cref="System"/>.
+        /// </summary>
+        public LuminousIntensityUnit LuminousIntensityUnit
+        {
+            get
+            {
+                return System != UnitSystem.None
+                    ? LuminousIntensityUnit.Candela : LuminousIntensityUnit.None;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the raw HID value describing the units.
+        /// </summary>
+        public uint Value
+        {
+            get { return _value; }
+            set { _value = value; }
+        }
+    }
+}

+ 53 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/ReportDescriptors/Units/UnitSystem.cs

@@ -0,0 +1,53 @@
+#region License
+/* Copyright 2011, 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+namespace HidSharp.ReportDescriptors.Units
+{
+    /// <summary>
+    /// Defines the possible unit systems.
+    /// </summary>
+    public enum UnitSystem
+    {
+        /// <summary>
+        /// No units are used.
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// The SI Linear unit system uses centimeters for length, grams for mass, seconds for time,
+        /// Kelvin for temperature, Amperes for current, and candelas for luminous intensity.
+        /// </summary>
+        SILinear,
+
+        /// <summary>
+        /// The SI Rotation unit system uses radians for length, grams for mass, seconds for time,
+        /// Kelvin for temperature, Amperes for current, and candelas for luminous intensity.
+        /// </summary>
+        SIRotation,
+
+        /// <summary>
+        /// The English Linear unit system uses inches for length, slugs for mass, seconds for time,
+        /// Fahrenheit for temperature, Amperes for current, and candelas for luminous intensity.
+        /// </summary>
+        EnglishLinear,
+
+        /// <summary>
+        /// The English Rotation unit system uses degrees for length, slugs for mass, seconds for time,
+        /// Fahrenheit for temperature, Amperes for current, and candelas for luminous intensity.
+        /// </summary>
+        EnglishRotation
+    }
+}

+ 50 - 0
dreamcheekyusb/DreamCheekyBTN/HidSharp/Throw.cs

@@ -0,0 +1,50 @@
+#region License
+/* Copyright 2013 James F. Bellinger <http://www.zer7.com/software/hidsharp>
+
+   Permission to use, copy, modify, and/or distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HidSharp {
+	sealed class Throw {
+		Throw() {
+
+		}
+
+		public static Throw If {
+			get { return null; }
+		}
+	}
+
+	static class ThrowExtensions {
+		public static Throw Null<T>(this Throw self, T value, string paramName) {
+			if (value == null) {
+				throw new ArgumentNullException(paramName);
+			}
+			return null;
+		}
+
+		public static Throw OutOfRange<T>(this Throw self, IList<T> buffer, int offset, int count) {
+			Throw.If.Null(buffer, "buffer");
+			if (offset < 0 || offset > buffer.Count) {
+				throw new ArgumentOutOfRangeException("offset");
+			}
+			if (count < 0 || count > buffer.Count - offset) {
+				throw new ArgumentOutOfRangeException("count");
+			}
+			return null;
+		}
+	}
+}

+ 176 - 0
dreamcheekyusb/DreamCheekyBTN/Program.cs

@@ -0,0 +1,176 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Diagnostics;
+
+namespace DreamCheekyUSB {
+	class Program {
+		static string strCMD = "";
+		static string strCMDARGs = "";
+		static string strMacro = "";
+		static int count = 0;
+
+		static int Main(string[] args) {
+			int actions = 0;
+			DreamCheekyBTN btn = null;
+			try {
+				if (args.ContainsInsensitive("debug")) {
+					Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
+				}
+
+				string devicearg = args.StartsWith("device=").FirstOrDefault();
+				if (string.IsNullOrEmpty(devicearg)) {
+					Trace.WriteLine("\r\nConnecting to DreamCheekyBTN using default values...");
+					try {
+						btn = new DreamCheekyBTN();
+					} catch (Exception ignored) {
+						Trace.WriteLine(ignored.Message);
+						Trace.WriteLine("No Iron Man USB Stress Buttons found.\r\nSearching for Big Red Buttons...");
+						btn = new DreamCheekyBigRedBTN(DreamCheekyBigRedBTN.DEFAULT_VENDOR_ID, DreamCheekyBigRedBTN.DEFAULT_PRODUCT_ID);
+					}
+				} else {
+					Trace.WriteLine("\r\nConnecting to DreamCheekyBTN using specified device {0}...", devicearg);
+					string[] deviceSplit = devicearg.Substring(7).Split(',');
+					if (deviceSplit.Length == 1) {
+						//One argument = device path
+						var searchString = string.Format("pid_{0}", DreamCheekyBigRedBTN.PID);
+						if (deviceSplit[0].Contains(searchString)) {
+							Trace.WriteLine("Device is a Big Red Button...");
+							btn = new DreamCheekyBigRedBTN(deviceSplit[0]);
+						} else {
+							Trace.WriteLine("Device is a Iron Man USB Stress Button...");
+							btn = new DreamCheekyBTN(deviceSplit[0]);
+						}
+					} else {
+						//Two or Three arguments = VID,PID,Count=0
+						int devicecount = 0;
+						if (deviceSplit.Length > 2) {
+							devicecount = int.Parse(deviceSplit[2]);
+						}
+
+						int VID = int.Parse(deviceSplit[0].Substring(2), System.Globalization.NumberStyles.HexNumber);
+						int PID = int.Parse(deviceSplit[1].Substring(2), System.Globalization.NumberStyles.HexNumber);
+												
+						if (PID == DreamCheekyBTN.DEFAULT_PRODUCT_ID) {
+							btn = new DreamCheekyBTN(VID, PID, devicecount);
+						} else {
+							btn = new DreamCheekyBigRedBTN(VID, PID, devicecount);
+						}
+					}
+				}
+
+				string cmdarg = args.StartsWith("CMD=").FirstOrDefault();
+				if (!string.IsNullOrEmpty(cmdarg)) {
+					actions++;
+					strCMD = cmdarg.Substring(4);
+					Console.WriteLine("Setting command to: " + strCMD);
+				}
+
+				string argarg = args.StartsWith("ARG=").FirstOrDefault();
+				if (!string.IsNullOrEmpty(argarg)) {
+					strCMDARGs = argarg.Substring(4);
+					Console.WriteLine("Setting command arguments to: " + strCMDARGs);
+				}
+
+				string macroarg = args.StartsWith("MACRO=").FirstOrDefault();
+				if (!string.IsNullOrEmpty(macroarg)) {
+					actions++;
+					string[] macosplit = macroarg.Split('=');
+					strMacro = macosplit[1];
+					Console.WriteLine("Setting Macro to: " + strMacro);
+				}
+
+				if (actions > 0) {
+					btn.RegisterCallback(DoAction);
+					Console.WriteLine("Listening for button press events. Press any key to escape...");
+					Console.ReadKey(true);
+				}
+			} catch (Exception ex) {
+				Trace.TraceError("\r\n\r\nError: " + ex.Message + "\r\n\r\n");
+			}
+
+			//Pause on exit or display usage syntax
+			if (actions > 0) {
+				Trace.WriteLine("Finished\r\n");
+			} else { //No actions specified, show help
+				Console.WriteLine("  DreamCheekyBTN.exe [device=...] [options]");
+
+				Console.WriteLine("\r\nExamples:");
+
+				Console.WriteLine("  DreamCheekyBTN.exe debug MACRO=ASDF~  (ASDF then Enter)");
+				Console.WriteLine("  DreamCheekyBTN.exe MACRO=%+{F1}       (ALT+SHIFT+F1)");
+				Console.WriteLine("  DreamCheekyBTN.exe CMD=c:\\temp\\test.bat");
+				Console.WriteLine(@"  DreamCheekyBTN.exe CMD=powershell ARG=""-noexit -executionpolicy unrestricted -File c:\test.ps1""");
+
+				Console.WriteLine("\r\n\r\nDevice Path:");
+				Console.WriteLine("  Optional, Defaults to first USB device with VID=0x1D34 and PID=0x0008");
+				Console.WriteLine("  Example (VID,PID,Index): device=\"0x1D34,0x0008,0\"");
+				Console.WriteLine("  Example (Path): device=" + @"""\\?\hid#vid_1d34&pid_0008#6&1067c3dc&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}""");
+
+				Console.WriteLine("\r\nOptions:");
+				Console.WriteLine("  debug = Print Console statements to Console.Out");
+
+				Console.WriteLine("\r\nCMD: will run specified command when button is pressed");
+				Console.WriteLine("ARG: can be used to specified command arguments");
+				Console.WriteLine("  Example (open calculator): CMD=calc");
+				Console.WriteLine("  Example (run Powershell commands): ");
+				Console.WriteLine("     CMD=\"%SystemRoot%\\system32\\WindowsPowerShell\\v1.0\\powershell.exe\"");
+				Console.WriteLine(@"     ARG=""-Command \""& {write-host 'BEEP!'; [console]::beep(440,1000);}\""""");
+				Console.WriteLine("  NOTE: use ^& instead of & if running from command prompt as & is special character");
+
+				Console.WriteLine("\r\nMACRO: will send specified key sequense to active window via C# Sendkeys");
+				Console.WriteLine("NOTE: +=Shift, ^=CTRL, %=ALT, ~=Return, use () to group characters.");
+				Console.WriteLine("  Example: MACRO=\"%^g\"        (ALT + CTRL + g)");
+				Console.WriteLine("  Example: MACRO=\"%(asdf)\"    (ALT + asdf)");
+				Console.WriteLine("\r\n");
+
+			}
+
+			if (args.ContainsInsensitive("pause")) {
+				Console.WriteLine("\r\nPress enter to exit...");
+				Console.ReadLine();
+			}
+
+			if (btn != null) {
+				btn.Dispose();
+			}
+			return 0;
+		}
+
+		static void DoAction() {
+			count++;
+			Console.WriteLine(String.Format("\r\n{0}: Detected button press event. Count={1}", DateTime.Now.ToLongTimeString(), count));
+			if (!string.IsNullOrEmpty(strCMD)) {
+				try {
+					Process.Start(strCMD, strCMDARGs);
+				} catch (Exception ex) {
+					Trace.TraceError("Error: " + ex.Message);
+				}
+			}
+			if (!string.IsNullOrEmpty(strMacro)) {
+				try {
+					Console.WriteLine("Sending keys: " + strMacro);
+					System.Windows.Forms.SendKeys.SendWait(strMacro);
+				} catch (Exception ex) {
+					Trace.TraceError("Error: " + ex.Message);
+				}
+			}
+		}
+	}
+
+	/// <summary>
+	/// Extenstions for working with string arrays
+	/// </summary>
+	public static class StringArrayExtenstions {
+		public static bool ContainsInsensitive(this string[] args, string name) {
+			return args.Contains(name, StringComparer.CurrentCultureIgnoreCase);
+		}
+
+		public static IEnumerable<string> StartsWith(this string[] args, string value, StringComparison options = StringComparison.CurrentCultureIgnoreCase) {
+			var q = from a in args
+			        where a.StartsWith(value, options)
+			        select a;
+			return q;
+		}
+	}
+}

+ 36 - 0
dreamcheekyusb/DreamCheekyBTN/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("DreamCheekyBTN")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Greg Bray")]
+[assembly: AssemblyProduct("DreamCheekyBTN")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("cca79608-f9fd-40b2-ab14-20cc8f32c49e")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 58 - 0
dreamcheekyusb/DreamCheekyBTN/Readme.txt

@@ -0,0 +1,58 @@
+DreamCheekyBTN is a Console based utility for the Dream Cheeky USB "Big Red Stress" buttons. Specifically this was
+Created for the Iron Man button, but I assume it works with other Dream Cheeky USB buttons as well.
+It was created using the https://github.com/mikeobrien/HidLibrary/ and is released under the Apache License V2.0
+
+The DreamCheekyBTN.exe has command line arguments that will let you run a program whenever the button is pressed or
+convert the button press events into a keyboard macro that can perform an action or be picked up by other programs
+like AutoHotKey. The code should also support multiple devices, and can be run multiple times for additional triggers.
+See below for command line examples or the AutoHotKey.ahk file for a sample AutoHotKey script.
+
+If you are interested in how this works at a high level the general process is:
+1. Create HidDevice object using HidLibrary.HidDevices.Enumerate (default VendorID=0x1D34 and ProductID=0x0008)
+
+2. Use a System.Timers.Timer to poll the device every 100ms.
+
+3. First it sends the following command to get the device status:
+	public static readonly byte[] cmd_status = new byte[9] { 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 };
+
+4. Then it reads from the device one of the following two results:
+byte[] btn_Active =   new byte[9] { 0, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 };
+byte[] btn_InActive = new byte[9] { 0, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 };
+NOTE: these values were found using the SimpleHIDWrite (http://www.lvr.com/hidpage.htm) and USBTrace programs 
+
+5. If the button is active, it will perform the requested action. The event then cannot be triggered again until after
+the button is released and pressed a second time. 
+
+
+Command Line Usage:
+  DreamCheekyBTN.exe [device=...] [options]
+
+Examples:
+  DreamCheekyBTN.exe debug MACRO=ASDF~  (ASDF then Enter)
+  DreamCheekyBTN.exe MACRO=%+{F1}       (ALT+SHIFT+F1)
+  DreamCheekyBTN.exe CMD=c:\temp\test.bat
+  DreamCheekyBTN.exe CMD=powershell ARG="-noexit -executionpolicy unrestricted -
+File c:\test.ps1"
+
+
+Device Path:
+  Optional, Defaults to first USB device with VID=0x1D34 and PID=0x0008
+  Example (VID,PID,Index): device="0x1D34,0x0008,0"
+  Example (Path): device="\\?\hid#vid_1d34&pid_0008#6&1067c3dc&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+Options:
+  debug = Print trace statements to Console.Out
+
+CMD: will run specified command when button is pressed
+ARG: can be used to specified command arguments
+  Example (open calculator): CMD=calc
+  Example (run Powershell commands):
+     CMD="%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe"
+     ARG="-Command \"& {write-host 'BEEP!'; [console]::beep(440,1000);}\""
+  NOTE: use ^& instead of & if running from command prompt as & is special chara
+cter
+
+MACRO: will send specified key sequense to active window via C# Sendkeys
+NOTE: +=Shift, ^=CTRL, %=ALT, ~=Return, use () to group characters.
+  Example: MACRO="%^g"        (ALT + CTRL + g)
+  Example: MACRO="%(asdf)"    (ALT + asdf)

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff