예제 #1
0
        /// <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;
        }
예제 #2
0
        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());
        }
예제 #3
0
        /// <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());
                }
            }
        }
예제 #4
0
        /// <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;
        }
예제 #5
0
        public static List <Device> GetDevices()
        {
            var devices = RawInputHelper.GetDevices();

            return(devices);
        }
예제 #6
0
 public HidDataReader(Window window) : this(window, RawInputHelper.GetDevices())
 {
 }