internal KeyboardDeviceInfo(IntPtr handle, string name, KeyboardDeviceType type, string description)
 {
     Handle      = handle;
     Name        = name;
     Type        = type;
     Description = description;
 }
        /// <summary>
        /// Gets the list of all keyboard devices.
        /// </summary>
        /// <returns>List of all keyboard devices</returns>
        public static IEnumerable <KeyboardDeviceInfo> Get()
        {
            lock (singleThreadLock)
            {
                uint deviceCount = 0;
                if (GetRawInputDeviceList(IntPtr.Zero, ref deviceCount, (uint)inputDeviceElementSize) == 0)
                {
                    var pRawInputDeviceList = Marshal.AllocHGlobal((int)(inputDeviceElementSize * deviceCount));
                    GetRawInputDeviceList(pRawInputDeviceList, ref deviceCount, (uint)inputDeviceElementSize);

                    for (var i = 0; i < deviceCount; i++)
                    {
                        uint pcbSize = 0;

                        // On Window 8 64bit when compiling against .Net > 3.5 using .ToInt32 you will generate an arithmetic overflow. Leave as it is for 32bit/64bit applications
                        var inputDevice = (InputDevice)Marshal.PtrToStructure(new IntPtr((pRawInputDeviceList.ToInt64() + (inputDeviceElementSize * i))), typeof(InputDevice));

                        GetRawInputDeviceInfo(inputDevice.Handle, 0x20000007 /*RIDI_DEVICENAME*/, IntPtr.Zero, ref pcbSize);

                        if (pcbSize <= 0)
                        {
                            continue;
                        }

                        IntPtr             pData      = IntPtr.Zero;
                        KeyboardDeviceType deviceType = KeyboardDeviceType.Other;
                        if (inputDevice.Type == 1)
                        {
                            deviceType = KeyboardDeviceType.Keyboard;
                        }
                        else if (inputDevice.Type == 2)
                        {
                            deviceType = KeyboardDeviceType.Hid;
                        }

                        try
                        {
                            pData = Marshal.AllocHGlobal((int)pcbSize);
                            GetRawInputDeviceInfo(inputDevice.Handle, 0x20000007 /*RIDI_DEVICENAME*/, pData, ref pcbSize);
                            var deviceName = Marshal.PtrToStringAnsi(pData);

                            if (deviceType != KeyboardDeviceType.Other)
                            {
                                var name        = Marshal.PtrToStringAnsi(pData);
                                var description = GetDeviceDescription(deviceName);

                                var device = new KeyboardDeviceInfo(inputDevice.Handle, name, deviceType, description);

                                yield return(device);
                            }
                        }
                        finally
                        {
                            if (pData != IntPtr.Zero)
                            {
                                Marshal.FreeHGlobal(pData);
                            }
                        }
                    }
                }
            }
        }
 public KeyboardDeviceInfo(string friendlyName, string deviceName, KeyboardDeviceType deviceType)
 {
     this.FriendlyName = friendlyName ?? throw new ArgumentNullException(nameof(friendlyName));
     this.DeviceName   = deviceName ?? throw new ArgumentNullException(nameof(deviceName));
     this.DeviceType   = deviceType;
 }