Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>After reading this question a few times and thinking about it for a bit, I thought of another solution for emulating blocking read behavior, but using the HID manager instead of replacing it.</p> <p>A blocking read function can register an input callback for the device, register the device on the current run loop, and then block by calling CFRunLoopRun(). The input callback can then copy the report into a shared buffer and call CFRunLoopStop(), which causes CFRunLoopRun() to return, thereby unblocking read(). Then, read() can return the report to the caller.</p> <p>The first issue I can think of is the case where the device is already scheduled on a run loop. Scheduling and then unscheduling the device in the read function may have adverse affects. But that would only be a problem if the application is trying to use both synchronous and asynchronous calls on the same device.</p> <p>The second thing that comes to mind is the case where the calling code already has a run loop running (Cocoa and Qt apps for example). But, the documentation for CFRunLoopStop() seems to indicate that nested calls to CFRunLoopRun() are handled properly. So, it should be ok.</p> <p>Here's a bit of simplified code to go with that. I just implemented something similar in my <a href="http://github.com/bfoz/libhid" rel="nofollow">HID Library</a> and it seems to work, although I haven't tested it extensively.</p> <pre><code>/* An IN report callback that stops its run loop when called. This is purely for emulating blocking behavior in the read() method */ static void input_oneshot(void* context, IOReturn result, void* deviceRef, IOHIDReportType type, uint32_t reportID, uint8_t* report, CFIndex length) { buffer_type *const buffer = static_cast&lt;HID::buffer_type*&gt;(context); /* If the report is valid, copy it into the caller's buffer The Report ID is prepended to the buffer so the caller can identify the report */ if( buffer ) { buffer-&gt;clear(); // Return an empty buffer on error if( !result &amp;&amp; report &amp;&amp; deviceRef ) { buffer-&gt;reserve(length+1); buffer-&gt;push_back(reportID); buffer-&gt;insert(buffer-&gt;end(), report, report+length); } } CFRunLoopStop(CFRunLoopGetCurrent()); } // Block while waiting for an IN interrupt report bool read(buffer_type&amp; buffer) { uint8_t _bufferInput[_lengthInputBuffer]; // Register a callback IOHIDDeviceRegisterInputReportCallback(deviceRef, _bufferInput, _lengthInputBuffer, input_oneshot, &amp;buffer); // Schedule the device on the current run loop IOHIDDeviceScheduleWithRunLoop(deviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); // Trap in the run loop until a report is received CFRunLoopRun(); // The run loop has returned, so unschedule the device IOHIDDeviceUnscheduleFromRunLoop(deviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); if( buffer.size() ) return true; return false; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload