Fix for mingw compilation of haptic subsystem by Alam.
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 Sam Lantinga
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.
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.
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
22 #include "SDL_config.h"
24 #ifdef SDL_JOYSTICK_DINPUT
26 /* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de
27 * A. Formiga's WINMM driver.
29 * Hats and sliders are completely untested; the app I'm writing this for mostly
30 * doesn't use them and I don't own any joysticks with them.
32 * We don't bother to use event notification here. It doesn't seem to work
33 * with polled devices, and it's fine to call IDirectInputDevice2_GetDeviceData and
34 * let it return 0 events. */
36 #include "SDL_error.h"
37 #include "SDL_events.h"
38 #include "SDL_joystick.h"
39 #include "../SDL_sysjoystick.h"
40 #include "../SDL_joystick_c.h"
41 #include "SDL_dxjoystick_c.h"
43 /* an ISO hack for VisualC++ */
45 #define snprintf _snprintf
48 #define INPUT_QSIZE 32 /* Buffer up to 32 input messages */
49 #define MAX_JOYSTICKS 8
50 #define AXIS_MIN -32768 /* minimum value for axis coordinate */
51 #define AXIS_MAX 32767 /* maximum value for axis coordinate */
52 #define JOY_AXIS_THRESHOLD (((AXIS_MAX)-(AXIS_MIN))/100) /* 1% motion */
54 /* external variables referenced. */
55 extern HWND SDL_HelperWindow;
59 static LPDIRECTINPUT dinput = NULL;
60 extern HRESULT(WINAPI * DInputCreate) (HINSTANCE hinst, DWORD dwVersion,
63 static DIDEVICEINSTANCE SYS_Joystick[MAX_JOYSTICKS]; /* array to hold joystick ID values */
64 static int SYS_NumJoysticks;
65 static HINSTANCE DInputDLL = NULL;
68 /* local prototypes */
69 static void SetDIerror(const char *function, HRESULT code);
70 static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE *
71 pdidInstance, VOID * pContext);
72 static BOOL CALLBACK EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev,
74 static Uint8 TranslatePOV(DWORD value);
75 static int SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis,
77 static int SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat,
79 static int SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick,
80 Uint8 button, Uint8 state);
83 /* Convert a DirectInput return code to a text message */
85 SetDIerror(const char *function, HRESULT code)
87 SDL_SetError("%s() [%s]: %s", function,
88 DXGetErrorString8A(code), DXGetErrorDescription8A(code));
92 /* Function to scan the system for joysticks.
93 * This function should set SDL_numjoysticks to the number of available
94 * joysticks. Joystick 0 should be the system default joystick.
95 * It should return 0, or -1 on an unrecoverable fatal error.
98 SDL_SYS_JoystickInit(void)
103 SYS_NumJoysticks = 0;
105 result = CoInitialize(NULL);
106 if (FAILED(result)) {
107 SetDIerror("CoInitialize", result);
111 result = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER,
112 &IID_IDirectInput, &dinput);
114 if (FAILED(result)) {
115 SetDIerror("CoCreateInstance", result);
119 /* Because we used CoCreateInstance, we need to Initialize it, first. */
120 instance = GetModuleHandle(NULL);
121 if (instance == NULL) {
122 SDL_SetError("GetModuleHandle() failed with error code %d.", GetLastError());
126 IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION);
128 if (FAILED(result)) {
129 SetDIerror("IDirectInput::Initialize", result);
133 /* Look for joysticks, wheels, head trackers, gamepads, etc.. */
134 result = IDirectInput_EnumDevices(dinput,
136 EnumJoysticksCallback,
137 NULL, DIEDFL_ATTACHEDONLY);
139 return SYS_NumJoysticks;
143 EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
145 SDL_memcpy(&SYS_Joystick[SYS_NumJoysticks], pdidInstance,
146 sizeof(DIDEVICEINSTANCE));
149 if (SYS_NumJoysticks >= MAX_JOYSTICKS)
152 return DIENUM_CONTINUE;
155 /* Function to get the device-dependent name of a joystick */
157 SDL_SYS_JoystickName(int index)
159 /***-> test for invalid index ? */
160 return (SYS_Joystick[index].tszProductName);
163 /* Function to open a joystick for use.
164 The joystick to open is specified by the index field of the joystick.
165 This should fill the nbuttons and naxes fields of the joystick structure.
166 It returns 0, or -1 if there is an error.
169 SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
172 LPDIRECTINPUTDEVICE device;
175 SDL_memset(&dipdw, 0, sizeof(DIPROPDWORD));
176 dipdw.diph.dwSize = sizeof(DIPROPDWORD);
177 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
180 /* allocate memory for system specific hardware data */
182 (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata));
183 if (joystick->hwdata == NULL) {
187 SDL_memset(joystick->hwdata, 0, sizeof(struct joystick_hwdata));
188 joystick->hwdata->buffered = 1;
189 joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
192 IDirectInput_CreateDevice(dinput,
193 &SYS_Joystick[joystick->index].
194 guidInstance, &device, NULL);
195 if (FAILED(result)) {
196 SetDIerror("IDirectInput::CreateDevice", result);
200 /* Now get the IDirectInputDevice2 interface, instead. */
201 result = IDirectInputDevice_QueryInterface(device,
202 &IID_IDirectInputDevice2,
203 (LPVOID *) & joystick->
204 hwdata->InputDevice);
205 /* We are done with this object. Use the stored one from now on. */
206 IDirectInputDevice_Release(device);
208 if (FAILED(result)) {
209 SetDIerror("IDirectInputDevice::QueryInterface", result);
213 /* Aquire shared access. Exclusive access is required for forces,
216 IDirectInputDevice2_SetCooperativeLevel(joystick->hwdata->
217 InputDevice, SDL_HelperWindow,
220 if (FAILED(result)) {
221 SetDIerror("IDirectInputDevice2::SetCooperativeLevel", result);
225 /* Use the extended data structure: DIJOYSTATE2. */
227 IDirectInputDevice2_SetDataFormat(joystick->hwdata->InputDevice,
229 if (FAILED(result)) {
230 SetDIerror("IDirectInputDevice2::SetDataFormat", result);
234 /* Get device capabilities */
236 IDirectInputDevice2_GetCapabilities(joystick->hwdata->InputDevice,
237 &joystick->hwdata->Capabilities);
239 if (FAILED(result)) {
240 SetDIerror("IDirectInputDevice2::GetCapabilities", result);
245 if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
247 result = IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
249 if (FAILED(result)) {
250 SetDIerror("IDirectInputDevice2::Acquire", result);
254 /* reset all accuators. */
256 IDirectInputDevice2_SendForceFeedbackCommand(joystick->hwdata->
260 if (FAILED(result)) {
261 SetDIerror("IDirectInputDevice2::SendForceFeedbackCommand",
266 result = IDirectInputDevice2_Unacquire(joystick->hwdata->InputDevice);
268 if (FAILED(result)) {
269 SetDIerror("IDirectInputDevice2::Unacquire", result);
273 /* Turn on auto-centering for a ForceFeedback device (until told
275 dipdw.diph.dwObj = 0;
276 dipdw.diph.dwHow = DIPH_DEVICE;
277 dipdw.dwData = DIPROPAUTOCENTER_ON;
280 IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
281 DIPROP_AUTOCENTER, &dipdw.diph);
283 if (FAILED(result)) {
284 SetDIerror("IDirectInputDevice2::SetProperty", result);
289 /* What buttons and axes does it have? */
290 IDirectInputDevice2_EnumObjects(joystick->hwdata->InputDevice,
291 EnumDevObjectsCallback, joystick,
292 DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
294 dipdw.diph.dwObj = 0;
295 dipdw.diph.dwHow = DIPH_DEVICE;
296 dipdw.dwData = INPUT_QSIZE;
298 /* Set the buffer size */
300 IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
301 DIPROP_BUFFERSIZE, &dipdw.diph);
303 if (result == DI_POLLEDDEVICE) {
304 /* This device doesn't support buffering, so we're forced
305 * to use less reliable polling. */
306 joystick->hwdata->buffered = 0;
307 } else if (FAILED(result)) {
308 SetDIerror("IDirectInputDevice2::SetProperty", result);
316 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
318 SDL_Joystick *joystick = (SDL_Joystick *) pvRef;
320 input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
322 in->ofs = dev->dwOfs;
324 if (dev->dwType & DIDFT_BUTTON) {
326 in->num = joystick->nbuttons;
327 joystick->nbuttons++;
328 } else if (dev->dwType & DIDFT_POV) {
330 in->num = joystick->nhats;
332 } else if (dev->dwType & DIDFT_AXIS) {
337 in->num = joystick->naxes;
339 diprg.diph.dwSize = sizeof(diprg);
340 diprg.diph.dwHeaderSize = sizeof(diprg.diph);
341 diprg.diph.dwObj = dev->dwOfs;
342 diprg.diph.dwHow = DIPH_BYOFFSET;
343 diprg.lMin = AXIS_MIN;
344 diprg.lMax = AXIS_MAX;
347 IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
348 DIPROP_RANGE, &diprg.diph);
349 if (FAILED(result)) {
350 return DIENUM_CONTINUE; /* don't use this axis */
353 /* Set dead zone to 0. */
354 dilong.diph.dwSize = sizeof(dilong);
355 dilong.diph.dwHeaderSize = sizeof(dilong.diph);
356 dilong.diph.dwObj = dev->dwOfs;
357 dilong.diph.dwHow = DIPH_BYOFFSET;
360 IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
361 DIPROP_DEADZONE, &dilong.diph);
362 if (FAILED(result)) {
363 return DIENUM_CONTINUE; /* don't use this axis */
368 /* not supported at this time */
369 return DIENUM_CONTINUE;
372 joystick->hwdata->NumInputs++;
374 if (joystick->hwdata->NumInputs == MAX_INPUTS) {
375 return DIENUM_STOP; /* too many */
378 return DIENUM_CONTINUE;
381 /* Function to update the state of a joystick - called as a device poll.
382 * This function shouldn't update the joystick structure directly,
383 * but instead should call SDL_PrivateJoystick*() to deliver events
384 * and update joystick device state.
387 SDL_SYS_JoystickUpdate_Polled(SDL_Joystick * joystick)
394 IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
395 sizeof(DIJOYSTATE2), &state);
396 if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
397 IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
399 IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
400 sizeof(DIJOYSTATE2), &state);
403 /* Set each known axis, button and POV. */
404 for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
405 const input_t *in = &joystick->hwdata->Inputs[i];
411 SDL_PrivateJoystickAxis_Int(joystick, in->num,
415 SDL_PrivateJoystickAxis_Int(joystick, in->num,
419 SDL_PrivateJoystickAxis_Int(joystick, in->num,
423 SDL_PrivateJoystickAxis_Int(joystick, in->num,
427 SDL_PrivateJoystickAxis_Int(joystick, in->num,
431 SDL_PrivateJoystickAxis_Int(joystick, in->num,
434 case DIJOFS_SLIDER(0):
435 SDL_PrivateJoystickAxis_Int(joystick, in->num,
436 (Sint16) state.rglSlider[0]);
438 case DIJOFS_SLIDER(1):
439 SDL_PrivateJoystickAxis_Int(joystick, in->num,
440 (Sint16) state.rglSlider[1]);
447 SDL_PrivateJoystickButton_Int(joystick, in->num,
456 Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs -
458 SDL_PrivateJoystickHat_Int(joystick, in->num, pos);
466 SDL_SYS_JoystickUpdate_Buffered(SDL_Joystick * joystick)
471 DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
473 numevents = INPUT_QSIZE;
475 IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
476 sizeof(DIDEVICEOBJECTDATA), evtbuf,
478 if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
479 IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
481 IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
482 sizeof(DIDEVICEOBJECTDATA),
483 evtbuf, &numevents, 0);
486 /* Handle the events or punt */
490 for (i = 0; i < (int) numevents; ++i) {
493 for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
494 const input_t *in = &joystick->hwdata->Inputs[j];
496 if (evtbuf[i].dwOfs != in->ofs)
501 SDL_PrivateJoystickAxis(joystick, in->num,
502 (Sint16) evtbuf[i].dwData);
505 SDL_PrivateJoystickButton(joystick, in->num,
507 dwData ? SDL_PRESSED :
512 Uint8 pos = TranslatePOV(evtbuf[i].dwData);
513 SDL_PrivateJoystickHat(joystick, in->num, pos);
522 TranslatePOV(DWORD value)
524 const int HAT_VALS[] = {
526 SDL_HAT_UP | SDL_HAT_RIGHT,
528 SDL_HAT_DOWN | SDL_HAT_RIGHT,
530 SDL_HAT_DOWN | SDL_HAT_LEFT,
532 SDL_HAT_UP | SDL_HAT_LEFT
535 if (LOWORD(value) == 0xFFFF)
536 return SDL_HAT_CENTERED;
538 /* Round the value up: */
544 return SDL_HAT_CENTERED; /* shouldn't happen */
546 return HAT_VALS[value];
549 /* SDL_PrivateJoystick* doesn't discard duplicate events, so we need to
552 SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
554 if (joystick->axes[axis] != value)
555 return SDL_PrivateJoystickAxis(joystick, axis, value);
560 SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
562 if (joystick->hats[hat] != value)
563 return SDL_PrivateJoystickHat(joystick, hat, value);
568 SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick, Uint8 button,
571 if (joystick->buttons[button] != state)
572 return SDL_PrivateJoystickButton(joystick, button, state);
577 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
581 result = IDirectInputDevice2_Poll(joystick->hwdata->InputDevice);
582 if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
583 IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
584 IDirectInputDevice2_Poll(joystick->hwdata->InputDevice);
587 if (joystick->hwdata->buffered)
588 SDL_SYS_JoystickUpdate_Buffered(joystick);
590 SDL_SYS_JoystickUpdate_Polled(joystick);
593 /* Function to close a joystick after use */
595 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
597 IDirectInputDevice2_Unacquire(joystick->hwdata->InputDevice);
598 IDirectInputDevice2_Release(joystick->hwdata->InputDevice);
600 if (joystick->hwdata != NULL) {
601 /* free system specific hardware data */
602 SDL_free(joystick->hwdata);
606 /* Function to perform any system-specific joystick related cleanup */
608 SDL_SYS_JoystickQuit(void)
610 IDirectInput_Release(dinput);
614 #endif /* SDL_JOYSTICK_DINPUT */
615 /* vi: set ts=4 sw=4 expandtab: */