MOUSE.CPP.BAK 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. /*
  2. ** Command & Conquer Red Alert(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. * Project Name : Westwood 32 bit Library *
  21. * *
  22. * File Name : MOUSE.CPP *
  23. * *
  24. * Programmer : Philip W. Gorrow *
  25. * *
  26. * Start Date : 12/12/95 *
  27. * *
  28. * Last Update : December 12, 1995 [PWG] *
  29. * *
  30. *---------------------------------------------------------------------------------------------*
  31. * Functions: *
  32. * WWMouseClass::WWMouseClass -- Constructor for the Mouse Class *
  33. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  34. #include "mouse.h"
  35. #include <mmsystem.h>
  36. static WWMouseClass *_Mouse=NULL;
  37. void CALLBACK Process_Mouse( UINT event_id, UINT res1 , DWORD user, DWORD res2, DWORD res3 );
  38. /***********************************************************************************************
  39. * MOUSECLASS::MOUSECLASS -- Constructor for the Mouse Class *
  40. * *
  41. * INPUT: GraphicBufferClass * screen - pointer to screen mouse is created for * *
  42. * *
  43. * OUTPUT: none *
  44. * *
  45. * HISTORY: *
  46. * 12/12/1995 PWG : Created. *
  47. *=============================================================================================*/
  48. WWMouseClass::WWMouseClass(GraphicBufferClass *scr, int mouse_max_width, int mouse_max_height)
  49. {
  50. MouseCursor = new char[mouse_max_width * mouse_max_height];
  51. MouseXHot = 0;
  52. MouseYHot = 0;
  53. CursorWidth = 0;
  54. CursorHeight = 0;
  55. MouseBuffer = new char[mouse_max_width * mouse_max_height];
  56. MouseBuffX = -1;
  57. MouseBuffY = -1;
  58. MaxWidth = mouse_max_width;
  59. MaxHeight = mouse_max_height;
  60. MouseCXLeft = 0;
  61. MouseCYUpper = 0;
  62. MouseCXRight = 0;
  63. MouseCYLower = 0;
  64. MCFlags = 0;
  65. MCCount = 0;
  66. Screen = scr;
  67. PrevCursor = NULL;
  68. MouseUpdate = 0;
  69. State = 1;
  70. timeBeginPeriod ( 1000/ 60);
  71. MutexObject = CreateMutex(NULL, FALSE, "WWLIB32MOUSEMUTEX");
  72. //
  73. // Install the timer callback event handler
  74. //
  75. EraseBuffer = new char[mouse_max_width * mouse_max_height];
  76. EraseBuffX = -1;
  77. EraseBuffY = -1;
  78. EraseFlags = FALSE;
  79. _Mouse = this;
  80. TimerHandle = timeSetEvent( 1000/60 , 1 , ::Process_Mouse, 0 , TIME_PERIODIC);
  81. }
  82. WWMouseClass::~WWMouseClass()
  83. {
  84. WaitForSingleObject(MutexObject, INFINITE);
  85. MouseUpdate++;
  86. if (MouseCursor) delete[] MouseCursor;
  87. if (MouseBuffer) delete[] MouseBuffer;
  88. if (TimerHandle) {
  89. timeKillEvent(TimerHandle);
  90. }
  91. timeEndPeriod (1);
  92. ReleaseMutex(MutexObject);
  93. }
  94. void WWMouseClass::Process_Mouse(void)
  95. {
  96. POINT pt; // define a structure to hold current cursor pos
  97. //
  98. // If the mouse is currently hidden or it has not been installed, then we
  99. // have no need to redraw the mouse.
  100. //
  101. if (!_Mouse || State > 0 || MouseUpdate || EraseFlags)
  102. return;
  103. //
  104. // Wait until we have exclusive access to our data
  105. //
  106. WaitForSingleObject(MutexObject, INFINITE);
  107. //
  108. // Get the mouse's current real cursor position
  109. //
  110. GetCursorPos(&pt); // get the current cursor position
  111. //
  112. // If the mouse has moved then we are responsible to redraw the mouse
  113. //
  114. if (pt.x != MouseBuffX || pt.y != MouseBuffY) {
  115. if (!EraseFlags) {
  116. //
  117. // If we can't lock the surface we need to draw to, we cannot update
  118. // the mouse.
  119. //
  120. if (Screen->Lock()) {
  121. //
  122. // Erase the old mouse by dumping the mouses shadow buff
  123. // to the screen (if its position had ever been recorded).
  124. //
  125. Low_Hide_Mouse();
  126. //
  127. // Verify that the mouse has not gone into a conditional hiden area
  128. // If it has, mark it as being in one.
  129. //
  130. if (MCFlags & CONDHIDE && pt.x >= MouseCXLeft && pt.x <= MouseCXRight && pt.y >= MouseCYUpper && pt.y <= MouseCYLower) {
  131. MCFlags |= CONDHIDDEN;
  132. }
  133. //
  134. // Show the mouse if we are allowed to.
  135. //
  136. if (!(MCFlags & CONDHIDDEN)) {
  137. Low_Show_Mouse(pt.x, pt.y);
  138. }
  139. //
  140. // Finally unlock the destination surface as we have sucessfully
  141. // updated the mouse.
  142. //
  143. Screen->Unlock();
  144. }
  145. } else {
  146. if (MCFlags & CONDHIDE && pt.x >= MouseCXLeft && pt.x <= MouseCXRight && pt.y >= MouseCYUpper && pt.y <= MouseCYLower) {
  147. MCFlags |= CONDHIDDEN;
  148. State++;
  149. }
  150. }
  151. }
  152. ReleaseMutex(MutexObject);
  153. }
  154. void *WWMouseClass::Set_Cursor(int xhotspot, int yhotspot, void *cursor)
  155. {
  156. //
  157. // If the pointer to the cursor we got is invalid, or its the same as the
  158. // currently set cursor then just return.
  159. if (!cursor || cursor == PrevCursor)
  160. return(cursor);
  161. //
  162. // Wait until we have exclusive access to our data
  163. //
  164. WaitForSingleObject(MutexObject, INFINITE);
  165. MouseUpdate++;
  166. //
  167. // Since we are updating the mouse we need to hide the cursor so we
  168. // do not get some sort of weird transformation.
  169. //
  170. Hide_Mouse();
  171. //
  172. // Now convert the shape to a mouse cursor with the given hotspots and
  173. // set it as our current mouse.
  174. //
  175. void *retval = ASM_Set_Mouse_Cursor(this, xhotspot, yhotspot, cursor);
  176. //
  177. // Show the mouse which will force it to appear with the new shape we
  178. // have assigned.
  179. //
  180. Show_Mouse();
  181. //
  182. // We are done updating the mouse cursor so on to bigger and better things.
  183. //
  184. MouseUpdate--;
  185. //
  186. // Inform Windows that we are done using the exclusive data we requested.
  187. //
  188. ReleaseMutex(MutexObject);
  189. //
  190. // Return the previous mouse cursor which as conveniantly passed back by
  191. // Asm_Set_Mouse_Cursor.
  192. //
  193. return(retval);
  194. }
  195. void WWMouseClass::Low_Hide_Mouse()
  196. {
  197. if (!State) {
  198. while (!Screen->Lock()) {}
  199. if (MouseBuffX != -1 || MouseBuffY != -1) {
  200. Mouse_Shadow_Buffer(this, Screen, MouseBuffer, MouseBuffX, MouseBuffY, 0);
  201. }
  202. MouseBuffX = -1;
  203. MouseBuffY = -1;
  204. Screen->Unlock();
  205. }
  206. State++;
  207. }
  208. void WWMouseClass::Hide_Mouse()
  209. {
  210. //
  211. // Wait until we have exclusive access to our data
  212. //
  213. WaitForSingleObject(MutexObject, INFINITE);
  214. MouseUpdate++;
  215. Low_Hide_Mouse();
  216. MouseUpdate--;
  217. ReleaseMutex(MutexObject);
  218. }
  219. void WWMouseClass::Low_Show_Mouse(int x, int y)
  220. {
  221. //
  222. // If the mouse is already visible then just ignore the problem.
  223. //
  224. if (State == 0) return;
  225. //
  226. // Make the mouse a little bit more visible
  227. //
  228. State--;
  229. //
  230. // If the mouse is completely visible then draw it at its current
  231. // position.
  232. //
  233. if (!State) {
  234. //
  235. // Try to lock the screen til we sucessfully get a lock.
  236. //
  237. while (!Screen->Lock()) {}
  238. //
  239. // Save off the area behind the mouse.
  240. //
  241. Mouse_Shadow_Buffer(this, Screen, MouseBuffer, x, y, 1);
  242. //
  243. // Draw the mouse in its new location
  244. //
  245. ::Draw_Mouse(this, Screen, x, y);
  246. //
  247. // Save off the positions that we saved the buffer from
  248. //
  249. MouseBuffX = x;
  250. MouseBuffY = y;
  251. //
  252. // Unlock the screen and lets get moving.
  253. //
  254. Screen->Unlock();
  255. }
  256. }
  257. void WWMouseClass::Show_Mouse()
  258. {
  259. POINT pt;
  260. GetCursorPos(&pt);
  261. //
  262. // Wait until we have exclusive access to our data
  263. //
  264. WaitForSingleObject(MutexObject, INFINITE);
  265. MouseUpdate++;
  266. Low_Show_Mouse(pt.x, pt.y);
  267. MouseUpdate--;
  268. ReleaseMutex(MutexObject);
  269. }
  270. void WWMouseClass::Conditional_Hide_Mouse(int x1, int y1, int x2, int y2)
  271. {
  272. POINT pt;
  273. //
  274. // Wait until we have exclusive access to our data
  275. //
  276. WaitForSingleObject(MutexObject, INFINITE);
  277. MouseUpdate++;
  278. //
  279. // First of all, adjust all the coordinates so that they handle
  280. // the fact that the hotspot is not necessarily the upper left
  281. // corner of the mouse.
  282. //
  283. x1 -= (CursorWidth - MouseXHot);
  284. x1 = MAX(0, x1);
  285. y1 -= (CursorHeight - MouseYHot);
  286. y1 = MAX(0, y1);
  287. x2 += MouseXHot;
  288. x2 = MIN(x2, Screen->Get_Width());
  289. y2 += MouseYHot;
  290. y2 = MIN(y2, Screen->Get_Height());
  291. // The mouse could be in one of four conditions.
  292. // 1) The mouse is visible and no conditional hide has been specified.
  293. // (perform normal region checking with possible hide)
  294. // 2) The mouse is hidden and no conditional hide as been specified.
  295. // (record region and do nothing)
  296. // 3) The mouse is visible and a conditional region has been specified
  297. // (expand region and perform check with possible hide).
  298. // 4) The mouse is already hidden by a previous conditional.
  299. // (expand region and do nothing)
  300. //
  301. // First: Set or expand the region according to the specified parameters
  302. if (!MCCount) {
  303. MouseCXLeft = x1;
  304. MouseCYUpper = y1;
  305. MouseCXRight = x2;
  306. MouseCYLower = y2;
  307. } else {
  308. MouseCXLeft = MIN(x1, MouseCXLeft);
  309. MouseCYUpper = MIN(y1, MouseCYUpper);
  310. MouseCXRight = MAX(x2, MouseCXRight);
  311. MouseCYLower = MAX(y2, MouseCYLower);
  312. }
  313. //
  314. // If the mouse isn't already hidden, then check its location against
  315. // the hiding region and hide if necessary.
  316. //
  317. if (!(MCFlags & CONDHIDDEN)) {
  318. GetCursorPos(&pt);
  319. if (pt.x >= MouseCXLeft && pt.x <= MouseCXRight && pt.y >= MouseCYUpper && pt.y <= MouseCYLower) {
  320. Hide_Mouse();
  321. MCFlags |= CONDHIDDEN;
  322. }
  323. }
  324. //
  325. // Record the fact that a conditional hide was called and then exit
  326. //
  327. //
  328. MCFlags |= CONDHIDE;
  329. MCCount++;
  330. MouseUpdate--;
  331. ReleaseMutex(MutexObject);
  332. }
  333. void WWMouseClass::Conditional_Show_Mouse(void)
  334. {
  335. //
  336. // Wait until we have exclusive access to our data
  337. //
  338. WaitForSingleObject(MutexObject, INFINITE);
  339. MouseUpdate++;
  340. //
  341. // if there are any nested hides then dec the count
  342. //
  343. if (MCCount) {
  344. MCCount--;
  345. //
  346. // If the mouse is now not hidden and it had actually been
  347. // hidden before then display it.
  348. //
  349. if (!MCCount) {
  350. if (MCFlags & CONDHIDDEN) {
  351. Show_Mouse();
  352. }
  353. MCFlags = 0;
  354. }
  355. }
  356. MouseUpdate--;
  357. ReleaseMutex(MutexObject);
  358. }
  359. void WWMouseClass::Draw_Mouse(GraphicBufferClass *scr)
  360. {
  361. POINT pt;
  362. if (State != 0) return;
  363. //
  364. // Wait until we have exclusive access to our data
  365. //
  366. WaitForSingleObject(MutexObject, INFINITE);
  367. MouseUpdate++;
  368. //
  369. // Get the position that the mouse is currently located at
  370. //
  371. GetCursorPos(&pt);
  372. if (MCFlags & CONDHIDE) {
  373. if (pt.x >= MouseCXLeft && pt.x <= MouseCXRight && pt.y >= MouseCYUpper && pt.y <= MouseCYLower) {
  374. Hide_Mouse();
  375. MCFlags |= CONDHIDDEN;
  376. }
  377. } else {
  378. //
  379. // If the mouse is already visible then just ignore the problem.
  380. //
  381. EraseFlags = TRUE;
  382. //
  383. // Try to lock the screen til we sucessfully get a lock.
  384. //
  385. while (!scr->Lock()) {}
  386. //
  387. // Save off the area behind the mouse into two different buffers, one
  388. // which will be used to restore the mouse and the other which will
  389. // be used to restore the hidden surface when we get a chance.
  390. //
  391. Mouse_Shadow_Buffer(this, scr, EraseBuffer, pt.x, pt.y, 1);
  392. memcpy(MouseBuffer, EraseBuffer, MaxWidth * MaxHeight);
  393. //
  394. // Draw the mouse in its new location
  395. //
  396. ::Draw_Mouse(this, scr, pt.x, pt.y);
  397. //
  398. // Save off the positions that we saved the buffer from
  399. //
  400. EraseBuffX = pt.x;
  401. MouseBuffX = pt.x;
  402. EraseBuffY = pt.y;
  403. MouseBuffY = pt.y;
  404. //
  405. // Unlock the screen and lets get moving.
  406. //
  407. scr->Unlock();
  408. }
  409. MouseUpdate--;
  410. ReleaseMutex(MutexObject);
  411. }
  412. void WWMouseClass::Erase_Mouse(GraphicBufferClass *scr, int forced)
  413. {
  414. if (!EraseFlags) return;
  415. // if (State != 0) return;
  416. //
  417. // If we are forcing the redraw of a mouse we already managed to
  418. // restore then just get outta here.
  419. //
  420. if (forced && EraseBuffX == -1 && EraseBuffY == -1) return;
  421. //
  422. // If we don't own the Mutex Object, then we need to because we may
  423. // update the mouse.
  424. //
  425. WaitForSingleObject(MutexObject, INFINITE);
  426. MouseUpdate++;
  427. //
  428. // If this is not a forced call, only update the mouse is we can legally
  429. // lock the buffer.
  430. //
  431. if (!forced) {
  432. #if(0)
  433. if (scr->Lock()) {
  434. //
  435. // If the surface has not already been restore then restore it and erase the
  436. // restoration coordinates so we don't accidentally do it twice.
  437. //
  438. if (EraseBuffX != -1 || EraseBuffY != -1) {
  439. Mouse_Shadow_Buffer(this, scr, EraseBuffer, EraseBuffX, EraseBuffY, 0);
  440. EraseBuffX = -1;
  441. EraseBuffY = -1;
  442. }
  443. //
  444. // We are done writing to the buffer so unlock it.
  445. //
  446. scr->Unlock();
  447. }
  448. #endif
  449. } else {
  450. //
  451. // If this is a forced call then wait til we are allowed to update the buffer
  452. //
  453. while (!scr->Lock()) {}
  454. //
  455. // If the surface has not already been restore then restore it and erase the
  456. // restoration coordinates so we don't accidentally do it twice.
  457. //
  458. if (EraseBuffX != -1 || EraseBuffY != -1) {
  459. Mouse_Shadow_Buffer(this, scr, EraseBuffer, EraseBuffX, EraseBuffY, 0);
  460. EraseBuffX = -1;
  461. EraseBuffY = -1;
  462. }
  463. //
  464. // We are done writing to the buffer so unlock it.
  465. //
  466. scr->Unlock();
  467. }
  468. MouseUpdate--;
  469. ReleaseMutex(MutexObject);
  470. EraseFlags = FALSE;
  471. }
  472. int WWMouseClass::Get_Mouse_State(void)
  473. {
  474. return(State);
  475. }
  476. /***********************************************************************************************
  477. * WWKeyboardClass::Get_Mouse_X -- Returns the mouses current x position in pixels *
  478. * *
  479. * INPUT: none *
  480. * *
  481. * OUTPUT: int - returns the mouses current x position in pixels *
  482. * *
  483. * HISTORY: *
  484. * 10/17/1995 PWG : Created. *
  485. *=============================================================================================*/
  486. int WWMouseClass::Get_Mouse_X(void)
  487. {
  488. POINT pt;
  489. GetCursorPos(&pt);
  490. return(pt.x);
  491. }
  492. /***********************************************************************************************
  493. * WWKeyboardClass::Get_Mouse_Y -- returns the mouses current y position in pixels *
  494. * *
  495. * INPUT: none *
  496. * *
  497. * OUTPUT: int - returns the mouses current y position in pixels *
  498. * *
  499. * HISTORY: *
  500. * 10/17/1995 PWG : Created. *
  501. *=============================================================================================*/
  502. int WWMouseClass::Get_Mouse_Y(void)
  503. {
  504. POINT pt;
  505. GetCursorPos(&pt);
  506. return(pt.y);
  507. }
  508. /***********************************************************************************************
  509. * WWKeyboardClass::Get_Mouse_XY -- Returns the mouses x,y position via reference vars *
  510. * *
  511. * INPUT: int &x - variable to return the mouses x position in pixels *
  512. * int &y - variable to return the mouses y position in pixels *
  513. * *
  514. * OUTPUT: none - output is via reference variables *
  515. * *
  516. * HISTORY: *
  517. * 10/17/1995 PWG : Created. *
  518. *=============================================================================================*/
  519. void WWMouseClass::Get_Mouse_XY(int &x, int &y)
  520. {
  521. POINT pt;
  522. GetCursorPos(&pt);
  523. x = pt.x;
  524. y = pt.y;
  525. }
  526. #pragma off(unreferenced)
  527. void CALLBACK Process_Mouse( UINT event_id, UINT res1 , DWORD user, DWORD res2, DWORD res3 )
  528. {
  529. if (_Mouse) {
  530. _Mouse->Process_Mouse();
  531. }
  532. }
  533. #pragma on(unreferenced)
  534. void Hide_Mouse(void)
  535. {
  536. if (!_Mouse) return;
  537. _Mouse->Hide_Mouse();
  538. }
  539. void Show_Mouse(void)
  540. {
  541. if (!_Mouse) return;
  542. _Mouse->Show_Mouse();
  543. }
  544. void Conditional_Hide_Mouse(int x1, int y1, int x2, int y2)
  545. {
  546. if (!_Mouse) return;
  547. _Mouse->Conditional_Hide_Mouse(x1, y1, x2, y2);
  548. }
  549. void Conditional_Show_Mouse(void)
  550. {
  551. if (!_Mouse) return;
  552. _Mouse->Conditional_Show_Mouse();
  553. }
  554. int Get_Mouse_State(void)
  555. {
  556. if (!_Mouse) return(0);
  557. return(_Mouse->Get_Mouse_State());
  558. }
  559. void *Set_Mouse_Cursor(int hotx, int hoty, void *cursor)
  560. {
  561. if (!_Mouse) return(0);
  562. return(_Mouse->Set_Cursor(hotx,hoty,cursor));
  563. }
  564. int Get_Mouse_X(void)
  565. {
  566. if (!_Mouse) return(0);
  567. return(_Mouse->Get_Mouse_X());
  568. }
  569. int Get_Mouse_Y(void)
  570. {
  571. if (!_Mouse) return(0);
  572. return(_Mouse->Get_Mouse_Y());
  573. }