Counter Strike : Global Offensive Source Code
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.

368 lines
10 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: PC Joystick implementation for inputsystem.dll
  4. //
  5. //===========================================================================//
  6. #include "inputsystem.h"
  7. #include "tier1/convar.h"
  8. // NOTE: This has to be the last file included!
  9. #include "tier0/memdbgon.h"
  10. //-----------------------------------------------------------------------------
  11. // Joystick helpers
  12. //-----------------------------------------------------------------------------
  13. #define JOY_POVFWDRIGHT ( ( JOY_POVFORWARD + JOY_POVRIGHT ) >> 1 ) // 4500
  14. #define JOY_POVRIGHTBACK ( ( JOY_POVRIGHT + JOY_POVBACKWARD ) >> 1 ) // 13500
  15. #define JOY_POVFBACKLEFT ( ( JOY_POVBACKWARD + JOY_POVLEFT ) >> 1 ) // 22500
  16. #define JOY_POVLEFTFWD ( ( JOY_POVLEFT + JOY_POVFORWARD ) >> 1 ) // 31500
  17. ConVar joy_wwhack1( "joy_wingmanwarrior_centerhack", "0", FCVAR_ARCHIVE, "Wingman warrior centering hack." );
  18. ConVar joy_axisbutton_threshold( "joy_axisbutton_threshold", "0.3", FCVAR_ARCHIVE, "Analog axis range before a button press is registered." );
  19. //-----------------------------------------------------------------------------
  20. // Initialize all joysticks
  21. //-----------------------------------------------------------------------------
  22. void CInputSystem::InitializeJoysticks( void )
  23. {
  24. // assume no joystick
  25. m_nJoystickCount = 0;
  26. // abort startup if user requests no joystick
  27. if ( CommandLine()->FindParm("-nojoy" ) )
  28. return;
  29. // verify joystick driver is present
  30. int nMaxJoysticks = joyGetNumDevs();
  31. if ( nMaxJoysticks > MAX_JOYSTICKS )
  32. {
  33. nMaxJoysticks = MAX_JOYSTICKS;
  34. }
  35. else if ( nMaxJoysticks <= 0 )
  36. {
  37. DevMsg( 1, "joystick not found -- driver not present\n");
  38. return;
  39. }
  40. // cycle through the joysticks looking for valid ones
  41. MMRESULT mmr;
  42. for ( int i=0; i < nMaxJoysticks; i++ )
  43. {
  44. JOYINFOEX ji;
  45. Q_memset( &ji, 0, sizeof( ji ) );
  46. ji.dwSize = sizeof(ji);
  47. ji.dwFlags = JOY_RETURNCENTERED;
  48. mmr = joyGetPosEx( i, &ji );
  49. if ( mmr != JOYERR_NOERROR )
  50. continue;
  51. // get the capabilities of the selected joystick
  52. // abort startup if command fails
  53. JOYCAPS jc;
  54. Q_memset( &jc, 0, sizeof( jc ) );
  55. mmr = joyGetDevCaps( i, &jc, sizeof( jc ) );
  56. if ( mmr != JOYERR_NOERROR )
  57. continue;
  58. JoystickInfo_t &info = m_pJoystickInfo[m_nJoystickCount];
  59. info.m_nDeviceId = i;
  60. info.m_JoyInfoEx = ji;
  61. info.m_nButtonCount = (int)jc.wNumButtons;
  62. info.m_bHasPOVControl = ( jc.wCaps & JOYCAPS_HASPOV ) ? true : false;
  63. info.m_bDiagonalPOVControlEnabled = false;
  64. info.m_nFlags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNX | JOY_RETURNY;
  65. info.m_nAxisFlags = 0;
  66. if ( jc.wNumAxes >= 2 )
  67. {
  68. info.m_nAxisFlags |= 0x3;
  69. }
  70. if ( info.m_bHasPOVControl )
  71. {
  72. info.m_nFlags |= JOY_RETURNPOV;
  73. }
  74. if ( jc.wCaps & JOYCAPS_HASZ )
  75. {
  76. info.m_nFlags |= JOY_RETURNZ;
  77. info.m_nAxisFlags |= 0x4;
  78. }
  79. if ( jc.wCaps & JOYCAPS_HASR )
  80. {
  81. info.m_nFlags |= JOY_RETURNR;
  82. info.m_nAxisFlags |= 0x8;
  83. }
  84. if ( jc.wCaps & JOYCAPS_HASU )
  85. {
  86. info.m_nFlags |= JOY_RETURNU;
  87. info.m_nAxisFlags |= 0x10;
  88. }
  89. if ( jc.wCaps & JOYCAPS_HASV )
  90. {
  91. info.m_nFlags |= JOY_RETURNV;
  92. info.m_nAxisFlags |= 0x20;
  93. }
  94. info.m_nLastPolledButtons = 0;
  95. info.m_nLastPolledAxisButtons = 0;
  96. info.m_nLastPolledPOVState = 0;
  97. memset( info.m_pLastPolledAxes, 0, sizeof(info.m_pLastPolledAxes) );
  98. ++m_nJoystickCount;
  99. EnableJoystickInput( i, true );
  100. }
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Process the event
  104. //-----------------------------------------------------------------------------
  105. void CInputSystem::JoystickButtonEvent( ButtonCode_t button, int sample )
  106. {
  107. // package the key
  108. if ( sample )
  109. {
  110. PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, button, button );
  111. }
  112. else
  113. {
  114. PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, button, button );
  115. }
  116. }
  117. //-----------------------------------------------------------------------------
  118. // Update the joystick button state
  119. //-----------------------------------------------------------------------------
  120. void CInputSystem::UpdateJoystickButtonState( int nJoystick )
  121. {
  122. JoystickInfo_t &info = m_pJoystickInfo[nJoystick];
  123. JOYINFOEX& ji = info.m_JoyInfoEx;
  124. // Standard joystick buttons
  125. unsigned int buttons = ji.dwButtons ^ info.m_nLastPolledButtons;
  126. if ( buttons )
  127. {
  128. for ( int j = 0 ; j < info.m_nButtonCount ; ++j )
  129. {
  130. int mask = buttons & ( 1 << j );
  131. if ( !mask )
  132. continue;
  133. ButtonCode_t code = (ButtonCode_t)JOYSTICK_BUTTON( nJoystick, j );
  134. if ( mask & ji.dwButtons )
  135. {
  136. // down event
  137. JoystickButtonEvent( code, MAX_BUTTONSAMPLE );
  138. }
  139. else
  140. {
  141. // up event
  142. JoystickButtonEvent( code, 0 );
  143. }
  144. }
  145. info.m_nLastPolledButtons = (unsigned int)ji.dwButtons;
  146. }
  147. // Analog axis buttons
  148. const float minValue = joy_axisbutton_threshold.GetFloat() * MAX_BUTTONSAMPLE;
  149. for ( int j = 0 ; j < MAX_JOYSTICK_AXES; ++j )
  150. {
  151. if ( ( info.m_nAxisFlags & (1 << j) ) == 0 )
  152. continue;
  153. // Positive side of the axis
  154. int mask = ( 1 << (j << 1) );
  155. ButtonCode_t code = JOYSTICK_AXIS_BUTTON( nJoystick, (j << 1) );
  156. float value = GetAnalogValue( JOYSTICK_AXIS( nJoystick, j ) );
  157. if ( value > minValue && !(info.m_nLastPolledAxisButtons & mask) )
  158. {
  159. info.m_nLastPolledAxisButtons |= mask;
  160. JoystickButtonEvent( code, MAX_BUTTONSAMPLE );
  161. }
  162. if ( value <= minValue && (info.m_nLastPolledAxisButtons & mask) )
  163. {
  164. info.m_nLastPolledAxisButtons &= ~mask;
  165. JoystickButtonEvent( code, 0 );
  166. }
  167. // Negative side of the axis
  168. mask <<= 1;
  169. code = (ButtonCode_t)( code + 1 );
  170. if ( value < -minValue && !(info.m_nLastPolledAxisButtons & mask) )
  171. {
  172. info.m_nLastPolledAxisButtons |= mask;
  173. JoystickButtonEvent( code, MAX_BUTTONSAMPLE );
  174. }
  175. if ( value >= -minValue && (info.m_nLastPolledAxisButtons & mask) )
  176. {
  177. info.m_nLastPolledAxisButtons &= ~mask;
  178. JoystickButtonEvent( code, 0 );
  179. }
  180. }
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Purpose: Get raw joystick sample along axis
  184. //-----------------------------------------------------------------------------
  185. unsigned int CInputSystem::AxisValue( JoystickAxis_t axis, JOYINFOEX& ji )
  186. {
  187. switch (axis)
  188. {
  189. case JOY_AXIS_X:
  190. return (unsigned int)ji.dwXpos;
  191. case JOY_AXIS_Y:
  192. return (unsigned int)ji.dwYpos;
  193. case JOY_AXIS_Z:
  194. return (unsigned int)ji.dwZpos;
  195. case JOY_AXIS_R:
  196. return (unsigned int)ji.dwRpos;
  197. case JOY_AXIS_U:
  198. return (unsigned int)ji.dwUpos;
  199. case JOY_AXIS_V:
  200. return (unsigned int)ji.dwVpos;
  201. }
  202. // FIX: need to do some kind of error
  203. return (unsigned int)ji.dwXpos;
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Update the joystick POV control
  207. //-----------------------------------------------------------------------------
  208. void CInputSystem::UpdateJoystickPOVControl( int nJoystick )
  209. {
  210. JoystickInfo_t &info = m_pJoystickInfo[nJoystick];
  211. JOYINFOEX& ji = info.m_JoyInfoEx;
  212. if ( !info.m_bHasPOVControl )
  213. return;
  214. // convert POV information into 4 bits of state information
  215. // this avoids any potential problems related to moving from one
  216. // direction to another without going through the center position
  217. unsigned int povstate = 0;
  218. if ( ji.dwPOV != JOY_POVCENTERED )
  219. {
  220. if (ji.dwPOV == JOY_POVFORWARD) // 0
  221. {
  222. povstate |= 0x01;
  223. }
  224. if (ji.dwPOV == JOY_POVRIGHT) // 9000
  225. {
  226. povstate |= 0x02;
  227. }
  228. if (ji.dwPOV == JOY_POVBACKWARD) // 18000
  229. {
  230. povstate |= 0x04;
  231. }
  232. if (ji.dwPOV == JOY_POVLEFT) // 27000
  233. {
  234. povstate |= 0x08;
  235. }
  236. // Deal with diagonals if user wants them
  237. if ( info.m_bDiagonalPOVControlEnabled )
  238. {
  239. if (ji.dwPOV == JOY_POVFWDRIGHT) // 4500
  240. {
  241. povstate |= ( 0x01 | 0x02 );
  242. }
  243. if (ji.dwPOV == JOY_POVRIGHTBACK) // 13500
  244. {
  245. povstate |= ( 0x02 | 0x04 );
  246. }
  247. if (ji.dwPOV == JOY_POVFBACKLEFT) // 22500
  248. {
  249. povstate |= ( 0x04 | 0x08 );
  250. }
  251. if (ji.dwPOV == JOY_POVLEFTFWD) // 31500
  252. {
  253. povstate |= ( 0x08 | 0x01 );
  254. }
  255. }
  256. }
  257. // determine which bits have changed and key an auxillary event for each change
  258. unsigned int buttons = povstate ^ info.m_nLastPolledPOVState;
  259. if ( buttons )
  260. {
  261. for ( int i = 0; i < JOYSTICK_POV_BUTTON_COUNT; ++i )
  262. {
  263. unsigned int mask = buttons & ( 1 << i );
  264. if ( !mask )
  265. continue;
  266. ButtonCode_t code = (ButtonCode_t)JOYSTICK_POV_BUTTON( nJoystick, i );
  267. if ( mask & povstate )
  268. {
  269. // Keydown on POV buttons
  270. JoystickButtonEvent( code, MAX_BUTTONSAMPLE );
  271. }
  272. else
  273. {
  274. // KeyUp on POV buttons
  275. JoystickButtonEvent( code, 0 );
  276. }
  277. }
  278. // Latch old values
  279. info.m_nLastPolledPOVState = povstate;
  280. }
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose: Sample the joystick
  284. //-----------------------------------------------------------------------------
  285. void CInputSystem::PollJoystick( void )
  286. {
  287. if ( !m_JoysticksEnabled.IsAnyFlagSet() )
  288. return;
  289. InputState_t &state = m_InputState[ m_bIsPolling ];
  290. for ( int i = 0; i < m_nJoystickCount; ++i )
  291. {
  292. if ( !m_JoysticksEnabled.IsFlagSet( 1 << i ) )
  293. continue;
  294. JoystickInfo_t &info = m_pJoystickInfo[i];
  295. JOYINFOEX& ji = info.m_JoyInfoEx;
  296. Q_memset( &ji, 0, sizeof( ji ) );
  297. ji.dwSize = sizeof( ji );
  298. ji.dwFlags = (DWORD)info.m_nFlags;
  299. if ( joyGetPosEx( info.m_nDeviceId, &ji ) != JOYERR_NOERROR )
  300. continue;
  301. // This hack fixes a bug in the Logitech WingMan Warrior DirectInput Driver
  302. // rather than having 32768 be the zero point, they have the zero point at 32668
  303. // go figure -- anyway, now we get the full resolution out of the device
  304. if ( joy_wwhack1.GetBool() )
  305. {
  306. ji.dwUpos += 100;
  307. }
  308. // Poll joystick axes
  309. for ( int j = 0; j < MAX_JOYSTICK_AXES; ++j )
  310. {
  311. if ( ( info.m_nAxisFlags & ( 1 << j ) ) == 0 )
  312. continue;
  313. AnalogCode_t code = JOYSTICK_AXIS( i, j );
  314. int nValue = AxisValue( (JoystickAxis_t)j, ji ) - MAX_BUTTONSAMPLE;
  315. state.m_pAnalogDelta[ code ] = nValue - state.m_pAnalogValue[ code ];
  316. state.m_pAnalogValue[ code ] = nValue;
  317. if ( state.m_pAnalogDelta[ code ] != 0 )
  318. {
  319. PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, code, state.m_pAnalogValue[ code ], state.m_pAnalogDelta[ code ] );
  320. }
  321. }
  322. UpdateJoystickButtonState( i );
  323. UpdateJoystickPOVControl( i );
  324. }
  325. }