src/video/wincommon/SDL_sysevents.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. TrackMouseTimerProc
  2. WIN_TrackMouseEvent
  3. WIN_GetKeyboardState
  4. WinMessage
  5. SDL_RegisterApp

   1 /*
   2     SDL - Simple DirectMedia Layer
   3     Copyright (C) 1997, 1998, 1999  Sam Lantinga
   4 
   5     This library is free software; you can redistribute it and/or
   6     modify it under the terms of the GNU Library General Public
   7     License as published by the Free Software Foundation; either
   8     version 2 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     Library General Public License for more details.
  14 
  15     You should have received a copy of the GNU Library General Public
  16     License along with this library; if not, write to the Free
  17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 
  19     Sam Lantinga
  20     slouken@devolution.com
  21 */
  22 
  23 #ifdef SAVE_RCSID
  24 static char rcsid =
  25  "@(#) $Id: SDL_sysevents.c,v 1.5.2.35 2001/02/28 12:35:28 hercules Exp $";
  26 #endif
  27 
  28 #include <stdlib.h>
  29 #include <stdio.h>
  30 #include <windows.h>
  31 
  32 #include "SDL_getenv.h"
  33 #include "SDL_events.h"
  34 #include "SDL_video.h"
  35 #include "SDL_error.h"
  36 #include "SDL_syswm.h"
  37 #include "SDL_sysevents.h"
  38 #include "SDL_events_c.h"
  39 #include "SDL_sysvideo.h"
  40 #include "SDL_lowvideo.h"
  41 #include "SDL_syswm_c.h"
  42 #include "SDL_main.h"
  43 
  44 #ifdef WMMSG_DEBUG
  45 #include "wmmsg.h"
  46 #endif
  47 
  48 #ifdef _WIN32_WCE
  49 #define NO_GETKEYBOARDSTATE
  50 #endif
  51 
  52 /* The window we use for everything... */
  53 const char *SDL_Appname = NULL;
  54 HINSTANCE SDL_Instance = NULL;
  55 HWND SDL_Window = NULL;
  56 RECT SDL_bounds = {0, 0, 0, 0};
  57 int SDL_resizing = 0;
  58 int mouse_relative = 0;
  59 int posted = 0;
  60 
  61 
  62 /* Functions called by the message processing function */
  63 LONG
  64 (*HandleMessage)(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)=NULL;
  65 void (*WIN_RealizePalette)(_THIS);
  66 void (*WIN_PaletteChanged)(_THIS, HWND window);
  67 void (*WIN_SwapGamma)(_THIS);
  68 void (*WIN_WinPAINT)(_THIS, HDC hdc);
  69 
  70 #ifdef WM_MOUSELEAVE
  71 /* 
  72    Special code to handle mouse leave events - this sucks...
  73    http://support.microsoft.com/support/kb/articles/q183/1/07.asp
  74 
  75    TrackMouseEvent() is only available on Win98 and WinNT.
  76    _TrackMouseEvent() is available on Win95, but isn't yet in the mingw32
  77    development environment, and only works on systems that have had IE 3.0
  78    or newer installed on them (which is not the case with the base Win95).
  79    Therefore, we implement our own version of _TrackMouseEvent() which
  80    uses our own implementation if TrackMouseEvent() is not available.
  81 */
  82 static BOOL (WINAPI *_TrackMouseEvent)(TRACKMOUSEEVENT *ptme) = NULL;
  83 
  84 static VOID CALLBACK
  85 TrackMouseTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
     /* [<][>][^][v][top][bottom][index][help] */
  86 {
  87         RECT rect;
  88         POINT pt;
  89 
  90         GetClientRect(hWnd, &rect);
  91         MapWindowPoints(hWnd, NULL, (LPPOINT)&rect, 2);
  92         GetCursorPos(&pt);
  93         if ( !PtInRect(&rect, pt) || (WindowFromPoint(pt) != hWnd) ) {
  94                 if ( !KillTimer(hWnd, idEvent) ) {
  95                         /* Error killing the timer! */
  96                 }
  97                 PostMessage(hWnd, WM_MOUSELEAVE, 0, 0);
  98         }
  99 }
 100 static BOOL WINAPI WIN_TrackMouseEvent(TRACKMOUSEEVENT *ptme)
     /* [<][>][^][v][top][bottom][index][help] */
 101 {
 102         if ( ptme->dwFlags == TME_LEAVE ) {
 103                 return SetTimer(ptme->hwndTrack, ptme->dwFlags, 100,
 104                                 (TIMERPROC)TrackMouseTimerProc);
 105         }
 106         return FALSE;
 107 }
 108 #endif /* WM_MOUSELEAVE */
 109 
 110 /* Function to retrieve the current keyboard modifiers */
 111 static void WIN_GetKeyboardState(void)
     /* [<][>][^][v][top][bottom][index][help] */
 112 {
 113 #ifndef NO_GETKEYBOARDSTATE
 114         SDLMod state;
 115         BYTE keyboard[256];
 116 
 117         state = KMOD_NONE;
 118         if ( GetKeyboardState(keyboard) ) {
 119                 if ( keyboard[VK_LSHIFT] & 0x80) {
 120                         state |= KMOD_LSHIFT;
 121                 }
 122                 if ( keyboard[VK_RSHIFT] & 0x80) {
 123                         state |= KMOD_RSHIFT;
 124                 }
 125                 if ( keyboard[VK_LCONTROL] & 0x80) {
 126                         state |= KMOD_LCTRL;
 127                 }
 128                 if ( keyboard[VK_RCONTROL] & 0x80) {
 129                         state |= KMOD_RCTRL;
 130                 }
 131                 if ( keyboard[VK_LMENU] & 0x80) {
 132                         state |= KMOD_LALT;
 133                 }
 134                 if ( keyboard[VK_RMENU] & 0x80) {
 135                         state |= KMOD_RALT;
 136                 }
 137                 if ( keyboard[VK_NUMLOCK] & 0x80) {
 138                         state |= KMOD_NUM;
 139                 }
 140                 if ( keyboard[VK_CAPITAL] & 0x80) {
 141                         state |= KMOD_CAPS;
 142                 }
 143         }
 144         SDL_SetModState(state);
 145 #endif /* !NO_GETKEYBOARDSTATE */
 146 }
 147 
 148 /* The main Win32 event handler */
 149 static LONG CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
     /* [<][>][^][v][top][bottom][index][help] */
 150 {
 151         SDL_VideoDevice *this = current_video;
 152         static int mouse_pressed = 0;
 153         static int in_window = 0;
 154 #ifdef WMMSG_DEBUG
 155         fprintf(stderr, "Received windows message:  ");
 156         if ( msg > MAX_WMMSG ) {
 157                 fprintf(stderr, "%d", msg);
 158         } else {
 159                 fprintf(stderr, "%s", wmtab[msg]);
 160         }
 161         fprintf(stderr, " -- 0x%X, 0x%X\n", wParam, lParam);
 162 #endif
 163         switch (msg) {
 164 
 165                 case WM_ACTIVATE: {
 166                         SDL_VideoDevice *this = current_video;
 167                         BOOL minimized;
 168                         Uint8 appstate;
 169 
 170                         minimized = HIWORD(wParam);
 171                         if ( !minimized && (LOWORD(wParam) != WA_INACTIVE) ) {
 172                                 /* Gain the following states */
 173                                 appstate = SDL_APPACTIVE|SDL_APPINPUTFOCUS;
 174                                 if ( this->input_grab != SDL_GRAB_OFF ) {
 175                                         WIN_GrabInput(this, SDL_GRAB_ON);
 176                                 }
 177                                 if ( !(SDL_GetAppState()&SDL_APPINPUTFOCUS) ) {
 178                                         WIN_SwapGamma(this);
 179                                 }
 180                                 posted = SDL_PrivateAppActive(1, appstate);
 181                                 WIN_GetKeyboardState();
 182                         } else {
 183                                 /* Lose the following states */
 184                                 appstate = SDL_APPINPUTFOCUS;
 185                                 if ( minimized ) {
 186                                         appstate |= SDL_APPACTIVE;
 187                                 }
 188                                 if ( this->input_grab != SDL_GRAB_OFF ) {
 189                                         WIN_GrabInput(this, SDL_GRAB_OFF);
 190                                 }
 191                                 if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
 192                                         WIN_SwapGamma(this);
 193                                 }
 194                                 posted = SDL_PrivateAppActive(0, appstate);
 195                         }
 196                         return(0);
 197                 }
 198                 break;
 199 
 200                 case WM_MOUSEMOVE: {
 201                         
 202                         /* Mouse is handled by DirectInput when fullscreen */
 203                         if ( SDL_VideoSurface && ! DIRECTX_FULLSCREEN() ) {
 204                                 Sint16 x, y;
 205 
 206                                 /* mouse has entered the window */
 207                                 if ( ! in_window ) {
 208 #ifdef WM_MOUSELEAVE
 209                                         TRACKMOUSEEVENT tme;
 210 
 211                                         tme.cbSize = sizeof(tme);
 212                                         tme.dwFlags = TME_LEAVE;
 213                                         tme.hwndTrack = SDL_Window;
 214                                         _TrackMouseEvent(&tme);
 215 #endif /* WM_MOUSELEAVE */
 216                                         in_window = TRUE;
 217 
 218                                         posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
 219                                 }
 220 
 221                                 /* mouse has moved within the window */
 222                                 x = LOWORD(lParam);
 223                                 y = HIWORD(lParam);
 224                                 if ( mouse_relative ) {
 225                                         POINT center;
 226                                         center.x = (SDL_VideoSurface->w/2);
 227                                         center.y = (SDL_VideoSurface->h/2);
 228                                         x -= (Sint16)center.x;
 229                                         y -= (Sint16)center.y;
 230                                         if ( x || y ) {
 231                                                 ClientToScreen(SDL_Window, &center);
 232                                                 SetCursorPos(center.x, center.y);
 233                                                 posted = SDL_PrivateMouseMotion(0, 1, x, y);
 234                                         }
 235                                 } else {
 236                                         posted = SDL_PrivateMouseMotion(0, 0, x, y);
 237                                 }
 238                         }
 239                 }
 240                 return(0);
 241 
 242 #ifdef WM_MOUSELEAVE
 243                 case WM_MOUSELEAVE: {
 244 
 245                         /* Mouse is handled by DirectInput when fullscreen */
 246                         if ( SDL_VideoSurface && ! DIRECTX_FULLSCREEN() ) {
 247                                 /* mouse has left the window */
 248                                 /* or */
 249                                 /* Elvis has left the building! */
 250                                 in_window = FALSE;
 251                                 posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
 252                         }
 253                 }
 254                 return(0);
 255 #endif /* WM_MOUSELEAVE */
 256 
 257                 case WM_LBUTTONDOWN:
 258                 case WM_LBUTTONUP:
 259                 case WM_MBUTTONDOWN:
 260                 case WM_MBUTTONUP:
 261                 case WM_RBUTTONDOWN:
 262                 case WM_RBUTTONUP: {
 263                         /* Mouse is handled by DirectInput when fullscreen */
 264                         if ( SDL_VideoSurface && ! DIRECTX_FULLSCREEN() ) {
 265                                 Sint16 x, y;
 266                                 Uint8 button, state;
 267 
 268                                 /* Figure out which button to use */
 269                                 switch (msg) {
 270                                         case WM_LBUTTONDOWN:
 271                                                 button = 1;
 272                                                 state = SDL_PRESSED;
 273                                                 break;
 274                                         case WM_LBUTTONUP:
 275                                                 button = 1;
 276                                                 state = SDL_RELEASED;
 277                                                 break;
 278                                         case WM_MBUTTONDOWN:
 279                                                 button = 2;
 280                                                 state = SDL_PRESSED;
 281                                                 break;
 282                                         case WM_MBUTTONUP:
 283                                                 button = 2;
 284                                                 state = SDL_RELEASED;
 285                                                 break;
 286                                         case WM_RBUTTONDOWN:
 287                                                 button = 3;
 288                                                 state = SDL_PRESSED;
 289                                                 break;
 290                                         case WM_RBUTTONUP:
 291                                                 button = 3;
 292                                                 state = SDL_RELEASED;
 293                                                 break;
 294                                         default:
 295                                                 /* Eh? Unknown button? */
 296                                                 return(0);
 297                                 }
 298                                 if ( state == SDL_PRESSED ) {
 299                                         /* Grab mouse so we get up events */
 300                                         if ( ++mouse_pressed > 0 ) {
 301                                                 SetCapture(hwnd);
 302                                         }
 303                                 } else {
 304                                         /* Release mouse after all up events */
 305                                         if ( --mouse_pressed <= 0 ) {
 306                                                 ReleaseCapture();
 307                                                 mouse_pressed = 0;
 308                                         }
 309                                 }
 310                                 if ( mouse_relative ) {
 311                                 /*      RJR: March 28, 2000
 312                                         report internal mouse position if in relative mode */
 313                                         x = 0; y = 0;
 314                                 } else {
 315                                         x = (Sint16)LOWORD(lParam);
 316                                         y = (Sint16)HIWORD(lParam);
 317                                 }
 318                                 posted = SDL_PrivateMouseButton(
 319                                                         state, button, x, y);
 320                         }
 321                 }
 322                 return(0);
 323 
 324 #ifdef WM_GETMINMAXINFO
 325                 /* This message is sent as a way for us to "check" the values
 326                  * of a position change.  If we don't like it, we can adjust
 327                  * the values before they are changed.
 328                  */
 329                 case WM_GETMINMAXINFO: {
 330                         MINMAXINFO *info;
 331                         RECT        size;
 332                         int x, y;
 333                         int width;
 334                         int height;
 335 
 336                         /* We don't want to clobber an internal resize */
 337                         if ( SDL_resizing )
 338                                 return(0);
 339 
 340                         /* We allow resizing with the SDL_RESIZABLE flag */
 341                         if ( SDL_PublicSurface &&
 342                                 (SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
 343                                 return(0);
 344                         }
 345 
 346                         /* Get the current position of our window */
 347                         GetWindowRect(SDL_Window, &size);
 348                         x = size.left;
 349                         y = size.top;
 350 
 351                         /* Calculate current width and height of our window */
 352                         size.top = 0;
 353                         size.left = 0;
 354                         if ( SDL_PublicSurface != NULL ) {
 355                                 size.bottom = SDL_PublicSurface->h;
 356                                 size.right = SDL_PublicSurface->w;
 357                         } else {
 358                                 size.bottom = 0;
 359                                 size.right = 0;
 360                         }
 361                         AdjustWindowRect(&size, GetWindowLong(hwnd, GWL_STYLE),
 362                                                                         FALSE);
 363                         width = size.right - size.left;
 364                         height = size.bottom - size.top;
 365 
 366                         /* Fix our size to the current size */
 367                         info = (MINMAXINFO *)lParam;
 368                         info->ptMaxSize.x = width;
 369                         info->ptMaxSize.y = height;
 370                         info->ptMaxPosition.x = x;
 371                         info->ptMaxPosition.y = y;
 372                         info->ptMinTrackSize.x = width;
 373                         info->ptMinTrackSize.y = height;
 374                         info->ptMaxTrackSize.x = width;
 375                         info->ptMaxTrackSize.y = height;
 376                 }
 377                 return(0);
 378 #endif /* WM_GETMINMAXINFO */
 379 
 380                 case WM_MOVE: {
 381                         SDL_VideoDevice *this = current_video;
 382 
 383                         GetClientRect(SDL_Window, &SDL_bounds);
 384                         ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds);
 385                         ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds+1);
 386                         if ( this->input_grab != SDL_GRAB_OFF ) {
 387                                 ClipCursor(&SDL_bounds);
 388                         }
 389                 }
 390                 break;
 391         
 392                 case WM_SIZE: {
 393                         if ( SDL_PublicSurface &&
 394                                 (SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
 395                                 SDL_PrivateResize(LOWORD(lParam), HIWORD(lParam));
 396                         }
 397                         return(0);
 398                 }
 399                 break;
 400 
 401                 /* We need to set the cursor */
 402                 case WM_SETCURSOR: {
 403                         Uint16 hittest;
 404 
 405                         hittest = LOWORD(lParam);
 406                         if ( hittest == HTCLIENT ) {
 407                                 SetCursor(SDL_hcursor);
 408                                 return(TRUE);
 409                         }
 410                 }
 411                 break;
 412 
 413                 /* We are about to get palette focus! */
 414                 case WM_QUERYNEWPALETTE: {
 415                         WIN_RealizePalette(current_video);
 416                         return(TRUE);
 417                 }
 418                 break;
 419 
 420                 /* Another application changed the palette */
 421                 case WM_PALETTECHANGED: {
 422                         WIN_PaletteChanged(current_video, (HWND)wParam);
 423                 }
 424                 break;
 425 
 426                 /* We were occluded, refresh our display */
 427                 case WM_PAINT: {
 428                         HDC hdc;
 429                         PAINTSTRUCT ps;
 430 
 431                         hdc = BeginPaint(SDL_Window, &ps);
 432                         if ( current_video->screen &&
 433                              !(current_video->screen->flags & SDL_OPENGL) ) {
 434                                 WIN_WinPAINT(current_video, hdc);
 435                         }
 436                         EndPaint(SDL_Window, &ps);
 437                 }
 438                 return(0);
 439 
 440                 case WM_ERASEBKGND: {
 441                         /* Just do nothing */ ;
 442                 }
 443                 return(1);
 444 
 445                 case WM_CLOSE: {
 446                         if ( (posted = SDL_PrivateQuit()) )
 447                                 PostQuitMessage(0);
 448                 }
 449                 return(0);
 450 
 451                 case WM_DESTROY: {
 452                         PostQuitMessage(0);
 453                 }
 454                 return(0);
 455 
 456                 default: {
 457                         /* Special handling by the video driver */
 458                         if (HandleMessage) {
 459                                 return(HandleMessage(current_video,
 460                                              hwnd, msg, wParam, lParam));
 461                         }
 462                 }
 463                 break;
 464         }
 465         return(DefWindowProc(hwnd, msg, wParam, lParam));
 466 }
 467 
 468 /* This allows the SDL_WINDOWID hack */
 469 const char *SDL_windowid = NULL;
 470 
 471 /* Register the class for this application -- exported for winmain.c */
 472 int SDL_RegisterApp(char *name, Uint32 style, void *hInst)
     /* [<][>][^][v][top][bottom][index][help] */
 473 {
 474         static int initialized = 0;
 475         WNDCLASS class;
 476 #ifdef WM_MOUSELEAVE
 477         HMODULE handle;
 478 #endif
 479 
 480         /* Only do this once... */
 481         if ( initialized ) {
 482                 return(0);
 483         }
 484 
 485         /* This function needs to be passed the correct process handle
 486            by the application.  The following call just returns a handle
 487            to the SDL DLL, which is useless for our purposes and causes
 488            DirectInput to fail to initialize.
 489          */
 490         if ( ! hInst ) {
 491                 hInst = GetModuleHandle(NULL);
 492         }
 493 
 494         /* Register the application class */
 495         class.hCursor           = NULL;
 496 #ifdef _WIN32_WCE
 497     {
 498         /* WinCE uses the UNICODE version */
 499         int nLen = strlen(name);
 500         LPWSTR lpszW = alloca((nLen+1)*2);
 501         MultiByteToWideChar(CP_ACP, 0, name, -1, lpszW, nLen);
 502         class.hIcon             = LoadImage(hInst, lpszW, IMAGE_ICON,
 503                                             0, 0, LR_DEFAULTCOLOR);
 504         class.lpszMenuName      = lpszW;
 505         class.lpszClassName     = lpszW;
 506     }
 507 #else
 508         class.hIcon             = LoadImage(hInst, name, IMAGE_ICON,
 509                                             0, 0, LR_DEFAULTCOLOR);
 510         class.lpszMenuName      = "(none)";
 511         class.lpszClassName     = name;
 512 #endif /* _WIN32_WCE */
 513         class.hbrBackground     = NULL;
 514         class.hInstance         = hInst ? hInst : GetModuleHandle(0);
 515         class.style             = style;
 516 #ifdef HAVE_OPENGL
 517         class.style             |= CS_OWNDC;
 518 #endif
 519         class.lpfnWndProc       = WinMessage;
 520         class.cbWndExtra        = 0;
 521         class.cbClsExtra        = 0;
 522         if ( ! RegisterClass(&class) ) {
 523                 SDL_SetError("Couldn't register application class");
 524                 return(-1);
 525         }
 526         SDL_Appname = name;
 527         SDL_Instance = hInst;
 528 
 529 #ifdef WM_MOUSELEAVE
 530         /* Get the version of TrackMouseEvent() we use */
 531         _TrackMouseEvent = NULL;
 532         handle = GetModuleHandle("USER32.DLL");
 533         if ( handle ) {
 534                 _TrackMouseEvent = (BOOL (WINAPI *)(TRACKMOUSEEVENT *))GetProcAddress(handle, "TrackMouseEvent");
 535         }
 536         if ( _TrackMouseEvent == NULL ) {
 537                 _TrackMouseEvent = WIN_TrackMouseEvent;
 538         }
 539 #endif /* WM_MOUSELEAVE */
 540 
 541         /* Check for SDL_WINDOWID hack */
 542         SDL_windowid = getenv("SDL_WINDOWID");
 543 
 544         initialized = 1;
 545         return(0);
 546 }
 547 

/* [<][>][^][v][top][bottom][index][help] */