mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-12-14 06:01:09 +00:00
906102c3b6
https://developer.apple.com/library/mac/samplecode/HID_Utilities/Introduction/Intro.html https://developer.apple.com/library/mac/samplecode/HID_Utilities/HID_Utilities.zip
354 lines
13 KiB
C
Executable file
354 lines
13 KiB
C
Executable file
// File: HID_Queue_Utilities.c
|
|
// Abstract: HID Queue Utilities.
|
|
// Version: 2.0
|
|
//
|
|
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
|
|
// Inc. ("Apple") in consideration of your agreement to the following
|
|
// terms, and your use, installation, modification or redistribution of
|
|
// this Apple software constitutes acceptance of these terms. If you do
|
|
// not agree with these terms, please do not use, install, modify or
|
|
// redistribute this Apple software.
|
|
//
|
|
// In consideration of your agreement to abide by the following terms, and
|
|
// subject to these terms, Apple grants you a personal, non-exclusive
|
|
// license, under Apple's copyrights in this original Apple software (the
|
|
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
|
// Software, with or without modifications, in source and/or binary forms;
|
|
// provided that if you redistribute the Apple Software in its entirety and
|
|
// without modifications, you must retain this notice and the following
|
|
// text and disclaimers in all such redistributions of the Apple Software.
|
|
// Neither the name, trademarks, service marks or logos of Apple Inc. may
|
|
// be used to endorse or promote products derived from the Apple Software
|
|
// without specific prior written permission from Apple. Except as
|
|
// expressly stated in this notice, no other rights or licenses, express or
|
|
// implied, are granted by Apple herein, including but not limited to any
|
|
// patent rights that may be infringed by your derivative works or by other
|
|
// works in which the Apple Software may be incorporated.
|
|
//
|
|
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE
|
|
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
|
|
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
|
|
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
|
|
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
|
//
|
|
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
|
|
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
|
|
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
|
|
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
|
|
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
|
//
|
|
//*****************************************************
|
|
#include "HID_Utilities_External.h"
|
|
|
|
// ==================================
|
|
// private functions
|
|
|
|
// creates a queue for a device, creates and opens device interface if required
|
|
static IOReturn HIDCreateQueue(IOHIDDeviceRef inIOHIDDeviceRef) {
|
|
IOReturn result = kIOReturnSuccess;
|
|
if ( inIOHIDDeviceRef ) {
|
|
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
|
|
|
// do we already have a queue?
|
|
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
|
if ( tIOHIDQueueRef ) { // (yes)
|
|
assert( IOHIDQueueGetTypeID() == CFGetTypeID(tIOHIDQueueRef) );
|
|
} else {
|
|
tIOHIDQueueRef = IOHIDQueueCreate(kCFAllocatorDefault, inIOHIDDeviceRef, kDeviceQueueSize, kIOHIDOptionsTypeNone);
|
|
if ( tIOHIDQueueRef ) { // did that work
|
|
IOHIDDevice_SetQueue(inIOHIDDeviceRef, tIOHIDQueueRef);
|
|
result = kIOReturnSuccess;
|
|
} else {
|
|
HIDReportErrorNum("Failed to create queue via create", result);
|
|
}
|
|
}
|
|
} else {
|
|
HIDReportErrorNum("HID device ref does not exist for queue creation", result);
|
|
}
|
|
|
|
return (result);
|
|
} /* HIDCreateQueue */
|
|
|
|
// ---------------------------------
|
|
// returns true if queue is empty false otherwise
|
|
// error if no device, empty if no queue
|
|
static unsigned char HIDIsDeviceQueueEmpty(IOHIDDeviceRef inIOHIDDeviceRef) {
|
|
if ( inIOHIDDeviceRef ) { // need device and queue
|
|
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
|
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
|
if ( tIOHIDQueueRef ) {
|
|
IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO);
|
|
|
|
while ( tIOHIDElementRef ) {
|
|
if ( IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) {
|
|
return (false);
|
|
}
|
|
|
|
tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO);
|
|
}
|
|
} else {
|
|
HIDReportError("NULL device passed to HIDIsDeviceQueueEmpty.");
|
|
}
|
|
} else {
|
|
HIDReportError("NULL device passed to HIDIsDeviceQueueEmpty.");
|
|
}
|
|
|
|
return (true);
|
|
} /* HIDIsDeviceQueueEmpty */
|
|
|
|
// ---------------------------------
|
|
|
|
// disposes and releases queue, sets queue to NULL,.
|
|
// Note: will have no effect if device or queue do not exist
|
|
static IOReturn HIDDisposeReleaseQueue(IOHIDDeviceRef inIOHIDDeviceRef) {
|
|
IOReturn result = kIOReturnSuccess;
|
|
if ( inIOHIDDeviceRef ) {
|
|
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
|
if ( tIOHIDQueueRef ) {
|
|
// stop queue
|
|
IOHIDQueueStop(tIOHIDQueueRef);
|
|
|
|
// release the queue
|
|
CFRelease(tIOHIDQueueRef);
|
|
}
|
|
} else {
|
|
HIDReportError("NULL device passed to HIDDisposeReleaseQueue.");
|
|
}
|
|
|
|
return (result);
|
|
} /* HIDDisposeReleaseQueue */
|
|
|
|
// ==================================
|
|
// public functions
|
|
// ----------------------------------
|
|
|
|
// queues specific element, performing any device queue set up required
|
|
// queue is started and ready to return events on exit from this function
|
|
int HIDQueueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) {
|
|
IOReturn result = kIOReturnSuccess;
|
|
if ( inIOHIDDeviceRef ) {
|
|
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
|
if ( inIOHIDElementRef ) {
|
|
assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) );
|
|
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
|
if ( !tIOHIDQueueRef ) { // if no queue create queue
|
|
result = HIDCreateQueue(inIOHIDDeviceRef);
|
|
if ( kIOReturnSuccess == result ) {
|
|
tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
|
}
|
|
}
|
|
if ( tIOHIDQueueRef ) {
|
|
// stop queue
|
|
IOHIDQueueStop(tIOHIDQueueRef);
|
|
// queue element
|
|
if ( !IOHIDQueueContainsElement(tIOHIDQueueRef, inIOHIDElementRef) ) {
|
|
IOHIDQueueAddElement(tIOHIDQueueRef, inIOHIDElementRef);
|
|
}
|
|
|
|
// restart queue
|
|
IOHIDQueueStart(tIOHIDQueueRef);
|
|
} else {
|
|
HIDReportError("No queue for device passed to HIDQueueElement.");
|
|
if ( kIOReturnSuccess == result ) {
|
|
result = kIOReturnError;
|
|
}
|
|
}
|
|
} else {
|
|
HIDReportError("NULL element passed to HIDQueueElement.");
|
|
result = kIOReturnBadArgument;
|
|
}
|
|
} else {
|
|
HIDReportError("NULL device passed to HIDQueueElement.");
|
|
result = kIOReturnBadArgument;
|
|
}
|
|
|
|
return (result);
|
|
} /* HIDQueueElement */
|
|
// ---------------------------------
|
|
|
|
// adds all elements to queue, performing any device queue set up required
|
|
// queue is started and ready to return events on exit from this function
|
|
int HIDQueueDevice(IOHIDDeviceRef inIOHIDDeviceRef) {
|
|
IOReturn result = kIOReturnSuccess;
|
|
// error checking
|
|
if ( !inIOHIDDeviceRef ) {
|
|
HIDReportError("Device does not exist, cannot queue device.");
|
|
return (kIOReturnBadArgument);
|
|
}
|
|
if ( !inIOHIDDeviceRef ) { // must have interface
|
|
HIDReportError("Device does not have hid device ref, cannot queue device.");
|
|
return (kIOReturnError);
|
|
}
|
|
|
|
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
|
if ( !tIOHIDQueueRef ) { // if no queue create queue
|
|
result = HIDCreateQueue(inIOHIDDeviceRef);
|
|
if ( kIOReturnSuccess == result ) {
|
|
tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
|
}
|
|
}
|
|
if ( (kIOReturnSuccess != result) || (!tIOHIDQueueRef) ) {
|
|
HIDReportErrorNum("Could not queue device due to problem creating queue.", result);
|
|
if ( kIOReturnSuccess != result ) {
|
|
return (result);
|
|
} else {
|
|
return (kIOReturnError);
|
|
}
|
|
}
|
|
|
|
// stop queue
|
|
IOHIDQueueStop(tIOHIDQueueRef);
|
|
|
|
// queue element
|
|
IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO);
|
|
|
|
while ( tIOHIDElementRef ) {
|
|
if ( !IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) {
|
|
IOHIDQueueAddElement(tIOHIDQueueRef, tIOHIDElementRef);
|
|
}
|
|
|
|
tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO);
|
|
}
|
|
|
|
// restart queue
|
|
IOHIDQueueStart(tIOHIDQueueRef);
|
|
|
|
return (result);
|
|
} /* HIDQueueDevice */
|
|
|
|
// ---------------------------------
|
|
// removes element for queue, if last element in queue will release queue and closes device interface
|
|
int HIDDequeueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) {
|
|
IOReturn result = kIOReturnSuccess;
|
|
if ( inIOHIDDeviceRef ) {
|
|
assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) );
|
|
if ( inIOHIDElementRef ) {
|
|
assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) );
|
|
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
|
if ( tIOHIDQueueRef ) {
|
|
// stop queue
|
|
IOHIDQueueStop(tIOHIDQueueRef);
|
|
// de-queue element
|
|
if ( IOHIDQueueContainsElement(tIOHIDQueueRef, inIOHIDElementRef) ) {
|
|
IOHIDQueueRemoveElement(tIOHIDQueueRef, inIOHIDElementRef);
|
|
}
|
|
// release device queue and close interface if queue empty
|
|
if ( HIDIsDeviceQueueEmpty(inIOHIDDeviceRef) ) {
|
|
result = HIDDisposeReleaseQueue(inIOHIDDeviceRef);
|
|
if ( kIOReturnSuccess != result ) {
|
|
HIDReportErrorNum("Failed to dispose and release queue.", result);
|
|
}
|
|
} else { // not empty so restart queue
|
|
IOHIDQueueStart(tIOHIDQueueRef);
|
|
}
|
|
} else {
|
|
HIDReportError("No queue for device passed to HIDDequeueElement.");
|
|
if ( kIOReturnSuccess == result ) {
|
|
result = kIOReturnError;
|
|
}
|
|
}
|
|
} else {
|
|
HIDReportError("NULL element passed to HIDDequeueElement.");
|
|
result = kIOReturnBadArgument;
|
|
}
|
|
} else {
|
|
HIDReportError("NULL device passed to HIDDequeueElement.");
|
|
result = kIOReturnBadArgument;
|
|
}
|
|
|
|
return (result);
|
|
} /* HIDDequeueElement */
|
|
|
|
// ---------------------------------
|
|
// completely removes all elements from queue and releases queue and closes device interface
|
|
// does not release device interfaces, application must call ReleaseHIDDeviceList on exit
|
|
int HIDDequeueDevice(IOHIDDeviceRef inIOHIDDeviceRef) {
|
|
IOReturn result = kIOReturnSuccess;
|
|
// error checking
|
|
if ( !inIOHIDDeviceRef ) {
|
|
HIDReportError("Device does not exist, cannot queue device.");
|
|
return (kIOReturnBadArgument);
|
|
}
|
|
if ( !inIOHIDDeviceRef ) { // must have interface
|
|
HIDReportError("Device does not have hid device ref, cannot queue device.");
|
|
return (kIOReturnError);
|
|
}
|
|
|
|
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
|
if ( tIOHIDQueueRef ) {
|
|
// iterate through elements and if queued, remove
|
|
IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO);
|
|
|
|
while ( tIOHIDElementRef ) {
|
|
// de-queue element
|
|
if ( IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) {
|
|
IOHIDQueueRemoveElement(tIOHIDQueueRef, tIOHIDElementRef);
|
|
}
|
|
|
|
tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO);
|
|
}
|
|
|
|
// ensure queue is disposed and released
|
|
result = HIDDisposeReleaseQueue(inIOHIDDeviceRef);
|
|
if ( kIOReturnSuccess != result ) {
|
|
HIDReportErrorNum("Failed to dispose and release queue.", result);
|
|
}
|
|
} else {
|
|
HIDReportError("No queue for device passed to HIDDequeueElement.");
|
|
if ( kIOReturnSuccess == result ) {
|
|
result = kIOReturnError;
|
|
}
|
|
}
|
|
|
|
return (result);
|
|
} /* HIDDequeueDevice */
|
|
// ---------------------------------
|
|
|
|
// releases all device queues for quit or rebuild (must be called)
|
|
// does not release device interfaces, application must call ReleaseHIDDeviceList on exit
|
|
IOReturn HIDReleaseAllDeviceQueues(void) {
|
|
IOReturn result = kIOReturnSuccess;
|
|
IOHIDDeviceRef tIOHIDDeviceRef = HIDGetFirstDevice();
|
|
|
|
while ( tIOHIDDeviceRef ) {
|
|
result = HIDDequeueDevice(tIOHIDDeviceRef);
|
|
if ( kIOReturnSuccess != result ) {
|
|
HIDReportErrorNum("Could not dequeue device.", result);
|
|
}
|
|
|
|
tIOHIDDeviceRef = HIDGetNextDevice(tIOHIDDeviceRef);
|
|
}
|
|
|
|
return (result);
|
|
} /* HIDReleaseAllDeviceQueues */
|
|
|
|
// ---------------------------------
|
|
// Get the next event in the queue for a device
|
|
// elements or entire device should be queued prior to calling this with HIDQueueElement or HIDQueueDevice
|
|
// returns true if an event is avialable for the element and fills out *pHIDEvent structure, returns false otherwise
|
|
// Note: kIOReturnUnderrun returned from getNextEvent indicates an empty queue not an error condition
|
|
// Note: application should pass in a pointer to a IOHIDEventStruct cast to a void (for CFM compatibility)
|
|
unsigned char HIDGetEvent(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDValueRef *pIOHIDValueRef) {
|
|
if ( inIOHIDDeviceRef ) {
|
|
IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef);
|
|
if ( tIOHIDQueueRef ) {
|
|
if ( pIOHIDValueRef ) {
|
|
*pIOHIDValueRef = IOHIDQueueCopyNextValueWithTimeout(tIOHIDQueueRef, 0.0);
|
|
if ( *pIOHIDValueRef ) {
|
|
return (true);
|
|
}
|
|
}
|
|
} else {
|
|
HIDReportError("Could not get HID event, hid queue reference does not exist.");
|
|
}
|
|
} else {
|
|
HIDReportError("Could not get HID event, device does not exist.");
|
|
}
|
|
|
|
return (false); // did not get event
|
|
} /* HIDGetEvent */
|