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