Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
HID_Manager_Test.c
/* |
File: HID Manager Test.c |
Contains: Basic HID Manager Test Code |
DRI: George Warner |
Copyright: Copyright © 2002 Apple Computer, Inc., All Rights Reserved |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, 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 Computer, 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. |
*/ |
// system includes ---------------------------------------------------------- |
#ifndef __APPLE_CC__ |
#include "Carbon_Include.h" |
#endif |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <ctype.h> |
#include <sys/errno.h> |
#include <sysexits.h> |
#include <mach/mach.h> |
#include <mach/mach_error.h> |
#include <IOKit/IOKitLib.h> |
#include <IOKit/IOCFPlugIn.h> |
#include <IOKit/hid/IOHIDLib.h> |
#include <IOKit/hid/IOHIDUsageTables.h> |
#include <IOKit/usb/USB.h> |
#include <CoreFoundation/CoreFoundation.h> |
#include <Carbon/Carbon.h> |
// project includes --------------------------------------------------------- |
#include "HID_Manager_Test.h" |
// prototypes --------------------------------------------------------------- |
void PrintErrMsgIfIOErr (long expr, char * msg); |
void PrintErrMsgIfErr (long expr, char * msg); |
static CFMutableDictionaryRef MySetUpHIDMatchingDictionary (UInt32 usagePage, UInt32 usage); |
static io_iterator_t MyFindHIDDevices (const mach_port_t masterPort, UInt32 usagePage, UInt32 usage); |
static void MyIncrementElementIndex(CFIndex increment); |
static void MyIndent (); |
static void MyStartBlock (Boolean printIndex); |
static void MyEndBlock (); |
static CFIndex MyGetElementIndex (); |
static void MySetElementIndex (CFIndex newIndex); |
static void MyCFArrayShow(CFArrayRef object); |
static void MyCFArrayShowApplier (const void * value, void * parameter); |
static void MyCFBooleanShow(CFBooleanRef object); |
static void MyStoreImportantCookies (CFDictionaryRef element); |
static void MyShowTypeElement (CFDictionaryRef dictionary); |
static void MyShowUsageAndPageElement (CFDictionaryRef dictionary); |
static void MyCFDictionaryShow(CFDictionaryRef object); |
static void MyCFNumberShow (CFNumberRef object); |
static void MyCFStringShow(CFStringRef object); |
static void MyCFObjectShow(CFTypeRef object); |
static void MyShowProperty(const void * key, const void * value); |
static Boolean MyShowDictionaryElement (CFDictionaryRef dictionary, CFStringRef key); |
static void MyShowHIDProperties (io_registry_entry_t hidDevice); |
static IOHIDDeviceInterface ** MyCreateHIDDeviceInterface (io_object_t hidDevice); |
static void MyTestEventInterface (IOHIDDeviceInterface **hidDeviceInterface); |
static void MyTestPollingInterface (IOHIDDeviceInterface ** hidDeviceInterface); |
// statics/globals (internal only) ------------------------------------------ |
static CFIndex gNestingLevel = 0; |
static CFIndex gElementIndex = 0; |
static IOHIDElementCookie gXAxisCookie = 0; |
static IOHIDElementCookie gButton1Cookie = 0; |
static IOHIDElementCookie gButton2Cookie = 0; |
static IOHIDElementCookie gButton3Cookie = 0; |
// functions (internal/private) --------------------------------------------- |
void PrintErrMsgIfIOErr (long expr, char * msg) |
{ |
IOReturn err = (expr); |
if (err != kIOReturnSuccess) |
{ |
fprintf (stderr, "%s - %s(%x,%d)\n", |
msg, mach_error_string (err), err, err & 0xffffff); |
fflush(stderr); |
DebugStr ("\pExecution Halted"); |
} |
} |
// -------------------------------------------------------------------------- |
void PrintErrMsg (char * msg) |
{ |
fprintf (stderr, "%s\n", msg); |
fflush (stderr); |
DebugStr ("\pExecution Halted"); |
} |
// -------------------------------------------------------------------------- |
static CFMutableDictionaryRef MySetUpHIDMatchingDictionary (UInt32 usagePage, UInt32 usage) |
{ |
CFNumberRef refUsage = NULL, refUsagePage = NULL; |
CFMutableDictionaryRef refHIDMatchDictionary = NULL; |
// Set up a matching dictionary to search I/O Registry by class name for all HID class devices. |
refHIDMatchDictionary = IOServiceMatching (kIOHIDDeviceKey); |
if (refHIDMatchDictionary != NULL) |
{ |
// Add key for device type (joystick, in this case) to refine the matching dictionary. |
refUsagePage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usagePage); |
refUsage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usage); |
CFDictionarySetValue (refHIDMatchDictionary, CFSTR (kIOHIDPrimaryUsagePageKey), refUsagePage); |
CFDictionarySetValue (refHIDMatchDictionary, CFSTR (kIOHIDPrimaryUsageKey), refUsage); |
} |
else |
PrintErrMsg ("Failed to get HID CFMutableDictionaryRef via IOServiceMatching."); |
return refHIDMatchDictionary; |
} |
// -------------------------------------------------------------------------- |
static io_iterator_t MyFindHIDDevices (const mach_port_t masterPort, UInt32 usagePage, UInt32 usage) |
{ |
CFMutableDictionaryRef hidMatchDictionary = NULL; |
IOReturn ioReturnValue = kIOReturnSuccess; |
io_iterator_t hidObjectIterator; |
// Set up matching dictionary to search the I/O Registry for HID devices we are interested in. Dictionary reference is NULL if error. |
hidMatchDictionary = MySetUpHIDMatchingDictionary (usagePage, usage); |
if (NULL == hidMatchDictionary) |
PrintErrMsg ("CouldnÕt create a matching dictionary."); |
// Now search I/O Registry for matching devices. |
ioReturnValue = IOServiceGetMatchingServices (masterPort, hidMatchDictionary, &hidObjectIterator); |
// If error, print message and hang (for debugging purposes). |
if ((ioReturnValue != kIOReturnSuccess) | (hidObjectIterator == NULL)) |
PrintErrMsg ("CouldnÕt create a HID object iterator."); |
// IOServiceGetMatchingServices consumes a reference to the dictionary, so we don't need to release the dictionary ref. |
hidMatchDictionary = NULL; |
return hidObjectIterator; |
} |
// -------------------------------------------------------------------------- |
static void MyIncrementElementIndex(CFIndex increment) |
{ |
gElementIndex += increment; |
} |
// -------------------------------------------------------------------------- |
static void MyIndent () |
{ |
int i; |
printf("\n"); |
for (i = 0; i < gNestingLevel; i++) |
printf (" "); |
} |
// -------------------------------------------------------------------------- |
static void MyStartBlock (Boolean printIndex) |
{ |
if (printIndex) |
{ |
MyIndent (); |
printf ("[%ld]", MyGetElementIndex()); |
} |
gNestingLevel++; |
} |
// -------------------------------------------------------------------------- |
static void MyEndBlock () |
{ |
gNestingLevel--; |
} |
// -------------------------------------------------------------------------- |
static CFIndex MyGetElementIndex () |
{ |
return gElementIndex; |
} |
// -------------------------------------------------------------------------- |
static void MySetElementIndex (CFIndex newIndex) |
{ |
gElementIndex = newIndex; |
} |
// -------------------------------------------------------------------------- |
static void MyCFArrayShow(CFArrayRef object) |
{ |
CFRange range = {0, CFArrayGetCount (object)}; |
CFIndex savedIndex = MyGetElementIndex (); |
//Show an element array containing one or more element dictionaries |
MySetElementIndex (0); //Reset index to zero |
MyStartBlock (FALSE); |
CFArrayApplyFunction (object, range, MyCFArrayShowApplier, 0); |
MyEndBlock (); |
MySetElementIndex (savedIndex); //Restore original index |
} |
// -------------------------------------------------------------------------- |
static void MyCFArrayShowApplier (const void * value, void * parameter) |
{ |
if (CFGetTypeID (value) != CFDictionaryGetTypeID ()) |
return; |
MyCFObjectShow(value); |
} |
// -------------------------------------------------------------------------- |
static void MyCFBooleanShow(CFBooleanRef object) |
{ |
printf(CFBooleanGetValue(object) ? "true" : "false"); |
} |
// -------------------------------------------------------------------------- |
static void MyStoreImportantCookies (CFDictionaryRef element) |
{ |
CFTypeRef object; |
long number; |
IOHIDElementCookie cookie; |
long usage; |
long usagePage; |
//Get cookie |
object = CFDictionaryGetValue (element, CFSTR(kIOHIDElementCookieKey)); |
if (object == 0 || CFGetTypeID (object) != CFNumberGetTypeID ()) |
return; |
if(!CFNumberGetValue ((CFNumberRef) object, kCFNumberLongType, &number)) |
return; |
cookie = (IOHIDElementCookie) number; |
//Get usage |
object = CFDictionaryGetValue (element, CFSTR(kIOHIDElementUsageKey)); |
if (object == 0 || CFGetTypeID (object) != CFNumberGetTypeID ()) |
return; |
if (!CFNumberGetValue ((CFNumberRef) object, kCFNumberLongType, &number)) |
return; |
usage = number; |
//Get usage page |
object = CFDictionaryGetValue (element,CFSTR(kIOHIDElementUsagePageKey)); |
if (object == 0 || CFGetTypeID (object) != CFNumberGetTypeID ()) |
return; |
if (!CFNumberGetValue ((CFNumberRef) object, kCFNumberLongType, &number)) |
return; |
usagePage = number; |
//Check for x axis |
if (usage == kHIDUsage_GD_X && usagePage == kHIDPage_GenericDesktop) |
gXAxisCookie = cookie; |
//Check for buttons |
else if (usage == kHIDUsage_Button_1 && usagePage == kHIDPage_Button) |
gButton1Cookie = cookie; |
else if (usage == kHIDUsage_Button_2 && usagePage == kHIDPage_Button) |
gButton2Cookie = cookie; |
else if (usage == kHIDUsage_Button_3 && usagePage == kHIDPage_Button) |
gButton3Cookie = cookie; |
} |
// -------------------------------------------------------------------------- |
static void MyShowTypeElement (CFDictionaryRef dictionary) |
{ |
CFStringRef keyType = CFSTR(kIOHIDElementTypeKey); |
CFTypeRef objectType = CFDictionaryGetValue (dictionary, keyType); |
long valueType = 0; |
if (objectType) |
{ |
if (CFNumberGetValue (objectType, kCFNumberLongType, &valueType)) |
{ |
MyIndent (); |
switch (valueType) |
{ |
case kIOHIDElementTypeInput_Misc: |
printf("Miscellaneous Input Type (%ld), ", valueType); |
break; |
case kIOHIDElementTypeInput_Button: |
printf("Button Input Type (%ld), ", valueType); |
break; |
case kIOHIDElementTypeInput_Axis: |
printf("Axis Input Type (%ld), ", valueType); |
break; |
case kIOHIDElementTypeInput_ScanCodes: |
printf("Scan Code Input Type (%ld), ", valueType); |
break; |
case kIOHIDElementTypeOutput: |
printf("Output Type (%ld), ", valueType); |
break; |
case kIOHIDElementTypeFeature: |
printf("Feature Type (%ld), ", valueType); |
break; |
case kIOHIDElementTypeCollection: |
printf("Collection Type (%ld), ", valueType); |
break; |
} |
} |
} |
} |
// -------------------------------------------------------------------------- |
static void MyShowUsageAndPageElement (CFDictionaryRef dictionary) |
{ |
CFStringRef keyUsagePage = CFSTR(kIOHIDElementUsagePageKey); |
CFStringRef keyUsage = CFSTR(kIOHIDElementUsageKey); |
CFTypeRef objectUsagePage = CFDictionaryGetValue (dictionary, keyUsagePage); |
CFTypeRef objectUsage = CFDictionaryGetValue (dictionary, keyUsage); |
long valueUsage = 0, valueUsagePage = 0; |
if (objectUsagePage && objectUsage) |
{ |
if (CFNumberGetValue (objectUsage, kCFNumberLongType, &valueUsage) && CFNumberGetValue (objectUsagePage, kCFNumberLongType, &valueUsagePage)) |
{ |
MyIndent (); |
printf ("Usage: "); |
switch (valueUsagePage) |
{ |
case kHIDPage_Undefined: |
printf("Undefined Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: |
printf("Undefined Usage (0x%lx)", valueUsage); |
break; |
} |
break; |
case kHIDPage_GenericDesktop: |
printf("Generic Desktop (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
case kHIDUsage_GD_Pointer: printf("Pointer (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Mouse: printf("Mouse (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Joystick: printf("Joystick (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_GamePad: printf("GamePad (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Keyboard: printf("Keyboard (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Keypad: printf("Keypad (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_MultiAxisController: printf("Multi-Axis Controller (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_X: printf("X-Axis (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Y: printf("Y-Axis (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Z: printf("Z-Axis (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Rx: printf("X-Rotation (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Ry: printf("Y-Rotation (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Rz: printf("Z-Rotation (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Slider: printf("Slider (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Dial: printf("Dial (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Wheel: printf("Wheel (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Hatswitch: printf("Hatswitch (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_CountedBuffer: printf("Counted Buffer (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_ByteCount: printf("Byte Count (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_MotionWakeup: printf("Motion Wakeup (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Start: printf("Start (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Select: printf("Select (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Vx: printf("X-Velocity (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Vy: printf("Y-Velocity (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Vz: printf("Z-Velocity (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Vbrx: printf("X-Rotation Velocity (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Vbry: printf("Y-Rotation Velocity (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Vbrz: printf("Z-Rotation Velocity (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Vno: printf("Vno (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemControl: printf("System Control (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemPowerDown: printf("System Power Down (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemSleep: printf("System Sleep (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemWakeUp: printf("System Wake Up (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemContextMenu: printf("System Context Menu (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemMainMenu: printf("System Main Menu (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemAppMenu: printf("System App Menu (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemMenuHelp: printf("System Menu Help (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemMenuExit: printf("System Menu Exit (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemMenu: printf("System Menu (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemMenuRight: printf("System Menu Right (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemMenuLeft: printf("System Menu Left (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemMenuUp: printf("System Menu Up (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_SystemMenuDown: printf("System Menu Down (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_DPadUp: printf("DPad Up (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_DPadDown: printf("DPad Down (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_DPadRight: printf("DPad Right (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_DPadLeft: printf("DPad Left (0x%lx)", valueUsage); break; |
case kHIDUsage_GD_Reserved: printf("Reserved (0x%lx)", valueUsage); break; |
default: printf("Undefined Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_Simulation: |
printf("Simulation Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_VR: |
printf("VR Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_Sport: |
printf("Sport Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_Game: |
printf("Game Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_KeyboardOrKeypad: |
printf("Keyboard or Keypad Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_Button: |
printf("Button Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Button #%ld (0x%lx)", valueUsage, valueUsage); break; |
} |
break; |
case kHIDPage_Ordinal: |
printf("Ordinal Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_Telephony: |
printf("Telephony Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_Consumer: |
printf("Consumer Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_Digitizer: |
printf("Digitizer Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_PID: |
printf("PID Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_Unicode: |
printf("Unicode Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_AlphanumericDisplay: |
printf("Alphanumeric Display Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_BarCodeScanner: |
printf("Bar Code Scanner Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_Scale: |
printf("Scale Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_CameraControl: |
printf("Camera Control Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
case kHIDPage_Arcade: |
printf("Arcade Page (0x%lx), ", valueUsagePage); |
switch (valueUsage) |
{ |
default: printf("Usage (0x%lx)", valueUsage); break; |
} |
break; |
default: |
printf("Unknown Page (0x%lx), ", valueUsagePage); |
printf("Usage (0x%lx)", valueUsage); |
break; |
} |
} |
} |
} |
// -------------------------------------------------------------------------- |
static void MyCFDictionaryShow(CFDictionaryRef object) |
{ |
MyStartBlock(TRUE); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementCookieKey)); |
MyShowTypeElement (object); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementCollectionTypeKey)); |
MyShowUsageAndPageElement (object); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementMinKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementMaxKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementScaledMinKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementScaledMaxKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementSizeKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementIsRelativeKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementIsWrappingKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementIsNonLinearKey)); |
#ifdef kIOHIDElementHasPreferredStateKey |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementHasPreferredStateKey)); |
#else |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementHasPreferedStateKey)); |
#endif |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementHasNullStateKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementVendorSpecificKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementUnitKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementUnitExponentKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementNameKey)); |
MyShowDictionaryElement (object, CFSTR(kIOHIDElementKey)); |
fflush (stdout); |
MyStoreImportantCookies (object); |
//Store specific elements in global variables for use in queue handling functions. |
MyEndBlock (); |
MyIncrementElementIndex (1); |
} |
// -------------------------------------------------------------------------- |
static void MyCFNumberShow (CFNumberRef object) |
{ |
long number; |
if (CFNumberGetValue (object, kCFNumberLongType, &number)) |
printf("0x%lx (%ld)", number, number); |
} |
// -------------------------------------------------------------------------- |
static void MyCFStringShow(CFStringRef object) |
{ |
const char * c = CFStringGetCStringPtr (object, CFStringGetSystemEncoding ()); |
if (c) |
printf ("%s", c); |
else |
{ |
CFIndex bufferSize = CFStringGetLength (object) + 1; |
char * buffer = (char *)malloc (bufferSize); |
if (buffer) |
{ |
if (CFStringGetCString (object, buffer, bufferSize, CFStringGetSystemEncoding ())) |
printf ("%s", buffer); |
free(buffer); |
} |
} |
} |
// -------------------------------------------------------------------------- |
static void MyCFObjectShow (CFTypeRef object) |
{ |
CFTypeID type = CFGetTypeID(object); |
if (type == CFArrayGetTypeID()) |
MyCFArrayShow(object); |
else if (type == CFBooleanGetTypeID()) |
MyCFBooleanShow(object); |
else if (type == CFDictionaryGetTypeID()) |
MyCFDictionaryShow(object); |
else if (type == CFNumberGetTypeID()) |
MyCFNumberShow(object); |
else if (type == CFStringGetTypeID()) |
MyCFStringShow(object); |
else |
printf("<unknown object>"); |
} |
// -------------------------------------------------------------------------- |
static void MyShowProperty(const void * key, const void * value) |
{ |
//Both parameters are references to CF objects |
MyIndent (); |
MyCFStringShow (key); |
printf (" = "); |
MyCFObjectShow (value); |
} |
// -------------------------------------------------------------------------- |
static Boolean MyShowDictionaryElement (CFDictionaryRef dictionary, CFStringRef key) |
{ |
CFTypeRef object = CFDictionaryGetValue (dictionary, key); |
if (object) |
MyShowProperty (key,object); |
return (object != NULL); |
} |
// -------------------------------------------------------------------------- |
static void MyShowHIDProperties (io_registry_entry_t hidDevice) |
{ |
kern_return_t result; |
CFMutableDictionaryRef properties = 0; |
char path[512]; |
result = IORegistryEntryGetPath (hidDevice, kIOServicePlane, path); |
if (result == KERN_SUCCESS) |
printf("IO Registry Path: [ %s ]\n", path); |
//Create a CF dictionary representation of the I/O Registry entryÕs properties |
result = IORegistryEntryCreateCFProperties (hidDevice, &properties, kCFAllocatorDefault, kNilOptions); |
if ((result == KERN_SUCCESS) && properties) |
{ |
printf ("- Device Properties -\n"); |
MyShowDictionaryElement (properties, CFSTR(kIOHIDTransportKey)); |
MyShowDictionaryElement (properties, CFSTR(kIOHIDVendorIDKey)); |
MyShowDictionaryElement (properties, CFSTR(kIOHIDProductIDKey)); |
MyShowDictionaryElement (properties, CFSTR(kIOHIDVersionNumberKey)); |
MyShowDictionaryElement (properties, CFSTR(kIOHIDManufacturerKey)); |
MyShowDictionaryElement (properties, CFSTR(kIOHIDProductKey)); |
MyShowDictionaryElement (properties, CFSTR(kIOHIDSerialNumberKey)); |
if (!MyShowDictionaryElement (properties, CFSTR(kIOHIDLocationIDKey))) |
MyShowDictionaryElement (properties, CFSTR(kUSBDevicePropertyLocationID)); |
MyShowDictionaryElement (properties, CFSTR(kIOHIDPrimaryUsageKey)); |
MyShowDictionaryElement (properties, CFSTR(kIOHIDPrimaryUsagePageKey)); |
MyShowDictionaryElement (properties, CFSTR("idVendor")); |
MyShowDictionaryElement (properties, CFSTR("USB Product Name")); |
MyShowDictionaryElement (properties, CFSTR("idProduct")); |
fflush (stdout); |
printf ("- Device Element Properties -\n"); |
MyShowDictionaryElement (properties, CFSTR(kIOHIDElementKey)); |
//Release the properties dictionary |
CFRelease (properties); |
} |
else |
PrintErrMsg ("Failed to create properties via IORegistryEntryCreateCFProperties."); |
printf ("\n\n"); |
} |
// -------------------------------------------------------------------------- |
static IOHIDDeviceInterface ** MyCreateHIDDeviceInterface (io_object_t hidDevice) |
{ |
io_name_t className; |
IOCFPlugInInterface **plugInInterface = NULL; |
HRESULT plugInResult = S_OK; |
SInt32 score = 0; |
IOReturn ioReturnValue = kIOReturnSuccess; |
IOHIDDeviceInterface ** pphidDeviceInterface = NULL; |
ioReturnValue = IOObjectGetClass (hidDevice, className); |
PrintErrMsgIfIOErr (ioReturnValue, "Failed to get class name."); |
printf ("Creating interface for device of class %s\n\n", className); |
ioReturnValue = IOCreatePlugInInterfaceForService (hidDevice, kIOHIDDeviceUserClientTypeID, |
kIOCFPlugInInterfaceID, &plugInInterface, &score); |
if (ioReturnValue == kIOReturnSuccess) |
{ |
// Call a method of the intermediate plug-in to create the device interface |
plugInResult = (*plugInInterface)->QueryInterface (plugInInterface, |
CFUUIDGetUUIDBytes (kIOHIDDeviceInterfaceID), (void *) &pphidDeviceInterface); |
if (plugInResult != S_OK) |
PrintErrMsg ("CouldnÕt query HID class device interface from plugInInterface"); |
(*plugInInterface)->Release (plugInInterface); |
} |
else |
PrintErrMsg ("Failed to create **plugInInterface via IOCreatePlugInInterfaceForService."); |
return pphidDeviceInterface; |
} |
// -------------------------------------------------------------------------- |
#define TEST_EVENT_CALLBACK TRUE |
#if TEST_EVENT_CALLBACK |
static UInt32 gCallback_count = 0; |
static void MyIOHIDCallbackFunction(void * target, IOReturn result, void * refcon, void * sender) |
{ |
gCallback_count++; |
//if (0 == (gCallback_count % 32)) |
{ |
printf("MyIOHIDCallbackFunction - count = %ld.\n",gCallback_count); |
fflush(stdout); |
} |
result = kIOReturnSuccess; |
} |
#endif TEST_EVENT_CALLBACK |
// -------------------------------------------------------------------------- |
static void MyTestEventInterface (IOHIDDeviceInterface **hidDeviceInterface) |
{ |
HRESULT result; |
IOHIDQueueInterface ** queue; |
Boolean hasElement; |
IOHIDEventStruct event; |
queue = (*hidDeviceInterface)->allocQueue (hidDeviceInterface); |
printf("Queue allocated: %lx\n", (long) queue); |
if (queue) |
{ |
//create the queue |
result = (*queue)->create (queue, 0, /* flag?? */ 8);/* depth: maximum number of elements |
in queue before oldest elements in |
queue begin to be lost*/ |
printf ("Queue create result: %lx\n", result); |
//add elements to the queue |
result = (*queue)->addElement (queue, gXAxisCookie, 0); |
printf ("Queue added x axis result: %lx\n", result); |
result = (*queue)->addElement (queue, gButton1Cookie, 0); |
printf ("Queue added button 1 result: %lx\n", result); |
result = (*queue)->addElement (queue, gButton2Cookie, 0); |
printf ("Queue added button 2 result: %lx\n", result); |
result = (*queue)->addElement (queue, gButton3Cookie, 0); |
printf ("Queue added button 3 result: %lx\n", result); |
//check to see if button 3 is in queue |
hasElement = (*queue)->hasElement (queue,gButton3Cookie); |
printf ("queue has button 3 result: %s\n", hasElement ? "true" : "false"); |
//remove button 3 from queue |
result = (*queue)->removeElement (queue, gButton3Cookie); |
printf ("queue remove button 3 result: %lx\n",result); |
#if TEST_EVENT_CALLBACK |
{ |
CFRunLoopSourceRef tCFRunLoopSourceRef = NULL; |
result = (*queue)->createAsyncEventSource(queue, &tCFRunLoopSourceRef); |
if (kIOReturnSuccess != result) |
printf ("Failed to createAsyncEventSource, error: %ld.\n", result); |
// if we have one nowÉ |
if (NULL != tCFRunLoopSourceRef) |
{ |
CFRunLoopRef tCFRunLoopRef = (CFRunLoopRef) GetCFRunLoopFromEventLoop(GetMainEventLoop()); |
// and it's not already attached to our runloopÉ |
if (!CFRunLoopContainsSource(tCFRunLoopRef, tCFRunLoopSourceRef, kCFRunLoopDefaultMode)) |
// then attach it now. |
CFRunLoopAddSource(tCFRunLoopRef, tCFRunLoopSourceRef, kCFRunLoopDefaultMode); |
} |
// now install our callback |
result = (*queue)->setEventCallout(queue, MyIOHIDCallbackFunction, queue, queue); |
if (kIOReturnSuccess != result) |
printf ("Failed to setEventCallout, error: %ld.\n", result); |
#endif TEST_EVENT_CALLBACK |
//start data delivery to queue |
result = (*queue)->start (queue); |
printf ("queue start result: %lx\n", result); |
//check queue a few times to see accumulated events |
printf ("Testing Event Interface (Mouse button to continue)...\n"); |
fflush (stdout); |
while (Button()) {} |
while (!Button()) |
{ |
AbsoluteTime zeroTime = {0,0}; |
result = (*queue)->getNextEvent (queue, &event, zeroTime, 0); |
if (result == kIOReturnUnderrun) |
{ |
// print nothing queue empty |
} |
else if (result != kIOReturnSuccess) |
printf ("queue getNextEvent result error: %lx\n", result); |
else |
printf ("queue: event:[%lx] %ld\n", (unsigned long) event.elementCookie, event.value); |
fflush (stdout); |
#if TEST_EVENT_CALLBACK |
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25f, true); |
#endif TEST_EVENT_CALLBACK |
} |
//stop data delivery to queue |
result = (*queue)->stop (queue); |
printf ("queue stop result: %lx\n", result); |
#if TEST_EVENT_CALLBACK |
// see if we have an Async event source for this queueÉ |
tCFRunLoopSourceRef = (*queue)->getAsyncEventSource(queue); |
if (NULL != tCFRunLoopSourceRef) // if so thenÉ |
{ |
CFRunLoopRef tCFRunLoopRef = (CFRunLoopRef) GetCFRunLoopFromEventLoop(GetMainEventLoop()); |
// if it's attached to our runloopÉ |
if (CFRunLoopContainsSource(tCFRunLoopRef, tCFRunLoopSourceRef, kCFRunLoopDefaultMode)) |
// then remove it |
CFRunLoopRemoveSource(tCFRunLoopRef, tCFRunLoopSourceRef, kCFRunLoopDefaultMode); |
// now release it. |
CFRelease(tCFRunLoopSourceRef); |
} |
} |
#endif TEST_EVENT_CALLBACK |
//dispose of queue |
result = (*queue)->dispose (queue); |
//release the queue we allocated |
result = (*queue)->Release (queue); |
printf ("queue release result: %lx\n", result); |
fflush (stdout); |
} |
} |
// -------------------------------------------------------------------------- |
static void MyTestPollingInterface (IOHIDDeviceInterface ** hidDeviceInterface) |
{ |
HRESULT result; |
IOHIDEventStruct hidEvent; |
printf ("Testing Polling Interface (Mouse button to continue)...\n"); |
printf("X Axis (%lx), Button 1 (%lx), Button 2 (%lx), Button 3 (%lx)\n", |
(long) gXAxisCookie, (long) gButton1Cookie, (long) gButton2Cookie, (long) gButton3Cookie); |
while (Button()) {} |
while (!Button()) |
{ |
long xAxis, button1, button2, button3; |
//Get x axis |
result = (*hidDeviceInterface)->getElementValue(hidDeviceInterface, gXAxisCookie, &hidEvent); |
if (result) |
printf("getElementValue error = %lx", result); |
xAxis = hidEvent.value; |
//Get button 1 |
result = (*hidDeviceInterface)->getElementValue(hidDeviceInterface, gButton1Cookie, &hidEvent); |
if (result) |
printf("getElementValue error = %lx", result); |
button1 = hidEvent.value; |
//Get button 2 |
result = (*hidDeviceInterface)->getElementValue(hidDeviceInterface, gButton2Cookie, &hidEvent); |
if (result) |
printf("getElementValue error = %lx", result); |
button2 = hidEvent.value; |
//Get button 3 |
result = (*hidDeviceInterface)->getElementValue (hidDeviceInterface, gButton3Cookie, &hidEvent); |
if (result) |
printf ("getElementValue error = %lx", result); |
button3 = hidEvent.value; |
//Print values |
printf ("xAxis: %ld\t Buttons:%s%s%s\n", |
xAxis, button1 ? " 1 " : "", button2 ? " 2 " : "", button3 ? " 3 " : ""); |
fflush (stdout); |
sleep (1); |
} |
} |
// functions (external/public) ---------------------------------------------- |
void MyStartHIDDeviceInterfaceTest (void) |
{ |
mach_port_t masterPort = NULL; |
io_iterator_t hidObjectIterator = NULL; |
IOReturn ioReturnValue = kIOReturnSuccess; |
// Get a Mach port to initiate communication with I/O Kit. |
ioReturnValue = IOMasterPort (bootstrap_port, &masterPort); |
PrintErrMsgIfIOErr (ioReturnValue, "CouldnÕt create a master I/O Kit Port."); |
printf("\n\n--- Finding GamePads ---\n"); |
hidObjectIterator = MyFindHIDDevices (masterPort, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad); |
if (hidObjectIterator != NULL) |
{ |
io_object_t hidDevice = NULL; |
IOHIDDeviceInterface ** pphidDeviceInterface = NULL; |
IOReturn ioReturnValue = kIOReturnSuccess; |
short numDevice = 0; |
while ((hidDevice = IOIteratorNext (hidObjectIterator))) |
{ |
printf ("\n--- Device %d ---\n", numDevice++); |
MyShowHIDProperties (hidDevice); |
pphidDeviceInterface = MyCreateHIDDeviceInterface (hidDevice); |
// Release the device |
ioReturnValue = IOObjectRelease (hidDevice); |
PrintErrMsgIfIOErr (ioReturnValue, "Error releasing HID device"); |
if (*pphidDeviceInterface != NULL) |
{ |
// open the device |
ioReturnValue = (*pphidDeviceInterface)->open (pphidDeviceInterface, 0); |
printf ("Open result = %d\n", ioReturnValue); |
//test the event interface |
MyTestEventInterface (pphidDeviceInterface); |
//test the polling interface |
MyTestPollingInterface (pphidDeviceInterface); |
//close the device |
if (ioReturnValue == KERN_SUCCESS) |
{ |
ioReturnValue = (*pphidDeviceInterface)->close (pphidDeviceInterface); |
printf ("Close result = %d\n", ioReturnValue); |
} |
// Release the device interface |
(*pphidDeviceInterface)->Release (pphidDeviceInterface); |
} |
} |
IOObjectRelease (hidObjectIterator); |
} |
fflush (stdout); |
//Free master port if we created one. |
if (masterPort) |
mach_port_deallocate (mach_task_self (), masterPort); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-07-10