Win32Mouse.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  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. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: Win32Mouse.cpp ///////////////////////////////////////////////////////////////////////////
  24. // Created: Colin Day, July 2001
  25. // Desc: Interface for the mouse using only the Win32 messages
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. #define WIN32_LEAN_AND_MEAN
  28. #include <windows.h>
  29. #include "Common/Debug.h"
  30. #include "Common/GlobalData.h"
  31. #include "Common/LocalFileSystem.h"
  32. #include "GameClient/GameClient.h"
  33. #include "Win32Device/GameClient/Win32Mouse.h"
  34. #include "WinMain.h"
  35. #ifdef _INTERNAL
  36. // for occasional debugging...
  37. //#pragma optimize("", off)
  38. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  39. #endif
  40. // EXTERN /////////////////////////////////////////////////////////////////////////////////////////
  41. extern Win32Mouse *TheWin32Mouse;
  42. HCURSOR cursorResources[Mouse::NUM_MOUSE_CURSORS][MAX_2D_CURSOR_DIRECTIONS];
  43. ///////////////////////////////////////////////////////////////////////////////////////////////////
  44. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
  45. ///////////////////////////////////////////////////////////////////////////////////////////////////
  46. //-------------------------------------------------------------------------------------------------
  47. /** Get a mouse event from the buffer if available, we need to translate
  48. * from the windows message meanings to our own internal mouse
  49. * structure */
  50. //-------------------------------------------------------------------------------------------------
  51. UnsignedByte Win32Mouse::getMouseEvent( MouseIO *result, Bool flush )
  52. {
  53. // if there is nothing here there is no event data to do
  54. if( m_eventBuffer[ m_nextGetIndex ].msg == 0 )
  55. return MOUSE_NONE;
  56. // translate the win32 mouse message to our own system
  57. translateEvent( m_nextGetIndex, result );
  58. // remove this event from the buffer by setting msg to zero
  59. m_eventBuffer[ m_nextGetIndex ].msg = 0;
  60. //
  61. // our next get index will now be advanced to the next index, wrapping at
  62. // the mad
  63. //
  64. m_nextGetIndex++;
  65. if( m_nextGetIndex >= Mouse::NUM_MOUSE_EVENTS )
  66. m_nextGetIndex = 0;
  67. // got event OK and all done with this one
  68. return MOUSE_OK;
  69. } // end getMouseEvent
  70. //-------------------------------------------------------------------------------------------------
  71. /** Translate a win32 mouse event to our own event info */
  72. //-------------------------------------------------------------------------------------------------
  73. void Win32Mouse::translateEvent( UnsignedInt eventIndex, MouseIO *result )
  74. {
  75. UINT msg = m_eventBuffer[ eventIndex ].msg;
  76. WPARAM wParam = m_eventBuffer[ eventIndex ].wParam;
  77. LPARAM lParam = m_eventBuffer[ eventIndex ].lParam;
  78. UnsignedInt frame;
  79. //
  80. // get the current input frame from the client, if we don't have
  81. // a client (like in the GUI editor) we just use frame 1 so it
  82. // registers with the system
  83. //
  84. if( TheGameClient )
  85. frame = TheGameClient->getFrame();
  86. else
  87. frame = 1;
  88. // set these to defaults
  89. result->leftState = result->middleState = result->rightState = MBS_Up;
  90. result->leftFrame = result->middleFrame = result->rightFrame = 0;
  91. result->pos.x = result->pos.y = result->wheelPos = 0;
  92. // Time is the same for all events
  93. result->time = m_eventBuffer[ eventIndex ].time;
  94. switch( msg )
  95. {
  96. // ------------------------------------------------------------------------
  97. case WM_LBUTTONDOWN:
  98. {
  99. result->leftState = MBS_Down;
  100. result->leftFrame = frame;
  101. result->pos.x = LOWORD( lParam );
  102. result->pos.y = HIWORD( lParam );
  103. break;
  104. } // end left button down
  105. // ------------------------------------------------------------------------
  106. case WM_LBUTTONUP:
  107. {
  108. result->leftState = MBS_Up;
  109. result->leftFrame = frame;
  110. result->pos.x = LOWORD( lParam );
  111. result->pos.y = HIWORD( lParam );
  112. break;
  113. } // end left button up
  114. // ------------------------------------------------------------------------
  115. case WM_LBUTTONDBLCLK:
  116. {
  117. result->leftState = MBS_DoubleClick;
  118. result->leftFrame = frame;
  119. result->pos.x = LOWORD( lParam );
  120. result->pos.y = HIWORD( lParam );
  121. break;
  122. } // end left button double click
  123. // ------------------------------------------------------------------------
  124. case WM_MBUTTONDOWN:
  125. {
  126. result->middleState = MBS_Down;
  127. result->middleFrame = frame;
  128. result->pos.x = LOWORD( lParam );
  129. result->pos.y = HIWORD( lParam );
  130. break;
  131. } // end middle button down
  132. // ------------------------------------------------------------------------
  133. case WM_MBUTTONUP:
  134. {
  135. result->middleState = MBS_Up;
  136. result->middleFrame = frame;
  137. result->pos.x = LOWORD( lParam );
  138. result->pos.y = HIWORD( lParam );
  139. break;
  140. } // end middle button up
  141. // ------------------------------------------------------------------------
  142. case WM_MBUTTONDBLCLK:
  143. {
  144. result->middleState = MBS_DoubleClick;
  145. result->middleFrame = frame;
  146. result->pos.x = LOWORD( lParam );
  147. result->pos.y = HIWORD( lParam );
  148. break;
  149. } // end middle button double click
  150. // ------------------------------------------------------------------------
  151. case WM_RBUTTONDOWN:
  152. {
  153. result->rightState = MBS_Down;
  154. result->rightFrame = frame;
  155. result->pos.x = LOWORD( lParam );
  156. result->pos.y = HIWORD( lParam );
  157. break;
  158. } // end right button down
  159. // ------------------------------------------------------------------------
  160. case WM_RBUTTONUP:
  161. {
  162. result->rightState = MBS_Up;
  163. result->rightFrame = frame;
  164. result->pos.x = LOWORD( lParam );
  165. result->pos.y = HIWORD( lParam );
  166. break;
  167. } // end right button up
  168. // ------------------------------------------------------------------------
  169. case WM_RBUTTONDBLCLK:
  170. {
  171. result->rightState = MBS_DoubleClick;
  172. result->rightFrame = frame;
  173. result->pos.x = LOWORD( lParam );
  174. result->pos.y = HIWORD( lParam );
  175. break;
  176. } // end right button double click
  177. // ------------------------------------------------------------------------
  178. case WM_MOUSEMOVE:
  179. {
  180. result->pos.x = LOWORD( lParam );
  181. result->pos.y = HIWORD( lParam );
  182. break;
  183. } // end mouse move
  184. // ------------------------------------------------------------------------
  185. case 0x020A: // WM_MOUSEWHEEL
  186. {
  187. POINT p;
  188. // translate the screen mouse position to be relative to the application window
  189. p.x = LOWORD( lParam );
  190. p.y = HIWORD( lParam );
  191. ScreenToClient( ApplicationHWnd, &p );
  192. // note the short cast here to keep signed information in tact
  193. result->wheelPos = (Short)HIWORD( wParam );
  194. result->pos.x = p.x;
  195. result->pos.y = p.y;
  196. break;
  197. } // end mouse wheel
  198. // ------------------------------------------------------------------------
  199. default:
  200. {
  201. DEBUG_CRASH(( "translateEvent: Unknown Win32 mouse event [%d,%d,%d]\n",
  202. msg, wParam, lParam ));
  203. return;
  204. } // end default
  205. } // end switch on message at event index in buffer
  206. } // end translateEvent
  207. ///////////////////////////////////////////////////////////////////////////////////////////////////
  208. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
  209. ///////////////////////////////////////////////////////////////////////////////////////////////////
  210. //-------------------------------------------------------------------------------------------------
  211. //-------------------------------------------------------------------------------------------------
  212. Win32Mouse::Win32Mouse( void )
  213. {
  214. // zero our event list
  215. memset( &m_eventBuffer, 0, sizeof( m_eventBuffer ) );
  216. m_nextFreeIndex = 0;
  217. m_nextGetIndex = 0;
  218. m_currentWin32Cursor = NONE;
  219. for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
  220. for (Int j=0; j<MAX_2D_CURSOR_DIRECTIONS; j++)
  221. cursorResources[i][j]=NULL;
  222. m_directionFrame=0; //points up.
  223. m_lostFocus = FALSE;
  224. } // end Win32Mouse
  225. //-------------------------------------------------------------------------------------------------
  226. //-------------------------------------------------------------------------------------------------
  227. Win32Mouse::~Win32Mouse( void )
  228. {
  229. // remove our global reference that was for the WndProc() only
  230. TheWin32Mouse = NULL;
  231. } // end ~Win32Mouse
  232. //-------------------------------------------------------------------------------------------------
  233. /** Initialize our device */
  234. //-------------------------------------------------------------------------------------------------
  235. void Win32Mouse::init( void )
  236. {
  237. // extending functionality
  238. Mouse::init();
  239. //
  240. // when we receive messages from a Windows message procedure, the mouse
  241. // moves report the current cursor position and not deltas, our mouse
  242. // needs to process those positions as absolute and not relative
  243. //
  244. m_inputMovesAbsolute = TRUE;
  245. } // end int
  246. //-------------------------------------------------------------------------------------------------
  247. /** Reset */
  248. //-------------------------------------------------------------------------------------------------
  249. void Win32Mouse::reset( void )
  250. {
  251. // extend
  252. Mouse::reset();
  253. } // end reset
  254. //-------------------------------------------------------------------------------------------------
  255. /** Update, called once per frame */
  256. //-------------------------------------------------------------------------------------------------
  257. void Win32Mouse::update( void )
  258. {
  259. // extend
  260. Mouse::update();
  261. } // end update
  262. //-------------------------------------------------------------------------------------------------
  263. /** Add a window message event along with its WPARAM and LPARAM parameters
  264. * to our input storage buffer */
  265. //-------------------------------------------------------------------------------------------------
  266. void Win32Mouse::addWin32Event( UINT msg, WPARAM wParam, LPARAM lParam, DWORD time )
  267. {
  268. //
  269. // we can only add this event if our next free index does not already
  270. // have an event in it, if it does ... our buffer is full and this input
  271. // event will be lost
  272. //
  273. if( m_eventBuffer[ m_nextFreeIndex ].msg != 0 )
  274. return;
  275. // add to this index
  276. m_eventBuffer[ m_nextFreeIndex ].msg = msg;
  277. m_eventBuffer[ m_nextFreeIndex ].wParam = wParam;
  278. m_eventBuffer[ m_nextFreeIndex ].lParam = lParam;
  279. m_eventBuffer[ m_nextFreeIndex ].time = time;
  280. // wrap index at max
  281. m_nextFreeIndex++;
  282. if( m_nextFreeIndex >= Mouse::NUM_MOUSE_EVENTS )
  283. m_nextFreeIndex = 0;
  284. } // end addWin32Event
  285. extern HINSTANCE ApplicationHInstance;
  286. void Win32Mouse::setVisibility(Bool visible)
  287. {
  288. //Extend
  289. Mouse::setVisibility(visible);
  290. //Maybe need to set cursor to force hiding of some cursors.
  291. Win32Mouse::setCursor(getMouseCursor());
  292. }
  293. /**Preload all the cursors we may need during the game. This must be done before the D3D device
  294. is created to avoid cursor corruption on buggy ATI Radeon cards. */
  295. void Win32Mouse::initCursorResources(void)
  296. {
  297. for (Int cursor=FIRST_CURSOR; cursor<NUM_MOUSE_CURSORS; cursor++)
  298. {
  299. for (Int direction=0; direction<m_cursorInfo[cursor].numDirections; direction++)
  300. { if (!cursorResources[cursor][direction] && !m_cursorInfo[cursor].textureName.isEmpty())
  301. { //this cursor has never been loaded before.
  302. char resourcePath[256];
  303. //Check if this is a directional cursor
  304. if (m_cursorInfo[cursor].numDirections > 1)
  305. sprintf(resourcePath,"data\\cursors\\%s%d.ANI",m_cursorInfo[cursor].textureName.str(),direction);
  306. else
  307. sprintf(resourcePath,"data\\cursors\\%s.ANI",m_cursorInfo[cursor].textureName.str());
  308. // check for a MOD cursor.
  309. Bool loaded = FALSE;
  310. if (TheGlobalData->m_modDir.isNotEmpty())
  311. {
  312. AsciiString fname;
  313. if (m_cursorInfo[cursor].numDirections > 1)
  314. fname.format("%sdata\\cursors\\%s%d.ANI", TheGlobalData->m_modDir.str(), m_cursorInfo[cursor].textureName.str(), direction);
  315. else
  316. fname.format("%sdata\\cursors\\%s.ANI", TheGlobalData->m_modDir.str(), m_cursorInfo[cursor].textureName.str());
  317. if (TheLocalFileSystem->doesFileExist(fname.str()))
  318. {
  319. cursorResources[cursor][direction]=LoadCursorFromFile(fname.str());
  320. loaded = TRUE;
  321. }
  322. }
  323. if (!loaded)
  324. cursorResources[cursor][direction]=LoadCursorFromFile(resourcePath);
  325. DEBUG_ASSERTCRASH(cursorResources[cursor][direction], ("MissingCursor %s\n",resourcePath));
  326. }
  327. }
  328. // SetCursor(cursorResources[cursor][m_directionFrame]);
  329. }
  330. }
  331. //-------------------------------------------------------------------------------------------------
  332. /** Super basic simplistic cursor */
  333. //-------------------------------------------------------------------------------------------------
  334. void Win32Mouse::setCursor( MouseCursor cursor )
  335. {
  336. // extend
  337. Mouse::setCursor( cursor );
  338. if (m_lostFocus)
  339. return; //stop messing with mouse cursor if we don't have focus.
  340. if (cursor == NONE || !m_visible)
  341. SetCursor( NULL );
  342. else
  343. {
  344. SetCursor(cursorResources[cursor][m_directionFrame]);
  345. } // end switch
  346. // save current cursor
  347. m_currentWin32Cursor=m_currentCursor = cursor;
  348. } // end setCursor
  349. //-------------------------------------------------------------------------------------------------
  350. /** Capture the mouse to our application */
  351. //-------------------------------------------------------------------------------------------------
  352. void Win32Mouse::capture( void )
  353. {
  354. // SetCapture( ApplicationHWnd );
  355. } // end capture
  356. //-------------------------------------------------------------------------------------------------
  357. /** Release the mouse capture for our app window */
  358. //-------------------------------------------------------------------------------------------------
  359. void Win32Mouse::releaseCapture( void )
  360. {
  361. // ReleaseCapture();
  362. } // end releaseCapture