Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2542 lines
85 KiB

  1. /******************************************************************************
  2. Copyright (c) 1985-1999 Microsoft Corporation
  3. Title: joy.c - MMSYSTEM Joystick interface code
  4. Version: 1.01
  5. Date: 10-Jun-1997
  6. Author: GLENNS ROBWI
  7. ------------------------------------------------------------------------------
  8. Change log:
  9. DATE REV DESCRIPTION
  10. -------- ----- -----------------------------------------------------------
  11. 2/7/90 Changes to avoid a bug in Windows which won't allow
  12. FreeLibrary to be called during WEP.
  13. 10/11/90 .61 Use windows timer + general cleanup
  14. 20-Aug-92 Convert to Windows NT
  15. 20-Nov-97 Use DINPUT instead of old driver
  16. 1/10/98 Add debug output for joy* API
  17. *****************************************************************************/
  18. #define INITGUID
  19. #define UNICODE
  20. #include <stdlib.h>
  21. #include <windows.h>
  22. #include <regstr.h>
  23. #include <winioctl.h>
  24. #include "winmmi.h"
  25. #include "joy.h"
  26. /****************************************************************************
  27. Local data
  28. ****************************************************************************/
  29. CRITICAL_SECTION joyCritSec; //also used in winmm.c
  30. static LPJOYDEVICE g_pJoyDev[cJoyMax];
  31. static DWORD g_dwNumOpen = 0;
  32. static UINT g_wmJoyChanged = 0;
  33. static UINT g_timerID = 0;
  34. static HANDLE g_hThreadMonitor = NULL;
  35. static DWORD g_dwThreadID = 0;
  36. static BOOL g_fThreadExist = FALSE;
  37. static WCHAR cwszREGKEYNAME[] = L"DINPUT.DLL";
  38. static CHAR cszREGKEYNAME[] = "DINPUT.DLL";
  39. static HKEY hkJoyWinmm;
  40. static TCHAR g_szJoyWinmm[] = REGSTR_PATH_PRIVATEPROPERTIES TEXT("\\Joystick\\Winmm");
  41. static BOOL g_fHasWheel = FALSE;
  42. static DWORD g_dwEnableWheel;
  43. static TCHAR g_szEnableWheel[] = TEXT("wheel");
  44. #ifdef DBG
  45. static DWORD g_dwDbgLevel;
  46. static TCHAR g_szDbgLevel[] = TEXT("level");
  47. #endif
  48. LPDIRECTINPUTW g_pdi;
  49. LPDIRECTINPUTJOYCONFIG g_pdijc;
  50. HINSTANCE g_hinstDinputDll;
  51. FARPROC g_farprocDirectInputCreateW;
  52. HANDLE g_hEventWinmm;
  53. /****************************************************************************
  54. Internal Data Structures
  55. ****************************************************************************/
  56. #ifndef HID_USAGE_SIMULATION_RUDDER
  57. #define HID_USAGE_SIMULATION_RUDDER ((USAGE) 0xBA)
  58. #endif
  59. #ifndef HID_USAGE_SIMULATION_THROTTLE
  60. #define HID_USAGE_SIMULATION_THROTTLE ((USAGE) 0xBB)
  61. #endif
  62. #ifndef HID_USAGE_SIMULATION_ACCELERATOR
  63. #define HID_USAGE_SIMULATION_ACCELERATOR ((USAGE) 0xC4)
  64. #endif
  65. #ifndef HID_USAGE_SIMULATION_BRAKE
  66. #define HID_USAGE_SIMULATION_BRAKE ((USAGE) 0xC5)
  67. #endif
  68. #ifndef HID_USAGE_SIMULATION_CLUTCH
  69. #define HID_USAGE_SIMULATION_CLUTCH ((USAGE) 0xC6)
  70. #endif
  71. #ifndef HID_USAGE_SIMULATION_SHIFTER
  72. #define HID_USAGE_SIMULATION_SHIFTER ((USAGE) 0xC7)
  73. #endif
  74. #ifndef HID_USAGE_SIMULATION_STEERING
  75. #define HID_USAGE_SIMULATION_STEERING ((USAGE) 0xC8)
  76. #endif
  77. #ifndef HID_USAGE_GAME_POV
  78. #define HID_USAGE_GAME_POV ((USAGE) 0x20)
  79. #endif
  80. #ifndef DIDFT_OPTIONAL
  81. #define DIDFT_OPTIONAL 0x80000000
  82. #endif
  83. #define MAX_BTNS 32
  84. #define MAX_CTRLS 46 //14 below + buttons
  85. #define MAX_FINAL 7+MAX_BTNS //6 axes + POV + buttons
  86. typedef enum eCtrls {
  87. eGEN_X=0,
  88. eGEN_Y,
  89. eGEN_Z,
  90. eGEN_RX,
  91. eGEN_RY,
  92. eGEN_RZ,
  93. eSIM_THROTTLE,
  94. eSIM_STEERING,
  95. eSIM_ACCELERATOR,
  96. eGEN_SLIDER,
  97. eGEN_DIAL,
  98. eSIM_RUDDER,
  99. eSIM_BRAKE,
  100. eGEN_POV,
  101. eBTN } eCtrls;
  102. typedef struct WINMMJOYSTATE {
  103. DWORD lX;
  104. DWORD lY;
  105. DWORD lZ;
  106. DWORD lR;
  107. DWORD lU;
  108. DWORD lV;
  109. DWORD dwPOV;
  110. BYTE rgbButtons[32];
  111. } WINMMJOYSTATE, *LPWINMMJOYSTATE;
  112. #define MAKEVAL(f) \
  113. { 0, \
  114. FIELD_OFFSET(WINMMJOYSTATE, f), \
  115. DIDFT_OPTIONAL, \
  116. 0, \
  117. } \
  118. #define MAKEBTN(n) \
  119. { 0, \
  120. FIELD_OFFSET(WINMMJOYSTATE, rgbButtons[n]), \
  121. DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, \
  122. 0, \
  123. } \
  124. //Note that only the offset fields are used now
  125. static DIOBJECTDATAFORMAT c_rgodfWinMMJoy[] = {
  126. MAKEVAL(lX),
  127. MAKEVAL(lY),
  128. MAKEVAL(lZ),
  129. MAKEVAL(lR),
  130. MAKEVAL(lU),
  131. MAKEVAL(lV),
  132. MAKEVAL(dwPOV),
  133. MAKEBTN(0),
  134. MAKEBTN(1),
  135. MAKEBTN(2),
  136. MAKEBTN(3),
  137. MAKEBTN(4),
  138. MAKEBTN(5),
  139. MAKEBTN(6),
  140. MAKEBTN(7),
  141. MAKEBTN(8),
  142. MAKEBTN(9),
  143. MAKEBTN(10),
  144. MAKEBTN(11),
  145. MAKEBTN(12),
  146. MAKEBTN(13),
  147. MAKEBTN(14),
  148. MAKEBTN(15),
  149. MAKEBTN(16),
  150. MAKEBTN(17),
  151. MAKEBTN(18),
  152. MAKEBTN(19),
  153. MAKEBTN(20),
  154. MAKEBTN(21),
  155. MAKEBTN(22),
  156. MAKEBTN(23),
  157. MAKEBTN(24),
  158. MAKEBTN(25),
  159. MAKEBTN(26),
  160. MAKEBTN(27),
  161. MAKEBTN(28),
  162. MAKEBTN(29),
  163. MAKEBTN(30),
  164. MAKEBTN(31),
  165. };
  166. static GUID rgoWinMMGUIDs[MAX_CTRLS];
  167. DIDATAFORMAT c_dfWINMMJoystick = {
  168. sizeof(DIDATAFORMAT),
  169. sizeof(DIOBJECTDATAFORMAT),
  170. DIDF_ABSAXIS,
  171. sizeof(WINMMJOYSTATE),
  172. sizeof(c_rgodfWinMMJoy)/sizeof(DIOBJECTDATAFORMAT),
  173. c_rgodfWinMMJoy,
  174. };
  175. #define RESET_VAL(index) c_rgodfWinMMJoy[index].pguid = 0; \
  176. c_rgodfWinMMJoy[index].dwType = DIDFT_OPTIONAL; \
  177. c_rgodfWinMMJoy[index].dwFlags = 0; \
  178. #define RESET_BTN(index) c_rgodfWinMMJoy[index].pguid = 0; \
  179. c_rgodfWinMMJoy[index].dwType = DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL; \
  180. c_rgodfWinMMJoy[index].dwFlags = 0; \
  181. #define RESET_RGODFWINMMJOY() \
  182. RESET_VAL(0); \
  183. RESET_VAL(1); \
  184. RESET_VAL(2); \
  185. RESET_VAL(3); \
  186. RESET_VAL(4); \
  187. RESET_VAL(5); \
  188. RESET_VAL(6); \
  189. RESET_VAL(7); \
  190. RESET_BTN(8); \
  191. RESET_BTN(9); \
  192. RESET_BTN(10); \
  193. RESET_BTN(11); \
  194. RESET_BTN(12); \
  195. RESET_BTN(13); \
  196. RESET_BTN(14); \
  197. RESET_BTN(15); \
  198. RESET_BTN(16); \
  199. RESET_BTN(17); \
  200. RESET_BTN(18); \
  201. RESET_BTN(19); \
  202. RESET_BTN(20); \
  203. RESET_BTN(21); \
  204. RESET_BTN(22); \
  205. RESET_BTN(23); \
  206. RESET_BTN(24); \
  207. RESET_BTN(25); \
  208. RESET_BTN(26); \
  209. RESET_BTN(27); \
  210. RESET_BTN(28); \
  211. RESET_BTN(29); \
  212. RESET_BTN(30); \
  213. RESET_BTN(31); \
  214. RESET_BTN(32); \
  215. RESET_BTN(33); \
  216. RESET_BTN(34); \
  217. RESET_BTN(35); \
  218. RESET_BTN(36); \
  219. RESET_BTN(37); \
  220. RESET_BTN(38); \
  221. #ifndef cchLENGTH
  222. #define cchLENGTH(_sz) (sizeof(_sz)/sizeof(_sz[0]))
  223. #endif
  224. /****************************************************************************
  225. Internal functions
  226. ****************************************************************************/
  227. BOOL CALLBACK DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi,LPVOID pvRef);
  228. HRESULT WINAPI joyOpen(UINT idJoy, LPJOYCAPSW pjc );
  229. void WINAPI joyClose( UINT idJoy );
  230. void WINAPI joyCloseAll( void );
  231. void CALLBACK joyPollCallback(HWND hWnd, UINT wMsg, UINT_PTR uIDEvent, DWORD dwTime); //TIMER MESSAGE for Joystick
  232. DWORD WINAPI joyMonitorThread(LPVOID);
  233. void WINAPI DllEnterCrit(void);
  234. void WINAPI DllLeaveCrit(void);
  235. BOOL WINAPI DllInCrit( void );
  236. void AssignToArray(LPCDIDEVICEOBJECTINSTANCE lpddoi, eCtrls CtrlID, LPDIOBJECTDATAFORMAT pDevs);
  237. void AssignToRGODF(LPDIOBJECTDATAFORMAT pDof, int CtrlID);
  238. void AssignMappings(DIOBJECTDATAFORMAT *dwAll, DWORD *dwCaps, DWORD *dwBtns, DWORD *dwAxes);
  239. BOOL CALLBACK DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi,LPVOID pvRef);
  240. HRESULT hresMumbleKeyEx(HKEY hk, LPCTSTR ptszKey, REGSAM sam, DWORD dwOptions, PHKEY phk);
  241. /****************************************************************************
  242. @doc WINAPI
  243. @api BOOL | JoyInit | This function initializes the joystick services.
  244. @rdesc The return value is TRUE if the services are initialised.
  245. ****************************************************************************/
  246. BOOL JoyInit(void)
  247. {
  248. HRESULT hres;
  249. LONG lRc;
  250. JOY_DBGPRINT( JOY_BABBLE, ("JoyInit: starting.") );
  251. memset(&g_pJoyDev, 0, sizeof(g_pJoyDev) );
  252. g_wmJoyChanged = RegisterWindowMessage(MSGSTR_JOYCHANGED);
  253. g_dwNumOpen = 0x0;
  254. g_fHasWheel = FALSE;
  255. #ifdef DBG
  256. g_dwDbgLevel = JOY_DEFAULT_DBGLEVEL;
  257. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
  258. g_szJoyWinmm,
  259. KEY_ALL_ACCESS,
  260. REG_OPTION_NON_VOLATILE,
  261. &hkJoyWinmm);
  262. if ( SUCCEEDED(hres) )
  263. {
  264. DWORD cb = sizeof(g_dwDbgLevel);
  265. lRc = RegQueryValueEx(hkJoyWinmm, g_szDbgLevel, 0, 0, (LPBYTE)&g_dwDbgLevel, &cb);
  266. if ( lRc != ERROR_SUCCESS )
  267. {
  268. DWORD dwDefault = 0;
  269. lRc = RegSetValueEx(hkJoyWinmm, g_szDbgLevel, 0, REG_DWORD, (LPBYTE)&dwDefault, cb);
  270. }
  271. RegCloseKey(hkJoyWinmm);
  272. }
  273. #endif
  274. g_dwEnableWheel = 1;
  275. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
  276. g_szJoyWinmm,
  277. KEY_ALL_ACCESS,
  278. REG_OPTION_NON_VOLATILE,
  279. &hkJoyWinmm);
  280. if ( SUCCEEDED(hres) )
  281. {
  282. DWORD cb = sizeof(g_dwEnableWheel);
  283. lRc = RegQueryValueEx(hkJoyWinmm, g_szEnableWheel, 0, 0, (LPBYTE)&g_dwEnableWheel, &cb);
  284. if ( lRc != ERROR_SUCCESS )
  285. {
  286. DWORD dwDefault = 1;
  287. lRc = RegSetValueEx(hkJoyWinmm, g_szEnableWheel, 0, REG_DWORD, (LPBYTE)&dwDefault, cb);
  288. }
  289. RegCloseKey(hkJoyWinmm);
  290. }
  291. if( !g_hEventWinmm ) {
  292. g_hEventWinmm = OpenEvent(SYNCHRONIZE, 0, TEXT("DINPUTWINMM"));
  293. if( !g_hEventWinmm ) {
  294. g_hEventWinmm = CreateEvent(0, TRUE, 0, TEXT("DINPUTWINMM"));
  295. }
  296. if( !g_hEventWinmm ) {
  297. JOY_DBGPRINT( JOY_ERR, ("JoyInit: create named event fails (0x%08lx).", GetLastError() ) );
  298. }
  299. }
  300. return TRUE;
  301. }
  302. /****************************************************************************
  303. @doc WINAPI
  304. @api void | JoyCleanup | This function clean up the joystick services.
  305. ****************************************************************************/
  306. void JoyCleanup(void)
  307. {
  308. joyCloseAll();
  309. if ( g_hEventWinmm && WAIT_OBJECT_0 != WaitForSingleObject(g_hEventWinmm, 10))
  310. {
  311. //DInput has not been released.
  312. if( g_pdijc) {
  313. IDirectInputJoyConfig_Release(g_pdijc);
  314. }
  315. if ( g_pdi ) {
  316. IDirectInput_Release(g_pdi);
  317. }
  318. (void*)g_pdijc = (void*)g_pdi = NULL;
  319. }
  320. if ( g_hinstDinputDll )
  321. {
  322. FreeLibrary(g_hinstDinputDll);
  323. }
  324. if( g_hEventWinmm ) {
  325. CloseHandle( g_hEventWinmm );
  326. g_hEventWinmm = NULL;
  327. }
  328. JOY_DBGPRINT( JOY_BABBLE, ("JoyCleanup: finished.") );
  329. }
  330. /*****************************************************************************
  331. *
  332. * @doc WINAPI
  333. *
  334. * @func MMRESULT | joyGetDevCapsW |
  335. *
  336. * Implementation of legacy joyGetDevCapsW for HID devices on NT.
  337. *
  338. * @parm IN UINT_PTR | idJoy |
  339. *
  340. * ID of Joystick
  341. *
  342. * @parm OUT LPJOYCAPSW | pjc |
  343. *
  344. * JOYCAPSW structure to be filled by this routine.
  345. *
  346. * @parm UINT | cbjc |
  347. *
  348. * Size in bytes of the JOYCAPSW structure.
  349. *
  350. * @returns
  351. *
  352. * MMRESULT code
  353. *
  354. *****************************************************************************/
  355. MMRESULT WINAPI joyGetDevCapsW( UINT_PTR idJoy, LPJOYCAPSW pjc, UINT cbjc )
  356. {
  357. HRESULT hres;
  358. MMRESULT mmRes;
  359. JOY_DBGPRINT( JOY_BABBLE, ("joyGetDevCapsW: idJoy=%d, pjc=0x%08x, cbjc=%d", idJoy, pjc, cbjc) );
  360. V_WPOINTER(pjc, sizeof(JOYCAPSW), MMSYSERR_INVALPARAM);
  361. if( ( sizeof(JOYCAPSW) != cbjc ) && ( sizeof(JOYCAPS2W) != cbjc ) && ( FIELD_OFFSET(JOYCAPSW, wRmin) != cbjc ) )
  362. {
  363. JOY_DBGPRINT( JOY_ERR, ("joyGetDevCapsW: return %d (bad size)", JOYERR_PARMS) );
  364. return JOYERR_PARMS;
  365. }
  366. mmRes = JOYERR_NOERROR;
  367. memset(pjc, 0, min(cbjc, sizeof(JOYCAPS2W)) );
  368. if ( idJoy == (UINT_PTR)(-1) )
  369. {
  370. lstrcpyW(pjc->szRegKey, cwszREGKEYNAME );
  371. } else if ( idJoy >= cJoyMax )
  372. {
  373. JOY_DBGPRINT( JOY_ERR, ("joyGetDevCapsW: return %d (idJoy > 16)", MMSYSERR_NODRIVER) );
  374. mmRes = MMSYSERR_NODRIVER;
  375. } else
  376. {
  377. DllEnterCrit();
  378. hres = joyOpen((UINT)idJoy, pjc);
  379. DllLeaveCrit();
  380. if ( FAILED(hres) )
  381. {
  382. JOY_DBGPRINT( JOY_ERR, ("joyGetDevCapsW: return %d", JOYERR_PARMS) );
  383. mmRes = JOYERR_PARMS;
  384. }
  385. }
  386. JOY_DBGPRINT( JOY_BABBLE, ("joyGetDevCapsW: return %d", mmRes) );
  387. return mmRes;
  388. }
  389. int static __inline Iwcstombs(LPSTR lpstr, LPCWSTR lpwstr, int len)
  390. {
  391. return WideCharToMultiByte(GetACP(), 0, lpwstr, -1, lpstr, len, NULL, NULL);
  392. }
  393. /*****************************************************************************
  394. *
  395. * @doc WINAPI
  396. *
  397. * @func MMRESULT | joyGetDevCapsA |
  398. *
  399. * Implementation of legacy joyGetDevCapsA for devices on NT.
  400. * We call the Uincode version joyGetDevCapsW and then munge
  401. * the structure into ASCII.
  402. *
  403. * @parm UINT_PTR | idJoy |
  404. *
  405. * ID of Joystick
  406. *
  407. * @parm LPJOYCAPSA | pjc |
  408. *
  409. * JOYCAPSA structure to be filled by this routine.
  410. *
  411. * @parm UINT | cbjc |
  412. *
  413. * Size in bytes of the JOYCAPSA structure.
  414. *
  415. * @returns
  416. *
  417. * MMRESULT code
  418. *
  419. *****************************************************************************/
  420. MMRESULT WINAPI joyGetDevCapsA( UINT_PTR idJoy, LPJOYCAPSA pjc, UINT cbjc )
  421. {
  422. #define UToA(dst, cchDst, src) WideCharToMultiByte(CP_ACP, 0, src, -1, dst, cchDst, 0, 0)
  423. JOYCAPS2W Caps2W;
  424. JOYCAPS2A Caps2A;
  425. MMRESULT mmRes;
  426. JOY_DBGPRINT( JOY_BABBLE, ("joyGetDevCapsA: idJoy=%d, pjc=0x%08x, cbjc=%d", idJoy, pjc, cbjc) );
  427. V_WPOINTER(pjc, cbjc, MMSYSERR_INVALPARAM);
  428. mmRes = JOYERR_NOERROR;
  429. if ( idJoy == (UINT_PTR)(-1) )
  430. {
  431. lstrcpyA(pjc->szRegKey, cszREGKEYNAME );
  432. goto _done;
  433. } else if ( idJoy >= cJoyMax )
  434. {
  435. JOY_DBGPRINT( JOY_ERR, ("joyGetDevCapsA: return %d (idJoy > 16)", MMSYSERR_NODRIVER) );
  436. return MMSYSERR_NODRIVER;
  437. }
  438. if( ( sizeof(JOYCAPSA) != cbjc ) && ( sizeof(JOYCAPS2A) != cbjc ) && ( FIELD_OFFSET(JOYCAPSA, wRmin) != cbjc ) )
  439. {
  440. JOY_DBGPRINT( JOY_ERR, ("joyGetDevCapsA: return JOYERR_PARMS( bad size )") );
  441. return JOYERR_PARMS;
  442. }
  443. memset(pjc, 0, min(cbjc, sizeof(Caps2A)) );
  444. memset(&Caps2W, 0, sizeof(Caps2W));
  445. mmRes = joyGetDevCapsW(idJoy, (LPJOYCAPSW)&Caps2W, sizeof(Caps2W));
  446. if ( mmRes == JOYERR_NOERROR )
  447. {
  448. //
  449. // Copy product name (etc) into ASCII version
  450. //
  451. UToA(Caps2A.szPname , sizeof(Caps2A.szPname ), Caps2W.szPname );
  452. UToA(Caps2A.szRegKey, sizeof(Caps2A.szRegKey), Caps2W.szRegKey);
  453. UToA(Caps2A.szOEMVxD, sizeof(Caps2A.szOEMVxD), Caps2W.szOEMVxD);
  454. //
  455. // Copy the rest of the fields
  456. //
  457. Caps2A.wMid = Caps2W.wMid;
  458. Caps2A.wPid = Caps2W.wPid;
  459. Caps2A.wXmin = Caps2W.wXmin;
  460. Caps2A.wXmax = Caps2W.wXmax;
  461. Caps2A.wYmin = Caps2W.wYmin;
  462. Caps2A.wYmax = Caps2W.wYmax;
  463. Caps2A.wZmin = Caps2W.wZmin;
  464. Caps2A.wZmax = Caps2W.wZmax;
  465. Caps2A.wNumButtons = Caps2W.wNumButtons;
  466. Caps2A.wPeriodMin = Caps2W.wPeriodMin;
  467. Caps2A.wPeriodMax = Caps2W.wPeriodMax;
  468. Caps2A.wRmin = Caps2W.wRmin;
  469. Caps2A.wRmax = Caps2W.wRmax;
  470. Caps2A.wUmin = Caps2W.wUmin;
  471. Caps2A.wUmax = Caps2W.wUmax;
  472. Caps2A.wVmin = Caps2W.wVmin;
  473. Caps2A.wVmax = Caps2W.wVmax;
  474. Caps2A.wCaps = Caps2W.wCaps;
  475. Caps2A.wMaxAxes = Caps2W.wMaxAxes;
  476. Caps2A.wNumAxes = Caps2W.wNumAxes;
  477. Caps2A.wMaxButtons = Caps2W.wMaxButtons;
  478. Caps2A.ManufacturerGuid = Caps2W.ManufacturerGuid;
  479. Caps2A.ProductGuid = Caps2W.ProductGuid;
  480. Caps2A.NameGuid = Caps2W.NameGuid;
  481. //
  482. // Pass back as much data as the requestor asked for
  483. //
  484. CopyMemory(pjc, &Caps2A, min(cbjc, sizeof(Caps2A)));
  485. }
  486. _done:
  487. JOY_DBGPRINT( JOY_BABBLE, ("joyGetDevCapsA: return %d", mmRes) );
  488. return mmRes;
  489. #undef UToA
  490. }
  491. /****************************************************************************
  492. @doc EXTERNAL
  493. @api UINT | joyGetNumDevs | This function returns the number of joystick
  494. devices supported by the system.
  495. @rdesc Returns the number of joystick devices supported by the joystick
  496. driver. If no driver is present, the function returns zero.
  497. @comm Use <f joyGetPos> to determine whether a given
  498. joystick is actually attached to the system. The <f joyGetPos> function returns
  499. a JOYERR_UNPLUGGED error code if the specified joystick is not connected.
  500. @xref joyGetDevCaps joyGetPos
  501. ****************************************************************************/
  502. UINT WINAPI joyGetNumDevs( void )
  503. {
  504. // simply return the max number of joysticks we can support
  505. JOY_DBGPRINT( JOY_BABBLE, ("joyGetNumDevs: return %d", cJoyMax) );
  506. return cJoyMax;
  507. }
  508. /*****************************************************************************
  509. *
  510. * @doc WINAPI
  511. *
  512. * @func MMRESULT | joyGetPosEx |
  513. *
  514. * Get Joystick Position Information.
  515. * Calls DInput for all the hard work
  516. *
  517. * @parm UINT | idJoy |
  518. *
  519. * Id of the Joystick.
  520. *
  521. * @parm LPJOYINFOEX | pji |
  522. *
  523. * Structure to be filled with Joystick Information data
  524. *
  525. *****************************************************************************/
  526. MMRESULT WINAPI joyGetPosEx( UINT idJoy, LPJOYINFOEX pji )
  527. {
  528. MMRESULT mmRes;
  529. HRESULT hres;
  530. static DWORD dwLastBrake=0xFFFF, dwLastAccl=0xFFFF;
  531. static DWORD dwMaxBrake=0, dwMaxAccl=0;
  532. static DWORD dwMaxY=0xFFFF, dwMidY=0x7FFF, dwMinY=0;
  533. JOY_DBGPRINT( JOY_BABBLE, ("joyGetPosEx: idJoy=%d, pji=0x%08x", idJoy, pji) );
  534. V_WPOINTER(pji, sizeof(JOYINFOEX), MMSYSERR_INVALPARAM);
  535. if ( pji->dwSize < sizeof(JOYINFOEX) )
  536. {
  537. JOY_DBGPRINT( JOY_ERR, ("joyGetPosEx: return JOYERR_PARMS(pji->dwSize < sizeof(JOYINFOEX))") );
  538. return JOYERR_PARMS;
  539. }
  540. DllEnterCrit();
  541. mmRes = JOYERR_NOERROR;
  542. if ( idJoy >= cJoyMax )
  543. {
  544. JOY_DBGPRINT( JOY_ERR, ("joyGetPosEx: return %d (idJoy > 16)", JOYERR_PARMS) );
  545. mmRes = JOYERR_PARMS;
  546. } else if ( SUCCEEDED( hres = joyOpen(idJoy, NULL ) ) )
  547. {
  548. LPJOYDEVICE pJoyDev;
  549. DWORD dwFlags;
  550. pJoyDev = g_pJoyDev[idJoy];
  551. dwFlags = pJoyDev->dwFlags;
  552. /* Have any of the Flag fields that we care about changed ? */
  553. while ( ! fEqualMaskFlFl( JOY_RETURNRAWDATA | JOY_USEDEADZONE ,
  554. pji->dwFlags, /* Desired State */
  555. dwFlags ) /* Current State */
  556. )
  557. {
  558. union {
  559. DIPROPHEADER diph;
  560. DIPROPDWORD dipdw;
  561. DIPROPRANGE diprg;
  562. DIPROPCAL dipcal;
  563. } u;
  564. DIPROPDWORD dipdw;
  565. u.diph.dwSize = sizeof(u.dipdw);
  566. u.diph.dwHeaderSize = sizeof(u.diph);
  567. u.diph.dwObj = 0x0;
  568. u.diph.dwHow = DIPH_DEVICE;
  569. hres = IDirectInputDevice2_Unacquire( pJoyDev->pdid);
  570. if ( SUCCEEDED(hres) )
  571. {
  572. }
  573. else
  574. { // Could not unacquire device
  575. mmRes = JOYERR_UNPLUGGED;
  576. dprintf1( (("Unacquire, FAILED hres=%08lX"), hres ));
  577. break;
  578. }
  579. if ( ! fEqualMaskFlFl( JOY_RETURNRAWDATA, pji->dwFlags, dwFlags ) )
  580. {
  581. /* Change in Calibration Mode */
  582. if( pji->dwFlags & JOY_RETURNRAWDATA )
  583. {
  584. /* RAW data */
  585. u.dipdw.dwData = DIPROPCALIBRATIONMODE_RAW;
  586. SetMaskpFl(JOY_RETURNRAWDATA, &dwFlags );
  587. } else
  588. {
  589. /* Cooked Data */
  590. u.dipdw.dwData = DIPROPCALIBRATIONMODE_COOKED;
  591. ClrMaskpFl(JOY_RETURNRAWDATA, &dwFlags );
  592. }
  593. hres = IDirectInputDevice2_SetProperty(pJoyDev->pdid, DIPROP_CALIBRATIONMODE, &u.dipdw.diph);
  594. if ( SUCCEEDED(hres) )
  595. {
  596. /* Change in Calibration Mode */
  597. if ( pji->dwFlags & JOY_RETURNRAWDATA )
  598. {
  599. u.diph.dwSize = sizeof(u.dipcal);
  600. u.diph.dwObj = DIJOFS_Y;
  601. u.diph.dwHow = DIPH_BYOFFSET;
  602. hres = IDirectInputDevice2_GetProperty( pJoyDev->pdid, DIPROP_CALIBRATION, &u.dipcal.diph );
  603. if ( SUCCEEDED(hres) )
  604. {
  605. dwMaxY = u.dipcal.lMax;
  606. dwMidY = u.dipcal.lCenter;
  607. dwMinY = u.dipcal.lMin;
  608. }
  609. } else
  610. {
  611. u.diph.dwSize = sizeof(u.diprg);
  612. u.diph.dwObj = DIJOFS_Y;
  613. u.diph.dwHow = DIPH_BYOFFSET;
  614. hres = IDirectInputDevice2_GetProperty( pJoyDev->pdid, DIPROP_RANGE, &u.dipcal.diph );
  615. if ( SUCCEEDED(hres) )
  616. {
  617. dwMaxY = u.diprg.lMax;
  618. dwMinY = u.diprg.lMin;
  619. dwMidY = (dwMaxY + dwMinY) >> 1;
  620. }
  621. }
  622. } else
  623. { // SetProperty( ) FAILED
  624. mmRes = JOYERR_UNPLUGGED;
  625. dprintf1((("SetProperty(DIPROP_CALIBRATIONMODE), FAILED hres=%08lX"), hres ));
  626. break;
  627. }
  628. } else if ( ! fEqualMaskFlFl( JOY_USEDEADZONE, pji->dwFlags, dwFlags ) )
  629. {
  630. /* Change in DeadZone */
  631. if ( pji->dwFlags & JOY_USEDEADZONE )
  632. {
  633. /* Default DeadZone */
  634. u.dipdw.dwData = 100 * DEADZONE_PERCENT;
  635. SetMaskpFl(JOY_USEDEADZONE, &dwFlags);
  636. } else
  637. { //
  638. /* No DeadZone */
  639. u.dipdw.dwData = 0x0;
  640. ClrMaskpFl(JOY_USEDEADZONE, &dwFlags);
  641. }
  642. hres = IDirectInputDevice2_SetProperty(pJoyDev->pdid, DIPROP_DEADZONE, &u.dipdw.diph);
  643. if ( SUCCEEDED(hres) )
  644. {
  645. }
  646. else
  647. { // SetProperty( ) FAILED
  648. mmRes = JOYERR_UNPLUGGED;
  649. dprintf4( (("SetProperty(DIPROP_DEADZONE), FAILED hres=%08lX"), hres ));
  650. break;
  651. }
  652. } else
  653. { // Weird Error
  654. break;
  655. }
  656. } // while
  657. pJoyDev->dwFlags = dwFlags;
  658. if ( SUCCEEDED(hres) )
  659. {
  660. WINMMJOYSTATE js;
  661. IDirectInputDevice2_Poll(pJoyDev->pdid);
  662. hres = IDirectInputDevice2_GetDeviceState(pJoyDev->pdid, sizeof(js), &js);
  663. if ( FAILED(hres) )
  664. {
  665. hres = IDirectInputDevice2_Acquire(pJoyDev->pdid);
  666. if ( SUCCEEDED(hres) )
  667. {
  668. IDirectInputDevice2_Poll(pJoyDev->pdid);
  669. hres = IDirectInputDevice2_GetDeviceState(pJoyDev->pdid, sizeof(js), &js);
  670. }
  671. }
  672. if ( SUCCEEDED(hres) )
  673. {
  674. pji->dwButtons = 0;
  675. pji->dwButtonNumber = 0;
  676. /* Button Press Information */
  677. if ( pji->dwFlags & JOY_RETURNBUTTONS )
  678. {
  679. DWORD dwButton;
  680. DWORD dwMinButtonFld;
  681. dwMinButtonFld = min( cJoyPosButtonMax, pJoyDev->dwButtons );
  682. for ( dwButton = 0 ;
  683. dwButton < dwMinButtonFld;
  684. dwButton++
  685. )
  686. {
  687. if ( js.rgbButtons[dwButton] & 0x80 )
  688. {
  689. /* Button Press */
  690. pji->dwButtons |= (0x1 << dwButton);
  691. /* Button Number */
  692. pji->dwButtonNumber++;
  693. }
  694. }
  695. }
  696. /* Axis Information */
  697. pji->dwXpos = (DWORD)js.lX; /* x position */
  698. pji->dwYpos = (DWORD)js.lY; /* y position */
  699. pji->dwRpos = (DWORD)js.lR; /* rudder/4th axis position */
  700. pji->dwZpos = (DWORD)js.lZ; /* z position */
  701. pji->dwUpos = (DWORD)js.lU; /* 5th axis position */
  702. pji->dwVpos = (DWORD)js.lV; /* 6th axis position */
  703. /* Note the WinMM POV is a WORD value */
  704. pji->dwPOV = (WORD)js.dwPOV; /* point of view state */
  705. if ( g_fHasWheel )
  706. {
  707. if( dwMaxAccl < pji->dwYpos ) {
  708. dwMaxAccl = pji->dwYpos;
  709. }
  710. if( dwMaxBrake < pji->dwRpos ) {
  711. dwMaxBrake = pji->dwRpos;
  712. }
  713. /*
  714. * Make up Y value with dwRpos(brake) and dwYpos(accelerator).
  715. */
  716. if( dwLastAccl != pji->dwYpos ) {
  717. dwLastAccl = pji->dwYpos;
  718. pji->dwYpos = pji->dwYpos>>1;
  719. } else if ( dwLastBrake != pji->dwRpos ) {
  720. dwLastBrake = pji->dwRpos;
  721. pji->dwYpos = dwMaxY - (pji->dwRpos>>1);
  722. } else {
  723. if( (pji->dwYpos == dwMaxAccl) && (pji->dwRpos == dwMaxBrake ) ) {
  724. pji->dwYpos = dwMidY;
  725. } else if ( (dwMaxAccl - pji->dwYpos) > (dwMaxBrake - pji->dwRpos) )
  726. /*
  727. * In this case, use percentage can get a little
  728. * more precision, but not worth doing that.
  729. */
  730. {
  731. pji->dwYpos = pji->dwYpos>>1;
  732. } else
  733. {
  734. pji->dwYpos = dwMaxY - (pji->dwRpos>>1);
  735. }
  736. }
  737. pji->dwRpos = 0x0; /* rudder/4th axis position */
  738. }
  739. } else
  740. { // GetDeviceState FAILED
  741. mmRes = JOYERR_UNPLUGGED;
  742. dprintf1(( ("GetDeviceState, FAILED hres=%08lX"), hres ));
  743. }
  744. } else
  745. { // Acquire FAILED
  746. mmRes = JOYERR_UNPLUGGED;
  747. dprintf1(( ("Acquire, FAILED hres=%08lX"), hres ));
  748. }
  749. } else
  750. { // Joy_Open FAILED
  751. mmRes = JOYERR_PARMS;
  752. dprintf1(( ("joyOpen, FAILED hres=%08lX"), hres ));
  753. }
  754. DllLeaveCrit();
  755. if ( mmRes == JOYERR_NOERROR )
  756. {
  757. JOY_DBGPRINT( JOY_BABBLE, ("joyGetPosEx: return OK, x:%d, y:%d, z:%d, r:%d, u:%d, v:%d, btn: %x", \
  758. pji->dwXpos, pji->dwXpos, pji->dwZpos, pji->dwRpos, pji->dwUpos, pji->dwVpos, pji->dwButtons) );
  759. } else
  760. {
  761. JOY_DBGPRINT( JOY_BABBLE, ("joyGetPosEx: return %d", mmRes) );
  762. }
  763. return mmRes;
  764. }
  765. /*****************************************************************************
  766. *
  767. * @doc WINAPI
  768. *
  769. * @func MMRESULT | joyGetPos |
  770. *
  771. * Get Joystick Position Information.
  772. *
  773. * @parm UINT | idJoy |
  774. *
  775. * Id of the Joystick.
  776. *
  777. * @parm LPJOYINFO | pji |
  778. *
  779. * Structure to be filled with Joystick Information data
  780. *
  781. *****************************************************************************/
  782. MMRESULT WINAPI joyGetPos( UINT idJoy, LPJOYINFO pji )
  783. {
  784. JOYINFOEX jiex;
  785. MMRESULT mmRes;
  786. JOY_DBGPRINT( JOY_BABBLE, ("joyGetPos: idJoy=%d, pji=0x%08x", idJoy, pji) );
  787. V_WPOINTER(pji, sizeof(JOYINFO), MMSYSERR_INVALPARAM);
  788. jiex.dwSize = sizeof(jiex);
  789. jiex.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS;
  790. if ( (mmRes = joyGetPosEx (idJoy, &jiex)) == JOYERR_NOERROR )
  791. {
  792. pji->wXpos = (UINT)jiex.dwXpos;
  793. pji->wYpos = (UINT)jiex.dwYpos;
  794. pji->wZpos = (UINT)jiex.dwZpos;
  795. pji->wButtons = (UINT)jiex.dwButtons;
  796. }
  797. if ( mmRes == JOYERR_NOERROR )
  798. {
  799. JOY_DBGPRINT( JOY_BABBLE, ("joyGetPos: return OK, x:%d, y:%d, z:%d, btn:%x", \
  800. pji->wXpos, pji->wXpos, pji->wZpos, pji->wButtons) );
  801. } else
  802. {
  803. JOY_DBGPRINT( JOY_BABBLE, ("joyGetPos: return %d", mmRes) );
  804. }
  805. return mmRes;
  806. }
  807. /****************************************************************************
  808. @doc EXTERNAL
  809. @api UINT | joyGetThreshold | This function queries the current
  810. movement threshold of a joystick device.
  811. @parm UINT | idJoy | Identifies the joystick device to be queried.
  812. @parm PUINT | lpwThreshold | Specifies a far pointer to a UINT variable
  813. that is filled with the movement threshold value.
  814. @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
  815. following error codes:
  816. @flag MMSYSERR_NODRIVER | The joystick driver is not present.
  817. @flag JOYERR_PARMS | The specified joystick device ID <p idJoy> is invalid.
  818. @comm The movement threshold is the distance the joystick must be
  819. moved before a WM_JOYMOVE message is sent to a window that has
  820. captured the device. The threshold is initially zero.
  821. @xref joySetThreshold
  822. ****************************************************************************/
  823. MMRESULT WINAPI joyGetThreshold( UINT idJoy, PUINT puThreshold )
  824. {
  825. HRESULT hres;
  826. MMRESULT mmRes = JOYERR_NOERROR;
  827. JOYCAPSW jc;
  828. JOY_DBGPRINT( JOY_BABBLE, ("joyGetThreshold: idJoy=%d, uThreshold=%d", idJoy, *puThreshold) );
  829. V_WPOINTER(puThreshold, sizeof(UINT), MMSYSERR_INVALPARAM);
  830. if (idJoy >= cJoyMax)
  831. {
  832. JOY_DBGPRINT( JOY_ERR, ("joyGetThreshold: return %d ", MMSYSERR_INVALPARAM) );
  833. return MMSYSERR_INVALPARAM;
  834. }
  835. memset(&jc, 0, sizeof(jc));
  836. DllEnterCrit();
  837. hres = joyOpen(idJoy, &jc);
  838. DllLeaveCrit();
  839. if ( FAILED(hres) )
  840. {
  841. JOY_DBGPRINT( JOY_ERR, ("joyGetThreshold: return MMSYSERROR_NOERROR, but no joystick configured.") );
  842. mmRes = MMSYSERR_INVALPARAM;
  843. } else
  844. {
  845. *puThreshold = g_pJoyDev[idJoy]->uThreshold;
  846. }
  847. JOY_DBGPRINT( JOY_BABBLE, ("joyGetThreshold: return %d", mmRes) );
  848. return mmRes;
  849. }
  850. /****************************************************************************
  851. @doc WINAPI
  852. @api UINT | joySetThreshold | This function sets the movement threshold
  853. of a joystick device.
  854. @parm UINT | idJoy | Identifies the joystick device. This value is either
  855. @parm UINT | uThreshold | Specifies the new movement threshold.
  856. @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
  857. following error codes:
  858. @flag MMSYSERR_NODRIVER | The joystick driver is not present.
  859. @flag JOYERR_PARMS | The specified joystick device ID <p idJoy> is invalid.
  860. @comm The movement threshold is the distance the joystick must be
  861. moved before a MM_JOYMOVE message is sent to a window that has
  862. captured the device.
  863. @xref joyGetThreshold joySetCapture
  864. ****************************************************************************/
  865. MMRESULT WINAPI joySetThreshold(UINT idJoy, UINT uThreshold)
  866. {
  867. HRESULT hres;
  868. MMRESULT mmRes = JOYERR_NOERROR;
  869. JOYCAPSW jc;
  870. JOY_DBGPRINT( JOY_BABBLE, ("joySetThreshold: idJoy=%d, uThreshold=%d", idJoy, uThreshold) );
  871. if ( (idJoy >= cJoyMax) || (uThreshold>0xFFFF) )
  872. {
  873. JOY_DBGPRINT( JOY_ERR, ("joySetThreshold: return MMSYSERR_INVALPARAM (idJoy>16 or uThreshold>65535)") );
  874. return MMSYSERR_INVALPARAM;
  875. }
  876. memset(&jc, 0, sizeof(jc));
  877. DllEnterCrit();
  878. hres = joyOpen(idJoy, &jc);
  879. DllLeaveCrit();
  880. if ( FAILED(hres) )
  881. {
  882. JOY_DBGPRINT( JOY_ERR, ("joySetThreshold: return MMSYSERROR_NOERROR, but no joystick configured") );
  883. mmRes = MMSYSERR_INVALPARAM;
  884. } else
  885. {
  886. g_pJoyDev[idJoy]->uThreshold = (UINT)uThreshold;
  887. }
  888. JOY_DBGPRINT( JOY_BABBLE, ("joySetThreshold: return %d", mmRes) );
  889. return mmRes;
  890. }
  891. /****************************************************************************
  892. @doc WINAPI
  893. @api UINT | joySetCapture | This function causes joystick messages to
  894. be sent to the specified window.
  895. @parm HWND | hWnd | Specifies a handle to the window to which messages
  896. are to be sent.
  897. @parm UINT | idJoy | Identifies the joystick device to be captured.
  898. @parm UINT | uPeriod | Specifies the polling rate, in milliseconds.
  899. @parm BOOL | fChanged | If this parameter is set to TRUE, then messages
  900. are sent only when the position changes by a value greater than the
  901. joystick movement threshold.
  902. @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
  903. following error codes:
  904. @flag MMSYSERR_NODRIVER | The joystick driver is not present.
  905. @flag JOYERR_PARMS | The specified window handle <p hWnd>
  906. or joystick device ID <p idJoy> is invalid.
  907. @flag JOYERR_NOCANDO | Cannot capture joystick input because some
  908. required service (for example, a Windows timer) is unavailable.
  909. @flag JOYERR_UNPLUGGED | The specified joystick is not connected to the
  910. system.
  911. @comm This function fails if the specified joystick device is
  912. currently captured. You should call the <f joyReleaseCapture> function when
  913. the joystick capture is no longer needed. If the window is destroyed,
  914. the joystick will be released automatically.
  915. @xref joyReleaseCapture joySetThreshold joyGetThreshold
  916. ****************************************************************************/
  917. MMRESULT WINAPI joySetCapture(HWND hwnd, UINT idJoy, UINT uPeriod, BOOL fChanged)
  918. {
  919. JOYINFO joyinfo;
  920. LPJOYINFO lpinfo = &joyinfo;
  921. UINT w;
  922. JOYCAPS JoyCaps;
  923. MMRESULT mmRes = MMSYSERR_NOERROR;
  924. JOY_DBGPRINT( JOY_BABBLE, ("joySetCapture: hwnd=0x%08x, idJoy=%d, uPeriod=%d, fChanged=%d", \
  925. hwnd, idJoy, uPeriod, fChanged) );
  926. if ( !hwnd || !IsWindow(hwnd) )
  927. {
  928. JOY_DBGPRINT( JOY_ERR, ("joySetCapture: return JOYERROR_PARMS(hwnd=NULL || !IsWindow(hwnd))"));
  929. return JOYERR_PARMS;
  930. }
  931. if ( idJoy >= cJoyMax )
  932. {
  933. JOY_DBGPRINT( JOY_ERR, ("joySetCapture: return JOYERR_PARMS(idJoy > 16)") );
  934. return JOYERR_PARMS;
  935. }
  936. if ( g_dwNumOpen >= cJoyMaxInWinmm )
  937. {
  938. JOY_DBGPRINT( JOY_ERR, ("joySetCapture: return MMSYSERR_NODRIVER") );
  939. return MMSYSERR_NODRIVER; //we don't support to capture more than two joysticks
  940. }
  941. if ( uPeriod < MIN_PERIOD )
  942. {
  943. uPeriod = MIN_PERIOD;
  944. } else if ( uPeriod > MAX_PERIOD )
  945. {
  946. uPeriod = MAX_PERIOD;
  947. }
  948. if ( g_pJoyDev[idJoy] )
  949. { //already opened
  950. if ( hwnd == g_pJoyDev[idJoy]->hwnd )
  951. {
  952. if( (g_pJoyDev[idJoy]->uPeriod == uPeriod)
  953. && (g_pJoyDev[idJoy]->fChanged = fChanged) ) {
  954. JOY_DBGPRINT( JOY_ERR, ("joySetCapture: return JOYERR_NOCANDO") );
  955. return JOYERR_NOCANDO;
  956. }
  957. g_pJoyDev[idJoy]->uPeriod = uPeriod; //assign new values
  958. g_pJoyDev[idJoy]->fChanged = fChanged;
  959. JOY_DBGPRINT( JOY_ERR, ("joySetCapture: return JOYERR_NOERROR") );
  960. return JOYERR_NOERROR;
  961. } else
  962. {
  963. if ( IsWindow(g_pJoyDev[idJoy]->hwnd) )
  964. { //already get focus
  965. JOY_DBGPRINT( JOY_ERR, ("joySetCapture: return JOYERR_NOCANDO") );
  966. return JOYERR_NOCANDO; //is being used by another windows
  967. }
  968. }
  969. }
  970. if ( joyGetDevCaps (idJoy, &JoyCaps, sizeof(JOYCAPS)) == JOYERR_NOERROR )
  971. {
  972. uPeriod = min(JoyCaps.wPeriodMax,max(JoyCaps.wPeriodMin,uPeriod));
  973. } else
  974. {
  975. JOY_DBGPRINT( JOY_ERR, ("joySetCapture: return MMSYSERR_NODRIVER") );
  976. return MMSYSERR_NODRIVER;
  977. }
  978. // ensure that position info. is ok.
  979. if ( w = joyGetPos(idJoy, lpinfo) )
  980. { //something wrong, so just return
  981. JOY_DBGPRINT( JOY_ERR, ("joySetCapture: return %d", w) );
  982. return(w);
  983. }
  984. DllEnterCrit();
  985. mmRes = (MMRESULT)joyOpen(idJoy, NULL);
  986. if ( SUCCEEDED(mmRes) )
  987. {
  988. if ( !(g_pJoyDev[idJoy]->uIDEvent = SetTimer(NULL, 0, uPeriod, joyPollCallback)) )
  989. {
  990. joyClose(idJoy);
  991. mmRes = JOYERR_NOCANDO;
  992. goto _OUT;
  993. }
  994. g_pJoyDev[idJoy]->hwnd = hwnd;
  995. g_pJoyDev[idJoy]->uIDJoy = g_dwNumOpen;
  996. g_pJoyDev[idJoy]->uPeriod = uPeriod;
  997. g_pJoyDev[idJoy]->fChanged = fChanged;
  998. g_pJoyDev[idJoy]->uThreshold = 0;
  999. g_dwNumOpen++;
  1000. mmRes = JOYERR_NOERROR;
  1001. } else
  1002. {
  1003. mmRes = MMSYSERR_NODRIVER;
  1004. }
  1005. _OUT:
  1006. DllLeaveCrit();
  1007. JOY_DBGPRINT( JOY_BABBLE, ("joySetCapture: return %d", mmRes) );
  1008. return mmRes;
  1009. }
  1010. /****************************************************************************
  1011. @doc WINAPI
  1012. @api UINT | joyReleaseCapture | This function releases the capture
  1013. set by <f joySetCapture> on the specified joystick device.
  1014. @parm UINT | idJoy | Identifies the joystick device to be released.
  1015. This value is either JOYSTICKID1 or JOYSTICK2.
  1016. @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
  1017. following error codes:
  1018. @flag MMSYSERR_NODRIVER | The joystick driver is not present.
  1019. @flag JOYERR_PARMS | The specified joystick device ID <p idJoy> is invalid.
  1020. @xref joySetCapture
  1021. ****************************************************************************/
  1022. MMRESULT WINAPI joyReleaseCapture(UINT idJoy)
  1023. {
  1024. JOY_DBGPRINT( JOY_BABBLE, ("joyReleaseCapture: idJoy=%d", idJoy) );
  1025. if ( idJoy >= cJoyMax )
  1026. {
  1027. JOY_DBGPRINT( JOY_ERR, ("joyReleaseCapture: return JOYERR_PARMS(idJoy > 16)") );
  1028. return JOYERR_PARMS;
  1029. }
  1030. if ( !g_pJoyDev[idJoy] )
  1031. {
  1032. JOY_DBGPRINT( JOY_ERR, ("joyReleaseCapture: return MMSYSERR_NODRIVER") );
  1033. return MMSYSERR_INVALPARAM;
  1034. }
  1035. DllEnterCrit();
  1036. // kill the timer
  1037. if ( g_pJoyDev[idJoy]->uIDEvent )
  1038. {
  1039. KillTimer (NULL, g_pJoyDev[idJoy]->uIDEvent);
  1040. }
  1041. DllLeaveCrit();
  1042. JOY_DBGPRINT( JOY_ERR, ("joyReleaseCapture: return JOYERR_NOERROR") );
  1043. return JOYERR_NOERROR;
  1044. }
  1045. /****************************************************************************
  1046. @doc WINAPI
  1047. @api void | joyPollCallback | Function called for joystick
  1048. timer polling scheme initiated from SetCapture call.
  1049. @parm HWND | hWnd | Identifies the window associated with the timer
  1050. event.
  1051. @parm UINT | wMsg | Specifies the WM_TIMER message.
  1052. @parm UINT | uIDEvent | Specifies the timer's ID.
  1053. @parm DWORD | dwTime | Specifies the current system time.
  1054. ****************************************************************************/
  1055. void CALLBACK joyPollCallback(HWND hWnd, UINT wMsg, UINT_PTR uIDEvent, DWORD dwTime)
  1056. {
  1057. #define diff(w1,w2) (UINT)(w1 > w2 ? w1-w2 : w2-w1)
  1058. static JOYINFO oldInfo[cJoyMaxInWinmm] = {{ 0, 0, 0, 0},{ 0, 0, 0, 0}};
  1059. static LPJOYDEVICE pJoyDev;
  1060. JOYINFO Info;
  1061. UINT idJoy, w ,fBtnMask;
  1062. for ( idJoy=0;idJoy<cJoyMax;idJoy++ )
  1063. {
  1064. if ( g_pJoyDev[idJoy] == NULL )
  1065. continue;
  1066. if ( uIDEvent == g_pJoyDev[idJoy]->uIDEvent )
  1067. {
  1068. pJoyDev = g_pJoyDev[idJoy];
  1069. uIDEvent = pJoyDev->uIDJoy;
  1070. break;
  1071. }
  1072. }
  1073. if ( idJoy == cJoyMax )
  1074. {
  1075. #ifdef DBG
  1076. dprintf1((("MMSYSTEM: Invalid timer handle in joy.c\n") ));
  1077. KillTimer (NULL, uIDEvent);
  1078. #endif
  1079. return;
  1080. }
  1081. if ( !pJoyDev->hwnd || !IsWindow(pJoyDev->hwnd) )
  1082. {
  1083. joyReleaseCapture((UINT)uIDEvent);
  1084. }
  1085. if ( !joyGetPos((UINT)uIDEvent,(LPJOYINFO)&Info) )
  1086. {
  1087. for ( w=0,fBtnMask=1; w<4; w++,fBtnMask <<=1 )
  1088. {
  1089. if ( (Info.wButtons ^ oldInfo[uIDEvent].wButtons) & fBtnMask )
  1090. {
  1091. PostMessage( pJoyDev->hwnd,
  1092. (UINT)(uIDEvent + ((Info.wButtons & fBtnMask) ? MM_JOY1BUTTONDOWN : MM_JOY1BUTTONUP)),
  1093. (WPARAM)(Info.wButtons | fBtnMask << 8),
  1094. MAKELPARAM(Info.wXpos,Info.wYpos));
  1095. }
  1096. }
  1097. if ( !pJoyDev->fChanged ||
  1098. diff(Info.wXpos,oldInfo[uIDEvent].wXpos)>pJoyDev->uThreshold ||
  1099. diff(Info.wYpos,oldInfo[uIDEvent].wYpos)>pJoyDev->uThreshold )
  1100. {
  1101. PostMessage( pJoyDev->hwnd,
  1102. (UINT)(MM_JOY1MOVE+uIDEvent),
  1103. (WPARAM)(Info.wButtons),
  1104. MAKELPARAM(Info.wXpos,Info.wYpos)); // WARNING: note the truncations
  1105. }
  1106. if ( !pJoyDev->fChanged ||
  1107. diff(Info.wZpos,oldInfo[uIDEvent].wZpos)>pJoyDev->uThreshold )
  1108. {
  1109. PostMessage(
  1110. pJoyDev->hwnd,
  1111. (UINT)(MM_JOY1ZMOVE+uIDEvent),
  1112. (WPARAM)Info.wButtons,
  1113. MAKELPARAM(Info.wZpos,0));
  1114. }
  1115. oldInfo[uIDEvent] = Info;
  1116. }
  1117. #undef diff
  1118. }
  1119. void AssignToArray(LPCDIDEVICEOBJECTINSTANCE lpddoi, eCtrls CtrlID, DIOBJECTDATAFORMAT* pDevs)
  1120. {
  1121. if (CtrlID < eSIM_THROTTLE) //axes
  1122. if (!(lpddoi->dwType & DIDFT_AXIS)) //some bizarre FF stuff
  1123. return;
  1124. if (CtrlID < eBTN) //only want first one
  1125. if (pDevs[CtrlID].dwType)
  1126. return;
  1127. //need to save GUIDs for the const data format pointers to pint to
  1128. rgoWinMMGUIDs[CtrlID] = lpddoi->guidType;
  1129. pDevs[CtrlID].pguid = &(rgoWinMMGUIDs[CtrlID]);
  1130. pDevs[CtrlID].dwFlags = lpddoi->dwFlags;
  1131. pDevs[CtrlID].dwOfs = lpddoi->dwOfs;
  1132. pDevs[CtrlID].dwType = lpddoi->dwType;
  1133. }
  1134. //Assigns to the custom data format while preserving the offsets
  1135. void AssignToRGODF(DIOBJECTDATAFORMAT* pDof, int CtrlID)
  1136. {
  1137. AssertF(CtrlID<MAX_FINAL);
  1138. c_rgodfWinMMJoy[CtrlID].pguid = pDof->pguid;
  1139. //c_rgodfWinMMJoy[CtrlID].pguid = NULL;
  1140. c_rgodfWinMMJoy[CtrlID].dwFlags = pDof->dwFlags;
  1141. c_rgodfWinMMJoy[CtrlID].dwType = pDof->dwType;
  1142. }
  1143. /* This version assigns on the basis of Usage/Usage Page
  1144. * This causes problems when using IHV remapping as this
  1145. * swaps the usage/usage page but not the guid. When we
  1146. * then go into dinput to get the values it carefully swaps
  1147. * it all back for us and we lose the mapping. Instead use the
  1148. * next version that assigns on the basis of guid (where applicable)
  1149. * so the dinput remappings remain in place.
  1150. BOOL CALLBACK DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi,LPVOID pvRef)
  1151. {
  1152. AssertF(lpddoi);
  1153. if (!pvRef)
  1154. return DIENUM_STOP; //we can't store them
  1155. //check the data down to dwType is valid
  1156. if (lpddoi->dwSize < 3*sizeof(DWORD)+sizeof(GUID))
  1157. {
  1158. //show some debug info
  1159. return DIENUM_CONTINUE;
  1160. }
  1161. //first we check if it is a button
  1162. if (lpddoi->dwType & DIDFT_BUTTON)
  1163. {
  1164. //the button number is the usage
  1165. //and we want up to 32 of them
  1166. if (lpddoi->wUsage<33)
  1167. AssignToArray(lpddoi,eBTN+lpddoi->wUsage-1,pvRef);
  1168. return DIENUM_CONTINUE;
  1169. }
  1170. switch (lpddoi->wUsagePage) {
  1171. case HID_USAGE_PAGE_GENERIC:
  1172. switch (lpddoi->wUsage) {
  1173. case HID_USAGE_GENERIC_X:
  1174. AssignToArray(lpddoi,eGEN_X,pvRef);
  1175. return DIENUM_CONTINUE;
  1176. case HID_USAGE_GENERIC_Y:
  1177. AssignToArray(lpddoi,eGEN_Y,pvRef);
  1178. return DIENUM_CONTINUE;
  1179. case HID_USAGE_GENERIC_Z:
  1180. AssignToArray(lpddoi,eGEN_Z,pvRef);
  1181. return DIENUM_CONTINUE;
  1182. case HID_USAGE_GENERIC_RX:
  1183. AssignToArray(lpddoi,eGEN_RX,pvRef);
  1184. return DIENUM_CONTINUE;
  1185. case HID_USAGE_GENERIC_RY:
  1186. AssignToArray(lpddoi,eGEN_RY,pvRef);
  1187. return DIENUM_CONTINUE;
  1188. case HID_USAGE_GENERIC_RZ:
  1189. AssignToArray(lpddoi,eGEN_RZ,pvRef);
  1190. return DIENUM_CONTINUE;
  1191. case HID_USAGE_GENERIC_SLIDER:
  1192. AssignToArray(lpddoi,eGEN_SLIDER,pvRef);
  1193. return DIENUM_CONTINUE;
  1194. case HID_USAGE_GENERIC_DIAL:
  1195. AssignToArray(lpddoi,eGEN_DIAL,pvRef);
  1196. return DIENUM_CONTINUE;
  1197. case HID_USAGE_GENERIC_HATSWITCH:
  1198. AssignToArray(lpddoi,eGEN_POV,pvRef);
  1199. return DIENUM_CONTINUE;
  1200. }
  1201. break;
  1202. case HID_USAGE_PAGE_SIMULATION:
  1203. switch (lpddoi->wUsage) {
  1204. case HID_USAGE_SIMULATION_STEERING:
  1205. AssignToArray(lpddoi,eSIM_STEERING,pvRef);
  1206. return DIENUM_CONTINUE;
  1207. case HID_USAGE_SIMULATION_ACCELERATOR:
  1208. AssignToArray(lpddoi,eSIM_ACCELERATOR,pvRef);
  1209. return DIENUM_CONTINUE;
  1210. case HID_USAGE_SIMULATION_THROTTLE:
  1211. AssignToArray(lpddoi,eSIM_THROTTLE,pvRef);
  1212. return DIENUM_CONTINUE;
  1213. case HID_USAGE_SIMULATION_RUDDER:
  1214. AssignToArray(lpddoi,eSIM_RUDDER,pvRef);
  1215. return DIENUM_CONTINUE;
  1216. case HID_USAGE_SIMULATION_BRAKE:
  1217. AssignToArray(lpddoi,eSIM_BRAKE,pvRef);
  1218. return DIENUM_CONTINUE;
  1219. }
  1220. break;
  1221. }
  1222. return DIENUM_CONTINUE;
  1223. }
  1224. ******************************************************************/
  1225. //This one assigns on the basis of GUID
  1226. BOOL CALLBACK DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi,LPVOID pvRef)
  1227. {
  1228. AssertF(lpddoi);
  1229. if (!pvRef)
  1230. return DIENUM_STOP; //we can't store them
  1231. //check the data down to dwType is valid
  1232. if (lpddoi->dwSize < 3*sizeof(DWORD)+sizeof(GUID))
  1233. {
  1234. //show some debug info
  1235. return DIENUM_CONTINUE;
  1236. }
  1237. if (lpddoi->wUsagePage == HID_USAGE_PAGE_GENERIC &&
  1238. lpddoi->wUsage == HID_USAGE_GENERIC_DIAL)
  1239. AssignToArray(lpddoi,eGEN_DIAL,pvRef);
  1240. else if (lpddoi->wUsagePage == HID_USAGE_PAGE_SIMULATION)
  1241. {
  1242. switch (lpddoi->wUsage)
  1243. {
  1244. case HID_USAGE_SIMULATION_STEERING:
  1245. AssignToArray(lpddoi,eSIM_STEERING,pvRef);break;
  1246. case HID_USAGE_SIMULATION_ACCELERATOR:
  1247. AssignToArray(lpddoi,eSIM_ACCELERATOR,pvRef);break;
  1248. case HID_USAGE_SIMULATION_THROTTLE:
  1249. AssignToArray(lpddoi,eSIM_THROTTLE,pvRef);break;
  1250. case HID_USAGE_SIMULATION_RUDDER:
  1251. AssignToArray(lpddoi,eSIM_RUDDER,pvRef);break;
  1252. case HID_USAGE_SIMULATION_BRAKE:
  1253. AssignToArray(lpddoi,eSIM_BRAKE,pvRef);break;
  1254. }
  1255. }
  1256. else if (IsEqualGUID(&(lpddoi->guidType),&GUID_Button))
  1257. {
  1258. //the button number is the usage
  1259. //and we want up to 32 of them
  1260. if (lpddoi->wUsage<33)
  1261. AssignToArray(lpddoi,eBTN+lpddoi->wUsage-1,pvRef);
  1262. }
  1263. else if (IsEqualGUID(&(lpddoi->guidType),&GUID_XAxis))
  1264. AssignToArray(lpddoi,eGEN_X,pvRef);
  1265. else if (IsEqualGUID(&(lpddoi->guidType),&GUID_YAxis))
  1266. AssignToArray(lpddoi,eGEN_Y,pvRef);
  1267. else if (IsEqualGUID(&(lpddoi->guidType),&GUID_ZAxis))
  1268. AssignToArray(lpddoi,eGEN_Z,pvRef);
  1269. else if (IsEqualGUID(&(lpddoi->guidType),&GUID_RxAxis))
  1270. AssignToArray(lpddoi,eGEN_RX,pvRef);
  1271. else if (IsEqualGUID(&(lpddoi->guidType),&GUID_RyAxis))
  1272. AssignToArray(lpddoi,eGEN_RY,pvRef);
  1273. else if (IsEqualGUID(&(lpddoi->guidType),&GUID_RzAxis))
  1274. AssignToArray(lpddoi,eGEN_RZ,pvRef);
  1275. else if (IsEqualGUID(&(lpddoi->guidType),&GUID_Slider))
  1276. AssignToArray(lpddoi,eGEN_SLIDER,pvRef);
  1277. else if (IsEqualGUID(&(lpddoi->guidType),&GUID_POV))
  1278. AssignToArray(lpddoi,eGEN_POV,pvRef);
  1279. return DIENUM_CONTINUE;
  1280. }
  1281. #define USED_RX 0x01
  1282. #define USED_RY 0x02
  1283. //#define USED_RZ 0x04
  1284. //#define USED_RUDDER 0x08
  1285. //#define USED_BRAKE 0x10
  1286. #define USED_THROT 0x20
  1287. #define USED_SLIDER 0x40
  1288. #define USED_DIAL 0x80
  1289. //Perform mapping of ctrls to axes/pov/btns as in joyhid.c
  1290. //return caps word and number of buttons and axes
  1291. void AssignMappings(DIOBJECTDATAFORMAT *dwAll, DWORD *dwCaps, DWORD *dwBtns, DWORD *dwAxes)
  1292. {
  1293. int i;
  1294. BYTE bUsed=0x00; //to prevent dual mapping
  1295. *dwAxes=0;
  1296. //Do the X-Axis
  1297. if (dwAll[eGEN_X].dwType)
  1298. {
  1299. AssignToRGODF(&(dwAll[eGEN_X]),0);
  1300. (*dwAxes)++;
  1301. }
  1302. else if (dwAll[eSIM_STEERING].dwType)
  1303. {
  1304. AssignToRGODF(&(dwAll[eSIM_STEERING]),0);
  1305. (*dwAxes)++;
  1306. }
  1307. else if (dwAll[eGEN_RY].dwType)
  1308. {
  1309. AssignToRGODF(&(dwAll[eGEN_RY]),0);
  1310. bUsed |= USED_RY;
  1311. (*dwAxes)++;
  1312. }
  1313. //Y-Axis
  1314. if (dwAll[eGEN_Y].dwType)
  1315. {
  1316. AssignToRGODF(&(dwAll[eGEN_Y]),1);
  1317. (*dwAxes)++;
  1318. }
  1319. else if (dwAll[eSIM_ACCELERATOR].dwType)
  1320. {
  1321. AssignToRGODF(&(dwAll[eSIM_ACCELERATOR]),1);
  1322. (*dwAxes)++;
  1323. }
  1324. else if (dwAll[eGEN_RX].dwType)
  1325. {
  1326. AssignToRGODF(&(dwAll[eGEN_RX]),1);
  1327. bUsed |= USED_RX;
  1328. (*dwAxes)++;
  1329. }
  1330. //Z-Axis
  1331. if (dwAll[eGEN_Z].dwType)
  1332. {
  1333. AssignToRGODF(&(dwAll[eGEN_Z]),2);
  1334. *dwCaps |= JOYCAPS_HASZ;
  1335. (*dwAxes)++;
  1336. }
  1337. else if (dwAll[eSIM_THROTTLE].dwType)
  1338. {
  1339. AssignToRGODF(&(dwAll[eSIM_THROTTLE]),2);
  1340. *dwCaps |= JOYCAPS_HASZ;
  1341. bUsed |= USED_THROT;
  1342. (*dwAxes)++;
  1343. }
  1344. else if (dwAll[eGEN_SLIDER].dwType)
  1345. {
  1346. AssignToRGODF(&(dwAll[eGEN_SLIDER]),2);
  1347. *dwCaps |= JOYCAPS_HASZ;
  1348. bUsed |= USED_SLIDER;
  1349. (*dwAxes)++;
  1350. }
  1351. else if (dwAll[eGEN_DIAL].dwType)
  1352. {
  1353. AssignToRGODF(&(dwAll[eGEN_DIAL]),2);
  1354. *dwCaps |= JOYCAPS_HASZ;
  1355. bUsed |= USED_DIAL;
  1356. (*dwAxes)++;
  1357. }
  1358. //RUV need use same set
  1359. for (i=0;i<3;++i)
  1360. {
  1361. if (!i) //R Only
  1362. {
  1363. if (dwAll[eSIM_RUDDER].dwType)
  1364. {
  1365. AssignToRGODF(&(dwAll[eSIM_RUDDER]),3);
  1366. *dwCaps |= JOYCAPS_HASR;
  1367. (*dwAxes)++;
  1368. continue;
  1369. }
  1370. if (dwAll[eGEN_RZ].dwType)
  1371. {
  1372. AssignToRGODF(&(dwAll[eGEN_RZ]),3);
  1373. *dwCaps |= JOYCAPS_HASR;
  1374. (*dwAxes)++;
  1375. continue;
  1376. }
  1377. if (dwAll[eSIM_BRAKE].dwType)
  1378. {
  1379. AssignToRGODF(&(dwAll[eSIM_BRAKE]),3);
  1380. *dwCaps |= JOYCAPS_HASR;
  1381. (*dwAxes)++;
  1382. continue;
  1383. }
  1384. }
  1385. if (i<2) //not V
  1386. {
  1387. if (dwAll[eSIM_THROTTLE].dwType && !(bUsed&USED_THROT))
  1388. {
  1389. AssignToRGODF(&(dwAll[eSIM_THROTTLE]),3+i);
  1390. if (!i)
  1391. *dwCaps |= JOYCAPS_HASR;
  1392. else
  1393. *dwCaps |= JOYCAPS_HASU;
  1394. bUsed |= USED_THROT;
  1395. (*dwAxes)++;
  1396. continue;
  1397. }
  1398. if (dwAll[eGEN_SLIDER].dwType && !(bUsed&USED_SLIDER))
  1399. {
  1400. AssignToRGODF(&(dwAll[eGEN_SLIDER]),3+i);
  1401. if (!i)
  1402. *dwCaps |= JOYCAPS_HASR;
  1403. else
  1404. *dwCaps |= JOYCAPS_HASU;
  1405. bUsed |= USED_SLIDER;
  1406. (*dwAxes)++;
  1407. continue;
  1408. }
  1409. if (dwAll[eGEN_DIAL].dwType && !(bUsed&USED_DIAL))
  1410. {
  1411. AssignToRGODF(&(dwAll[eGEN_DIAL]),3+i);
  1412. if (!i)
  1413. *dwCaps |= JOYCAPS_HASR;
  1414. else
  1415. *dwCaps |= JOYCAPS_HASU;
  1416. bUsed |= USED_DIAL;
  1417. (*dwAxes)++;
  1418. continue;
  1419. }
  1420. if (dwAll[eGEN_RY].dwType && !(bUsed&USED_RY))
  1421. {
  1422. AssignToRGODF(&(dwAll[eGEN_RY]),3+i);
  1423. if (!i)
  1424. *dwCaps |= JOYCAPS_HASR;
  1425. else
  1426. *dwCaps |= JOYCAPS_HASU;
  1427. bUsed |= USED_RY;
  1428. (*dwAxes)++;
  1429. continue;
  1430. }
  1431. }
  1432. //All 3
  1433. if (dwAll[eGEN_RX].dwType && !(bUsed&USED_RX))
  1434. {
  1435. AssignToRGODF(&(dwAll[eGEN_RX]),3+i);
  1436. if (!i)
  1437. *dwCaps |= JOYCAPS_HASR;
  1438. else if (i==1)
  1439. *dwCaps |= JOYCAPS_HASU;
  1440. else
  1441. *dwCaps |= JOYCAPS_HASV;
  1442. bUsed |= USED_RX;
  1443. (*dwAxes)++;
  1444. }
  1445. } //RUV loop
  1446. //POV control
  1447. if (dwAll[eGEN_POV].dwType)
  1448. {
  1449. AssignToRGODF(&(dwAll[eGEN_POV]),6);
  1450. *dwCaps |= JOYCAPS_HASPOV;
  1451. }
  1452. //now the buttons
  1453. *dwBtns = 0;
  1454. for (i=0;i<MAX_BTNS;++i)
  1455. {
  1456. if (dwAll[eBTN+i].dwType)
  1457. {
  1458. AssignToRGODF(&(dwAll[eBTN+i]),7+i);
  1459. (*dwBtns)++;
  1460. }
  1461. }
  1462. }
  1463. /*****************************************************************************
  1464. *
  1465. * @doc EXTERNAL
  1466. *
  1467. * @func LRESULT | joyOpen |
  1468. *
  1469. * Called to open a Joystick with a specified Id.
  1470. *
  1471. * @parm UINT | idJoy |
  1472. *
  1473. * Id of the Joystick to be opened.
  1474. *
  1475. * @returns LRESULT
  1476. * DRV_OK indicates the required joystick driver was loaded and
  1477. * can be accessed
  1478. *
  1479. *****************************************************************************/
  1480. HRESULT WINAPI joyOpen(UINT idJoy, LPJOYCAPSW pjc )
  1481. {
  1482. HRESULT hres = S_OK;
  1483. LPJOYDEVICE pJoyDev;
  1484. DWORD dwBtns = 0x00;
  1485. DWORD dwCaps = 0x00;
  1486. DWORD dwAxes = 0x00;
  1487. AssertF(DllInCrit());
  1488. if ( idJoy >= cJoyMax )
  1489. {
  1490. hres = E_FAIL;
  1491. goto done;
  1492. }
  1493. pJoyDev = g_pJoyDev[idJoy];
  1494. if ( pJoyDev == NULL )
  1495. {
  1496. if ( !g_hinstDinputDll )
  1497. {
  1498. g_hinstDinputDll = LoadLibrary(TEXT("DINPUT.DLL"));
  1499. if ( g_hinstDinputDll )
  1500. {
  1501. g_farprocDirectInputCreateW = GetProcAddress( g_hinstDinputDll, "DirectInputCreateW" );
  1502. if ( !g_farprocDirectInputCreateW )
  1503. {
  1504. dprintf1(( ("GetProcAddress(DirectInputCreateW) failed.") ));
  1505. FreeLibrary(g_hinstDinputDll);
  1506. g_hinstDinputDll = 0;
  1507. hres = E_FAIL;
  1508. goto done;
  1509. }
  1510. } else
  1511. {
  1512. dprintf1(( ("LoadLibrary(dinput.dll) failed.") ));
  1513. hres = E_FAIL;
  1514. goto done;
  1515. }
  1516. }
  1517. if ( !g_pdi )
  1518. {
  1519. // Create the DirectInput interface object
  1520. hres = (HRESULT)g_farprocDirectInputCreateW( ghInst, DIRECTINPUT_VERSION, &g_pdi, NULL) ;
  1521. }
  1522. if ( SUCCEEDED(hres) ) {
  1523. // thread will not do anything until we let go oF the critical section
  1524. if ( !g_fThreadExist )
  1525. {
  1526. g_hThreadMonitor = CreateThread(0, 0, joyMonitorThread, 0, 0, &g_dwThreadID);
  1527. if ( g_hThreadMonitor )
  1528. {
  1529. SetThreadPriority( g_hThreadMonitor, THREAD_PRIORITY_LOWEST );
  1530. g_fThreadExist = TRUE;
  1531. }
  1532. CloseHandle( g_hThreadMonitor );
  1533. }
  1534. }
  1535. if ( SUCCEEDED(hres) )
  1536. {
  1537. if ( !g_pdijc )
  1538. {
  1539. /* Query for the JoyConfig interface */
  1540. hres = IDirectInput_QueryInterface(g_pdi,& IID_IDirectInputJoyConfig, &g_pdijc);
  1541. }
  1542. if ( SUCCEEDED(hres) )
  1543. {
  1544. DIJOYCONFIG jc;
  1545. /* Get GUID that maps idJoy */
  1546. jc.dwSize = sizeof(jc);
  1547. IDirectInputJoyConfig_SendNotify( g_pdijc );
  1548. hres = IDirectInputJoyConfig_GetConfig(g_pdijc, idJoy, &jc, DIJC_REGHWCONFIGTYPE | DIJC_GUIDINSTANCE | DIJC_GAIN );
  1549. if ( SUCCEEDED(hres) )
  1550. {
  1551. LPDIRECTINPUTDEVICEW pdidTemp;
  1552. LPDIRECTINPUTDEVICE2W pdid;
  1553. hres = IDirectInput_CreateDevice(g_pdi, &jc.guidInstance, &pdidTemp, NULL);
  1554. /* Create the device object */
  1555. if ( SUCCEEDED(hres) )
  1556. {
  1557. hres = IDirectInputDevice_QueryInterface(pdidTemp, &IID_IDirectInputDevice2, &pdid);
  1558. IDirectInputDevice_Release(pdidTemp);
  1559. (void*)pdidTemp = NULL;
  1560. if ( SUCCEEDED(hres) )
  1561. {
  1562. /* enumerate our controls into the superset*/
  1563. DIOBJECTDATAFORMAT didoAll[MAX_CTRLS];
  1564. int i=0;
  1565. for (i=0;i<MAX_CTRLS;++i)
  1566. {
  1567. didoAll[i].dwFlags = 0;//DIDFT_ANYINSTANCE | DIDFT_OPTIONAL;
  1568. didoAll[i].dwOfs = 0;
  1569. didoAll[i].dwType = 0;
  1570. didoAll[i].pguid = NULL;
  1571. }
  1572. hres = IDirectInputDevice2_EnumObjects(
  1573. pdid,
  1574. DIEnumDeviceObjectsCallback,
  1575. didoAll,
  1576. DIDFT_ALL);
  1577. // c_rgodfWinMMJoy needs to be reset for every device.
  1578. RESET_RGODFWINMMJOY();
  1579. // Assign our values to the custom device format
  1580. AssignMappings(didoAll,&dwCaps,&dwBtns,&dwAxes);
  1581. if ( SUCCEEDED(hres) )
  1582. {
  1583. DIDEVCAPS dc;
  1584. dc.dwSize = sizeof(DIDEVCAPS_DX3);
  1585. hres = IDirectInputDevice2_GetCapabilities(pdid, &dc);
  1586. if ( SUCCEEDED(hres) )
  1587. {
  1588. hres = IDirectInputDevice2_SetCooperativeLevel(pdid, NULL, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND );
  1589. if ( SUCCEEDED(hres) )
  1590. {
  1591. //set to our new custom device format
  1592. hres = IDirectInputDevice2_SetDataFormat(pdid, (LPCDIDATAFORMAT)&c_dfWINMMJoystick);
  1593. if ( SUCCEEDED(hres) )
  1594. {
  1595. pJoyDev = LocalAlloc( LPTR, sizeof(JOYDEVICE) );
  1596. if ( pJoyDev )
  1597. {
  1598. memset( pJoyDev, 0, sizeof(*pJoyDev) );
  1599. pJoyDev->pdid = pdid;
  1600. pJoyDev->dwButtons = dc.dwButtons;
  1601. pJoyDev->dwFlags = 0x0;
  1602. pJoyDev->uState = INUSE;
  1603. // get values for pJoyDev->jcw
  1604. {
  1605. DIDEVICEINSTANCE didi;
  1606. didi.dwSize = sizeof(didi);
  1607. IDirectInputDevice2_Acquire(pdid);
  1608. hres = IDirectInputDevice2_GetDeviceInfo(pdid, &didi);
  1609. if ( SUCCEEDED(hres) )
  1610. {
  1611. DIPROPDWORD dipd;
  1612. if( g_dwEnableWheel ) {
  1613. DIDEVICEOBJECTINSTANCE didoi;
  1614. didoi.dwSize = sizeof(DIDEVICEOBJECTINSTANCE);
  1615. hres = IDirectInputDevice2_GetObjectInfo( pdid, &didoi, DIJOFS_Y, DIPH_BYOFFSET);
  1616. if ( SUCCEEDED(hres) )
  1617. {
  1618. if ( didoi.wUsagePage == 2 && didoi.wUsage == 196 ) // This is Accelerator
  1619. {
  1620. if ( jc.hwc.hws.dwFlags & JOY_HWS_HASR )
  1621. { // Is this Brake?
  1622. hres = IDirectInputDevice2_GetObjectInfo( pdid, &didoi, DIJOFS_RZ, DIPH_BYOFFSET);
  1623. if ( SUCCEEDED(hres) )
  1624. {
  1625. if ( didoi.wUsagePage == 2 && didoi.wUsage == 197 ) // This is Accelerator
  1626. {
  1627. //Yes, this is brake, great!
  1628. g_fHasWheel = TRUE;
  1629. }
  1630. }
  1631. }
  1632. }
  1633. }
  1634. } // g_dwEnableWheel
  1635. memset( &(pJoyDev->jcw), 0, sizeof(pJoyDev->jcw) );
  1636. dipd.diph.dwSize = sizeof(dipd);
  1637. dipd.diph.dwHeaderSize = sizeof(dipd.diph);
  1638. dipd.diph.dwHow = DIPH_BYOFFSET;
  1639. // use our mapped one instead if available
  1640. if (c_rgodfWinMMJoy[6].dwType)
  1641. dipd.diph.dwObj = c_rgodfWinMMJoy[6].dwOfs;
  1642. else
  1643. dipd.diph.dwObj = DIJOFS_POV(0);
  1644. hres = IDirectInputDevice2_GetProperty( pdid , DIPROP_GRANULARITY, & dipd.diph );
  1645. if ( SUCCEEDED(hres) )
  1646. {
  1647. //(pJoyDev->jcw).wCaps |= JOYCAPS_HASPOV; //should now be set by AssignMappings
  1648. AssertF(dwCaps&JOYCAPS_HASPOV);
  1649. //Do this instead to copy VJOYD
  1650. dwCaps |= JOYCAPS_POV4DIR;
  1651. /***************
  1652. if ( dipd.dwData >= 9000 )
  1653. { // 4 directional POV
  1654. (pJoyDev->jcw).wCaps |= JOYCAPS_POV4DIR;
  1655. } else
  1656. { // Continuous POV
  1657. (pJoyDev->jcw).wCaps |= JOYCAPS_POVCTS;
  1658. }
  1659. *****************/
  1660. } else
  1661. {
  1662. hres = S_OK;
  1663. }
  1664. (pJoyDev->jcw).wMid = LOWORD(didi.guidProduct.Data1); // manufacturer ID
  1665. (pJoyDev->jcw).wPid = HIWORD(didi.guidProduct.Data1); // product ID
  1666. LoadString (ghInst,STR_JOYSTICKNAME,(LPTSTR)(&((pJoyDev->jcw).szPname)),cchLENGTH((pJoyDev->jcw).szPname));
  1667. /*
  1668. * Already memset to 0
  1669. *
  1670. (pJoyDev->jcw).wXmin =
  1671. (pJoyDev->jcw).wYmin =
  1672. (pJoyDev->jcw).wZmin =
  1673. (pJoyDev->jcw).wRmin =
  1674. (pJoyDev->jcw).wUmin =
  1675. (pJoyDev->jcw).wVmin = 0;
  1676. */
  1677. (pJoyDev->jcw).wXmax =
  1678. (pJoyDev->jcw).wYmax =
  1679. (pJoyDev->jcw).wZmax =
  1680. (pJoyDev->jcw).wRmax =
  1681. (pJoyDev->jcw).wUmax =
  1682. (pJoyDev->jcw).wVmax = 0xFFFF;
  1683. (pJoyDev->jcw).wPeriodMin = MIN_PERIOD; // minimum message period when captured
  1684. (pJoyDev->jcw).wPeriodMax = MAX_PERIOD; // maximum message period when captured
  1685. //Now set buttons and axes by Assign Mappings
  1686. //(pJoyDev->jcw).wNumAxes = dc.dwAxes; // number of axes in use
  1687. //(pJoyDev->jcw).wNumButtons = dc.dwButtons; // number of buttons
  1688. //(pJoyDev->jcw).wMaxAxes = cJoyPosAxisMax; // maximum number of axes supported
  1689. //(pJoyDev->jcw).wMaxButtons = cJoyPosButtonMax; // maximum number of buttons supported
  1690. (pJoyDev->jcw).wNumAxes = dwAxes;
  1691. (pJoyDev->jcw).wNumButtons = dwBtns;
  1692. (pJoyDev->jcw).wMaxAxes = 6; // maximum number of axes supported
  1693. (pJoyDev->jcw).wMaxButtons = MAX_BTNS; // maximum number of buttons supported
  1694. lstrcpyW((pJoyDev->jcw).szRegKey, cwszREGKEYNAME ); // registry key
  1695. //Copy settings from AssignMappings
  1696. (pJoyDev->jcw).wCaps |= dwCaps;
  1697. /***************
  1698. // Now done in AssignMappings
  1699. if( !g_fHasWheel ) {
  1700. if ( jc.hwc.hws.dwFlags & JOY_HWS_HASZ )
  1701. (pJoyDev->jcw).wCaps |= JOYCAPS_HASZ;
  1702. if ( jc.hwc.hws.dwFlags & JOY_HWS_HASR )
  1703. (pJoyDev->jcw).wCaps |= JOYCAPS_HASR;
  1704. }
  1705. if ( jc.hwc.hws.dwFlags & JOY_HWS_HASU )
  1706. (pJoyDev->jcw).wCaps |= JOYCAPS_HASU;
  1707. if ( jc.hwc.hws.dwFlags & JOY_HWS_HASV )
  1708. (pJoyDev->jcw).wCaps |= JOYCAPS_HASV;
  1709. *******************/
  1710. }
  1711. }
  1712. if( pjc ) {
  1713. memcpy( pjc, &(pJoyDev->jcw), sizeof(pJoyDev->jcw) );
  1714. }
  1715. } else
  1716. { // Local Alloc FAILED
  1717. hres = E_OUTOFMEMORY;
  1718. dprintf1( ("LocalAlloc, FAILED") );
  1719. }
  1720. } else
  1721. { // SetDataFormat FAILED
  1722. dprintf1(( ("SetDataFormat, FAILED hres=%08lX"), hres ));
  1723. }
  1724. } else
  1725. { // SetCooperativeLevel FAILED
  1726. dprintf1(( ("SetCooperativeLevel, FAILED hres=%08lX"), hres ));
  1727. }
  1728. } else
  1729. { // GetCapabilities FAILED
  1730. dprintf1(( ("GetCapabilities, FAILED hres=%08lX"), hres ));
  1731. }
  1732. } else
  1733. { // EnumObjects FAILED
  1734. dprintf1(( ("EnumObjects, FAILED hres=%08lX"), hres ));
  1735. }
  1736. } else
  1737. { // QueryInterface FAILED
  1738. dprintf1(( ("QueryInterface, FAILED hres=%08lX"), hres ));
  1739. }
  1740. /* If we fail to intitialize the device, then release the interface */
  1741. if ( FAILED(hres) )
  1742. {
  1743. LocalFree( (HLOCAL)pJoyDev );
  1744. IDirectInputDevice2_Release(pdid);
  1745. }
  1746. } else
  1747. { // Create Device Failed
  1748. dprintf1(( ("CreateDevice, FAILED hres=%08lX"), hres ));
  1749. }
  1750. } else
  1751. { // JoyGetConfig FAILED
  1752. dprintf1(( ("joyGetConfig, FAILED hres=%08lX"), hres ));
  1753. }
  1754. /* Release the JoyConfig Interface */
  1755. //IDirectInputJoyConfig_Release(pdijc);
  1756. } else
  1757. { // QI for JoyConfig FAILED
  1758. dprintf1(( ("QueryInterface for JoyConfig, FAILED hres=%08lX"), hres ));
  1759. }
  1760. /* Release the Direct Input interface */
  1761. //IDirectInput_Release(pdi);
  1762. } else
  1763. { // IDirectInputCreate FAILED
  1764. dprintf1(( ("IDirectInputCreate, FAILED hres=%08lX"), hres ));
  1765. }
  1766. g_pJoyDev[idJoy] = pJoyDev;
  1767. } else
  1768. { // Device Interface already exists
  1769. pJoyDev->uState = INUSE;
  1770. if( pjc ) {
  1771. memcpy( pjc, &(pJoyDev->jcw), sizeof(pJoyDev->jcw) );
  1772. }
  1773. hres = S_OK;
  1774. }
  1775. done:
  1776. return hres;
  1777. }
  1778. /****************************************************************************
  1779. @doc WINAPI
  1780. @api void | joyMonitorThread | This function monitors whether there is a joystick
  1781. that has not being used for a specific time. If yes, close this joystick. If
  1782. there is no joystick opened. This thread will exit itself.
  1783. ****************************************************************************/
  1784. DWORD WINAPI joyMonitorThread(LPVOID lpv)
  1785. {
  1786. UINT idJoy;
  1787. LPJOYDEVICE pjd;
  1788. BOOL fJoyOpen = TRUE;
  1789. DWORD dwWaitResult;
  1790. while ( fJoyOpen )
  1791. {
  1792. fJoyOpen = FALSE; //prepare to exit, and this thread will die.
  1793. if( g_hEventWinmm ) {
  1794. dwWaitResult = WaitForSingleObject(g_hEventWinmm, 60000);
  1795. if ( dwWaitResult == WAIT_OBJECT_0 ) {
  1796. //DInput has been released.
  1797. JOY_DBGPRINT( JOY_BABBLE, ("joyMonitorThread: DInput has been released.") );
  1798. break;
  1799. } else if ( dwWaitResult == WAIT_TIMEOUT ) {
  1800. ;
  1801. } else {
  1802. //g_hEventWinmm is ABANDONED.
  1803. SleepEx( 60000, FALSE );
  1804. }
  1805. } else {
  1806. //g_hEventWinmm is NULL.
  1807. SleepEx( 60000, FALSE );
  1808. }
  1809. for ( idJoy = 0x0; idJoy < cJoyMax; idJoy++ )
  1810. {
  1811. pjd = g_pJoyDev[idJoy];
  1812. if ( pjd != NULL )
  1813. {
  1814. DllEnterCrit();
  1815. if ( pjd->uState == INUSE )
  1816. {
  1817. pjd->uState = DEATHROW;
  1818. fJoyOpen = TRUE; //A joystick is still likely being used
  1819. } else if ( pjd->uState == DEATHROW )
  1820. {
  1821. pjd->uState = EXECUTE;
  1822. fJoyOpen = TRUE; //A joystick is still likely being used
  1823. } else
  1824. { /* if ( pjd->bState == EXECUTE ) */
  1825. AssertF( pjd->uState == EXECUTE );
  1826. joyClose(idJoy);
  1827. }
  1828. DllLeaveCrit();
  1829. }
  1830. }
  1831. if ( fJoyOpen == FALSE )
  1832. {
  1833. DllEnterCrit();
  1834. joyCloseAll();
  1835. DllLeaveCrit();
  1836. }
  1837. }
  1838. g_fThreadExist = FALSE;
  1839. return 0;
  1840. }
  1841. /*****************************************************************************
  1842. *
  1843. * @doc WINAPI
  1844. *
  1845. * @func VOID | joyClose |
  1846. *
  1847. * Close a Joystick with specific Id.
  1848. *
  1849. * @parm UINT | idJoy |
  1850. *
  1851. * Id of the Joystick to be closed.
  1852. *
  1853. *
  1854. *****************************************************************************/
  1855. void WINAPI joyClose( UINT idJoy )
  1856. {
  1857. if ( idJoy < cJoyMax )
  1858. {
  1859. /* If the device is open, close it */
  1860. if ( g_pJoyDev[idJoy] )
  1861. {
  1862. if ( g_hEventWinmm && WAIT_OBJECT_0 != WaitForSingleObject(g_hEventWinmm, 10))
  1863. {
  1864. //DInput has not been released.
  1865. IDirectInputDevice2_Unacquire(g_pJoyDev[idJoy]->pdid);
  1866. IDirectInputDevice2_Release(g_pJoyDev[idJoy]->pdid);
  1867. }
  1868. /* Free local memory */
  1869. LocalFree( (HLOCAL)g_pJoyDev[idJoy] );
  1870. g_pJoyDev[idJoy] = NULL;
  1871. }
  1872. }
  1873. }
  1874. /*****************************************************************************
  1875. *
  1876. * @doc EXTERNAL
  1877. *
  1878. * @func VOID | joyCloseAll |
  1879. *
  1880. * Close all currently opened Joysticks
  1881. *
  1882. *
  1883. *****************************************************************************/
  1884. void WINAPI joyCloseAll( void )
  1885. {
  1886. UINT idJoy;
  1887. for ( idJoy=0; idJoy<cJoyMax; idJoy++ )
  1888. {
  1889. joyClose(idJoy);
  1890. }
  1891. }
  1892. /****************************************************************************
  1893. @doc WINAPI
  1894. @api MMRESULT | joyConfigChanged | tells the joystick driver to that
  1895. the configuration information about the joystick has changed.
  1896. @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
  1897. following error codes:
  1898. @flag MMSYSERR_BADDEVICEID | The joystick driver is not present.
  1899. @comm This is used by configuration utilites to tell the driver
  1900. to update its info. As well, it can be used by apps to
  1901. set specific capabilites. This will be documented later...
  1902. ****************************************************************************/
  1903. MMRESULT WINAPI joyConfigChanged( DWORD dwFlags )
  1904. {
  1905. JOY_DBGPRINT( JOY_BABBLE, ("joyConfigChanged: dwFalgs=0x%08x", dwFlags) );
  1906. if ( dwFlags )
  1907. {
  1908. JOY_DBGPRINT( JOY_BABBLE, ("joyConfigChanged: dwFalgs=0x%08x", dwFlags) );
  1909. return JOYERR_PARMS;
  1910. }
  1911. DllEnterCrit();
  1912. joyCloseAll();
  1913. DllLeaveCrit();
  1914. PostMessage (HWND_BROADCAST, g_wmJoyChanged, 0, 0L);
  1915. JOY_DBGPRINT( JOY_BABBLE, ("joyConfigChanged: return 0") );
  1916. return 0L;
  1917. }
  1918. /****************************************************************************
  1919. @doc INTERNAL
  1920. @api UINT | joySetCalibration | This function sets the values used to
  1921. convert the values returned by the joystick drivers GetPos function
  1922. to the range specified in GetDevCaps.
  1923. @parm UINT | idJoy | Identifies the joystick device
  1924. @parm PUINT | pwXbase | Specifies the base value for the X pot. The
  1925. previous value will be copied back to the variable pointed to here.
  1926. @parm PUINT | pwXdelta | Specifies the delta value for the X pot. The
  1927. previous value will be copied back to the variable pointed to here.
  1928. @parm PUINT | pwYbase | Specifies the base value for the Y pot. The
  1929. previous value will be copied back to the variable pointed to here.
  1930. @parm PUINT | pwYdelta | Specifies the delta value for the Y pot. The
  1931. previous value will be copied back to the variable pointed to here.
  1932. @parm PUINT | pwZbase | Specifies the base value for the Z pot. The
  1933. previous value will be copied back to the variable pointed to here.
  1934. @parm PUINT | pwZdelta | Specifies the delta value for the Z pot. The
  1935. previous value will be copied back to the variable pointed to here.
  1936. @rdesc The return value is zero if the function was successful, otherwise
  1937. it is an error number.
  1938. @comm The base represents the lowest value the joystick driver returns,
  1939. whereas the delta represents the multiplier to use to convert
  1940. the actual value returned by the driver to the valid range
  1941. for the joystick API's.
  1942. i.e. If the driver returns a range of 43-345 for the X pot, and
  1943. the valid mmsystem API range is 0-65535, the base value will be
  1944. 43, and the delta will be 65535/(345-43)=217. Thus the base,
  1945. and delta convert 43-345 to a range of 0-65535 with the formula:
  1946. ((wXvalue-43)*217) , where wXvalue was given by the joystick driver.
  1947. ****************************************************************************/
  1948. // !!! We don't support it in WINMM again.
  1949. UINT APIENTRY joySetCalibration(UINT id, PUINT pwXbase, PUINT pwXdelta,
  1950. PUINT pwYbase, PUINT pwYdelta, PUINT pwZbase,
  1951. PUINT pwZdelta)
  1952. {
  1953. JOY_DBGPRINT( JOY_BABBLE, ("joySetCalibration: not supported, please use DINPUT.") );
  1954. return 0;
  1955. }
  1956. /************************************************************
  1957. Debug
  1958. *************************************************************/
  1959. #ifdef DBG
  1960. int g_cCrit = -1;
  1961. UINT g_thidCrit;
  1962. TCHAR g_tszLogFile[MAX_PATH];
  1963. #endif
  1964. /*****************************************************************************
  1965. *
  1966. * @doc WINAPI
  1967. *
  1968. * @func void | //DllEnterCrit |
  1969. *
  1970. * Take the DLL critical section.
  1971. *
  1972. * The DLL critical section is the lowest level critical section.
  1973. * You may not attempt to acquire any other critical sections or
  1974. * yield while the DLL critical section is held. Failure to
  1975. * comply is a violation of the semaphore hierarchy and will
  1976. * lead to deadlocks.
  1977. *
  1978. *****************************************************************************/
  1979. void WINAPI DllEnterCrit(void)
  1980. {
  1981. EnterCriticalSection(&joyCritSec);
  1982. #ifdef DBG
  1983. if ( ++g_cCrit == 0 )
  1984. {
  1985. g_thidCrit = GetCurrentThreadId();
  1986. }
  1987. AssertF(g_thidCrit == GetCurrentThreadId());
  1988. #endif
  1989. }
  1990. /*****************************************************************************
  1991. *
  1992. * @doc WINAPI
  1993. *
  1994. * @func void | //DllLeaveCrit |
  1995. *
  1996. * Leave the DLL critical section.
  1997. *
  1998. *****************************************************************************/
  1999. void WINAPI DllLeaveCrit( void )
  2000. {
  2001. #ifdef DBG
  2002. AssertF(g_thidCrit == GetCurrentThreadId());
  2003. AssertF(g_cCrit >= 0);
  2004. if ( --g_cCrit < 0 )
  2005. {
  2006. g_thidCrit = 0;
  2007. }
  2008. #endif
  2009. LeaveCriticalSection(&joyCritSec);
  2010. }
  2011. /*****************************************************************************
  2012. *
  2013. * @doc WINAPI
  2014. *
  2015. * @func void | DllInCrit |
  2016. *
  2017. * Nonzero if we are in the DLL critical section.
  2018. *
  2019. *****************************************************************************/
  2020. #ifdef DBG
  2021. BOOL WINAPI DllInCrit( void )
  2022. {
  2023. return( g_cCrit >= 0 && g_thidCrit == GetCurrentThreadId() );
  2024. }
  2025. #endif
  2026. #ifdef DBG
  2027. int WINAPI AssertPtszPtszLn(LPCTSTR ptszExpr, LPCTSTR ptszFile, int iLine)
  2028. {
  2029. winmmDbgOut( ("Assertion failed: `%s' at %s(%d)"), ptszExpr, ptszFile, iLine);
  2030. DebugBreak();
  2031. return 0;
  2032. }
  2033. void joyDbgOut(LPSTR lpszFormat, ...)
  2034. {
  2035. char buf[512];
  2036. UINT n;
  2037. va_list va;
  2038. n = wsprintfA(buf, "WINMM::joy: ");
  2039. va_start(va, lpszFormat);
  2040. n += vsprintf(buf+n, lpszFormat, va);
  2041. va_end(va);
  2042. buf[n++] = '\n';
  2043. buf[n] = 0;
  2044. OutputDebugStringA(buf);
  2045. Sleep(0); // let terminal catch up
  2046. }
  2047. #endif
  2048. /*****************************************************************************
  2049. *
  2050. * @doc
  2051. *
  2052. * @func HRESULT | hresMumbleKeyEx |
  2053. *
  2054. * Either open or create the key, depending on the degree
  2055. * of access requested.
  2056. *
  2057. * @parm HKEY | hk |
  2058. *
  2059. * Base key.
  2060. *
  2061. * @parm LPCTSTR | ptszKey |
  2062. *
  2063. * Name of subkey, possibly NULL.
  2064. *
  2065. * @parm REGSAM | sam |
  2066. *
  2067. * Security access mask.
  2068. *
  2069. * @parm DWORD | dwOptions |
  2070. * Options for RegCreateEx
  2071. *
  2072. * @parm PHKEY | phk |
  2073. *
  2074. * Receives output key.
  2075. *
  2076. * @returns
  2077. *
  2078. * Return value from <f RegOpenKeyEx> or <f RegCreateKeyEx>,
  2079. * converted to an <t HRESULT>.
  2080. *
  2081. *****************************************************************************/
  2082. HRESULT hresMumbleKeyEx(HKEY hk, LPCTSTR ptszKey, REGSAM sam, DWORD dwOptions, PHKEY phk)
  2083. {
  2084. HRESULT hres;
  2085. LONG lRc;
  2086. /*
  2087. * If caller is requesting write access, then create the key.
  2088. * Else just open it.
  2089. */
  2090. if ( IsWriteSam(sam) )
  2091. {
  2092. lRc = RegOpenKeyEx(hk, ptszKey, 0, sam, phk);
  2093. if ( lRc == ERROR_SUCCESS )
  2094. {
  2095. // Don't need to create it already exists
  2096. }
  2097. else
  2098. {
  2099. lRc = RegCreateKeyEx(hk, ptszKey, 0, 0,
  2100. dwOptions,
  2101. sam, 0, phk, 0);
  2102. }
  2103. } else
  2104. {
  2105. lRc = RegOpenKeyEx(hk, ptszKey, 0, sam, phk);
  2106. }
  2107. if ( lRc == ERROR_SUCCESS )
  2108. {
  2109. hres = S_OK;
  2110. } else
  2111. {
  2112. if ( lRc == ERROR_KEY_DELETED || lRc == ERROR_BADKEY )
  2113. {
  2114. lRc = ERROR_FILE_NOT_FOUND;
  2115. }
  2116. hres = hresLe(lRc);
  2117. }
  2118. return hres;
  2119. }