1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@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 16 /* Maximum of 16-1 input devices */
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
GetTopLevelParent(HWND hWnd)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 */
SetDIerror(char * function,int code)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, &c_dfDIMouse,
147 (DISCL_FOREGROUND|DISCL_NONEXCLUSIVE),
148 (DISCL_FOREGROUND|DISCL_EXCLUSIVE), handle_mouse },
149 { NULL, NULL, NULL, 0, 0, NULL }
150 };
151
DX5_DInputInit(_THIS)152 static int DX5_DInputInit(_THIS)
153 {
154 int i;
155 LPDIRECTINPUTDEVICE device;
156 HRESULT result;
157 DIPROPDWORD dipdw;
158 HWND topwnd;
159
160 /* Create the DirectInput object */
161 result = DInputCreate(SDL_Instance, DIRECTINPUT_VERSION,
162 &dinput, NULL);
163 if ( result != DI_OK ) {
164 SetDIerror("DirectInputCreate", result);
165 return(-1);
166 }
167
168 /* Create all of our registered input devices */
169 SDL_DIndev = 0;
170 for ( i=0; inputs[i].name; ++i ) {
171 /* Create the DirectInput device */
172 result = IDirectInput_CreateDevice(dinput, inputs[i].guid,
173 &device, NULL);
174 if ( result != DI_OK ) {
175 SetDIerror("DirectInput::CreateDevice", result);
176 return(-1);
177 }
178 result = IDirectInputDevice_QueryInterface(device,
179 &IID_IDirectInputDevice2, (LPVOID *)&SDL_DIdev[i]);
180 IDirectInputDevice_Release(device);
181 if ( result != DI_OK ) {
182 SetDIerror("DirectInputDevice::QueryInterface", result);
183 return(-1);
184 }
185 topwnd = GetTopLevelParent(SDL_Window);
186 result = IDirectInputDevice2_SetCooperativeLevel(SDL_DIdev[i],
187 topwnd, inputs[i].win_level);
188 if ( result != DI_OK ) {
189 SetDIerror("DirectInputDevice::SetCooperativeLevel",
190 result);
191 return(-1);
192 }
193 result = IDirectInputDevice2_SetDataFormat(SDL_DIdev[i],
194 inputs[i].format);
195 if ( result != DI_OK ) {
196 SetDIerror("DirectInputDevice::SetDataFormat", result);
197 return(-1);
198 }
199
200 /* Set buffered input -- we aren't polling */
201 SDL_memset(&dipdw, 0, sizeof(dipdw));
202 dipdw.diph.dwSize = sizeof(dipdw);
203 dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
204 dipdw.diph.dwObj = 0;
205 dipdw.diph.dwHow = DIPH_DEVICE;
206 dipdw.dwData = INPUT_QSIZE;
207 result = IDirectInputDevice2_SetProperty(SDL_DIdev[i],
208 DIPROP_BUFFERSIZE, &dipdw.diph);
209 if ( result != DI_OK ) {
210 SetDIerror("DirectInputDevice::SetProperty", result);
211 return(-1);
212 }
213
214 /* Create an event to be signaled when input is ready */
215 SDL_DIevt[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
216 if ( SDL_DIevt[i] == NULL ) {
217 SDL_SetError("Couldn't create DirectInput event");
218 return(-1);
219 }
220 result = IDirectInputDevice2_SetEventNotification(SDL_DIdev[i],
221 SDL_DIevt[i]);
222 if ( result != DI_OK ) {
223 SetDIerror("DirectInputDevice::SetEventNotification",
224 result);
225 return(-1);
226 }
227 SDL_DIfun[i] = inputs[i].fun;
228
229 /* Acquire the device for input */
230 IDirectInputDevice2_Acquire(SDL_DIdev[i]);
231
232 /* Increment the number of devices we have */
233 ++SDL_DIndev;
234 }
235 mouse_pressed = 0;
236 mouse_buttons_swapped = GetSystemMetrics(SM_SWAPBUTTON);
237
238 /* DirectInput is ready! */
239 return(0);
240 }
241
242 /* Clean up DirectInput */
DX5_DInputQuit(_THIS)243 static void DX5_DInputQuit(_THIS)
244 {
245 int i;
246
247 if ( dinput != NULL ) {
248 /* Close and release all DirectInput devices */
249 for ( i=0; i<MAX_INPUTS; ++i ) {
250 if ( SDL_DIdev[i] != NULL ) {
251 IDirectInputDevice2_Unacquire(SDL_DIdev[i]);
252 IDirectInputDevice2_SetEventNotification(
253 SDL_DIdev[i], NULL);
254 if ( SDL_DIevt[i] != NULL ) {
255 CloseHandle(SDL_DIevt[i]);
256 SDL_DIevt[i] = NULL;
257 }
258 IDirectInputDevice2_Release(SDL_DIdev[i]);
259 SDL_DIdev[i] = NULL;
260 }
261 }
262 /* Release DirectInput */
263 IDirectInput_Release(dinput);
264 dinput = NULL;
265 }
266 }
267
268 /* Flag to tell SDL whether or not we queued an event */
269 static int posted = 0;
270
271 /* Input event handler functions */
handle_keyboard(const int numevents,DIDEVICEOBJECTDATA * keybuf)272 static void handle_keyboard(const int numevents, DIDEVICEOBJECTDATA *keybuf)
273 {
274 int i;
275 SDL_keysym keysym;
276
277 /* Translate keyboard messages */
278 for ( i=0; i<numevents; ++i ) {
279 if ( keybuf[i].dwData & 0x80 ) {
280 posted = SDL_PrivateKeyboard(SDL_PRESSED,
281 TranslateKey(keybuf[i].dwOfs, &keysym, 1));
282 } else {
283 posted = SDL_PrivateKeyboard(SDL_RELEASED,
284 TranslateKey(keybuf[i].dwOfs, &keysym, 0));
285 }
286 }
287 }
handle_mouse(const int numevents,DIDEVICEOBJECTDATA * ptrbuf)288 static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *ptrbuf)
289 {
290 int i;
291 Sint16 xrel, yrel;
292 Uint8 state;
293 Uint8 button;
294 DWORD timestamp = 0;
295
296 /* Sanity check. Mailing list reports this being NULL unexpectedly. */
297 if (SDL_PublicSurface == NULL) {
298 return;
299 }
300
301 /* If we are in windowed mode, Windows is taking care of the mouse */
302 if ( (SDL_PublicSurface->flags & SDL_OPENGL) ||
303 !(SDL_PublicSurface->flags & SDL_FULLSCREEN) ) {
304 return;
305 }
306
307 /* If the mouse was lost, regain some sense of mouse state */
308 if ( mouse_lost ) {
309 POINT mouse_pos;
310 Uint8 old_state;
311 Uint8 new_state;
312
313 /* Set ourselves up with the current cursor position */
314 GetCursorPos(&mouse_pos);
315 ScreenToClient(SDL_Window, &mouse_pos);
316 posted = SDL_PrivateMouseMotion(0, 0,
317 (Sint16)mouse_pos.x, (Sint16)mouse_pos.y);
318
319 /* Check for mouse button changes */
320 old_state = SDL_GetMouseState(NULL, NULL);
321 new_state = 0;
322 { /* Get the new DirectInput button state for the mouse */
323 DIMOUSESTATE distate;
324 HRESULT result;
325
326 result=IDirectInputDevice2_GetDeviceState(SDL_DIdev[1],
327 sizeof(distate), &distate);
328 if ( result != DI_OK ) {
329 /* Try again next time */
330 SetDIerror(
331 "IDirectInputDevice2::GetDeviceState", result);
332 return;
333 }
334 for ( i=3; i>=0; --i ) {
335 if ( (distate.rgbButtons[i]&0x80) == 0x80 ) {
336 new_state |= 0x01;
337 }
338 new_state <<= 1;
339 }
340 }
341 for ( i=0; i<8; ++i ) {
342 if ( (old_state&0x01) != (new_state&0x01) ) {
343 button = (Uint8)(i+1);
344 /* Button #2 on two button mice is button 3
345 (the middle button is button 2)
346 */
347 if ( button == 2 ) {
348 button = 3;
349 } else
350 if ( button == 3 ) {
351 button = 2;
352 }
353 if ( new_state & 0x01 ) {
354 /* Grab mouse so we get mouse-up */
355 if ( ++mouse_pressed > 0 ) {
356 SetCapture(SDL_Window);
357 }
358 state = SDL_PRESSED;
359 } else {
360 /* Release mouse after all mouse-ups */
361 if ( --mouse_pressed <= 0 ) {
362 ReleaseCapture();
363 mouse_pressed = 0;
364 }
365 state = SDL_RELEASED;
366 }
367 if ( mouse_buttons_swapped ) {
368 if ( button == 1 ) button = 3;
369 else
370 if ( button == 3 ) button = 1;
371 }
372 posted = SDL_PrivateMouseButton(state, button,
373 0, 0);
374 }
375 old_state >>= 1;
376 new_state >>= 1;
377 }
378 mouse_lost = 0;
379 return;
380 }
381
382 /* Translate mouse messages */
383 xrel = 0;
384 yrel = 0;
385 for ( i=0; i<(int)numevents; ++i ) {
386 switch (ptrbuf[i].dwOfs) {
387 case DIMOFS_X:
388 if ( timestamp != ptrbuf[i].dwTimeStamp ) {
389 if ( xrel || yrel ) {
390 posted = SDL_PrivateMouseMotion(
391 0, 1, xrel, yrel);
392 xrel = 0;
393 yrel = 0;
394 }
395 timestamp = ptrbuf[i].dwTimeStamp;
396 }
397 xrel += (Sint16)ptrbuf[i].dwData;
398 break;
399 case DIMOFS_Y:
400 if ( timestamp != ptrbuf[i].dwTimeStamp ) {
401 if ( xrel || yrel ) {
402 posted = SDL_PrivateMouseMotion(
403 0, 1, xrel, yrel);
404 xrel = 0;
405 yrel = 0;
406 }
407 timestamp = ptrbuf[i].dwTimeStamp;
408 }
409 yrel += (Sint16)ptrbuf[i].dwData;
410 break;
411 case DIMOFS_Z:
412 if ( xrel || yrel ) {
413 posted = SDL_PrivateMouseMotion(
414 0, 1, xrel, yrel);
415 xrel = 0;
416 yrel = 0;
417 }
418 timestamp = 0;
419 if((int)ptrbuf[i].dwData > 0)
420 button = SDL_BUTTON_WHEELUP;
421 else
422 button = SDL_BUTTON_WHEELDOWN;
423 posted = SDL_PrivateMouseButton(
424 SDL_PRESSED, button, 0, 0);
425 posted |= SDL_PrivateMouseButton(
426 SDL_RELEASED, button, 0, 0);
427 break;
428 case DIMOFS_BUTTON0:
429 case DIMOFS_BUTTON1:
430 case DIMOFS_BUTTON2:
431 case DIMOFS_BUTTON3:
432 if ( xrel || yrel ) {
433 posted = SDL_PrivateMouseMotion(
434 0, 1, xrel, yrel);
435 xrel = 0;
436 yrel = 0;
437 }
438 timestamp = 0;
439 button = (Uint8)(ptrbuf[i].dwOfs-DIMOFS_BUTTON0)+1;
440 /* Button #2 on two button mice is button 3
441 (the middle button is button 2)
442 */
443 if ( button == 2 ) {
444 button = 3;
445 } else
446 if ( button == 3 ) {
447 button = 2;
448 }
449 if ( ptrbuf[i].dwData & 0x80 ) {
450 /* Grab mouse so we get mouse-up */
451 if ( ++mouse_pressed > 0 ) {
452 SetCapture(SDL_Window);
453 }
454 state = SDL_PRESSED;
455 } else {
456 /* Release mouse after all mouse-ups */
457 if ( --mouse_pressed <= 0 ) {
458 ReleaseCapture();
459 mouse_pressed = 0;
460 }
461 state = SDL_RELEASED;
462 }
463 if ( mouse_buttons_swapped ) {
464 if ( button == 1 ) button = 3;
465 else
466 if ( button == 3 ) button = 1;
467 }
468 posted = SDL_PrivateMouseButton(state, button,
469 0, 0);
470 break;
471 }
472 }
473 if ( xrel || yrel ) {
474 posted = SDL_PrivateMouseMotion( 0, 1, xrel, yrel);
475 }
476 }
477
478 /* The main Win32 event handler */
DX5_HandleMessage(_THIS,HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)479 LRESULT DX5_HandleMessage(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
480 {
481 switch (msg) {
482 #ifdef WM_ACTIVATEAPP
483 case WM_ACTIVATEAPP: {
484 int i, active;
485
486 active = (wParam && (GetForegroundWindow() == hwnd));
487 if ( active ) {
488 for ( i=0; SDL_DIdev[i]; ++i ) {
489 IDirectInputDevice2_Acquire(
490 SDL_DIdev[i]);
491 }
492 } else {
493 for ( i=0; SDL_DIdev[i]; ++i ) {
494 IDirectInputDevice2_Unacquire(
495 SDL_DIdev[i]);
496 }
497 mouse_lost = 1;
498 }
499 }
500 break;
501 #endif /* WM_ACTIVATEAPP */
502
503 #ifdef WM_DISPLAYCHANGE
504 case WM_DISPLAYCHANGE: {
505 WPARAM BitsPerPixel;
506 WORD SizeX, SizeY;
507
508 /* Ack! The display changed size and/or depth! */
509 SizeX = LOWORD(lParam);
510 SizeY = HIWORD(lParam);
511 BitsPerPixel = wParam;
512 /* We cause this message when we go fullscreen */
513 }
514 break;
515 #endif /* WM_DISPLAYCHANGE */
516
517 /* The keyboard is handled via DirectInput */
518 case WM_SYSKEYUP:
519 case WM_SYSKEYDOWN: {
520 /* Pass syskey to DefWindwoProc (ALT-F4, etc.) */
521 }
522 break;
523 case WM_KEYUP:
524 case WM_KEYDOWN: {
525 /* Ignore windows keyboard messages */;
526 }
527 return(0);
528
529 #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
530 /* Don't allow screen savers or monitor power downs.
531 This is because they quietly clear DirectX surfaces.
532 It would be better to allow the application to
533 decide whether or not to blow these off, but the
534 semantics of SDL_PrivateSysWMEvent() don't allow
535 the application that choice.
536 */
537 case WM_SYSCOMMAND: {
538 if ((wParam&0xFFF0)==SC_SCREENSAVE ||
539 (wParam&0xFFF0)==SC_MONITORPOWER)
540 return(0);
541 }
542 /* Fall through to default processing */
543
544 #endif /* SC_SCREENSAVE || SC_MONITORPOWER */
545
546 default: {
547 /* Only post the event if we're watching for it */
548 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
549 SDL_SysWMmsg wmmsg;
550
551 SDL_VERSION(&wmmsg.version);
552 wmmsg.hwnd = hwnd;
553 wmmsg.msg = msg;
554 wmmsg.wParam = wParam;
555 wmmsg.lParam = lParam;
556 posted = SDL_PrivateSysWMEvent(&wmmsg);
557
558 /* DJM: If the user isn't watching for private
559 messages in her SDL event loop, then pass it
560 along to any win32 specific window proc.
561 */
562 } else if (userWindowProc) {
563 return CallWindowProc(userWindowProc, hwnd, msg, wParam, lParam);
564 }
565 }
566 break;
567 }
568 return(DefWindowProc(hwnd, msg, wParam, lParam));
569 }
570
571 /* This function checks the windows message queue and DirectInput and returns
572 1 if there was input, 0 if there was no input, or -1 if the application has
573 posted a quit message.
574 */
DX5_CheckInput(_THIS,int timeout,BOOL processInput)575 static int DX5_CheckInput(_THIS, int timeout, BOOL processInput)
576 {
577 MSG msg;
578 int i;
579 HRESULT result;
580 DWORD event;
581
582 /* Check the normal windows queue (highest preference) */
583 posted = 0;
584 while ( ! posted &&
585 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {
586 if ( GetMessage(&msg, NULL, 0, 0) > 0 ) {
587 DispatchMessage(&msg);
588 } else {
589 return(-1);
590 }
591 }
592 if ( posted ) {
593 return(1);
594 }
595
596 /* Pump the DirectInput flow */
597 if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
598 for ( i=0; i<SDL_DIndev; ++i ) {
599 result = IDirectInputDevice2_Poll(SDL_DIdev[i]);
600 if ( (result == DIERR_INPUTLOST) ||
601 (result == DIERR_NOTACQUIRED) ) {
602 if ( SDL_strcmp(inputs[i].name, "mouse") == 0 ) {
603 mouse_lost = 1;
604 }
605 IDirectInputDevice2_Acquire(SDL_DIdev[i]);
606 IDirectInputDevice2_Poll(SDL_DIdev[i]);
607 }
608 }
609 }
610
611 /* Wait for messages and input events */
612 event = MsgWaitForMultipleObjects(SDL_DIndev, SDL_DIevt, FALSE,
613 timeout, QS_ALLEVENTS);
614 if ((event >= WAIT_OBJECT_0) && (event < (WAIT_OBJECT_0+SDL_DIndev))) {
615 DWORD numevents;
616 static DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
617
618 event -= WAIT_OBJECT_0;
619 numevents = INPUT_QSIZE;
620 result = IDirectInputDevice2_GetDeviceData(
621 SDL_DIdev[event], sizeof(DIDEVICEOBJECTDATA),
622 evtbuf, &numevents, 0);
623 if ( (result == DIERR_INPUTLOST) ||
624 (result == DIERR_NOTACQUIRED) ) {
625 if ( SDL_strcmp(inputs[event].name, "mouse") == 0 ) {
626 mouse_lost = 1;
627 }
628 IDirectInputDevice2_Acquire(SDL_DIdev[event]);
629 result = IDirectInputDevice2_GetDeviceData(
630 SDL_DIdev[event], sizeof(DIDEVICEOBJECTDATA),
631 evtbuf, &numevents, 0);
632 }
633 /* Handle the events */
634 if ( result == DI_OK && processInput ) {
635 /* Note: This can post multiple events to event queue
636 */
637 (*SDL_DIfun[event])((int)numevents, evtbuf);
638 return(1);
639 }
640 }
641 if ( event != WAIT_TIMEOUT ) {
642 /* Maybe there was a windows message? */
643 if ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {
644 if ( GetMessage(&msg, NULL, 0, 0) > 0 ) {
645 DispatchMessage(&msg);
646 } else {
647 return(-1);
648 }
649 return(1);
650 }
651 }
652 return(0);
653 }
654
655 /* Change cooperative level based on whether or not we are fullscreen */
DX5_DInputReset(_THIS,int fullscreen)656 void DX5_DInputReset(_THIS, int fullscreen)
657 {
658 DWORD level;
659 int i;
660 HRESULT result;
661 HWND topwnd;
662
663 for ( i=0; i<MAX_INPUTS; ++i ) {
664 if ( SDL_DIdev[i] != NULL ) {
665 if ( fullscreen ) {
666 level = inputs[i].raw_level;
667 } else {
668 level = inputs[i].win_level;
669 }
670 IDirectInputDevice2_Unacquire(SDL_DIdev[i]);
671 topwnd = GetTopLevelParent(SDL_Window);
672 result = IDirectInputDevice2_SetCooperativeLevel(
673 SDL_DIdev[i], topwnd, level);
674 IDirectInputDevice2_Acquire(SDL_DIdev[i]);
675 if ( result != DI_OK ) {
676 SetDIerror(
677 "DirectInputDevice::SetCooperativeLevel", result);
678 }
679 }
680 }
681 mouse_lost = 1;
682
683 /* Flush pending input */
684 DX5_CheckInput(this, 0, FALSE);
685 }
686
DX5_PumpEvents(_THIS)687 void DX5_PumpEvents(_THIS)
688 {
689 /* Wait for messages and DirectInput */
690 while ( DX5_CheckInput(this, 0, TRUE) > 0 ) {
691 /* Loop and check again */;
692 }
693 }
694
DX5_InitOSKeymap(_THIS)695 void DX5_InitOSKeymap(_THIS)
696 {
697 #ifndef DIK_PAUSE
698 #define DIK_PAUSE 0xC5
699 #endif
700 #ifndef DIK_OEM_102
701 #define DIK_OEM_102 0x56 /* < > | on UK/Germany keyboards */
702 #endif
703 int i;
704
705 /* Map the DIK scancodes to SDL keysyms */
706 for ( i=0; i<SDL_arraysize(DIK_keymap); ++i )
707 DIK_keymap[i] = 0;
708
709 /* Defined DIK_* constants */
710 DIK_keymap[DIK_ESCAPE] = SDLK_ESCAPE;
711 DIK_keymap[DIK_1] = SDLK_1;
712 DIK_keymap[DIK_2] = SDLK_2;
713 DIK_keymap[DIK_3] = SDLK_3;
714 DIK_keymap[DIK_4] = SDLK_4;
715 DIK_keymap[DIK_5] = SDLK_5;
716 DIK_keymap[DIK_6] = SDLK_6;
717 DIK_keymap[DIK_7] = SDLK_7;
718 DIK_keymap[DIK_8] = SDLK_8;
719 DIK_keymap[DIK_9] = SDLK_9;
720 DIK_keymap[DIK_0] = SDLK_0;
721 DIK_keymap[DIK_MINUS] = SDLK_MINUS;
722 DIK_keymap[DIK_EQUALS] = SDLK_EQUALS;
723 DIK_keymap[DIK_BACK] = SDLK_BACKSPACE;
724 DIK_keymap[DIK_TAB] = SDLK_TAB;
725 DIK_keymap[DIK_Q] = SDLK_q;
726 DIK_keymap[DIK_W] = SDLK_w;
727 DIK_keymap[DIK_E] = SDLK_e;
728 DIK_keymap[DIK_R] = SDLK_r;
729 DIK_keymap[DIK_T] = SDLK_t;
730 DIK_keymap[DIK_Y] = SDLK_y;
731 DIK_keymap[DIK_U] = SDLK_u;
732 DIK_keymap[DIK_I] = SDLK_i;
733 DIK_keymap[DIK_O] = SDLK_o;
734 DIK_keymap[DIK_P] = SDLK_p;
735 DIK_keymap[DIK_LBRACKET] = SDLK_LEFTBRACKET;
736 DIK_keymap[DIK_RBRACKET] = SDLK_RIGHTBRACKET;
737 DIK_keymap[DIK_RETURN] = SDLK_RETURN;
738 DIK_keymap[DIK_LCONTROL] = SDLK_LCTRL;
739 DIK_keymap[DIK_A] = SDLK_a;
740 DIK_keymap[DIK_S] = SDLK_s;
741 DIK_keymap[DIK_D] = SDLK_d;
742 DIK_keymap[DIK_F] = SDLK_f;
743 DIK_keymap[DIK_G] = SDLK_g;
744 DIK_keymap[DIK_H] = SDLK_h;
745 DIK_keymap[DIK_J] = SDLK_j;
746 DIK_keymap[DIK_K] = SDLK_k;
747 DIK_keymap[DIK_L] = SDLK_l;
748 DIK_keymap[DIK_SEMICOLON] = SDLK_SEMICOLON;
749 DIK_keymap[DIK_APOSTROPHE] = SDLK_QUOTE;
750 DIK_keymap[DIK_GRAVE] = SDLK_BACKQUOTE;
751 DIK_keymap[DIK_LSHIFT] = SDLK_LSHIFT;
752 DIK_keymap[DIK_BACKSLASH] = SDLK_BACKSLASH;
753 DIK_keymap[DIK_OEM_102] = SDLK_LESS;
754 DIK_keymap[DIK_Z] = SDLK_z;
755 DIK_keymap[DIK_X] = SDLK_x;
756 DIK_keymap[DIK_C] = SDLK_c;
757 DIK_keymap[DIK_V] = SDLK_v;
758 DIK_keymap[DIK_B] = SDLK_b;
759 DIK_keymap[DIK_N] = SDLK_n;
760 DIK_keymap[DIK_M] = SDLK_m;
761 DIK_keymap[DIK_COMMA] = SDLK_COMMA;
762 DIK_keymap[DIK_PERIOD] = SDLK_PERIOD;
763 DIK_keymap[DIK_SLASH] = SDLK_SLASH;
764 DIK_keymap[DIK_RSHIFT] = SDLK_RSHIFT;
765 DIK_keymap[DIK_MULTIPLY] = SDLK_KP_MULTIPLY;
766 DIK_keymap[DIK_LMENU] = SDLK_LALT;
767 DIK_keymap[DIK_SPACE] = SDLK_SPACE;
768 DIK_keymap[DIK_CAPITAL] = SDLK_CAPSLOCK;
769 DIK_keymap[DIK_F1] = SDLK_F1;
770 DIK_keymap[DIK_F2] = SDLK_F2;
771 DIK_keymap[DIK_F3] = SDLK_F3;
772 DIK_keymap[DIK_F4] = SDLK_F4;
773 DIK_keymap[DIK_F5] = SDLK_F5;
774 DIK_keymap[DIK_F6] = SDLK_F6;
775 DIK_keymap[DIK_F7] = SDLK_F7;
776 DIK_keymap[DIK_F8] = SDLK_F8;
777 DIK_keymap[DIK_F9] = SDLK_F9;
778 DIK_keymap[DIK_F10] = SDLK_F10;
779 DIK_keymap[DIK_NUMLOCK] = SDLK_NUMLOCK;
780 DIK_keymap[DIK_SCROLL] = SDLK_SCROLLOCK;
781 DIK_keymap[DIK_NUMPAD7] = SDLK_KP7;
782 DIK_keymap[DIK_NUMPAD8] = SDLK_KP8;
783 DIK_keymap[DIK_NUMPAD9] = SDLK_KP9;
784 DIK_keymap[DIK_SUBTRACT] = SDLK_KP_MINUS;
785 DIK_keymap[DIK_NUMPAD4] = SDLK_KP4;
786 DIK_keymap[DIK_NUMPAD5] = SDLK_KP5;
787 DIK_keymap[DIK_NUMPAD6] = SDLK_KP6;
788 DIK_keymap[DIK_ADD] = SDLK_KP_PLUS;
789 DIK_keymap[DIK_NUMPAD1] = SDLK_KP1;
790 DIK_keymap[DIK_NUMPAD2] = SDLK_KP2;
791 DIK_keymap[DIK_NUMPAD3] = SDLK_KP3;
792 DIK_keymap[DIK_NUMPAD0] = SDLK_KP0;
793 DIK_keymap[DIK_DECIMAL] = SDLK_KP_PERIOD;
794 DIK_keymap[DIK_F11] = SDLK_F11;
795 DIK_keymap[DIK_F12] = SDLK_F12;
796
797 DIK_keymap[DIK_F13] = SDLK_F13;
798 DIK_keymap[DIK_F14] = SDLK_F14;
799 DIK_keymap[DIK_F15] = SDLK_F15;
800
801 DIK_keymap[DIK_NUMPADEQUALS] = SDLK_KP_EQUALS;
802 DIK_keymap[DIK_NUMPADENTER] = SDLK_KP_ENTER;
803 DIK_keymap[DIK_RCONTROL] = SDLK_RCTRL;
804 DIK_keymap[DIK_DIVIDE] = SDLK_KP_DIVIDE;
805 DIK_keymap[DIK_SYSRQ] = SDLK_PRINT;
806 DIK_keymap[DIK_RMENU] = SDLK_RALT;
807 DIK_keymap[DIK_PAUSE] = SDLK_PAUSE;
808 DIK_keymap[DIK_HOME] = SDLK_HOME;
809 DIK_keymap[DIK_UP] = SDLK_UP;
810 DIK_keymap[DIK_PRIOR] = SDLK_PAGEUP;
811 DIK_keymap[DIK_LEFT] = SDLK_LEFT;
812 DIK_keymap[DIK_RIGHT] = SDLK_RIGHT;
813 DIK_keymap[DIK_END] = SDLK_END;
814 DIK_keymap[DIK_DOWN] = SDLK_DOWN;
815 DIK_keymap[DIK_NEXT] = SDLK_PAGEDOWN;
816 DIK_keymap[DIK_INSERT] = SDLK_INSERT;
817 DIK_keymap[DIK_DELETE] = SDLK_DELETE;
818 DIK_keymap[DIK_LWIN] = SDLK_LMETA;
819 DIK_keymap[DIK_RWIN] = SDLK_RMETA;
820 DIK_keymap[DIK_APPS] = SDLK_MENU;
821 }
822
TranslateKey(UINT scancode,SDL_keysym * keysym,int pressed)823 static SDL_keysym *TranslateKey(UINT scancode, SDL_keysym *keysym, int pressed)
824 {
825 /* Set the keysym information */
826 keysym->scancode = (unsigned char)scancode;
827 keysym->sym = DIK_keymap[scancode];
828 keysym->mod = KMOD_NONE;
829 keysym->unicode = 0;
830 if ( pressed && SDL_TranslateUNICODE ) {
831 UINT vkey;
832 #ifndef NO_GETKEYBOARDSTATE
833 BYTE keystate[256];
834 Uint16 wchars[2];
835 #endif
836
837 vkey = MapVirtualKey(scancode, 1);
838 #ifdef NO_GETKEYBOARDSTATE
839 /* Uh oh, better hope the vkey is close enough.. */
840 keysym->unicode = vkey;
841 #else
842 GetKeyboardState(keystate);
843 if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) == 1)
844 {
845 keysym->unicode = wchars[0];
846 }
847 #endif /* NO_GETKEYBOARDSTATE */
848 }
849 return(keysym);
850 }
851
DX5_CreateWindow(_THIS)852 int DX5_CreateWindow(_THIS)
853 {
854 char *windowid = SDL_getenv("SDL_WINDOWID");
855 int i;
856
857 /* Clear out DirectInput variables in case we fail */
858 for ( i=0; i<MAX_INPUTS; ++i ) {
859 SDL_DIdev[i] = NULL;
860 SDL_DIevt[i] = NULL;
861 SDL_DIfun[i] = NULL;
862 }
863
864 SDL_RegisterApp(NULL, 0, 0);
865
866 SDL_windowid = (windowid != NULL);
867 if ( SDL_windowid ) {
868 SDL_Window = (HWND)SDL_strtoull(windowid, NULL, 0);
869 if ( SDL_Window == NULL ) {
870 SDL_SetError("Couldn't get user specified window");
871 return(-1);
872 }
873
874 /* DJM: we want all event's for the user specified
875 window to be handled by SDL.
876 */
877 userWindowProc = (WNDPROCTYPE)GetWindowLongPtr(SDL_Window, GWLP_WNDPROC);
878 SetWindowLongPtr(SDL_Window, GWLP_WNDPROC, (LONG_PTR)WinMessage);
879 } else {
880 SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
881 (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX),
882 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, SDL_Instance, NULL);
883 if ( SDL_Window == NULL ) {
884 SDL_SetError("Couldn't create window");
885 return(-1);
886 }
887 ShowWindow(SDL_Window, SW_HIDE);
888 }
889
890 /* Initialize DirectInput */
891 if ( DX5_DInputInit(this) < 0 ) {
892 return(-1);
893 }
894
895 /* JC 14 Mar 2006
896 Flush the message loop or this can cause big problems later
897 Especially if the user decides to use dialog boxes or assert()!
898 */
899 WIN_FlushMessageQueue();
900
901 /* Ready to roll */
902 return(0);
903 }
904
DX5_DestroyWindow(_THIS)905 void DX5_DestroyWindow(_THIS)
906 {
907 /* Close down DirectInput */
908 DX5_DInputQuit(this);
909
910 /* Destroy our window */
911 if ( SDL_windowid ) {
912 SetWindowLongPtr(SDL_Window, GWLP_WNDPROC, (LONG_PTR)userWindowProc);
913 } else {
914 DestroyWindow(SDL_Window);
915 }
916 SDL_UnregisterApp();
917
918 /* JC 14 Mar 2006
919 Flush the message loop or this can cause big problems later
920 Especially if the user decides to use dialog boxes or assert()!
921 */
922 WIN_FlushMessageQueue();
923 }
924