コード例 #1
0
void JoyInitHaptic() {
#if 0
    uint8_t i;
    unsigned int haptic_query = 0;
    for (i = 0; i < 2; i++) {
        if (g.PadState[i].JoyDev && SDL_JoystickIsHaptic(g.PadState[i].JoyDev)) {
            if (g.PadState[i].haptic != NULL) {
                SDL_HapticClose(g.PadState[i].haptic);
                g.PadState[i].haptic = NULL;
            }

            g.PadState[i].haptic = SDL_HapticOpenFromJoystick(g.PadState[i].JoyDev);
            if (g.PadState[i].haptic == NULL)
                continue;

            if (SDL_HapticRumbleSupported(g.PadState[i].haptic) == SDL_FALSE) {
                printf("\nRumble not supported\n");
                g.PadState[i].haptic = NULL;
                continue;
            }

            if (SDL_HapticRumbleInit(g.PadState[i].haptic) != 0) {
                printf("\nFailed to initialize rumble: %s\n", SDL_GetError());
                g.PadState[i].haptic = NULL;
                continue;
            }
        }
    }
#endif
}
コード例 #2
0
ファイル: SDLFrontend.cpp プロジェクト: ptitSeb/caveexpress
void SDLFrontend::initJoystickAndHaptic ()
{
	if (_haptic != nullptr) {
		SDL_HapticClose(_haptic);
		_haptic = nullptr;
	}

	const int joysticks = SDL_NumJoysticks();
	SDL_Haptic *haptic = nullptr;
	for (int i = 0; i < joysticks; i++) {
		const char *name;
		if (SDL_IsGameController(i)) {
			name = SDL_GameControllerNameForIndex(i);
		} else {
			name = SDL_JoystickNameForIndex(i);
		}
		SDL_Joystick *joystick = SDL_JoystickOpen(i);
		info(LOG_CLIENT, String::format("found joystick %s", name ? name : "Unknown Joystick"));
		info(LOG_CLIENT, String::format("joystick axes: %i", SDL_JoystickNumAxes(joystick)));
		info(LOG_CLIENT, String::format("joystick hats: %i", SDL_JoystickNumHats(joystick)));
		info(LOG_CLIENT, String::format("joystick balls: %i", SDL_JoystickNumBalls(joystick)));
		info(LOG_CLIENT, String::format("joystick buttons: %i", SDL_JoystickNumButtons(joystick)));
		if (haptic == nullptr)
			haptic = SDL_HapticOpenFromJoystick(joystick);
	}
	if (!joysticks) {
		info(LOG_CLIENT, "no joysticks found");
	}

	info(LOG_CLIENT, String::format("found %i touch device(s)", SDL_GetNumTouchDevices()));

	info(LOG_CLIENT, String::format("%i haptic devices", SDL_NumHaptics()));
	if (haptic == nullptr && SDL_MouseIsHaptic()) {
		haptic = SDL_HapticOpenFromMouse();
	}
	if (haptic != nullptr) {
		const bool rumbleSupported = SDL_HapticRumbleSupported(haptic) && SDL_HapticRumbleInit(haptic) == 0;
		if (rumbleSupported) {
			info(LOG_CLIENT, "rumble support");
			_haptic = haptic;
		}
	}
	if (_haptic == nullptr) {
		info(LOG_CLIENT, "no rumble support");
	}
}
コード例 #3
0
C4GamePadOpener::C4GamePadOpener(int iGamepad)
{
	int n = iGamepad;
	for (int i = 0; i < SDL_NumJoysticks(); i++)
		if (SDL_IsGameController(i) && n-- == 0)
		{
			controller = SDL_GameControllerOpen(i);
			if (!controller) LogF("SDL: %s", SDL_GetError());
			SDL_Joystick *joystick = SDL_GameControllerGetJoystick(controller);
			haptic = SDL_HapticOpenFromJoystick(joystick);
			if (haptic && SDL_HapticRumbleSupported(haptic))
				SDL_HapticRumbleInit(haptic);
			else
				LogF("Gamepad #%d %s does not support rumbling.", SDL_JoystickInstanceID(joystick), SDL_JoystickName(joystick));
			break;
		}

	if (!controller) LogF("Gamepad %d not available", iGamepad);
}
コード例 #4
0
ファイル: Controller.cpp プロジェクト: EthanShimooka/BAA
Controller::Controller(){
	SDL_InitSubSystem(SDL_INIT_JOYSTICK);
	SDL_Init(SDL_INIT_HAPTIC);
	SDL_JoystickEventState(SDL_ENABLE);
	joystick = SDL_JoystickOpen(0);
	if (joystick){
		joystickAnalogs.resize(SDL_JoystickNumAxes(joystick));
		joystickButtonHeld.resize(SDL_JoystickNumButtons(joystick));
		joystickButtonPressed.resize(SDL_JoystickNumButtons(joystick));
		joystickButtonReleased.resize(SDL_JoystickNumButtons(joystick));
		joystickDPad.resize(13);
		haptic = SDL_HapticOpenFromJoystick(joystick);
		if (SDL_HapticRumbleSupported(haptic) == SDL_TRUE){
			SDL_HapticRumbleInit(haptic);
			rumbleSupport = true;
		}
		else rumbleSupport = false;
	}
	
}
コード例 #5
0
ファイル: sdl2-jstest.c プロジェクト: marxjohnson/sdl-jstest
void test_rumble(int joy_idx)
{
  SDL_Joystick* joy = SDL_JoystickOpen(joy_idx);
  if (!joy)
  {
    fprintf(stderr, "Unable to open joystick %d\n", joy_idx);
  }
  else
  {
    SDL_Haptic* haptic = SDL_HapticOpenFromJoystick(joy);
    if (!haptic)
    {
      fprintf(stderr, "Unable to open haptic on joystick %d\n", joy_idx);
      fprintf(stderr, "SDL_Error: %s\n", SDL_GetError());
    }
    else
    {
      if (!SDL_HapticRumbleSupported(haptic))
      {
        fprintf(stderr, "rumble not supported on joystick %d\n", joy_idx);
      }
      else
      {
        if (SDL_HapticRumbleInit(haptic) != 0)
        {
          fprintf(stderr, "failed to init rumble\n");
        }
        else
        {
          SDL_HapticRumblePlay(haptic, 1.0, 3000);
          SDL_Delay(3000);
        }
      }
      SDL_HapticClose(haptic);
    }
    SDL_JoystickClose(joy);
  }
}
コード例 #6
0
ファイル: testrumble.c プロジェクト: spurious/SDL-mirror
/**
 * @brief The entry point of this force feedback demo.
 * @param[in] argc Number of arguments.
 * @param[in] argv Array of argc arguments.
 */
