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