Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to know when a HID USB/Bluetooth device is connected in Cocoa?

How can I get a simple call back when a HID device, or at last, any USB/Bluetooth device gets connected/disconnected?

I made a simple app that shows the connected joysticks and the pressed buttons/axis for mac in a pretty way. Since I am not very familiar with cocoa yet, I made the UI using a webview, and used the SDL Joystick library. Everything is working nice, the only problem is that the user needs to scan for new joysticks manually if he/she connects/disconnects something while the program is running.

With a callback, I I can just call the Scan function. I don't want to handle the device or do something fancy, just know when there is something new happening...

Thanks.

like image 370
Rodrigo Avatar asked Dec 12 '22 03:12

Rodrigo


2 Answers

Take a look at IOServiceAddMatchingNotification() and related functions. I've only worked with it in the context of serial ports (which are in fact USB to serial adapters, though that doesn't matter), but it should be applicable to any IOKit accessible device. I'm not sure about Bluetooth, but it should at least work for USB devices. Here's a snippet of code I use:

IONotificationPortRef notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
CFRunLoopAddSource(CFRunLoopGetCurrent(), 
               IONotificationPortGetRunLoopSource(notificationPort), 
               kCFRunLoopDefaultMode);

CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOSerialBSDServiceValue);
CFRetain(matchingDict); // Need to use it twice and IOServiceAddMatchingNotification() consumes a reference

CFDictionaryAddValue(matchingDict, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDRS232Type));

io_iterator_t portIterator = 0;
// Register for notifications when a serial port is added to the system
kern_return_t result = IOServiceAddMatchingNotification(notificationPort,
                                                        kIOPublishNotification,
                                                        matchingDictort,
                                                        SerialDeviceWasAddedFunction,
                                                        self,           
                                                        &portIterator);
io_object_t d;
// Run out the iterator or notifications won't start (you can also use it to iterate the available devices).
while ((d = IOIteratorNext(iterator))) { IOObjectRelease(d); }

// Also register for removal notifications
IONotificationPortRef terminationNotificationPort = IONotificationPortCreate(kIOMasterPortDefault);
CFRunLoopAddSource(CFRunLoopGetCurrent(),
                   IONotificationPortGetRunLoopSource(terminationNotificationPort),
                   kCFRunLoopDefaultMode);
result = IOServiceAddMatchingNotification(terminationNotificationPort,
                                          kIOTerminatedNotification,
                                          matchingDict,
                                          SerialPortWasRemovedFunction,
                                          self,         // refCon/contextInfo
                                          &portIterator);

io_object_t d;
// Run out the iterator or notifications won't start (you can also use it to iterate the available devices).
while ((d = IOIteratorNext(iterator))) { IOObjectRelease(d); }

My SerialPortDeviceWasAddedFunction() and SerialPortWasRemovedFunction() are called when a serial port becomes available on the system or is removed, respectively.

Relevant documentation is here, particularly under the heading Getting Notifications of Device Arrival and Departure.

like image 64
Andrew Madsen Avatar answered Jan 19 '23 00:01

Andrew Madsen


Use IOHIDManager to get the notifications.

like image 32
Arjuna Avatar answered Jan 19 '23 01:01

Arjuna