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 (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* CAUTION!!!! If you modify this file, check ../windib/SDL_sysevents.c */ 25 26 #include "directx.h" 27 28 #include "SDL_main.h" 29 #include "SDL_events.h" 30 #include "SDL_video.h" 31 #include "SDL_syswm.h" 32 #include "../../events/SDL_sysevents.h" 33 #include "../../events/SDL_events_c.h" 34 #include "../wincommon/SDL_lowvideo.h" 35 #include "SDL_dx5video.h" 36 37 #ifndef WM_APP 38 #define WM_APP 0x8000 39 #endif 40 41 #ifdef _WIN32_WCE 42 #define NO_GETKEYBOARDSTATE 43 #endif 44 45 /* The keyboard and mouse device input */ 46 #define MAX_INPUTS 2 47 #define INPUT_QSIZE 512 /* Buffer up to 512 input messages */ 48 49 static LPDIRECTINPUT dinput = NULL; 50 static LPDIRECTINPUTDEVICE2 SDL_DIdev[MAX_INPUTS]; 51 static HANDLE SDL_DIevt[MAX_INPUTS]; 52 static void (*SDL_DIfun[MAX_INPUTS])(const int, DIDEVICEOBJECTDATA *); 53 static int SDL_DIndev = 0; 54 static int mouse_lost; 55 static int mouse_pressed; 56 static int mouse_buttons_swapped = 0; 57 58 /* The translation table from a DirectInput scancode to an SDL keysym */ 59 static SDLKey DIK_keymap[256]; 60 static SDL_keysym *TranslateKey(UINT scancode, SDL_keysym *keysym, int pressed); 61 62 /* DJM: If the user setup the window for us, we want to save his window proc, 63 and give him a chance to handle some messages. */ 64 #ifdef STRICT 65 #define WNDPROCTYPE WNDPROC 66 #else 67 #define WNDPROCTYPE FARPROC 68 #endif 69 static WNDPROCTYPE userWindowProc = NULL; 70 71 static HWND GetTopLevelParent(HWND hWnd) 72 { 73 HWND hParentWnd; 74 while (1) 75 { 76 hParentWnd = GetParent(hWnd); 77 if (hParentWnd == NULL) 78 break; 79 hWnd = hParentWnd; 80 } 81 return hWnd; 82 } 83 84 /* Convert a DirectInput return code to a text message */ 85 static void SetDIerror(char *function, int code) 86 { 87 static char *error; 88 static char errbuf[1024]; 89 90 errbuf[0] = 0; 91 switch (code) { 92 case DIERR_GENERIC: 93 error = "Undefined error!"; 94 break; 95 case DIERR_OLDDIRECTINPUTVERSION: 96 error = "Your version of DirectInput needs upgrading"; 97 break; 98 case DIERR_INVALIDPARAM: 99 error = "Invalid parameters"; 100 break; 101 case DIERR_OUTOFMEMORY: 102 error = "Out of memory"; 103 break; 104 case DIERR_DEVICENOTREG: 105 error = "Device not registered"; 106 break; 107 case DIERR_NOINTERFACE: 108 error = "Interface not supported"; 109 break; 110 case DIERR_NOTINITIALIZED: 111 error = "Device not initialized"; 112 break; 113 default: 114 SDL_snprintf(errbuf, SDL_arraysize(errbuf), 115 "%s: Unknown DirectInput error: 0x%x", 116 function, code); 117 break; 118 } 119 if ( ! errbuf[0] ) { 120 SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function, error); 121 } 122 SDL_SetError("%s", errbuf); 123 return; 124 } 125 126 /* Initialize DirectInput 127 Note: If NONEXCLUSIVE access is requested for the devices, normal 128 windows input messages will continue to be generated for that 129 input device, in addition to DirectInput messages. 130 */ 131 static void handle_keyboard(const int numevents, DIDEVICEOBJECTDATA *events); 132 static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *events); 133 struct { 134 char *name; 135 REFGUID guid; 136 LPCDIDATAFORMAT format; 137 DWORD win_level; 138 DWORD raw_level; 139 void (*fun)(const int numevents, DIDEVICEOBJECTDATA *events); 140 } inputs[] = { 141 { "keyboard", 142 &GUID_SysKeyboard, &c_dfDIKeyboard, 143 (DISCL_FOREGROUND|DISCL_NONEXCLUSIVE), 144 (DISCL_FOREGROUND|DISCL_NONEXCLUSIVE), handle_keyboard }, 145 { "mouse", 146 &GUID_SysMouse, 147 #if DIRECTINPUT_VERSION >= 0x700 148 &c_dfDIMouse2, 149 #else 150 &c_dfDIMouse, 151 #endif 152 (DISCL_BACKGROUND|DISCL_NONEXCLUSIVE), 153 (DISCL_BACKGROUND|DISCL_NONEXCLUSIVE), handle_mouse }, 154 { NULL, NULL, NULL, 0, 0, NULL } 155 }; 156 157 static int DX5_DInputInit(_THIS) 158 { 159 int i; 160 LPDIRECTINPUTDEVICE device; 161 HRESULT result; 162 DIPROPDWORD dipdw; 163 HWND topwnd; 164 165 /* Create the DirectInput object */ 166 result = DInputCreate(SDL_Instance, DIRECTINPUT_VERSION, 167 &dinput, NULL); 168 if ( result != DI_OK ) { 169 SetDIerror("DirectInputCreate", result); 170 return(-1); 171 } 172 173 /* Create all of our registered input devices */ 174 SDL_DIndev = 0; 175 for ( i=0; inputs[i].name; ++i ) { 176 /* Create the DirectInput device */ 177 result = IDirectInput_CreateDevice(dinput, inputs[i].guid, 178 &device, NULL); 179 if ( result != DI_OK ) { 180 SetDIerror("DirectInput::CreateDevice", result); 181 return(-1); 182 } 183 result = IDirectInputDevice_QueryInterface(device, 184 &IID_IDirectInputDevice2, (LPVOID *)&SDL_DIdev[i]); 185 IDirectInputDevice_Release(device); 186 if ( result != DI_OK ) { 187 SetDIerror("DirectInputDevice::QueryInterface", result); 188 return(-1); 189 } 190 topwnd = GetTopLevelParent(SDL_Window); 191 result = IDirectInputDevice2_SetCooperativeLevel(SDL_DIdev[i], 192 topwnd, inputs[i].win_level); 193 if ( result != DI_OK ) { 194 SetDIerror("DirectInputDevice::SetCooperativeLevel", 195 result); 196 return(-1); 197 } 198 result = IDirectInputDevice2_SetDataFormat(SDL_DIdev[i], 199 inputs[i].format); 200 if ( result != DI_OK ) { 201 SetDIerror("DirectInputDevice::SetDataFormat", result); 202 return(-1); 203 } 204 205 /* Set buffered input -- we aren't polling */ 206 SDL_memset(&dipdw, 0, sizeof(dipdw)); 207 dipdw.diph.dwSize = sizeof(dipdw); 208 dipdw.diph.dwHeaderSize = sizeof(dipdw.diph); 209 dipdw.diph.dwObj = 0; 210 dipdw.diph.dwHow = DIPH_DEVICE; 211 dipdw.dwData = INPUT_QSIZE; 212 result = IDirectInputDevice2_SetProperty(SDL_DIdev[i], 213 DIPROP_BUFFERSIZE, &dipdw.diph); 214 if ( result != DI_OK ) { 215 SetDIerror("DirectInputDevice::SetProperty", result); 216 return(-1); 217 } 218 219 /* Create an event to be signaled when input is ready */ 220 SDL_DIevt[i] = CreateEvent(NULL, FALSE, FALSE, NULL); 221 if ( SDL_DIevt[i] == NULL ) { 222 SDL_SetError("Couldn't create DirectInput event"); 223 return(-1); 224 } 225 result = IDirectInputDevice2_SetEventNotification(SDL_DIdev[i], 226 SDL_DIevt[i]); 227 if ( result != DI_OK ) { 228 SetDIerror("DirectInputDevice::SetEventNotification", 229 result); 230 return(-1); 231 } 232 SDL_DIfun[i] = inputs[i].fun; 233 234 /* Acquire the device for input */ 235 IDirectInputDevice2_Acquire(SDL_DIdev[i]); 236 237 /* Increment the number of devices we have */ 238 ++SDL_DIndev; 239 } 240 mouse_pressed = 0; 241 mouse_buttons_swapped = GetSystemMetrics(SM_SWAPBUTTON); 242 243 /* DirectInput is ready! */ 244 return(0); 245 } 246 247 /* Clean up DirectInput */ 248 static void DX5_DInputQuit(_THIS) 249 { 250 int i; 251 252 if ( dinput != NULL ) { 253 /* Close and release all DirectInput devices */ 254 for ( i=0; i<MAX_INPUTS; ++i ) { 255 if ( SDL_DIdev[i] != NULL ) { 256 IDirectInputDevice2_Unacquire(SDL_DIdev[i]); 257 IDirectInputDevice2_SetEventNotification( 258 SDL_DIdev[i], NULL); 259 if ( SDL_DIevt[i] != NULL ) { 260 CloseHandle(SDL_DIevt[i]); 261 SDL_DIevt[i] = NULL; 262 } 263 IDirectInputDevice2_Release(SDL_DIdev[i]); 264 SDL_DIdev[i] = NULL; 265 } 266 } 267 SDL_DIndev = 0; 268 269 /* Release DirectInput */ 270 IDirectInput_Release(dinput); 271 dinput = NULL; 272 } 273 } 274 275 /* Flag to tell SDL whether or not we queued an event */ 276 static int posted = 0; 277 278 /* Input event handler functions */ 279 static void handle_keyboard(const int numevents, DIDEVICEOBJECTDATA *keybuf) 280 { 281 int i; 282 SDL_keysym keysym; 283 284 /* Translate keyboard messages */ 285 for ( i=0; i<numevents; ++i ) { 286 if ( keybuf[i].dwData & 0x80 ) { 287 posted = SDL_PrivateKeyboard(SDL_PRESSED, 288 TranslateKey(keybuf[i].dwOfs, &keysym, 1)); 289 } else { 290 posted = SDL_PrivateKeyboard(SDL_RELEASED, 291 TranslateKey(keybuf[i].dwOfs, &keysym, 0)); 292 } 293 } 294 } 295 296 static void post_mouse_motion(int relative, Sint16 x, Sint16 y) 297 { 298 extern int mouse_relative; 299 300 if ( SDL_GetAppState() & SDL_APPMOUSEFOCUS ) { 301 posted = SDL_PrivateMouseMotion( 302 0, relative, x, y); 303 304 if ( !mouse_relative ) { 305 /* As DirectInput reads raw device coordinates, it has no notion of 306 * cursors or absolute position. We must assume responsibility for 307 * keeping track of this. */ 308 int current_x, current_y; 309 POINT cursor; 310 RECT trap; 311 RECT window; 312 int at_edge; 313 314 /* Get the current cursor position */ 315 SDL_GetMouseState(¤t_x, ¤t_y); 316 cursor.x = current_x; 317 cursor.y = current_y; 318 ClientToScreen(SDL_Window, &cursor); 319 320 /* Construct a 1 pixel square RECT that is used to confine the cursor 321 * pointer to a specific pixel using ClipCursor. This is used in 322 * preference to SetCursorPos as it avoids the cursor jumping around as 323 * both the OS and SDL attempt to move it simultaneously. */ 324 trap.left = cursor.x; 325 trap.top = cursor.y; 326 trap.right = cursor.x + 1; 327 trap.bottom = cursor.y + 1; 328 329 GetClientRect(SDL_Window, &window); 330 window.right -= window.left; window.left = 0; 331 window.bottom -= window.top; window.top = 0; 332 333 /* As we're assuming control over the cursor, we need to know when to 334 * relinquish control of it back to the operating system. This is when 335 * the cursor reaches the edge of the window. */ 336 at_edge = (current_x == window.left) || 337 (current_x == (window.right - 1)) || 338 (current_y == window.top) || 339 (current_y == (window.bottom - 1)); 340 341 if ( at_edge ) { 342 ClipCursor(NULL); 343 } else { 344 ClipCursor(&trap); 345 } 346 } else { 347 /* When in relative mode, warp the OS's idea of where the cursor is to 348 * the center of the screen. This isn't really necessary as DirectInput 349 * reads from the hardware itself, but in case things go wrong, the 350 * cursor will be left in a sensible place. */ 351 POINT center; 352 center.x = (SDL_VideoSurface->w/2); 353 center.y = (SDL_VideoSurface->h/2); 354 ClientToScreen(SDL_Window, ¢er); 355 SetCursorPos(center.x, center.y); 356 } 357 } 358 } 359 360 static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *ptrbuf) 361 { 362 int i; 363 Sint16 xrel, yrel; 364 Uint8 state; 365 Uint8 button; 366 DWORD timestamp = 0; 367 368 /* Sanity check. Mailing list reports this being NULL unexpectedly. */ 369 if (SDL_PublicSurface == NULL) { 370 return; 371 } 372 373 /* If mouse focus has been lost, make sure we release the cursor. */ 374 if ( !(SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) { 375 mouse_lost = 1; 376 ClipCursor(NULL); 377 } else { 378 /* If the mouse was lost, regain some sense of mouse state */ 379 if ( mouse_lost ) { 380 POINT mouse_pos; 381 Uint8 old_state; 382 Uint8 new_state; 383 384 /* Set ourselves up with the current cursor position */ 385 GetCursorPos(&mouse_pos); 386 ScreenToClient(SDL_Window, &mouse_pos); 387 post_mouse_motion( 0, (Sint16)mouse_pos.x, (Sint16)mouse_pos.y); 388 389 /* Check for mouse button changes */ 390 old_state = SDL_GetMouseState(NULL, NULL); 391 new_state = 0; 392 { /* Get the new DirectInput button state for the mouse */ 393 #if DIRECTINPUT_VERSION >= 0x700 394 DIMOUSESTATE2 distate; 395 #else 396 DIMOUSESTATE distate; 397 #endif 398 HRESULT result; 399 400 result=IDirectInputDevice2_GetDeviceState(SDL_DIdev[1], 401 sizeof(distate), &distate); 402 if ( result != DI_OK ) { 403 /* Try again next time */ 404 SetDIerror( 405 "IDirectInputDevice2::GetDeviceState", result); 406 return; 407 } 408 for ( i=3; i>=0; --i ) { 409 if ( (distate.rgbButtons[i]&0x80) == 0x80 ) { 410 new_state |= 0x01; 411 } 412 new_state <<= 1; 413 } 414 } 415 for ( i=0; i<8; ++i ) { 416 if ( (old_state&0x01) != (new_state&0x01) ) { 417 button = (Uint8)(i+1); 418 /* Map DI button numbers to SDL */ 419 switch ( button ) { 420 case 2: button = SDL_BUTTON_RIGHT; break; 421 case 3: button = SDL_BUTTON_MIDDLE; break; 422 case 4: button = SDL_BUTTON_X1; break; 423 case 5: button = SDL_BUTTON_X2; break; 424 default: break; 425 } 426 if ( new_state & 0x01 ) { 427 /* Grab mouse so we get mouse-up */ 428 if ( ++mouse_pressed > 0 ) { 429 SetCapture(SDL_Window); 430 } 431 state = SDL_PRESSED; 432 } else { 433 /* Release mouse after all mouse-ups */ 434 if ( --mouse_pressed <= 0 ) { 435 ReleaseCapture(); 436 mouse_pressed = 0; 437 } 438 state = SDL_RELEASED; 439 } 440 if ( mouse_buttons_swapped ) { 441 if ( button == 1 ) button = 3; 442 else 443 if ( button == 3 ) button = 1; 444 } 445 posted = SDL_PrivateMouseButton(state, button, 446 0, 0); 447 } 448 old_state >>= 1; 449 new_state >>= 1; 450 } 451 mouse_lost = 0; 452 return; 453 } 454 455 /* Translate mouse messages */ 456 xrel = 0; 457 yrel = 0; 458 for ( i=0; i<(int)numevents; ++i ) { 459 switch (ptrbuf[i].dwOfs) { 460 case DIMOFS_X: 461 if ( timestamp != ptrbuf[i].dwTimeStamp ) { 462 if ( xrel || yrel ) { 463 post_mouse_motion(1, xrel, yrel); 464 xrel = 0; 465 yrel = 0; 466 } 467 timestamp = ptrbuf[i].dwTimeStamp; 468 } 469 xrel += (Sint16)ptrbuf[i].dwData; 470 break; 471 case DIMOFS_Y: 472 if ( timestamp != ptrbuf[i].dwTimeStamp ) { 473 if ( xrel || yrel ) { 474 post_mouse_motion(1, xrel, yrel); 475 xrel = 0; 476 yrel = 0; 477 } 478 timestamp = ptrbuf[i].dwTimeStamp; 479 } 480 yrel += (Sint16)ptrbuf[i].dwData; 481 break; 482 case DIMOFS_Z: 483 if ( xrel || yrel ) { 484 post_mouse_motion(1, xrel, yrel); 485 xrel = 0; 486 yrel = 0; 487 } 488 timestamp = 0; 489 if((int)ptrbuf[i].dwData > 0) 490 button = SDL_BUTTON_WHEELUP; 491 else 492 button = SDL_BUTTON_WHEELDOWN; 493 posted = SDL_PrivateMouseButton( 494 SDL_PRESSED, button, 0, 0); 495 posted |= SDL_PrivateMouseButton( 496 SDL_RELEASED, button, 0, 0); 497 break; 498 case DIMOFS_BUTTON0: 499 case DIMOFS_BUTTON1: 500 case DIMOFS_BUTTON2: 501 case DIMOFS_BUTTON3: 502 #if DIRECTINPUT_VERSION >= 0x700 503 case DIMOFS_BUTTON4: 504 case DIMOFS_BUTTON5: 505 case DIMOFS_BUTTON6: 506 case DIMOFS_BUTTON7: 507 #endif 508 if ( xrel || yrel ) { 509 post_mouse_motion(1, xrel, yrel); 510 xrel = 0; 511 yrel = 0; 512 } 513 timestamp = 0; 514 button = (Uint8)(ptrbuf[i].dwOfs-DIMOFS_BUTTON0)+1; 515 /* Map DI button numbers to SDL */ 516 switch ( button ) { 517 case 2: button = SDL_BUTTON_RIGHT; break; 518 case 3: button = SDL_BUTTON_MIDDLE; break; 519 case 4: button = SDL_BUTTON_X1; break; 520 case 5: button = SDL_BUTTON_X2; break; 521 default: break; 522 } 523 if ( ptrbuf[i].dwData & 0x80 ) { 524 /* Grab mouse so we get mouse-up */ 525 if ( ++mouse_pressed > 0 ) { 526 SetCapture(SDL_Window); 527 } 528 state = SDL_PRESSED; 529 } else { 530 /* Release mouse after all mouse-ups */ 531 if ( --mouse_pressed <= 0 ) { 532 ReleaseCapture(); 533 mouse_pressed = 0; 534 } 535 state = SDL_RELEASED; 536 } 537 if ( mouse_buttons_swapped ) { 538 if ( button == 1 ) button = 3; 539 else 540 if ( button == 3 ) button = 1; 541 } 542 posted = SDL_PrivateMouseButton(state, button, 543 0, 0); 544 break; 545 } 546 } 547 if ( xrel || yrel ) { 548 post_mouse_motion(1, xrel, yrel); 549 } 550 } 551 } 552 553 /* The main Win32 event handler */ 554 LRESULT DX5_HandleMessage(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 555 { 556 switch (msg) { 557 #ifdef WM_ACTIVATEAPP 558 case WM_ACTIVATEAPP: { 559 int i, active; 560 561 active = (wParam && (GetForegroundWindow() == hwnd)); 562 if ( active ) { 563 for ( i=0; i<MAX_INPUTS; ++i ) { 564 if (SDL_DIdev[i] != NULL) 565 IDirectInputDevice2_Acquire( 566 SDL_DIdev[i]); 567 } 568 } else { 569 for ( i=0; i<MAX_INPUTS; ++i ) { 570 if (SDL_DIdev[i] != NULL) 571 IDirectInputDevice2_Unacquire( 572 SDL_DIdev[i]); 573 } 574 mouse_lost = 1; 575 } 576 } 577 break; 578 #endif /* WM_ACTIVATEAPP */ 579 580 #ifdef WM_DISPLAYCHANGE 581 case WM_DISPLAYCHANGE: { 582 WPARAM BitsPerPixel; 583 WORD SizeX, SizeY; 584 585 /* Ack! The display changed size and/or depth! */ 586 SizeX = LOWORD(lParam); 587 SizeY = HIWORD(lParam); 588 BitsPerPixel = wParam; 589 /* We cause this message when we go fullscreen */ 590 } 591 break; 592 #endif /* WM_DISPLAYCHANGE */ 593 594 /* The keyboard is handled via DirectInput */ 595 case WM_SYSKEYUP: 596 case WM_SYSKEYDOWN: 597 case WM_KEYUP: 598 case WM_KEYDOWN: { 599 /* Ignore windows keyboard messages */; 600 } 601 return(0); 602 603 #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER) 604 /* Don't allow screen savers or monitor power downs. 605 This is because they quietly clear DirectX surfaces. 606 It would be better to allow the application to 607 decide whether or not to blow these off, but the 608 semantics of SDL_PrivateSysWMEvent() don't allow 609 the application that choice. 610 */ 611 case WM_SYSCOMMAND: { 612 if ((wParam&0xFFF0)==SC_SCREENSAVE || 613 (wParam&0xFFF0)==SC_MONITORPOWER) 614 return(0); 615 } 616 /* Fall through to default processing */ 617 618 #endif /* SC_SCREENSAVE || SC_MONITORPOWER */ 619 620 default: { 621 /* Only post the event if we're watching for it */ 622 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) { 623 SDL_SysWMmsg wmmsg; 624 625 SDL_VERSION(&wmmsg.version); 626 wmmsg.hwnd = hwnd; 627 wmmsg.msg = msg; 628 wmmsg.wParam = wParam; 629 wmmsg.lParam = lParam; 630 posted = SDL_PrivateSysWMEvent(&wmmsg); 631 632 /* DJM: If the user isn't watching for private 633 messages in her SDL event loop, then pass it 634 along to any win32 specific window proc. 635 */ 636 } else if (userWindowProc) { 637 return CallWindowProc(userWindowProc, hwnd, msg, wParam, lParam); 638 } 639 } 640 break; 641 } 642 return(DefWindowProc(hwnd, msg, wParam, lParam)); 643 } 644 645 /* This function checks the windows message queue and DirectInput and returns 646 1 if there was input, 0 if there was no input, or -1 if the application has 647 posted a quit message. 648 */ 649 static int DX5_CheckInput(_THIS, int timeout, BOOL processInput) 650 { 651 MSG msg; 652 int i; 653 HRESULT result; 654 DWORD event; 655 656 /* Check the normal windows queue (highest preference) */ 657 posted = 0; 658 while ( ! posted && 659 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) { 660 if ( GetMessage(&msg, NULL, 0, 0) > 0 ) { 661 DispatchMessage(&msg); 662 } else { 663 return(-1); 664 } 665 } 666 if ( posted ) { 667 return(1); 668 } 669 670 /* Pump the DirectInput flow */ 671 if ( SDL_GetAppState() & SDL_APPMOUSEFOCUS ) { 672 for ( i=0; i<MAX_INPUTS; ++i ) { 673 if ( SDL_DIdev[i] != NULL ) { 674 result = IDirectInputDevice2_Poll(SDL_DIdev[i]); 675 if ( (result == DIERR_INPUTLOST) || 676 (result == DIERR_NOTACQUIRED) ) { 677 if ( SDL_strcmp(inputs[i].name, "mouse") == 0 ) { 678 mouse_lost = 1; 679 } 680 IDirectInputDevice2_Acquire(SDL_DIdev[i]); 681 IDirectInputDevice2_Poll(SDL_DIdev[i]); 682 } 683 } 684 } 685 } 686 687 /* Wait for messages and input events */ 688 event = MsgWaitForMultipleObjects(SDL_DIndev, SDL_DIevt, FALSE, 689 timeout, QS_ALLEVENTS); 690 if ((event >= WAIT_OBJECT_0) && (event < (WAIT_OBJECT_0+SDL_DIndev))) { 691 DWORD numevents; 692 static DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE]; 693 694 event -= WAIT_OBJECT_0; 695 numevents = INPUT_QSIZE; 696 result = IDirectInputDevice2_GetDeviceData( 697 SDL_DIdev[event], sizeof(DIDEVICEOBJECTDATA), 698 evtbuf, &numevents, 0); 699 if ( (result == DIERR_INPUTLOST) || 700 (result == DIERR_NOTACQUIRED) ) { 701 if ( SDL_strcmp(inputs[event].name, "mouse") == 0 ) { 702 mouse_lost = 1; 703 } 704 IDirectInputDevice2_Acquire(SDL_DIdev[event]); 705 result = IDirectInputDevice2_GetDeviceData( 706 SDL_DIdev[event], sizeof(DIDEVICEOBJECTDATA), 707 evtbuf, &numevents, 0); 708 } 709 /* Handle the events */ 710 if ( result == DI_OK && processInput ) { 711 /* Note: This can post multiple events to event queue 712 */ 713 (*SDL_DIfun[event])((int)numevents, evtbuf); 714 return(1); 715 } 716 } 717 if ( event != WAIT_TIMEOUT ) { 718 /* Maybe there was a windows message? */ 719 if ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) { 720 if ( GetMessage(&msg, NULL, 0, 0) > 0 ) { 721 DispatchMessage(&msg); 722 } else { 723 return(-1); 724 } 725 return(1); 726 } 727 } 728 return(0); 729 } 730 731 /* Change cooperative level based on whether or not we are fullscreen */ 732 void DX5_DInputReset(_THIS, int fullscreen) 733 { 734 DWORD level; 735 int i; 736 HRESULT result; 737 HWND topwnd; 738 739 for ( i=0; i<MAX_INPUTS; ++i ) { 740 if ( SDL_DIdev[i] != NULL ) { 741 if ( fullscreen ) { 742 level = inputs[i].raw_level; 743 } else { 744 level = inputs[i].win_level; 745 } 746 IDirectInputDevice2_Unacquire(SDL_DIdev[i]); 747 topwnd = GetTopLevelParent(SDL_Window); 748 result = IDirectInputDevice2_SetCooperativeLevel( 749 SDL_DIdev[i], topwnd, level); 750 IDirectInputDevice2_Acquire(SDL_DIdev[i]); 751 if ( result != DI_OK ) { 752 SetDIerror( 753 "DirectInputDevice::SetCooperativeLevel", result); 754 } 755 } 756 } 757 mouse_lost = 1; 758 759 /* Flush pending input */ 760 DX5_CheckInput(this, 0, FALSE); 761 } 762 763 void DX5_PumpEvents(_THIS) 764 { 765 /* Wait for messages and DirectInput */ 766 while ( DX5_CheckInput(this, 0, TRUE) > 0 ) { 767 /* Loop and check again */; 768 } 769 } 770 771 void DX5_InitOSKeymap(_THIS) 772 { 773 #ifndef DIK_PAUSE 774 #define DIK_PAUSE 0xC5 775 #endif 776 #ifndef DIK_OEM_102 777 #define DIK_OEM_102 0x56 /* < > | on UK/Germany keyboards */ 778 #endif 779 int i; 780 781 /* Map the DIK scancodes to SDL keysyms */ 782 for ( i=0; i<SDL_arraysize(DIK_keymap); ++i ) 783 DIK_keymap[i] = 0; 784 785 /* Defined DIK_* constants */ 786 DIK_keymap[DIK_ESCAPE] = SDLK_ESCAPE; 787 DIK_keymap[DIK_1] = SDLK_1; 788 DIK_keymap[DIK_2] = SDLK_2; 789 DIK_keymap[DIK_3] = SDLK_3; 790 DIK_keymap[DIK_4] = SDLK_4; 791 DIK_keymap[DIK_5] = SDLK_5; 792 DIK_keymap[DIK_6] = SDLK_6; 793 DIK_keymap[DIK_7] = SDLK_7; 794 DIK_keymap[DIK_8] = SDLK_8; 795 DIK_keymap[DIK_9] = SDLK_9; 796 DIK_keymap[DIK_0] = SDLK_0; 797 DIK_keymap[DIK_MINUS] = SDLK_MINUS; 798 DIK_keymap[DIK_EQUALS] = SDLK_EQUALS; 799 DIK_keymap[DIK_BACK] = SDLK_BACKSPACE; 800 DIK_keymap[DIK_TAB] = SDLK_TAB; 801 DIK_keymap[DIK_Q] = SDLK_q; 802 DIK_keymap[DIK_W] = SDLK_w; 803 DIK_keymap[DIK_E] = SDLK_e; 804 DIK_keymap[DIK_R] = SDLK_r; 805 DIK_keymap[DIK_T] = SDLK_t; 806 DIK_keymap[DIK_Y] = SDLK_y; 807 DIK_keymap[DIK_U] = SDLK_u; 808 DIK_keymap[DIK_I] = SDLK_i; 809 DIK_keymap[DIK_O] = SDLK_o; 810 DIK_keymap[DIK_P] = SDLK_p; 811 DIK_keymap[DIK_LBRACKET] = SDLK_LEFTBRACKET; 812 DIK_keymap[DIK_RBRACKET] = SDLK_RIGHTBRACKET; 813 DIK_keymap[DIK_RETURN] = SDLK_RETURN; 814 DIK_keymap[DIK_LCONTROL] = SDLK_LCTRL; 815 DIK_keymap[DIK_A] = SDLK_a; 816 DIK_keymap[DIK_S] = SDLK_s; 817 DIK_keymap[DIK_D] = SDLK_d; 818 DIK_keymap[DIK_F] = SDLK_f; 819 DIK_keymap[DIK_G] = SDLK_g; 820 DIK_keymap[DIK_H] = SDLK_h; 821 DIK_keymap[DIK_J] = SDLK_j; 822 DIK_keymap[DIK_K] = SDLK_k; 823 DIK_keymap[DIK_L] = SDLK_l; 824 DIK_keymap[DIK_SEMICOLON] = SDLK_SEMICOLON; 825 DIK_keymap[DIK_APOSTROPHE] = SDLK_QUOTE; 826 DIK_keymap[DIK_GRAVE] = SDLK_BACKQUOTE; 827 DIK_keymap[DIK_LSHIFT] = SDLK_LSHIFT; 828 DIK_keymap[DIK_BACKSLASH] = SDLK_BACKSLASH; 829 DIK_keymap[DIK_OEM_102] = SDLK_LESS; 830 DIK_keymap[DIK_Z] = SDLK_z; 831 DIK_keymap[DIK_X] = SDLK_x; 832 DIK_keymap[DIK_C] = SDLK_c; 833 DIK_keymap[DIK_V] = SDLK_v; 834 DIK_keymap[DIK_B] = SDLK_b; 835 DIK_keymap[DIK_N] = SDLK_n; 836 DIK_keymap[DIK_M] = SDLK_m; 837 DIK_keymap[DIK_COMMA] = SDLK_COMMA; 838 DIK_keymap[DIK_PERIOD] = SDLK_PERIOD; 839 DIK_keymap[DIK_SLASH] = SDLK_SLASH; 840 DIK_keymap[DIK_RSHIFT] = SDLK_RSHIFT; 841 DIK_keymap[DIK_MULTIPLY] = SDLK_KP_MULTIPLY; 842 DIK_keymap[DIK_LMENU] = SDLK_LALT; 843 DIK_keymap[DIK_SPACE] = SDLK_SPACE; 844 DIK_keymap[DIK_CAPITAL] = SDLK_CAPSLOCK; 845 DIK_keymap[DIK_F1] = SDLK_F1; 846 DIK_keymap[DIK_F2] = SDLK_F2; 847 DIK_keymap[DIK_F3] = SDLK_F3; 848 DIK_keymap[DIK_F4] = SDLK_F4; 849 DIK_keymap[DIK_F5] = SDLK_F5; 850 DIK_keymap[DIK_F6] = SDLK_F6; 851 DIK_keymap[DIK_F7] = SDLK_F7; 852 DIK_keymap[DIK_F8] = SDLK_F8; 853 DIK_keymap[DIK_F9] = SDLK_F9; 854 DIK_keymap[DIK_F10] = SDLK_F10; 855 DIK_keymap[DIK_NUMLOCK] = SDLK_NUMLOCK; 856 DIK_keymap[DIK_SCROLL] = SDLK_SCROLLOCK; 857 DIK_keymap[DIK_NUMPAD7] = SDLK_KP7; 858 DIK_keymap[DIK_NUMPAD8] = SDLK_KP8; 859 DIK_keymap[DIK_NUMPAD9] = SDLK_KP9; 860 DIK_keymap[DIK_SUBTRACT] = SDLK_KP_MINUS; 861 DIK_keymap[DIK_NUMPAD4] = SDLK_KP4; 862 DIK_keymap[DIK_NUMPAD5] = SDLK_KP5; 863 DIK_keymap[DIK_NUMPAD6] = SDLK_KP6; 864 DIK_keymap[DIK_ADD] = SDLK_KP_PLUS; 865 DIK_keymap[DIK_NUMPAD1] = SDLK_KP1; 866 DIK_keymap[DIK_NUMPAD2] = SDLK_KP2; 867 DIK_keymap[DIK_NUMPAD3] = SDLK_KP3; 868 DIK_keymap[DIK_NUMPAD0] = SDLK_KP0; 869 DIK_keymap[DIK_DECIMAL] = SDLK_KP_PERIOD; 870 DIK_keymap[DIK_F11] = SDLK_F11; 871 DIK_keymap[DIK_F12] = SDLK_F12; 872 873 DIK_keymap[DIK_F13] = SDLK_F13; 874 DIK_keymap[DIK_F14] = SDLK_F14; 875 DIK_keymap[DIK_F15] = SDLK_F15; 876 877 DIK_keymap[DIK_NUMPADEQUALS] = SDLK_KP_EQUALS; 878 DIK_keymap[DIK_NUMPADENTER] = SDLK_KP_ENTER; 879 DIK_keymap[DIK_RCONTROL] = SDLK_RCTRL; 880 DIK_keymap[DIK_DIVIDE] = SDLK_KP_DIVIDE; 881 DIK_keymap[DIK_SYSRQ] = SDLK_PRINT; 882 DIK_keymap[DIK_RMENU] = SDLK_RALT; 883 DIK_keymap[DIK_PAUSE] = SDLK_PAUSE; 884 DIK_keymap[DIK_HOME] = SDLK_HOME; 885 DIK_keymap[DIK_UP] = SDLK_UP; 886 DIK_keymap[DIK_PRIOR] = SDLK_PAGEUP; 887 DIK_keymap[DIK_LEFT] = SDLK_LEFT; 888 DIK_keymap[DIK_RIGHT] = SDLK_RIGHT; 889 DIK_keymap[DIK_END] = SDLK_END; 890 DIK_keymap[DIK_DOWN] = SDLK_DOWN; 891 DIK_keymap[DIK_NEXT] = SDLK_PAGEDOWN; 892 DIK_keymap[DIK_INSERT] = SDLK_INSERT; 893 DIK_keymap[DIK_DELETE] = SDLK_DELETE; 894 DIK_keymap[DIK_LWIN] = SDLK_LMETA; 895 DIK_keymap[DIK_RWIN] = SDLK_RMETA; 896 DIK_keymap[DIK_APPS] = SDLK_MENU; 897 } 898 899 static SDL_keysym *TranslateKey(UINT scancode, SDL_keysym *keysym, int pressed) 900 { 901 /* Set the keysym information */ 902 keysym->scancode = (unsigned char)scancode; 903 keysym->sym = DIK_keymap[scancode]; 904 keysym->mod = KMOD_NONE; 905 keysym->unicode = 0; 906 if ( pressed && SDL_TranslateUNICODE ) { 907 UINT vkey; 908 #ifndef NO_GETKEYBOARDSTATE 909 BYTE keystate[256]; 910 Uint16 wchars[2]; 911 #endif 912 913 vkey = MapVirtualKey(scancode, 1); 914 #ifdef NO_GETKEYBOARDSTATE 915 /* Uh oh, better hope the vkey is close enough.. */ 916 keysym->unicode = vkey; 917 #else 918 GetKeyboardState(keystate); 919 /* Numlock isn't taken into account in ToUnicode, 920 * so we handle it as a special case here */ 921 if ((keystate[VK_NUMLOCK] & 1) && vkey >= VK_NUMPAD0 && vkey <= VK_NUMPAD9) 922 { 923 keysym->unicode = vkey - VK_NUMPAD0 + '0'; 924 } 925 else if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) > 0) 926 { 927 keysym->unicode = wchars[0]; 928 } 929 #endif /* NO_GETKEYBOARDSTATE */ 930 } 931 return(keysym); 932 } 933 934 int DX5_CreateWindow(_THIS) 935 { 936 char *windowid = SDL_getenv("SDL_WINDOWID"); 937 int i; 938 939 /* Clear out DirectInput variables in case we fail */ 940 for ( i=0; i<MAX_INPUTS; ++i ) { 941 SDL_DIdev[i] = NULL; 942 SDL_DIevt[i] = NULL; 943 SDL_DIfun[i] = NULL; 944 } 945 946 SDL_RegisterApp(NULL, 0, 0); 947 948 SDL_windowid = (windowid != NULL); 949 if ( SDL_windowid ) { 950 SDL_Window = (HWND)((size_t)SDL_strtoull(windowid, NULL, 0)); 951 if ( SDL_Window == NULL ) { 952 SDL_SetError("Couldn't get user specified window"); 953 return(-1); 954 } 955 956 /* DJM: we want all event's for the user specified 957 window to be handled by SDL. 958 */ 959 userWindowProc = (WNDPROCTYPE)GetWindowLongPtr(SDL_Window, GWLP_WNDPROC); 960 SetWindowLongPtr(SDL_Window, GWLP_WNDPROC, (LONG_PTR)WinMessage); 961 } else { 962 SDL_Window = CreateWindow(SDL_Appname, SDL_Appname, 963 (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX), 964 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, SDL_Instance, NULL); 965 if ( SDL_Window == NULL ) { 966 SDL_SetError("Couldn't create window"); 967 return(-1); 968 } 969 ShowWindow(SDL_Window, SW_HIDE); 970 } 971 972 /* Initialize DirectInput */ 973 if ( DX5_DInputInit(this) < 0 ) { 974 return(-1); 975 } 976 977 /* JC 14 Mar 2006 978 Flush the message loop or this can cause big problems later 979 Especially if the user decides to use dialog boxes or assert()! 980 */ 981 WIN_FlushMessageQueue(); 982 983 /* Ready to roll */ 984 return(0); 985 } 986 987 void DX5_DestroyWindow(_THIS) 988 { 989 /* Close down DirectInput */ 990 DX5_DInputQuit(this); 991 992 /* Destroy our window */ 993 if ( SDL_windowid ) { 994 SetWindowLongPtr(SDL_Window, GWLP_WNDPROC, (LONG_PTR)userWindowProc); 995 } else { 996 DestroyWindow(SDL_Window); 997 } 998 SDL_UnregisterApp(); 999 1000 /* JC 14 Mar 2006 1001 Flush the message loop or this can cause big problems later 1002 Especially if the user decides to use dialog boxes or assert()! 1003 */ 1004 WIN_FlushMessageQueue(); 1005 } 1006