1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2006 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library 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 GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 #define WIN32_LEAN_AND_MEAN 25 #include <windows.h> 26 27 /* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */ 28 #ifndef WM_XBUTTONDOWN 29 #define WM_XBUTTONDOWN 0x020B 30 #endif 31 #ifndef WM_XBUTTONUP 32 #define WM_XBUTTONUP 0x020C 33 #endif 34 #ifndef GET_XBUTTON_WPARAM 35 #define GET_XBUTTON_WPARAM(w) (HIWORD(w)) 36 #endif 37 38 #include "SDL_events.h" 39 #include "SDL_video.h" 40 #include "SDL_syswm.h" 41 #include "../SDL_sysvideo.h" 42 #include "../../events/SDL_sysevents.h" 43 #include "../../events/SDL_events_c.h" 44 #include "SDL_lowvideo.h" 45 #include "SDL_syswm_c.h" 46 #include "SDL_main.h" 47 #include "SDL_loadso.h" 48 49 #ifdef WMMSG_DEBUG 50 #include "wmmsg.h" 51 #endif 52 53 #ifdef _WIN32_WCE 54 #include "../gapi/SDL_gapivideo.h" 55 56 #define IsZoomed(HWND) 1 57 #define NO_GETKEYBOARDSTATE 58 #if _WIN32_WCE < 420 59 #define NO_CHANGEDISPLAYSETTINGS 60 #endif 61 #endif 62 63 /* The window we use for everything... */ 64 #ifdef _WIN32_WCE 65 LPWSTR SDL_Appname = NULL; 66 #else 67 LPSTR SDL_Appname = NULL; 68 #endif 69 Uint32 SDL_Appstyle = 0; 70 HINSTANCE SDL_Instance = NULL; 71 HWND SDL_Window = NULL; 72 RECT SDL_bounds = {0, 0, 0, 0}; 73 int SDL_windowX = 0; 74 int SDL_windowY = 0; 75 int SDL_resizing = 0; 76 int mouse_relative = 0; 77 int posted = 0; 78 #ifndef NO_CHANGEDISPLAYSETTINGS 79 DEVMODE SDL_desktop_mode; 80 DEVMODE SDL_fullscreen_mode; 81 #endif 82 WORD *gamma_saved = NULL; 83 84 85 /* Functions called by the message processing function */ 86 LONG (*HandleMessage)(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)=NULL; 87 void (*WIN_Activate)(_THIS, BOOL active, BOOL iconic); 88 void (*WIN_RealizePalette)(_THIS); 89 void (*WIN_PaletteChanged)(_THIS, HWND window); 90 void (*WIN_WinPAINT)(_THIS, HDC hdc); 91 extern void DIB_SwapGamma(_THIS); 92 93 #ifndef NO_GETKEYBOARDSTATE 94 /* Variables and support functions for SDL_ToUnicode() */ 95 static int codepage; 96 static int Is9xME(); 97 static int GetCodePage(); 98 static int WINAPI ToUnicode9xME(UINT vkey, UINT scancode, BYTE *keystate, LPWSTR wchars, int wsize, UINT flags); 99 100 ToUnicodeFN SDL_ToUnicode = ToUnicode9xME; 101 #endif /* !NO_GETKEYBOARDSTATE */ 102 103 104 #if defined(_WIN32_WCE) 105 106 // dynamically load aygshell dll because we want SDL to work on HPC and be300 107 HINSTANCE aygshell = NULL; 108 BOOL (WINAPI *SHFullScreen)(HWND hwndRequester, DWORD dwState) = 0; 109 110 #define SHFS_SHOWTASKBAR 0x0001 111 #define SHFS_HIDETASKBAR 0x0002 112 #define SHFS_SHOWSIPBUTTON 0x0004 113 #define SHFS_HIDESIPBUTTON 0x0008 114 #define SHFS_SHOWSTARTICON 0x0010 115 #define SHFS_HIDESTARTICON 0x0020 116 117 static void LoadAygshell(void) 118 { 119 if( !aygshell ) 120 aygshell = SDL_LoadObject("aygshell.dll"); 121 if( (aygshell != 0) && (SHFullScreen == 0) ) 122 { 123 SHFullScreen = (int (WINAPI *)(struct HWND__ *,unsigned long)) SDL_LoadFunction(aygshell, "SHFullScreen"); 124 } 125 } 126 127 /* for gapi landscape mode */ 128 static void GapiTransform(SDL_ScreenOrientation rotate, char hires, Sint16 *x, Sint16 *y) { 129 Sint16 rotatedX; 130 Sint16 rotatedY; 131 132 if (hires) { 133 *x = *x * 2; 134 *y = *y * 2; 135 } 136 137 switch(rotate) { 138 case SDL_ORIENTATION_UP: 139 { 140 /* this code needs testing on a real device! 141 So it will be enabled later */ 142 /* 143 #ifdef _WIN32_WCE 144 #if _WIN32_WCE >= 420 145 // test device orientation 146 // FIXME: do not check every mouse message 147 DEVMODE settings; 148 SDL_memset(&settings, 0, sizeof(DEVMODE)); 149 settings.dmSize = sizeof(DEVMODE); 150 settings.dmFields = DM_DISPLAYORIENTATION; 151 ChangeDisplaySettingsEx(NULL, &settings, NULL, CDS_TEST, NULL); 152 if( settings.dmOrientation == DMDO_90 ) 153 { 154 rotatedX = SDL_VideoSurface->h - *x; 155 rotatedY = *y; 156 *x = rotatedX; 157 *y = rotatedY; 158 } 159 #endif 160 #endif */ 161 } 162 break; 163 case SDL_ORIENTATION_RIGHT: 164 if (!SDL_VideoSurface) 165 break; 166 rotatedX = SDL_VideoSurface->w - *y; 167 rotatedY = *x; 168 *x = rotatedX; 169 *y = rotatedY; 170 break; 171 case SDL_ORIENTATION_LEFT: 172 if (!SDL_VideoSurface) 173 break; 174 rotatedX = *y; 175 rotatedY = SDL_VideoSurface->h - *x; 176 *x = rotatedX; 177 *y = rotatedY; 178 break; 179 } 180 } 181 182 #endif 183 184 /* JC 14 Mar 2006 185 This is used all over the place, in the windib driver and in the dx5 driver 186 So we may as well stick it here instead of having multiple copies scattered 187 about 188 */ 189 void WIN_FlushMessageQueue() 190 { 191 MSG msg; 192 while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) { 193 if ( msg.message == WM_QUIT ) break; 194 TranslateMessage( &msg ); 195 DispatchMessage( &msg ); 196 } 197 } 198 199 static void SDL_RestoreGameMode(void) 200 { 201 #ifdef _WIN32_WCE 202 SDL_VideoDevice *this = current_video; 203 if(SDL_strcmp(this->name, "gapi") == 0) 204 { 205 if( this->hidden->suspended ) 206 { 207 this->hidden->suspended = 0; 208 } 209 } 210 #else 211 ShowWindow(SDL_Window, SW_RESTORE); 212 #endif 213 214 #ifndef NO_CHANGEDISPLAYSETTINGS 215 #ifndef _WIN32_WCE 216 ChangeDisplaySettings(&SDL_fullscreen_mode, CDS_FULLSCREEN); 217 #endif 218 #endif /* NO_CHANGEDISPLAYSETTINGS */ 219 } 220 static void SDL_RestoreDesktopMode(void) 221 { 222 223 #ifdef _WIN32_WCE 224 SDL_VideoDevice *this = current_video; 225 if(SDL_strcmp(this->name, "gapi") == 0) 226 { 227 if( !this->hidden->suspended ) 228 { 229 this->hidden->suspended = 1; 230 } 231 } 232 #else 233 /* WinCE does not have a taskbar, so minimizing is not convenient */ 234 ShowWindow(SDL_Window, SW_MINIMIZE); 235 #endif 236 237 #ifndef NO_CHANGEDISPLAYSETTINGS 238 #ifndef _WIN32_WCE 239 ChangeDisplaySettings(NULL, 0); 240 #endif 241 #endif /* NO_CHANGEDISPLAYSETTINGS */ 242 } 243 244 #ifdef WM_MOUSELEAVE 245 /* 246 Special code to handle mouse leave events - this sucks... 247 http://support.microsoft.com/support/kb/articles/q183/1/07.asp 248 249 TrackMouseEvent() is only available on Win98 and WinNT. 250 _TrackMouseEvent() is available on Win95, but isn't yet in the mingw32 251 development environment, and only works on systems that have had IE 3.0 252 or newer installed on them (which is not the case with the base Win95). 253 Therefore, we implement our own version of _TrackMouseEvent() which 254 uses our own implementation if TrackMouseEvent() is not available. 255 */ 256 static BOOL (WINAPI *_TrackMouseEvent)(TRACKMOUSEEVENT *ptme) = NULL; 257 258 static VOID CALLBACK 259 TrackMouseTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime) 260 { 261 RECT rect; 262 POINT pt; 263 264 GetClientRect(hWnd, &rect); 265 MapWindowPoints(hWnd, NULL, (LPPOINT)&rect, 2); 266 GetCursorPos(&pt); 267 if ( !PtInRect(&rect, pt) || (WindowFromPoint(pt) != hWnd) ) { 268 if ( !KillTimer(hWnd, idEvent) ) { 269 /* Error killing the timer! */ 270 } 271 PostMessage(hWnd, WM_MOUSELEAVE, 0, 0); 272 } 273 } 274 static BOOL WINAPI WIN_TrackMouseEvent(TRACKMOUSEEVENT *ptme) 275 { 276 if ( ptme->dwFlags == TME_LEAVE ) { 277 return SetTimer(ptme->hwndTrack, ptme->dwFlags, 100, 278 (TIMERPROC)TrackMouseTimerProc) != 0; 279 } 280 return FALSE; 281 } 282 #endif /* WM_MOUSELEAVE */ 283 284 /* Function to retrieve the current keyboard modifiers */ 285 static void WIN_GetKeyboardState(void) 286 { 287 #ifndef NO_GETKEYBOARDSTATE 288 SDLMod state; 289 BYTE keyboard[256]; 290 Uint8 *kstate = SDL_GetKeyState(NULL); 291 292 state = KMOD_NONE; 293 if ( GetKeyboardState(keyboard) ) { 294 if ( keyboard[VK_LSHIFT] & 0x80) { 295 state |= KMOD_LSHIFT; 296 kstate[SDLK_LSHIFT] = SDL_PRESSED; 297 } 298 if ( keyboard[VK_RSHIFT] & 0x80) { 299 state |= KMOD_RSHIFT; 300 kstate[SDLK_RSHIFT] = SDL_PRESSED; 301 } 302 if ( keyboard[VK_LCONTROL] & 0x80) { 303 state |= KMOD_LCTRL; 304 kstate[SDLK_LCTRL] = SDL_PRESSED; 305 } 306 if ( keyboard[VK_RCONTROL] & 0x80) { 307 state |= KMOD_RCTRL; 308 kstate[SDLK_RCTRL] = SDL_PRESSED; 309 } 310 if ( keyboard[VK_LMENU] & 0x80) { 311 state |= KMOD_LALT; 312 kstate[SDLK_LALT] = SDL_PRESSED; 313 } 314 if ( keyboard[VK_RMENU] & 0x80) { 315 state |= KMOD_RALT; 316 kstate[SDLK_RALT] = SDL_PRESSED; 317 } 318 if ( keyboard[VK_NUMLOCK] & 0x01) { 319 state |= KMOD_NUM; 320 kstate[SDLK_NUMLOCK] = SDL_PRESSED; 321 } 322 if ( keyboard[VK_CAPITAL] & 0x01) { 323 state |= KMOD_CAPS; 324 kstate[SDLK_CAPSLOCK] = SDL_PRESSED; 325 } 326 } 327 SDL_SetModState(state); 328 #endif /* !NO_GETKEYBOARDSTATE */ 329 } 330 331 /* The main Win32 event handler 332 DJM: This is no longer static as (DX5/DIB)_CreateWindow needs it 333 */ 334 LRESULT CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 335 { 336 SDL_VideoDevice *this = current_video; 337 static int mouse_pressed = 0; 338 static int in_window = 0; 339 #ifdef WMMSG_DEBUG 340 fprintf(stderr, "Received windows message: "); 341 if ( msg > MAX_WMMSG ) { 342 fprintf(stderr, "%d", msg); 343 } else { 344 fprintf(stderr, "%s", wmtab[msg]); 345 } 346 fprintf(stderr, " -- 0x%X, 0x%X\n", wParam, lParam); 347 #endif 348 switch (msg) { 349 350 case WM_ACTIVATE: { 351 SDL_VideoDevice *this = current_video; 352 BOOL active, minimized; 353 Uint8 appstate; 354 355 minimized = HIWORD(wParam); 356 active = (LOWORD(wParam) != WA_INACTIVE) && !minimized; 357 if ( active ) { 358 /* Gain the following states */ 359 appstate = SDL_APPACTIVE|SDL_APPINPUTFOCUS; 360 if ( this->input_grab != SDL_GRAB_OFF ) { 361 WIN_GrabInput(this, SDL_GRAB_ON); 362 } 363 if ( !(SDL_GetAppState()&SDL_APPINPUTFOCUS) ) { 364 if ( ! DDRAW_FULLSCREEN() ) { 365 DIB_SwapGamma(this); 366 } 367 if ( WINDIB_FULLSCREEN() ) { 368 SDL_RestoreGameMode(); 369 } 370 } 371 #if defined(_WIN32_WCE) 372 if ( WINDIB_FULLSCREEN() ) { 373 LoadAygshell(); 374 if( SHFullScreen ) 375 SHFullScreen(SDL_Window, SHFS_HIDESTARTICON|SHFS_HIDETASKBAR|SHFS_HIDESIPBUTTON); 376 else 377 ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_HIDE); 378 } 379 #endif 380 posted = SDL_PrivateAppActive(1, appstate); 381 WIN_GetKeyboardState(); 382 } else { 383 /* Lose the following states */ 384 appstate = SDL_APPINPUTFOCUS; 385 if ( minimized ) { 386 appstate |= SDL_APPACTIVE; 387 } 388 if ( this->input_grab != SDL_GRAB_OFF ) { 389 WIN_GrabInput(this, SDL_GRAB_OFF); 390 } 391 if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) { 392 if ( ! DDRAW_FULLSCREEN() ) { 393 DIB_SwapGamma(this); 394 } 395 if ( WINDIB_FULLSCREEN() ) { 396 SDL_RestoreDesktopMode(); 397 #if defined(_WIN32_WCE) 398 LoadAygshell(); 399 if( SHFullScreen ) 400 SHFullScreen(SDL_Window, SHFS_SHOWSTARTICON|SHFS_SHOWTASKBAR|SHFS_SHOWSIPBUTTON); 401 else 402 ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_SHOW); 403 #endif 404 } 405 } 406 posted = SDL_PrivateAppActive(0, appstate); 407 } 408 WIN_Activate(this, active, minimized); 409 return(0); 410 } 411 break; 412 413 case WM_MOUSEMOVE: { 414 415 /* Mouse is handled by DirectInput when fullscreen */ 416 if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) { 417 Sint16 x, y; 418 419 /* mouse has entered the window */ 420 if ( ! in_window ) { 421 #ifdef WM_MOUSELEAVE 422 TRACKMOUSEEVENT tme; 423 424 tme.cbSize = sizeof(tme); 425 tme.dwFlags = TME_LEAVE; 426 tme.hwndTrack = SDL_Window; 427 _TrackMouseEvent(&tme); 428 #endif /* WM_MOUSELEAVE */ 429 in_window = TRUE; 430 431 posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); 432 } 433 434 /* mouse has moved within the window */ 435 x = LOWORD(lParam); 436 y = HIWORD(lParam); 437 if ( mouse_relative ) { 438 POINT center; 439 center.x = (SDL_VideoSurface->w/2); 440 center.y = (SDL_VideoSurface->h/2); 441 x -= (Sint16)center.x; 442 y -= (Sint16)center.y; 443 if ( x || y ) { 444 ClientToScreen(SDL_Window, ¢er); 445 SetCursorPos(center.x, center.y); 446 posted = SDL_PrivateMouseMotion(0, 1, x, y); 447 } 448 } else { 449 #ifdef _WIN32_WCE 450 if (SDL_VideoSurface) 451 GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &x, &y); 452 #endif 453 posted = SDL_PrivateMouseMotion(0, 0, x, y); 454 } 455 } 456 } 457 return(0); 458 459 #ifdef WM_MOUSELEAVE 460 case WM_MOUSELEAVE: { 461 462 /* Mouse is handled by DirectInput when fullscreen */ 463 if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) { 464 /* mouse has left the window */ 465 /* or */ 466 /* Elvis has left the building! */ 467 posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); 468 } 469 in_window = FALSE; 470 } 471 return(0); 472 #endif /* WM_MOUSELEAVE */ 473 474 case WM_LBUTTONDOWN: 475 case WM_LBUTTONUP: 476 case WM_MBUTTONDOWN: 477 case WM_MBUTTONUP: 478 case WM_RBUTTONDOWN: 479 case WM_RBUTTONUP: 480 case WM_XBUTTONDOWN: 481 case WM_XBUTTONUP: { 482 /* Mouse is handled by DirectInput when fullscreen */ 483 if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) { 484 WORD xbuttonval = 0; 485 Sint16 x, y; 486 Uint8 button, state; 487 488 /* DJM: 489 We want the SDL window to take focus so that 490 it acts like a normal windows "component" 491 (e.g. gains keyboard focus on a mouse click). 492 */ 493 SetFocus(SDL_Window); 494 495 /* Figure out which button to use */ 496 switch (msg) { 497 case WM_LBUTTONDOWN: 498 button = SDL_BUTTON_LEFT; 499 state = SDL_PRESSED; 500 break; 501 case WM_LBUTTONUP: 502 button = SDL_BUTTON_LEFT; 503 state = SDL_RELEASED; 504 break; 505 case WM_MBUTTONDOWN: 506 button = SDL_BUTTON_MIDDLE; 507 state = SDL_PRESSED; 508 break; 509 case WM_MBUTTONUP: 510 button = SDL_BUTTON_MIDDLE; 511 state = SDL_RELEASED; 512 break; 513 case WM_RBUTTONDOWN: 514 button = SDL_BUTTON_RIGHT; 515 state = SDL_PRESSED; 516 break; 517 case WM_RBUTTONUP: 518 button = SDL_BUTTON_RIGHT; 519 state = SDL_RELEASED; 520 break; 521 case WM_XBUTTONDOWN: 522 xbuttonval = GET_XBUTTON_WPARAM(wParam); 523 button = SDL_BUTTON_WHEELDOWN + xbuttonval; 524 state = SDL_PRESSED; 525 break; 526 case WM_XBUTTONUP: 527 xbuttonval = GET_XBUTTON_WPARAM(wParam); 528 button = SDL_BUTTON_WHEELDOWN + xbuttonval; 529 state = SDL_RELEASED; 530 break; 531 default: 532 /* Eh? Unknown button? */ 533 return(0); 534 } 535 if ( state == SDL_PRESSED ) { 536 /* Grab mouse so we get up events */ 537 if ( ++mouse_pressed > 0 ) { 538 SetCapture(hwnd); 539 } 540 } else { 541 /* Release mouse after all up events */ 542 if ( --mouse_pressed <= 0 ) { 543 ReleaseCapture(); 544 mouse_pressed = 0; 545 } 546 } 547 if ( mouse_relative ) { 548 /* RJR: March 28, 2000 549 report internal mouse position if in relative mode */ 550 x = 0; y = 0; 551 } else { 552 x = (Sint16)LOWORD(lParam); 553 y = (Sint16)HIWORD(lParam); 554 #ifdef _WIN32_WCE 555 if (SDL_VideoSurface) 556 GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &x, &y); 557 #endif 558 } 559 posted = SDL_PrivateMouseButton( 560 state, button, x, y); 561 562 /* 563 * MSDN says: 564 * "Unlike the WM_LBUTTONUP, WM_MBUTTONUP, and WM_RBUTTONUP 565 * messages, an application should return TRUE from [an 566 * XBUTTON message] if it processes it. Doing so will allow 567 * software that simulates this message on Microsoft Windows 568 * systems earlier than Windows 2000 to determine whether 569 * the window procedure processed the message or called 570 * DefWindowProc to process it. 571 */ 572 if (xbuttonval > 0) 573 return(TRUE); 574 } 575 } 576 return(0); 577 578 579 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) 580 case WM_MOUSEWHEEL: 581 if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) { 582 int move = (short)HIWORD(wParam); 583 if ( move ) { 584 Uint8 button; 585 if ( move > 0 ) 586 button = SDL_BUTTON_WHEELUP; 587 else 588 button = SDL_BUTTON_WHEELDOWN; 589 posted = SDL_PrivateMouseButton( 590 SDL_PRESSED, button, 0, 0); 591 posted |= SDL_PrivateMouseButton( 592 SDL_RELEASED, button, 0, 0); 593 } 594 } 595 return(0); 596 #endif 597 598 #ifdef WM_GETMINMAXINFO 599 /* This message is sent as a way for us to "check" the values 600 * of a position change. If we don't like it, we can adjust 601 * the values before they are changed. 602 */ 603 case WM_GETMINMAXINFO: { 604 MINMAXINFO *info; 605 RECT size; 606 int x, y; 607 int style; 608 int width; 609 int height; 610 611 /* We don't want to clobber an internal resize */ 612 if ( SDL_resizing ) 613 return(0); 614 615 /* We allow resizing with the SDL_RESIZABLE flag */ 616 if ( SDL_PublicSurface && 617 (SDL_PublicSurface->flags & SDL_RESIZABLE) ) { 618 return(0); 619 } 620 621 /* Get the current position of our window */ 622 GetWindowRect(SDL_Window, &size); 623 x = size.left; 624 y = size.top; 625 626 /* Calculate current width and height of our window */ 627 size.top = 0; 628 size.left = 0; 629 if ( SDL_PublicSurface != NULL ) { 630 size.bottom = SDL_PublicSurface->h; 631 size.right = SDL_PublicSurface->w; 632 } else { 633 size.bottom = 0; 634 size.right = 0; 635 } 636 637 /* DJM - according to the docs for GetMenu(), the 638 return value is undefined if hwnd is a child window. 639 Aparently it's too difficult for MS to check 640 inside their function, so I have to do it here. 641 */ 642 style = GetWindowLong(hwnd, GWL_STYLE); 643 AdjustWindowRect( 644 &size, 645 style, 646 style & WS_CHILDWINDOW ? FALSE 647 : GetMenu(hwnd) != NULL); 648 649 width = size.right - size.left; 650 height = size.bottom - size.top; 651 652 /* Fix our size to the current size */ 653 info = (MINMAXINFO *)lParam; 654 info->ptMaxSize.x = width; 655 info->ptMaxSize.y = height; 656 info->ptMaxPosition.x = x; 657 info->ptMaxPosition.y = y; 658 info->ptMinTrackSize.x = width; 659 info->ptMinTrackSize.y = height; 660 info->ptMaxTrackSize.x = width; 661 info->ptMaxTrackSize.y = height; 662 } 663 return(0); 664 #endif /* WM_GETMINMAXINFO */ 665 666 case WM_WINDOWPOSCHANGED: { 667 SDL_VideoDevice *this = current_video; 668 int w, h; 669 670 GetClientRect(SDL_Window, &SDL_bounds); 671 ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds); 672 ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds+1); 673 if ( !SDL_resizing && !IsZoomed(SDL_Window) && 674 SDL_PublicSurface && 675 !(SDL_PublicSurface->flags & SDL_FULLSCREEN) ) { 676 SDL_windowX = SDL_bounds.left; 677 SDL_windowY = SDL_bounds.top; 678 } 679 w = SDL_bounds.right-SDL_bounds.left; 680 h = SDL_bounds.bottom-SDL_bounds.top; 681 if ( this->input_grab != SDL_GRAB_OFF ) { 682 ClipCursor(&SDL_bounds); 683 } 684 if ( SDL_PublicSurface && 685 (SDL_PublicSurface->flags & SDL_RESIZABLE) ) { 686 SDL_PrivateResize(w, h); 687 } 688 } 689 break; 690 691 /* We need to set the cursor */ 692 case WM_SETCURSOR: { 693 Uint16 hittest; 694 695 hittest = LOWORD(lParam); 696 if ( hittest == HTCLIENT ) { 697 SetCursor(SDL_hcursor); 698 return(TRUE); 699 } 700 } 701 break; 702 703 /* We are about to get palette focus! */ 704 case WM_QUERYNEWPALETTE: { 705 WIN_RealizePalette(current_video); 706 return(TRUE); 707 } 708 break; 709 710 /* Another application changed the palette */ 711 case WM_PALETTECHANGED: { 712 WIN_PaletteChanged(current_video, (HWND)wParam); 713 } 714 break; 715 716 /* We were occluded, refresh our display */ 717 case WM_PAINT: { 718 HDC hdc; 719 PAINTSTRUCT ps; 720 721 hdc = BeginPaint(SDL_Window, &ps); 722 if ( current_video->screen && 723 !(current_video->screen->flags & SDL_OPENGL) ) { 724 WIN_WinPAINT(current_video, hdc); 725 } 726 EndPaint(SDL_Window, &ps); 727 } 728 return(0); 729 730 /* DJM: Send an expose event in this case */ 731 case WM_ERASEBKGND: { 732 posted = SDL_PrivateExpose(); 733 } 734 return(0); 735 736 case WM_CLOSE: { 737 if ( (posted = SDL_PrivateQuit()) ) 738 PostQuitMessage(0); 739 } 740 return(0); 741 742 case WM_DESTROY: { 743 PostQuitMessage(0); 744 } 745 return(0); 746 747 #ifndef NO_GETKEYBOARDSTATE 748 case WM_INPUTLANGCHANGE: { 749 codepage = GetCodePage(); 750 } 751 return(TRUE); 752 #endif 753 754 default: { 755 /* Special handling by the video driver */ 756 if (HandleMessage) { 757 return(HandleMessage(current_video, 758 hwnd, msg, wParam, lParam)); 759 } 760 } 761 break; 762 } 763 return(DefWindowProc(hwnd, msg, wParam, lParam)); 764 } 765 766 /* Allow the application handle to be stored and retrieved later */ 767 static void *SDL_handle = NULL; 768 769 void SDL_SetModuleHandle(void *handle) 770 { 771 SDL_handle = handle; 772 } 773 void *SDL_GetModuleHandle(void) 774 { 775 void *handle; 776 777 if ( SDL_handle ) { 778 handle = SDL_handle; 779 } else { 780 handle = GetModuleHandle(NULL); 781 } 782 return(handle); 783 } 784 785 /* This allows the SDL_WINDOWID hack */ 786 BOOL SDL_windowid = FALSE; 787 788 static int app_registered = 0; 789 790 /* Register the class for this application -- exported for winmain.c */ 791 int SDL_RegisterApp(char *name, Uint32 style, void *hInst) 792 { 793 WNDCLASS class; 794 #ifdef WM_MOUSELEAVE 795 HMODULE handle; 796 #endif 797 798 /* Only do this once... */ 799 if ( app_registered ) { 800 ++app_registered; 801 return(0); 802 } 803 804 #ifndef CS_BYTEALIGNCLIENT 805 #define CS_BYTEALIGNCLIENT 0 806 #endif 807 if ( ! name && ! SDL_Appname ) { 808 name = "SDL_app"; 809 SDL_Appstyle = CS_BYTEALIGNCLIENT; 810 SDL_Instance = hInst ? hInst : SDL_GetModuleHandle(); 811 } 812 813 if ( name ) { 814 #ifdef _WIN32_WCE 815 /* WinCE uses the UNICODE version */ 816 SDL_Appname = SDL_iconv_utf8_ucs2(name); 817 #else 818 SDL_Appname = SDL_iconv_utf8_locale(name); 819 #endif /* _WIN32_WCE */ 820 SDL_Appstyle = style; 821 SDL_Instance = hInst ? hInst : SDL_GetModuleHandle(); 822 } 823 824 /* Register the application class */ 825 class.hCursor = NULL; 826 class.hIcon = LoadImage(SDL_Instance, SDL_Appname, 827 IMAGE_ICON, 828 0, 0, LR_DEFAULTCOLOR); 829 class.lpszMenuName = NULL; 830 class.lpszClassName = SDL_Appname; 831 class.hbrBackground = NULL; 832 class.hInstance = SDL_Instance; 833 class.style = SDL_Appstyle; 834 #if SDL_VIDEO_OPENGL 835 class.style |= CS_OWNDC; 836 #endif 837 class.lpfnWndProc = WinMessage; 838 class.cbWndExtra = 0; 839 class.cbClsExtra = 0; 840 if ( ! RegisterClass(&class) ) { 841 SDL_SetError("Couldn't register application class"); 842 return(-1); 843 } 844 845 #ifdef WM_MOUSELEAVE 846 /* Get the version of TrackMouseEvent() we use */ 847 _TrackMouseEvent = NULL; 848 handle = GetModuleHandle("USER32.DLL"); 849 if ( handle ) { 850 _TrackMouseEvent = (BOOL (WINAPI *)(TRACKMOUSEEVENT *))GetProcAddress(handle, "TrackMouseEvent"); 851 } 852 if ( _TrackMouseEvent == NULL ) { 853 _TrackMouseEvent = WIN_TrackMouseEvent; 854 } 855 #endif /* WM_MOUSELEAVE */ 856 857 #ifndef NO_GETKEYBOARDSTATE 858 /* Initialise variables for SDL_ToUnicode() */ 859 codepage = GetCodePage(); 860 SDL_ToUnicode = Is9xME() ? ToUnicode9xME : ToUnicode; 861 #endif 862 863 app_registered = 1; 864 return(0); 865 } 866 867 /* Unregisters the windowclass registered in SDL_RegisterApp above. */ 868 void SDL_UnregisterApp() 869 { 870 WNDCLASS class; 871 872 /* SDL_RegisterApp might not have been called before */ 873 if ( !app_registered ) { 874 return; 875 } 876 --app_registered; 877 if ( app_registered == 0 ) { 878 /* Check for any registered window classes. */ 879 if ( GetClassInfo(SDL_Instance, SDL_Appname, &class) ) { 880 UnregisterClass(SDL_Appname, SDL_Instance); 881 } 882 SDL_free(SDL_Appname); 883 SDL_Appname = NULL; 884 } 885 } 886 887 #ifndef NO_GETKEYBOARDSTATE 888 /* JFP: Implementation of ToUnicode() that works on 9x/ME/2K/XP */ 889 890 static int Is9xME() 891 { 892 OSVERSIONINFO info; 893 894 SDL_memset(&info, 0, sizeof(info)); 895 info.dwOSVersionInfoSize = sizeof(info); 896 if (!GetVersionEx(&info)) { 897 return 0; 898 } 899 return (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); 900 } 901 902 static int GetCodePage() 903 { 904 char buff[8]; 905 int lcid = MAKELCID(LOWORD(GetKeyboardLayout(0)), SORT_DEFAULT); 906 int cp = GetACP(); 907 908 if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buff, sizeof(buff))) { 909 cp = SDL_atoi(buff); 910 } 911 return cp; 912 } 913 914 static int WINAPI ToUnicode9xME(UINT vkey, UINT scancode, PBYTE keystate, LPWSTR wchars, int wsize, UINT flags) 915 { 916 BYTE chars[2]; 917 918 if (ToAsciiEx(vkey, scancode, keystate, (WORD*)chars, 0, GetKeyboardLayout(0)) == 1) { 919 return MultiByteToWideChar(codepage, 0, chars, 1, wchars, wsize); 920 } 921 return 0; 922 } 923 924 #endif /* !NO_GETKEYBOARDSTATE */ 925