int
main(int argc, char **argv)
{
    int i;
    char *name;
    int index;

    /* Enable standard application logging */
    SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);

    name = NULL;
    index = -1;
    if (argc > 1) {
        size_t l;
        name = argv[1];
        if ((strcmp(name, "--help") == 0) || (strcmp(name, "-h") == 0)) {
            SDL_Log("USAGE: %s [device]\n"
                   "If device is a two-digit number it'll use it as an index, otherwise\n"
                   "it'll use it as if it were part of the device's name.\n",
                   argv[0]);
            return 0;
        }

        l = SDL_strlen(name);
        if ((l < 3) && SDL_isdigit(name[0]) && ((l == 1) || SDL_isdigit(name[1]))) {
            index = SDL_atoi(name);
            name = NULL;
        }
    }

    /* Initialize the force feedbackness */
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK |
             SDL_INIT_HAPTIC);
    SDL_Log("%d Haptic devices detected.\n", SDL_NumHaptics());
    if (SDL_NumHaptics() > 0) {
        /* We'll just use index or the first force feedback device found */
        if (name == NULL) {
            i = (index != -1) ? index : 0;
        }
        /* Try to find matching device */
        else {
            for (i = 0; i < SDL_NumHaptics(); i++) {
                if (strstr(SDL_HapticName(i), name) != NULL)
                    break;
            }

            if (i >= SDL_NumHaptics()) {
                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to find device matching '%s', aborting.\n",
                       name);
                return 1;
            }
        }

        haptic = SDL_HapticOpen(i);
        if (haptic == NULL) {
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s\n",
                   SDL_GetError());
            return 1;
        }
        SDL_Log("Device: %s\n", SDL_HapticName(i));
    } else {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Haptic devices found!\n");
        return 1;
    }

    /* We only want force feedback errors. */
    SDL_ClearError();

    if (SDL_HapticRumbleSupported(haptic) == SDL_FALSE) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Rumble not supported!\n");
        return 1;
    }
    if (SDL_HapticRumbleInit(haptic) != 0) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize rumble: %s\n", SDL_GetError());
        return 1;
    }
    SDL_Log("Playing 2 second rumble at 0.5 magnitude.\n");
    if (SDL_HapticRumblePlay(haptic, 0.5, 5000) != 0) {
       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to play rumble: %s\n", SDL_GetError() );
       return 1;
    }
    SDL_Delay(2000);
    SDL_Log("Stopping rumble.\n");
    SDL_HapticRumbleStop(haptic);
    SDL_Delay(2000);
    SDL_Log("Playing 2 second rumble at 0.3 magnitude.\n");
    if (SDL_HapticRumblePlay(haptic, 0.3f, 5000) != 0) {
       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to play rumble: %s\n", SDL_GetError() );
       return 1;
    }
    SDL_Delay(2000);

    /* Quit */
    if (haptic != NULL)
        SDL_HapticClose(haptic);
    SDL_Quit();

    return 0;
}
コード例 #7
0
void C4GamePadOpener::StopRumble()
{
	if (SDL_HapticRumbleSupported(haptic))
		SDL_HapticRumbleStop(haptic);
}
コード例 #8
0
void C4GamePadOpener::PlayRumble(float strength, uint32_t length)
{
	if (SDL_HapticRumbleSupported(haptic))
		SDL_HapticRumblePlay(haptic, strength, length);
}
コード例 #9
0
ファイル: control.cpp プロジェクト: rongzhou/speed-dreams
// First time (lazy) initialization.
void
gfctrlJoyInit(void)
{
#ifndef SDL_JOYSTICK
    gfctrlJoyPresent = GFCTRL_JOY_NONE;

    for (int index = 0; index < GFCTRL_JOY_NUMBER; index++) {
		if (!Joysticks[index]) {
			Joysticks[index] = new jsJoystick(index);
		}
    
		// Don't configure the joystick if it doesn't work
		if (Joysticks[index]->notWorking()) {
			delete Joysticks[index];
			Joysticks[index] = 0;
		} else {
			gfctrlJoyPresent = GFCTRL_JOY_PRESENT;
		}
    }
#else
#if SDL_MAJOR_VERSION >= 2
    memset(&cfx, 0, sizeof(cfx));

    if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) < 0) {
#else
    if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
#endif
        GfLogError("Couldn't initialize SDL: %s\n", SDL_GetError());
        gfctrlJoyPresent = GFCTRL_JOY_UNTESTED;
	return;
    }
#if SDL_MAJOR_VERSION >= 2
    // Ignore the joystick events, we will poll directly as it is faster
    SDL_JoystickEventState(SDL_IGNORE);
#endif
    gfctrlJoyPresent = SDL_NumJoysticks();
    if (gfctrlJoyPresent > GFCTRL_JOY_NUMBER) gfctrlJoyPresent = GFCTRL_JOY_NUMBER;

    for (int index = 0; index < gfctrlJoyPresent; index++) {
		if (!Joysticks[index]) {
			Joysticks[index] = SDL_JoystickOpen(index);
		}
    
		// Don't configure the joystick if it doesn't work
		if (Joysticks[index] ==  NULL) {
			GfLogError("Couldn't open joystick %d: %s\n", index, SDL_GetError());
#if SDL_MAJOR_VERSION >= 2
		} else {
			cfx_timeout[index] = 0;
			rfx_timeout[index] = 0;
			
			// Find which Haptic device relates to this joystick
			Haptics[index] = SDL_HapticOpenFromJoystick(Joysticks[index]);

			if (!Haptics[index]) {
				GfLogInfo("Joystick %d does not support haptic\n", index);
				break;
#if 0
			} else {
				// add an CF effect on startup
				gfctrlJoyConstantForce(index, 50000, 9000);
#endif
			}

			// Check for Rumble capability
			if (SDL_HapticRumbleSupported(Haptics[index]) == SDL_TRUE) {
				if (SDL_HapticRumbleInit(Haptics[index]) != 0) 
					GfLogError("Couldn't init rumble on joystick %d: %s\n", index, SDL_GetError());
#if 0
				else
					gfctrlJoyRumble(index, 0.5);
#endif
			}
#endif
                }
     }
#endif
}

#if SDL_JOYSTICK
void
gfctrlJoyConstantForce(int index, unsigned int level, int dir)
{
#if SDL_MAJOR_VERSION >= 2
	if (!Haptics[index]) return;

	if ((SDL_HapticQuery(Haptics[index]) & SDL_HAPTIC_CONSTANT) == 0) return;

	cfx[index].type = SDL_HAPTIC_CONSTANT;
	cfx[index].constant.direction.type = SDL_HAPTIC_POLAR;
	cfx[index].constant.direction.dir[0] = dir;
	cfx[index].constant.length = 1000;
	cfx[index].constant.level = level;
	cfx[index].constant.attack_length = 0;
	cfx[index].constant.fade_length = 1000;

#if __WIN32__
	if (SDL_HapticGetEffectStatus(Haptics[index], id[index]) == SDL_TRUE)
#else
	// Linux SDL doesn't support checking status at the moment :-(
	if (cfx_timeout[index] > SDL_GetTicks())
#endif
		SDL_HapticUpdateEffect(Haptics[index], id[index], &cfx[index]);
	else {
		SDL_HapticDestroyEffect(Haptics[index], id[index]);
		id[index] = SDL_HapticNewEffect(Haptics[index], &cfx[index]);
		SDL_HapticRunEffect(Haptics[index], id[index], 1);
	}

	cfx_timeout[index] = SDL_GetTicks() + cfx[index].constant.length;
#endif
}

void
gfctrlJoyRumble(int index, float level)
{
#if SDL_MAJOR_VERSION >= 2
	if (!Haptics[index]) return;

	if (SDL_HapticRumbleSupported(Haptics[index]) != SDL_TRUE) return;

	// we have to stop the rumble before updating
	if (rfx_timeout[index] > SDL_GetTicks()) {
		if (SDL_HapticRumbleStop(Haptics[index]) != 0)
			GfLogError("Failed to stop rumble: %s\n", SDL_GetError() );
	}

	if (SDL_HapticRumblePlay(Haptics[index], level, 100) != 0)
		GfLogError("Failed to play rumble: %s\n", SDL_GetError() );

	rfx_timeout[index] = SDL_GetTicks() + 100;
#endif
}
#endif

// Shutdown time.
void
gfctrlJoyShutdown(void)
{
   if (gfctrlJoyPresent != GFCTRL_JOY_UNTESTED)
#ifndef SDL_JOYSTICK
	
		for (int index = 0; index < GFCTRL_JOY_NUMBER; index++)
			delete Joysticks[index];

	
#else
      for (int index = 0; index < gfctrlJoyPresent; index++) {
			SDL_JoystickClose(Joysticks[index]);
			Joysticks[index] = NULL;
#if SDL_MAJOR_VERSION >= 2
			if (Haptics[index]) {
				SDL_HapticClose(Haptics[index]);
				Haptics[index] = NULL;
			}			
#endif
		}
#endif
      gfctrlJoyPresent = GFCTRL_JOY_UNTESTED;
}

/** Create the joystick control
    @ingroup	ctrl
    @return	pointer on a tCtrlJoyInfo structure
		<br>0 .. if no joystick present
    @note	call GfctrlJoyRelease to free the tCtrlJoyInfo structure
    @see	GfctrlJoyRelease
    @see	tCtrlJoyInfo
*/
tCtrlJoyInfo *
GfctrlJoyCreate(void)
{
    if (gfctrlJoyPresent == GFCTRL_JOY_UNTESTED)
       gfctrlJoyInit();

    tCtrlJoyInfo* joyInfo = (tCtrlJoyInfo *)calloc(1, sizeof(tCtrlJoyInfo));

#if SDL_JOYSTICK
    joyInfoCopy = joyInfo;
#endif

    return joyInfo;
}

/** Release the tCtrlJoyInfo structure
    @ingroup	ctrl
    @param	joyInfo	joystick structure
    @return	none
*/
void
GfctrlJoyRelease(tCtrlJoyInfo *joyInfo)
{
    freez(joyInfo);
}
コード例 #10
0
void EventosJoysticks::processarEvento(const SDL_Event& evento)
{
	Joystick* joy;

	switch(evento.type)
	{
	case SDL_JOYAXISMOTION:
		joy = identificarJoystick(evento.jaxis.which);
		if(joy)
		{
			switch(evento.jaxis.axis)
			{
			case SDL_CONTROLLER_AXIS_LEFTX:
				joy->x = evento.caxis.value/32767.0f;
				filtrarInput(joy->x, joy);
				break;

			case SDL_CONTROLLER_AXIS_LEFTY:
				joy->y = evento.caxis.value/32767.0f;
				filtrarInput(joy->y, joy);
				break;

			case SDL_CONTROLLER_AXIS_RIGHTX:
				joy->xDir = evento.caxis.value/32767.0f;
				filtrarInput(joy->xDir, joy);
				break;

			case SDL_CONTROLLER_AXIS_RIGHTY:
				joy->yDir = evento.caxis.value/32767.0f;
				filtrarInput(joy->yDir, joy);
				break;

			case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
				joy->z = evento.caxis.value/32767.0f;
				filtrarInput(joy->z, joy);
				break;

			case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
				joy->zDir = evento.caxis.value/32767.0f;
				filtrarInput(joy->zDir, joy);
				break;
			}
		}
		break;

	case SDL_CONTROLLERBUTTONDOWN:
		joy = identificarJoystick(evento.cbutton.which);
		if (joy)
		{
			joy->segurando[evento.cbutton.button] = true;

			if (evento.cbutton.state == SDL_PRESSED)
			{
				joy->pressionou[evento.cbutton.button] = true;
			}
		}
		break;

	case SDL_CONTROLLERBUTTONUP:
		joy = identificarJoystick(evento.cbutton.which);
		if (joy)
		{
			joy->segurando[evento.cbutton.button] = false;

			if (evento.cbutton.state == SDL_RELEASED)
			{
				joy->soltou[evento.cbutton.button] = true;
			}
		}
		break;

	case SDL_JOYBUTTONDOWN:
		joy = identificarJoystick(evento.jbutton.which);
		if(joy)
		{
			if (joy->eControle())
			{
				//	para aqui, pois controles são tratados separadamente
				break;
			}

			joy->segurando[evento.jbutton.button] = true;

			if(evento.jbutton.state == SDL_PRESSED)
			{
				joy->pressionou[evento.jbutton.button] = true;
			}
		}

		break;

	case SDL_JOYBUTTONUP:	
		joy = identificarJoystick(evento.jbutton.which);
		if(joy)
		{
			if (joy->eControle())
			{
				//	para aqui, pois controles são tratados separadamente
				break;
			}

			joy->segurando[evento.jbutton.button] = false;

			if(evento.jbutton.state == SDL_RELEASED)
			{
				joy->soltou[evento.jbutton.button] = true;
			}
		}

		break;


	case SDL_JOYDEVICEADDED:
		joy = getPrimeiroJoystickLivre();
		if(joy)
		{
			if (SDL_IsGameController(evento.jdevice.which))
			{
				joy->sdl_controller = SDL_GameControllerOpen(evento.jdevice.which);
				joy->sdl_joystick = SDL_GameControllerGetJoystick(joy->sdl_controller);
			}
			else
			{
				joy->sdl_joystick = SDL_JoystickOpen(evento.jdevice.which);
				joy->sdl_controller = NULL;
			}
			joy->id = nextId;
			joy->sdl_haptic = SDL_HapticOpenFromJoystick(joy->sdl_joystick);
			if(joy->sdl_haptic)
			{
				if(SDL_HapticRumbleSupported(joy->sdl_haptic))
					SDL_HapticRumbleInit(joy->sdl_haptic);
			}
			nextId++;
		}
		break;

	case SDL_JOYDEVICEREMOVED:
		joy = identificarJoystick(evento.jdevice.which);
		if(joy)
		{
			if(joy->sdl_haptic)
			{
				SDL_HapticClose(joy->sdl_haptic);
				joy->sdl_haptic = NULL;
			}

			if (joy->sdl_controller)
			{
				SDL_GameControllerClose(joy->sdl_controller);
			}
			else
			{
				SDL_JoystickClose(joy->sdl_joystick);
			}
			joy->sdl_controller = NULL;
			joy->sdl_joystick = NULL;
			joy->id = -1;
		}
		break;
	}
}
コード例 #11
0
ファイル: testrumble.c プロジェクト: CrypticGator/hackterm
/**
 * @brief The entry point of this force feedback demo.
 * @param[in] argc Number of arguments.
 * @param[in] argv Array of argc arguments.
 */
