internal MacHidStream(MacHidDevice device)
     : base(device)
 {
     _inputQueue  = new Queue <byte[]>();
     _outputQueue = new Queue <CommonOutputReport>();
     _readThread  = new Thread(ReadThread)
     {
         IsBackground = true, Name = "HID Reader"
     };
     _writeThread = new Thread(WriteThread)
     {
         IsBackground = true, Name = "HID Writer"
     };
 }
Beispiel #2
0
 protected override bool TryCreateHidDevice(object key, out Device device)
 {
     device = MacHidDevice.TryCreate((NativeMethods.io_string_t)key);
     return(device != null);
 }
        internal static MacHidDevice TryCreate(NativeMethods.io_string_t path)
        {
            var d = new MacHidDevice()
            {
                _path = path
            };

            var service = NativeMethods.IORegistryEntryFromPath(0, ref path).ToIOObject();

            if (!service.IsSet)
            {
                return(null);
            }

            using (service)
            {
                int?vid     = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDVendorIDKey);
                int?pid     = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDProductIDKey);
                int?version = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDVersionNumberKey);
                if (vid == null || pid == null || version == null)
                {
                    return(null);
                }

                // TODO: Craft the report descriptor from IOHIDElements so we can support it below OS X 10.8...
                //       Also, our report sizes aren't correct for the no-report-ID case without this...

                d._vid              = (int)vid;
                d._pid              = (int)pid;
                d._version          = (int)version;
                d._maxInput         = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDMaxInputReportSizeKey) ?? 0;
                d._maxOutput        = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDMaxOutputReportSizeKey) ?? 0;
                d._maxFeature       = NativeMethods.IORegistryEntryGetCFProperty_Int(service, NativeMethods.kIOHIDMaxFeatureReportSizeKey) ?? 0;
                d._manufacturer     = NativeMethods.IORegistryEntryGetCFProperty_String(service, NativeMethods.kIOHIDManufacturerKey);
                d._productName      = NativeMethods.IORegistryEntryGetCFProperty_String(service, NativeMethods.kIOHIDProductKey);
                d._serialNumber     = NativeMethods.IORegistryEntryGetCFProperty_String(service, NativeMethods.kIOHIDSerialNumberKey);
                d._reportDescriptor = NativeMethods.IORegistryEntryGetCFProperty_Data(service, NativeMethods.kIOHIDReportDescriptorKey);
                if (d._maxInput == 0 && d._maxOutput == 0 && d._maxFeature == 0)
                {
                    return(null);
                }

                // Does this device use Report IDs? Let's find out.
                d._reportsUseID = false; bool hasInput = false, hasOutput = false, hasFeature = false;
                using (var device = NativeMethods.IOHIDDeviceCreate(IntPtr.Zero, service).ToCFType())
                {
                    if (!device.IsSet)
                    {
                        return(null);
                    }

                    using (var elementArray = NativeMethods.IOHIDDeviceCopyMatchingElements(device, IntPtr.Zero).ToCFType())
                    {
                        if (!elementArray.IsSet)
                        {
                            return(null);
                        }

                        int elementCount = checked ((int)NativeMethods.CFArrayGetCount(elementArray));
                        for (int elementIndex = 0; elementIndex < elementCount; elementIndex++)
                        {
                            var element = NativeMethods.CFArrayGetValueAtIndex(elementArray, (IntPtr)elementIndex);
                            if (element == IntPtr.Zero)
                            {
                                continue;
                            }

                            var elementType = NativeMethods.IOHIDElementGetType(element);
                            switch (elementType)
                            {
                            case NativeMethods.IOHIDElementType.InputMisc:
                            case NativeMethods.IOHIDElementType.InputButton:
                            case NativeMethods.IOHIDElementType.InputAxis:
                            case NativeMethods.IOHIDElementType.InputScanCodes:
                                hasInput = true; break;

                            case NativeMethods.IOHIDElementType.Output:
                                hasOutput = true; break;

                            case NativeMethods.IOHIDElementType.Feature:
                                hasFeature = true; break;
                            }

                            if (NativeMethods.IOHIDElementGetReportID(element) != 0)
                            {
                                d._reportsUseID = true;
                            }
                        }
                    }
                }

                if (!d._reportsUseID)
                {
                    // It does not use Report IDs. MacOS's maximums do not include said Report ID.
                    if (d._maxInput != 0)
                    {
                        d._maxInput++;
                    }
                    if (d._maxOutput != 0)
                    {
                        d._maxOutput++;
                    }
                    if (d._maxFeature != 0)
                    {
                        d._maxFeature++;
                    }
                }

                if (!hasInput)
                {
                    d._maxInput = 0;
                }
                if (!hasOutput)
                {
                    d._maxOutput = 0;
                }
                if (!hasFeature)
                {
                    d._maxFeature = 0;
                }
            }

            return(d);
        }