/// <summary> /// Creates new HID data reader. /// </summary> /// <param name="window">Window instance, which will reveice the WM_INPUT messages</param> public HidDataReader(Window window) { if (window == null) { throw new ArgumentNullException("window"); } this.window = window; this.window.Closed += this.OnWindowClosed; var handle = new WindowInteropHelper(this.window).Handle; var source = HwndSource.FromHwnd(handle); source.AddHook(this.WndProc); var devices = RawInputHelper.GetDevices(); int i = 0; RAWINPUTDEVICE[] rids = new RAWINPUTDEVICE[devices.Count]; // Setting handle to each rid device to receive the WM_INPUT message foreach (var device in devices) { rids[i].usUsagePage = device.UsagePage; rids[i].usUsage = device.UsageCollection; rids[i].dwFlags = RawInputDeviceFlags.RIDEV_INPUTSINK; rids[i].hwndTarget = handle; i++; } this.handler = new HidHandler(rids); this.handler.OnHidEvent += this.OnHidEvent; }
public static List <Device> GetDevices() { var treeview = new System.Windows.Forms.TreeView(); RawInputHelper.PopulateDeviceList(treeview); var devices = new Dictionary <uint, Device>(); foreach (System.Windows.Forms.TreeNode node in treeview.Nodes) { var dev = (Device)node.Tag; if (!devices.ContainsKey(dev.UsageId)) { devices.Add(dev.UsageId, dev); } } return(devices.Values.ToList()); }
/// <summary> /// Private constructor. /// </summary> /// <param name="handleToRawInputDevice"></param> private void Construct(IntPtr handleToRawInputDevice) { this.PreParsedData = IntPtr.Zero; this.inputButtonCapabilities = null; this.inputValueCapabilities = null; // Fetch various information defining the given HID device this.Name = RawInputHelper.GetDeviceName(handleToRawInputDevice); // Fetch device info this.info = new RID_DEVICE_INFO(); if (!RawInputHelper.GetDeviceInfo(handleToRawInputDevice, ref this.info)) { throw new Exception("HidDevice: GetDeviceInfo failed: " + Marshal.GetLastWin32Error().ToString()); } // Open our device from the device name/path var handle = Win32.Win32CreateFile.NativeMethods.CreateFile( this.Name, FileAccess.NONE, FileShare.FILE_SHARE_READ | FileShare.FILE_SHARE_WRITE, IntPtr.Zero, CreationDisposition.OPEN_EXISTING, FileFlagsAttributes.FILE_FLAG_OVERLAPPED, IntPtr.Zero); // Check if CreateFile worked if (handle.IsInvalid) { throw new Exception("HidDevice: CreateFile failed: " + Marshal.GetLastWin32Error().ToString()); } // Get manufacturer string var manufacturerString = new StringBuilder(256); if (Win32.Win32Hid.NativeMethods.HidD_GetManufacturerString(handle, manufacturerString, manufacturerString.Capacity)) { this.Manufacturer = manufacturerString.ToString(); } // Get product string StringBuilder productString = new StringBuilder(256); if (Win32.Win32Hid.NativeMethods.HidD_GetProductString(handle, productString, productString.Capacity)) { this.Product = productString.ToString(); } // Get attributes HIDD_ATTRIBUTES attributes = new HIDD_ATTRIBUTES(); if (Win32.Win32Hid.NativeMethods.HidD_GetAttributes(handle, ref attributes)) { this.VendorId = attributes.VendorID; this.ProductId = attributes.ProductID; this.Version = attributes.VersionNumber; } handle.Close(); this.SetFriendlyName(); // Get our HID descriptor pre-parsed data this.PreParsedData = RawInputHelper.GetPreParsedData(handleToRawInputDevice); if (this.PreParsedData == IntPtr.Zero) { // We are done then. Some devices don't have pre-parsed data. return; } // Get capabilities var status = Win32.Win32Hid.NativeMethods.HidP_GetCaps(this.PreParsedData, ref this.capabilities); if (status != HidStatus.HIDP_STATUS_SUCCESS) { throw new Exception("HidDevice: HidP_GetCaps failed: " + status.ToString()); } this.SetInputCapabilitiesDescription(); // Get input button caps if needed if (this.Capabilities.NumberInputButtonCaps > 0) { this.inputButtonCapabilities = new HIDP_BUTTON_CAPS[this.Capabilities.NumberInputButtonCaps]; ushort buttonCapabilitiesLength = this.Capabilities.NumberInputButtonCaps; status = Win32.Win32Hid.NativeMethods.HidP_GetButtonCaps(HIDP_REPORT_TYPE.HidP_Input, this.inputButtonCapabilities, ref buttonCapabilitiesLength, this.PreParsedData); if (status != HidStatus.HIDP_STATUS_SUCCESS || buttonCapabilitiesLength != this.Capabilities.NumberInputButtonCaps) { throw new Exception("HidDevice: HidP_GetButtonCaps failed: " + status.ToString()); } this.ComputeButtonCount(); } // Get input value caps if needed if (this.Capabilities.NumberInputValueCaps > 0) { this.inputValueCapabilities = new HIDP_VALUE_CAPS[this.Capabilities.NumberInputValueCaps]; ushort valueCapabilitiesLength = this.Capabilities.NumberInputValueCaps; status = Win32.Win32Hid.NativeMethods.HidP_GetValueCaps(HIDP_REPORT_TYPE.HidP_Input, this.inputValueCapabilities, ref valueCapabilitiesLength, this.PreParsedData); if (status != HidStatus.HIDP_STATUS_SUCCESS || valueCapabilitiesLength != this.Capabilities.NumberInputValueCaps) { throw new Exception("HidDevice: HidP_GetValueCaps failed: " + status.ToString()); } } }
/// <summary> /// Initialize an HidEvent from a WM_INPUT message /// </summary> /// <param name="message"></param> /// <param name="repeatDelegate"></param> /// <param name="repeat"></param> /// <param name="repeatDelayInMs"></param> /// <param name="repeatSpeedInMs"></param> internal HidEvent(Message message) { this.RepeatCount = 0; this.IsValid = false; this.IsKeyboard = false; this.IsGeneric = false; this.Time = DateTime.Now; this.OriginalTime = DateTime.Now; this.Buttons = new Dictionary <HIDP_BUTTON_CAPS, bool>(); this.UsageValues = new Dictionary <HIDP_VALUE_CAPS, uint>(); if (message.Msg != Contants.WM_INPUT) { // Has to be a WM_INPUT message return; } if (Helper.GET_RAWINPUT_CODE_WPARAM(message.WParam) == Contants.RIM_INPUT) { this.IsForeground = true; } else if (Helper.GET_RAWINPUT_CODE_WPARAM(message.WParam) == Contants.RIM_INPUTSINK) { this.IsForeground = false; } // Declare some pointers IntPtr rawInputBuffer = IntPtr.Zero; try { // Fetch raw input this.rawInput = new RAWINPUT(); if (!RawInputHelper.GetRawInputData(message.LParam, ref this.rawInput, ref rawInputBuffer)) { Debug.WriteLine("GetRawInputData failed!"); return; } // Our device can actually be null. This is notably happening for some keyboard events if (this.RawInput.header.hDevice != IntPtr.Zero) { this.Device = new Device(this.RawInput.header.hDevice); } if (this.RawInput.header.dwType == RawInputDeviceType.RIM_TYPEHID) { this.IsGeneric = true; Debug.WriteLine("WM_INPUT source device is HID."); // Get Usage Page and Usage this.UsagePage = this.Device.Info.hid.usUsagePage; this.UsageCollection = this.Device.Info.hid.usUsage; /* Make sure our HID msg size more than 1. * In fact the first ushort is irrelevant to us for now * Check that we have at least one HID msg */ if (!(this.RawInput.hid.dwSizeHid > 1 && this.RawInput.hid.dwCount > 0)) { return; } // Allocate a buffer for one HID input this.InputReport = new byte[this.RawInput.hid.dwSizeHid]; Debug.WriteLine("Raw input contains " + this.RawInput.hid.dwCount + " HID input report(s)"); // For each HID input report in our raw input for (int i = 0; i < this.RawInput.hid.dwCount; i++) { // Compute the address from which to copy our HID input int hidInputOffset = 0; unsafe { byte *source = (byte *)rawInputBuffer; source += sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + (this.RawInput.hid.dwSizeHid * i); hidInputOffset = (int)source; } // Copy HID input into our buffer Marshal.Copy(new IntPtr(hidInputOffset), this.InputReport, 0, (int)this.RawInput.hid.dwSizeHid); this.ProcessInputReport(this.InputReport); } } else if (this.RawInput.header.dwType == RawInputDeviceType.RIM_TYPEMOUSE) { this.IsMouse = true; this.UsagePage = (ushort)Hid.UsagePage.GenericDesktopControls; this.UsageCollection = (ushort)Hid.UsageCollection.GenericDesktop.Mouse; Debug.WriteLine("WM_INPUT source device is Mouse."); } else if (this.RawInput.header.dwType == RawInputDeviceType.RIM_TYPEKEYBOARD) { this.IsKeyboard = true; this.UsagePage = (ushort)Hid.UsagePage.GenericDesktopControls; this.UsageCollection = (ushort)Hid.UsageCollection.GenericDesktop.Keyboard; // Precise ALT key - work out if we are left or right ALT if (this.rawInput.keyboard.VKey == (ushort)Keys.Menu) { if (this.RawInput.keyboard.Flags.HasFlag(RawInputKeyFlags.RI_KEY_E0)) { this.rawInput.keyboard.VKey = (ushort)Keys.RMenu; } else { this.rawInput.keyboard.VKey = (ushort)Keys.LMenu; } } // Precise CTRL key - work out if we are left or right CTRL if (this.rawInput.keyboard.VKey == (ushort)Keys.ControlKey) { if (this.RawInput.keyboard.Flags.HasFlag(RawInputKeyFlags.RI_KEY_E0)) { this.rawInput.keyboard.VKey = (ushort)Keys.RControlKey; } else { this.rawInput.keyboard.VKey = (ushort)Keys.LControlKey; } } // Precise SHIFT key - work out if we are left or right SHIFT if (this.rawInput.keyboard.VKey == (ushort)Keys.ShiftKey) { if (this.RawInput.keyboard.MakeCode == 0x0036) { this.rawInput.keyboard.VKey = (ushort)Keys.RShiftKey; } else { Debug.Assert(this.RawInput.keyboard.MakeCode == 0x002A, "Keyboard make code is different from 0x002A"); this.rawInput.keyboard.VKey = (ushort)Keys.LShiftKey; } } Debug.WriteLine("WM_INPUT source device is Keyboard."); // Do keyboard handling... if (this.Device != null) { Debug.WriteLine("Type: " + this.Device.Info.keyboard.dwType.ToString()); Debug.WriteLine("SubType: " + this.Device.Info.keyboard.dwSubType.ToString()); Debug.WriteLine("Mode: " + this.Device.Info.keyboard.dwKeyboardMode.ToString()); Debug.WriteLine("Number of function keys: " + this.Device.Info.keyboard.dwNumberOfFunctionKeys.ToString()); Debug.WriteLine("Number of indicators: " + this.Device.Info.keyboard.dwNumberOfIndicators.ToString()); Debug.WriteLine("Number of keys total: " + this.Device.Info.keyboard.dwNumberOfKeysTotal.ToString()); } } } finally { // Always executed when leaving our try block Marshal.FreeHGlobal(rawInputBuffer); } this.IsValid = true; }
public static List <Device> GetDevices() { var devices = RawInputHelper.GetDevices(); return(devices); }
public HidDataReader(Window window) : this(window, RawInputHelper.GetDevices()) { }