SDL_windowshaptic.c (10847B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#if SDL_HAPTIC_DINPUT || SDL_HAPTIC_XINPUT 24 25#include "SDL_assert.h" 26#include "SDL_thread.h" 27#include "SDL_mutex.h" 28#include "SDL_timer.h" 29#include "SDL_hints.h" 30#include "SDL_haptic.h" 31#include "../SDL_syshaptic.h" 32#include "SDL_joystick.h" 33#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */ 34#include "../../joystick/windows/SDL_windowsjoystick_c.h" /* For joystick hwdata */ 35#include "../../joystick/windows/SDL_xinputjoystick_c.h" /* For xinput rumble */ 36 37#include "SDL_windowshaptic_c.h" 38#include "SDL_dinputhaptic_c.h" 39#include "SDL_xinputhaptic_c.h" 40 41 42/* 43 * Internal stuff. 44 */ 45SDL_hapticlist_item *SDL_hapticlist = NULL; 46static SDL_hapticlist_item *SDL_hapticlist_tail = NULL; 47static int numhaptics = 0; 48 49 50/* 51 * Initializes the haptic subsystem. 52 */ 53int 54SDL_SYS_HapticInit(void) 55{ 56 if (SDL_DINPUT_HapticInit() < 0) { 57 return -1; 58 } 59 if (SDL_XINPUT_HapticInit() < 0) { 60 return -1; 61 } 62 return numhaptics; 63} 64 65int 66SDL_SYS_AddHapticDevice(SDL_hapticlist_item *item) 67{ 68 if (SDL_hapticlist_tail == NULL) { 69 SDL_hapticlist = SDL_hapticlist_tail = item; 70 } else { 71 SDL_hapticlist_tail->next = item; 72 SDL_hapticlist_tail = item; 73 } 74 75 /* Device has been added. */ 76 ++numhaptics; 77 78 return numhaptics; 79} 80 81int 82SDL_SYS_RemoveHapticDevice(SDL_hapticlist_item *prev, SDL_hapticlist_item *item) 83{ 84 const int retval = item->haptic ? item->haptic->index : -1; 85 if (prev != NULL) { 86 prev->next = item->next; 87 } else { 88 SDL_assert(SDL_hapticlist == item); 89 SDL_hapticlist = item->next; 90 } 91 if (item == SDL_hapticlist_tail) { 92 SDL_hapticlist_tail = prev; 93 } 94 --numhaptics; 95 /* !!! TODO: Send a haptic remove event? */ 96 SDL_free(item); 97 return retval; 98} 99 100int 101SDL_SYS_NumHaptics() 102{ 103 return numhaptics; 104} 105 106static SDL_hapticlist_item * 107HapticByDevIndex(int device_index) 108{ 109 SDL_hapticlist_item *item = SDL_hapticlist; 110 111 if ((device_index < 0) || (device_index >= numhaptics)) { 112 return NULL; 113 } 114 115 while (device_index > 0) { 116 SDL_assert(item != NULL); 117 --device_index; 118 item = item->next; 119 } 120 return item; 121} 122 123/* 124 * Return the name of a haptic device, does not need to be opened. 125 */ 126const char * 127SDL_SYS_HapticName(int index) 128{ 129 SDL_hapticlist_item *item = HapticByDevIndex(index); 130 return item->name; 131} 132 133/* 134 * Opens a haptic device for usage. 135 */ 136int 137SDL_SYS_HapticOpen(SDL_Haptic * haptic) 138{ 139 SDL_hapticlist_item *item = HapticByDevIndex(haptic->index); 140 if (item->bXInputHaptic) { 141 return SDL_XINPUT_HapticOpen(haptic, item); 142 } else { 143 return SDL_DINPUT_HapticOpen(haptic, item); 144 } 145} 146 147 148/* 149 * Opens a haptic device from first mouse it finds for usage. 150 */ 151int 152SDL_SYS_HapticMouse(void) 153{ 154#if SDL_HAPTIC_DINPUT 155 SDL_hapticlist_item *item; 156 int index = 0; 157 158 /* Grab the first mouse haptic device we find. */ 159 for (item = SDL_hapticlist; item != NULL; item = item->next) { 160 if (item->capabilities.dwDevType == DI8DEVCLASS_POINTER ) { 161 return index; 162 } 163 ++index; 164 } 165#endif /* SDL_HAPTIC_DINPUT */ 166 return -1; 167} 168 169 170/* 171 * Checks to see if a joystick has haptic features. 172 */ 173int 174SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick) 175{ 176 const struct joystick_hwdata *hwdata = joystick->hwdata; 177#if SDL_HAPTIC_XINPUT 178 if (hwdata->bXInputHaptic) { 179 return 1; 180 } 181#endif 182#if SDL_HAPTIC_DINPUT 183 if (hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) { 184 return 1; 185 } 186#endif 187 return 0; 188} 189 190/* 191 * Checks to see if the haptic device and joystick are in reality the same. 192 */ 193int 194SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) 195{ 196 if (joystick->hwdata->bXInputHaptic != haptic->hwdata->bXInputHaptic) { 197 return 0; /* one is XInput, one is not; not the same device. */ 198 } else if (joystick->hwdata->bXInputHaptic) { 199 return SDL_XINPUT_JoystickSameHaptic(haptic, joystick); 200 } else { 201 return SDL_DINPUT_JoystickSameHaptic(haptic, joystick); 202 } 203} 204 205/* 206 * Opens a SDL_Haptic from a SDL_Joystick. 207 */ 208int 209SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) 210{ 211 if (joystick->hwdata->bXInputDevice) { 212 return SDL_XINPUT_HapticOpenFromJoystick(haptic, joystick); 213 } else { 214 return SDL_DINPUT_HapticOpenFromJoystick(haptic, joystick); 215 } 216} 217 218/* 219 * Closes the haptic device. 220 */ 221void 222SDL_SYS_HapticClose(SDL_Haptic * haptic) 223{ 224 if (haptic->hwdata) { 225 226 /* Free effects. */ 227 SDL_free(haptic->effects); 228 haptic->effects = NULL; 229 haptic->neffects = 0; 230 231 /* Clean up */ 232 if (haptic->hwdata->bXInputHaptic) { 233 SDL_XINPUT_HapticClose(haptic); 234 } else { 235 SDL_DINPUT_HapticClose(haptic); 236 } 237 238 /* Free */ 239 SDL_free(haptic->hwdata); 240 haptic->hwdata = NULL; 241 } 242} 243 244/* 245 * Clean up after system specific haptic stuff 246 */ 247void 248SDL_SYS_HapticQuit(void) 249{ 250 SDL_hapticlist_item *item; 251 SDL_hapticlist_item *next = NULL; 252 SDL_Haptic *hapticitem = NULL; 253 254 extern SDL_Haptic *SDL_haptics; 255 for (hapticitem = SDL_haptics; hapticitem; hapticitem = hapticitem->next) { 256 if ((hapticitem->hwdata->bXInputHaptic) && (hapticitem->hwdata->thread)) { 257 /* we _have_ to stop the thread before we free the XInput DLL! */ 258 hapticitem->hwdata->stopThread = 1; 259 SDL_WaitThread(hapticitem->hwdata->thread, NULL); 260 hapticitem->hwdata->thread = NULL; 261 } 262 } 263 264 for (item = SDL_hapticlist; item; item = next) { 265 /* Opened and not closed haptics are leaked, this is on purpose. 266 * Close your haptic devices after usage. */ 267 /* !!! FIXME: (...is leaking on purpose a good idea?) - No, of course not. */ 268 next = item->next; 269 SDL_free(item->name); 270 SDL_free(item); 271 } 272 273 SDL_XINPUT_HapticQuit(); 274 SDL_DINPUT_HapticQuit(); 275} 276 277/* 278 * Creates a new haptic effect. 279 */ 280int 281SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, 282 SDL_HapticEffect * base) 283{ 284 int result; 285 286 /* Alloc the effect. */ 287 effect->hweffect = (struct haptic_hweffect *) 288 SDL_malloc(sizeof(struct haptic_hweffect)); 289 if (effect->hweffect == NULL) { 290 SDL_OutOfMemory(); 291 return -1; 292 } 293 SDL_zerop(effect->hweffect); 294 295 if (haptic->hwdata->bXInputHaptic) { 296 result = SDL_XINPUT_HapticNewEffect(haptic, effect, base); 297 } else { 298 result = SDL_DINPUT_HapticNewEffect(haptic, effect, base); 299 } 300 if (result < 0) { 301 SDL_free(effect->hweffect); 302 effect->hweffect = NULL; 303 } 304 return result; 305} 306 307/* 308 * Updates an effect. 309 */ 310int 311SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, 312 struct haptic_effect *effect, 313 SDL_HapticEffect * data) 314{ 315 if (haptic->hwdata->bXInputHaptic) { 316 return SDL_XINPUT_HapticUpdateEffect(haptic, effect, data); 317 } else { 318 return SDL_DINPUT_HapticUpdateEffect(haptic, effect, data); 319 } 320} 321 322/* 323 * Runs an effect. 324 */ 325int 326SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, 327 Uint32 iterations) 328{ 329 if (haptic->hwdata->bXInputHaptic) { 330 return SDL_XINPUT_HapticRunEffect(haptic, effect, iterations); 331 } else { 332 return SDL_DINPUT_HapticRunEffect(haptic, effect, iterations); 333 } 334} 335 336/* 337 * Stops an effect. 338 */ 339int 340SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect) 341{ 342 if (haptic->hwdata->bXInputHaptic) { 343 return SDL_XINPUT_HapticStopEffect(haptic, effect); 344 } else { 345 return SDL_DINPUT_HapticStopEffect(haptic, effect); 346 } 347} 348 349/* 350 * Frees the effect. 351 */ 352void 353SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect) 354{ 355 if (haptic->hwdata->bXInputHaptic) { 356 SDL_XINPUT_HapticDestroyEffect(haptic, effect); 357 } else { 358 SDL_DINPUT_HapticDestroyEffect(haptic, effect); 359 } 360 SDL_free(effect->hweffect); 361 effect->hweffect = NULL; 362} 363 364/* 365 * Gets the status of a haptic effect. 366 */ 367int 368SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, 369 struct haptic_effect *effect) 370{ 371 if (haptic->hwdata->bXInputHaptic) { 372 return SDL_XINPUT_HapticGetEffectStatus(haptic, effect); 373 } else { 374 return SDL_DINPUT_HapticGetEffectStatus(haptic, effect); 375 } 376} 377 378/* 379 * Sets the gain. 380 */ 381int 382SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) 383{ 384 if (haptic->hwdata->bXInputHaptic) { 385 return SDL_XINPUT_HapticSetGain(haptic, gain); 386 } else { 387 return SDL_DINPUT_HapticSetGain(haptic, gain); 388 } 389} 390 391/* 392 * Sets the autocentering. 393 */ 394int 395SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) 396{ 397 if (haptic->hwdata->bXInputHaptic) { 398 return SDL_XINPUT_HapticSetAutocenter(haptic, autocenter); 399 } else { 400 return SDL_DINPUT_HapticSetAutocenter(haptic, autocenter); 401 } 402} 403 404/* 405 * Pauses the device. 406 */ 407int 408SDL_SYS_HapticPause(SDL_Haptic * haptic) 409{ 410 if (haptic->hwdata->bXInputHaptic) { 411 return SDL_XINPUT_HapticPause(haptic); 412 } else { 413 return SDL_DINPUT_HapticPause(haptic); 414 } 415} 416 417/* 418 * Pauses the device. 419 */ 420int 421SDL_SYS_HapticUnpause(SDL_Haptic * haptic) 422{ 423 if (haptic->hwdata->bXInputHaptic) { 424 return SDL_XINPUT_HapticUnpause(haptic); 425 } else { 426 return SDL_DINPUT_HapticUnpause(haptic); 427 } 428} 429 430/* 431 * Stops all the playing effects on the device. 432 */ 433int 434SDL_SYS_HapticStopAll(SDL_Haptic * haptic) 435{ 436 if (haptic->hwdata->bXInputHaptic) { 437 return SDL_XINPUT_HapticStopAll(haptic); 438 } else { 439 return SDL_DINPUT_HapticStopAll(haptic); 440 } 441} 442 443#endif /* SDL_HAPTIC_DINPUT || SDL_HAPTIC_XINPUT */ 444 445/* vi: set ts=4 sw=4 expandtab: */