Example #1
0
int
SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
{
    const Uint8 userId = joystickdevice->XInputUserId;
    XINPUT_CAPABILITIES capabilities;
    XINPUT_VIBRATION state;

    SDL_assert(s_bXInputEnabled);
    SDL_assert(XINPUTGETCAPABILITIES);
    SDL_assert(XINPUTSETSTATE);
    SDL_assert(userId < XUSER_MAX_COUNT);

    joystick->hwdata->bXInputDevice = SDL_TRUE;

    if (XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities) != ERROR_SUCCESS) {
        SDL_free(joystick->hwdata);
        joystick->hwdata = NULL;
        return SDL_SetError("Failed to obtain XInput device capabilities. Device disconnected?");
    }
    SDL_zero(state);
    joystick->hwdata->bXInputHaptic = (XINPUTSETSTATE(userId, &state) == ERROR_SUCCESS);
    joystick->hwdata->userid = userId;

    /* The XInput API has a hard coded button/axis mapping, so we just match it */
    if (SDL_XInputUseOldJoystickMapping()) {
        joystick->naxes = 6;
        joystick->nbuttons = 15;
    } else {
        joystick->naxes = 6;
        joystick->nbuttons = 11;
        joystick->nhats = 1;
    }
    return 0;
}
Example #2
0
static int
SDL_SYS_HapticOpenFromXInput(SDL_Haptic * haptic, Uint8 userid)
{
    char threadName[32];
    XINPUT_VIBRATION vibration = { 0, 0 };  /* stop any current vibration */
    XINPUTSETSTATE(userid, &vibration);

    /* !!! FIXME: we can probably do more than SINE if we figure out how to set up the left and right motors properly. */
    haptic->supported = SDL_HAPTIC_SINE;

    haptic->neffects = 1;
    haptic->nplaying = 1;

    /* Prepare effects memory. */
    haptic->effects = (struct haptic_effect *)
        SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
    if (haptic->effects == NULL) {
        return SDL_OutOfMemory();
    }
    /* Clear the memory */
    SDL_memset(haptic->effects, 0,
               sizeof(struct haptic_effect) * haptic->neffects);

    haptic->hwdata = (struct haptic_hwdata *) SDL_malloc(sizeof(*haptic->hwdata));
    if (haptic->hwdata == NULL) {
        SDL_free(haptic->effects);
        haptic->effects = NULL;
        return SDL_OutOfMemory();
    }
    SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));

    haptic->hwdata->bXInputHaptic = 1;
    haptic->hwdata->userid = userid;

    haptic->hwdata->mutex = SDL_CreateMutex();
    if (haptic->hwdata->mutex == NULL) {
        SDL_free(haptic->effects);
        SDL_free(haptic->hwdata);
        haptic->effects = NULL;
        return SDL_SetError("Couldn't create XInput haptic mutex");
    }

    SDL_snprintf(threadName, sizeof (threadName), "SDLXInputDev%d", (int) userid);

#if defined(__WIN32__) && !defined(HAVE_LIBC)  /* !!! FIXME: this is nasty. */
    #undef SDL_CreateThread
    haptic->hwdata->thread = SDL_CreateThread(SDL_RunXInputHaptic, threadName, haptic->hwdata, NULL, NULL);
#else
    haptic->hwdata->thread = SDL_CreateThread(SDL_RunXInputHaptic, threadName, haptic->hwdata);
#endif
    if (haptic->hwdata->thread == NULL) {
        SDL_DestroyMutex(haptic->hwdata->mutex);
        SDL_free(haptic->effects);
        SDL_free(haptic->hwdata);
        haptic->effects = NULL;
        return SDL_SetError("Couldn't create XInput haptic thread");
    }

    return 0;
 }
Example #3
0
/*
 * Runs an effect.
 */
int
SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
                        Uint32 iterations)
{
    HRESULT ret;
    DWORD iter;

    if (haptic->hwdata->bXInputHaptic) {
        XINPUT_VIBRATION *vib = &effect->hweffect->vibration;
        SDL_assert(effect->effect.type == SDL_HAPTIC_SINE);  /* should catch this at higher level */
        SDL_LockMutex(haptic->hwdata->mutex);
        haptic->hwdata->stopTicks = SDL_GetTicks() + (effect->effect.periodic.length * iterations);
        SDL_UnlockMutex(haptic->hwdata->mutex);
        return (XINPUTSETSTATE(haptic->hwdata->userid, vib) == ERROR_SUCCESS) ? 0 : -1;
    }

    /* Check if it's infinite. */
    if (iterations == SDL_HAPTIC_INFINITY) {
        iter = INFINITE;
    } else
        iter = iterations;

    /* Run the effect. */
    ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0);
    if (FAILED(ret)) {
        return DI_SetError("Running the effect", ret);
    }

    return 0;
}
int
SDL_XINPUT_HapticStopAll(SDL_Haptic * haptic)
{
    XINPUT_VIBRATION vibration = { 0, 0 };
    SDL_LockMutex(haptic->hwdata->mutex);
    haptic->hwdata->stopTicks = 0;
    SDL_UnlockMutex(haptic->hwdata->mutex);
    return (XINPUTSETSTATE(haptic->hwdata->userid, &vibration) == ERROR_SUCCESS) ? 0 : -1;
}
static int
SDL_XINPUT_HapticOpenFromUserIndex(SDL_Haptic *haptic, const Uint8 userid)
{
    char threadName[32];
    XINPUT_VIBRATION vibration = { 0, 0 };  /* stop any current vibration */
    XINPUTSETSTATE(userid, &vibration);

    haptic->supported = SDL_HAPTIC_LEFTRIGHT;

    haptic->neffects = 1;
    haptic->nplaying = 1;

    /* Prepare effects memory. */
    haptic->effects = (struct haptic_effect *)
        SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
    if (haptic->effects == NULL) {
        return SDL_OutOfMemory();
    }
    /* Clear the memory */
    SDL_memset(haptic->effects, 0,
        sizeof(struct haptic_effect) * haptic->neffects);

    haptic->hwdata = (struct haptic_hwdata *) SDL_malloc(sizeof(*haptic->hwdata));
    if (haptic->hwdata == NULL) {
        SDL_free(haptic->effects);
        haptic->effects = NULL;
        return SDL_OutOfMemory();
    }
    SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));

    haptic->hwdata->bXInputHaptic = 1;
    haptic->hwdata->userid = userid;

    haptic->hwdata->mutex = SDL_CreateMutex();
    if (haptic->hwdata->mutex == NULL) {
        SDL_free(haptic->effects);
        SDL_free(haptic->hwdata);
        haptic->effects = NULL;
        return SDL_SetError("Couldn't create XInput haptic mutex");
    }

    SDL_snprintf(threadName, sizeof(threadName), "SDLXInputDev%d", (int)userid);
    haptic->hwdata->thread = SDL_CreateThreadInternal(SDL_RunXInputHaptic, threadName, 64 * 1024, haptic->hwdata);

    if (haptic->hwdata->thread == NULL) {
        SDL_DestroyMutex(haptic->hwdata->mutex);
        SDL_free(haptic->effects);
        SDL_free(haptic->hwdata);
        haptic->effects = NULL;
        return SDL_SetError("Couldn't create XInput haptic thread");
    }

    return 0;
}
int
SDL_XINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data)
{
    XINPUT_VIBRATION *vib = &effect->hweffect->vibration;
    SDL_assert(data->type == SDL_HAPTIC_LEFTRIGHT);
    vib->wLeftMotorSpeed = data->leftright.large_magnitude;
    vib->wRightMotorSpeed = data->leftright.small_magnitude;
    SDL_LockMutex(haptic->hwdata->mutex);
    if (haptic->hwdata->stopTicks) {  /* running right now? Update it. */
        XINPUTSETSTATE(haptic->hwdata->userid, vib);
    }
    SDL_UnlockMutex(haptic->hwdata->mutex);
    return 0;
}
int
SDL_XINPUT_MaybeAddDevice(const DWORD dwUserid)
{
    const Uint8 userid = (Uint8)dwUserid;
    SDL_hapticlist_item *item;
    XINPUT_VIBRATION state;

    if ((!loaded_xinput) || (dwUserid >= XUSER_MAX_COUNT)) {
        return -1;
    }

    /* Make sure we don't already have it */
    for (item = SDL_hapticlist; item; item = item->next) {
        if (item->bXInputHaptic && item->userid == userid) {
            return -1;  /* Already added */
        }
    }

    SDL_zero(state);
    if (XINPUTSETSTATE(dwUserid, &state) != ERROR_SUCCESS) {
        return -1;  /* no force feedback on this device. */
    }

    item = (SDL_hapticlist_item *)SDL_malloc(sizeof(SDL_hapticlist_item));
    if (item == NULL) {
        return SDL_OutOfMemory();
    }

    SDL_zerop(item);

    /* !!! FIXME: I'm not bothering to query for a real name right now (can we even?) */
    {
        char buf[64];
        SDL_snprintf(buf, sizeof(buf), "XInput Controller #%u", (unsigned int)(userid + 1));
        item->name = SDL_strdup(buf);
    }

    if (!item->name) {
        SDL_free(item);
        return -1;
    }

    /* Copy the instance over, useful for creating devices. */
    item->bXInputHaptic = SDL_TRUE;
    item->userid = userid;

    return SDL_SYS_AddHapticDevice(item);
}
int
SDL_XINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations)
{
    XINPUT_VIBRATION *vib = &effect->hweffect->vibration;
    SDL_assert(effect->effect.type == SDL_HAPTIC_LEFTRIGHT);  /* should catch this at higher level */
    SDL_LockMutex(haptic->hwdata->mutex);
    if (effect->effect.leftright.length == SDL_HAPTIC_INFINITY || iterations == SDL_HAPTIC_INFINITY) {
        haptic->hwdata->stopTicks = SDL_HAPTIC_INFINITY;
    } else if ((!effect->effect.leftright.length) || (!iterations)) {
        /* do nothing. Effect runs for zero milliseconds. */
    } else {
        haptic->hwdata->stopTicks = SDL_GetTicks() + (effect->effect.leftright.length * iterations);
        if ((haptic->hwdata->stopTicks == SDL_HAPTIC_INFINITY) || (haptic->hwdata->stopTicks == 0)) {
            haptic->hwdata->stopTicks = 1;  /* fix edge cases. */
        }
    }
    SDL_UnlockMutex(haptic->hwdata->mutex);
    return (XINPUTSETSTATE(haptic->hwdata->userid, vib) == ERROR_SUCCESS) ? 0 : -1;
}
Example #9
0
/* Since XInput doesn't offer a way to vibrate for X time, we hook into
 *  SDL_PumpEvents() to check if it's time to stop vibrating with some
 *  frequency.
 * In practice, this works for 99% of use cases. But in an ideal world,
 *  we do this in a separate thread so that:
 *    - we aren't bound to when the app chooses to pump the event queue.
 *    - we aren't adding more polling to the event queue
 *    - we can emulate all the haptic effects correctly (start on a delay,
 *      mix multiple effects, etc).
 *
 * Mostly, this is here to get rumbling to work, and all the other features
 *  are absent in the XInput path for now.  :(
 */
static int SDLCALL
SDL_RunXInputHaptic(void *arg)
{
    struct haptic_hwdata *hwdata = (struct haptic_hwdata *) arg;

    while (!hwdata->stopThread) {
        SDL_Delay(50);
        SDL_LockMutex(hwdata->mutex);
        /* If we're currently running and need to stop... */
        if ((hwdata->stopTicks) && (hwdata->stopTicks < SDL_GetTicks())) {
            XINPUT_VIBRATION vibration = { 0, 0 };
            hwdata->stopTicks = 0;
            XINPUTSETSTATE(hwdata->userid, &vibration);
        }
        SDL_UnlockMutex(hwdata->mutex);
    }

    return 0;
}
Example #10
0
/*
 * Stops an effect.
 */
int
SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
{
    HRESULT ret;

    if (haptic->hwdata->bXInputHaptic) {
        XINPUT_VIBRATION vibration = { 0, 0 };
        SDL_LockMutex(haptic->hwdata->mutex);
        haptic->hwdata->stopTicks = 0;
        SDL_UnlockMutex(haptic->hwdata->mutex);
        return (XINPUTSETSTATE(haptic->hwdata->userid, &vibration) == ERROR_SUCCESS) ? 0 : -1;
    }

    ret = IDirectInputEffect_Stop(effect->hweffect->ref);
    if (FAILED(ret)) {
        return DI_SetError("Unable to stop effect", ret);
    }

    return 0;
}
/* Since XInput doesn't offer a way to vibrate for X time, we hook into
 *  SDL_PumpEvents() to check if it's time to stop vibrating with some
 *  frequency.
 * In practice, this works for 99% of use cases. But in an ideal world,
 *  we do this in a separate thread so that:
 *    - we aren't bound to when the app chooses to pump the event queue.
 *    - we aren't adding more polling to the event queue
 *    - we can emulate all the haptic effects correctly (start on a delay,
 *      mix multiple effects, etc).
 *
 * Mostly, this is here to get rumbling to work, and all the other features
 *  are absent in the XInput path for now.  :(
 */
static int SDLCALL
SDL_RunXInputHaptic(void *arg)
{
    struct haptic_hwdata *hwdata = (struct haptic_hwdata *) arg;

    while (!SDL_AtomicGet(&hwdata->stopThread)) {
        SDL_Delay(50);
        SDL_LockMutex(hwdata->mutex);
        /* If we're currently running and need to stop... */
        if (hwdata->stopTicks) {
            if ((hwdata->stopTicks != SDL_HAPTIC_INFINITY) && SDL_TICKS_PASSED(SDL_GetTicks(), hwdata->stopTicks)) {
                XINPUT_VIBRATION vibration = { 0, 0 };
                hwdata->stopTicks = 0;
                XINPUTSETSTATE(hwdata->userid, &vibration);
            }
        }
        SDL_UnlockMutex(hwdata->mutex);
    }

    return 0;
}
Example #12
0
int
SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
{
    XINPUT_VIBRATION XVibration;

    if (!XINPUTSETSTATE) {
        return SDL_Unsupported();
    }

    XVibration.wLeftMotorSpeed = low_frequency_rumble;
    XVibration.wRightMotorSpeed = high_frequency_rumble;
    if (XINPUTSETSTATE(joystick->hwdata->userid, &XVibration) != ERROR_SUCCESS) {
        return SDL_SetError("XInputSetState() failed");
    }

    if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
        joystick->hwdata->rumble_expiration = SDL_GetTicks() + duration_ms;
    } else {
        joystick->hwdata->rumble_expiration = 0;
    }
    return 0;
}
Example #13
0
/*
 * Stops all the playing effects on the device.
 */
int
SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
{
    HRESULT ret;

    if (haptic->hwdata->bXInputHaptic) {
        XINPUT_VIBRATION vibration = { 0, 0 };
        SDL_LockMutex(haptic->hwdata->mutex);
        haptic->hwdata->stopTicks = 0;
        SDL_UnlockMutex(haptic->hwdata->mutex);
        return (XINPUTSETSTATE(haptic->hwdata->userid, &vibration) == ERROR_SUCCESS) ? 0 : -1;
    }

    /* Try to stop the effects. */
    ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
                                                       DISFFC_STOPALL);
    if (FAILED(ret)) {
        return DI_SetError("Stopping the device", ret);
    }

    return 0;
}
Example #14
0
static int
SDL_XINPUT_HapticOpenFromUserIndex(SDL_Haptic *haptic, const Uint8 userid)
{
    char threadName[32];
    XINPUT_VIBRATION vibration = { 0, 0 };  /* stop any current vibration */
    XINPUTSETSTATE(userid, &vibration);

    haptic->supported = SDL_HAPTIC_LEFTRIGHT;

    haptic->neffects = 1;
    haptic->nplaying = 1;

    /* Prepare effects memory. */
    haptic->effects = (struct haptic_effect *)
        SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
    if (haptic->effects == NULL) {
        return SDL_OutOfMemory();
    }
    /* Clear the memory */
    SDL_memset(haptic->effects, 0,
        sizeof(struct haptic_effect) * haptic->neffects);

    haptic->hwdata = (struct haptic_hwdata *) SDL_malloc(sizeof(*haptic->hwdata));
    if (haptic->hwdata == NULL) {
        SDL_free(haptic->effects);
        haptic->effects = NULL;
        return SDL_OutOfMemory();
    }
    SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));

    haptic->hwdata->bXInputHaptic = 1;
    haptic->hwdata->userid = userid;

    haptic->hwdata->mutex = SDL_CreateMutex();
    if (haptic->hwdata->mutex == NULL) {
        SDL_free(haptic->effects);
        SDL_free(haptic->hwdata);
        haptic->effects = NULL;
        return SDL_SetError("Couldn't create XInput haptic mutex");
    }

    SDL_snprintf(threadName, sizeof(threadName), "SDLXInputDev%d", (int)userid);

#if defined(__WIN32__) && !defined(HAVE_LIBC)  /* !!! FIXME: this is nasty. */
#undef SDL_CreateThread
#if SDL_DYNAMIC_API
    haptic->hwdata->thread = SDL_CreateThread_REAL(SDL_RunXInputHaptic, threadName, haptic->hwdata, NULL, NULL);
#else
    haptic->hwdata->thread = SDL_CreateThread(SDL_RunXInputHaptic, threadName, haptic->hwdata, NULL, NULL);
#endif
#else
    haptic->hwdata->thread = SDL_CreateThread(SDL_RunXInputHaptic, threadName, haptic->hwdata);
#endif
    if (haptic->hwdata->thread == NULL) {
        SDL_DestroyMutex(haptic->hwdata->mutex);
        SDL_free(haptic->effects);
        SDL_free(haptic->hwdata);
        haptic->effects = NULL;
        return SDL_SetError("Couldn't create XInput haptic thread");
    }

    return 0;
}