win32_winproc.c revision c041511d
1 2/* Copyright (c) Nate Robins, 1997. */ 3/* portions Copyright (c) Mark Kilgard, 1997, 1998. */ 4 5/* This program is freely distributable without licensing fees 6 and is provided without guarantee or warrantee expressed or 7 implied. This program is -not- in the public domain. */ 8 9 10#include "glutint.h" 11#include <sys/timeb.h> 12#ifdef __MINGW32__ 13#include <ctype.h> 14#endif 15 16#if defined(_WIN32) && !defined(__CYGWIN32__) 17#include <mmsystem.h> /* Win32 Multimedia API header. */ 18#endif 19 20extern unsigned __glutMenuButton; 21extern GLUTidleCB __glutIdleFunc; 22extern GLUTtimer *__glutTimerList; 23extern GLUTmenuItem *__glutGetUniqueMenuItem(GLUTmenu * menu, int unique); 24static HMENU __glutHMenu; 25 26void 27updateWindowState(GLUTwindow *window, int visState) 28{ 29 GLUTwindow* child; 30 31 /* XXX shownState and visState are the same in Win32. */ 32 window->shownState = visState; 33 if (visState != window->visState) { 34 if (window->windowStatus) { 35 window->visState = visState; 36 __glutSetWindow(window); 37 window->windowStatus(visState); 38 } 39 } 40 /* Since Win32 only sends an activate for the toplevel window, 41 update the visibility for all the child windows. */ 42 child = window->children; 43 while (child) { 44 updateWindowState(child, visState); 45 child = child->siblings; 46 } 47} 48 49LONG WINAPI 50__glutWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 51{ 52 POINT point; /* Point structure. */ 53 PAINTSTRUCT ps; /* Paint structure. */ 54 LPMINMAXINFO minmax; /* Minimum/maximum info structure. */ 55 GLUTwindow* window; /* GLUT window associated with message. */ 56 GLUTmenu* menu; /* GLUT menu associated with message. */ 57 int x, y, width, height, key; 58 int button = -1; 59 60 switch(msg) { 61 case WM_CREATE: 62 return 0; 63 case WM_CLOSE: 64 if (__glutExitFunc) { 65 __glutExitFunc(0); 66 } 67 exit(0); 68 break; 69#if 0 70 case WM_DESTROY: 71 /* XXX NVidia's NT OpenGL can have problems closing down 72 its OpenGL internal data structures if we just allow 73 the process to terminate without unbinding and deleting 74 the windows context. Apparently, DirectDraw unloads 75 before OPENGL32.DLL in the close down sequence, but 76 NVidia's NT OpenGL needs DirectDraw to close down its 77 data structures. */ 78 window = __glutGetWindow(hwnd); 79 if (window) { 80 if (window->ctx) { 81 wglMakeCurrent(NULL, NULL); 82 wglDeleteContext(window->ctx); 83 } 84 } 85 return 0; 86#endif 87 case WM_PAINT: 88 window = __glutGetWindow(hwnd); 89 if (window) { 90 BeginPaint(hwnd, &ps); /* Must have this for some Win32 reason. */ 91 EndPaint(hwnd, &ps); 92 if (window->win == hwnd) { 93 __glutPostRedisplay(window, GLUT_REPAIR_WORK); 94 } else if (window->overlay && window->overlay->win == hwnd) { 95 __glutPostRedisplay(window, GLUT_OVERLAY_REPAIR_WORK); 96 } 97 } 98 return 0; 99 100 case WM_SYSKEYUP: 101 case WM_KEYUP: 102 window = __glutGetWindow(hwnd); 103 if (!window) { 104 break; 105 } 106 /* Win32 is dumb and sends these messages only to the parent 107 window. Therefore, find out if we're in a child window and 108 call the child windows keyboard callback if we are. */ 109 if (window->parent) { 110 GetCursorPos(&point); 111 ScreenToClient(hwnd, &point); 112 hwnd = ChildWindowFromPoint(hwnd, point); 113 window = __glutGetWindow(hwnd); 114 } 115 if (window->specialUp || window->keyboardUp) { 116 GetCursorPos(&point); 117 ScreenToClient(window->win, &point); 118 __glutSetWindow(window); 119 __glutModifierMask = 0; 120 if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 121 __glutModifierMask |= ShiftMask; 122 if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 123 __glutModifierMask |= ControlMask; 124 if (GetKeyState(VK_MENU) < 0) 125 __glutModifierMask |= Mod1Mask; 126 switch (wParam) { 127 /* *INDENT-OFF* */ 128 case VK_F1: key = GLUT_KEY_F1; break; 129 case VK_F2: key = GLUT_KEY_F2; break; 130 case VK_F3: key = GLUT_KEY_F3; break; 131 case VK_F4: key = GLUT_KEY_F4; break; 132 case VK_F5: key = GLUT_KEY_F5; break; 133 case VK_F6: key = GLUT_KEY_F6; break; 134 case VK_F7: key = GLUT_KEY_F7; break; 135 case VK_F8: key = GLUT_KEY_F8; break; 136 case VK_F9: key = GLUT_KEY_F9; break; 137 case VK_F10: key = GLUT_KEY_F10; break; 138 case VK_F11: key = GLUT_KEY_F11; break; 139 case VK_F12: key = GLUT_KEY_F12; break; 140 case VK_LEFT: key = GLUT_KEY_LEFT; break; 141 case VK_UP: key = GLUT_KEY_UP; break; 142 case VK_RIGHT: key = GLUT_KEY_RIGHT; break; 143 case VK_DOWN: key = GLUT_KEY_DOWN; break; 144 case VK_PRIOR: key = GLUT_KEY_PAGE_UP; break; 145 case VK_NEXT: key = GLUT_KEY_PAGE_DOWN; break; 146 case VK_HOME: key = GLUT_KEY_HOME; break; 147 case VK_END: key = GLUT_KEY_END; break; 148 case VK_INSERT: key = GLUT_KEY_INSERT; break; 149 case VK_DELETE: 150 /* Delete is an ASCII character. */ 151 if (window->keyboardUp) { 152 window->keyboardUp((unsigned char) 127, point.x, point.y); 153 } 154 return 0; 155 /* *INDENT-ON* */ 156 default: 157 if (window->keyboardUp) { 158 key = MapVirtualKey(wParam, 2); /* Map to ASCII. */ 159 if (isascii(key) && (key != 0)) { 160 161 /* XXX Attempt to determine modified ASCII character 162 is quite incomplete. Digits, symbols, CapsLock, 163 Ctrl, and numeric keypad are all ignored. Fix this. */ 164 165 if (!(__glutModifierMask & ShiftMask)) 166 key = tolower(key); 167 window->keyboardUp((unsigned char) key, point.x, point.y); 168 } 169 } 170 __glutModifierMask = (unsigned int) ~0; 171 return 0; 172 } 173 if (window->specialUp) { 174 window->specialUp(key, point.x, point.y); 175 } 176 __glutModifierMask = (unsigned int) ~0; 177 } 178 return 0; 179 180 case WM_SYSCHAR: 181 case WM_CHAR: 182 window = __glutGetWindow(hwnd); 183 if (!window) { 184 break; 185 } 186 187 /* Bit 30 of lParam is set if key already held down. If 188 we are ignoring auto repeated key strokes for the window, bail. */ 189 if (window->ignoreKeyRepeat && (lParam & (1 << 30)) ) { 190 break; 191 } 192 193 /* Win32 is dumb and sends these messages only to the parent 194 window. Therefore, find out if we're in a child window and 195 call the child windows keyboard callback if we are. */ 196 if (window->parent) { 197 GetCursorPos(&point); 198 ScreenToClient(hwnd, &point); 199 hwnd = ChildWindowFromPoint(hwnd, point); 200 window = __glutGetWindow(hwnd); 201 } 202 if (window->keyboard) { 203 GetCursorPos(&point); 204 ScreenToClient(window->win, &point); 205 __glutSetWindow(window); 206 __glutModifierMask = 0; 207 if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 208 __glutModifierMask |= ShiftMask; 209 if (GetKeyState(VK_CONTROL) < 0) 210 __glutModifierMask |= ControlMask; 211 if (GetKeyState(VK_MENU) < 0) 212 __glutModifierMask |= Mod1Mask; 213 window->keyboard((unsigned char)wParam, point.x, point.y); 214 __glutModifierMask = (unsigned int) ~0; 215 } 216 return 0; 217 218 case WM_SYSKEYDOWN: 219 case WM_KEYDOWN: 220 window = __glutGetWindow(hwnd); 221 if (!window) { 222 break; 223 } 224 225 /* Bit 30 of lParam is set if key already held down. If 226 we are ignoring auto repeated key strokes for the window, bail. */ 227 if (window->ignoreKeyRepeat && (lParam & (1 << 30)) ) { 228 break; 229 } 230 231 /* Win32 is dumb and sends these messages only to the parent 232 window. Therefore, find out if we're in a child window and 233 call the child windows keyboard callback if we are. */ 234 if (window->parent) { 235 GetCursorPos(&point); 236 ScreenToClient(hwnd, &point); 237 hwnd = ChildWindowFromPoint(hwnd, point); 238 window = __glutGetWindow(hwnd); 239 } 240 if (window->special) { 241 switch (wParam) { 242 /* *INDENT-OFF* */ 243 /* function keys */ 244 case VK_F1: key = GLUT_KEY_F1; break; 245 case VK_F2: key = GLUT_KEY_F2; break; 246 case VK_F3: key = GLUT_KEY_F3; break; 247 case VK_F4: key = GLUT_KEY_F4; break; 248 case VK_F5: key = GLUT_KEY_F5; break; 249 case VK_F6: key = GLUT_KEY_F6; break; 250 case VK_F7: key = GLUT_KEY_F7; break; 251 case VK_F8: key = GLUT_KEY_F8; break; 252 case VK_F9: key = GLUT_KEY_F9; break; 253 case VK_F10: key = GLUT_KEY_F10; break; 254 case VK_F11: key = GLUT_KEY_F11; break; 255 case VK_F12: key = GLUT_KEY_F12; break; 256 /* directional keys */ 257 case VK_LEFT: key = GLUT_KEY_LEFT; break; 258 case VK_UP: key = GLUT_KEY_UP; break; 259 case VK_RIGHT: key = GLUT_KEY_RIGHT; break; 260 case VK_DOWN: key = GLUT_KEY_DOWN; break; 261 /* *INDENT-ON* */ 262 263 case VK_PRIOR: 264 /* VK_PRIOR is Win32's Page Up */ 265 key = GLUT_KEY_PAGE_UP; 266 break; 267 case VK_NEXT: 268 /* VK_NEXT is Win32's Page Down */ 269 key = GLUT_KEY_PAGE_DOWN; 270 break; 271 case VK_HOME: 272 key = GLUT_KEY_HOME; 273 break; 274 case VK_END: 275 key = GLUT_KEY_END; 276 break; 277 case VK_INSERT: 278 key = GLUT_KEY_INSERT; 279 break; 280 case VK_DELETE: 281 goto handleDelete; 282 default: 283 goto defproc; 284 } 285 GetCursorPos(&point); 286 ScreenToClient(window->win, &point); 287 __glutSetWindow(window); 288 __glutModifierMask = 0; 289 if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 290 __glutModifierMask |= ShiftMask; 291 if (GetKeyState(VK_CONTROL) < 0) 292 __glutModifierMask |= ControlMask; 293 if (GetKeyState(VK_MENU) < 0) 294 __glutModifierMask |= Mod1Mask; 295 window->special(key, point.x, point.y); 296 __glutModifierMask = (unsigned int) ~0; 297 } else if (window->keyboard) { 298 /* Specially handle any keys that match ASCII values but 299 do not generate Windows WM_SYSCHAR or WM_CHAR messages. */ 300 switch (wParam) { 301 case VK_DELETE: 302 handleDelete: 303 /* Delete is an ASCII character. */ 304 GetCursorPos(&point); 305 ScreenToClient(window->win, &point); 306 __glutSetWindow(window); 307 __glutModifierMask = 0; 308 if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 309 __glutModifierMask |= ShiftMask; 310 if (GetKeyState(VK_CONTROL) < 0) 311 __glutModifierMask |= ControlMask; 312 if (GetKeyState(VK_MENU) < 0) 313 __glutModifierMask |= Mod1Mask; 314 window->keyboard((unsigned char) 127, point.x, point.y); 315 __glutModifierMask = (unsigned int) ~0; 316 return 0; 317 default: 318 /* Let the following WM_SYSCHAR or WM_CHAR message generate 319 the keyboard callback. */ 320 break; 321 } 322 } 323 return 0; 324 325 case WM_LBUTTONDOWN: 326 button = GLUT_LEFT_BUTTON; 327 case WM_MBUTTONDOWN: 328 if (button < 0) 329 button = GLUT_MIDDLE_BUTTON; 330 case WM_RBUTTONDOWN: 331 if (button < 0) 332 button = GLUT_RIGHT_BUTTON; 333 334 /* finish the menu if we get a button down message (user must have 335 cancelled the menu). */ 336 if (__glutMappedMenu) { 337 /* TODO: take this out once the menu on middle mouse stuff works 338 properly. */ 339 if (button == GLUT_MIDDLE_BUTTON) 340 return 0; 341 GetCursorPos(&point); 342 ScreenToClient(hwnd, &point); 343 __glutItemSelected = NULL; 344 __glutFinishMenu(hwnd, point.x, point.y); 345 return 0; 346 } 347 348 /* set the capture so we can get mouse events outside the window */ 349 SetCapture(hwnd); 350 351 /* Win32 doesn't return the same numbers as X does when the mouse 352 goes beyond the upper or left side of the window. roll the 353 Win32's 0..2^16 pointer co-ord range to 0 +/- 2^15. */ 354 x = LOWORD(lParam); 355 y = HIWORD(lParam); 356 if(x & 1 << 15) x -= (1 << 16); 357 if(y & 1 << 15) y -= (1 << 16); 358 359 window = __glutGetWindow(hwnd); 360 if (window) { 361 menu = __glutGetMenuByNum(window->menu[button]); 362 if (menu) { 363 point.x = LOWORD(lParam); point.y = HIWORD(lParam); 364 ClientToScreen(window->win, &point); 365 __glutMenuButton = button == GLUT_RIGHT_BUTTON ? TPM_RIGHTBUTTON : 366 button == GLUT_LEFT_BUTTON ? TPM_LEFTBUTTON : 367 0x0001; 368 __glutStartMenu(menu, window, point.x, point.y, x, y); 369 } else if (window->mouse) { 370 371 __glutSetWindow(window); 372 __glutModifierMask = 0; 373 if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on. */ 374 __glutModifierMask |= ShiftMask; 375 if (GetKeyState(VK_CONTROL) < 0) 376 __glutModifierMask |= ControlMask; 377 if (GetKeyState(VK_MENU) < 0) 378 __glutModifierMask |= Mod1Mask; 379 window->mouse(button, GLUT_DOWN, x, y); 380 __glutModifierMask = (unsigned int)~0; 381 } else { 382 /* Stray mouse events. Ignore. */ 383 } 384 } 385 return 0; 386 387 case WM_LBUTTONUP: 388 button = GLUT_LEFT_BUTTON; 389 case WM_MBUTTONUP: 390 if (button < 0) 391 button = GLUT_MIDDLE_BUTTON; 392 case WM_RBUTTONUP: 393 if (button < 0) 394 button = GLUT_RIGHT_BUTTON; 395 396 /* Bail out if we're processing a menu. */ 397 if (__glutMappedMenu) { 398 GetCursorPos(&point); 399 ScreenToClient(hwnd, &point); 400 /* if we're getting the middle button up signal, then something 401 on the menu was selected. */ 402 if (button == GLUT_MIDDLE_BUTTON) { 403 return 0; 404 /* For some reason, the code below always returns -1 even 405 though the point IS IN THE ITEM! Therefore, just bail out if 406 we get a middle mouse up. The user must select using the 407 left mouse button. Stupid Win32. */ 408#if 0 409 int item = MenuItemFromPoint(hwnd, __glutHMenu, point); 410 if (item != -1) 411 __glutItemSelected = (GLUTmenuItem*)GetMenuItemID(__glutHMenu, item); 412 else 413 __glutItemSelected = NULL; 414 __glutFinishMenu(hwnd, point.x, point.y); 415#endif 416 } else { 417 __glutItemSelected = NULL; 418 __glutFinishMenu(hwnd, point.x, point.y); 419 } 420 return 0; 421 } 422 423 /* Release the mouse capture. */ 424 ReleaseCapture(); 425 426 window = __glutGetWindow(hwnd); 427 if (window && window->mouse) { 428 /* Win32 doesn't return the same numbers as X does when the 429 mouse goes beyond the upper or left side of the window. roll 430 the Win32's 0..2^16 pointer co-ord range to 0 +/- 2^15. */ 431 x = LOWORD(lParam); 432 y = HIWORD(lParam); 433 if(x & 1 << 15) x -= (1 << 16); 434 if(y & 1 << 15) y -= (1 << 16); 435 436 __glutSetWindow(window); 437 __glutModifierMask = 0; 438 if (GetKeyState(VK_SHIFT) < 0) /* < 0 = high order bit is on */ 439 __glutModifierMask |= ShiftMask; 440 if (GetKeyState(VK_CONTROL) < 0) 441 __glutModifierMask |= ControlMask; 442 if (GetKeyState(VK_MENU) < 0) 443 __glutModifierMask |= Mod1Mask; 444 window->mouse(button, GLUT_UP, x, y); 445 __glutModifierMask = (unsigned int)~0; 446 } else { 447 /* Window might have been destroyed and all the 448 events for the window may not yet be received. */ 449 } 450 return 0; 451 452 case WM_ENTERMENULOOP: 453 /* KLUDGE: create a timer that fires every 100 ms when we start a 454 menu so that we can still process the idle & timer events (that 455 way, the timers will fire during a menu pick and so will the 456 idle func. */ 457 SetTimer(hwnd, 1, 1, NULL); 458 return 0; 459 460 case WM_TIMER: 461#if 0 462 /* If the timer id is 2, then this is the timer that is set up in 463 the main glut message processing loop, and we don't want to do 464 anything but acknowledge that we got it. It is used to prevent 465 CPU spiking when an idle function is installed. */ 466 if (wParam == 2) 467 return 0; 468#endif 469 470 /* only worry about the idle function and the timeouts, since 471 these are the only events we expect to process during 472 processing of a menu. */ 473 /* we no longer process the idle functions (as outlined in the 474 README), since drawing can't be done until the menu has 475 finished...it's pretty lame when the animation goes on, but 476 doesn't update, so you get this weird jerkiness. */ 477#if 0 478 if (__glutIdleFunc) 479 __glutIdleFunc(); 480#endif 481 if (__glutTimerList) 482 handleTimeouts(); 483 return 0; 484 485 case WM_EXITMENULOOP: 486 /* nuke the above created timer...we don't need it anymore, since 487 the menu is gone now. */ 488 KillTimer(hwnd, 1); 489 return 0; 490 491 case WM_MENUSELECT: 492 if (lParam != 0) 493 __glutHMenu = (HMENU)lParam; 494 return 0; 495 496 case WM_COMMAND: 497 if (__glutMappedMenu) { 498 if (GetSubMenu(__glutHMenu, LOWORD(wParam))) 499 __glutItemSelected = NULL; 500 else 501 __glutItemSelected = 502 __glutGetUniqueMenuItem(__glutMappedMenu, LOWORD(wParam)); 503 GetCursorPos(&point); 504 ScreenToClient(hwnd, &point); 505 __glutFinishMenu(hwnd, point.x, point.y); 506 } 507 return 0; 508 509 case WM_MOUSEMOVE: 510 if (!__glutMappedMenu) { 511 window = __glutGetWindow(hwnd); 512 if (window) { 513 /* If motion function registered _and_ buttons held * 514 down, call motion function... */ 515 x = LOWORD(lParam); 516 y = HIWORD(lParam); 517 518 /* Win32 doesn't return the same numbers as X does when the 519 mouse goes beyond the upper or left side of the window. 520 roll the Win32's 0..2^16 pointer co-ord range to 0..+/-2^15. */ 521 if(x & 1 << 15) x -= (1 << 16); 522 if(y & 1 << 15) y -= (1 << 16); 523 524 if (window->motion && wParam & 525 (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) { 526 __glutSetWindow(window); 527 window->motion(x, y); 528 } 529 /* If passive motion function registered _and_ 530 buttons not held down, call passive motion 531 function... */ 532 else if (window->passive && 533 ((wParam & 534 (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) == 535 0)) { 536 __glutSetWindow(window); 537 window->passive(x, y); 538 } 539 } 540 } else { 541 /* Motion events are thrown away when a pop up menu is 542 active. */ 543 } 544 return 0; 545 546 case WM_GETMINMAXINFO: 547 /* this voodoo is brought to you by Win32 (again). It allows the 548 window to be bigger than the screen, and smaller than 100x100 549 (although it doesn't seem to help the y minimum). */ 550 minmax = (LPMINMAXINFO)lParam; 551 minmax->ptMaxSize.x = __glutScreenWidth; 552 minmax->ptMaxSize.y = __glutScreenHeight; 553 minmax->ptMinTrackSize.x = 0; 554 minmax->ptMinTrackSize.y = 0; 555 minmax->ptMaxTrackSize.x = __glutScreenWidth + 556 GetSystemMetrics(SM_CXSIZE) * 2; 557 minmax->ptMaxTrackSize.y = __glutScreenHeight + 558 GetSystemMetrics(SM_CXSIZE) * 2 + GetSystemMetrics(SM_CYCAPTION); 559 return 0; 560 561 case WM_SIZE: 562 window = __glutGetWindow(hwnd); 563 if (window) { 564 width = LOWORD(lParam); 565 height = HIWORD(lParam); 566 if (width != window->width || height != window->height) { 567#if 0 /* Win32 GLUT does not support overlays for now. */ 568 if (window->overlay) { 569 XResizeWindow(__glutDisplay, window->overlay->win, width, height); 570 } 571#endif 572 window->width = width; 573 window->height = height; 574 __glutSetWindow(window); 575 /* Do not execute OpenGL out of sequence with respect 576 to the SetWindowPos request! */ 577 GdiFlush(); 578 window->reshape(width, height); 579 window->forceReshape = FALSE; 580 /* A reshape should be considered like posting a 581 repair request. */ 582 __glutPostRedisplay(window, GLUT_REPAIR_WORK); 583 } 584 } 585 return 0; 586 587 case WM_SETCURSOR: 588 /* If the cursor is not in the client area, then we want to send 589 this message to the default window procedure ('cause its 590 probably in the border or title, and we don't handle that 591 cursor. otherwise, set our cursor. Win32 makes us set the 592 cursor every time the mouse moves (DUMB!). */ 593 if(LOWORD(lParam) != HTCLIENT) { 594 goto defproc; 595 } 596 window = __glutGetWindow(hwnd); 597 if (window) { 598 __glutSetCursor(window); 599 } 600 /* TODO: check out the info in DevStudio on WM_SETCURSOR in the 601 DefaultAction section. */ 602 return 1; 603 604 case WM_SETFOCUS: 605 window = __glutGetWindow(hwnd); 606 if (window) { 607 window->entryState = WM_SETFOCUS; 608 if (window->entry) { 609 __glutSetWindow(window); 610 window->entry(GLUT_ENTERED); 611 /* XXX Generation of fake passive notify? See how much 612 work the X11 code does to support fake passive notify 613 callbacks. */ 614 } 615 if (window->joystick && __glutCurrentWindow) { 616 if (__glutCurrentWindow->joyPollInterval > 0) { 617 MMRESULT result; 618 619 /* Because Win32 will only let one window capture the 620 joystick at a time, we must capture it when we get the 621 focus and release it when we lose the focus. */ 622 result = joySetCapture(__glutCurrentWindow->win, 623 JOYSTICKID1, 0, TRUE); 624 if (result != JOYERR_NOERROR) { 625 return 0; 626 } 627 (void) joySetThreshold(JOYSTICKID1, 628 __glutCurrentWindow->joyPollInterval); 629 } 630 } 631 } 632 return 0; 633 634 case WM_KILLFOCUS: 635 window = __glutGetWindow(hwnd); 636 if (window) { 637 window->entryState = WM_KILLFOCUS; 638 if (window->entry) { 639 __glutSetWindow(window); 640 window->entry(GLUT_LEFT); 641 } 642 if (window->joystick && __glutCurrentWindow) { 643 if (__glutCurrentWindow->joyPollInterval > 0) { 644 /* Because Win32 will only let one window capture the 645 joystick at a time, we must capture it when we get the 646 focus and release it when we lose the focus. */ 647 (void) joyReleaseCapture(JOYSTICKID1); 648 } 649 } 650 } 651 return 0; 652 case WM_ACTIVATE: 653 window = __glutGetWindow(hwnd); 654 /* Make sure we re-select the correct palette if needed. */ 655 if (LOWORD(wParam)) { 656 PostMessage(hwnd, WM_PALETTECHANGED, 0, 0); 657 } 658 if (window) { 659 int visState; 660 661 /* HIWORD(wParam) is the minimized flag. */ 662 visState = !HIWORD(wParam); 663 updateWindowState(window, visState); 664 } 665 return 0; 666 667 /* Colour Palette Management */ 668 case WM_PALETTECHANGED: 669 if (hwnd == (HWND)wParam) { 670 /* Don't respond to the message that we sent! */ 671 break; 672 } 673 /* fall through to WM_QUERYNEWPALETTE */ 674 675 case WM_QUERYNEWPALETTE: 676 window = __glutGetWindow(hwnd); 677 if (window && window->colormap) { 678 UnrealizeObject(window->colormap->cmap); 679 SelectPalette(window->hdc, window->colormap->cmap, FALSE); 680 RealizePalette(window->hdc); 681 return TRUE; 682 } 683 return FALSE; 684 685 case MM_JOY1MOVE: 686 case MM_JOY1ZMOVE: 687 window = __glutGetWindow(hwnd); 688 if (window->joystick) { 689 JOYINFOEX jix; 690 int x, y, z; 691 692 /* Because WIN32 only supports messages for X, Y, and Z 693 translations, we must poll for the rest */ 694 jix.dwSize = sizeof(jix); 695 jix.dwFlags = JOY_RETURNALL; 696 joyGetPosEx(JOYSTICKID1,&jix); 697 698#define SCALE(v) ((int) ((v - 32767)/32.768)) 699 700 /* Convert to integer for scaling. */ 701 x = jix.dwXpos; 702 y = jix.dwYpos; 703 z = jix.dwZpos; 704 window->joystick(jix.dwButtons, SCALE(x), SCALE(y), SCALE(z)); 705 706 return TRUE; 707 } 708 return FALSE; 709 case MM_JOY1BUTTONDOWN: 710 case MM_JOY1BUTTONUP: 711 window = __glutGetWindow(hwnd); 712 if (window->joystick) { 713 JOYINFOEX jix; 714 715 /* Because WIN32 only supports messages for X, Y, and Z 716 translations, we must poll for the rest */ 717 jix.dwSize = sizeof(jix); 718 jix.dwFlags = JOY_RETURNALL; 719 joyGetPosEx(JOYSTICKID1,&jix); 720 721 return TRUE; 722 } 723 return FALSE; 724 725#if 0 726 /* Miscellaneous messages (don't really need to enumerate them, 727 but it's good to know what you're not getting sometimes). */ 728 case WM_DISPLAYCHANGE: 729 break; 730 case WM_NCHITTEST: 731 /* This event is generated by every mouse move event. */ 732 goto defproc; 733 case WM_NCMOUSEMOVE: 734 goto defproc; 735 case WM_NCACTIVATE: 736 goto defproc; 737 case WM_NCPAINT: 738 goto defproc; 739 case WM_NCCALCSIZE: 740 goto defproc; 741 case WM_NCCREATE: 742 goto defproc; 743 case WM_NCDESTROY: 744 goto defproc; 745 case WM_NCLBUTTONDOWN: 746 goto defproc; 747 case WM_SETTEXT: 748 goto defproc; 749 case WM_GETTEXT: 750 goto defproc; 751 case WM_ACTIVATEAPP: 752 goto defproc; 753 case WM_GETICON: 754 goto defproc; 755 case WM_ERASEBKGND: 756 goto defproc; 757 case WM_WINDOWPOSCHANGING: 758 goto defproc; 759 case WM_WINDOWPOSCHANGED: 760 goto defproc; 761 case WM_MOUSEACTIVATE: 762 goto defproc; 763 case WM_SHOWWINDOW: 764 goto defproc; 765 case WM_MOVING: 766 goto defproc; 767 case WM_MOVE: 768 goto defproc; 769 case WM_KEYUP: 770 goto defproc; 771 case WM_CAPTURECHANGED: 772 goto defproc; 773 case WM_SYSCOMMAND: 774 goto defproc; 775 case WM_ENTERSIZEMOVE: 776 goto defproc; 777 case WM_ENTERIDLE: 778 goto defproc; 779#endif 780 781 default: 782 goto defproc; 783 } 784 785defproc: 786 return DefWindowProc(hwnd, msg, wParam, lParam); 787} 788