direcs  2012-09-30
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
joyreaderMacOS.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  * Copyright (C) Markus Knapp *
3  * www.direcs.de *
4  * *
5  * This file is part of direcs. *
6  * *
7  * direcs is free software: you can redistribute it and/or modify it *
8  * under the terms of the GNU General Public License as published *
9  * by the Free Software Foundation, version 3 of the License. *
10  * *
11  * direcs is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License *
17  * along with direcs. If not, see <http://www.gnu.org/licenses/>. *
18  * *
19  *************************************************************************/
20 
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <sys/errno.h>
26 #include <sysexits.h>
27 #include <IOKit/hid/IOHIDLib.h>
28 
29 #include "joyreaderMacOS.h"
30 
31 
33 {
34  exist=0;
35  elem=NULL;
36  value=0;
37 }
38 
40 {
41  min=0;
42  max=0;
43  scaledMin=0;
44  scaledMax=0;
45  calibCenter=0;
46  calibMin=0;
47  calibMax=0;
48 }
49 
51 {
52  double calib;
53 
55  {
56  calib=(double)(value-calibCenter)/(double)(calibMax-calibCenter);
57  }
59  {
60  calib=(double)(value-calibCenter)/(double)(calibCenter-calibMin);
61  }
62  else
63  {
64  return 0.0;
65  }
66 
67  if(calib>1.0)
68  {
69  calib=1.0;
70  }
71  if(calib<-1.0)
72  {
73  calib=-1.0;
74  }
75 
76  return calib;
77 }
78 
80 {
82 }
83 
85 {
86  calibMin=calibCenter+1000;
87  calibMax=calibCenter-1000;
88 }
89 
91 {
92  if(value<calibMin)
93  {
95  }
96  if(value>calibMax)
97  {
99  }
100 }
101 
103 {
105 }
106 
108 {
109 }
110 
112 {
113  valueNeutral=0;
114  value0Deg=1;
115  value90Deg=3;
116  value180Deg=5;
117  value270Deg=7;
118 }
119 
121 {
122  if(value==valueNeutral)
123  {
124  return 0;
125  }
126  else if(value==value0Deg)
127  {
128  return 1;
129  }
130  else if(value==value90Deg)
131  {
132  return 3;
133  }
134  else if(value==value180Deg)
135  {
136  return 5;
137  }
138  else if(value270Deg==value)
139  {
140  return 7;
141  }
142  else if(value0Deg<value && value<value90Deg)
143  {
144  return 2;
145  }
146  else if(value90Deg<value && value<value180Deg)
147  {
148  return 4;
149  }
150  else if(value180Deg<value && value<value270Deg)
151  {
152  return 6;
153  }
154  else if(value270Deg<value)
155  {
156  return 8;
157  }
158  return 0;
159 }
160 
161 
162 IOHIDManagerRef JoyReader::hidManager=NULL;
163 CFMutableArrayRef JoyReader::devArray=NULL;
164 
166 {
167  hidDev=NULL;
168 }
169 
170 int JoyReader::SetUpInterface(int joyId,IOHIDDeviceRef hidDev)
171 {
172  this->joyId=joyId;
173 
174  if(hidDev!=NULL)
175  {
176  CFArrayRef elemAry=IOHIDDeviceCopyMatchingElements(hidDev,NULL,0);
177  int nElem=(int)CFArrayGetCount(elemAry);
178  int isMouse=0,isJoystick=0,isKeyboard=0,isGamePad=0;
179 
180 // qDebug("This HID Device has %d elements.",nElem);
181 
182  int j;
183  for(j=0; j<nElem; j++)
184  {
185  IOHIDElementRef elem=(IOHIDElementRef)CFArrayGetValueAtIndex(elemAry,j);
186 // IOHIDElementType elemType=IOHIDElementGetType(elem);
187  unsigned int usage=IOHIDElementGetUsage(elem);
188  unsigned int usagePage=IOHIDElementGetUsagePage(elem);
189 /*
190  printf("Element %3d",j);
191  switch(elemType)
192  {
193  case kIOHIDElementTypeInput_ScanCodes:
194  printf(" ScanCode ");
195  break;
196  case kIOHIDElementTypeInput_Misc:
197  printf(" Misc ");
198  break;
199  case kIOHIDElementTypeInput_Button:
200  printf(" Button ");
201  break;
202  case kIOHIDElementTypeInput_Axis:
203  printf(" Axis ");
204  break;
205  case kIOHIDElementTypeOutput:
206  printf(" Output ");
207  break;
208  case kIOHIDElementTypeFeature:
209  printf(" Feature ");
210  break;
211  case kIOHIDElementTypeCollection:
212  printf(" Collection");
213  break;
214  }
215 
216  printf(" Usage %3d UsagePage %3d\n",usage,usagePage);
217 */
218  if(kHIDPage_GenericDesktop==usagePage)
219  {
220  switch(usage)
221  {
222  case kHIDUsage_GD_Mouse:
223 // printf(" Can function as mouse\n");
224  isMouse=1;
225  break;
226  case kHIDUsage_GD_Keyboard:
227 // printf(" Can function as Keyboard\n");
228  isKeyboard=1;
229  break;
230  case kHIDUsage_GD_Joystick:
231 // qDebug("Found a Joystick.");
232  isJoystick=1;
233  break;
234  case kHIDUsage_GD_GamePad:
235 // qDebug("Found a GamePad.");
236  isGamePad=1;
237  break;
238  }
239  }
240  }
241 
242  if(0!=isJoystick)
243  {
244  int nAxis=0;
245  int nHat=0;
246 
247  int j;
248  for(j=0; j<nElem; j++)
249  {
250  IOHIDElementRef elem=(IOHIDElementRef)CFArrayGetValueAtIndex(elemAry,j);
251  IOHIDElementType elemType=IOHIDElementGetType(elem);
252  unsigned int usage=IOHIDElementGetUsage(elem);
253  unsigned int usagePage=IOHIDElementGetUsagePage(elem);
254  // The following two returned 0 and 255
255  // IOHIDElementGetPhysicalMin(elem);
256  // IOHIDElementGetPhysicalMax(elem);
257  int min=IOHIDElementGetLogicalMin(elem);
258  int max=IOHIDElementGetLogicalMax(elem);
259  int scaledMin=min;
260  int scaledMax=max;
261 
262  if(elemType==kIOHIDElementTypeInput_Misc ||
263  elemType==kIOHIDElementTypeInput_Button ||
264  elemType==kIOHIDElementTypeInput_Axis ||
265  elemType==kIOHIDElementTypeInput_ScanCodes)
266  {
267  switch(usagePage)
268  {
269  case kHIDPage_GenericDesktop:
270  switch(usage)
271  {
272  case kHIDUsage_GD_Mouse:
273  break;
274  case kHIDUsage_GD_Keyboard:
275  break;
276  case kHIDUsage_GD_Joystick:
277  break;
278  case kHIDUsage_GD_GamePad:
279  break;
280  case kHIDUsage_GD_X:
281 // printf(" This element is for X-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
282  AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
283  break;
284  case kHIDUsage_GD_Y:
285 // printf(" This element is for Y-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
286  AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
287  break;
288  case kHIDUsage_GD_Z:
289 // printf(" This element is for Z-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
290  AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
291  break;
292  case kHIDUsage_GD_Rx:
293 // printf(" This element is for Rx-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
294  AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
295  break;
296  case kHIDUsage_GD_Ry:
297 // printf(" This element is for Ry-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
298  AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
299  break;
300  case kHIDUsage_GD_Rz:
301 // printf(" This element is for Rz-Axis (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
302  AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
303  break;
304  case kHIDUsage_GD_Slider:
305 // printf(" This element is for Slider (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
306  AddAxis(nAxis++,elem,min,max,scaledMin,scaledMax);
307  break;
308  case kHIDUsage_GD_Wheel:
309 // printf(" This element is for Wheel (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
310  break;
311  case kHIDUsage_GD_Hatswitch:
312 // printf(" This element is for Hatswitch (%d->%d) Scaled(%d->%d)\n",min,max,scaledMin,scaledMax);
313  if(nHat<JoyReaderMaxNumHatSwitch)
314  {
315  hatSwitch[nHat].exist=1;
316  hatSwitch[nHat].elem=elem;
317  CFRetain(elem);
318  nHat++;
319  }
320  break;
321  }
322  break;
323  case kHIDPage_Button:
324 // printf(" This element is for Button %d\n",usage-1);
325  usage--;
326  if(0<=usage && usage<JoyReaderMaxNumButton)
327  {
328  button[usage].exist=1;
329  button[usage].elem=elem;
330  CFRetain(elem);
331  }
332  break;
333  }
334  }
335  }
336  CFRelease(elemAry);
337  this->hidDev=hidDev;
338  return 1;
339 
340  }
341 
342  CFRelease(elemAry);
343  }
344 
345  return 0;
346 }
347 
348 void JoyReader::Read(void)
349 {
350  int i;
351  IOHIDValueRef valueRef;
352  for(i=0; i<JoyReaderMaxNumAxis; i++)
353  {
354  if(axis[i].exist!=0)
355  {
356  IOHIDDeviceGetValue(hidDev,axis[i].elem,&valueRef);
357  axis[i].value=IOHIDValueGetIntegerValue(valueRef);
358  }
359  }
360  for(i=0; i<JoyReaderMaxNumButton; i++)
361  {
362  if(button[i].exist!=0)
363  {
364  IOHIDDeviceGetValue(hidDev,button[i].elem,&valueRef);
365  button[i].value=IOHIDValueGetIntegerValue(valueRef);
366  }
367  }
368  for(i=0; i<JoyReaderMaxNumHatSwitch; i++)
369  {
370  if(hatSwitch[i].exist!=0)
371  {
372  IOHIDDeviceGetValue(hidDev,hatSwitch[i].elem,&valueRef);
373 
374  double scaled=IOHIDValueGetScaledValue(valueRef,kIOHIDValueScaleTypePhysical);
375  if(scaled<-0.001 || 359.999<scaled)
376  {
377  hatSwitch[i].value=0;
378  }
379  else
380  {
381  hatSwitch[i].value=1+(int)((scaled+22.5)/45.0);
382  }
383  }
384  }
385 }
386 
388 {
389  if(hidDev!=NULL)
390  {
391  // Honestly, I don't know what to do.
392  //
393  // Should I do
394  // CFRelease(hidDev);
395  // ?
396  //
397  // This hidDev was copied from a copy of IOHIDManager's device list.
398  // Who owns it? Why did I have to make a copy?
399  //
400  // The Creare Rule implies that I have the ownership.
401  // http://developer.apple.com/mac/library/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-SW1
402  //
403  // Then, I suppose I should release it. Am I right?
404  CFRelease(hidDev);
405  hidDev=NULL;
406  }
407 }
408 
409 void JoyReader::AddAxis(int axisId,IOHIDElementRef elem,int min,int max,int scaledMin,int scaledMax)
410 {
411  if(0<=axisId && axisId<JoyReaderMaxNumAxis)
412  {
413  axis[axisId].exist=1;
414  axis[axisId].elem=elem;
415  axis[axisId].min=min;
416  axis[axisId].max=max;
417  axis[axisId].scaledMin=scaledMin;
418  axis[axisId].scaledMax=scaledMax;
419 
420  axis[axisId].calibCenter=(min+max)/2;
421  axis[axisId].calibMin=min;
422  axis[axisId].calibMax=max;
423 
424  CFRetain(elem);
425  }
426 }
427 
428 void CFSetCopyCallBack(const void *value,void *context)
429 {
430  CFArrayAppendValue((CFMutableArrayRef)context,value);
431 }
432 
433 int JoyReader::SetUpJoystick(int &nJoystick,JoyReader joystick[],int maxNumJoystick)
434 {
435  nJoystick=0;
436 
437  if(NULL==hidManager)
438  {
439  hidManager=IOHIDManagerCreate(kCFAllocatorDefault,kIOHIDOptionsTypeNone);
440  }
441 
442  if(NULL!=hidManager)
443  {
444  IOHIDManagerSetDeviceMatching(hidManager,NULL); // Just enumrate all devices
445  IOHIDManagerOpen(hidManager,kIOHIDOptionsTypeNone);
446 
447  CFSetRef copyOfDevices=IOHIDManagerCopyDevices(hidManager);
448  if(NULL!=devArray)
449  {
450  CFRelease(devArray);
451  devArray=NULL;
452  }
453  devArray=CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks);
454  CFSetApplyFunction(copyOfDevices,CFSetCopyCallBack,(void *)devArray);
455 
456  CFIndex nDev=CFArrayGetCount(devArray);
457 
458  qDebug("%d HID devices found. Looking for joysticks...", (int) nDev);
459 
460  CFRelease(copyOfDevices);
461 
462 
463 
464  int i;
465  for(i=0; i<nDev && nJoystick<maxNumJoystick; i++)
466  {
467  IOHIDDeviceRef hidDev=(IOHIDDeviceRef)CFArrayGetValueAtIndex(devArray,i);
468  if(joystick[nJoystick].SetUpInterface(nJoystick,hidDev)!=0)
469  {
470  nJoystick++;
471  // CFRelease(hidDev); // Doesn't it destroy integrity of devArray?
472  }
473  }
474  }
475 
476 
477  qDebug("%d joystick(s) found.", nJoystick);
478 
479  return nJoystick;
480 }
481 
482 int JoyReader::WriteCalibInfoFile(FILE *fp) const
483 {
484  int i;
485  fprintf(fp,"BGNJOY %d\n",joyId);
486  for(i=0; i<JoyReaderMaxNumAxis; i++)
487  {
488  if(0!=axis[i].exist)
489  {
490  fprintf(fp,"AXSINF %d %d %d %d\n",i,axis[i].calibCenter,axis[i].calibMin,axis[i].calibMax);
491  }
492  }
493 #ifdef YSJOYREADER_USE_HAT_CALIBRATION
494  for(i=0; i<JoyReaderMaxNumHatSwitch; i++)
495  {
496  if(0!=hatSwitch[i].exist)
497  {
498  fprintf(fp,"HATINF %d %d %d %d %d %d\n",
499  i,
500  hatSwitch[i].valueNeutral,
501  hatSwitch[i].value0Deg,
502  hatSwitch[i].value90Deg,
503  hatSwitch[i].value180Deg,
504  hatSwitch[i].value270Deg);
505  }
506  }
507 #endif
508  fprintf(fp,"ENDJOY\n");
509  return 1;
510 }
511 
513 {
514  char str[256];
515  while(fgets(str,255,fp)!=NULL)
516  {
517  if(strncmp(str,"AXSINF",6)==0)
518  {
519  int axisId,cen,min,max;
520  sscanf(str,"%*s %d %d %d %d",&axisId,&cen,&min,&max);
521  if(0<=axisId && axisId<JoyReaderMaxNumAxis)
522  {
523  axis[axisId].calibCenter=cen;
524  axis[axisId].calibMin=min;
525  axis[axisId].calibMax=max;
526  }
527  }
528 #ifdef YSJOYREADER_USE_HAT_CALIBRATION
529  else if(strncmp(str,"HATINF",6)==0)
530  {
531  int hatId;
532  int valueNeutral=0,value0Deg=1,value90Deg=3,value180Deg=5,value270Deg=7;
533  sscanf(str,"%*s %d %d %d %d %d %d",&hatId,&valueNeutral,&value0Deg,&value90Deg,&value180Deg,&value270Deg);
534  if(0<=hatId && hatId<JoyReaderMaxNumHatSwitch)
535  {
536  hatSwitch[hatId].valueNeutral=valueNeutral;
537  hatSwitch[hatId].value0Deg=value0Deg;
538  hatSwitch[hatId].value90Deg=value90Deg;
539  hatSwitch[hatId].value180Deg=value180Deg;
540  hatSwitch[hatId].value270Deg=value270Deg;
541  }
542  }
543 #endif
544  else if(strncmp(str,"ENDJOY",6)==0)
545  {
546  return 1;
547  }
548  }
549  return 0;
550 }
551 
552 int JoyReaderSetUpJoystick(int &nJoystick,JoyReader joystick[],int maxNumJoystick)
553 {
554  return JoyReader::SetUpJoystick(nJoystick,joystick,maxNumJoystick);
555 }
556 
557 
558 extern "C" FILE *JoyReaderOpenJoystickCalibrationFileC(const char mode[]);
559 
560 FILE *JoyReaderOpenJoystickCalibrationFile(const char mode[])
561 {
563 }
564 
565 int JoyReaderSaveJoystickCalibrationInfo(int nJoystick,JoyReader joystick[])
566 {
567  FILE *fp;
569 
570  if(fp!=NULL)
571  {
572  int i;
573  for(i=0; i<nJoystick; i++)
574  {
575  joystick[i].WriteCalibInfoFile(fp);
576  }
577 
578  fclose(fp);
579  return 1;
580  }
581  return 0;
582 }
583 
584 int JoyReaderLoadJoystickCalibrationInfo(int nJoystick,JoyReader joystick[])
585 {
586  FILE *fp;
588 
589  if(fp!=NULL)
590  {
591  char str[256];
592  while(fgets(str,255,fp)!=NULL)
593  {
594  if(strncmp(str,"BGNJOY",6)==0)
595  {
596  int joyId;
597  sscanf(str,"%*s %d",&joyId);
598  if(0<=joyId && joyId<nJoystick)
599  {
600  joystick[joyId].ReadCalibInfoFile(fp);
601  }
602  }
603  }
604  fclose(fp);
605  return 1;
606  }
607  return 0;
608 }