MOUSEWW.CPP 20 KB

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