1// 2// IOHIDReportDescriptorParser.c 3// IOHIDFamily 4// 5// Created by Rob Yepez on 2/23/13. 6// 7// 8 9#include <string.h> 10#include <limits.h> 11#include <stdarg.h> 12#include <stdio.h> 13#include <stdlib.h> 14#include <unistd.h> 15 16#include <sys/types.h> 17#include <sys/sysctl.h> 18#include <IOKit/hid/IOHIDUsageTables.h> 19#include "IOHIDReportDescriptorParser.h" 20 21#define UnpackReportSize(packedByte) ((packedByte) & 0x03) 22#define UnpackReportType(packedByte) (((packedByte) & 0x0C) >> 2) 23#define UnpackReportTag(packedByte) (((packedByte) & 0xF0) >> 4) 24 25enum 26{ 27 kReport_TypeMain = 0, 28 kReport_TypeGlobal = 1, 29 kReport_TypeLocal = 2, 30 kReport_TypeReserved = 3, 31 32 kReport_TagLongItem = 0x0F, 33 34 // main items 35 kReport_TagInput = 0x08, 36 kReport_TagOutput = 0x09, 37 kReport_TagFeature = 0x0B, 38 kReport_TagCollection = 0x0A, 39 kReport_TagEndCollection = 0x0C, 40 41 // global items 42 kReport_TagUsagePage = 0x00, 43 kReport_TagLogicalMin = 0x01, 44 kReport_TagLogicalMax = 0x02, 45 kReport_TagPhysicalMin = 0x03, 46 kReport_TagPhysicalMax = 0x04, 47 kReport_TagUnitExponent = 0x05, 48 kReport_TagUnit = 0x06, 49 kReport_TagReportSize = 0x07, 50 kReport_TagReportID = 0x08, 51 kReport_TagReportCount = 0x09, 52 kReport_TagPush = 0x0A, 53 kReport_TagPop = 0x0B, 54 55 // local items 56 kReport_TagUsage = 0x00, 57 kReport_TagUsageMin = 0x01, 58 kReport_TagUsageMax = 0x02, 59 kReport_TagDesignatorIndex = 0x03, 60 kReport_TagDesignatorMin = 0x04, 61 kReport_TagDesignatorMax = 0x05, 62 kReport_TagStringIndex = 0x07, 63 kReport_TagStringMin = 0x08, 64 kReport_TagStringMax = 0x09, 65 kReport_TagSetDelimiter = 0x0A 66}; 67 68// Collection constants 69enum 70{ 71 kCollection_Physical = 0x00, 72 kCollection_Application = 0x01, 73 kCollection_Logical = 0x02 74}; 75 76// I/O constants (used for Input/Output/Feature tags) 77enum 78{ 79 kIO_Data_or_Constant = 0x0001, 80 kIO_Array_or_Variable = 0x0002, 81 kIO_Absolute_or_Relative = 0x0004, 82 kIO_NoWrap_or_Wrap = 0x0008, 83 kIO_Linear_or_NonLinear = 0x0010, 84 kIO_PreferredState_or_NoPreferred = 0x0020, 85 kIO_NoNullPosition_or_NullState = 0x0040, 86 kIO_NonVolatile_or_Volatile = 0x0080, // reserved for Input 87 kIO_BitField_or_BufferedBytes = 0x0100 88}; 89 90 91static void PrintAtIndentLevel(unsigned int level, const char * format, ...) 92{ 93 va_list ap; 94 95 for (unsigned int i = 0; i < level; i++) { 96 fputs(" ", stdout); 97 } 98 99 va_start(ap, format); 100 vprintf(format, ap); 101 va_end(ap); 102} 103 104static void PrintBytesAtIndentLevel(unsigned int level, const uint8_t * data, uint32_t length) 105{ 106 uint32_t index; 107 108 for ( index=0; index<length; index+=16 ) { 109 uint32_t innerIndex; 110 uint32_t innerLength = length-index; 111 if ( innerLength > 16 ) 112 innerLength = 16; 113 114 PrintAtIndentLevel(level, "%08X: ", index); 115 for ( innerIndex=0; innerIndex<innerLength; innerIndex++) 116 printf("%02X ", data[index+innerIndex]); 117 118 printf("\n"); 119 } 120} 121 122void PrintHIDDescriptor(const uint8_t *reportDesc, uint32_t length) 123{ 124 const uint8_t * end = reportDesc + length; 125 uint8_t size, type, tag; 126 uint32_t usagePage = 0; 127 uint32_t value=0; 128 int32_t svalue=0; 129 static unsigned char buf[350], tempbuf[350], bufvalue[350], tempbufvalue[350]; 130 int i, indentLevel; 131 int datahandled=0; 132 int itemsigned=0; 133 int len; 134 135 printf("\n"); 136 printf("Raw HID Descriptor:\n"); 137 printf("---------------------------------------------------------\n"); 138 139 PrintBytesAtIndentLevel(0, reportDesc, length); 140 141 printf("\n"); 142 printf("Parsed HID Descriptor:\n"); 143 printf("---------------------------------------------------------\n"); 144 indentLevel = 0; 145 while (reportDesc < end) 146 { 147 int padLevel = 7; 148 149 buf[0] = 0; 150 bufvalue[0] = 0; 151 size = UnpackReportSize(*reportDesc); 152 if (size == 3) size = 4; // 0 == 0 bytes, 1 == 1 bytes, 2 == 2 bytes, but 3 == 4 bytes 153 154 type = UnpackReportType(*reportDesc); 155 tag = UnpackReportTag(*reportDesc); 156 157 sprintf((char *)tempbuf, "0x%02X, ", *(reportDesc++)); 158 strcat((char *)buf, (char *)tempbuf); 159 padLevel--; 160 161 if (tag == kReport_TagLongItem) 162 { 163 size = *reportDesc; 164 sprintf((char *)tempbuf, "0x%02X, ", *(reportDesc++)); 165 strcat((char *)buf, (char *)tempbuf); 166 tag = *reportDesc; 167 sprintf((char *)tempbuf, "0x%02X, ", *(reportDesc++)); 168 strcat((char *)buf, (char *)tempbuf); 169 170 padLevel -= 2; 171 } 172 173 174 // if we're small enough, load the value into a register (byte swaping) 175 if (size <= 4) 176 { 177 value = 0; 178 for (i = 0; i < size; i++) { 179 value += (*(reportDesc)) << (i * 8); 180 sprintf((char *)tempbuf, "0x%02X, ", *(reportDesc++)); 181 strcat((char *)buf, (char *)tempbuf); 182 padLevel--; 183 } 184 185 svalue = 0; 186 switch (size) 187 { 188 case 1: svalue = (int8_t) value; break; 189 case 2: svalue = (int16_t) value; break; 190 191 // if the top bit is set, then sign extend it and fall thru to 32bit case 192 case 3: if (value & 0x00800000) value |= 0xFF000000; // no break 193 case 4: svalue = (int32_t) value; break; 194 } 195 } 196 197 // pad it a bit 198 for (i = 0; i < padLevel; i++) 199 strcat((char *)buf, " "); 200 201 strcat((char *)buf, "// "); 202 203 // indent this line 204 for (i = 0; i < indentLevel; i++) 205 strcat((char *)buf, " "); 206 207 208 // get the name of this tag, and do any specific data handling 209 datahandled = 0; 210 switch (type) 211 { 212 case kReport_TypeMain: 213 switch (tag) 214 { 215 case kReport_TagInput: 216 case kReport_TagOutput: 217 case kReport_TagFeature: 218 switch (tag) 219 { 220 case kReport_TagInput: strcat((char *)buf, "Input..................."); break; 221 case kReport_TagOutput: strcat((char *)buf, "Output.................."); break; 222 case kReport_TagFeature: strcat((char *)buf, "Feature................."); break; 223 } 224 225 strcat((char *)bufvalue, (char *)"("); 226 227 strcat((char *)bufvalue, (value & kIO_Data_or_Constant) ? "Constant, " : "Data, "); 228 229 if ( (value & kIO_Data_or_Constant) == 0 ) { 230 231 strcat((char *)bufvalue, (value & kIO_Array_or_Variable) ? "Variable, ": "Array, "); 232 233 strcat((char *)bufvalue, (value & kIO_Absolute_or_Relative) ? "Relative, " : "Absolute, "); 234 235 if (((tag == kReport_TagInput) && (value & kIO_Array_or_Variable)) || tag != kReport_TagInput) 236 { 237 #if VERBOSE 238 // these are only valid for variable inputs, and feature/output tags 239 strcat((char *)bufvalue, (value & kIO_NoWrap_or_Wrap) ? "Wrap, " : "No Wrap, "); 240 strcat((char *)bufvalue, (value & kIO_Linear_or_NonLinear) ? "Nonlinear, " : "Linear, "); 241 strcat((char *)bufvalue, (value & kIO_PreferredState_or_NoPreferred) ? "No Preferred, " : "Preferred State, "); 242 strcat((char *)bufvalue, (value & kIO_NoNullPosition_or_NullState) ? "Null State, " : "No Null Position, "); 243 244 if (tag != kReport_TagInput) 245 strcat((char *)bufvalue, (value & kIO_NonVolatile_or_Volatile) ? "Volatile, " : "Nonvolatile, "); 246 strcat((char *)bufvalue, (value & kIO_BitField_or_BufferedBytes) ? "Buffered bytes" : "Bitfield"); 247 #else 248 // these are only valid for variable inputs, and feature/output tags 249 strcat((char *)bufvalue, (value & kIO_NoWrap_or_Wrap) ? "Wrap, " : ""); 250 strcat((char *)bufvalue, (value & kIO_Linear_or_NonLinear) ? "Nonlinear, " : ""); 251 strcat((char *)bufvalue, (value & kIO_PreferredState_or_NoPreferred) ? "No Preferred, " : ""); 252 strcat((char *)bufvalue, (value & kIO_NoNullPosition_or_NullState) ? "Null State, " : ""); 253 254 if (tag != kReport_TagInput) 255 strcat((char *)bufvalue, (value & kIO_NonVolatile_or_Volatile) ? "Volatile, " : ""); 256 strcat((char *)bufvalue, (value & kIO_BitField_or_BufferedBytes) ? "Buffered bytes" : ""); 257 #endif 258 } 259 } 260 261 len = strlen((char *)bufvalue); 262 if ( strcmp((const char *)&bufvalue[len-2], ", ") == 0 ) 263 bufvalue[len-2]=0; 264 strcat((char *)bufvalue, (char *)")"); 265 266 tempbuf[0] = 0; // we don't want to add this again outside the switch 267 tempbufvalue[0] = 0; 268 datahandled = 1; 269 break; 270 271 272 case kReport_TagCollection: 273 indentLevel++; 274 275 sprintf((char *)tempbuf, "Collection "); 276 277 strcat((char *)buf, (char *)tempbuf); 278 279 strcat((char *)buf, (char *)"("); 280 switch (value) 281 { 282 case kCollection_Physical: sprintf((char *)tempbuf, "Physical"); break; 283 case kCollection_Application: sprintf((char *)tempbuf, "Application"); break; 284 case kCollection_Logical: sprintf((char *)tempbuf, "Logical"); break; 285 } 286 strcat((char *)buf, (char *)tempbuf); 287 strcat((char *)buf, (char *)")"); 288 289 tempbuf[0] = 0; // we don't want to add this again outside the switch 290 tempbufvalue[0] = 0; 291 datahandled = 1; 292 break; 293 294 case kReport_TagEndCollection: 295 { 296 // recalc indentation, since we want this line to start earlier 297 298 len = strlen((char *)buf); 299 300 if (indentLevel-- && len > 2) { 301 buf[len-2]=0; 302 } 303 304 sprintf((char *)tempbuf, "End Collection "); 305 306 } 307 break; 308 } 309 break; 310 311 case kReport_TypeGlobal: 312 switch (tag) 313 { 314 case kReport_TagUsagePage: 315 strcat((char *)buf, "Usage Page "); 316 usagePage = value; 317 strcat((char *)bufvalue, (char *)"("); 318 switch (usagePage) 319 { 320 case kHIDPage_GenericDesktop: sprintf((char *)tempbufvalue, "Generic Desktop"); break; 321 case kHIDPage_Simulation: sprintf((char *)tempbufvalue, "Simulation Controls"); break; 322 case kHIDPage_VR: sprintf((char *)tempbufvalue, "VR Controls"); break; 323 case kHIDPage_Sport: sprintf((char *)tempbufvalue, "Sports Controls"); break; 324 case kHIDPage_Game: sprintf((char *)tempbufvalue, "Game Controls"); break; 325 case kHIDPage_KeyboardOrKeypad: sprintf((char *)tempbufvalue, "Keyboard/Keypad"); break; 326 case kHIDPage_LEDs: sprintf((char *)tempbufvalue, "LED"); break; 327 case kHIDPage_Button: sprintf((char *)tempbufvalue, "Button"); break; 328 case kHIDPage_Ordinal: sprintf((char *)tempbufvalue, "Ordinal"); break; 329 case kHIDPage_Telephony: sprintf((char *)tempbufvalue, "Telephony Device"); break; 330 case kHIDPage_Consumer: sprintf((char *)tempbufvalue, "Consumer"); break; 331 case kHIDPage_Digitizer: sprintf((char *)tempbufvalue, "Digitizer"); break; 332 case kHIDPage_PID: sprintf((char *)tempbufvalue, "PID"); break; 333 case kHIDPage_Unicode: sprintf((char *)tempbufvalue, "Unicode"); break; 334 case kHIDPage_AlphanumericDisplay: sprintf((char *)tempbufvalue, "Alphanumeric Display"); break; 335 case kHIDPage_Monitor: sprintf((char *)tempbufvalue, "Monitor"); break; 336 case kHIDPage_MonitorEnumerated: sprintf((char *)tempbufvalue, "Monitor Enumerated Values"); break; 337 case kHIDPage_MonitorVirtual: sprintf((char *)tempbufvalue, "VESA Virtual Controls"); break; 338 case kHIDPage_MonitorReserved: sprintf((char *)tempbufvalue, "Monitor Class reserved"); break; 339 case kHIDPage_PowerDevice: sprintf((char *)tempbufvalue, "Power Device"); break; 340 case kHIDPage_BatterySystem: sprintf((char *)tempbufvalue, "Battery System"); break; 341 case kHIDPage_PowerReserved: sprintf((char *)tempbufvalue, "Power Class reserved"); break; 342 case kHIDPage_PowerReserved2: sprintf((char *)tempbufvalue, "Power Class reserved"); break; 343 case 0xff: sprintf((char *)tempbufvalue, "Vendor Defined"); break; 344 345 default: sprintf((char *)tempbufvalue, "%u", usagePage); break; 346 } 347 348 //strcat((char *)buf, (char *)tempbuf); 349 strcat((char *)bufvalue, (char *)tempbufvalue); 350 strcat((char *)bufvalue, (char *)")"); 351 tempbuf[0] = 0; // we don't want to add this again outside the switch 352 tempbufvalue[0] = 0; 353 datahandled = 1; 354 break; 355 356 case kReport_TagLogicalMin: sprintf((char *)tempbuf, "Logical Minimum......... "); itemsigned=1; break; 357 case kReport_TagLogicalMax: sprintf((char *)tempbuf, "Logical Maximum......... "); itemsigned=1; break; 358 case kReport_TagPhysicalMin: sprintf((char *)tempbuf, "Physical Minimum........ "); itemsigned=1; break; 359 case kReport_TagPhysicalMax: sprintf((char *)tempbuf, "Physical Maximum........ "); itemsigned=1; break; 360 case kReport_TagUnitExponent: sprintf((char *)tempbuf, "Unit Exponent........... "); break; 361 case kReport_TagUnit: sprintf((char *)tempbuf, "Unit.................... "); break; 362 case kReport_TagReportSize: sprintf((char *)tempbuf, "Report Size............. "); break; 363 case kReport_TagReportID: sprintf((char *)tempbuf, "ReportID................ "); break; 364 case kReport_TagReportCount: sprintf((char *)tempbuf, "Report Count............ "); break; 365 case kReport_TagPush: sprintf((char *)tempbuf, "Push.................... "); break; 366 case kReport_TagPop: sprintf((char *)tempbuf, "Pop..................... "); break; 367 } 368 break; 369 370 case kReport_TypeLocal: 371 switch (tag) 372 { 373 case kReport_TagUsage: 374 sprintf((char *)tempbuf, "Usage "); 375 strcat((char *)buf, (char *)tempbuf); 376 if (usagePage == kHIDPage_GenericDesktop) 377 { 378 strcat((char *)buf, (char *)"("); 379 switch (value) 380 { 381 case kHIDUsage_GD_Pointer: sprintf((char *)tempbuf, "Pointer"); break; 382 case kHIDUsage_GD_Mouse: sprintf((char *)tempbuf, "Mouse"); break; 383 case kHIDUsage_GD_Joystick: sprintf((char *)tempbuf, "Joystick"); break; 384 case kHIDUsage_GD_GamePad: sprintf((char *)tempbuf, "GamePad"); break; 385 case kHIDUsage_GD_Keyboard: sprintf((char *)tempbuf, "Keyboard"); break; 386 case kHIDUsage_GD_Keypad: sprintf((char *)tempbuf, "Keypad"); break; 387 case kHIDUsage_GD_MultiAxisController: sprintf((char *)tempbuf, "MultiAxisController"); break; 388 389 case kHIDUsage_GD_X: sprintf((char *)tempbuf, "X"); break; 390 case kHIDUsage_GD_Y: sprintf((char *)tempbuf, "Y"); break; 391 case kHIDUsage_GD_Z: sprintf((char *)tempbuf, "Z"); break; 392 case kHIDUsage_GD_Rx: sprintf((char *)tempbuf, "Rx"); break; 393 case kHIDUsage_GD_Ry: sprintf((char *)tempbuf, "Ry"); break; 394 case kHIDUsage_GD_Rz: sprintf((char *)tempbuf, "Rz"); break; 395 case kHIDUsage_GD_Slider: sprintf((char *)tempbuf, "Slider"); break; 396 case kHIDUsage_GD_Dial: sprintf((char *)tempbuf, "Dial"); break; 397 case kHIDUsage_GD_Wheel: sprintf((char *)tempbuf, "Wheel"); break; 398 case kHIDUsage_GD_Hatswitch: sprintf((char *)tempbuf, "Hat Switch"); break; 399 case kHIDUsage_GD_CountedBuffer: sprintf((char *)tempbuf, "Counted Buffer"); break; 400 case kHIDUsage_GD_ByteCount: sprintf((char *)tempbuf, "Byte Count"); break; 401 case kHIDUsage_GD_MotionWakeup: sprintf((char *)tempbuf, "Motion Wakeup"); break; 402 403 case kHIDUsage_GD_Vx: sprintf((char *)tempbuf, "Vx"); break; 404 case kHIDUsage_GD_Vy: sprintf((char *)tempbuf, "Vy"); break; 405 case kHIDUsage_GD_Vz: sprintf((char *)tempbuf, "Vz"); break; 406 case kHIDUsage_GD_Vbrx: sprintf((char *)tempbuf, "Vbrx"); break; 407 case kHIDUsage_GD_Vbry: sprintf((char *)tempbuf, "Vbry"); break; 408 case kHIDUsage_GD_Vbrz: sprintf((char *)tempbuf, "Vbrz"); break; 409 case kHIDUsage_GD_Vno: sprintf((char *)tempbuf, "Vno"); break; 410 411 case kHIDUsage_GD_SystemControl: sprintf((char *)tempbuf, "System Control"); break; 412 case kHIDUsage_GD_SystemPowerDown: sprintf((char *)tempbuf, "System Power Down"); break; 413 case kHIDUsage_GD_SystemSleep: sprintf((char *)tempbuf, "System Sleep"); break; 414 case kHIDUsage_GD_SystemWakeUp: sprintf((char *)tempbuf, "System Wakeup"); break; 415 case kHIDUsage_GD_SystemContextMenu: sprintf((char *)tempbuf, "System Context Menu"); break; 416 case kHIDUsage_GD_SystemMainMenu: sprintf((char *)tempbuf, "System Main Menu"); break; 417 case kHIDUsage_GD_SystemAppMenu: sprintf((char *)tempbuf, "System App Menu"); break; 418 case kHIDUsage_GD_SystemMenuHelp: sprintf((char *)tempbuf, "System Menu Help"); break; 419 case kHIDUsage_GD_SystemMenuExit: sprintf((char *)tempbuf, "System Menu Exit"); break; 420 case kHIDUsage_GD_SystemMenuSelect: sprintf((char *)tempbuf, "System Menu Select"); break; 421 case kHIDUsage_GD_SystemMenuRight: sprintf((char *)tempbuf, "System Menu Right"); break; 422 case kHIDUsage_GD_SystemMenuLeft: sprintf((char *)tempbuf, "System Menu Left"); break; 423 case kHIDUsage_GD_SystemMenuUp: sprintf((char *)tempbuf, "System Menu Up"); break; 424 case kHIDUsage_GD_SystemMenuDown: sprintf((char *)tempbuf, "System Menu Down"); break; 425 426 default: sprintf((char *)tempbuf, "%d (0x%x)", (int)value, (unsigned int)value); break; 427 } 428 strcat((char *)tempbuf, (char *)")"); 429 } 430 else if (usagePage == kHIDPage_Digitizer) 431 { 432 strcat((char *)buf, (char *)"("); 433 switch (value) 434 { 435 case kHIDUsage_Dig_Digitizer: sprintf((char *)tempbuf, "Digitizer"); break; 436 case kHIDUsage_Dig_Pen: sprintf((char *)tempbuf, "Pen"); break; 437 case kHIDUsage_Dig_LightPen: sprintf((char *)tempbuf, "Light Pen"); break; 438 case kHIDUsage_Dig_TouchScreen: sprintf((char *)tempbuf, "Touch Screen"); break; 439 case kHIDUsage_Dig_TouchPad: sprintf((char *)tempbuf, "Touch Pad"); break; 440 case kHIDUsage_Dig_WhiteBoard: sprintf((char *)tempbuf, "White Board"); break; 441 case kHIDUsage_Dig_CoordinateMeasuringMachine: sprintf((char *)tempbuf, "Coordinate Measuring Machine"); break; 442 case kHIDUsage_Dig_3DDigitizer: sprintf((char *)tempbuf, "3D Digitizer"); break; 443 case kHIDUsage_Dig_StereoPlotter: sprintf((char *)tempbuf, "Stereo Plotter"); break; 444 case kHIDUsage_Dig_ArticulatedArm: sprintf((char *)tempbuf, "Articulated Arm"); break; 445 case kHIDUsage_Dig_Armature: sprintf((char *)tempbuf, "Armature"); break; 446 case kHIDUsage_Dig_MultiplePointDigitizer: sprintf((char *)tempbuf, "Multi Point Digitizer"); break; 447 case kHIDUsage_Dig_FreeSpaceWand: sprintf((char *)tempbuf, "Free Space Wand"); break; 448 case kHIDUsage_Dig_DeviceConfiguration: sprintf((char *)tempbuf, "Device Configuration"); break; 449 case kHIDUsage_Dig_Stylus: sprintf((char *)tempbuf, "Stylus"); break; 450 case kHIDUsage_Dig_Puck: sprintf((char *)tempbuf, "Puck"); break; 451 case kHIDUsage_Dig_Finger: sprintf((char *)tempbuf, "Finger"); break; 452 case kHIDUsage_Dig_DeviceSettings: sprintf((char *)tempbuf, "Device Settings"); break; 453 case kHIDUsage_Dig_GestureCharacter: sprintf((char *)tempbuf, "Gesture Character"); break; 454 case kHIDUsage_Dig_TipPressure: sprintf((char *)tempbuf, "Tip Pressure"); break; 455 case kHIDUsage_Dig_BarrelPressure: sprintf((char *)tempbuf, "Barrel Pressure"); break; 456 case kHIDUsage_Dig_InRange: sprintf((char *)tempbuf, "In Range"); break; 457 case kHIDUsage_Dig_Touch: sprintf((char *)tempbuf, "Touch"); break; 458 case kHIDUsage_Dig_Untouch: sprintf((char *)tempbuf, "Untouch"); break; 459 case kHIDUsage_Dig_Tap: sprintf((char *)tempbuf, "Tap"); break; 460 case kHIDUsage_Dig_Quality: sprintf((char *)tempbuf, "Quality"); break; 461 case kHIDUsage_Dig_DataValid: sprintf((char *)tempbuf, "Data Valid"); break; 462 case kHIDUsage_Dig_TransducerIndex: sprintf((char *)tempbuf, "Transducer Index"); break; 463 case kHIDUsage_Dig_TabletFunctionKeys: sprintf((char *)tempbuf, "Tablet Function Keys"); break; 464 case kHIDUsage_Dig_ProgramChangeKeys: sprintf((char *)tempbuf, "Program Change Buttons"); break; 465 case kHIDUsage_Dig_BatteryStrength: sprintf((char *)tempbuf, "Battery Strength"); break; 466 case kHIDUsage_Dig_Invert: sprintf((char *)tempbuf, "Invert"); break; 467 case kHIDUsage_Dig_XTilt: sprintf((char *)tempbuf, "X Tilt"); break; 468 case kHIDUsage_Dig_YTilt: sprintf((char *)tempbuf, "Y Tilt"); break; 469 case kHIDUsage_Dig_Azimuth: sprintf((char *)tempbuf, "Azimuth"); break; 470 case kHIDUsage_Dig_Altitude: sprintf((char *)tempbuf, "Altitude"); break; 471 case kHIDUsage_Dig_Twist: sprintf((char *)tempbuf, "Twist"); break; 472 case kHIDUsage_Dig_TipSwitch: sprintf((char *)tempbuf, "Tip Switch"); break; 473 case kHIDUsage_Dig_SecondaryTipSwitch: sprintf((char *)tempbuf, "Secondary Tip Switch"); break; 474 case kHIDUsage_Dig_BarrelSwitch: sprintf((char *)tempbuf, "Barrel Switch"); break; 475 case kHIDUsage_Dig_Eraser: sprintf((char *)tempbuf, "Eraser"); break; 476 case kHIDUsage_Dig_TabletPick: sprintf((char *)tempbuf, "Tablet Pick"); break; 477 case kHIDUsage_Dig_TouchValid: sprintf((char *)tempbuf, "Touch Valid"); break; 478 case kHIDUsage_Dig_Width: sprintf((char *)tempbuf, "Width"); break; 479 case kHIDUsage_Dig_Height: sprintf((char *)tempbuf, "Height"); break; 480 case kHIDUsage_Dig_GestureCharacterEnable: sprintf((char *)tempbuf, "Gesture Character Enable"); break; 481 case kHIDUsage_Dig_GestureCharacterQuality: sprintf((char *)tempbuf, "Gesture Character Quality"); break; 482 case kHIDUsage_Dig_GestureCharacterDataLength: sprintf((char *)tempbuf, "Gesture Character Data Length"); break; 483 case kHIDUsage_Dig_GestureCharacterData: sprintf((char *)tempbuf, "Gesture Character Data"); break; 484 case kHIDUsage_Dig_GestureCharacterEncoding: sprintf((char *)tempbuf, "Gesture Character Encoding"); break; 485 case kHIDUsage_Dig_GestureCharacterEncodingUTF8: sprintf((char *)tempbuf, "Gesture Character Encoding UTF8"); break; 486 case kHIDUsage_Dig_GestureCharacterEncodingUTF16LE: sprintf((char *)tempbuf, "Gesture Character Encoding UTF16 Little Endian"); break; 487 case kHIDUsage_Dig_GestureCharacterEncodingUTF16BE: sprintf((char *)tempbuf, "Gesture Character Encoding UTF16 Big Endian"); break; 488 case kHIDUsage_Dig_GestureCharacterEncodingUTF32LE: sprintf((char *)tempbuf, "Gesture Character Encoding UTF32 Little Endian"); break; 489 case kHIDUsage_Dig_GestureCharacterEncodingUTF32BE: sprintf((char *)tempbuf, "Gesture Character Encoding UTF32 Big Endian"); break; 490 491 default: sprintf((char *)tempbuf, "%d (0x%x)", (int)value, (unsigned int)value); break; 492 } 493 strcat((char *)tempbuf, (char *)")"); 494 } 495 else if (usagePage == kHIDPage_PID) 496 { 497 strcat((char *)buf, (char *)"("); 498 switch (value) 499 { 500 case 1: sprintf((char *)tempbuf, "Physical Interface Device"); break; 501 case 0x20: sprintf((char *)tempbuf, "Normal"); break; 502 case 0x21: sprintf((char *)tempbuf, "Set Effect Report"); break; 503 case 0x22: sprintf((char *)tempbuf, "Effect Block Index"); break; 504 case 0x23: sprintf((char *)tempbuf, "Parameter Block Offset"); break; 505 case 0x24: sprintf((char *)tempbuf, "ROM Flag"); break; 506 case 0x25: sprintf((char *)tempbuf, "Effect Type"); break; 507 case 0x26: sprintf((char *)tempbuf, "ET Constant Force"); break; 508 case 0x27: sprintf((char *)tempbuf, "ET Ramp"); break; 509 case 0x28: sprintf((char *)tempbuf, "ET Custom Force Data"); break; 510 case 0x30: sprintf((char *)tempbuf, "ET Square"); break; 511 case 0x31: sprintf((char *)tempbuf, "ET Sine"); break; 512 case 0x32: sprintf((char *)tempbuf, "ET Triangle"); break; 513 case 0x33: sprintf((char *)tempbuf, "ET Sawtooth Up"); break; 514 case 0x34: sprintf((char *)tempbuf, "ET Sawtooth Down"); break; 515 case 0x40: sprintf((char *)tempbuf, "ET Spring"); break; 516 case 0x41: sprintf((char *)tempbuf, "ET Damper"); break; 517 case 0x42: sprintf((char *)tempbuf, "ET Inertia"); break; 518 case 0x43: sprintf((char *)tempbuf, "ET Friction"); break; 519 case 0x50: sprintf((char *)tempbuf, "Duration"); break; 520 case 0x51: sprintf((char *)tempbuf, "Sample Period"); break; 521 case 0x52: sprintf((char *)tempbuf, "Gain"); break; 522 case 0x53: sprintf((char *)tempbuf, "Trigger Button"); break; 523 case 0x54: sprintf((char *)tempbuf, "Trigger Repeat Interval"); break; 524 case 0x55: sprintf((char *)tempbuf, "Axes Enable"); break; 525 case 0x56: sprintf((char *)tempbuf, "Direction Enable"); break; 526 case 0x57: sprintf((char *)tempbuf, "Direction"); break; 527 case 0x58: sprintf((char *)tempbuf, "Type Specific Block Offset"); break; 528 case 0x59: sprintf((char *)tempbuf, "Block Type"); break; 529 case 0x5a: sprintf((char *)tempbuf, "Set Envelope Report"); break; 530 case 0x5b: sprintf((char *)tempbuf, "Attack Level"); break; 531 case 0x5c: sprintf((char *)tempbuf, "Attack Time"); break; 532 case 0x5d: sprintf((char *)tempbuf, "Fade Level"); break; 533 case 0x5e: sprintf((char *)tempbuf, "Fade Time"); break; 534 case 0x5f: sprintf((char *)tempbuf, "Set Condition Report"); break; 535 case 0x60: sprintf((char *)tempbuf, "CP Offset"); break; 536 case 0x61: sprintf((char *)tempbuf, "Positive Coefficient"); break; 537 case 0x62: sprintf((char *)tempbuf, "Negative Coefficient"); break; 538 case 0x63: sprintf((char *)tempbuf, "Positive Saturation"); break; 539 case 0x64: sprintf((char *)tempbuf, "Negative Saturation"); break; 540 case 0x65: sprintf((char *)tempbuf, "Dead Band"); break; 541 case 0x66: sprintf((char *)tempbuf, "Download Force Data Report"); break; 542 case 0x67: sprintf((char *)tempbuf, "Isoch Custom Force Enable"); break; 543 case 0x68: sprintf((char *)tempbuf, "Custom Force Data Report"); break; 544 case 0x69: sprintf((char *)tempbuf, "Custom Force Data"); break; 545 case 0x6a: sprintf((char *)tempbuf, "Custom Force Vendor Defined Data"); break; 546 case 0x6b: sprintf((char *)tempbuf, "Set Custom Force Report"); break; 547 case 0x6c: sprintf((char *)tempbuf, "Custom Force Data Offset"); break; 548 case 0x6d: sprintf((char *)tempbuf, "Sample Count"); break; 549 case 0x6e: sprintf((char *)tempbuf, "Set Periodic Report"); break; 550 case 0x6f: sprintf((char *)tempbuf, "Offset"); break; 551 case 0x70: sprintf((char *)tempbuf, "Magnitude"); break; 552 case 0x71: sprintf((char *)tempbuf, "Phase"); break; 553 case 0x72: sprintf((char *)tempbuf, "Period"); break; 554 case 0x73: sprintf((char *)tempbuf, "Set Constant Force Report"); break; 555 case 0x74: sprintf((char *)tempbuf, "Set Constant Force"); break; 556 case 0x75: sprintf((char *)tempbuf, "Ramp Start"); break; 557 case 0x76: sprintf((char *)tempbuf, "Ramp End"); break; 558 case 0x77: sprintf((char *)tempbuf, "Effect Operation Report"); break; 559 case 0x78: sprintf((char *)tempbuf, "Effect Operation"); break; 560 case 0x79: sprintf((char *)tempbuf, "Op Effect Start"); break; 561 case 0x7a: sprintf((char *)tempbuf, "Op Effect Start Solo"); break; 562 case 0x7b: sprintf((char *)tempbuf, "Op Effect Stop"); break; 563 case 0x7c: sprintf((char *)tempbuf, "Loop Count"); break; 564 case 0x7d: sprintf((char *)tempbuf, "Gain Report"); break; 565 case 0x7e: sprintf((char *)tempbuf, "Gain"); break; 566 case 0x7f: sprintf((char *)tempbuf, "PID Pool Report"); break; 567 case 0x80: sprintf((char *)tempbuf, "RAM Pool Size"); break; 568 case 0x81: sprintf((char *)tempbuf, "ROM Pool Size"); break; 569 case 0x82: sprintf((char *)tempbuf, "ROM Effect Block Count"); break; 570 case 0x83: sprintf((char *)tempbuf, "Simultaneous Effects Max"); break; 571 case 0x84: sprintf((char *)tempbuf, "Pool Alignment"); break; 572 case 0x85: sprintf((char *)tempbuf, "PID Pool Move Report"); break; 573 case 0x86: sprintf((char *)tempbuf, "Move Source"); break; 574 case 0x87: sprintf((char *)tempbuf, "Move Destination"); break; 575 case 0x88: sprintf((char *)tempbuf, "Move Length"); break; 576 case 0x89: sprintf((char *)tempbuf, "PID Block Load Report"); break; 577 case 0x8b: sprintf((char *)tempbuf, "Block Load Status"); break; 578 case 0x8c: sprintf((char *)tempbuf, "Block Load Success"); break; 579 case 0x8d: sprintf((char *)tempbuf, "Block Load Full"); break; 580 case 0x8e: sprintf((char *)tempbuf, "Block Load Error"); break; 581 case 0x8f: sprintf((char *)tempbuf, "Block Handle"); break; 582 case 0x90: sprintf((char *)tempbuf, "PID Block Free Report"); break; 583 case 0x91: sprintf((char *)tempbuf, "Type Specific Block Handle"); break; 584 case 0x92: sprintf((char *)tempbuf, "PID State Report"); break; 585 case 0x94: sprintf((char *)tempbuf, "Effect Playing"); break; 586 case 0x95: sprintf((char *)tempbuf, "PID Device Control Report"); break; 587 case 0x96: sprintf((char *)tempbuf, "PID Device Control"); break; 588 case 0x97: sprintf((char *)tempbuf, "DC Enable Actuators"); break; 589 case 0x98: sprintf((char *)tempbuf, "DC Disable Actuators"); break; 590 case 0x99: sprintf((char *)tempbuf, "DC Stoop All Effects"); break; 591 case 0x9a: sprintf((char *)tempbuf, "DC Device Reset"); break; 592 case 0x9b: sprintf((char *)tempbuf, "DC Device Pause"); break; 593 case 0x9c: sprintf((char *)tempbuf, "DC Device Continue"); break; 594 case 0x9f: sprintf((char *)tempbuf, "Device Paused"); break; 595 case 0xa0: sprintf((char *)tempbuf, "Actuators Enabled"); break; 596 case 0xa4: sprintf((char *)tempbuf, "Safety Switch"); break; 597 case 0xa5: sprintf((char *)tempbuf, "Actuator Override Switch"); break; 598 case 0xa6: sprintf((char *)tempbuf, "Actuator Power"); break; 599 case 0xa7: sprintf((char *)tempbuf, "Start Delay"); break; 600 case 0xa8: sprintf((char *)tempbuf, "Parameter Block Size"); break; 601 case 0xa9: sprintf((char *)tempbuf, "Device Managed Pool"); break; 602 case 0xaa: sprintf((char *)tempbuf, "Shared parameter blocks"); break; 603 case 0xab: sprintf((char *)tempbuf, "Create New Effect Report"); break; 604 case 0xac: sprintf((char *)tempbuf, "RAM Pool Available"); break; 605 606 607 default: sprintf((char *)tempbuf, "%d (0x%x)", (int)value, (unsigned int)value); break; 608 } 609 strcat((char *)tempbuf, (char *)")"); 610 } 611 else 612 { 613 sprintf((char *)tempbuf, "%d (0x%x)", (int)value, (unsigned int)value); 614 } 615 616 strcat((char *)buf, (char *)tempbuf); 617 tempbuf[0] = 0; // we don't want to add this again outside the switch 618 tempbufvalue[0] = 0; 619 datahandled = 1; 620 break; 621 622 case kReport_TagUsageMin: sprintf((char *)tempbuf, "Usage Minimum........... "); break; 623 case kReport_TagUsageMax: sprintf((char *)tempbuf, "Usage Maximum........... "); break; 624 case kReport_TagDesignatorIndex: sprintf((char *)tempbuf, "Designator Index........ "); break; 625 case kReport_TagDesignatorMin: sprintf((char *)tempbuf, "Designator Minumum...... "); break; 626 case kReport_TagDesignatorMax: sprintf((char *)tempbuf, "Designator Maximum...... "); break; 627 case kReport_TagStringIndex: sprintf((char *)tempbuf, "String Index............ "); break; 628 case kReport_TagStringMin: sprintf((char *)tempbuf, "String Minimum.......... "); break; 629 case kReport_TagStringMax: sprintf((char *)tempbuf, "String Maximum.......... "); break; 630 case kReport_TagSetDelimiter: sprintf((char *)tempbuf, "Set Delimiter........... "); break; 631 } 632 break; 633 634 case kReport_TypeReserved: 635 sprintf((char *)tempbuf, "Reserved "); break; 636 break; 637 } 638 639 // actually put in the data from the switch -- why not just strcat there?? 640 strcat((char *)buf, (char *)tempbuf); 641 642 // if we didn't handle the data before, print in generic fashion 643 if (!datahandled ) 644 { 645 if (size) { 646 strcat((char *)bufvalue, (char *)"("); 647 if (size <= 4) 648 { 649 if (itemsigned) 650 { 651 sprintf((char *)tempbufvalue, "%d", (int32_t)svalue); 652 } 653 else 654 { 655 sprintf((char *)tempbufvalue, "%u", (uint32_t)value); 656 } 657 strcat((char *)bufvalue, (char *)tempbufvalue); 658 } 659 else 660 for (i = 0; i < size; i++) 661 { 662 sprintf((char *)tempbufvalue, "%02X ", *(reportDesc++)); 663 strcat((char *)bufvalue, (char *)tempbufvalue); 664 } 665 strcat((char *)bufvalue, (char *)") "); 666 } 667 itemsigned=0; 668 } 669 670 671 // finally add the info 672 strcat((char *)bufvalue, " "); // in case bufvalue was empty, add a blank space 673 674 675 // this juggling is because the End Collection tags were not nested deep enough in the OutlineView. 676 677 /* if (tag == kReport_TagEndCollection) { 678 [self PrintKeyVal:buf val:bufvalue forDevice:deviceNumber atDepth:depth+indentLevel+1 forNode:node]; 679 } 680 else 681 [self PrintKeyVal:buf val:bufvalue forDevice:deviceNumber atDepth:depth+indentLevel forNode:node];*/ 682 683 printf("%s%s\n",buf, bufvalue); 684 } 685} 686