src/haptic/windows/SDL_windowshaptic.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 26 May 2015 06:27:46 -0700
changeset 9619 b94b6d0bff0f
parent 8972 dfc759d7486f
child 9740 55e88e3bc7cc
permissions -rw-r--r--
Updated the copyright year to 2015
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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  */
    45 SDL_hapticlist_item *SDL_hapticlist = NULL;
    46 static SDL_hapticlist_item *SDL_hapticlist_tail = NULL;
    47 static int numhaptics = 0;
    48 
    49 
    50 /*
    51  * Initializes the haptic subsystem.
    52  */
    53 int
    54 SDL_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 
    65 int
    66 SDL_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 
    81 int
    82 SDL_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 
   100 int
   101 SDL_SYS_NumHaptics()
   102 {
   103     return numhaptics;
   104 }
   105 
   106 static SDL_hapticlist_item *
   107 HapticByDevIndex(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  */
   126 const char *
   127 SDL_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  */
   136 int
   137 SDL_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  */
   151 int
   152 SDL_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  */
   173 int
   174 SDL_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  */
   193 int
   194 SDL_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  */
   208 int
   209 SDL_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  */
   221 void
   222 SDL_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  */
   247 void
   248 SDL_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  */
   280 int
   281 SDL_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  */
   310 int
   311 SDL_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  */
   325 int
   326 SDL_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  */
   339 int
   340 SDL_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  */
   352 void
   353 SDL_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  */
   367 int
   368 SDL_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  */
   381 int
   382 SDL_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  */
   394 int
   395 SDL_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  */
   407 int
   408 SDL_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  */
   420 int
   421 SDL_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  */
   433 int
   434 SDL_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: */