From dc7047bb5d3d6cf34aab206d57f6bfa77e8e2025 Mon Sep 17 00:00:00 2001 From: Edgar Simo Date: Sun, 1 Jun 2008 11:44:25 +0000 Subject: [PATCH] First commit of the SDL_haptic subsystem. Code compiles and works, very limited functionality (linux only). --- configure.in | 18 +++ include/SDL.h | 1 + include/SDL_haptic.h | 87 +++++++++++++++ src/SDL.c | 26 +++++ src/haptic/SDL_haptic.c | 127 +++++++++++++++++++++ src/haptic/SDL_haptic_c.h | 33 ++++++ src/haptic/SDL_syshaptic.h | 44 ++++++++ src/haptic/linux/SDL_syshaptic.c | 185 +++++++++++++++++++++++++++++++ 8 files changed, 521 insertions(+) create mode 100644 include/SDL_haptic.h create mode 100644 src/haptic/SDL_haptic.c create mode 100644 src/haptic/SDL_haptic_c.h create mode 100644 src/haptic/SDL_syshaptic.h create mode 100644 src/haptic/linux/SDL_syshaptic.c diff --git a/configure.in b/configure.in index 8cfa63c98..1bb975eb4 100644 --- a/configure.in +++ b/configure.in @@ -235,6 +235,14 @@ if test x$enable_joystick != xyes; then else SOURCES="$SOURCES $srcdir/src/joystick/*.c" fi +AC_ARG_ENABLE(haptic, +AC_HELP_STRING([--enable-haptic], [Enable the haptic (force feedback) subsystem [[default=yes]]]), + , enable_haptic=yes) +if test x$enable_haptic != xyes; then + AC_DEFINE(SDL_HAPTIC_DISABLE) +else + SOURCES="$SOURCES $srcdir/src/haptic/*.c" +fi AC_ARG_ENABLE(cdrom, AC_HELP_STRING([--enable-cdrom], [Enable the cdrom subsystem [[default=yes]]]), , enable_cdrom=yes) @@ -2176,6 +2184,16 @@ case "$host" in ;; esac fi + # Set up files for the haptic library + if test x$enable_haptic = xyes; then + case $ARCH in + linux) + AC_DEFINE(SDL_HAPTIC_LINUX) + SOURCES="$SOURCES $srcdir/src/haptic/linux/*.c" + have_haptic=yes + ;; + esac + fi # Set up files for the cdrom library if test x$enable_cdrom = xyes; then case $ARCH in diff --git a/include/SDL.h b/include/SDL.h index e079d2882..5d23a29d7 100644 --- a/include/SDL.h +++ b/include/SDL.h @@ -109,6 +109,7 @@ extern "C" { #define SDL_INIT_VIDEO 0x00000020 #define SDL_INIT_CDROM 0x00000100 #define SDL_INIT_JOYSTICK 0x00000200 +#define SDL_INIT_HAPTIC 0x00001000 #define SDL_INIT_NOPARACHUTE 0x00100000 /* Don't catch fatal signals */ #define SDL_INIT_EVENTTHREAD 0x01000000 /* Not supported on all OS's */ #define SDL_INIT_EVERYTHING 0x0000FFFF diff --git a/include/SDL_haptic.h b/include/SDL_haptic.h new file mode 100644 index 000000000..fd360cc17 --- /dev/null +++ b/include/SDL_haptic.h @@ -0,0 +1,87 @@ +/* + 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 +*/ + +/** + * \file SDL_haptic.h + * + * Include file for SDL haptic subsystem + */ + +#ifndef _SDL_haptic_h +#define _SDL_haptic_h + +#include "SDL_stdinc.h" +#include "SDL_error.h" + +#include "begin_code.h" +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { + /* *INDENT-ON* */ +#endif + +/* The haptic structure used to identify an SDL haptic */ +struct _SDL_Haptic; +typedef struct _SDL_Haptic SDL_Haptic; + + +/* Different effects that can be generated */ +#define SDL_HAPTIC_CONSTANT (1<<0) +#define SDL_HAPTIC_PERIODIC (1<<1) +#define SDL_HAPTIC_RAMP (1<<2) +#define SDL_HAPTIC_SPRING (1<<3) +#define SDL_HAPTIC_FRICTION (1<<4) +#define SDL_HAPTIC_DAMPER (1<<5) +#define SDL_HAPTIC_RUMBLE (1<<6) +#define SDL_HAPTIC_INERTIA (1<<7) +#define SDL_HAPTIC_GAIN (1<<8) +#define SDL_HAPTIC_AUTOCENTER (1<<9) + + +/* Function prototypes */ +/* + * Count the number of joysticks attached to the system + */ +extern DECLSPEC int SDLCALL SDL_NumHaptics(void); + +/* + * Get the implementation dependent name of a joystick. + * This can be called before any joysticks are opened. + * If no name can be found, this function returns NULL. + */ +extern DECLSPEC const char *SDLCALL SDL_HapticName(int device_index); + + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif +#include "close_code.h" + +#endif /* _SDL_haptic_h */ + +/* vi: set ts=4 sw=4 expandtab: */ + + diff --git a/src/SDL.c b/src/SDL.c index d2858673b..968ab75e2 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -38,6 +38,10 @@ extern int SDL_JoystickInit(void); extern void SDL_JoystickQuit(void); #endif +#if !SDL_HAPTIC_DISABLED +extern int SDL_HapticInit(void); +extern int SDL_HapticQuit(void); +#endif #if !SDL_CDROM_DISABLED extern int SDL_CDROMInit(void); extern void SDL_CDROMQuit(void); @@ -123,6 +127,22 @@ SDL_InitSubSystem(Uint32 flags) } #endif +#if !SDL_HAPTIC_DISABLED + /* Initialize the haptic subsystem */ + if ((flags & SDL_INIT_HAPTIC) && !(SDL_initialized & SDL_INIT_HAPTIC)) { + if (SDL_HapticInit() < 0) { + return (-1); + } + SDL_initialized |= SDL_INIT_HAPTIC; + } +#else + if (flags & SDL_INIT_HAPTIC) { + SDL_SetError("SDL not built with haptic (force feedback) support"); + return (-1); + } +#endif + + #if !SDL_CDROM_DISABLED /* Initialize the CD-ROM subsystem */ if ((flags & SDL_INIT_CDROM) && !(SDL_initialized & SDL_INIT_CDROM)) { @@ -180,6 +200,12 @@ SDL_QuitSubSystem(Uint32 flags) SDL_initialized &= ~SDL_INIT_JOYSTICK; } #endif +#if !SDL_HAPTIC_DISABLED + if ((flags & SDL_initialized & SDL_INIT_HAPTIC)) { + SDL_HapticQuit(); + SDL_initialized &= ~SDL_INIT_HAPTIC; + } +#endif #if !SDL_TIMERS_DISABLED if ((flags & SDL_initialized & SDL_INIT_TIMER)) { SDL_TimerQuit(); diff --git a/src/haptic/SDL_haptic.c b/src/haptic/SDL_haptic.c new file mode 100644 index 000000000..040182c75 --- /dev/null +++ b/src/haptic/SDL_haptic.c @@ -0,0 +1,127 @@ +/* + 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_c.h" +#include "SDL_syshaptic.h" + + +static Uint8 SDL_numhaptics = 0; +SDL_Haptic **SDL_haptics = NULL; +static SDL_Haptic *default_haptic = 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) { + SDL_numhaptics = 0; + } else { + SDL_memset(SDL_haptics, 0, arraylen); + SDL_numhaptics = status; + } + status = 0; + } + default_haptic = NULL; + + return status; +} + + +/* + * 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("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("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 and initialize the haptic */ + haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic)); + if (haptic != NULL) { + SDL_memset(haptic, 0, (sizeof *haptic)); + haptic->index = device_index; + if (SDL_SYS_HapticOpen(haptic) < 0) { + SDL_free(haptic); + haptic = NULL; + } else { + } + } + if (haptic) { + /* Add haptic to list */ + ++haptic->ref_count; + for (i = 0; SDL_haptics[i]; ++i) + /* Skip to next haptic */ ; + SDL_haptics[i] = haptic; + } + return haptic; +} diff --git a/src/haptic/SDL_haptic_c.h b/src/haptic/SDL_haptic_c.h new file mode 100644 index 000000000..fd8d9d140 --- /dev/null +++ b/src/haptic/SDL_haptic_c.h @@ -0,0 +1,33 @@ +/* + 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_haptic.h" + +struct _SDL_Haptic; + +extern int SDL_HapticInit(void); +extern int SDL_NumHaptics(void); +extern const char * SDL_HapticName(int device_index); +extern struct _SDL_Haptic * SDL_HapticOpen(int device_index); +extern int SDL_HapticOpened(int device_index); +extern int SDL_HapticIndex(struct _SDL_Haptic *haptic); +extern void SDL_HapticClose(struct _SDL_Haptic *haptic); diff --git a/src/haptic/SDL_syshaptic.h b/src/haptic/SDL_syshaptic.h new file mode 100644 index 000000000..7e2304b61 --- /dev/null +++ b/src/haptic/SDL_syshaptic.h @@ -0,0 +1,44 @@ +/* + 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" + + +struct _SDL_Haptic +{ + Uint8 index; + const char* name; + + int neffects; /* maximum amount of effects */ + unsigned int supported; /* supported effects */ + + struct haptic_hwdata *hwdata; /* driver dependent */ + int ref_count; /* count for multiple opens */ +}; + + +extern int SDL_SYS_HapticInit(void); + +extern const char * SDL_SYS_HapticName(int index); + diff --git a/src/haptic/linux/SDL_syshaptic.c b/src/haptic/linux/SDL_syshaptic.c new file mode 100644 index 000000000..345fda74b --- /dev/null +++ b/src/haptic/linux/SDL_syshaptic.c @@ -0,0 +1,185 @@ +/* + 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_JOYSTICK_LINUX + +#include "SDL_haptic.h" +#include "../SDL_haptic_c.h" +#include "../SDL_syshaptic.h" + +#include /* close */ +#include +#include +#include +#include +#include +#include +#include + + +#include + + +#define MAX_HAPTICS 32 + + +static struct +{ + char *fname; + SDL_Haptic *haptic; +} SDL_hapticlist[MAX_HAPTICS]; + +struct haptic_hwdata +{ + int fd; +}; + + +#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); +static int +EV_IsHaptic(int fd) +{ + unsigned int ret; + unsigned long features[1 + FF_MAX/sizeof(unsigned long)]; + + ret = 0; + + ioctl(fd, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features); + + EV_TEST(FF_CONSTANT, SDL_HAPTIC_CONSTANT); + EV_TEST(FF_PERIODIC, SDL_HAPTIC_PERIODIC); + 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_RUMBLE, SDL_HAPTIC_RUMBLE); + EV_TEST(FF_INERTIA, SDL_HAPTIC_INERTIA); + EV_TEST(FF_GAIN, SDL_HAPTIC_GAIN); + EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER); + + return ret; +} + +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; + + 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; +} + + +const char * +SDL_SYS_HapticName(int index) +{ + int fd; + static char namebuf[128]; + char *name; + + name = NULL; + fd = open(SDL_hapticlist[index].fname, O_RDONLY, 0); + if (fd >= 0) { + if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) { + name = SDL_hapticlist[index].fname; + } + else { + name = namebuf; + } + } + close(fd); + + return name; +} + + +int +SDL_SYS_HapticOpen(SDL_Haptic * haptic) +{ + /* TODO finish + int fd; + + fd = open(SDL_hapticlist[haptic->index].fname, O_RDWR, 0); + + if (fd < 0) { + SDL_SetError("Unable to open %s\n", SDL_hapticlist[haptic->index]); + return (-1); + } + + + + return 0; + */ +} + + +#endif /* SDL_HAPTIC_LINUX */