Final merge of Google Summer of Code 2008 work...
Force Feedback for SDL by Edgar Simo, mentored by Ryan C. Gordon --HG-- extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%403159
This commit is contained in:
parent
0aca811202
commit
4fd9c25fe6
29 changed files with 6642 additions and 165 deletions
698
src/haptic/SDL_haptic.c
Normal file
698
src/haptic/SDL_haptic.c
Normal file
|
@ -0,0 +1,698 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 2008 Edgar Simo
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#include "SDL_syshaptic.h"
|
||||
#include "../joystick/SDL_joystick_c.h" /* For SDL_PrivateJoystickValid */
|
||||
|
||||
|
||||
Uint8 SDL_numhaptics = 0;
|
||||
SDL_Haptic **SDL_haptics = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Initializes the Haptic devices.
|
||||
*/
|
||||
int
|
||||
SDL_HapticInit(void)
|
||||
{
|
||||
int arraylen;
|
||||
int status;
|
||||
|
||||
SDL_numhaptics = 0;
|
||||
status = SDL_SYS_HapticInit();
|
||||
if (status >= 0) {
|
||||
arraylen = (status + 1) * sizeof(*SDL_haptics);
|
||||
SDL_haptics = (SDL_Haptic **) SDL_malloc(arraylen);
|
||||
if (SDL_haptics == NULL) { /* Out of memory. */
|
||||
SDL_numhaptics = 0;
|
||||
} else {
|
||||
SDL_memset(SDL_haptics, 0, arraylen);
|
||||
SDL_numhaptics = status;
|
||||
}
|
||||
status = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Checks to see if the haptic device is valid
|
||||
*/
|
||||
static int
|
||||
ValidHaptic(SDL_Haptic * haptic)
|
||||
{
|
||||
int i;
|
||||
int valid;
|
||||
|
||||
valid = 0;
|
||||
for (i = 0; i < SDL_numhaptics; i++) {
|
||||
if (SDL_haptics[i] == haptic) {
|
||||
valid = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns the number of available devices.
|
||||
*/
|
||||
int
|
||||
SDL_NumHaptics(void)
|
||||
{
|
||||
return SDL_numhaptics;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Gets the name of a Haptic device by index.
|
||||
*/
|
||||
const char *
|
||||
SDL_HapticName(int device_index)
|
||||
{
|
||||
if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
|
||||
SDL_SetError("Haptic: There are %d haptic devices available",
|
||||
SDL_numhaptics);
|
||||
return NULL;
|
||||
}
|
||||
return SDL_SYS_HapticName(device_index);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Opens a Haptic device.
|
||||
*/
|
||||
SDL_Haptic *
|
||||
SDL_HapticOpen(int device_index)
|
||||
{
|
||||
int i;
|
||||
SDL_Haptic *haptic;
|
||||
|
||||
if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
|
||||
SDL_SetError("Haptic: There are %d haptic devices available",
|
||||
SDL_numhaptics);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If the haptic is already open, return it */
|
||||
for (i = 0; SDL_haptics[i]; i++) {
|
||||
if (device_index == SDL_haptics[i]->index) {
|
||||
haptic = SDL_haptics[i];
|
||||
++haptic->ref_count;
|
||||
return haptic;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the haptic device */
|
||||
haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
|
||||
if (haptic == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize the haptic device */
|
||||
SDL_memset(haptic, 0, (sizeof *haptic));
|
||||
haptic->index = device_index;
|
||||
if (SDL_SYS_HapticOpen(haptic) < 0) {
|
||||
SDL_free(haptic);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Disable autocenter and set gain to max. */
|
||||
if (haptic->supported & SDL_HAPTIC_GAIN)
|
||||
SDL_HapticSetGain(haptic, 100);
|
||||
if (haptic->supported & SDL_HAPTIC_AUTOCENTER)
|
||||
SDL_HapticSetAutocenter(haptic, 0);
|
||||
|
||||
/* Add haptic to list */
|
||||
++haptic->ref_count;
|
||||
for (i = 0; SDL_haptics[i]; i++)
|
||||
/* Skip to next haptic */ ;
|
||||
SDL_haptics[i] = haptic;
|
||||
|
||||
return haptic;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns 1 if the device has been opened.
|
||||
*/
|
||||
int
|
||||
SDL_HapticOpened(int device_index)
|
||||
{
|
||||
int i, opened;
|
||||
|
||||
opened = 0;
|
||||
for (i = 0; SDL_haptics[i]; i++) {
|
||||
if (SDL_haptics[i]->index == (Uint8) device_index) {
|
||||
opened = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return opened;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns the index to a haptic device.
|
||||
*/
|
||||
int
|
||||
SDL_HapticIndex(SDL_Haptic * haptic)
|
||||
{
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return haptic->index;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns SDL_TRUE if mouse is haptic, SDL_FALSE if it isn't.
|
||||
*/
|
||||
int
|
||||
SDL_MouseIsHaptic(void)
|
||||
{
|
||||
if (SDL_SYS_HapticMouse() < 0)
|
||||
return SDL_FALSE;
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns the haptic device if mouse is haptic or NULL elsewise.
|
||||
*/
|
||||
SDL_Haptic *
|
||||
SDL_HapticOpenFromMouse(void)
|
||||
{
|
||||
int device_index;
|
||||
|
||||
device_index = SDL_SYS_HapticMouse();
|
||||
|
||||
if (device_index < 0) {
|
||||
SDL_SetError("Haptic: Mouse isn't a haptic device.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return SDL_HapticOpen(device_index);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns SDL_TRUE if joystick has haptic features.
|
||||
*/
|
||||
int
|
||||
SDL_JoystickIsHaptic(SDL_Joystick * joystick)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Must be a valid joystick */
|
||||
if (!SDL_PrivateJoystickValid(&joystick)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = SDL_SYS_JoystickIsHaptic(joystick);
|
||||
|
||||
if (ret > 0)
|
||||
return SDL_TRUE;
|
||||
else if (ret == 0)
|
||||
return SDL_FALSE;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Opens a haptic device from a joystick.
|
||||
*/
|
||||
SDL_Haptic *
|
||||
SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
|
||||
{
|
||||
int i;
|
||||
SDL_Haptic *haptic;
|
||||
|
||||
/* Must be a valid joystick */
|
||||
if (!SDL_PrivateJoystickValid(&joystick)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Joystick must be haptic */
|
||||
if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check to see if joystick's haptic is already open */
|
||||
for (i = 0; SDL_haptics[i]; i++) {
|
||||
if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i], joystick)) {
|
||||
haptic = SDL_haptics[i];
|
||||
++haptic->ref_count;
|
||||
return haptic;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the haptic device */
|
||||
haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
|
||||
if (haptic == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize the haptic device */
|
||||
SDL_memset(haptic, 0, sizeof(SDL_Haptic));
|
||||
if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
|
||||
SDL_free(haptic);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add haptic to list */
|
||||
++haptic->ref_count;
|
||||
for (i = 0; SDL_haptics[i]; i++)
|
||||
/* Skip to next haptic */ ;
|
||||
SDL_haptics[i] = haptic;
|
||||
|
||||
return haptic;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Closes a SDL_Haptic device.
|
||||
*/
|
||||
void
|
||||
SDL_HapticClose(SDL_Haptic * haptic)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Must be valid */
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if it's still in use */
|
||||
if (--haptic->ref_count < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Close it, properly removing effects if needed */
|
||||
for (i = 0; i < haptic->neffects; i++) {
|
||||
if (haptic->effects[i].hweffect != NULL) {
|
||||
SDL_HapticDestroyEffect(haptic, i);
|
||||
}
|
||||
}
|
||||
SDL_SYS_HapticClose(haptic);
|
||||
|
||||
/* Remove from the list */
|
||||
for (i = 0; SDL_haptics[i]; ++i) {
|
||||
if (haptic == SDL_haptics[i]) {
|
||||
SDL_haptics[i] = NULL;
|
||||
SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
|
||||
(SDL_numhaptics - i) * sizeof(haptic));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free */
|
||||
SDL_free(haptic);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleans up after the subsystem.
|
||||
*/
|
||||
void
|
||||
SDL_HapticQuit(void)
|
||||
{
|
||||
SDL_SYS_HapticQuit();
|
||||
if (SDL_haptics != NULL) {
|
||||
SDL_free(SDL_haptics);
|
||||
SDL_haptics = NULL;
|
||||
}
|
||||
SDL_numhaptics = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the number of effects a haptic device has.
|
||||
*/
|
||||
int
|
||||
SDL_HapticNumEffects(SDL_Haptic * haptic)
|
||||
{
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return haptic->neffects;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns the number of effects a haptic device can play.
|
||||
*/
|
||||
int
|
||||
SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
|
||||
{
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return haptic->nplaying;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns supported effects by the device.
|
||||
*/
|
||||
unsigned int
|
||||
SDL_HapticQuery(SDL_Haptic * haptic)
|
||||
{
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return haptic->supported;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns the number of axis on the device.
|
||||
*/
|
||||
int
|
||||
SDL_HapticNumAxes(SDL_Haptic * haptic)
|
||||
{
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return haptic->naxes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks to see if the device can support the effect.
|
||||
*/
|
||||
int
|
||||
SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
|
||||
{
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((haptic->supported & effect->type) != 0)
|
||||
return SDL_TRUE;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new haptic effect.
|
||||
*/
|
||||
int
|
||||
SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Check for device validity. */
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check to see if effect is supported */
|
||||
if (SDL_HapticEffectSupported(haptic, effect) == SDL_FALSE) {
|
||||
SDL_SetError("Haptic: Effect not supported by haptic device.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* See if there's a free slot */
|
||||
for (i = 0; i < haptic->neffects; i++) {
|
||||
if (haptic->effects[i].hweffect == NULL) {
|
||||
|
||||
/* Now let the backend create the real effect */
|
||||
if (SDL_SYS_HapticNewEffect(haptic, &haptic->effects[i], effect)
|
||||
!= 0) {
|
||||
return -1; /* Backend failed to create effect */
|
||||
}
|
||||
|
||||
SDL_memcpy(&haptic->effects[i].effect, effect,
|
||||
sizeof(SDL_HapticEffect));
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetError("Haptic: Device has no free space left.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks to see if an effect is valid.
|
||||
*/
|
||||
static int
|
||||
ValidEffect(SDL_Haptic * haptic, int effect)
|
||||
{
|
||||
if ((effect < 0) || (effect >= haptic->neffects)) {
|
||||
SDL_SetError("Haptic: Invalid effect identifier.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates an effect.
|
||||
*/
|
||||
int
|
||||
SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect,
|
||||
SDL_HapticEffect * data)
|
||||
{
|
||||
if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Can't change type dynamically. */
|
||||
if (data->type != haptic->effects[effect].effect.type) {
|
||||
SDL_SetError("Haptic: Updating effect type is illegal.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Updates the effect */
|
||||
if (SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data) <
|
||||
0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_memcpy(&haptic->effects[effect].effect, data,
|
||||
sizeof(SDL_HapticEffect));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Runs the haptic effect on the device.
|
||||
*/
|
||||
int
|
||||
SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
|
||||
{
|
||||
if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Run the effect */
|
||||
if (SDL_SYS_HapticRunEffect(haptic, &haptic->effects[effect], iterations)
|
||||
< 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stops the haptic effect on the device.
|
||||
*/
|
||||
int
|
||||
SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
|
||||
{
|
||||
if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Stop the effect */
|
||||
if (SDL_SYS_HapticStopEffect(haptic, &haptic->effects[effect]) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets rid of a haptic effect.
|
||||
*/
|
||||
void
|
||||
SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
|
||||
{
|
||||
if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not allocated */
|
||||
if (haptic->effects[effect].hweffect == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the status of a haptic effect.
|
||||
*/
|
||||
int
|
||||
SDL_HapticGetEffectStatus(SDL_Haptic * haptic, int effect)
|
||||
{
|
||||
if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
|
||||
SDL_SetError("Haptic: Device does not support status queries.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the global gain of the device.
|
||||
*/
|
||||
int
|
||||
SDL_HapticSetGain(SDL_Haptic * haptic, int gain)
|
||||
{
|
||||
const char *env;
|
||||
int real_gain, max_gain;
|
||||
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
|
||||
SDL_SetError("Haptic: Device does not support setting gain.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((gain < 0) || (gain > 100)) {
|
||||
SDL_SetError("Haptic: Gain must be between 0 and 100.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We use the envvar to get the maximum gain. */
|
||||
env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
|
||||
if (env != NULL) {
|
||||
max_gain = SDL_atoi(env);
|
||||
|
||||
/* Check for sanity. */
|
||||
if (max_gain < 0)
|
||||
max_gain = 0;
|
||||
else if (max_gain > 100)
|
||||
max_gain = 100;
|
||||
|
||||
/* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
|
||||
real_gain = (gain * max_gain) / 100;
|
||||
} else {
|
||||
real_gain = gain;
|
||||
}
|
||||
|
||||
if (SDL_SYS_HapticSetGain(haptic, real_gain) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Makes the device autocenter, 0 disables.
|
||||
*/
|
||||
int
|
||||
SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
|
||||
{
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
|
||||
SDL_SetError("Haptic: Device does not support setting autocenter.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((autocenter < 0) || (autocenter > 100)) {
|
||||
SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SDL_SYS_HapticSetAutocenter(haptic, autocenter) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pauses the haptic device.
|
||||
*/
|
||||
int
|
||||
SDL_HapticPause(SDL_Haptic * haptic)
|
||||
{
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
|
||||
SDL_SetError("Haptic: Device does not support setting pausing.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return SDL_SYS_HapticPause(haptic);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unpauses the haptic device.
|
||||
*/
|
||||
int
|
||||
SDL_HapticUnpause(SDL_Haptic * haptic)
|
||||
{
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
|
||||
return 0; /* Not going to be paused, so we pretend it's unpaused. */
|
||||
}
|
||||
|
||||
return SDL_SYS_HapticUnpause(haptic);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stops all the currently playing effects.
|
||||
*/
|
||||
int
|
||||
SDL_HapticStopAll(SDL_Haptic * haptic)
|
||||
{
|
||||
if (!ValidHaptic(haptic)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return SDL_SYS_HapticStopAll(haptic);
|
||||
}
|
201
src/haptic/SDL_syshaptic.h
Normal file
201
src/haptic/SDL_syshaptic.h
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 2008 Edgar Simo
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
|
||||
#include "SDL_config.h"
|
||||
|
||||
#include "SDL_haptic.h"
|
||||
|
||||
|
||||
/*
|
||||
* Number of haptic devices on the system.
|
||||
*/
|
||||
extern Uint8 SDL_numhaptics;
|
||||
|
||||
|
||||
struct haptic_effect
|
||||
{
|
||||
SDL_HapticEffect effect; /* The current event */
|
||||
struct haptic_hweffect *hweffect; /* The hardware behind the event */
|
||||
};
|
||||
|
||||
/*
|
||||
* The real SDL_Haptic struct.
|
||||
*/
|
||||
struct _SDL_Haptic
|
||||
{
|
||||
Uint8 index; /* Stores index it is attached to */
|
||||
|
||||
struct haptic_effect *effects; /* Allocated effects */
|
||||
int neffects; /* Maximum amount of effects */
|
||||
int nplaying; /* Maximum amount of effects to play at the same time */
|
||||
unsigned int supported; /* Supported effects */
|
||||
int naxes; /* Number of axes on the device. */
|
||||
|
||||
struct haptic_hwdata *hwdata; /* Driver dependent */
|
||||
int ref_count; /* Count for multiple opens */
|
||||
};
|
||||
|
||||
/*
|
||||
* Scans the system for haptic devices.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticInit(void);
|
||||
|
||||
/*
|
||||
* Gets the device dependent name of the haptic device
|
||||
*/
|
||||
extern const char *SDL_SYS_HapticName(int index);
|
||||
|
||||
/*
|
||||
* Opens the haptic device for usage. The haptic device should have
|
||||
* the index value set previously.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticOpen(SDL_Haptic * haptic);
|
||||
|
||||
/*
|
||||
* Returns the index of the haptic core pointer or -1 if none is found.
|
||||
*/
|
||||
int SDL_SYS_HapticMouse(void);
|
||||
|
||||
/*
|
||||
* Checks to see if the joystick has haptic capabilities.
|
||||
*
|
||||
* Returns >0 if haptic capabilities are detected, 0 if haptic
|
||||
* capabilities aren't detected and -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick);
|
||||
|
||||
/*
|
||||
* Opens the haptic device for usage using the same device as
|
||||
* the joystick.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic,
|
||||
SDL_Joystick * joystick);
|
||||
/*
|
||||
* Checks to see if haptic device and joystick device are the same.
|
||||
*
|
||||
* Returns 1 if they are the same, 0 if they aren't.
|
||||
*/
|
||||
extern int SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic,
|
||||
SDL_Joystick * joystick);
|
||||
|
||||
/*
|
||||
* Closes a haptic device after usage.
|
||||
*/
|
||||
extern void SDL_SYS_HapticClose(SDL_Haptic * haptic);
|
||||
|
||||
/*
|
||||
* Performs a cleanup on the haptic subsystem.
|
||||
*/
|
||||
extern void SDL_SYS_HapticQuit(void);
|
||||
|
||||
/*
|
||||
* Creates a new haptic effect on the haptic device using base
|
||||
* as a template for the effect.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticNewEffect(SDL_Haptic * haptic,
|
||||
struct haptic_effect *effect,
|
||||
SDL_HapticEffect * base);
|
||||
|
||||
/*
|
||||
* Updates the haptic effect on the haptic device using data
|
||||
* as a template.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
|
||||
struct haptic_effect *effect,
|
||||
SDL_HapticEffect * data);
|
||||
|
||||
/*
|
||||
* Runs the effect on the haptic device.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticRunEffect(SDL_Haptic * haptic,
|
||||
struct haptic_effect *effect,
|
||||
Uint32 iterations);
|
||||
|
||||
/*
|
||||
* Stops the effect on the haptic device.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticStopEffect(SDL_Haptic * haptic,
|
||||
struct haptic_effect *effect);
|
||||
|
||||
/*
|
||||
* Cleanups up the effect on the haptic device.
|
||||
*/
|
||||
extern void SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic,
|
||||
struct haptic_effect *effect);
|
||||
|
||||
/*
|
||||
* Queries the device for the status of effect.
|
||||
*
|
||||
* Returns 0 if device is stopped, >0 if device is playing and
|
||||
* -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
|
||||
struct haptic_effect *effect);
|
||||
|
||||
/*
|
||||
* Sets the global gain of the haptic device.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain);
|
||||
|
||||
/*
|
||||
* Sets the autocenter feature of the haptic device.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter);
|
||||
|
||||
/*
|
||||
* Pauses the haptic device.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticPause(SDL_Haptic * haptic);
|
||||
|
||||
/*
|
||||
* Unpauses the haptic device.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticUnpause(SDL_Haptic * haptic);
|
||||
|
||||
/*
|
||||
* Stops all the currently playing haptic effects on the device.
|
||||
*
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
extern int SDL_SYS_HapticStopAll(SDL_Haptic * haptic);
|
1317
src/haptic/darwin/SDL_syshaptic.c
Normal file
1317
src/haptic/darwin/SDL_syshaptic.c
Normal file
File diff suppressed because it is too large
Load diff
194
src/haptic/dummy/SDL_syshaptic.c
Normal file
194
src/haptic/dummy/SDL_syshaptic.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 2008 Edgar Simo
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#if defined(SDL_HAPTIC_DUMMY) || defined(SDL_HAPTIC_DISABLED)
|
||||
|
||||
#include "SDL_haptic.h"
|
||||
#include "../SDL_syshaptic.h"
|
||||
|
||||
|
||||
static int
|
||||
SDL_SYS_LogicError(void)
|
||||
{
|
||||
SDL_SetError("Logic error: No haptic devices available.");;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_HapticInit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
SDL_SYS_HapticName(int index)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_HapticOpen(SDL_Haptic * haptic)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_HapticMouse(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SDL_SYS_HapticClose(SDL_Haptic * haptic)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SDL_SYS_HapticQuit(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_HapticNewEffect(SDL_Haptic * haptic,
|
||||
struct haptic_effect *effect, SDL_HapticEffect * base)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
|
||||
struct haptic_effect *effect,
|
||||
SDL_HapticEffect * data)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
|
||||
Uint32 iterations)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
|
||||
struct haptic_effect *effect)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_HapticPause(SDL_Haptic * haptic)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
|
||||
{
|
||||
SDL_SYS_LogicError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* SDL_HAPTIC_DUMMY || SDL_HAPTIC_DISABLED */
|
956
src/haptic/linux/SDL_syshaptic.c
Normal file
956
src/haptic/linux/SDL_syshaptic.c
Normal file
|
@ -0,0 +1,956 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 2008 Edgar Simo
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#ifdef SDL_HAPTIC_LINUX
|
||||
|
||||
#include "SDL_haptic.h"
|
||||
#include "../SDL_syshaptic.h"
|
||||
#include "SDL_joystick.h"
|
||||
#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */
|
||||
#include "../../joystick/linux/SDL_sysjoystick_c.h" /* For joystick hwdata */
|
||||
|
||||
#include <unistd.h> /* close */
|
||||
#include <linux/input.h> /* Force feedback linux stuff. */
|
||||
#include <fcntl.h> /* O_RDWR */
|
||||
#include <limits.h> /* INT_MAX */
|
||||
#include <errno.h> /* errno, strerror */
|
||||
#include <math.h> /* atan2 */
|
||||
|
||||
/* Just in case. */
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX_HAPTICS 32 /* It's doubtful someone has more then 32 evdev */
|
||||
|
||||
|
||||
/*
|
||||
* List of available haptic devices.
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
char *fname; /* Dev path name (like /dev/input/event1) */
|
||||
SDL_Haptic *haptic; /* Assosciated haptic. */
|
||||
} SDL_hapticlist[MAX_HAPTICS];
|
||||
|
||||
|
||||
/*
|
||||
* Haptic system hardware data.
|
||||
*/
|
||||
struct haptic_hwdata
|
||||
{
|
||||
int fd; /* File descriptor of the device. */
|
||||
char *fname; /* Points to the name in SDL_hapticlist. */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Haptic system effect data.
|
||||
*/
|
||||
struct haptic_hweffect
|
||||
{
|
||||
struct ff_effect effect; /* The linux kernel effect structure. */
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define test_bit(nr, addr) \
|
||||
(((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
|
||||
#define EV_TEST(ev,f) \
|
||||
if (test_bit((ev), features)) ret |= (f);
|
||||
/*
|
||||
* Test whether a device has haptic properties.
|
||||
* Returns available properties or 0 if there are none.
|
||||
*/
|
||||
static int
|
||||
EV_IsHaptic(int fd)
|
||||
{
|
||||
unsigned int ret;
|
||||
unsigned long features[1 + FF_MAX / sizeof(unsigned long)];
|
||||
|
||||
/* Ask device for what it has. */
|
||||
ret = 0;
|
||||
if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) {
|
||||
SDL_SetError("Haptic: Unable to get device's features: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert supported features to SDL_HAPTIC platform-neutral features. */
|
||||
EV_TEST(FF_CONSTANT, SDL_HAPTIC_CONSTANT);
|
||||
EV_TEST(FF_SINE, SDL_HAPTIC_SINE);
|
||||
EV_TEST(FF_SQUARE, SDL_HAPTIC_SQUARE);
|
||||
EV_TEST(FF_TRIANGLE, SDL_HAPTIC_TRIANGLE);
|
||||
EV_TEST(FF_SAW_UP, SDL_HAPTIC_SAWTOOTHUP);
|
||||
EV_TEST(FF_SAW_DOWN, SDL_HAPTIC_SAWTOOTHDOWN);
|
||||
EV_TEST(FF_RAMP, SDL_HAPTIC_RAMP);
|
||||
EV_TEST(FF_SPRING, SDL_HAPTIC_SPRING);
|
||||
EV_TEST(FF_FRICTION, SDL_HAPTIC_FRICTION);
|
||||
EV_TEST(FF_DAMPER, SDL_HAPTIC_DAMPER);
|
||||
EV_TEST(FF_INERTIA, SDL_HAPTIC_INERTIA);
|
||||
EV_TEST(FF_CUSTOM, SDL_HAPTIC_CUSTOM);
|
||||
EV_TEST(FF_GAIN, SDL_HAPTIC_GAIN);
|
||||
EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER);
|
||||
|
||||
/* Return what it supports. */
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Tests whether a device is a mouse or not.
|
||||
*/
|
||||
static int
|
||||
EV_IsMouse(int fd)
|
||||
{
|
||||
unsigned long argp[40];
|
||||
|
||||
/* Ask for supported features. */
|
||||
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(argp)), argp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Currently we only test for BTN_MOUSE which can give fake positives. */
|
||||
if (test_bit(BTN_MOUSE, argp) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes the haptic subsystem by finding available devices.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticInit(void)
|
||||
{
|
||||
const char joydev_pattern[] = "/dev/input/event%d";
|
||||
dev_t dev_nums[MAX_HAPTICS];
|
||||
char path[PATH_MAX];
|
||||
struct stat sb;
|
||||
int fd;
|
||||
int i, j, k;
|
||||
int duplicate;
|
||||
int numhaptics;
|
||||
|
||||
numhaptics = 0;
|
||||
|
||||
/*
|
||||
* Limit amount of checks to MAX_HAPTICS since we may or may not have
|
||||
* permission to some or all devices.
|
||||
*/
|
||||
i = 0;
|
||||
for (j = 0; j < MAX_HAPTICS; ++j) {
|
||||
|
||||
snprintf(path, PATH_MAX, joydev_pattern, i++);
|
||||
|
||||
/* check to see if file exists */
|
||||
if (stat(path, &sb) != 0)
|
||||
break;
|
||||
|
||||
/* check for duplicates */
|
||||
duplicate = 0;
|
||||
for (k = 0; (k < numhaptics) && !duplicate; ++k) {
|
||||
if (sb.st_rdev == dev_nums[k]) {
|
||||
duplicate = 1;
|
||||
}
|
||||
}
|
||||
if (duplicate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* try to open */
|
||||
fd = open(path, O_RDWR, 0);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
|
||||
#ifdef DEBUG_INPUT_EVENTS
|
||||
printf("Checking %s\n", path);
|
||||
#endif
|
||||
|
||||
/* see if it works */
|
||||
if (EV_IsHaptic(fd) > 0) {
|
||||
SDL_hapticlist[numhaptics].fname = SDL_strdup(path);
|
||||
SDL_hapticlist[numhaptics].haptic = NULL;
|
||||
dev_nums[numhaptics] = sb.st_rdev;
|
||||
++numhaptics;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return numhaptics;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Gets the name from a file descriptor.
|
||||
*/
|
||||
static const char *
|
||||
SDL_SYS_HapticNameFromFD(int fd)
|
||||
{
|
||||
static char namebuf[128];
|
||||
|
||||
/* We use the evdev name ioctl. */
|
||||
if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return namebuf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the name of a haptic device, does not need to be opened.
|
||||
*/
|
||||
const char *
|
||||
SDL_SYS_HapticName(int index)
|
||||
{
|
||||
int fd;
|
||||
const char *name;
|
||||
|
||||
/* Open the haptic device. */
|
||||
name = NULL;
|
||||
fd = open(SDL_hapticlist[index].fname, O_RDONLY, 0);
|
||||
|
||||
if (fd >= 0) {
|
||||
|
||||
name = SDL_SYS_HapticNameFromFD(fd);
|
||||
if (name == NULL) {
|
||||
/* No name found, return device character device */
|
||||
name = SDL_hapticlist[index].fname;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Opens the haptic device from the file descriptor.
|
||||
*/
|
||||
static int
|
||||
SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
/* Allocate the hwdata */
|
||||
haptic->hwdata = (struct haptic_hwdata *)
|
||||
SDL_malloc(sizeof(*haptic->hwdata));
|
||||
if (haptic->hwdata == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
goto open_err;
|
||||
}
|
||||
SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
|
||||
|
||||
/* Set the data. */
|
||||
haptic->hwdata->fd = fd;
|
||||
haptic->supported = EV_IsHaptic(fd);
|
||||
haptic->naxes = 2; /* Hardcoded for now, not sure if it's possible to find out. */
|
||||
|
||||
/* Set the effects */
|
||||
if (ioctl(fd, EVIOCGEFFECTS, &haptic->neffects) < 0) {
|
||||
SDL_SetError("Haptic: Unable to query device memory: %s",
|
||||
strerror(errno));
|
||||
goto open_err;
|
||||
}
|
||||
haptic->nplaying = haptic->neffects; /* Linux makes no distinction. */
|
||||
haptic->effects = (struct haptic_effect *)
|
||||
SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
|
||||
if (haptic->effects == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
goto open_err;
|
||||
}
|
||||
/* Clear the memory */
|
||||
SDL_memset(haptic->effects, 0,
|
||||
sizeof(struct haptic_effect) * haptic->neffects);
|
||||
|
||||
return 0;
|
||||
|
||||
/* Error handling */
|
||||
open_err:
|
||||
close(fd);
|
||||
if (haptic->hwdata != NULL) {
|
||||
free(haptic->hwdata);
|
||||
haptic->hwdata = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Opens a haptic device for usage.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticOpen(SDL_Haptic * haptic)
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
|
||||
/* Open the character device */
|
||||
fd = open(SDL_hapticlist[haptic->index].fname, O_RDWR, 0);
|
||||
if (fd < 0) {
|
||||
SDL_SetError("Haptic: Unable to open %s: %s",
|
||||
SDL_hapticlist[haptic->index], strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Try to create the haptic. */
|
||||
ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the fname. */
|
||||
haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Opens a haptic device from first mouse it finds for usage.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticMouse(void)
|
||||
{
|
||||
int fd;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SDL_numhaptics; i++) {
|
||||
|
||||
/* Open the device. */
|
||||
fd = open(SDL_hapticlist[i].fname, O_RDWR, 0);
|
||||
if (fd < 0) {
|
||||
SDL_SetError("Haptic: Unable to open %s: %s",
|
||||
SDL_hapticlist[i], strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Is it a mouse? */
|
||||
if (EV_IsMouse(fd)) {
|
||||
close(fd);
|
||||
return i;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Checks to see if a joystick has haptic features.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
|
||||
{
|
||||
return EV_IsHaptic(joystick->hwdata->fd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Checks to see if the haptic device and joystick and in reality the same.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
|
||||
{
|
||||
/* We are assuming linux is using evdev which should trump the old
|
||||
* joystick methods. */
|
||||
if (SDL_strcmp(joystick->hwdata->fname, haptic->hwdata->fname) == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Opens a SDL_Haptic from a SDL_Joystick.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
|
||||
{
|
||||
int i;
|
||||
int fd;
|
||||
int ret;
|
||||
|
||||
/* Find the joystick in the haptic list. */
|
||||
for (i = 0; i < MAX_HAPTICS; i++) {
|
||||
if (SDL_hapticlist[i].fname != NULL) {
|
||||
if (SDL_strcmp(SDL_hapticlist[i].fname, joystick->hwdata->fname)
|
||||
== 0) {
|
||||
haptic->index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fd = open(joystick->hwdata->fname, O_RDWR, 0);
|
||||
ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Closes the haptic device.
|
||||
*/
|
||||
void
|
||||
SDL_SYS_HapticClose(SDL_Haptic * haptic)
|
||||
{
|
||||
if (haptic->hwdata) {
|
||||
|
||||
/* Free effects. */
|
||||
SDL_free(haptic->effects);
|
||||
haptic->effects = NULL;
|
||||
haptic->neffects = 0;
|
||||
|
||||
/* Clean up */
|
||||
close(haptic->hwdata->fd);
|
||||
|
||||
/* Free */
|
||||
SDL_free(haptic->hwdata);
|
||||
haptic->hwdata = NULL;
|
||||
}
|
||||
|
||||
/* Clear the rest. */
|
||||
SDL_memset(haptic, 0, sizeof(SDL_Haptic));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Clean up after system specific haptic stuff
|
||||
*/
|
||||
void
|
||||
SDL_SYS_HapticQuit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; SDL_hapticlist[i].fname != NULL; i++) {
|
||||
/* Opened and not closed haptics are leaked, this is on purpose.
|
||||
* Close your haptic devices after usage. */
|
||||
|
||||
SDL_free(SDL_hapticlist[i].fname);
|
||||
}
|
||||
SDL_hapticlist[0].fname = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Converts an SDL button to a ff_trigger button.
|
||||
*/
|
||||
static Uint16
|
||||
SDL_SYS_ToButton(Uint16 button)
|
||||
{
|
||||
Uint16 ff_button;
|
||||
|
||||
ff_button = 0;
|
||||
|
||||
/*
|
||||
* Not sure what the proper syntax is because this actually isn't implemented
|
||||
* in the current kernel from what I've seen (2.6.26).
|
||||
*/
|
||||
if (button != 0) {
|
||||
ff_button = BTN_GAMEPAD + button - 1;
|
||||
}
|
||||
|
||||
return ff_button;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns the ff_effect usable direction from a SDL_HapticDirection.
|
||||
*/
|
||||
static Uint16
|
||||
SDL_SYS_ToDirection(SDL_HapticDirection * dir)
|
||||
{
|
||||
Uint32 tmp;
|
||||
float f; /* Ideally we'd use fixed point math instead of floats... */
|
||||
|
||||
switch (dir->type) {
|
||||
case SDL_HAPTIC_POLAR:
|
||||
/* Linux directions are inverted. */
|
||||
tmp = (((18000 + dir->dir[0]) % 36000) * 0xFFFF) / 36000;
|
||||
return (Uint16) tmp;
|
||||
|
||||
case SDL_HAPTIC_CARTESIAN:
|
||||
/* We must invert "x" and "y" to go clockwise. */
|
||||
f = atan2(dir->dir[0], dir->dir[1]);
|
||||
tmp = (int) (f * 18000. / M_PI) % 36000;
|
||||
tmp = (tmp * 0xFFFF) / 36000;
|
||||
return (Uint16) tmp;
|
||||
|
||||
case SDL_HAPTIC_SPHERICAL:
|
||||
tmp = (36000 - dir->dir[0]) + 27000; /* Convert to polars */
|
||||
tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000;
|
||||
return (Uint16) tmp;
|
||||
|
||||
default:
|
||||
SDL_SetError("Haptic: Unsupported direction type.");
|
||||
return (Uint16) - 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define CLAMP(x) (((x) > 32767) ? 32767 : x)
|
||||
/*
|
||||
* Initializes the linux effect struct from a haptic_effect.
|
||||
* Values above 32767 (for unsigned) are unspecified so we must clamp.
|
||||
*/
|
||||
static int
|
||||
SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src)
|
||||
{
|
||||
Uint32 tmp;
|
||||
SDL_HapticConstant *constant;
|
||||
SDL_HapticPeriodic *periodic;
|
||||
SDL_HapticCondition *condition;
|
||||
SDL_HapticRamp *ramp;
|
||||
|
||||
/* Clear up */
|
||||
SDL_memset(dest, 0, sizeof(struct ff_effect));
|
||||
|
||||
switch (src->type) {
|
||||
case SDL_HAPTIC_CONSTANT:
|
||||
constant = &src->constant;
|
||||
|
||||
/* Header */
|
||||
dest->type = FF_CONSTANT;
|
||||
dest->direction = SDL_SYS_ToDirection(&constant->direction);
|
||||
if (dest->direction == (Uint16) - 1)
|
||||
return -1;
|
||||
|
||||
/* Replay */
|
||||
dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ?
|
||||
0 : CLAMP(constant->length);
|
||||
dest->replay.delay = CLAMP(constant->delay);
|
||||
|
||||
/* Trigger */
|
||||
dest->trigger.button = SDL_SYS_ToButton(constant->button);
|
||||
dest->trigger.interval = CLAMP(constant->interval);
|
||||
|
||||
/* Constant */
|
||||
dest->u.constant.level = constant->level;
|
||||
|
||||
/* Envelope */
|
||||
dest->u.constant.envelope.attack_length =
|
||||
CLAMP(constant->attack_length);
|
||||
dest->u.constant.envelope.attack_level =
|
||||
CLAMP(constant->attack_level);
|
||||
dest->u.constant.envelope.fade_length = CLAMP(constant->fade_length);
|
||||
dest->u.constant.envelope.fade_level = CLAMP(constant->fade_level);
|
||||
|
||||
break;
|
||||
|
||||
case SDL_HAPTIC_SINE:
|
||||
case SDL_HAPTIC_SQUARE:
|
||||
case SDL_HAPTIC_TRIANGLE:
|
||||
case SDL_HAPTIC_SAWTOOTHUP:
|
||||
case SDL_HAPTIC_SAWTOOTHDOWN:
|
||||
periodic = &src->periodic;
|
||||
|
||||
/* Header */
|
||||
dest->type = FF_PERIODIC;
|
||||
dest->direction = SDL_SYS_ToDirection(&periodic->direction);
|
||||
if (dest->direction == (Uint16) - 1)
|
||||
return -1;
|
||||
|
||||
/* Replay */
|
||||
dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ?
|
||||
0 : CLAMP(periodic->length);
|
||||
dest->replay.delay = CLAMP(periodic->delay);
|
||||
|
||||
/* Trigger */
|
||||
dest->trigger.button = SDL_SYS_ToButton(periodic->button);
|
||||
dest->trigger.interval = CLAMP(periodic->interval);
|
||||
|
||||
/* Periodic */
|
||||
if (periodic->type == SDL_HAPTIC_SINE)
|
||||
dest->u.periodic.waveform = FF_SINE;
|
||||
else if (periodic->type == SDL_HAPTIC_SQUARE)
|
||||
dest->u.periodic.waveform = FF_SQUARE;
|
||||
else if (periodic->type == SDL_HAPTIC_TRIANGLE)
|
||||
dest->u.periodic.waveform = FF_TRIANGLE;
|
||||
else if (periodic->type == SDL_HAPTIC_SAWTOOTHUP)
|
||||
dest->u.periodic.waveform = FF_SAW_UP;
|
||||
else if (periodic->type == SDL_HAPTIC_SAWTOOTHDOWN)
|
||||
dest->u.periodic.waveform = FF_SAW_DOWN;
|
||||
dest->u.periodic.period = CLAMP(periodic->period);
|
||||
dest->u.periodic.magnitude = periodic->magnitude;
|
||||
dest->u.periodic.offset = periodic->offset;
|
||||
/* Phase is calculated based of offset from period and then clamped. */
|
||||
tmp = ((periodic->phase % 36000) * dest->u.periodic.period) / 36000;
|
||||
dest->u.periodic.phase = CLAMP(tmp);
|
||||
|
||||
/* Envelope */
|
||||
dest->u.periodic.envelope.attack_length =
|
||||
CLAMP(periodic->attack_length);
|
||||
dest->u.periodic.envelope.attack_level =
|
||||
CLAMP(periodic->attack_level);
|
||||
dest->u.periodic.envelope.fade_length = CLAMP(periodic->fade_length);
|
||||
dest->u.periodic.envelope.fade_level = CLAMP(periodic->fade_level);
|
||||
|
||||
break;
|
||||
|
||||
case SDL_HAPTIC_SPRING:
|
||||
case SDL_HAPTIC_DAMPER:
|
||||
case SDL_HAPTIC_INERTIA:
|
||||
case SDL_HAPTIC_FRICTION:
|
||||
condition = &src->condition;
|
||||
|
||||
/* Header */
|
||||
if (condition->type == SDL_HAPTIC_SPRING)
|
||||
dest->type = FF_SPRING;
|
||||
else if (condition->type == SDL_HAPTIC_DAMPER)
|
||||
dest->type = FF_DAMPER;
|
||||
else if (condition->type == SDL_HAPTIC_INERTIA)
|
||||
dest->type = FF_INERTIA;
|
||||
else if (condition->type == SDL_HAPTIC_FRICTION)
|
||||
dest->type = FF_FRICTION;
|
||||
dest->direction = 0; /* Handled by the condition-specifics. */
|
||||
|
||||
/* Replay */
|
||||
dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ?
|
||||
0 : CLAMP(condition->length);
|
||||
dest->replay.delay = CLAMP(condition->delay);
|
||||
|
||||
/* Trigger */
|
||||
dest->trigger.button = SDL_SYS_ToButton(condition->button);
|
||||
dest->trigger.interval = CLAMP(condition->interval);
|
||||
|
||||
/* Condition */
|
||||
/* X axis */
|
||||
dest->u.condition[0].right_saturation =
|
||||
CLAMP(condition->right_sat[0]);
|
||||
dest->u.condition[0].left_saturation = CLAMP(condition->left_sat[0]);
|
||||
dest->u.condition[0].right_coeff = condition->right_coeff[0];
|
||||
dest->u.condition[0].left_coeff = condition->left_coeff[0];
|
||||
dest->u.condition[0].deadband = CLAMP(condition->deadband[0]);
|
||||
dest->u.condition[0].center = condition->center[0];
|
||||
/* Y axis */
|
||||
dest->u.condition[1].right_saturation =
|
||||
CLAMP(condition->right_sat[1]);
|
||||
dest->u.condition[1].left_saturation = CLAMP(condition->left_sat[1]);
|
||||
dest->u.condition[1].right_coeff = condition->right_coeff[1];
|
||||
dest->u.condition[1].left_coeff = condition->left_coeff[1];
|
||||
dest->u.condition[1].deadband = CLAMP(condition->deadband[1]);
|
||||
dest->u.condition[1].center = condition->center[1];
|
||||
|
||||
/*
|
||||
* There is no envelope in the linux force feedback api for conditions.
|
||||
*/
|
||||
|
||||
break;
|
||||
|
||||
case SDL_HAPTIC_RAMP:
|
||||
ramp = &src->ramp;
|
||||
|
||||
/* Header */
|
||||
dest->type = FF_RAMP;
|
||||
dest->direction = SDL_SYS_ToDirection(&ramp->direction);
|
||||
if (dest->direction == (Uint16) - 1)
|
||||
return -1;
|
||||
|
||||
/* Replay */
|
||||
dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ?
|
||||
0 : CLAMP(ramp->length);
|
||||
dest->replay.delay = CLAMP(ramp->delay);
|
||||
|
||||
/* Trigger */
|
||||
dest->trigger.button = SDL_SYS_ToButton(ramp->button);
|
||||
dest->trigger.interval = CLAMP(ramp->interval);
|
||||
|
||||
/* Ramp */
|
||||
dest->u.ramp.start_level = ramp->start;
|
||||
dest->u.ramp.end_level = ramp->end;
|
||||
|
||||
/* Envelope */
|
||||
dest->u.ramp.envelope.attack_length = CLAMP(ramp->attack_length);
|
||||
dest->u.ramp.envelope.attack_level = CLAMP(ramp->attack_level);
|
||||
dest->u.ramp.envelope.fade_length = CLAMP(ramp->fade_length);
|
||||
dest->u.ramp.envelope.fade_level = CLAMP(ramp->fade_level);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
SDL_SetError("Haptic: Unknown effect type.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Creates a new haptic effect.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
|
||||
SDL_HapticEffect * base)
|
||||
{
|
||||
struct ff_effect *linux_effect;
|
||||
|
||||
/* Allocate the hardware effect */
|
||||
effect->hweffect = (struct haptic_hweffect *)
|
||||
SDL_malloc(sizeof(struct haptic_hweffect));
|
||||
if (effect->hweffect == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Prepare the ff_effect */
|
||||
linux_effect = &effect->hweffect->effect;
|
||||
if (SDL_SYS_ToFFEffect(linux_effect, base) != 0) {
|
||||
goto new_effect_err;
|
||||
}
|
||||
linux_effect->id = -1; /* Have the kernel give it an id */
|
||||
|
||||
/* Upload the effect */
|
||||
if (ioctl(haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) {
|
||||
SDL_SetError("Haptic: Error uploading effect to the device: %s",
|
||||
strerror(errno));
|
||||
goto new_effect_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
new_effect_err:
|
||||
free(effect->hweffect);
|
||||
effect->hweffect = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Updates an effect.
|
||||
*
|
||||
* Note: Dynamically updating the direction can in some cases force
|
||||
* the effect to restart and run once.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
|
||||
struct haptic_effect *effect,
|
||||
SDL_HapticEffect * data)
|
||||
{
|
||||
struct ff_effect linux_effect;
|
||||
|
||||
/* Create the new effect */
|
||||
if (SDL_SYS_ToFFEffect(&linux_effect, data) != 0) {
|
||||
return -1;
|
||||
}
|
||||
linux_effect.id = effect->hweffect->effect.id;
|
||||
|
||||
/* See if it can be uploaded. */
|
||||
if (ioctl(haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) {
|
||||
SDL_SetError("Haptic: Error updating the effect: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy the new effect into memory. */
|
||||
SDL_memcpy(&effect->hweffect->effect, &linux_effect,
|
||||
sizeof(struct ff_effect));
|
||||
|
||||
return effect->hweffect->effect.id;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Runs an effect.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
|
||||
Uint32 iterations)
|
||||
{
|
||||
struct input_event run;
|
||||
|
||||
/* Prepare to run the effect */
|
||||
run.type = EV_FF;
|
||||
run.code = effect->hweffect->effect.id;
|
||||
/* We don't actually have infinity here, so we just do INT_MAX which is pretty damn close. */
|
||||
run.value = (iterations > INT_MAX) ? INT_MAX : iterations;
|
||||
|
||||
if (write(haptic->hwdata->fd, (const void *) &run, sizeof(run)) < 0) {
|
||||
SDL_SetError("Haptic: Unable to run the effect: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Stops an effect.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
|
||||
{
|
||||
struct input_event stop;
|
||||
|
||||
stop.type = EV_FF;
|
||||
stop.code = effect->hweffect->effect.id;
|
||||
stop.value = 0;
|
||||
|
||||
if (write(haptic->hwdata->fd, (const void *) &stop, sizeof(stop)) < 0) {
|
||||
SDL_SetError("Haptic: Unable to stop the effect: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Frees the effect.
|
||||
*/
|
||||
void
|
||||
SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
|
||||
{
|
||||
if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) {
|
||||
SDL_SetError("Haptic: Error removing the effect from the device: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
SDL_free(effect->hweffect);
|
||||
effect->hweffect = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Gets the status of a haptic effect.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
|
||||
struct haptic_effect *effect)
|
||||
{
|
||||
#if 0 /* Not supported atm. */
|
||||
struct input_event ie;
|
||||
|
||||
ie.type = EV_FF;
|
||||
ie.type = EV_FF_STATUS;
|
||||
ie.code = effect->hweffect->effect.id;
|
||||
|
||||
if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
|
||||
SDL_SetError("Haptic: Error getting device status.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sets the gain.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
|
||||
{
|
||||
struct input_event ie;
|
||||
|
||||
ie.type = EV_FF;
|
||||
ie.code = FF_GAIN;
|
||||
ie.value = (0xFFFFUL * gain) / 100;
|
||||
|
||||
if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
|
||||
SDL_SetError("Haptic: Error setting gain: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sets the autocentering.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
|
||||
{
|
||||
struct input_event ie;
|
||||
|
||||
ie.type = EV_FF;
|
||||
ie.code = FF_AUTOCENTER;
|
||||
ie.value = (0xFFFFUL * autocenter) / 100;
|
||||
|
||||
if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
|
||||
SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Pausing is not supported atm by linux.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticPause(SDL_Haptic * haptic)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unpausing is not supported atm by linux.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Stops all the currently playing effects.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
/* Linux does not support this natively so we have to loop. */
|
||||
for (i = 0; i < haptic->neffects; i++) {
|
||||
if (haptic->effects[i].hweffect != NULL) {
|
||||
ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]);
|
||||
if (ret < 0) {
|
||||
SDL_SetError
|
||||
("Haptic: Error while trying to stop all playing effects.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* SDL_HAPTIC_LINUX */
|
1392
src/haptic/win32/SDL_syshaptic.c
Normal file
1392
src/haptic/win32/SDL_syshaptic.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue