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.
UHIDTest.c
/* |
File: UHIDTest.c |
Contains: xxx put contents here xxx |
Version: xxx put version here xxx |
Copyright: © 1999 by Apple Computer, Inc., all rights reserved. |
File Ownership: |
DRI: xxx put dri here xxx |
Other Contact: xxx put other contact here xxx |
Technology: xxx put technology here xxx |
Writers: |
(BWS) Brent Schorsch |
Change History (most recent first): |
<SP6> 3/20/99 BWS Update to lastest HIDOpenReportDescriptor API |
<SP5> 3/7/99 BWS Add Simulate ISp enumeration - similar code to ISp driver |
<SP4> 3/7/99 BWS Print out caps usage page and usage. Print all usages in hex |
<SP3> 3/7/99 BWS Implemented get capabilities and print parsed data |
<SP2> 3/5/99 BWS Added HIDLib calls |
*/ |
#include <MacTypes.h> |
#include <SIOUX.h> |
#include <LowMem.h> |
#include <USB.h> |
#include <InputSprocket.h> |
#include "HID.h" |
//#include "UniversalHIDModule.h" |
#include <stdarg.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
//#include "HIDPriv.h" |
// extern protos |
extern void PrintHIDReport(UInt8 * reportDesc, UInt32 length); |
// globals |
// quit state |
Boolean gShouldQuit = false; |
// steps of process |
SInt32 gStep; |
char gStepId[255]; |
// 'safe' (delayed) printf |
enum { kPrintfBufferSize = 1024 * 32 }; |
UInt32 gMaxPacketSize; |
char gPrintfBuffer1[kPrintfBufferSize + 256]; |
char gPrintfBuffer2[kPrintfBufferSize + 256]; |
char * gInsertPrintfBuffer; |
char * gFreePrintfBuffer; |
UInt32 gInsertIndex = 0; |
enum |
{ |
kPrint_AsHex = 1, |
kPrint_AsBinary, |
kPrint_ParseButtons, |
kPrint_ParseBoth, |
kPrint_SimulateISp |
}; |
UInt32 gPrint_AsType; |
// HID stuff |
// these constants are from the USB HID Usage Table spec |
enum |
{ |
kHIDPage_Generic = 1, |
kHIDUsage_Joystick = 0x04, |
kHIDUsage_Gamepad = 0x05, |
kHIDUsage_X = 0x30, |
kHIDUsage_Y = 0x31, |
kHIDUsage_Z = 0x32, |
kHIDUsage_Rx = 0x33, |
kHIDUsage_Ry = 0x34, |
kHIDUsage_Rz = 0x35, |
kHIDUsage_Slider = 0x36, |
kHIDUsage_Dial = 0x37, |
kHIDUsage_Wheel = 0x38, |
kHIDUsage_HatSwitch = 0x39, |
kHIDPage_Simulation = 2, |
kHIDUsage_Rudder = 0xBA, |
kHIDUsage_Throttle = 0xBB, |
kHIDPage_Button = 9 |
}; |
// these constants are used to describe specific values for an element (a usbElementKey) |
enum |
{ |
// it is important that all buttons come first and start at 1 |
kUSB_button1_element = 1, |
kUSB_button2_element, |
kUSB_button3_element, |
kUSB_button4_element, |
kUSB_button5_element, |
kUSB_button6_element, |
kUSB_button7_element, |
kUSB_button8_element, |
kUSB_button9_element, |
kUSB_button10_element, |
kUSB_button11_element, |
kUSB_button12_element, |
kUSB_button13_element, |
kUSB_button14_element, |
kUSB_button15_element, |
kUSB_button16_element, |
kUSB_trigger_element, |
kUSB_buttonStart_element, |
kUSB_buttonSelect_element, |
kUSB_povhat_element, |
kUSB_povhat4_element, |
kUSB_dpad_element, |
kUSB_dpad4_element, |
kUSB_xaxis_element, |
kUSB_yaxis_element, |
kUSB_throttle_element, |
kUSB_rudder_element, |
kUSB_trim_element, |
kUSB_gas_element, |
kUSB_brake_element, |
kUSB_axis_element |
}; |
enum |
{ |
kStrListResource_DefaultNames = 128 |
}; |
enum |
{ |
kStrList_DefaultNames_Trigger = 1, |
kStrList_DefaultNames_LeftTrigger, |
kStrList_DefaultNames_RightTrigger, |
kStrList_DefaultNames_LeftIndexTop, |
kStrList_DefaultNames_LeftIndexBottom, |
kStrList_DefaultNames_RightIndexTop, |
kStrList_DefaultNames_RightIndexBottom, |
kStrList_DefaultNames_ThumbLeftButton, |
kStrList_DefaultNames_ThumbCenterButton, |
kStrList_DefaultNames_ThumbRightButton, |
kStrList_DefaultNames_ThumbTopButton, |
kStrList_DefaultNames_ThumbBottomButton, |
kStrList_DefaultNames_AButton, |
kStrList_DefaultNames_BButton, |
kStrList_DefaultNames_CButton, |
kStrList_DefaultNames_DButton, |
kStrList_DefaultNames_EButton, |
kStrList_DefaultNames_FButton, |
kStrList_DefaultNames_XButton, |
kStrList_DefaultNames_YButton, |
kStrList_DefaultNames_ZButton, |
kStrList_DefaultNames_MButton, |
kStrList_DefaultNames_TAButton, |
kStrList_DefaultNames_TBButton, |
kStrList_DefaultNames_F1Button, |
kStrList_DefaultNames_F2Button, |
kStrList_DefaultNames_F3Button, |
kStrList_DefaultNames_F4Button, |
kStrList_DefaultNames_F5Button, |
kStrList_DefaultNames_F6Button, |
kStrList_DefaultNames_F7Button, |
kStrList_DefaultNames_F8Button, |
kStrList_DefaultNames_YellowButton, |
kStrList_DefaultNames_RedButton, |
kStrList_DefaultNames_GreenButton, |
kStrList_DefaultNames_BlueButton, |
kStrList_DefaultNames_StartButton, |
kStrList_DefaultNames_SelectButton, |
kStrList_DefaultNames_ShiftButton, |
kStrList_DefaultNames_LeftShiftButton, |
kStrList_DefaultNames_RightShiftButton, |
kStrList_DefaultNames_SensorButton, |
kStrList_DefaultNames_Button1, |
kStrList_DefaultNames_Button2, |
kStrList_DefaultNames_Button3, |
kStrList_DefaultNames_Button4, |
kStrList_DefaultNames_Button5, |
kStrList_DefaultNames_Button6, |
kStrList_DefaultNames_Button7, |
kStrList_DefaultNames_Button8, |
kStrList_DefaultNames_Button9, |
kStrList_DefaultNames_Button10, |
kStrList_DefaultNames_Button11, |
kStrList_DefaultNames_Button12, |
kStrList_DefaultNames_Button13, |
kStrList_DefaultNames_Button14, |
kStrList_DefaultNames_Button15, |
kStrList_DefaultNames_Button16, |
kStrList_DefaultNames_Button, |
kStrList_DefaultNames_POVHat, |
kStrList_DefaultNames_DPad, |
kStrList_DefaultNames_XAxis, |
kStrList_DefaultNames_YAxis, |
kStrList_DefaultNames_XTilt, |
kStrList_DefaultNames_YTilt, |
kStrList_DefaultNames_Twist, |
kStrList_DefaultNames_Throttle, |
kStrList_DefaultNames_Trim, |
kStrList_DefaultNames_Rudder, |
kStrList_DefaultNames_Axis, |
kStrList_DefaultNames_Wheel, |
kStrList_DefaultNames_Gas, |
kStrList_DefaultNames_Brake, |
kStrList_DefaultNames_Error |
}; |
enum |
{ |
kButtonElement = 1, |
kValueElement = 2 |
}; |
struct HIDElement |
{ |
UInt32 type; |
UInt32 capsIndex; |
HIDUsage usagePage; |
HIDUsage usage; |
UInt32 key; |
SInt32 min; |
SInt32 max; |
SInt32 stringIndex; |
}; |
typedef struct HIDElement HIDElement; |
HIDCaps gHIDCaps; |
HIDButtonCaps * gHIDButtonCaps; |
HIDValueCaps * gHIDValueCaps; |
HIDElement * gHIDElements; |
UInt32 gHIDElementCount = 0; |
enum { kMaxReportDescSize = 1024 }; |
UInt8 gReportDesc[kMaxReportDescSize]; |
UInt32 gReportDescLength; |
HIDPreparsedDataRef gPreparsedDataRef; |
HIDPreparsedData gPreparsedData; |
UInt32 gMaxUsageListLength = 0; |
HIDUsageAndPage * gPreviousDownButtons = nil; |
HIDUsageAndPage * gCurrentDownButtons = nil; |
// lists of dispatch tables |
enum { kMaxDevices = 128 }; |
UHIDModuleDispatchTablePtr gUHID_dispatchTables[kMaxDevices]; |
int gUHID_count = 0; |
UHIDModuleDispatchTablePtr gCurrentUHID_dispatchTable; |
UHIDModuleConnectionID gCurrentUHIDModuleConnectionID; |
USBHIDModuleDispatchTablePtr gMouse_dispatchTables[kMaxDevices]; |
int gMouse_count = 0; |
// macros |
#define VERIFY(x) if (x) { FailCode(x); return; } |
#define FAILMSG(x) { FailMsg(x); return; } |
#define FAILCODE(x) { FailCode(x); return; } |
#define FFAILMSG(x) { FailMsg(x); return false; } |
#define FFAILCODE(x) { FailCode(x); return false; } |
// protos |
void ShowFourByte(OSType fourByte); |
void ExitProc (void); |
void DoHIDTest (void); |
void GetButtonCapabilities (void); |
void GetValueCapabilities (void); |
void PrintButtonCapabilities (HIDCaps hidCaps, HIDButtonCaps * hidButtonCaps); |
void PrintValueCapabilities (HIDCaps hidCaps, HIDValueCaps * hidValueCaps); |
void ClaimAndInstallHandler (void); |
void RemoveHandlerAndRelease (void); |
void myUniversalInterruptProc(void * theData, UInt32 refcon); |
OSStatus HidP_PrintAllInputValues |
(UInt32 iCollection, |
HIDPreparsedDataPtr ptPreparsedData, |
char *psReport, |
int iReportLength); |
int safeprintf(const char *format, ...); |
void PrintPreparsedData (void); |
void PrintCollectionItems (UInt32 firstCollection, UInt32 collectionCount, char * indent); |
void PrintReportItems (UInt32 firstReportItem, UInt32 reportItemCount, char * indent); |
void PrintUsageItems (UInt32 firstUsageItem, UInt32 usageItemCount, char * indent); |
void SimulateISpEnumeration (void); |
OSStatus PrintHIDElements (void); |
OSStatus BuildHIDElements (void); |
UInt32 CountHIDElements(void); |
OSStatus InitializeHIDElement(HIDElement * hidElement); |
SInt32 ParseElementValue (UInt32 inElementIndex, Ptr inBuffer); |
// code |
static Boolean Progress(UInt32 inItr, UInt32 inTotal, UInt32 inNumReports, char *string) |
{ |
UInt32 everyNTimes = inTotal / inNumReports; |
if (everyNTimes == 0) { everyNTimes = 1; } |
if (inItr == 0) { return false; } |
if ((inItr % everyNTimes) == 0) |
{ |
UInt32 percent = (inItr * 100) / inTotal; |
sprintf(string, "%d%% [%d of %d]", percent, inItr, inTotal); |
return true; |
} |
return false; |
} |
static void InitStep(char *msg) |
{ |
gStep = 0; |
sprintf(gStepId, "%3d"); |
if (msg == nil) |
{ |
printf("step %s\n", gStepId); |
} |
else |
{ |
printf("step %s %s\n",gStepId, msg); |
} |
} |
static void NextStep(char *msg) |
{ |
long this_app_memory; |
long this_sys_memory; |
static Boolean first_time = true; |
static long last_app_memory; |
static long last_sys_memory; |
gStep++; |
sprintf(gStepId, "%3d", gStep); |
this_app_memory = FreeMem(); |
this_sys_memory = FreeMemSys(); |
if (first_time) |
{ |
first_time = false; |
} |
else |
{ |
long delta_app_memory = last_app_memory - this_app_memory; |
long delta_sys_memory = last_sys_memory - this_sys_memory; |
printf("step %s ending app mem = %d sys mem = %d\n", gStepId, this_app_memory, this_sys_memory); |
printf("step %s delta app mem = %d sys mem = %d\n", gStepId, delta_app_memory, delta_sys_memory); |
} |
if (msg == nil) |
{ |
printf("step %s\n", gStepId); |
} |
else |
{ |
printf("step %s %s\n",gStepId, msg); |
} |
printf("step %s starting app mem = %d sys mem = %d\n", gStepId, this_app_memory, this_sys_memory); |
last_app_memory = this_app_memory; |
last_sys_memory = this_sys_memory; |
} |
static void FailMsg(char *failure) |
{ |
printf("step %s FAILED reason = %s\n", gStepId, failure); |
} |
static void FailCode(OSStatus errorCode) |
{ |
printf("step %s FAILED errorCode = %d\n", gStepId, errorCode); |
} |
static void StatusMsg(char *msg) |
{ |
printf("step %s status msg = %s\n",gStepId, msg); |
} |
void ShowFourByte(OSType fourByte) |
{ |
putchar(((fourByte & 0xff000000) >> 24)); |
putchar(((fourByte & 0x00ff0000) >> 16)); |
putchar(((fourByte & 0x0000ff00) >> 8)); |
putchar(((fourByte & 0x000000ff) >> 00)); |
} |
void main(void) |
{ |
OSErr status = noErr; |
CFragConnectionID usbConnID; |
USBDeviceRef usbDeviceRef; |
CFragSymbolClass symClass; |
UHIDModuleDispatchTablePtr uHID_dispatchTable; |
// USBHIDModuleDispatchTablePtr mouse_dispatchTable; |
UInt16 vendor; |
UInt16 product; |
THz currentZone; |
#if defined(__MWERKS__) |
// tell SIOUX to shut up |
SIOUXSettings.autocloseonquit = false; |
SIOUXSettings.asktosaveonclose = false; |
SIOUXSettings.columns = 120; |
SIOUXSettings.rows = 70; |
#endif |
printf("starting up...\n"); |
printf("searching for universal HID devices\n"); |
usbDeviceRef = 0; |
while (status == noErr && gUHID_count < kMaxDevices) |
{ |
printf ("searching for next device...\n"); |
status = USBGetNextDeviceByClass (&usbDeviceRef, &usbConnID, kUSBHIDClass, kUSBCompositeSubClass, kUSBNoInterfaceProtocol); |
if (status) |
{ |
if (status != kUSBNotFound && status != fnfErr) |
FailCode (status); |
continue; |
} |
printf ("candidate found (connID: %00000008x), searching for symbol...\n", usbConnID); |
// need to be in the system zone when we search for the symbol |
currentZone = GetZone (); |
SetZone (SystemZone ()); |
status = FindSymbol (usbConnID, "\pTheUHIDModuleDispatchTable", (Ptr *)&uHID_dispatchTable, &symClass); |
SetZone (currentZone); |
// if we failed to find it, go on to the next device |
if (status) |
{ |
FailCode (status); |
status = noErr; |
continue; |
} |
printf("symbol found, checking versions...\n"); |
// version checking |
if (uHID_dispatchTable->dispatchTableCurrentVersion < kOldestCompatableDispatchTableVersion) |
{ |
printf (" DispatchTable current version (%d) too old (%d)\n", |
uHID_dispatchTable->dispatchTableCurrentVersion, kOldestCompatableDispatchTableVersion); |
continue; |
} |
if (uHID_dispatchTable->dispatchTableOldestVersion > kCurrentDispatchTableVersion) |
{ |
printf (" DispatchTable oldest version (%d) too new (%d)\n", |
uHID_dispatchTable->dispatchTableOldestVersion, kCurrentDispatchTableVersion); |
continue; |
} |
gUHID_dispatchTables[gUHID_count++] = uHID_dispatchTable; |
(UHIDInstallInterruptProcPtr)(*(uHID_dispatchTable->pUHIDGetDeviceInfo))(kUHIDGetVenderID, &vendor); |
(UHIDInstallInterruptProcPtr)(*(uHID_dispatchTable->pUHIDGetDeviceInfo))(kUHIDGetProductID, &product); |
printf("version check success, valid device (Vender:%0004X Product:%0004X).\n", vendor, product); |
} |
while (gUHID_count > 0 && !gShouldQuit) |
DoHIDTest(); |
printf("quitting...\n"); |
} |
void ExitProc (void) |
{ |
RemoveHandlerAndRelease (); |
} |
void DoHIDTest (void) |
{ |
OSErr status = noErr; |
UHIDModuleDispatchTablePtr uHID_dispatchTable; |
// USBHIDModuleDispatchTablePtr mouse_dispatchTable; |
UInt16 vendor; |
UInt16 product; |
int index; |
char string[256]; |
choosedevice: |
// ¥¥¥ memory leak here, but who cares for now... (We never dispose of these) |
gHIDElementCount = 0; |
printf ("\nChoose a device:\n"); |
// choice to quit |
printf ("1. Exit\n"); |
// print out UHID choices |
index = 0; |
while (index < gUHID_count) |
{ |
uHID_dispatchTable = gUHID_dispatchTables[index]; |
(UHIDInstallInterruptProcPtr)(*(uHID_dispatchTable->pUHIDGetDeviceInfo))(kUHIDGetVenderID, &vendor); |
(UHIDInstallInterruptProcPtr)(*(uHID_dispatchTable->pUHIDGetDeviceInfo))(kUHIDGetProductID, &product); |
printf ("%d. Vender:%0004X Product:%0004X\n", index + 2, vendor, product); |
index++; |
} |
// ¥ todo ¥Êprint out mouse choices |
// get user choice |
printf ("Selection: "); |
gets (string); |
index = atoi (string); |
printf ("\n"); |
// handle the quit case |
if (index == 1) |
{ |
gShouldQuit = true; |
return; |
} |
// setup for this device |
uHID_dispatchTable = gCurrentUHID_dispatchTable = gUHID_dispatchTables[index - 2]; |
// init the printf double buffer |
gInsertPrintfBuffer = gPrintfBuffer1; |
gFreePrintfBuffer = gPrintfBuffer2; |
gInsertIndex = 0; |
// get the max packet size |
gMaxPacketSize = 0; |
(UHIDInstallInterruptProcPtr)(*(uHID_dispatchTable->pUHIDGetDeviceInfo))(kUHIDGetMaxPacketSize, &gMaxPacketSize); |
printf("Max packet size = %d\n", gMaxPacketSize); |
printf("Printing the report descriptor\n", status); |
// print the HID report descriptor |
gReportDescLength = sizeof (gReportDesc); |
status = (*uHID_dispatchTable->pUHIDGetHIDDescriptor)(kUSBReportDesc, 0, &gReportDescLength, gReportDesc); |
if (status) |
printf("*** Error (%d) on Get Report Descriptor Device\n", status); |
else |
PrintHIDReport(gReportDesc, gReportDescLength); |
// setup the HID stuff |
status = HIDOpenReportDescriptor (gReportDesc, gReportDescLength, &gPreparsedDataRef, kHIDFlag_StrictErrorChecking); |
if (status) |
printf("*** Error (%d) on HIDOpenDescriptor (strict error checking) \n", status); |
// if error, less error checking on the HID stuff |
if (status) |
{ |
status = HIDOpenReportDescriptor (gReportDesc, gReportDescLength, &gPreparsedDataRef, 0); |
if (status) |
printf("*** Error (%d) on HIDOpenDescriptor\n", status); |
else |
printf("HIDOpenDescriptor (lax error checking) succeeded. \n", status); |
} |
// allocate our buffers |
gMaxUsageListLength = HIDMaxUsageListLength (kHIDInputReport, 0, gPreparsedDataRef); |
printf("Number of buttons (max usage list length) = %ld\n", gMaxUsageListLength); |
gPreviousDownButtons = (HIDUsageAndPage *) NewPtr (gMaxUsageListLength * sizeof (HIDUsageAndPage)); |
if (gPreviousDownButtons == nil) |
printf("*** Error (%d) on NewPtr for gPreviousDownButtons\n", MemError()); |
gCurrentDownButtons = (HIDUsageAndPage *) NewPtr (gMaxUsageListLength * sizeof (HIDUsageAndPage)); |
if (gCurrentDownButtons == nil) |
printf("*** Error (%d) on NewPtr for gCurrentDownButtons\n", MemError()); |
printf("gPreviousDownButtons = %lx, gCurrentDownButtons = %lx\n", gPreviousDownButtons, gCurrentDownButtons); |
whattoget: |
printf ("1. Exit\n"); |
printf ("2. Choose another device\n"); |
printf ("3. Get data\n"); |
printf ("4. Get button capabilities\n"); |
printf ("5. Get value capabilities\n"); |
printf ("6. Print preparsed data\n"); |
printf ("7. Simulate ISp Enumeration\n"); |
// get user choice |
printf ("Selection: "); |
gets (string); |
index = atoi (string); |
printf ("\n"); |
switch (index) |
{ |
// exit |
case 1: |
gShouldQuit = true; |
goto close; |
case 2: |
goto choosedevice; |
case 3: |
break; |
case 4: |
GetButtonCapabilities(); |
goto whattoget; |
case 5: |
GetValueCapabilities(); |
goto whattoget; |
case 6: |
PrintPreparsedData(); |
goto whattoget; |
case 7: |
SimulateISpEnumeration(); |
goto whattoget; |
default: |
goto whattoget; |
} |
getdata: |
printf ("1. Exit\n"); |
printf ("2. Previous menu\n"); |
printf ("3. Display raw bits as hex\n"); |
printf ("4. Display raw bits as binary\n"); |
printf ("5. Display parsed buttons\n"); |
printf ("6. Display parsed values and buttons\n"); |
if (gHIDElementCount > 0) |
printf ("7. Simulate ISp\n"); |
// get user choice |
printf ("Selection: "); |
gets (string); |
index = atoi (string); |
printf ("\n"); |
// make as binary the default, and use in the unimplemented cases? |
gPrint_AsType = kPrint_AsBinary; |
switch (index) |
{ |
// exit |
case 1: |
gShouldQuit = true; |
goto close; |
case 2: |
goto whattoget; |
case 3: |
gPrint_AsType = kPrint_AsHex; |
break; |
case 4: |
gPrint_AsType = kPrint_AsBinary; |
break; |
case 5: |
gPrint_AsType = kPrint_ParseButtons; |
break; |
case 6: |
gPrint_AsType = kPrint_ParseBoth; |
break; |
case 7: |
if (gHIDElementCount > 0) |
gPrint_AsType = kPrint_SimulateISp; |
else |
goto getdata; |
break; |
default: |
goto getdata; |
} |
ClaimAndInstallHandler(); |
// get data |
printf("getting data (press command to end)\n"); |
while (1) |
{ |
KeyMap theKeys; |
if (gInsertIndex) // if we have data in the queue, then printf it |
{ |
char * temp = gInsertPrintfBuffer; |
gInsertPrintfBuffer = gFreePrintfBuffer; // must do 1st! - atomic switch |
gInsertIndex = 0; // _technically_ bad, could possibly miss some data |
gFreePrintfBuffer = temp; |
printf(temp); |
fflush(stdout); |
} |
GetKeys(theKeys); |
if ((theKeys[1] & 0x8000)) |
{ |
break; |
} |
SIOUXHandleOneEvent(nil); |
} |
RemoveHandlerAndRelease (); |
if (!gShouldQuit) |
goto getdata; |
close: |
status = HIDCloseReportDescriptor (gPreparsedDataRef); |
if (status) |
printf("*** Error (%d) on HIDCloseDescriptor\n", status); |
DisposePtr ((void *) gPreviousDownButtons); |
gPreviousDownButtons = nil; |
DisposePtr ((void *) gCurrentDownButtons); |
gCurrentDownButtons = nil; |
printf("finished\n\n"); |
} |
void GetButtonCapabilities(void) |
{ |
OSStatus err = noErr; |
HIDCaps hidCaps; |
HIDButtonCaps * hidButtonCaps = nil; |
// get the overall capabilities of the device |
if (err == noErr) |
err = HIDGetCaps (gPreparsedDataRef, &hidCaps); |
// allocate space for button caps |
if (err == noErr) |
{ |
hidButtonCaps = (HIDButtonCaps *) NewPtrSysClear(sizeof(HIDButtonCaps) * hidCaps.numberInputButtonCaps); |
if (hidButtonCaps == nil) |
{ |
printf ("\n¥¥ Failed to allocate space for ButtonCaps\n"); |
err = memFullErr; |
} |
} |
// get the button capabilities |
if (err == noErr) |
err = HIDGetButtonCaps (kHIDInputReport, hidButtonCaps, &hidCaps.numberInputButtonCaps, gPreparsedDataRef); |
// print what we found |
if (err == noErr) |
PrintButtonCapabilities (hidCaps, hidButtonCaps); |
// dispose the memory |
if (hidButtonCaps != nil) |
DisposePtr((LogicalAddress) hidButtonCaps); |
} |
void GetValueCapabilities (void) |
{ |
OSStatus err = noErr; |
HIDCaps hidCaps; |
HIDValueCaps * hidValueCaps = nil; |
// get the overall capabilities of the device |
if (err == noErr) |
err = HIDGetCaps (gPreparsedDataRef, &hidCaps); |
// allocate space for value caps |
if (err == noErr) |
{ |
hidValueCaps = (HIDValueCaps *) NewPtrSysClear(sizeof(HIDValueCaps) * hidCaps.numberInputValueCaps); |
if (hidValueCaps == nil) |
{ |
err = memFullErr; |
printf ("\n¥¥ Failed to allocate space for ValueCaps\n"); |
} |
} |
// get the value capabilities |
if (err == noErr) |
err = HIDGetValueCaps (kHIDInputReport, hidValueCaps, &hidCaps.numberInputValueCaps, gPreparsedDataRef); |
// print what we found |
if (err == noErr) |
PrintValueCapabilities (hidCaps, hidValueCaps); |
// dispose the memory |
if (hidValueCaps != nil) |
DisposePtr((LogicalAddress) hidValueCaps); |
} |
void PrintButtonCapabilities (HIDCaps hidCaps, HIDButtonCaps * hidButtonCaps) |
{ |
UInt32 index; |
UInt32 reportID = 0; |
printf("%d buttons (device usage: %X on page: %d)\n", |
hidCaps.numberInputButtonCaps, |
hidCaps.usage, |
hidCaps.usagePage); |
for (index = 0; index < hidCaps.numberInputButtonCaps; index++) |
{ |
if (reportID != hidButtonCaps[index].reportID) |
{ |
reportID = hidButtonCaps[index].reportID; |
printf("Report ID: %d\n", reportID); |
} |
if (hidButtonCaps[index].isRange) |
printf("%X-%X:%d\n", |
hidButtonCaps[index].u.range.usageMin, |
hidButtonCaps[index].u.range.usageMax, |
hidButtonCaps[index].usagePage); |
else |
printf("%X:%d\n", |
hidButtonCaps[index].u.notRange.usage, |
hidButtonCaps[index].usagePage); |
} |
printf("\n\n"); |
} |
void PrintValueCapabilities (HIDCaps hidCaps, HIDValueCaps * hidValueCaps) |
{ |
UInt32 index; |
UInt32 reportID = 0; |
printf("%d values (device usage:%d on page:%d\n", |
hidCaps.numberInputValueCaps, |
hidCaps.usage, |
hidCaps.usagePage); |
for (index = 0; index < hidCaps.numberInputValueCaps; index++) |
{ |
if (reportID != hidValueCaps[index].reportID) |
{ |
reportID = hidValueCaps[index].reportID; |
printf("Report ID: %d\n", reportID); |
} |
if (hidValueCaps[index].isRange) |
printf("%X-%X:%d\t\t(%d<->%d)\t(%d<->%d)\t\t[%d * %d]\t\t¥¥¥¥\n", |
hidValueCaps[index].u.range.usageMin, |
hidValueCaps[index].u.range.usageMax, |
hidValueCaps[index].usagePage, |
hidValueCaps[index].logicalMin, |
hidValueCaps[index].logicalMax, |
hidValueCaps[index].physicalMin, |
hidValueCaps[index].physicalMax, |
hidValueCaps[index].bitSize, |
hidValueCaps[index].reportCount); |
else |
printf("%X:%d\t\t(%d<->%d)\t(%d<->%d)\t\t[%d * %d]\n", |
hidValueCaps[index].u.notRange.usage, |
hidValueCaps[index].usagePage, |
hidValueCaps[index].logicalMin, |
hidValueCaps[index].logicalMax, |
hidValueCaps[index].physicalMin, |
hidValueCaps[index].physicalMax, |
hidValueCaps[index].bitSize, |
hidValueCaps[index].reportCount); |
if (hidValueCaps[index].reportCount > 1) |
printf("¥¥¥ Report Count > 1\n"); |
} |
printf("\n\n"); |
} |
void ClaimAndInstallHandler (void) |
{ |
OSErr status = noErr; |
UHIDModuleConnectionID uHIDModuleConnectionID; |
if (gCurrentUHID_dispatchTable == nil) |
{ |
printf("*** Error: have not specified a device\n"); |
return; |
} |
if (gCurrentUHIDModuleConnectionID != 0) |
{ |
printf("*** Error: Already have device active\n"); |
return; |
} |
printf("Claiming the device\n"); |
// claim the device |
status = (OSStatus) ((UHIDClaimDeviceProcPtr)(*(gCurrentUHID_dispatchTable->pUHIDClaimDevice)) |
(&uHIDModuleConnectionID, 0)); |
if (status) |
{ |
printf("*** Error (%d) on Claim Device\n", status); |
return; |
} |
gCurrentUHIDModuleConnectionID = uHIDModuleConnectionID; |
// install the handler |
printf("Installing the handler\n"); |
status = (OSStatus) ((UHIDInstallInterruptProcPtr)(*(gCurrentUHID_dispatchTable->pUHIDInstallInterrupt)) |
(uHIDModuleConnectionID, myUniversalInterruptProc, 0)); |
if (status) |
{ |
printf("*** Error (%d) on Universal Interrupt Handler install\n", status); |
return; |
} |
} |
void RemoveHandlerAndRelease (void) |
{ |
OSErr status = noErr; |
if (gCurrentUHID_dispatchTable == nil) |
{ |
printf("*** Error have not specified a device\n"); |
return; |
} |
if (gCurrentUHIDModuleConnectionID == 0) |
return; |
// remove the handler |
status = (OSStatus) (UHIDInstallInterruptProcPtr)(*(gCurrentUHID_dispatchTable->pUHIDInstallInterrupt)) |
(gCurrentUHIDModuleConnectionID, nil, 0); |
if (status) |
printf("*** Error (%d) on Universal Interrupt Handler remove\n", status); |
// release the device |
status = (OSStatus) ((UHIDReleaseDeviceProcPtr)(*(gCurrentUHID_dispatchTable->pUHIDReleaseDevice)) |
(gCurrentUHIDModuleConnectionID)); |
if (status) |
printf("*** Error (%d) on release device\n", status); |
gCurrentUHIDModuleConnectionID = 0; |
} |
void myUniversalInterruptProc(void * theData, UInt32 /* refcon */) |
{ |
//#pragma unused refcon |
UInt16 i; |
UInt8 *pRawData; |
OSErr status = noErr; |
UInt32 length; |
UInt32 index; |
SInt32 value; |
pRawData = (UInt8*)theData; |
switch (gPrint_AsType) |
{ |
case kPrint_AsHex: |
case kPrint_AsBinary: |
for (i = 0; i < gMaxPacketSize; i++) |
{ |
switch (gPrint_AsType) |
{ |
case kPrint_AsHex: |
safeprintf("$%02X ", pRawData[i]); |
break; |
case kPrint_AsBinary: |
safeprintf("%d%d%d%d%d%d%d%d ", !!(pRawData[i]&0x80), !!(pRawData[i]&0x40), |
!!(pRawData[i]&0x20), !!(pRawData[i]&0x10), |
!!(pRawData[i]&0x08), !!(pRawData[i]&0x04), |
!!(pRawData[i]&0x02), !!(pRawData[i]&0x01)); |
break; |
} |
} |
break; |
case kPrint_ParseButtons: |
length = gMaxUsageListLength; |
status = HIDGetButtons (kHIDInputReport, 0, gCurrentDownButtons, &length, |
gPreparsedDataRef, theData, gMaxPacketSize); |
if (status) |
safeprintf("HIDGetButtons error (%d)\n", status); |
safeprintf("%d buttons down: ", length); |
for (i = 0; i < length; i++) |
safeprintf("%d(%d) ", gCurrentDownButtons[i].usage, gCurrentDownButtons[i].usagePage); |
break; |
case kPrint_ParseBoth: |
status = HidP_PrintAllInputValues (0,(HIDPreparsedDataPtr) gPreparsedDataRef, theData, gMaxPacketSize); |
if (status) |
safeprintf("HidP_PrintAllInputValues error (%d)\n", status); |
break; |
case kPrint_SimulateISp: |
for (index = 0; index < gHIDElementCount; index++) |
{ |
value = ParseElementValue (index, theData); |
safeprintf("%ld, ", value); |
} |
break; |
} |
safeprintf(" "); |
safeprintf("\n"); |
} |
OSStatus HidP_PrintAllInputValues |
(UInt32 iCollection, |
HIDPreparsedDataPtr ptPreparsedData, |
char *psReport, |
int iReportLength) |
{ |
HIDCollection *ptCollection; |
HIDReportItem *ptReportItem; |
UInt32 iR, iE, iU; |
SInt32 iValue; |
UInt32 iStart; |
UInt32 iReportItem; |
HIDUsageAndPage tUsageAndPage; |
/* |
* Disallow Null Pointers |
*/ |
if ((ptPreparsedData == NULL) || (psReport == NULL)) |
return kHIDNullPointerErr; |
if (ptPreparsedData->hidTypeIfValid != kHIDOSType) |
return kHIDInvalidPreparsedDataErr; |
/* |
* Search only the scope of the Collection specified |
* Go through the ReportItems |
* Filter on ReportType |
*/ |
ptCollection = &ptPreparsedData->collections[iCollection]; |
#if 0 |
safeprintf ("Collection: count: %d\n", ptCollection->reportItemCount); |
#endif |
for (iR=0; iR<ptCollection->reportItemCount; iR++) |
{ |
iReportItem = ptCollection->firstReportItem + iR; |
ptReportItem = &ptPreparsedData->reportItems[iReportItem]; |
#if 0 |
safeprintf ("Report Item: Type:%d, Size:%d, Start:%d, Count:%d, %s, %s\n", |
ptReportItem->reportType, |
ptReportItem->globals.reportSize, |
ptReportItem->startBit, |
ptReportItem->globals.reportCount, |
(ptReportItem->dataModes & kHIDDataArrayBit) == kHIDDataArray ? "isArray" : "notArray", |
(ptReportItem->dataModes & kHIDDataConstantBit) == kHIDDataConstant ? "isConstant" : "notConstant"); |
#endif |
if ((ptReportItem->reportType == kHIDInputReport) && |
(ptReportItem->dataModes & kHIDDataConstantBit) != kHIDDataConstant) |
{ |
/* |
* Values |
*/ |
if (HIDIsVariable(ptReportItem)) |
{ |
int iUsageItem; |
iStart = ptReportItem->startBit; |
iUsageItem = ptReportItem->firstUsageItem; |
// loop for each usage item |
for (iU=0; iU<ptReportItem->usageItemCount; iU++) |
{ |
OSStatus status = kHIDSuccess; |
HIDP_UsageItem *ptUsageItem; |
ptUsageItem = &ptPreparsedData->usageItems[iU]; |
// if range, loop for each usage in range (is this right???) |
if (ptUsageItem->isRange && false) // ¥¥Êdiabled |
{ |
int iUsageValue, min, max; |
min = ptUsageItem->usageMinimum; |
max = ptUsageItem->usageMaximum; |
if (max < min) |
{ |
int temp; |
temp = min; min = max; max = temp; |
} |
for (iUsageValue = min; iUsageValue <= max; iUsageValue++) |
{ |
status = HIDGetData(psReport, iReportLength, iStart, |
ptReportItem->globals.reportSize, &iValue, |
((ptReportItem->globals.logicalMinimum < 0) |
||(ptReportItem->globals.logicalMaximum < 0))); |
if (status) |
safeprintf ("\nHidP_GetData error = %d\n", status); |
iStart += ptReportItem->globals.reportSize; |
safeprintf("%d:\t%d (%x) ", iUsageValue, iValue, iValue); |
/* |
* Try to scale the data |
*/ |
#if 0 |
status = HIDScaleUsageValueIn(ptReportItem,iValue,&iValue); |
if (status) |
safeprintf ("\nHidP_ScaleUsageValueIn error = %d\n", status); |
else |
safeprintf("[%d (%x)] ", iValue, iValue); |
#endif |
} |
} |
else // not range |
{ |
status = HIDGetData(psReport, iReportLength, iStart, |
ptReportItem->globals.reportSize, &iValue, |
((ptReportItem->globals.logicalMinimum < 0) |
||(ptReportItem->globals.logicalMaximum < 0))); |
if (status) |
safeprintf ("\nHidP_GetData error = %d\n", status); |
iStart += ptReportItem->globals.reportSize; |
safeprintf("%d(%d-%d):\t%d (%x) ", |
ptUsageItem->usage, ptUsageItem->usageMinimum, ptUsageItem->usageMinimum, |
iValue, iValue); |
#if 0 |
/* |
* Try to scale the data |
*/ |
status = HIDScaleUsageValueIn(ptReportItem,iValue,&iValue); |
if (status) |
safeprintf ("\nHidP_ScaleUsageValueIn error = %d\n", status); |
else |
safeprintf("[%d (%x)] ", iValue, iValue); |
#endif |
} |
} |
} |
/* |
* Buttons |
*/ |
else // is button |
{ |
/* |
* Save Arrays and Bitmaps |
*/ |
iStart = ptReportItem->startBit; |
for (iE=0; iE<ptReportItem->globals.reportCount; iE++) |
{ |
OSStatus status = kHIDSuccess; |
#if 0 |
safeprintf ("startbits = %d (%x) of report item %d:%d\n", iStart, iStart, iR, iE); |
#endif |
if ((ptReportItem->dataModes & kHIDDataArrayBit) == kHIDDataArray) |
{ |
status = HIDGetData(psReport, iReportLength, iStart, ptReportItem->globals.reportSize, &iValue, false); |
if (status) |
safeprintf ("\nHidP_GetData error = %d\n", status); |
#if 0 |
else |
safeprintf ("Value = %d (%x) of array item %d:%d\n", iValue, iValue, iE, iR); |
#endif |
iStart += ptReportItem->globals.reportSize; |
HIDUsageAndPageFromIndex((HIDPreparsedDataRef)ptPreparsedData,ptReportItem,ptReportItem->globals.logicalMinimum+iE, &tUsageAndPage); |
safeprintf("%d:%d ", tUsageAndPage.usage, tUsageAndPage.usagePage); |
} |
else |
{ |
iValue = 0; |
status = HIDGetData(psReport, iReportLength, iStart, 1, &iValue, false); |
if (status) |
safeprintf ("\nHidP_GetData error = %d\n", status); |
#if 0 |
else |
safeprintf ("Value = %d (%x) of item %d:%d\n", iValue, iValue, iE, iR); |
#endif |
iStart++; |
if (iValue != 0) |
{ |
HIDUsageAndPageFromIndex((HIDPreparsedDataRef)ptPreparsedData,ptReportItem,ptReportItem->globals.logicalMinimum+iE,&tUsageAndPage); |
safeprintf("%d:%d ", tUsageAndPage.usage, tUsageAndPage.usagePage); |
} |
} |
} |
} |
} |
} |
return kHIDSuccess; |
} |
int safeprintf(const char *format, ...) |
{ |
va_list arglist; |
int return_value = 0; |
long len; |
va_start(arglist, format); |
return_value= vsprintf(&gInsertPrintfBuffer[gInsertIndex], format, arglist); |
va_end(arglist); |
len = strlen(&gInsertPrintfBuffer[gInsertIndex]); |
if (gInsertIndex + len < kPrintfBufferSize) |
gInsertIndex += len; |
return return_value; |
} |
void PrintPreparsedData (void) |
{ |
HIDPreparsedDataPtr parsedData = (HIDPreparsedDataPtr) gPreparsedDataRef; |
char indent[] = " "; |
printf ("\n_Collections_\n"); |
PrintCollectionItems(0, parsedData->collectionCount, indent); |
printf ("\n_ReportItems_\n"); |
PrintReportItems(0, parsedData->reportItemCount, indent); |
printf ("\n_UsageItems_\n"); |
PrintUsageItems(0, parsedData->usageItemCount, indent); |
printf ("\n_StringItems_: %d items\n", parsedData->stringItemCount); |
printf ("\n_DesigItems_: %d items\n", parsedData->desigItemCount); |
if (parsedData->stringItemCount > 0 || parsedData->desigItemCount > 0) |
printf ("¥¥¥ Wow, it has strings or physical designators!\n"); |
printf ("\n\n"); |
} |
void PrintCollectionItems (UInt32 firstCollection, UInt32 collectionCount, char * indent) |
{ |
HIDPreparsedDataPtr parsedData = (HIDPreparsedDataPtr) gPreparsedDataRef; |
unsigned index, start, end; |
char subIndent[32]; |
sprintf (subIndent, "\t%s", indent); |
start = firstCollection; |
end = start + collectionCount; |
if (end > parsedData->collectionCount) |
{ |
printf ("%s¥¥¥!!!collection integrity error! (%d, %d)\n", indent, end, parsedData->collectionCount); |
return; |
} |
else for (index = start; index < end; index++) |
{ |
printf ("%sCollection (%X): %d (parent:%d, children:%d, firstChild:%d, nextSibling:%d)\n", |
indent, |
index, |
parsedData->collections[index].data, |
parsedData->collections[index].parent, |
parsedData->collections[index].children, |
parsedData->collections[index].firstChild, |
parsedData->collections[index].nextSibling); |
// print usage items in collection |
PrintUsageItems (parsedData->collections[index].firstUsageItem, |
parsedData->collections[index].usageItemCount, |
subIndent); |
// print report items in collection |
PrintReportItems (parsedData->collections[index].firstReportItem, |
parsedData->collections[index].reportItemCount, |
subIndent); |
} |
} |
void PrintReportItems (UInt32 firstReportItem, UInt32 reportItemCount, char * indent) |
{ |
HIDPreparsedDataPtr parsedData = (HIDPreparsedDataPtr) gPreparsedDataRef; |
unsigned index, start, end; |
char subIndent[32]; |
sprintf (subIndent, "\t%s", indent); |
start = firstReportItem; |
end = start + reportItemCount; |
if (end > parsedData->reportItemCount) |
{ |
printf ("%s¥¥¥!!!report integrity error! (%d, %d)\n", indent, end, parsedData->reportItemCount); |
return; |
} |
else for (index = start; index < end; index++) |
{ |
printf ("%sReportItem(%d): Page:%d\t(%d<->%d)\t(%d<->%d)\t[%d+(%d*%d)] %s %s\n", |
indent, |
index, |
parsedData->reportItems[index].globals.usagePage, |
parsedData->reportItems[index].globals.logicalMinimum, |
parsedData->reportItems[index].globals.logicalMaximum, |
parsedData->reportItems[index].globals.physicalMinimum, |
parsedData->reportItems[index].globals.physicalMaximum, |
parsedData->reportItems[index].startBit, |
parsedData->reportItems[index].globals.reportSize, |
parsedData->reportItems[index].globals.reportCount, |
(parsedData->reportItems[index].dataModes & kHIDDataConstantBit) ? "isConstant" : "", |
(parsedData->reportItems[index].dataModes & kHIDDataArrayBit) ? "isArray" : ""); |
// print usage items in report item |
PrintUsageItems (parsedData->reportItems[index].firstUsageItem, |
parsedData->reportItems[index].usageItemCount, |
subIndent); |
if (parsedData->reportItems[index].stringItemCount > 0 || parsedData->reportItems[index].desigItemCount > 0) |
printf ("%sWow, it has strings or physical designators!\n", indent); |
} |
} |
void PrintUsageItems (UInt32 firstUsageItem, UInt32 usageItemCount, char * indent) |
{ |
HIDPreparsedDataPtr parsedData = (HIDPreparsedDataPtr) gPreparsedDataRef; |
unsigned index, start, end; |
start = firstUsageItem; |
end = start + usageItemCount; |
if (end > parsedData->usageItemCount) |
{ |
printf ("%s¥¥¥!!!usage integrity error! (%d, %d)\n", indent, end, parsedData->usageItemCount); |
return; |
} |
else for (index = start; index < end; index++) |
{ |
if (parsedData->usageItems[index].isRange) |
printf ("%sUsage(%X): %d-%d\n", indent, index, |
parsedData->usageItems[index].usageMinimum, |
parsedData->usageItems[index].usageMaximum); |
else |
printf ("%sUsage(%d): %d\n", indent, index, parsedData->usageItems[index].usage); |
} |
} |
void SimulateISpEnumeration (void) |
{ |
OSStatus err = noErr; |
UInt32 count; |
// get the overall capabilities of the device |
if (err == noErr) |
err = HIDGetCaps (gPreparsedDataRef, &gHIDCaps); |
// ¥¥¥ for now, only work with devices that appear to be a joystick or gamepad |
if (err == noErr) |
{ |
if (gHIDCaps.usagePage != kHIDPage_Generic || |
(gHIDCaps.usage != kHIDUsage_Joystick && gHIDCaps.usage != kHIDUsage_Gamepad)) |
{ |
printf("¥¥ matched to non-joystick, non-gamepad... bailing out\n"); |
err = fnfErr; |
} |
} |
// allocate space for button caps |
if (err == noErr) |
{ |
gHIDButtonCaps = (HIDButtonCaps *) NewPtrSysClear(sizeof(HIDButtonCaps) * gHIDCaps.numberInputButtonCaps); |
if (gHIDButtonCaps == nil) printf("¥¥ could not allocate space for buttonCaps\n"); |
if (gHIDButtonCaps == nil) err = memFullErr; |
} |
// get the button capabilities |
if (err == noErr) |
{ |
count = gHIDCaps.numberInputButtonCaps; |
err = HIDGetButtonCaps (kHIDInputReport, gHIDButtonCaps, &gHIDCaps.numberInputButtonCaps, gPreparsedDataRef); |
if (count > gHIDCaps.numberInputButtonCaps) |
printf ("¥¥ number of button caps increased! (%d->%d)\n", gHIDCaps.numberInputButtonCaps, count); |
else |
gHIDCaps.numberInputButtonCaps = count; |
} |
// allocate space for value caps |
if (err == noErr) |
{ |
gHIDValueCaps = (HIDValueCaps *) NewPtrSysClear(sizeof(HIDValueCaps) * gHIDCaps.numberInputValueCaps); |
if (gHIDValueCaps == nil) printf("¥¥ could not allocate space for valueCaps\n"); |
if (gHIDValueCaps == nil) err = memFullErr; |
} |
// get the value capabilities |
if (err == noErr) |
err = HIDGetValueCaps (kHIDInputReport, gHIDValueCaps, &gHIDCaps.numberInputValueCaps, gPreparsedDataRef); |
// build HID elements |
if (err == noErr) |
err = BuildHIDElements (); |
// print HID elements |
if (err == noErr) |
err = PrintHIDElements (); |
// report error |
if (err) |
printf ("¥¥Êerror = %d\n", err); |
} |
OSStatus PrintHIDElements (void) |
{ |
UInt32 index; |
printf ("\nHIDElements (%d):\n", gHIDElementCount); |
for (index = 0; index < gHIDElementCount; index++) |
{ |
switch (gHIDElements[index].type) |
{ |
case kButtonElement: |
printf ("%2.2d:Button (%d): %X:%d, key:%d, (%d<->%d), str:%d\n", |
index, |
gHIDElements[index].capsIndex, |
gHIDElements[index].usage, |
gHIDElements[index].usagePage, |
gHIDElements[index].key, |
gHIDElements[index].min, |
gHIDElements[index].max, |
gHIDElements[index].stringIndex |
); |
break; |
case kValueElement: |
printf ("%2.2d:Value (%d): %X:%d, key:%d, (%d<->%d), str:%d\n", |
index, |
gHIDElements[index].capsIndex, |
gHIDElements[index].usage, |
gHIDElements[index].usagePage, |
gHIDElements[index].key, |
gHIDElements[index].min, |
gHIDElements[index].max, |
gHIDElements[index].stringIndex |
); |
break; |
} |
} |
printf ("\n"); |
return noErr; |
} |
OSStatus BuildHIDElements (void) |
{ |
OSStatus err = noErr; |
OSStatus initErr; |
UInt32 hidElementIndex = 0; |
UInt32 valueIndex; |
UInt32 buttonIndex; |
HIDUsage usage; |
// allocate space for HID elements |
if (err == noErr) |
{ |
gHIDElementCount = CountHIDElements(); |
gHIDElements = (HIDElement *) NewPtrSysClear(sizeof(HIDElement) * gHIDElementCount); |
if (gHIDElements == nil) printf("¥¥ could not allocate space for HIDElements\n"); |
if (gHIDElements == nil) err = memFullErr; |
} |
// add all values to the elements |
if (err == noErr) |
for (valueIndex = 0; valueIndex < gHIDCaps.numberInputValueCaps; valueIndex++) |
{ |
HIDElement hidElement; |
if (gHIDValueCaps[valueIndex].reportCount != 1) |
printf("BuildHIDElements: value caps reportCount is not 1!\n"); |
if (gHIDValueCaps[valueIndex].isRange) |
printf("BuildHIDElements: value caps is range!\n"); |
hidElement.type = kValueElement; |
hidElement.capsIndex = valueIndex; |
hidElement.usagePage = gHIDValueCaps[valueIndex].usagePage; |
hidElement.min = gHIDValueCaps[valueIndex].logicalMin; |
hidElement.max = gHIDValueCaps[valueIndex].logicalMax; |
// NOTE: no devices I can find have values that are ranges, so this code may not be right! |
if (gHIDValueCaps[valueIndex].isRange) |
{ |
for (usage = gHIDValueCaps[valueIndex].u.range.usageMin; |
usage <= gHIDValueCaps[valueIndex].u.range.usageMax; |
usage++) |
{ |
hidElement.usage = usage; |
initErr = InitializeHIDElement(&hidElement); |
if (initErr == noErr) |
gHIDElements[hidElementIndex++] = hidElement; |
} |
} |
else // notRange |
{ |
hidElement.usage = gHIDValueCaps[valueIndex].u.notRange.usage; |
initErr = InitializeHIDElement(&hidElement); |
if (initErr == noErr) |
gHIDElements[hidElementIndex++] = hidElement; |
} |
} |
// add all buttons to the elements |
if (err == noErr) |
for (buttonIndex = 0; buttonIndex < gHIDCaps.numberInputButtonCaps; buttonIndex++) |
{ |
HIDElement hidElement; |
hidElement.type = kButtonElement; |
hidElement.capsIndex = buttonIndex; |
hidElement.usagePage = gHIDButtonCaps[buttonIndex].usagePage; |
hidElement.min = 0; |
hidElement.max = 1; |
printf("enumerating button (%d)\n", buttonIndex); |
// most buttons are reported as ranges of usage values |
if (gHIDButtonCaps[buttonIndex].isRange) |
{ |
for (usage = gHIDButtonCaps[buttonIndex].u.range.usageMin; |
usage <= gHIDButtonCaps[buttonIndex].u.range.usageMax; |
usage++) |
{ |
hidElement.usage = usage; |
initErr = InitializeHIDElement(&hidElement); |
if (initErr == noErr) |
gHIDElements[hidElementIndex++] = hidElement; |
} |
} |
else // notRange |
{ |
hidElement.usage = gHIDButtonCaps[buttonIndex].u.notRange.usage; |
initErr = InitializeHIDElement(&hidElement); |
if (initErr == noErr) |
gHIDElements[hidElementIndex++] = hidElement; |
} |
} |
return err; |
} |
UInt32 CountHIDElements(void) |
{ |
OSStatus err = noErr; |
UInt32 count = 0; |
UInt32 valueIndex; |
UInt32 buttonIndex; |
if (err == noErr) |
for (valueIndex = 0; valueIndex < gHIDCaps.numberInputValueCaps; valueIndex++) |
{ |
if (gHIDValueCaps[valueIndex].isRange) |
count += (gHIDValueCaps[valueIndex].u.range.usageMax - gHIDValueCaps[valueIndex].u.range.usageMin) + 1; |
else // notRange |
count++; |
} |
// count all buttons |
if (err == noErr) |
for (buttonIndex = 0; buttonIndex < gHIDCaps.numberInputButtonCaps; buttonIndex++) |
{ |
if (gHIDButtonCaps[buttonIndex].isRange) |
count += (gHIDButtonCaps[buttonIndex].u.range.usageMax - gHIDButtonCaps[buttonIndex].u.range.usageMin) + 1; |
else // notRange |
count++; |
} |
return count; |
} |
OSStatus InitializeHIDElement(HIDElement * hidElement) |
{ |
OSStatus err = noErr; |
SInt32 stringIndex = -1; |
switch (hidElement->type) |
{ |
case kButtonElement: |
if (hidElement->usagePage != kHIDPage_Button) |
printf("InitializeHIDElement: button found not on button page (%d)\n", hidElement->usagePage); |
if (hidElement->usagePage != kHIDPage_Button) |
return kHIDBadParameterErr; |
switch (hidElement->usage) |
{ |
case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: |
case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: |
hidElement->key = kUSB_button1_element + (hidElement->usage - 1); |
stringIndex = kStrList_DefaultNames_Button1 + (hidElement->usage - 1); |
break; |
default: |
return kHIDBadParameterErr; |
} |
break; |
case kValueElement: |
if (hidElement->usagePage == kHIDPage_Generic) |
switch (hidElement->usage) |
{ |
case kHIDUsage_X: |
hidElement->key = kUSB_xaxis_element; |
stringIndex = kStrList_DefaultNames_XAxis; |
break; |
case kHIDUsage_Y: |
hidElement->key = kUSB_yaxis_element; |
stringIndex = kStrList_DefaultNames_YAxis; |
break; |
case kHIDUsage_Z: |
hidElement->key = kUSB_axis_element; |
stringIndex = kStrList_DefaultNames_Axis; |
break; |
case kHIDUsage_Rx: |
hidElement->key = kUSB_axis_element; |
stringIndex = kStrList_DefaultNames_Axis; |
break; |
case kHIDUsage_Ry: |
hidElement->key = kUSB_axis_element; |
stringIndex = kStrList_DefaultNames_Axis; |
break; |
case kHIDUsage_Rz: |
hidElement->key = kUSB_rudder_element; |
stringIndex = kStrList_DefaultNames_Twist; |
break; |
case kHIDUsage_Slider: |
hidElement->key = kUSB_throttle_element; |
stringIndex = kStrList_DefaultNames_Throttle; |
break; |
case kHIDUsage_Dial: |
case kHIDUsage_Wheel: |
hidElement->key = kUSB_trim_element; |
stringIndex = kStrList_DefaultNames_Trim; |
break; |
case kHIDUsage_HatSwitch: |
hidElement->key = kUSB_povhat_element; |
stringIndex = kStrList_DefaultNames_POVHat; |
break; |
} |
else if (hidElement->usagePage == kHIDPage_Simulation) |
switch (hidElement->usage) |
{ |
case kHIDUsage_Rudder: |
hidElement->key = kUSB_rudder_element; |
stringIndex = kStrList_DefaultNames_Rudder; |
break; |
case kHIDUsage_Throttle: |
hidElement->key = kUSB_throttle_element; |
stringIndex = kStrList_DefaultNames_Throttle; |
break; |
} |
break; |
default: |
printf("InitializeHIDElement: unknown type (%d)\n", hidElement->type); |
err = kHIDBadParameterErr; |
break; |
} |
hidElement->stringIndex = stringIndex; |
return err; |
} |
SInt32 ParseElementValue (UInt32 inElementIndex, Ptr inBuffer) |
{ |
OSStatus err = noErr; |
HIDUsage usageList[kUSB_button16_element]; |
UInt32 usageListSize = kUSB_button16_element; |
UInt32 index; |
HIDElement * hidElement = &gHIDElements[inElementIndex]; |
SInt32 usageValue; |
switch (hidElement->type) |
{ |
case kButtonElement: |
// for now, we'll only look at buttons on the button page |
err = HIDGetButtonsOnPage (kHIDInputReport, |
kHIDPage_Button, |
0, |
usageList, |
&usageListSize, |
gPreparsedDataRef, |
inBuffer, |
gMaxPacketSize); |
// confirm we succeeded |
if (err != noErr && err != kHIDUsageNotFoundErr) |
safeprintf ("¥¥ParseElementValue: HIDGetButtonsOnPage failed (%d)", err); |
if (err != noErr) |
break; |
// walk the returned usage list |
for (index = 0; index < usageListSize; index++) |
{ |
// if our usage is in the usage list, then we are down |
if (usageList[index] == hidElement->usage) |
return 1; |
} |
// we were not in the list, so we are up |
return 0; |
case kValueElement: |
// get the usage value |
err = HIDGetUsageValue (kHIDInputReport, |
hidElement->usagePage, |
0, // ¥¥ this might be faster if we store collection and pass here |
hidElement->usage, |
&usageValue, |
gPreparsedDataRef, |
inBuffer, |
gMaxPacketSize); |
// confirm we succeeded |
if (err != noErr && err != kHIDUsageNotFoundErr) |
safeprintf ("¥¥ParseElementValue: HIDGetUsageValue failed (%d)", err); |
if (err != noErr) |
break; |
// handle dpads |
if (false && hidElement->key == kUSB_povhat_element) |
{ |
if (usageValue < hidElement->min || usageValue > hidElement->max) |
usageValue = kISpPadIdle; |
else |
{ |
SInt32 normalized = usageValue - hidElement->min; |
SInt32 normalizedMax = hidElement->max - hidElement->min; |
// avoid devide by zero |
if (normalizedMax == 0) return kISpPadIdle; |
// rescale value |
normalized = ((normalized * 7)) / normalizedMax; |
switch (normalized) |
{ |
case 0: usageValue = kISpPadUp; break; |
case 1: usageValue = kISpPadUpRight; break; |
case 2: usageValue = kISpPadRight; break; |
case 3: usageValue = kISpPadDownRight; break; |
case 4: usageValue = kISpPadDown; break; |
case 5: usageValue = kISpPadDownLeft; break; |
case 6: usageValue = kISpPadLeft; break; |
case 7: usageValue = kISpPadUpLeft; break; |
default:usageValue = kISpPadIdle; break; // should not get here |
} |
} |
} |
return usageValue; |
} |
return 0; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14