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.

725 lines
21 KiB

  1. /******************************************************************************
  2. Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
  3. Title: joy.c - MMSYSTEM Joystick interface code
  4. Version: 1.00
  5. Date: 10-Jun-1990
  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. *****************************************************************************/
  15. #include <windows.h>
  16. #include "mmsystem.h"
  17. #include "mmddk.h"
  18. #include "mmsysi.h"
  19. #include "thunks.h"
  20. // Put init and terminate code in correct segment.
  21. static void NEAR PASCAL joyGetCalibration(void);
  22. #pragma alloc_text( INIT, JoyInit )
  23. #pragma alloc_text( INIT, joyGetCalibration)
  24. /* -------------------------------------------------------------------------
  25. ** Thunking stuff
  26. ** -------------------------------------------------------------------------
  27. */
  28. extern JOYMESSAGEPROC PASCAL joy32Message;
  29. /****************************************************************************
  30. strings
  31. ****************************************************************************/
  32. extern char far szNull[]; // in INIT.C
  33. extern char far szSystemIni[];
  34. extern char far szJoystick[];
  35. extern char far szJoystickDrv[];
  36. extern char far szDrivers[];
  37. char szJoyKey[] = "JoyCal ";
  38. /****************************************************************************
  39. Joystick Capture Internal Structure
  40. ****************************************************************************/
  41. typedef struct joycapture_tag {
  42. HWND hWnd;
  43. UINT wPeriod;
  44. BOOL bChanged;
  45. UINT wThreshold;
  46. UINT wIDEvent;
  47. } JOYCAPTURE;
  48. #define iJoyMax 2
  49. #define JOY_UNINITIALIZED 0xFFFF
  50. // !!! Code assumes these constants equal 0 and 1
  51. #if JOYSTICKID1 != 0
  52. ERROR IN ASSUMMED CONSTANT
  53. #endif
  54. #if JOYSTICKID2 != 1
  55. ERROR IN ASSUMMED CONSTANT
  56. #endif
  57. /****************************************************************************
  58. Local data
  59. ****************************************************************************/
  60. static JOYCAPTURE JoyCapture[iJoyMax];
  61. static HDRVR hDrvJoy[iJoyMax];
  62. static UINT wNumDevs = JOY_UNINITIALIZED;
  63. void CALLBACK joyPollCallback(HWND hWnd, UINT wMsg, UINT wIDEvent, DWORD dwTime);
  64. /****************************************************************************
  65. @doc INTERNAL
  66. @api void | joyGetCalibration | Retrieve and set calibration from
  67. [joystick.drv] section of system.ini file.
  68. ****************************************************************************/
  69. // !!! need to do clean up of strings in all of mmsystem
  70. static void NEAR PASCAL joyGetCalibration(void)
  71. {
  72. char szKeyName[sizeof(szJoyKey)];
  73. #define hexval(h) (int)(h>='a'?h-'a'+10:h-'0')
  74. UINT val[6];
  75. UINT wDev,wVal;
  76. int hv;
  77. char c,sz[80],far *psz;
  78. lstrcpy(szKeyName, szJoyKey);
  79. for (wDev=0; wDev < wNumDevs; wDev++)
  80. {
  81. szKeyName[sizeof(szKeyName)-2] = (char)(wDev + '0');
  82. if (GetPrivateProfileString(szJoystickDrv,
  83. szKeyName,szNull,sz,sizeof(sz),szSystemIni))
  84. {
  85. AnsiLower(sz);
  86. for (psz=sz,wVal=0; c = *psz, wVal < 6; psz++)
  87. {
  88. if (c != ' ')
  89. {
  90. hv=0;
  91. do {
  92. hv = (hv << 4) + hexval(c);
  93. } while ((c=*++psz) && (c!=' '));
  94. val[wVal++] = hv;
  95. }
  96. }
  97. joySetCalibration (wDev,val+0,val+1,val+2,val+3,val+4,val+5);
  98. }
  99. }
  100. }
  101. /****************************************************************************
  102. @doc INTERNAL
  103. @api BOOL | JoyInit | This function initializes the joystick services.
  104. @rdesc The return value is TRUE if the services are initialised, FALSE
  105. if an error occurs
  106. ****************************************************************************/
  107. BOOL FAR PASCAL JoyInit(void)
  108. {
  109. // Only attempt initialization once.
  110. if (wNumDevs != JOY_UNINITIALIZED) {
  111. return FALSE;
  112. }
  113. else {
  114. wNumDevs = 0;
  115. }
  116. wNumDevs = joyMessage( (HDRVR)1, JDD_GETNUMDEVS, 0L, 0L );
  117. // Make sure driver was installed.
  118. if (joy32Message == NULL) {
  119. return FALSE;
  120. }
  121. switch ( wNumDevs ) {
  122. case 2:
  123. hDrvJoy[1] = (HDRVR)2;
  124. /* fall thru */
  125. case 1:
  126. hDrvJoy[0] = (HDRVR)1;
  127. break;
  128. default:
  129. return FALSE;
  130. }
  131. // Initialize joycapture...
  132. // Code relies on hWnd being NULL or an invalid window handle
  133. // if joystick is not captured.
  134. JoyCapture[0].hWnd = NULL;
  135. JoyCapture[1].hWnd = NULL;
  136. // Code relies on joystick threshold being initialized to a rational
  137. // value. 0 essentially turns threshold off - any change in joystick
  138. // position will be reported.
  139. JoyCapture[0].wThreshold= 0;
  140. JoyCapture[1].wThreshold= 0;
  141. JoyCapture[0].wIDEvent= 0;
  142. JoyCapture[1].wIDEvent= 0;
  143. // bChanged, and wPeriod do not need initializing.
  144. joyGetCalibration ();
  145. return TRUE;
  146. }
  147. /****************************************************************************
  148. *
  149. * MMSYSTEM JOYSTICK API'S
  150. *
  151. ****************************************************************************/
  152. /****************************************************************************
  153. @doc EXTERNAL
  154. @api UINT | joyGetDevCaps | This function queries a joystick device to
  155. determine its capabilities.
  156. @parm UINT | wId | Identifies the device to be queried. This value
  157. is either JOYSTICKID1 or JOYSTICKID2.
  158. @parm LPJOYCAPS | lpCaps | Specifies a far pointer to a <t JOYCAPS>
  159. data structure. This structure is filled with information about the
  160. capabilities of the joystick device.
  161. @parm UINT | wSize | Specifies the size of the <t JOYCAPS> structure.
  162. @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
  163. following error codes:
  164. @flag MMSYSERR_NODRIVER | The joystick driver is not present.
  165. @flag JOYERR_PARMS | The specified joystick device ID <p wId> is invalid.
  166. @comm Use <f joyGetNumDevs> to determine the number of
  167. joystick devices supported by the driver.
  168. @xref joyGetNumDevs
  169. ****************************************************************************/
  170. UINT WINAPI joyGetDevCaps(UINT wId, LPJOYCAPS lpCaps, UINT wSize)
  171. {
  172. V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
  173. if ((!hDrvJoy[0] && !JoyInit()) || (wId >= iJoyMax))
  174. return MMSYSERR_NODRIVER;
  175. if (wId >= wNumDevs)
  176. return JOYERR_PARMS;
  177. return joyMessage( hDrvJoy[wId], JDD_GETDEVCAPS,
  178. (DWORD)lpCaps, (DWORD)wSize );
  179. }
  180. /****************************************************************************
  181. @doc EXTERNAL
  182. @api UINT | joyGetNumDevs | This function returns the number of joystick
  183. devices supported by the system.
  184. @rdesc Returns the number of joystick devices supported by the joystick
  185. driver. If no driver is present, the function returns zero.
  186. @comm Use <f joyGetPos> to determine whether a given
  187. joystick is actually attached to the system. The <f joyGetPos> function returns
  188. a JOYERR_UNPLUGGED error code if the specified joystick is not connected.
  189. @xref joyGetDevCaps joyGetPos
  190. ****************************************************************************/
  191. UINT WINAPI joyGetNumDevs(void)
  192. {
  193. // Return 0 on error (Can't return JOYERR_NODRIVER
  194. // since no way to distinguish error code from valid count.)
  195. if (!hDrvJoy[0] && !JoyInit())
  196. return 0;
  197. return wNumDevs;
  198. }
  199. /****************************************************************************
  200. @doc EXTERNAL
  201. @api UINT | joyGetPos | This function queries for the position and button
  202. activity of a joystick device.
  203. @parm UINT | wId | Identifies the joystick device to be queried.
  204. This value is either JOYSTICKID1 or JOYSTICKID2.
  205. @parm LPJOYINFO | lpInfo | Specifies a far pointer to a <t JOYINFO>
  206. data structure. This structure is filled with information about the
  207. position and button activity of the joystick device.
  208. @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
  209. following error codes:
  210. @flag MMSYSERR_NODRIVER | The joystick driver is not present.
  211. @flag JOYERR_PARMS | The specified joystick device ID <p wId> is invalid.
  212. @flag JOYERR_UNPLUGGED | The specified joystick is not connected to the
  213. system.
  214. ****************************************************************************/
  215. UINT WINAPI joyGetPos(UINT wId, LPJOYINFO lpInfo)
  216. {
  217. V_WPOINTER(lpInfo, sizeof(JOYINFO), MMSYSERR_INVALPARAM);
  218. if ((!hDrvJoy[0] && !JoyInit()) || (wId >= iJoyMax))
  219. return MMSYSERR_NODRIVER;
  220. if (wId >= wNumDevs)
  221. return JOYERR_PARMS;
  222. return joyMessage( hDrvJoy[wId], JDD_GETPOS, (DWORD)lpInfo, 0L );
  223. }
  224. /****************************************************************************
  225. @doc EXTERNAL
  226. @api UINT | joyGetThreshold | This function queries the current
  227. movement threshold of a joystick device.
  228. @parm UINT | wId | Identifies the joystick device to be queried.
  229. This value is either JOYSTICKID1 or JOYSTICKID2.
  230. @parm UINT FAR* | lpwThreshold | Specifies a far pointer to a UINT variable
  231. that is filled with the movement threshold value.
  232. @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
  233. following error codes:
  234. @flag MMSYSERR_NODRIVER | The joystick driver is not present.
  235. @flag JOYERR_PARMS | The specified joystick device ID <p wId> is invalid.
  236. @comm The movement threshold is the distance the joystick must be
  237. moved before a WM_JOYMOVE message is sent to a window that has
  238. captured the device. The threshold is initially zero.
  239. @xref joySetThreshold
  240. ****************************************************************************/
  241. UINT WINAPI joyGetThreshold(UINT wId, UINT FAR* lpwThreshold)
  242. {
  243. V_WPOINTER(lpwThreshold, sizeof(UINT), MMSYSERR_INVALPARAM);
  244. if (!hDrvJoy[0] && !JoyInit())
  245. return MMSYSERR_NODRIVER;
  246. if (wId >= iJoyMax)
  247. return MMSYSERR_INVALPARAM;
  248. if (wId >= wNumDevs)
  249. return JOYERR_PARMS;
  250. *lpwThreshold = (JoyCapture[wId].wThreshold);
  251. return JOYERR_NOERROR;
  252. }
  253. /****************************************************************************
  254. @doc EXTERNAL
  255. @api UINT | joyReleaseCapture | This function releases the capture
  256. set by <f joySetCapture> on the specified joystick device.
  257. @parm UINT | wId | Identifies the joystick device to be released.
  258. This value is either JOYSTICKID1 or JOYSTICK2.
  259. @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
  260. following error codes:
  261. @flag MMSYSERR_NODRIVER | The joystick driver is not present.
  262. @flag JOYERR_PARMS | The specified joystick device ID <p wId> is invalid.
  263. @xref joySetCapture
  264. ****************************************************************************/
  265. UINT WINAPI joyReleaseCapture(UINT wId)
  266. {
  267. if (!hDrvJoy[0] && !JoyInit())
  268. return MMSYSERR_NODRIVER;
  269. if (wId >= iJoyMax)
  270. return MMSYSERR_INVALPARAM;
  271. if (wId >= wNumDevs)
  272. return JOYERR_PARMS;
  273. if (JoyCapture[wId].hWnd == NULL)
  274. return JOYERR_NOERROR;
  275. KillTimer (NULL, JoyCapture[wId].wIDEvent);
  276. JoyCapture[wId].wIDEvent = 0;
  277. JoyCapture[wId].hWnd = NULL;
  278. return JOYERR_NOERROR;
  279. }
  280. /****************************************************************************
  281. @doc EXTERNAL
  282. @api UINT | joySetCapture | This function causes joystick messages to
  283. be sent to the specified window.
  284. @parm HWND | hWnd | Specifies a handle to the window to which messages
  285. are to be sent.
  286. @parm UINT | wId | Identifies the joystick device to be captured.
  287. This value is either JOYSTICKID1 or JOYSTICKID2.
  288. @parm UINT | wPeriod | Specifies the polling rate, in milliseconds.
  289. @parm BOOL | bChanged | If this parameter is set to TRUE, then messages
  290. are sent only when the position changes by a value greater than the
  291. joystick movement threshold.
  292. @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
  293. following error codes:
  294. @flag MMSYSERR_NODRIVER | The joystick driver is not present.
  295. @flag JOYERR_PARMS | The specified window handle <p hWnd>
  296. or joystick device ID <p wId> is invalid.
  297. @flag JOYERR_NOCANDO | Cannot capture joystick input because some
  298. required service (for example, a Windows timer) is unavailable.
  299. @flag JOYERR_UNPLUGGED | The specified joystick is not connected to the
  300. system.
  301. @comm This function fails if the specified joystick device is
  302. currently captured. You should call the <f joyReleaseCapture> function when
  303. the joystick capture is no longer needed. If the window is destroyed,
  304. the joystick will be released automatically.
  305. @xref joyReleaseCapture joySetThreshold joyGetThreshold
  306. ****************************************************************************/
  307. UINT WINAPI joySetCapture(HWND hwnd, UINT wId, UINT wPeriod, BOOL bChanged )
  308. {
  309. JOYINFO joyinfo;
  310. LPJOYINFO lpinfo = &joyinfo;
  311. UINT w;
  312. JOYCAPS JoyCaps;
  313. if (!hwnd || !IsWindow(hwnd))
  314. return JOYERR_PARMS;
  315. if (!hDrvJoy[0] && !JoyInit())
  316. return MMSYSERR_NODRIVER;
  317. if (wId >= iJoyMax)
  318. return MMSYSERR_INVALPARAM;
  319. if (wId >= wNumDevs)
  320. return JOYERR_PARMS;
  321. if (JoyCapture[wId].hWnd)
  322. if (IsWindow(JoyCapture[wId].hWnd))
  323. return JOYERR_NOCANDO;
  324. else
  325. joyReleaseCapture(wId);
  326. if (joyGetDevCaps (wId, &JoyCaps, sizeof(JOYCAPS)) == 0)
  327. wPeriod = min(JoyCaps.wPeriodMax,max(JoyCaps.wPeriodMin,wPeriod));
  328. else
  329. return JOYERR_NOCANDO;
  330. // ensure that position info. is ok.
  331. if (w = joyGetPos(wId, lpinfo))
  332. return (w);
  333. JoyCapture[wId].wPeriod = wPeriod;
  334. JoyCapture[wId].bChanged = bChanged;
  335. if (!(JoyCapture[wId].wIDEvent = SetTimer(NULL, 0, wPeriod, (TIMERPROC)joyPollCallback)))
  336. {
  337. DOUT("MMSYSTEM: Couldn't allocate timer in joy.c\r\n");
  338. return JOYERR_NOCANDO;
  339. }
  340. JoyCapture[wId].hWnd = hwnd;
  341. return JOYERR_NOERROR;
  342. }
  343. /****************************************************************************
  344. @doc EXTERNAL
  345. @api UINT | joySetThreshold | This function sets the movement threshold
  346. of a joystick device.
  347. @parm UINT | wId | Identifies the joystick device. This value is either
  348. JOYSTICKID1 or JOYSTICKID2.
  349. @parm UINT | wThreshold | Specifies the new movement threshold.
  350. @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
  351. following error codes:
  352. @flag MMSYSERR_NODRIVER | The joystick driver is not present.
  353. @flag JOYERR_PARMS | The specified joystick device ID <p wId> is invalid.
  354. @comm The movement threshold is the distance the joystick must be
  355. moved before a MM_JOYMOVE message is sent to a window that has
  356. captured the device.
  357. @xref joyGetThreshold joySetCapture
  358. ****************************************************************************/
  359. UINT WINAPI joySetThreshold(UINT wId, UINT wThreshold)
  360. {
  361. if (!hDrvJoy[0] && !JoyInit())
  362. return MMSYSERR_NODRIVER;
  363. if (wId >= iJoyMax)
  364. return MMSYSERR_INVALPARAM;
  365. if (wId >= wNumDevs)
  366. return JOYERR_PARMS;
  367. JoyCapture[wId].wThreshold = wThreshold;
  368. return JOYERR_NOERROR;
  369. }
  370. /****************************************************************************
  371. @doc INTERNAL
  372. @api UINT | joySetCalibration | This function sets the values used to
  373. convert the values returned by the joystick drivers GetPos function
  374. to the range specified in GetDevCaps.
  375. @parm UINT | wId | Identifies the joystick device
  376. @parm UINT FAR* | pwXbase | Specifies the base value for the X pot. The
  377. previous value will be copied back to the variable pointed to here.
  378. @parm UINT FAR* | pwXdelta | Specifies the delta value for the X pot. The
  379. previous value will be copied back to the variable pointed to here.
  380. @parm UINT FAR* | pwYbase | Specifies the base value for the Y pot. The
  381. previous value will be copied back to the variable pointed to here.
  382. @parm UINT FAR* | pwYdelta | Specifies the delta value for the Y pot. The
  383. previous value will be copied back to the variable pointed to here.
  384. @parm UINT FAR* | pwZbase | Specifies the base value for the Z pot. The
  385. previous value will be copied back to the variable pointed to here.
  386. @parm UINT FAR* | pwZdelta | Specifies the delta value for the Z pot. The
  387. previous value will be copied back to the variable pointed to here.
  388. @rdesc The return value is zero if the function was successful, otherwise
  389. it is an error number.
  390. @comm The base represents the lowest value the joystick driver returns,
  391. whereas the delta represents the multiplier to use to convert
  392. the actual value returned by the driver to the valid range
  393. for the joystick API's.
  394. i.e. If the driver returns a range of 43-345 for the X pot, and
  395. the valid mmsystem API range is 0-65535, the base value will be
  396. 43, and the delta will be 65535/(345-43)=217. Thus the base,
  397. and delta convert 43-345 to a range of 0-65535 with the formula:
  398. ((wXvalue-43)*217) , where wXvalue was given by the joystick driver.
  399. ****************************************************************************/
  400. UINT WINAPI joySetCalibration( UINT wId,
  401. UINT FAR* pwXbase,
  402. UINT FAR* pwXdelta,
  403. UINT FAR* pwYbase,
  404. UINT FAR* pwYdelta,
  405. UINT FAR* pwZbase,
  406. UINT FAR* pwZdelta )
  407. {
  408. JOYCALIBRATE oldCal,newCal;
  409. UINT w;
  410. if (!hDrvJoy[0] && !JoyInit())
  411. return MMSYSERR_NODRIVER;
  412. if (wId >= wNumDevs)
  413. return JOYERR_PARMS;
  414. newCal.wXbase = *pwXbase;
  415. newCal.wXdelta = *pwXdelta;
  416. newCal.wYbase = *pwYbase;
  417. newCal.wYdelta = *pwYdelta;
  418. newCal.wZbase = *pwZbase;
  419. newCal.wZdelta = *pwZdelta;
  420. w = joyMessage( hDrvJoy[wId], JDD_SETCALIBRATION, (DWORD)(LPSTR)&newCal,
  421. (DWORD)(LPSTR)&oldCal );
  422. *pwXbase = oldCal.wXbase;
  423. *pwXdelta = oldCal.wXdelta;
  424. *pwYbase = oldCal.wYbase;
  425. *pwYdelta = oldCal.wYdelta;
  426. *pwZbase = oldCal.wZbase;
  427. *pwZdelta = oldCal.wZdelta;
  428. return w;
  429. }
  430. /****************************************************************************
  431. @doc INTERNAL
  432. @api void | joyPollCallback | Function called for joystick
  433. timer polling scheme initiated from SetCapture call.
  434. @parm HWND | hWnd | Identifies the window associated with the timer
  435. event.
  436. @parm UINT | wMsg | Specifies the WM_TIMER message.
  437. @parm UINT | wIDEvent | Specifies the timer's ID.
  438. @parm DWORD | dwTime | Specifies the current system time.
  439. ****************************************************************************/
  440. void CALLBACK joyPollCallback(HWND hWnd, UINT wMsg, UINT wIDEvent, DWORD dwTime)
  441. {
  442. #define diff(w1,w2) (UINT)(w1 > w2 ? w1-w2 : w2-w1)
  443. static JOYINFO oldInfo[2] = {{ 0, 0, 0, 0 },{ 0, 0, 0, 0 }};
  444. JOYINFO Info;
  445. UINT w ,fBtnMask;
  446. if (wIDEvent == JoyCapture[0].wIDEvent)
  447. wIDEvent = 0;
  448. else if (wIDEvent == JoyCapture[1].wIDEvent)
  449. wIDEvent = 1;
  450. #ifdef DEBUG
  451. else
  452. {
  453. DOUT("MMSYSTEM: Invalid timer handle in joy.c\r\n");
  454. KillTimer (NULL, wIDEvent);
  455. }
  456. #endif
  457. if (!JoyCapture[wIDEvent].hWnd || !IsWindow(JoyCapture[wIDEvent].hWnd))
  458. joyReleaseCapture(wIDEvent);
  459. if (!joyMessage( hDrvJoy[wIDEvent], JDD_GETPOS,
  460. (DWORD)(LPJOYINFO)&Info, 0L ))
  461. {
  462. for (w=0,fBtnMask=1; w < 4; w++,fBtnMask <<=1)
  463. {
  464. if ((Info.wButtons ^ oldInfo[wIDEvent].wButtons) & fBtnMask)
  465. {
  466. PostMessage(
  467. JoyCapture[wIDEvent].hWnd,
  468. wIDEvent + ((Info.wButtons & fBtnMask) ?
  469. MM_JOY1BUTTONDOWN : MM_JOY1BUTTONUP ),
  470. (WPARAM)(Info.wButtons | fBtnMask << 8),
  471. MAKELPARAM(Info.wXpos,Info.wYpos));
  472. }
  473. }
  474. if (!JoyCapture[wIDEvent].bChanged ||
  475. diff(Info.wXpos,oldInfo[wIDEvent].wXpos)>JoyCapture[wIDEvent].wThreshold ||
  476. diff(Info.wYpos,oldInfo[wIDEvent].wYpos)>JoyCapture[wIDEvent].wThreshold)
  477. {
  478. PostMessage(
  479. JoyCapture[wIDEvent].hWnd,
  480. MM_JOY1MOVE+wIDEvent,
  481. (WPARAM)(Info.wButtons),
  482. MAKELPARAM(Info.wXpos,Info.wYpos));
  483. }
  484. else if (!JoyCapture[wIDEvent].bChanged ||
  485. diff(Info.wZpos,oldInfo[wIDEvent].wZpos)>JoyCapture[wIDEvent].wThreshold)
  486. {
  487. PostMessage(
  488. JoyCapture[wIDEvent].hWnd,
  489. MM_JOY1ZMOVE+wIDEvent,
  490. (WPARAM)Info.wButtons,
  491. MAKELPARAM(Info.wZpos,0));
  492. }
  493. oldInfo[wIDEvent] = Info;
  494. }
  495. #undef diff
  496. }