int
main(int argc, char **argv)
{
    int i;
    char *name;
    int index;
    SDL_HapticEffect efx[5];
    int id[5];
    int nefx;
    unsigned int supported;

    name = NULL;
    index = -1;
    if (argc > 1) {
        name = argv[1];
        if ((strcmp(name, "--help") == 0) || (strcmp(name, "-h") == 0)) {
            printf("USAGE: %s [device]\n"
                   "If device is a two-digit number it'll use it as an index, otherwise\n"
                   "it'll use it as if it were part of the device's name.\n",
                   argv[0]);
            return 0;
        }

        i = strlen(name);
        if ((i < 3) && isdigit(name[0]) && ((i == 1) || isdigit(name[1]))) {
            index = atoi(name);
            name = NULL;
        }
    }

    /* Initialize the force feedbackness */
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK |
             SDL_INIT_HAPTIC);
    printf("%d Haptic devices detected.\n", SDL_NumHaptics());
    if (SDL_NumHaptics() > 0) {
        /* We'll just use index or the first force feedback device found */
        if (name == NULL) {
            i = (index != -1) ? index : 0;
        }
        /* Try to find matching device */
        else {
            for (i = 0; i < SDL_NumHaptics(); i++) {
                if (strstr(SDL_HapticName(i), name) != NULL)
                    break;
            }

            if (i >= SDL_NumHaptics()) {
                printf("Unable to find device matching '%s', aborting.\n",
                       name);
                return 1;
            }
        }

        haptic = SDL_HapticOpen(i);
        if (haptic == NULL) {
            printf("Unable to create the haptic device: %s\n",
                   SDL_GetError());
            return 1;
        }
        printf("Device: %s\n", SDL_HapticName(i));
    } else {
        printf("No Haptic devices found!\n");
        return 1;
    }

    /* We only want force feedback errors. */
    SDL_ClearError();

    if (SDL_HapticRumbleSupported(haptic) == SDL_FALSE) {
        printf("\nRumble not supported!\n");
        return 1;
    }
    if (SDL_HapticRumbleInit(haptic) != 0) {
        printf("\nFailed to initialize rumble: %s\n", SDL_GetError());
        return 1;
    }
    printf("Playing 2 second rumble at 0.5 magnitude.\n");
    if (SDL_HapticRumblePlay(haptic, 0.5, 5000) != 0) {
       printf("\nFailed to play rumble: %s\n", SDL_GetError() );
       return 1;
    }
    SDL_Delay(2000);
    printf("Stopping rumble.\n");
    SDL_HapticRumbleStop(haptic);
    SDL_Delay(2000);
    printf("Playing 2 second rumble at 0.3 magnitude.\n");
    if (SDL_HapticRumblePlay(haptic, 0.3, 5000) != 0) {
       printf("\nFailed to play rumble: %s\n", SDL_GetError() );
       return 1;
    }
    SDL_Delay(2000);

    /* Quit */
    if (haptic != NULL)
        SDL_HapticClose(haptic);
    SDL_Quit();

    return 0;
}