00001 #include <stdio.h>
00002 #include <unistd.h>
00003 #include <stdlib.h>
00004 #include <ctype.h>
00005 #include <sys/errno.h>
00006 #include <sysexits.h>
00007 #include <IOKit/hid/IOHIDLib.h>
00008
00009
00010
00011
00012 #include "ysjoyreader.h"
00013
00014
00015 YsJoyReaderElement::YsJoyReaderElement()
00016 {
00017 exist=0;
00018 elem=NULL;
00019 value=0;
00020 }
00021
00022 YsJoyReaderAxis::YsJoyReaderAxis()
00023 {
00024 min=0;
00025 max=0;
00026 scaledMin=0;
00027 scaledMax=0;
00028 calibCenter=0;
00029 calibMin=0;
00030 calibMax=0;
00031 }
00032
00033 double YsJoyReaderAxis::GetCalibratedValue(void) const
00034 {
00035 double calib;
00036
00037 if(calibCenter<value && calibMax!=calibCenter)
00038 {
00039 calib=(double)(value-calibCenter)/(double)(calibMax-calibCenter);
00040 }
00041 else if(value<calibCenter && calibMin!=calibCenter)
00042 {
00043 calib=(double)(value-calibCenter)/(double)(calibCenter-calibMin);
00044 }
00045 else
00046 {
00047 return 0.0;
00048 }
00049
00050 if(calib>1.0)
00051 {
00052 calib=1.0;
00053 }
00054 if(calib<-1.0)
00055 {
00056 calib=-1.0;
00057 }
00058
00059 return calib;
00060 }
00061
00062 void YsJoyReaderAxis::CaptureCenter(void)
00063 {
00064 calibCenter=value;
00065 }
00066
00067 void YsJoyReaderAxis::BeginCaptureMinMax(void)
00068 {
00069 calibMin=calibCenter+1000;
00070 calibMax=calibCenter-1000;
00071 }
00072
00073 void YsJoyReaderAxis::CaptureMinMax(void)
00074 {
00075 if(value<calibMin)
00076 {
00077 calibMin=value;
00078 }
00079 if(value>calibMax)
00080 {
00081 calibMax=value;
00082 }
00083 }
00084
00085 void YsJoyReaderAxis::CenterFromMinMax(void)
00086 {
00087 calibCenter=(calibMin+calibMax)/2;
00088 }
00089
00090 YsJoyReaderButton::YsJoyReaderButton()
00091 {
00092 }
00093
00094 YsJoyReaderHatSwitch::YsJoyReaderHatSwitch()
00095 {
00096 valueNeutral=0;
00097 value0Deg=1;
00098 value90Deg=3;
00099 value180Deg=5;
00100 value270Deg=7;
00101 }
00102
00103 int YsJoyReaderHatSwitch::GetDiscreteValue(void) const
00104 {
00105 if(value==valueNeutral)
00106 {
00107 return 0;
00108 }
00109 else if(value==value0Deg)
00110 {
00111 return 1;
00112 }
00113 else if(value==value90Deg)
00114 {
00115 return 3;
00116 }
00117 else if(value==value180Deg)
00118 {
00119 return 5;
00120 }
00121 else if(value270Deg==value)
00122 {
00123 return 7;
00124 }
00125 else if(value0Deg<value && value<value90Deg)
00126 {
00127 return 2;
00128 }
00129 else if(value90Deg<value && value<value180Deg)
00130 {
00131 return 4;
00132 }
00133 else if(value180Deg<value && value<value270Deg)
00134 {
00135 return 6;
00136 }
00137 else if(value270Deg<value)
00138 {
00139 return 8;
00140 }
00141 return 0;
00142 }
00143
00144
00145 IOHIDManagerRef YsJoyReader::hidManager=NULL;
00146 CFMutableArrayRef YsJoyReader::devArray=NULL;
00147
00148 YsJoyReader::YsJoyReader()
00149 {
00150 hidDev=NULL;
00151 }
00152
00153 int YsJoyReader::SetUpInterface(int joyId,IOHIDDeviceRef hidDev)
00154 {
00155 this->joyId=joyId;
00156
00157 if(hidDev!=NULL)
00158 {
00159 CFArrayRef elemAry=IOHIDDeviceCopyMatchingElements(hidDev,NULL,0);
00160 int nElem=(int)CFArrayGetCount(elemAry);
00161 int isMouse=0,isJoystick=0,isKeyboard=0,isGamePad=0;
00162
00163 printf("This HID Device has %d elements.\n",nElem);
00164
00165 int j;
00166 for(j=0; j<nElem; j++)
00167 {
00168 IOHIDElementRef elem=(IOHIDElementRef)CFArrayGetValueAtIndex(elemAry,j);
00169 IOHIDElementType elemType=IOHIDElementGetType(elem);
00170 unsigned int usage=IOHIDElementGetUsage(elem);
00171 unsigned int usagePage=IOHIDElementGetUsagePage(elem);
00172
00173 printf("Element %3d",j);
00174 switch(elemType)
00175 {
00176 case kIOHIDElementTypeInput_ScanCodes:
00177 printf(" ScanCode ");
00178 break;
00179 case kIOHIDElementTypeInput_Misc:
00180 printf(" Misc ");
00181 break;
00182 case kIOHIDElementTypeInput_Button:
00183 printf(" Button ");
00184 break;
00185 case kIOHIDElementTypeInput_Axis:
00186 printf(" Axis ");
00187 break;
00188 case kIOHIDElementTypeOutput:
00189 printf(" Output ");
00190 break;
00191 case kIOHIDElementTypeFeature:
00192 printf(" Feature ");
00193 break;
00194 case kIOHIDElementTypeCollection:
00195 printf(" Collection");
00196 break;
00197 }
00198
00199 printf(" Usage %3d UsagePage %3d\n",usage,usagePage);
00200
00201 if(kHIDPage_GenericDesktop==usagePage)
00202 {
00203 switch(usage)
00204 {
00205 case kHIDUsage_GD_Mouse:
00206 printf(" Can function as mouse\n");
00207 isMouse=1;
00208 break;
00209 case kHIDUsage_GD_Keyboard:
00210 printf(" Can function as Keyboard\n");
00211 isKeyboard=1;
00212 break;
00213 case kHIDUsage_GD_Joystick:
00214 printf(" Can function as Joystick\n");
00215 isJoystick=1;
00216 break;
00217 case kHIDUsage_GD_GamePad:
00218 printf(" Can function as GamePad\n");
00219 isGamePad=1;
00220 break;
00221 }
00222 }
00223 }
00224
00225 if(0!=isJoystick)
00226 {
00227 int nAxis=0;
00228 int nHat=0;
00229
00230 int j;
00231 for(j=0; j<nElem; j++)
00232 {
00233 IOHIDElementRef elem=(IOHIDElementRef)CFArrayGetValueAtIndex(elemAry,j);
00234 IOHIDElementType elemType=IOHIDElementGetType(elem);
00235 unsigned int usage=IOHIDElementGetUsage(elem);
00236 unsigned int usagePage=IOHIDElementGetUsagePage(elem);
00237
00238
00239
00240 int min=IOHIDElementGetLogicalMin(elem);
00241 int max=IOHIDElementGetLogicalMax(elem);
00242 int scaledMin=min;
00243 int scaledMax=max;
00244
00245 if(elemType==kIOHIDElementTypeInput_Misc ||
00246 elemType==kIOHIDElementTypeInput_Button ||
00247 elemType==kIOHIDElementTypeInput_Axis ||
00248 elemType==kIOHIDElementTypeInput_ScanCodes)
00249 {
00250 switch(usagePage)
00251 {
00252 case kHIDPage_GenericDesktop:
00253 switch(usage)
00254 {
00255 case kHIDUsage_GD_Mouse:
00256 break;
00257 case kHIDUsage_GD_Keyboard:
00258 break;
00259 case kHIDUsage_GD_Joystick:
00260 break;
00261 case kHIDUsage_GD_GamePad:
00262 break;
00263 case kHIDUsage_GD_X:
00264 printf(" This element is for X-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
00265 AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
00266 break;
00267 case kHIDUsage_GD_Y:
00268 printf(" This element is for Y-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
00269 AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
00270 break;
00271 case kHIDUsage_GD_Z:
00272 printf(" This element is for Z-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
00273 AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
00274 break;
00275 case kHIDUsage_GD_Rx:
00276 printf(" This element is for Rx-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
00277 AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
00278 break;
00279 case kHIDUsage_GD_Ry:
00280 printf(" This element is for Ry-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
00281 AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
00282 break;
00283 case kHIDUsage_GD_Rz:
00284 printf(" This element is for Rz-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
00285 AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
00286 break;
00287 case kHIDUsage_GD_Slider:
00288 printf(" This element is for Slider (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
00289 AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
00290 break;
00291 case kHIDUsage_GD_Wheel:
00292 printf(" This element is for Wheel (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
00293 break;
00294 case kHIDUsage_GD_Hatswitch:
00295 printf(" This element is for Hatswitch (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
00296 if(nHat<YsJoyReaderMaxNumHatSwitch)
00297 {
00298 hatSwitch[nHat].exist=1;
00299 hatSwitch[nHat].elem=elem;
00300 CFRetain(elem);
00301 nHat++;
00302 }
00303 break;
00304 }
00305 break;
00306 case kHIDPage_Button:
00307 printf(" This element is for Button %d\n",usage-1);
00308 usage--;
00309 if(0<=usage && usage<YsJoyReaderMaxNumButton)
00310 {
00311 button[usage].exist=1;
00312 button[usage].elem=elem;
00313 CFRetain(elem);
00314 }
00315 break;
00316 }
00317 }
00318 }
00319 CFRelease(elemAry);
00320 this->hidDev=hidDev;
00321 return 1;
00322
00323 }
00324 CFRelease(elemAry);
00325 }
00326
00327 return 0;
00328 }
00329
00330 void YsJoyReader::Read(void)
00331 {
00332 int i;
00333 IOHIDValueRef valueRef;
00334 for(i=0; i<YsJoyReaderMaxNumAxis; i++)
00335 {
00336 if(axis[i].exist!=0)
00337 {
00338 IOHIDDeviceGetValue(hidDev,axis[i].elem,&valueRef);
00339 axis[i].value=IOHIDValueGetIntegerValue(valueRef);
00340 }
00341 }
00342 for(i=0; i<YsJoyReaderMaxNumButton; i++)
00343 {
00344 if(button[i].exist!=0)
00345 {
00346 IOHIDDeviceGetValue(hidDev,button[i].elem,&valueRef);
00347 button[i].value=IOHIDValueGetIntegerValue(valueRef);
00348 }
00349 }
00350 for(i=0; i<YsJoyReaderMaxNumHatSwitch; i++)
00351 {
00352 if(hatSwitch[i].exist!=0)
00353 {
00354 IOHIDDeviceGetValue(hidDev,hatSwitch[i].elem,&valueRef);
00355
00356 double scaled=IOHIDValueGetScaledValue(valueRef,kIOHIDValueScaleTypePhysical);
00357 if(scaled<-0.001 || 359.999<scaled)
00358 {
00359 hatSwitch[i].value=0;
00360 }
00361 else
00362 {
00363 hatSwitch[i].value=1+(int)((scaled+22.5)/45.0);
00364 }
00365 }
00366 }
00367 }
00368
00369 void YsJoyReader::ReleaseInterface(void)
00370 {
00371 if(hidDev!=NULL)
00372 {
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 CFRelease(hidDev);
00387 hidDev=NULL;
00388 }
00389 }
00390
00391 void YsJoyReader::AddAxis(int axisId,IOHIDElementRef elem,int min,int max,int scaledMin,int scaledMax)
00392 {
00393 if(0<=axisId && axisId<YsJoyReaderMaxNumAxis)
00394 {
00395 axis[axisId].exist=1;
00396 axis[axisId].elem=elem;
00397 axis[axisId].min=min;
00398 axis[axisId].max=max;
00399 axis[axisId].scaledMin=scaledMin;
00400 axis[axisId].scaledMax=scaledMax;
00401
00402 axis[axisId].calibCenter=(min+max)/2;
00403 axis[axisId].calibMin=min;
00404 axis[axisId].calibMax=max;
00405
00406 CFRetain(elem);
00407 }
00408 }
00409
00410 void CFSetCopyCallBack(const void *value,void *context)
00411 {
00412 CFArrayAppendValue((CFMutableArrayRef)context,value);
00413 }
00414
00415 int YsJoyReader::SetUpJoystick(int &nJoystick,YsJoyReader joystick[],int maxNumJoystick)
00416 {
00417 nJoystick=0;
00418
00419 if(NULL==hidManager)
00420 {
00421 hidManager=IOHIDManagerCreate(kCFAllocatorDefault,kIOHIDOptionsTypeNone);
00422 }
00423
00424 if(NULL!=hidManager)
00425 {
00426 IOHIDManagerSetDeviceMatching(hidManager,NULL);
00427 IOHIDManagerOpen(hidManager,kIOHIDOptionsTypeNone);
00428
00429 CFSetRef copyOfDevices=IOHIDManagerCopyDevices(hidManager);
00430 if(NULL!=devArray)
00431 {
00432 CFRelease(devArray);
00433 devArray=NULL;
00434 }
00435 devArray=CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks);
00436 CFSetApplyFunction(copyOfDevices,CFSetCopyCallBack,(void *)devArray);
00437
00438 CFIndex nDev=CFArrayGetCount(devArray);
00439
00440 printf("%d devices found\n",(int)nDev);
00441
00442 CFRelease(copyOfDevices);
00443
00444
00445
00446 int i;
00447 for(i=0; i<nDev && nJoystick<maxNumJoystick; i++)
00448 {
00449 IOHIDDeviceRef hidDev=(IOHIDDeviceRef)CFArrayGetValueAtIndex(devArray,i);
00450 if(joystick[nJoystick].SetUpInterface(nJoystick,hidDev)!=0)
00451 {
00452 nJoystick++;
00453
00454 }
00455 }
00456 }
00457
00458 return nJoystick;
00459 }
00460
00461 int YsJoyReader::WriteCalibInfoFile(FILE *fp) const
00462 {
00463 int i;
00464 fprintf(fp,"BGNJOY %d\n",joyId);
00465 for(i=0; i<YsJoyReaderMaxNumAxis; i++)
00466 {
00467 if(0!=axis[i].exist)
00468 {
00469 fprintf(fp,"AXSINF %d %d %d %d\n",i,axis[i].calibCenter,axis[i].calibMin,axis[i].calibMax);
00470 }
00471 }
00472 #ifdef YSJOYREADER_USE_HAT_CALIBRATION
00473 for(i=0; i<YsJoyReaderMaxNumHatSwitch; i++)
00474 {
00475 if(0!=hatSwitch[i].exist)
00476 {
00477 fprintf(fp,"HATINF %d %d %d %d %d %d\n",
00478 i,
00479 hatSwitch[i].valueNeutral,
00480 hatSwitch[i].value0Deg,
00481 hatSwitch[i].value90Deg,
00482 hatSwitch[i].value180Deg,
00483 hatSwitch[i].value270Deg);
00484 }
00485 }
00486 #endif
00487 fprintf(fp,"ENDJOY\n");
00488 return 1;
00489 }
00490
00491 int YsJoyReader::ReadCalibInfoFile(FILE *fp)
00492 {
00493 char str[256];
00494 while(fgets(str,255,fp)!=NULL)
00495 {
00496 if(strncmp(str,"AXSINF",6)==0)
00497 {
00498 int axisId,cen,min,max;
00499 sscanf(str,"%*s %d %d %d %d",&axisId,&cen,&min,&max);
00500 if(0<=axisId && axisId<YsJoyReaderMaxNumAxis)
00501 {
00502 axis[axisId].calibCenter=cen;
00503 axis[axisId].calibMin=min;
00504 axis[axisId].calibMax=max;
00505 }
00506 }
00507 #ifdef YSJOYREADER_USE_HAT_CALIBRATION
00508 else if(strncmp(str,"HATINF",6)==0)
00509 {
00510 int hatId;
00511 int valueNeutral=0,value0Deg=1,value90Deg=3,value180Deg=5,value270Deg=7;
00512 sscanf(str,"%*s %d %d %d %d %d %d",&hatId,&valueNeutral,&value0Deg,&value90Deg,&value180Deg,&value270Deg);
00513 if(0<=hatId && hatId<YsJoyReaderMaxNumHatSwitch)
00514 {
00515 hatSwitch[hatId].valueNeutral=valueNeutral;
00516 hatSwitch[hatId].value0Deg=value0Deg;
00517 hatSwitch[hatId].value90Deg=value90Deg;
00518 hatSwitch[hatId].value180Deg=value180Deg;
00519 hatSwitch[hatId].value270Deg=value270Deg;
00520 }
00521 }
00522 #endif
00523 else if(strncmp(str,"ENDJOY",6)==0)
00524 {
00525 return 1;
00526 }
00527 }
00528 return 0;
00529 }
00530
00531 int YsJoyReaderSetUpJoystick(int &nJoystick,YsJoyReader joystick[],int maxNumJoystick)
00532 {
00533 return YsJoyReader::SetUpJoystick(nJoystick,joystick,maxNumJoystick);
00534 }
00535
00536
00537 extern "C" FILE *YsJoyReaderOpenJoystickCalibrationFileC(const char mode[]);
00538
00539 FILE *YsJoyReaderOpenJoystickCalibrationFile(const char mode[])
00540 {
00541 return YsJoyReaderOpenJoystickCalibrationFileC(mode);
00542 }
00543
00544 int YsJoyReaderSaveJoystickCalibrationInfo(int nJoystick,YsJoyReader joystick[])
00545 {
00546 FILE *fp;
00547 fp=YsJoyReaderOpenJoystickCalibrationFile("w");
00548
00549 if(fp!=NULL)
00550 {
00551 int i;
00552 for(i=0; i<nJoystick; i++)
00553 {
00554 joystick[i].WriteCalibInfoFile(fp);
00555 }
00556
00557 fclose(fp);
00558 return 1;
00559 }
00560 return 0;
00561 }
00562
00563 int YsJoyReaderLoadJoystickCalibrationInfo(int nJoystick,YsJoyReader joystick[])
00564 {
00565 FILE *fp;
00566 fp=YsJoyReaderOpenJoystickCalibrationFile("r");
00567
00568 if(fp!=NULL)
00569 {
00570 char str[256];
00571 while(fgets(str,255,fp)!=NULL)
00572 {
00573 if(strncmp(str,"BGNJOY",6)==0)
00574 {
00575 int joyId;
00576 sscanf(str,"%*s %d",&joyId);
00577 if(0<=joyId && joyId<nJoystick)
00578 {
00579 joystick[joyId].ReadCalibInfoFile(fp);
00580 }
00581 }
00582 }
00583 fclose(fp);
00584 return 1;
00585 }
00586 return 0;
00587 }