Win32DIMouse.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. // FILE: Win32DIMouse.cpp /////////////////////////////////////////////////////////////////////////
  19. // Created: Colin Day, June 2001
  20. // Desc: Win32 direct input implementation for the mouse
  21. ///////////////////////////////////////////////////////////////////////////////////////////////////
  22. #include <stdlib.h>
  23. #include <windows.h>
  24. #include <assert.h>
  25. #include "Common/Debug.h"
  26. #include "GameClient/Display.h"
  27. #include "Win32Device/GameClient/Win32DIMouse.h"
  28. #include "WinMain.h"
  29. // DEFINES ////////////////////////////////////////////////////////////////////////////////////////
  30. enum { MOUSE_BUFFER_SIZE = 256, };
  31. ///////////////////////////////////////////////////////////////////////////////////////////////////
  32. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
  33. ///////////////////////////////////////////////////////////////////////////////////////////////////
  34. //-------------------------------------------------------------------------------------------------
  35. /** Create our direct input object, mouse device, and initialize it to the
  36. * data formats we want */
  37. //-------------------------------------------------------------------------------------------------
  38. void DirectInputMouse::openMouse( void )
  39. {
  40. HRESULT hr;
  41. // create our direct input device for mouse access
  42. hr = DirectInput8Create( ApplicationHInstance,
  43. DIRECTINPUT_VERSION,
  44. IID_IDirectInput8,
  45. (void **)&m_pDirectInput,
  46. NULL );
  47. if( FAILED( hr ) )
  48. {
  49. DEBUG_LOG(( "ERROR - openMouse: Unabled to create direct input interface\n" ));
  50. assert( 0 );
  51. closeMouse();
  52. return;
  53. } // end if
  54. // create a device for the system mouse
  55. hr = m_pDirectInput->CreateDevice( GUID_SysMouse,
  56. &m_pMouseDevice,
  57. NULL );
  58. if( FAILED( hr ) )
  59. {
  60. DEBUG_LOG(( "ERROR - openMouse: Unable to create mouse device\n" ));
  61. assert( 0 );
  62. closeMouse();
  63. return;
  64. } // end if
  65. // set the data format for the mouse
  66. hr = m_pMouseDevice->SetDataFormat( &c_dfDIMouse );
  67. if( FAILED( hr ) )
  68. {
  69. DEBUG_LOG(( "ERROR - openMouse: Unabled to set mouse data format\n" ));
  70. assert( 0 );
  71. closeMouse();
  72. return;
  73. } // end if
  74. // set the mouse cooperative level
  75. hr = m_pMouseDevice->SetCooperativeLevel( ApplicationHWnd,
  76. DISCL_NONEXCLUSIVE |
  77. DISCL_FOREGROUND );
  78. if( FAILED( hr ) )
  79. {
  80. DEBUG_LOG(( "ERROR - openMouse: Unabled to set coop level\n" ));
  81. assert( 0 );
  82. closeMouse();
  83. return;
  84. } // end if
  85. // set the mouse buffer size
  86. DIPROPDWORD prop;
  87. prop.diph.dwSize = sizeof( DIPROPDWORD );
  88. prop.diph.dwHeaderSize = sizeof( DIPROPHEADER );
  89. prop.diph.dwObj = 0;
  90. prop.diph.dwHow = DIPH_DEVICE;
  91. prop.dwData = MOUSE_BUFFER_SIZE;
  92. hr = m_pMouseDevice->SetProperty( DIPROP_BUFFERSIZE, &prop.diph );
  93. if( FAILED( hr ) )
  94. {
  95. DEBUG_LOG(( "ERROR - openMouse: Unabled to set buffer property\n" ));
  96. assert( 0 );
  97. closeMouse();
  98. return;
  99. } // end if
  100. // acquire the mouse
  101. hr = m_pMouseDevice->Acquire();
  102. if( FAILED( hr ) )
  103. {
  104. DEBUG_LOG(( "ERROR - openMouse: Unabled to acquire mouse\n" ));
  105. assert( 0 );
  106. closeMouse();
  107. return;
  108. } // end if
  109. // get some information about the mouse
  110. DIDEVCAPS diDevCaps;
  111. diDevCaps.dwSize = sizeof( DIDEVCAPS );
  112. hr = m_pMouseDevice->GetCapabilities( &diDevCaps );
  113. if( FAILED( hr ) )
  114. {
  115. DEBUG_LOG(( "WARNING - openMouse: Cann't get capabilities of mouse for button setup\n" ));
  116. } // end if
  117. else
  118. {
  119. // keep some data about the mouse we care about
  120. m_numButtons = (UnsignedByte)diDevCaps.dwButtons;
  121. m_numAxes = (UnsignedByte)diDevCaps.dwAxes;
  122. m_forceFeedback = BitTest( diDevCaps.dwFlags, DIDC_FORCEFEEDBACK );
  123. DEBUG_LOG(( "OK - Mouse info: Buttons = '%d', Force Feedback = '%s', Axes = '%d'\n",
  124. m_numButtons, m_forceFeedback ? "Yes" : "No", m_numAxes ));
  125. } // end else
  126. DEBUG_LOG(( "OK - Mouse initialized successfully\n" ));
  127. } // end openMouse
  128. //-------------------------------------------------------------------------------------------------
  129. /** Release any resources for our direct input mouse */
  130. //-------------------------------------------------------------------------------------------------
  131. void DirectInputMouse::closeMouse( void )
  132. {
  133. // release the mouse device
  134. if( m_pMouseDevice )
  135. {
  136. m_pMouseDevice->Unacquire();
  137. m_pMouseDevice->Release();
  138. m_pMouseDevice = NULL;
  139. DEBUG_LOG(( "OK - Mouse device closed\n" ));
  140. } // end if
  141. // release our direct input interface for the mouse
  142. if( m_pDirectInput )
  143. {
  144. m_pDirectInput->Release();
  145. m_pDirectInput = NULL;
  146. DEBUG_LOG(( "OK - Mouse direct input interface closed\n" ));
  147. } // end if
  148. DEBUG_LOG(( "OK - Mouse shutdown complete\n" ));
  149. } // end closeMouse
  150. //-------------------------------------------------------------------------------------------------
  151. /** Get a single mouse event from the device */
  152. //-------------------------------------------------------------------------------------------------
  153. UnsignedByte DirectInputMouse::getMouseEvent( MouseIO *result, Bool flush )
  154. {
  155. HRESULT hr;
  156. DIDEVICEOBJECTDATA mdat;
  157. UnsignedByte mouseResult = MOUSE_NONE;
  158. DWORD num;
  159. /* set these to defaults */
  160. result->leftState = result->middleState = result->rightState = FALSE;
  161. result->leftFrame = result->middleFrame = result->rightFrame = 0;
  162. result->pos.x = result->pos.y = result->wheelPos = 0;
  163. if( m_pMouseDevice )
  164. {
  165. // get 1 event, if available
  166. num = 1;
  167. m_pMouseDevice->Poll();
  168. hr = m_pMouseDevice->GetDeviceData( sizeof( DIDEVICEOBJECTDATA ),
  169. &mdat,
  170. &num,
  171. 0 );
  172. switch( hr )
  173. {
  174. // ----------------------------------------------------------------------
  175. case DI_OK:
  176. {
  177. // nothing returned
  178. if( num != 0 )
  179. {
  180. mapDirectInputMouse( result, &mdat );
  181. mouseResult = MOUSE_OK;
  182. }
  183. break;
  184. }
  185. // ----------------------------------------------------------------------
  186. case DIERR_NOTACQUIRED:
  187. case DIERR_INPUTLOST:
  188. {
  189. // if we lost focus, attempt to re-acquire
  190. hr = m_pMouseDevice->Acquire();
  191. switch( hr )
  192. {
  193. // ------------------------------------------------------------------
  194. // If successful... tell system to loop back
  195. case DI_OK:
  196. case S_FALSE:
  197. mouseResult = MOUSE_LOST;
  198. // ------------------------------------------------------------------
  199. //If an error occurs return MOUSE_NONE
  200. case DIERR_INVALIDPARAM:
  201. case DIERR_NOTINITIALIZED:
  202. case DIERR_OTHERAPPHASPRIO:
  203. default:
  204. break;
  205. } // end switch
  206. break;
  207. }
  208. // ----------------------------------------------------------------------
  209. default:
  210. // DBGPRINTF(("GetMouseEvent: GetDeviceData Error: %X.\r\n", hr ));
  211. break;
  212. } // end switch
  213. } // end if
  214. return mouseResult;
  215. } // end getMouseEvent
  216. //-------------------------------------------------------------------------------------------------
  217. /** Map the direct input codes to our own mouse format */
  218. //-------------------------------------------------------------------------------------------------
  219. void DirectInputMouse::mapDirectInputMouse( MouseIO *mouse,
  220. DIDEVICEOBJECTDATA *mdat )
  221. {
  222. switch( mdat->dwOfs )
  223. {
  224. case DIMOFS_BUTTON0:
  225. mouse->leftState = (( mdat->dwData & 0x0080 ) ? TRUE : FALSE);
  226. mouse->leftFrame = mdat->dwSequence;
  227. break;
  228. case DIMOFS_BUTTON1:
  229. mouse->rightState = (( mdat->dwData & 0x0080 ) ? TRUE : FALSE);
  230. mouse->rightFrame = mdat->dwSequence;
  231. break;
  232. case DIMOFS_BUTTON2:
  233. mouse->middleState = (( mdat->dwData & 0x0080 ) ? TRUE : FALSE);
  234. mouse->middleFrame = mdat->dwSequence;
  235. break;
  236. case DIMOFS_BUTTON3:
  237. break;
  238. case DIMOFS_X:
  239. mouse->pos.x = mdat->dwData;
  240. break;
  241. case DIMOFS_Y:
  242. mouse->pos.y = mdat->dwData;
  243. break;
  244. case DIMOFS_Z:
  245. mouse->wheelPos = mdat->dwData;
  246. break;
  247. }
  248. } // end mapDirectInputMouse
  249. ///////////////////////////////////////////////////////////////////////////////////////////////////
  250. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
  251. ///////////////////////////////////////////////////////////////////////////////////////////////////
  252. //-------------------------------------------------------------------------------------------------
  253. //-------------------------------------------------------------------------------------------------
  254. DirectInputMouse::DirectInputMouse( void )
  255. {
  256. m_pDirectInput = NULL;
  257. m_pMouseDevice = NULL;
  258. } // end DirectInputMouse
  259. //-------------------------------------------------------------------------------------------------
  260. //-------------------------------------------------------------------------------------------------
  261. DirectInputMouse::~DirectInputMouse( void )
  262. {
  263. // relase all mouse resources
  264. closeMouse();
  265. // ShowCursor( TRUE );
  266. } // end ~DirectInputMouse
  267. //-------------------------------------------------------------------------------------------------
  268. /** Initialize the direct input mouse device */
  269. //-------------------------------------------------------------------------------------------------
  270. void DirectInputMouse::init( void )
  271. {
  272. POINT p;
  273. // extending functionality from our base class
  274. Mouse::init();
  275. // open the mouse and create the direct input interfaces we need
  276. openMouse();
  277. // move the window mouse to the location we have initialized in our system
  278. p.x = m_currMouse.pos.x;
  279. p.y = m_currMouse.pos.y;
  280. ClientToScreen( ApplicationHWnd, &p );
  281. SetCursorPos( p.x, p.y );
  282. // ShowCursor( FALSE );
  283. } // end init
  284. //-------------------------------------------------------------------------------------------------
  285. /** Reset direct input mouse */
  286. //-------------------------------------------------------------------------------------------------
  287. void DirectInputMouse::reset( void )
  288. {
  289. // extend
  290. Mouse::reset();
  291. } // end reset
  292. //-------------------------------------------------------------------------------------------------
  293. /** Update the mouse position and button data, this is called once per
  294. * frame in the engine. NOTE that this routine is extendion functionality
  295. * that we may need that is direct input specific, not replacing */
  296. //-------------------------------------------------------------------------------------------------
  297. void DirectInputMouse::update( void )
  298. {
  299. // extendion functionality from our base class
  300. Mouse::update();
  301. //
  302. // since we are currently using the windows cursor because it updates at
  303. // an independent rate of our application we will always just use the windows
  304. // mouse cursor position
  305. //
  306. /** @todo we need to really visit this system and possibly come up with
  307. our own multi-threaded cursor etc */
  308. POINT p;
  309. GetCursorPos( &p );
  310. ScreenToClient( ApplicationHWnd, &p );
  311. moveMouse( p.x, p.y, MOUSE_MOVE_ABSOLUTE );
  312. } // end update
  313. //-------------------------------------------------------------------------------------------------
  314. /** Set the limits which the mouse is allowed to move around in. We
  315. * will limit it to the client area, and if we are windowed we will
  316. * allow for the mouse to move within the title bar at the top of
  317. * the window */
  318. //-------------------------------------------------------------------------------------------------
  319. void DirectInputMouse::setMouseLimits( void )
  320. {
  321. //
  322. // extending functionality, although we may overwrite the limits set
  323. // from the base class
  324. //
  325. Mouse::setMouseLimits();
  326. //
  327. // when runing windowed we want to keep the mouse within the game
  328. // window cause it's annoying to mouse out of the window and click
  329. // on a background window.
  330. //
  331. if( TheDisplay && TheDisplay->getWindowed() == TRUE )
  332. {
  333. RECT windowRect;
  334. // get the window rect
  335. GetWindowRect( ApplicationHWnd, &windowRect );
  336. // keep the cursor clipped to these coords when running windowed
  337. ClipCursor( &windowRect );
  338. } // end if
  339. } // end setMouseLimits
  340. //-------------------------------------------------------------------------------------------------
  341. /** set the cursor position for windows OS */
  342. //-------------------------------------------------------------------------------------------------
  343. void DirectInputMouse::setPosition( Int x, Int y )
  344. {
  345. POINT p;
  346. // extending functionality
  347. Mouse::setPosition( x, y );
  348. // set the windows cursor
  349. p.x = x;
  350. p.y = y;
  351. ClientToScreen( ApplicationHWnd, &p );
  352. // set the window mouse
  353. SetCursorPos( p.x, p.y );
  354. } // end setPosition
  355. //-------------------------------------------------------------------------------------------------
  356. /** Super basic simplistic cursor */
  357. //-------------------------------------------------------------------------------------------------
  358. void DirectInputMouse::setCursor( MouseCursor cursor )
  359. {
  360. // extend
  361. Mouse::setCursor( cursor );
  362. // if we're already on this cursor ignore
  363. if( m_currentCursor == cursor )
  364. return;
  365. switch( cursor )
  366. {
  367. case NONE:
  368. SetCursor( NULL );
  369. break;
  370. case NORMAL:
  371. case ARROW:
  372. SetCursor( LoadCursor( NULL, IDC_ARROW ) );
  373. break;
  374. case SCROLL:
  375. SetCursor( LoadCursor( NULL, IDC_SIZEALL ) );
  376. break;
  377. case CROSS:
  378. SetCursor( LoadCursor( NULL, IDC_CROSS ) );
  379. break;
  380. } // end switch
  381. // save current cursor
  382. m_currentCursor = cursor;
  383. } // end setCursor
  384. //-------------------------------------------------------------------------------------------------
  385. /** Capture the mouse to our application */
  386. //-------------------------------------------------------------------------------------------------
  387. void DirectInputMouse::capture( void )
  388. {
  389. SetCapture( ApplicationHWnd );
  390. } // end capture
  391. //-------------------------------------------------------------------------------------------------
  392. /** Release the mouse capture for our app window */
  393. //-------------------------------------------------------------------------------------------------
  394. void DirectInputMouse::releaseCapture( void )
  395. {
  396. ReleaseCapture();
  397. } // end releaseCapture