freejoy.macosx.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. // freejoy.macosx.c
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <ctype.h>
  6. #include <sys/errno.h>
  7. #include <sysexits.h>
  8. #include <mach/mach.h>
  9. #include <mach/mach_error.h>
  10. #include <IOKit/IOKitLib.h>
  11. #include <IOKit/IOCFPlugIn.h>
  12. #include <IOKit/hid/IOHIDLib.h>
  13. #include <IOKit/hid/IOHIDUsageTables.h>
  14. #include <IOKit/hid/IOHIDKeys.h>
  15. #include <CoreFoundation/CoreFoundation.h>
  16. #include <Carbon/Carbon.h>
  17. #include "freejoy.h"
  18. mach_port_t masterPort;
  19. IOHIDDeviceInterface **OpenDevice(io_object_t device)
  20. {
  21. IOHIDDeviceInterface **handle;
  22. IOCFPlugInInterface **plug;
  23. SInt32 score;
  24. io_name_t class;
  25. IOReturn iores;
  26. HRESULT res;
  27. iores=IOObjectGetClass(device,class);
  28. if (iores) printf("Failed to get class name");
  29. iores=IOCreatePlugInInterfaceForService(device,kIOHIDDeviceUserClientTypeID,kIOCFPlugInInterfaceID,&plug,&score);
  30. if (iores!=kIOReturnSuccess) printf("IOCreatePlugInInterfaceForService failed");
  31. res=(*plug)->QueryInterface(plug,CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),(void *)&handle);
  32. if (res!= S_OK) printf("Couldn't query HID class device interface from plugInInterface\n");
  33. res=(*handle)->open(handle,0);
  34. if (res!= S_OK) printf("Couldn't open HID device\n");
  35. (*plug)->Release(plug);
  36. return handle;
  37. }
  38. struct macjoy
  39. {
  40. struct macjoy *link;
  41. IOHIDDeviceInterface **device;
  42. IOHIDElementCookie button[32];
  43. IOHIDElementCookie axis[16];
  44. long axismax[16],axismin[16];
  45. int bcaps,acaps;
  46. char name[256];
  47. };
  48. void freemacjoy(struct macjoy *j)
  49. {
  50. int res;
  51. res=IOObjectRelease( (int)j->device);
  52. }
  53. void readmacjoy(struct macjoy *j,int *buttons,float *axis)
  54. {
  55. IOHIDEventStruct event;
  56. IOHIDElementCookie cookie;
  57. int i,res,b;
  58. b=0;
  59. for (i=0;i<32;i++)
  60. {
  61. if (cookie=j->button[i])
  62. {
  63. res=(*j->device)->getElementValue(j->device,cookie,&event);
  64. if (event.value) b|=1<<i;
  65. }
  66. }
  67. *buttons=b;
  68. for (i=0;i<16;i++)
  69. {
  70. if (cookie=j->axis[i])
  71. {
  72. res=(*j->device)->getElementValue(j->device,cookie,&event);
  73. if (i==JOYHAT)
  74. {
  75. axis[i]=event.value/8.0;
  76. if (axis[i]==1.0) axis[i]=-1.0;
  77. }
  78. else
  79. {
  80. // axis[i]=(event.value-128)/128.0;
  81. axis[i]=event.value;
  82. // if (j->axismax[i]) axis[i]/=j->axismax[i]; //32768.0;
  83. if (j->axismax[i]) {
  84. axis[i]=(((axis[i]-j->axismin[i])/j->axismax[i])-0.5)*2.0; //32768.0;
  85. }
  86. }
  87. }
  88. }
  89. };
  90. void macjoyelement(struct macjoy *j,CFDictionaryRef element)
  91. {
  92. IOHIDElementCookie cookie;
  93. CFTypeRef object;
  94. long number,usage,page,axismax,axismin;
  95. int axis;
  96. object = CFDictionaryGetValue (element, CFSTR(kIOHIDElementCookieKey));
  97. if (object == 0 || CFGetTypeID (object) != CFNumberGetTypeID ()) return;
  98. if(!CFNumberGetValue ((CFNumberRef) object, kCFNumberLongType, &number)) return;
  99. cookie = (IOHIDElementCookie) number;
  100. object = CFDictionaryGetValue (element, CFSTR(kIOHIDElementUsageKey));
  101. if (object == 0 || CFGetTypeID (object) != CFNumberGetTypeID ()) return;
  102. if (!CFNumberGetValue ((CFNumberRef) object, kCFNumberLongType, &number)) return;
  103. usage = number;
  104. axismax=0;axismin=0;
  105. object=CFDictionaryGetValue(element,CFSTR(kIOHIDElementMaxKey));
  106. if (object && CFNumberGetValue(object, kCFNumberLongType, &number)){
  107. axismax=number;
  108. // printf("max=%d\n",number);fflush(stdout);
  109. }
  110. object=CFDictionaryGetValue(element,CFSTR(kIOHIDElementMinKey));
  111. if (object && CFNumberGetValue(object, kCFNumberLongType, &number)){
  112. axismin=number;
  113. // printf("min=%d\n",number);fflush(stdout);
  114. }
  115. object = CFDictionaryGetValue (element,CFSTR(kIOHIDElementUsagePageKey));
  116. if (object == 0 || CFGetTypeID (object) != CFNumberGetTypeID ()) return;
  117. if (!CFNumberGetValue ((CFNumberRef) object, kCFNumberLongType, &number)) return;
  118. page = number;
  119. switch (page)
  120. {
  121. case kHIDPage_GenericDesktop:
  122. // printf("page=kHIDPage_GenericDesktop usage=%d cookie=%d\n",usage,cookie);
  123. axis=-1;
  124. switch (usage)
  125. {
  126. case kHIDUsage_GD_X:
  127. axis=JOYX;
  128. break;
  129. case kHIDUsage_GD_Y:
  130. axis=JOYY;
  131. break;
  132. case kHIDUsage_GD_Z:
  133. axis=JOYZ;
  134. break;
  135. case kHIDUsage_GD_Rz:
  136. axis=JOYR;
  137. break;
  138. case kHIDUsage_GD_Ry:
  139. axis=JOYU;
  140. break;
  141. case kHIDUsage_GD_Rx:
  142. axis=JOYV;
  143. break;
  144. case kHIDUsage_GD_Slider:
  145. axis=JOYYAW;
  146. break;
  147. case kHIDUsage_GD_Hatswitch:
  148. axis=JOYHAT;
  149. break;
  150. case kHIDUsage_GD_Wheel:
  151. axis=JOYWHEEL;
  152. break;
  153. }
  154. if (axis!=-1){
  155. j->axis[axis]=cookie;
  156. j->axismax[axis]=axismax-axismin;
  157. j->axismin[axis]=axismin;
  158. }
  159. break;
  160. case kHIDPage_Button:
  161. // printf("page=kHIDPage_Button usage=%d cookie=%d\n",usage,cookie);
  162. if (usage>0 && usage<=32)
  163. {
  164. usage--;
  165. if (!j->button[usage]) j->button[usage]=cookie;
  166. }
  167. break;
  168. }
  169. }
  170. void enumprops(CFTypeRef object,struct macjoy *j)
  171. {
  172. CFTypeID type;
  173. const void **keys,**vals,*obj;
  174. CFTypeRef key,val;
  175. int n,k;
  176. const char *c;
  177. if (!object) return;
  178. type=CFGetTypeID(object);
  179. if (type==CFArrayGetTypeID())
  180. {
  181. // printf( "array!\n" );
  182. n=CFArrayGetCount( object );
  183. for( k=0;k<n;++k )
  184. {
  185. obj=CFArrayGetValueAtIndex( object,k );
  186. enumprops(obj,j);
  187. }
  188. return;
  189. }
  190. if (type==CFDictionaryGetTypeID())
  191. {
  192. // printf( "dictionery!\n" );
  193. macjoyelement(j,object);
  194. n=CFDictionaryGetCount( object );
  195. keys=(const void**)malloc( n*sizeof(void*) );
  196. vals=(const void**)malloc( n*sizeof(void*) );
  197. CFDictionaryGetKeysAndValues( object,keys,vals );
  198. for (k=0;k<n;++k)
  199. {
  200. key=keys[k];
  201. val=vals[k];
  202. type=CFGetTypeID(key);
  203. if (type==CFStringGetTypeID())
  204. {
  205. c=CFStringGetCStringPtr(key,CFStringGetSystemEncoding());
  206. if (c)
  207. {
  208. // printf("%s\n",c);
  209. enumprops(val,j);
  210. }
  211. }
  212. else
  213. {
  214. // printf( "<unknown keytype>\n");
  215. }
  216. }
  217. free( vals );
  218. free( keys );
  219. return;
  220. }
  221. }
  222. int macjoycount=0;
  223. struct macjoy *joylist[16];
  224. void enumhid(UInt32 page,UInt32 usage)
  225. {
  226. CFMutableDictionaryRef dic,props;
  227. CFNumberRef rpage,rusage;
  228. CFTypeRef element;
  229. IOHIDDeviceInterface **device;
  230. io_iterator_t it;
  231. io_object_t obj;
  232. IOReturn res;
  233. struct macjoy *joy;
  234. int i,m;
  235. dic=IOServiceMatching(kIOHIDDeviceKey);
  236. if (dic==0) {printf("No dictionary returned by IOServiceMatching");return;}
  237. rpage=CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&page);
  238. rusage=CFNumberCreate(kCFAllocatorDefault,kCFNumberIntType,&usage);
  239. CFDictionarySetValue(dic,CFSTR(kIOHIDPrimaryUsagePageKey),rpage);
  240. CFDictionarySetValue(dic,CFSTR(kIOHIDPrimaryUsageKey),rusage);
  241. res=IOServiceGetMatchingServices(masterPort,dic,&it);
  242. if (res!=kIOReturnSuccess) {printf("IOServiceGetMatchingServices failed");return;}
  243. while (obj=IOIteratorNext(it))
  244. {
  245. device=OpenDevice(obj);
  246. if (device)
  247. {
  248. // printf("Got HID Device Handle\n");
  249. joy=calloc(1,sizeof (struct macjoy));
  250. joy->device=device;
  251. res=IORegistryEntryCreateCFProperties(obj,&props,kCFAllocatorDefault,kNilOptions);
  252. if (res!=kIOReturnSuccess) {printf("IORegistryEntryCreateCFProperties failed");return;}
  253. // MyShowObject(props);
  254. enumprops(props,joy);
  255. m=0;for (i=0;i<32;i++) {if (joy->button[i]) m|=1<<i;}
  256. joy->bcaps=m;
  257. m=0;for (i=0;i<16;i++) {if (joy->axis[i]) m|=1<<i;}
  258. joy->acaps=m;
  259. if (macjoycount<16) joylist[macjoycount++]=joy;
  260. }
  261. }
  262. IOObjectRelease(it);
  263. }
  264. int InitMacJoy()
  265. {
  266. io_iterator_t it;
  267. IOReturn res;
  268. // printf("enumerating hid devices\n");
  269. macjoycount=0;
  270. res=IOMasterPort (bootstrap_port, &masterPort);
  271. if (res) printf("IOMasterPort failed\n");
  272. enumhid(kHIDPage_GenericDesktop,kHIDUsage_GD_Joystick);
  273. enumhid(kHIDPage_GenericDesktop,kHIDUsage_GD_GamePad);
  274. enumhid(kHIDPage_GenericDesktop,kHIDUsage_GD_MultiAxisController);
  275. // if (masterPort) mach_port_deallocate(mach_task_self(),masterPort);
  276. }
  277. int JoyCount()
  278. {
  279. if( !macjoycount ) InitMacJoy();
  280. return macjoycount;
  281. }
  282. char *JoyCName(int port)
  283. {
  284. return "MacOSX Joystick";
  285. }
  286. int JoyButtonCaps(int port)
  287. {
  288. if (port>=0 && port<macjoycount) return joylist[port]->bcaps;
  289. return 0;
  290. }
  291. int JoyAxisCaps(int port)
  292. {
  293. if (port>=0 && port<macjoycount) return joylist[port]->acaps;
  294. return 0;
  295. }
  296. int ReadJoy(int port,int *buttons,float *axis)
  297. {
  298. if (port>=0 && port<macjoycount) readmacjoy(joylist[port],buttons,axis);
  299. return 0;
  300. }
  301. void WriteJoy(int port,int channel,float value)
  302. {
  303. }