Source code of Windows XP (NT5)
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.

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