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