// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel // // 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. using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Windows.Forms; using SharpDX.Multimedia; using SharpDX.Win32; namespace SharpDX.RawInput { /// /// Provides access to RawInput methods. /// public partial class Device { private static RawInputMessageFilter rawInputMessageFilter; /// /// Occurs when [keyboard input]. /// public static event EventHandler KeyboardInput; /// /// Occurs when [mouse input]. /// public static event EventHandler MouseInput; /// /// Occurs when [raw input]. /// public static event EventHandler RawInput; /// /// Gets the devices. /// /// public static unsafe List GetDevices() { // Get the number of input device int deviceCount = 0; RawInputFunctions.GetRawInputDeviceList(null, ref deviceCount, Utilities.SizeOf()); if (deviceCount == 0) return null; // Get the raw input device list var rawInputDeviceList = new RawInputDevicelist[deviceCount]; RawInputFunctions.GetRawInputDeviceList(rawInputDeviceList, ref deviceCount, Utilities.SizeOf()); var deviceInfoList = new List(); // Iterate on all input device for (int i = 0; i < deviceCount; i++) { var deviceHandle = rawInputDeviceList[i].Device; // Get the DeviceName int countDeviceNameChars = 0; RawInputFunctions.GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.DeviceName, IntPtr.Zero, ref countDeviceNameChars); char* deviceNamePtr = stackalloc char[countDeviceNameChars]; RawInputFunctions.GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.DeviceName, (IntPtr)deviceNamePtr, ref countDeviceNameChars); var nullCharIndex = 0; while (nullCharIndex <= countDeviceNameChars && deviceNamePtr[nullCharIndex++] != '\0') ; var deviceName = new string(deviceNamePtr, 0, nullCharIndex == 0 ? 0 : nullCharIndex - 1); // Get the DeviceInfo int sizeOfDeviceInfo = 0; RawInputFunctions.GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.DeviceInfo, IntPtr.Zero, ref sizeOfDeviceInfo); byte* deviceInfoPtr = stackalloc byte[sizeOfDeviceInfo]; RawInputFunctions.GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.DeviceInfo, (IntPtr)deviceInfoPtr, ref sizeOfDeviceInfo); deviceInfoList.Add(DeviceInfo.Convert(ref *(RawDeviceInformation*)deviceInfoPtr, deviceName, deviceHandle)); } return deviceInfoList; } /// /// Registers the devices that supply the raw input data. /// /// The usage page. /// The usage id. /// The flags. public static void RegisterDevice(UsagePage usagePage, UsageId usageId, DeviceFlags flags) { RegisterDevice(usagePage, usageId, flags, IntPtr.Zero); } /// /// Registers the devices that supply the raw input data. /// /// The usage page. /// The usage id. /// The flags. /// The target. /// The options. public static void RegisterDevice(UsagePage usagePage, UsageId usageId, DeviceFlags flags, IntPtr target, RegisterDeviceOptions options = RegisterDeviceOptions.Default) { var rawInputDevices = new RawInputDevice[1]; rawInputDevices[0].UsagePage = (short)usagePage; rawInputDevices[0].Usage = (short)usageId; rawInputDevices[0].Flags = (int)flags; rawInputDevices[0].Target = target; // Register this device RawInputFunctions.RegisterRawInputDevices(rawInputDevices, 1, Utilities.SizeOf()); if (options != RegisterDeviceOptions.NoFiltering && rawInputMessageFilter == null) { rawInputMessageFilter = new RawInputMessageFilter(); if (options == RegisterDeviceOptions.Default) { Application.AddMessageFilter(rawInputMessageFilter); } else { MessageFilterHook.AddMessageFilter(target, rawInputMessageFilter); } } } /// /// Handles a RawInput message manually. /// /// A pointer to a RawInput message. /// The handle of the window that received the RawInput message. /// /// This method can be used directly when handling RawInput messages from non-WinForms application. /// public static void HandleMessage(IntPtr rawInputMessagePointer, IntPtr hwnd) { unsafe { // Get the size of the RawInput structure int sizeOfRawInputData = 0; RawInputFunctions.GetRawInputData(rawInputMessagePointer, RawInputDataType.Input, IntPtr.Zero, ref sizeOfRawInputData, Utilities.SizeOf()); if (sizeOfRawInputData == 0) return; // Get the RawInput data structure var rawInputDataPtr = stackalloc byte[sizeOfRawInputData]; RawInputFunctions.GetRawInputData(rawInputMessagePointer, RawInputDataType.Input, (IntPtr)rawInputDataPtr, ref sizeOfRawInputData, Utilities.SizeOf()); var rawInput = (RawInput*)rawInputDataPtr; switch (rawInput->Header.Type) { case DeviceType.HumanInputDevice: if (RawInput != null) RawInput(null, new HidInputEventArgs(ref *rawInput, hwnd)); break; case DeviceType.Keyboard: if (KeyboardInput != null) KeyboardInput(null, new KeyboardInputEventArgs(ref *rawInput, hwnd)); break; case DeviceType.Mouse: if (MouseInput != null) MouseInput(null, new MouseInputEventArgs(ref *rawInput, hwnd)); break; } } } /// /// Internal RawInput message filtering /// internal class RawInputMessageFilter : IMessageFilter { /// /// WM_INPUT /// private const int WmInput = 0x00FF; public virtual bool PreFilterMessage(ref Message m) { // Handle only WM_INPUT messages if (m.Msg == WmInput) HandleMessage(m.LParam, m.HWnd); return false; } } } }