SDL-1.2.14
[sdl_omap.git] / src / video / windx5 / SDL_dx5events.c
CommitLineData
e14743d1 1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 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 2
47#define INPUT_QSIZE 512 /* Buffer up to 512 input messages */
48
49static LPDIRECTINPUT dinput = NULL;
50static LPDIRECTINPUTDEVICE2 SDL_DIdev[MAX_INPUTS];
51static HANDLE SDL_DIevt[MAX_INPUTS];
52static void (*SDL_DIfun[MAX_INPUTS])(const int, DIDEVICEOBJECTDATA *);
53static int SDL_DIndev = 0;
54static int mouse_lost;
55static int mouse_pressed;
56static int mouse_buttons_swapped = 0;
57
58/* The translation table from a DirectInput scancode to an SDL keysym */
59static SDLKey DIK_keymap[256];
60static 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
69static WNDPROCTYPE userWindowProc = NULL;
70
71static 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 */
85static 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 */
131static void handle_keyboard(const int numevents, DIDEVICEOBJECTDATA *events);
132static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *events);
133struct {
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_FOREGROUND|DISCL_NONEXCLUSIVE),
153 (DISCL_FOREGROUND|DISCL_NONEXCLUSIVE), handle_mouse },
154 { NULL, NULL, NULL, 0, 0, NULL }
155};
156
157static 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 */
248static 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 */
276static int posted = 0;
277
278/* Input event handler functions */
279static 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
296static void post_mouse_motion(int relative, Sint16 x, Sint16 y)
297{
298 extern int mouse_relative;
299
300 if ( (SDL_GetAppState() & (SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS)) ==
301 (SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS) ) {
302 posted = SDL_PrivateMouseMotion(
303 0, relative, x, y);
304
305 if ( !mouse_relative ) {
306 /* As DirectInput reads raw device coordinates, it has no notion of
307 * cursors or absolute position. We must assume responsibility for
308 * keeping track of this. */
309 int current_x, current_y;
310 POINT cursor;
311 RECT trap;
312 RECT window;
313 int at_edge;
314
315 /* Get the current cursor position */
316 SDL_GetMouseState(&current_x, &current_y);
317 cursor.x = current_x;
318 cursor.y = current_y;
319 ClientToScreen(SDL_Window, &cursor);
320
321 /* Construct a 1 pixel square RECT that is used to confine the cursor
322 * pointer to a specific pixel using ClipCursor. This is used in
323 * preference to SetCursorPos as it avoids the cursor jumping around as
324 * both the OS and SDL attempt to move it simultaneously. */
325 trap.left = cursor.x;
326 trap.top = cursor.y;
327 trap.right = cursor.x + 1;
328 trap.bottom = cursor.y + 1;
329
330 GetClientRect(SDL_Window, &window);
331 window.right -= window.left; window.left = 0;
332 window.bottom -= window.top; window.top = 0;
333
334 /* As we're assuming control over the cursor, we need to know when to
335 * relinquish control of it back to the operating system. This is when
336 * the cursor reaches the edge of the window. */
337 at_edge = (current_x == window.left) ||
338 (current_x == (window.right - 1)) ||
339 (current_y == window.top) ||
340 (current_y == (window.bottom - 1));
341
342 if ( at_edge ) {
343 ClipCursor(NULL);
344 } else {
345 ClipCursor(&trap);
346 }
347 } else {
348 /* When in relative mode, warp the OS's idea of where the cursor is to
349 * the center of the screen. This isn't really necessary as DirectInput
350 * reads from the hardware itself, but in case things go wrong, the
351 * cursor will be left in a sensible place. */
352 POINT center;
353 center.x = (SDL_VideoSurface->w/2);
354 center.y = (SDL_VideoSurface->h/2);
355 ClientToScreen(SDL_Window, &center);
356 SetCursorPos(center.x, center.y);
357 }
358 } else {
359 /* No window or mouse focus, control is lost */
360 mouse_lost = 1;
361 ClipCursor(NULL);
362 }
363}
364
365static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *ptrbuf)
366{
367 int i;
368 Sint16 xrel, yrel;
369 Uint8 state;
370 Uint8 button;
371 DWORD timestamp = 0;
372
373 /* Sanity check. Mailing list reports this being NULL unexpectedly. */
374 if (SDL_PublicSurface == NULL) {
375 return;
376 }
377
378 /* If the mouse was lost, regain some sense of mouse state */
379 if ( mouse_lost && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
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/* The main Win32 event handler */
553LRESULT DX5_HandleMessage(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
554{
555 switch (msg) {
556#ifdef WM_ACTIVATEAPP
557 case WM_ACTIVATEAPP: {
558 int i, active;
559
560 active = (wParam && (GetForegroundWindow() == hwnd));
561 if ( active ) {
562 for ( i=0; SDL_DIdev[i]; ++i ) {
563 IDirectInputDevice2_Acquire(
564 SDL_DIdev[i]);
565 }
566 } else {
567 for ( i=0; SDL_DIdev[i]; ++i ) {
568 IDirectInputDevice2_Unacquire(
569 SDL_DIdev[i]);
570 }
571 mouse_lost = 1;
572 }
573 }
574 break;
575#endif /* WM_ACTIVATEAPP */
576
577#ifdef WM_DISPLAYCHANGE
578 case WM_DISPLAYCHANGE: {
579 WPARAM BitsPerPixel;
580 WORD SizeX, SizeY;
581
582 /* Ack! The display changed size and/or depth! */
583 SizeX = LOWORD(lParam);
584 SizeY = HIWORD(lParam);
585 BitsPerPixel = wParam;
586 /* We cause this message when we go fullscreen */
587 }
588 break;
589#endif /* WM_DISPLAYCHANGE */
590
591 /* The keyboard is handled via DirectInput */
592 case WM_SYSKEYUP:
593 case WM_SYSKEYDOWN:
594 case WM_KEYUP:
595 case WM_KEYDOWN: {
596 /* Ignore windows keyboard messages */;
597 }
598 return(0);
599
600#if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
601 /* Don't allow screen savers or monitor power downs.
602 This is because they quietly clear DirectX surfaces.
603 It would be better to allow the application to
604 decide whether or not to blow these off, but the
605 semantics of SDL_PrivateSysWMEvent() don't allow
606 the application that choice.
607 */
608 case WM_SYSCOMMAND: {
609 if ((wParam&0xFFF0)==SC_SCREENSAVE ||
610 (wParam&0xFFF0)==SC_MONITORPOWER)
611 return(0);
612 }
613 /* Fall through to default processing */
614
615#endif /* SC_SCREENSAVE || SC_MONITORPOWER */
616
617 default: {
618 /* Only post the event if we're watching for it */
619 if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
620 SDL_SysWMmsg wmmsg;
621
622 SDL_VERSION(&wmmsg.version);
623 wmmsg.hwnd = hwnd;
624 wmmsg.msg = msg;
625 wmmsg.wParam = wParam;
626 wmmsg.lParam = lParam;
627 posted = SDL_PrivateSysWMEvent(&wmmsg);
628
629 /* DJM: If the user isn't watching for private
630 messages in her SDL event loop, then pass it
631 along to any win32 specific window proc.
632 */
633 } else if (userWindowProc) {
634 return CallWindowProc(userWindowProc, hwnd, msg, wParam, lParam);
635 }
636 }
637 break;
638 }
639 return(DefWindowProc(hwnd, msg, wParam, lParam));
640}
641
642/* This function checks the windows message queue and DirectInput and returns
643 1 if there was input, 0 if there was no input, or -1 if the application has
644 posted a quit message.
645*/
646static int DX5_CheckInput(_THIS, int timeout, BOOL processInput)
647{
648 MSG msg;
649 int i;
650 HRESULT result;
651 DWORD event;
652
653 /* Check the normal windows queue (highest preference) */
654 posted = 0;
655 while ( ! posted &&
656 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {
657 if ( GetMessage(&msg, NULL, 0, 0) > 0 ) {
658 TranslateMessage(&msg);
659 DispatchMessage(&msg);
660 } else {
661 return(-1);
662 }
663 }
664 if ( posted ) {
665 return(1);
666 }
667
668 /* Pump the DirectInput flow */
669 if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
670 for ( i=0; i<MAX_INPUTS; ++i ) {
671 if ( SDL_DIdev[i] != NULL ) {
672 result = IDirectInputDevice2_Poll(SDL_DIdev[i]);
673 if ( (result == DIERR_INPUTLOST) ||
674 (result == DIERR_NOTACQUIRED) ) {
675 if ( SDL_strcmp(inputs[i].name, "mouse") == 0 ) {
676 mouse_lost = 1;
677 }
678 IDirectInputDevice2_Acquire(SDL_DIdev[i]);
679 IDirectInputDevice2_Poll(SDL_DIdev[i]);
680 }
681 }
682 }
683 }
684
685 /* Wait for messages and input events */
686 event = MsgWaitForMultipleObjects(SDL_DIndev, SDL_DIevt, FALSE,
687 timeout, QS_ALLEVENTS);
688 if ((event >= WAIT_OBJECT_0) && (event < (WAIT_OBJECT_0+SDL_DIndev))) {
689 DWORD numevents;
690 static DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
691
692 event -= WAIT_OBJECT_0;
693 numevents = INPUT_QSIZE;
694 result = IDirectInputDevice2_GetDeviceData(
695 SDL_DIdev[event], sizeof(DIDEVICEOBJECTDATA),
696 evtbuf, &numevents, 0);
697 if ( (result == DIERR_INPUTLOST) ||
698 (result == DIERR_NOTACQUIRED) ) {
699 if ( SDL_strcmp(inputs[event].name, "mouse") == 0 ) {
700 mouse_lost = 1;
701 }
702 IDirectInputDevice2_Acquire(SDL_DIdev[event]);
703 result = IDirectInputDevice2_GetDeviceData(
704 SDL_DIdev[event], sizeof(DIDEVICEOBJECTDATA),
705 evtbuf, &numevents, 0);
706 }
707 /* Handle the events */
708 if ( result == DI_OK && processInput ) {
709 /* Note: This can post multiple events to event queue
710 */
711 (*SDL_DIfun[event])((int)numevents, evtbuf);
712 return(1);
713 }
714 }
715 if ( event != WAIT_TIMEOUT ) {
716 /* Maybe there was a windows message? */
717 posted = 0;
718 while ( ! posted &&
719 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {
720 if ( GetMessage(&msg, NULL, 0, 0) > 0 ) {
721 TranslateMessage(&msg);
722 DispatchMessage(&msg);
723 } else {
724 return(-1);
725 }
726 }
727 if ( posted ) {
728 return(1);
729 }
730 }
731 return(0);
732}
733
734/* Change cooperative level based on whether or not we are fullscreen */
735void DX5_DInputReset(_THIS, int fullscreen)
736{
737 DWORD level;
738 int i;
739 HRESULT result;
740 HWND topwnd;
741
742 for ( i=0; i<MAX_INPUTS; ++i ) {
743 if ( SDL_DIdev[i] != NULL ) {
744 if ( fullscreen ) {
745 level = inputs[i].raw_level;
746 } else {
747 level = inputs[i].win_level;
748 }
749 IDirectInputDevice2_Unacquire(SDL_DIdev[i]);
750 topwnd = GetTopLevelParent(SDL_Window);
751 result = IDirectInputDevice2_SetCooperativeLevel(
752 SDL_DIdev[i], topwnd, level);
753 IDirectInputDevice2_Acquire(SDL_DIdev[i]);
754 if ( result != DI_OK ) {
755 SetDIerror(
756 "DirectInputDevice::SetCooperativeLevel", result);
757 }
758 }
759 }
760 mouse_lost = 1;
761
762 /* Flush pending input */
763 DX5_CheckInput(this, 0, FALSE);
764}
765
766void DX5_PumpEvents(_THIS)
767{
768 /* Wait for messages and DirectInput */
769 while ( DX5_CheckInput(this, 0, TRUE) > 0 ) {
770 /* Loop and check again */;
771 }
772}
773
774void DX5_InitOSKeymap(_THIS)
775{
776#ifndef DIK_PAUSE
777#define DIK_PAUSE 0xC5
778#endif
779#ifndef DIK_OEM_102
780#define DIK_OEM_102 0x56 /* < > | on UK/Germany keyboards */
781#endif
782 int i;
783
784 /* Map the DIK scancodes to SDL keysyms */
785 for ( i=0; i<SDL_arraysize(DIK_keymap); ++i )
786 DIK_keymap[i] = 0;
787
788 /* Defined DIK_* constants */
789 DIK_keymap[DIK_ESCAPE] = SDLK_ESCAPE;
790 DIK_keymap[DIK_1] = SDLK_1;
791 DIK_keymap[DIK_2] = SDLK_2;
792 DIK_keymap[DIK_3] = SDLK_3;
793 DIK_keymap[DIK_4] = SDLK_4;
794 DIK_keymap[DIK_5] = SDLK_5;
795 DIK_keymap[DIK_6] = SDLK_6;
796 DIK_keymap[DIK_7] = SDLK_7;
797 DIK_keymap[DIK_8] = SDLK_8;
798 DIK_keymap[DIK_9] = SDLK_9;
799 DIK_keymap[DIK_0] = SDLK_0;
800 DIK_keymap[DIK_MINUS] = SDLK_MINUS;
801 DIK_keymap[DIK_EQUALS] = SDLK_EQUALS;
802 DIK_keymap[DIK_BACK] = SDLK_BACKSPACE;
803 DIK_keymap[DIK_TAB] = SDLK_TAB;
804 DIK_keymap[DIK_Q] = SDLK_q;
805 DIK_keymap[DIK_W] = SDLK_w;
806 DIK_keymap[DIK_E] = SDLK_e;
807 DIK_keymap[DIK_R] = SDLK_r;
808 DIK_keymap[DIK_T] = SDLK_t;
809 DIK_keymap[DIK_Y] = SDLK_y;
810 DIK_keymap[DIK_U] = SDLK_u;
811 DIK_keymap[DIK_I] = SDLK_i;
812 DIK_keymap[DIK_O] = SDLK_o;
813 DIK_keymap[DIK_P] = SDLK_p;
814 DIK_keymap[DIK_LBRACKET] = SDLK_LEFTBRACKET;
815 DIK_keymap[DIK_RBRACKET] = SDLK_RIGHTBRACKET;
816 DIK_keymap[DIK_RETURN] = SDLK_RETURN;
817 DIK_keymap[DIK_LCONTROL] = SDLK_LCTRL;
818 DIK_keymap[DIK_A] = SDLK_a;
819 DIK_keymap[DIK_S] = SDLK_s;
820 DIK_keymap[DIK_D] = SDLK_d;
821 DIK_keymap[DIK_F] = SDLK_f;
822 DIK_keymap[DIK_G] = SDLK_g;
823 DIK_keymap[DIK_H] = SDLK_h;
824 DIK_keymap[DIK_J] = SDLK_j;
825 DIK_keymap[DIK_K] = SDLK_k;
826 DIK_keymap[DIK_L] = SDLK_l;
827 DIK_keymap[DIK_SEMICOLON] = SDLK_SEMICOLON;
828 DIK_keymap[DIK_APOSTROPHE] = SDLK_QUOTE;
829 DIK_keymap[DIK_GRAVE] = SDLK_BACKQUOTE;
830 DIK_keymap[DIK_LSHIFT] = SDLK_LSHIFT;
831 DIK_keymap[DIK_BACKSLASH] = SDLK_BACKSLASH;
832 DIK_keymap[DIK_OEM_102] = SDLK_LESS;
833 DIK_keymap[DIK_Z] = SDLK_z;
834 DIK_keymap[DIK_X] = SDLK_x;
835 DIK_keymap[DIK_C] = SDLK_c;
836 DIK_keymap[DIK_V] = SDLK_v;
837 DIK_keymap[DIK_B] = SDLK_b;
838 DIK_keymap[DIK_N] = SDLK_n;
839 DIK_keymap[DIK_M] = SDLK_m;
840 DIK_keymap[DIK_COMMA] = SDLK_COMMA;
841 DIK_keymap[DIK_PERIOD] = SDLK_PERIOD;
842 DIK_keymap[DIK_SLASH] = SDLK_SLASH;
843 DIK_keymap[DIK_RSHIFT] = SDLK_RSHIFT;
844 DIK_keymap[DIK_MULTIPLY] = SDLK_KP_MULTIPLY;
845 DIK_keymap[DIK_LMENU] = SDLK_LALT;
846 DIK_keymap[DIK_SPACE] = SDLK_SPACE;
847 DIK_keymap[DIK_CAPITAL] = SDLK_CAPSLOCK;
848 DIK_keymap[DIK_F1] = SDLK_F1;
849 DIK_keymap[DIK_F2] = SDLK_F2;
850 DIK_keymap[DIK_F3] = SDLK_F3;
851 DIK_keymap[DIK_F4] = SDLK_F4;
852 DIK_keymap[DIK_F5] = SDLK_F5;
853 DIK_keymap[DIK_F6] = SDLK_F6;
854 DIK_keymap[DIK_F7] = SDLK_F7;
855 DIK_keymap[DIK_F8] = SDLK_F8;
856 DIK_keymap[DIK_F9] = SDLK_F9;
857 DIK_keymap[DIK_F10] = SDLK_F10;
858 DIK_keymap[DIK_NUMLOCK] = SDLK_NUMLOCK;
859 DIK_keymap[DIK_SCROLL] = SDLK_SCROLLOCK;
860 DIK_keymap[DIK_NUMPAD7] = SDLK_KP7;
861 DIK_keymap[DIK_NUMPAD8] = SDLK_KP8;
862 DIK_keymap[DIK_NUMPAD9] = SDLK_KP9;
863 DIK_keymap[DIK_SUBTRACT] = SDLK_KP_MINUS;
864 DIK_keymap[DIK_NUMPAD4] = SDLK_KP4;
865 DIK_keymap[DIK_NUMPAD5] = SDLK_KP5;
866 DIK_keymap[DIK_NUMPAD6] = SDLK_KP6;
867 DIK_keymap[DIK_ADD] = SDLK_KP_PLUS;
868 DIK_keymap[DIK_NUMPAD1] = SDLK_KP1;
869 DIK_keymap[DIK_NUMPAD2] = SDLK_KP2;
870 DIK_keymap[DIK_NUMPAD3] = SDLK_KP3;
871 DIK_keymap[DIK_NUMPAD0] = SDLK_KP0;
872 DIK_keymap[DIK_DECIMAL] = SDLK_KP_PERIOD;
873 DIK_keymap[DIK_F11] = SDLK_F11;
874 DIK_keymap[DIK_F12] = SDLK_F12;
875
876 DIK_keymap[DIK_F13] = SDLK_F13;
877 DIK_keymap[DIK_F14] = SDLK_F14;
878 DIK_keymap[DIK_F15] = SDLK_F15;
879
880 DIK_keymap[DIK_NUMPADEQUALS] = SDLK_KP_EQUALS;
881 DIK_keymap[DIK_NUMPADENTER] = SDLK_KP_ENTER;
882 DIK_keymap[DIK_RCONTROL] = SDLK_RCTRL;
883 DIK_keymap[DIK_DIVIDE] = SDLK_KP_DIVIDE;
884 DIK_keymap[DIK_SYSRQ] = SDLK_PRINT;
885 DIK_keymap[DIK_RMENU] = SDLK_RALT;
886 DIK_keymap[DIK_PAUSE] = SDLK_PAUSE;
887 DIK_keymap[DIK_HOME] = SDLK_HOME;
888 DIK_keymap[DIK_UP] = SDLK_UP;
889 DIK_keymap[DIK_PRIOR] = SDLK_PAGEUP;
890 DIK_keymap[DIK_LEFT] = SDLK_LEFT;
891 DIK_keymap[DIK_RIGHT] = SDLK_RIGHT;
892 DIK_keymap[DIK_END] = SDLK_END;
893 DIK_keymap[DIK_DOWN] = SDLK_DOWN;
894 DIK_keymap[DIK_NEXT] = SDLK_PAGEDOWN;
895 DIK_keymap[DIK_INSERT] = SDLK_INSERT;
896 DIK_keymap[DIK_DELETE] = SDLK_DELETE;
897 DIK_keymap[DIK_LWIN] = SDLK_LMETA;
898 DIK_keymap[DIK_RWIN] = SDLK_RMETA;
899 DIK_keymap[DIK_APPS] = SDLK_MENU;
900}
901
902static SDL_keysym *TranslateKey(UINT scancode, SDL_keysym *keysym, int pressed)
903{
904 /* Set the keysym information */
905 keysym->scancode = (unsigned char)scancode;
906 keysym->sym = DIK_keymap[scancode];
907 keysym->mod = KMOD_NONE;
908 keysym->unicode = 0;
909 if ( pressed && SDL_TranslateUNICODE ) {
910 UINT vkey;
911#ifndef NO_GETKEYBOARDSTATE
912 BYTE keystate[256];
913 Uint16 wchars[2];
914#endif
915
916 vkey = MapVirtualKey(scancode, 1);
917#ifdef NO_GETKEYBOARDSTATE
918 /* Uh oh, better hope the vkey is close enough.. */
919 keysym->unicode = vkey;
920#else
921 GetKeyboardState(keystate);
922 /* Numlock isn't taken into account in ToUnicode,
923 * so we handle it as a special case here */
924 if ((keystate[VK_NUMLOCK] & 1) && vkey >= VK_NUMPAD0 && vkey <= VK_NUMPAD9)
925 {
926 keysym->unicode = vkey - VK_NUMPAD0 + '0';
927 }
928 else if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) > 0)
929 {
930 keysym->unicode = wchars[0];
931 }
932#endif /* NO_GETKEYBOARDSTATE */
933 }
934 return(keysym);
935}
936
937int DX5_CreateWindow(_THIS)
938{
939 char *windowid = SDL_getenv("SDL_WINDOWID");
940 int i;
941
942 /* Clear out DirectInput variables in case we fail */
943 for ( i=0; i<MAX_INPUTS; ++i ) {
944 SDL_DIdev[i] = NULL;
945 SDL_DIevt[i] = NULL;
946 SDL_DIfun[i] = NULL;
947 }
948
949 SDL_RegisterApp(NULL, 0, 0);
950
951 SDL_windowid = (windowid != NULL);
952 if ( SDL_windowid ) {
953 SDL_Window = (HWND)SDL_strtoull(windowid, NULL, 0);
954 if ( SDL_Window == NULL ) {
955 SDL_SetError("Couldn't get user specified window");
956 return(-1);
957 }
958
959 /* DJM: we want all event's for the user specified
960 window to be handled by SDL.
961 */
962 userWindowProc = (WNDPROCTYPE)GetWindowLongPtr(SDL_Window, GWLP_WNDPROC);
963 SetWindowLongPtr(SDL_Window, GWLP_WNDPROC, (LONG_PTR)WinMessage);
964 } else {
965 SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
966 (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX),
967 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, SDL_Instance, NULL);
968 if ( SDL_Window == NULL ) {
969 SDL_SetError("Couldn't create window");
970 return(-1);
971 }
972 ShowWindow(SDL_Window, SW_HIDE);
973 }
974
975 /* Initialize DirectInput */
976 if ( DX5_DInputInit(this) < 0 ) {
977 return(-1);
978 }
979
980 /* JC 14 Mar 2006
981 Flush the message loop or this can cause big problems later
982 Especially if the user decides to use dialog boxes or assert()!
983 */
984 WIN_FlushMessageQueue();
985
986 /* Ready to roll */
987 return(0);
988}
989
990void DX5_DestroyWindow(_THIS)
991{
992 /* Close down DirectInput */
993 DX5_DInputQuit(this);
994
995 /* Destroy our window */
996 if ( SDL_windowid ) {
997 SetWindowLongPtr(SDL_Window, GWLP_WNDPROC, (LONG_PTR)userWindowProc);
998 } else {
999 DestroyWindow(SDL_Window);
1000 }
1001 SDL_UnregisterApp();
1002
1003 /* JC 14 Mar 2006
1004 Flush the message loop or this can cause big problems later
1005 Especially if the user decides to use dialog boxes or assert()!
1006 */
1007 WIN_FlushMessageQueue();
1008}