Final merge of Google Summer of Code 2008 work...
authorSam Lantinga <slouken@libsdl.org>
Mon, 25 Aug 2008 09:55:03 +0000
changeset 27130906692aa6a4
parent 2712 c4e697245676
child 2714 1d1be6137875
Final merge of Google Summer of Code 2008 work...

Force Feedback for SDL
by Edgar Simo, mentored by Ryan C. Gordon
Makefile.in
Makefile.minimal
configure.in
include/SDL.h
include/SDL_config.h.in
include/SDL_config_dreamcast.h
include/SDL_config_macosx.h
include/SDL_config_minimal.h
include/SDL_config_os2.h
include/SDL_config_win32.h
include/SDL_haptic.h
src/SDL.c
src/haptic/SDL_haptic.c
src/haptic/SDL_syshaptic.h
src/haptic/darwin/SDL_syshaptic.c
src/haptic/dummy/SDL_syshaptic.c
src/haptic/linux/SDL_syshaptic.c
src/haptic/win32/SDL_syshaptic.c
src/joystick/SDL_joystick.c
src/joystick/SDL_joystick_c.h
src/joystick/darwin/SDL_sysjoystick.c
src/joystick/darwin/SDL_sysjoystick_c.h
src/joystick/linux/SDL_sysjoystick.c
src/joystick/linux/SDL_sysjoystick_c.h
src/joystick/win32/SDL_dxjoystick.c
src/joystick/win32/SDL_dxjoystick_c.h
src/video/win32/SDL_win32window.c
test/Makefile.in
test/testhaptic.c
     1.1 --- a/Makefile.in	Mon Aug 25 08:50:37 2008 +0000
     1.2 +++ b/Makefile.in	Mon Aug 25 09:55:03 2008 +0000
     1.3 @@ -42,7 +42,7 @@
     1.4  
     1.5  DIST = acinclude.m4 autogen.sh Borland.html Borland.zip BUGS build-scripts configure configure.in COPYING CREDITS docs docs.html include INSTALL Makefile.dc Makefile.minimal Makefile.in README* sdl-config.in sdl.m4 sdl.pc.in SDL.qpg.in SDL.spec SDL.spec.in src test TODO VisualC.html VisualC VisualCE Watcom-OS2.zip Watcom-Win32.zip WhatsNew Xcode
     1.6  
     1.7 -HDRS = SDL.h SDL_audio.h SDL_cdrom.h SDL_compat.h SDL_cpuinfo.h SDL_endian.h SDL_error.h SDL_events.h SDL_joystick.h SDL_keyboard.h SDL_keysym.h SDL_loadso.h SDL_main.h SDL_mouse.h SDL_mutex.h SDL_name.h SDL_opengl.h SDL_pixels.h SDL_platform.h SDL_quit.h SDL_rect.h SDL_rwops.h SDL_scancode.h SDL_stdinc.h SDL_surface.h SDL_syswm.h SDL_thread.h SDL_timer.h SDL_types.h SDL_version.h SDL_video.h begin_code.h close_code.h
     1.8 +HDRS = SDL.h SDL_audio.h SDL_cdrom.h SDL_compat.h SDL_cpuinfo.h SDL_endian.h SDL_error.h SDL_events.h SDL_haptic.h SDL_joystick.h SDL_keyboard.h SDL_keysym.h SDL_loadso.h SDL_main.h SDL_mouse.h SDL_mutex.h SDL_name.h SDL_opengl.h SDL_pixels.h SDL_platform.h SDL_quit.h SDL_rect.h SDL_rwops.h SDL_scancode.h SDL_stdinc.h SDL_surface.h SDL_syswm.h SDL_thread.h SDL_timer.h SDL_types.h SDL_version.h SDL_video.h begin_code.h close_code.h
     1.9  
    1.10  LT_AGE      = @LT_AGE@
    1.11  LT_CURRENT  = @LT_CURRENT@
     2.1 --- a/Makefile.minimal	Mon Aug 25 08:50:37 2008 +0000
     2.2 +++ b/Makefile.minimal	Mon Aug 25 09:55:03 2008 +0000
     2.3 @@ -15,6 +15,7 @@
     2.4  	src/events/*.c \
     2.5  	src/file/*.c \
     2.6  	src/joystick/*.c \
     2.7 +	src/haptic/*.c \
     2.8  	src/stdlib/*.c \
     2.9  	src/thread/*.c \
    2.10  	src/timer/*.c \
    2.11 @@ -22,6 +23,7 @@
    2.12  	src/audio/dummy/*.c \
    2.13  	src/video/dummy/*.c \
    2.14  	src/joystick/dummy/*.c \
    2.15 +	src/haptic/dummy/*.c \
    2.16  	src/cdrom/dummy/*.c \
    2.17  	src/thread/generic/*.c \
    2.18  	src/timer/dummy/*.c \
     3.1 --- a/configure.in	Mon Aug 25 08:50:37 2008 +0000
     3.2 +++ b/configure.in	Mon Aug 25 09:55:03 2008 +0000
     3.3 @@ -235,6 +235,14 @@
     3.4  else
     3.5      SOURCES="$SOURCES $srcdir/src/joystick/*.c"
     3.6  fi
     3.7 +AC_ARG_ENABLE(haptic,
     3.8 +AC_HELP_STRING([--enable-haptic], [Enable the haptic (force feedback) subsystem [[default=yes]]]),
     3.9 +              , enable_haptic=yes)
    3.10 +if test x$enable_haptic != xyes; then
    3.11 +    AC_DEFINE(SDL_HAPTIC_DISABLED)
    3.12 +else
    3.13 +    SOURCES="$SOURCES $srcdir/src/haptic/*.c"
    3.14 +fi
    3.15  AC_ARG_ENABLE(cdrom,
    3.16  AC_HELP_STRING([--enable-cdrom], [Enable the cdrom subsystem [[default=yes]]]),
    3.17                , enable_cdrom=yes)
    3.18 @@ -2179,6 +2187,18 @@
    3.19              ;;
    3.20            esac
    3.21          fi
    3.22 +        # Set up files for the haptic library
    3.23 +        if test x$enable_haptic = xyes; then
    3.24 +           if test x$use_input_events = xyes; then
    3.25 +             case $ARCH in
    3.26 +               linux)
    3.27 +                   AC_DEFINE(SDL_HAPTIC_LINUX)
    3.28 +                   SOURCES="$SOURCES $srcdir/src/haptic/linux/*.c"
    3.29 +                   have_haptic=yes
    3.30 +               ;;
    3.31 +             esac
    3.32 +           fi
    3.33 +        fi
    3.34          # Set up files for the cdrom library
    3.35          if test x$enable_cdrom = xyes; then
    3.36            case $ARCH in
    3.37 @@ -2316,6 +2336,13 @@
    3.38              fi
    3.39              have_joystick=yes
    3.40          fi
    3.41 +        if test x$enable_haptic = xyes; then
    3.42 +            if test x$have_dinput = xyes; then
    3.43 +                AC_DEFINE(SDL_HAPTIC_DINPUT)
    3.44 +                SOURCES="$SOURCES $srcdir/src/haptic/win32/SDL_syshaptic.c"
    3.45 +                have_haptic=yes
    3.46 +            fi
    3.47 +        fi
    3.48          # Set up files for the cdrom library
    3.49          if test x$enable_cdrom = xyes; then
    3.50              AC_DEFINE(SDL_CDROM_WIN32)
    3.51 @@ -2457,6 +2484,13 @@
    3.52              SOURCES="$SOURCES $srcdir/src/joystick/darwin/*.c"
    3.53              have_joystick=yes
    3.54          fi
    3.55 +        # Set up files for the haptic library
    3.56 +        if test x$enable_haptic = xyes; then
    3.57 +            AC_DEFINE(SDL_HAPTIC_IOKIT)
    3.58 +            SOURCES="$SOURCES $srcdir/src/haptic/darwin/*.c"
    3.59 +            have_haptic=yes
    3.60 +            EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,ForceFeedback"
    3.61 +        fi
    3.62          # Set up files for the cdrom library
    3.63          if test x$enable_cdrom = xyes; then
    3.64              AC_DEFINE(SDL_CDROM_MACOSX)
    3.65 @@ -2565,6 +2599,12 @@
    3.66      SOURCES="$SOURCES $srcdir/src/joystick/dummy/*.c"
    3.67    fi
    3.68  fi
    3.69 +if test x$have_haptic != xyes; then
    3.70 +    if test x$enable_haptic = xyes; then
    3.71 +        AC_DEFINE(SDL_HAPTIC_DISABLED)
    3.72 +    fi
    3.73 +    SOURCES="$SOURCES $srcdir/src/haptic/dummy/*.c"
    3.74 +fi
    3.75  if test x$have_cdrom != xyes; then
    3.76      if test x$enable_cdrom = xyes; then
    3.77          AC_DEFINE(SDL_CDROM_DISABLED)
     4.1 --- a/include/SDL.h	Mon Aug 25 08:50:37 2008 +0000
     4.2 +++ b/include/SDL.h	Mon Aug 25 09:55:03 2008 +0000
     4.3 @@ -104,14 +104,15 @@
     4.4  /* These are the flags which may be passed to SDL_Init() -- you should
     4.5     specify the subsystems which you will be using in your application.
     4.6  */
     4.7 -#define	SDL_INIT_TIMER		0x00000001
     4.8 -#define SDL_INIT_AUDIO		0x00000010
     4.9 -#define SDL_INIT_VIDEO		0x00000020
    4.10 -#define SDL_INIT_CDROM		0x00000100
    4.11 -#define SDL_INIT_JOYSTICK	0x00000200
    4.12 -#define SDL_INIT_NOPARACHUTE	0x00100000      /* Don't catch fatal signals */
    4.13 -#define SDL_INIT_EVENTTHREAD	0x01000000      /* Not supported on all OS's */
    4.14 -#define SDL_INIT_EVERYTHING	0x0000FFFF
    4.15 +#define SDL_INIT_TIMER          0x00000001
    4.16 +#define SDL_INIT_AUDIO          0x00000010
    4.17 +#define SDL_INIT_VIDEO          0x00000020
    4.18 +#define SDL_INIT_CDROM          0x00000100
    4.19 +#define SDL_INIT_JOYSTICK       0x00000200
    4.20 +#define SDL_INIT_HAPTIC         0x00001000
    4.21 +#define SDL_INIT_NOPARACHUTE    0x00100000      /* Don't catch fatal signals */
    4.22 +#define SDL_INIT_EVENTTHREAD    0x01000000      /* Not supported on all OS's */
    4.23 +#define SDL_INIT_EVERYTHING     0x0000FFFF
    4.24  
    4.25  /* This function loads the SDL dynamically linked library and initializes 
    4.26   * the subsystems specified by 'flags' (and those satisfying dependencies)
     5.1 --- a/include/SDL_config.h.in	Mon Aug 25 08:50:37 2008 +0000
     5.2 +++ b/include/SDL_config.h.in	Mon Aug 25 09:55:03 2008 +0000
     5.3 @@ -149,6 +149,7 @@
     5.4  #undef SDL_EVENTS_DISABLED
     5.5  #undef SDL_FILE_DISABLED
     5.6  #undef SDL_JOYSTICK_DISABLED
     5.7 +#undef SDL_HAPTIC_DISABLED
     5.8  #undef SDL_LOADSO_DISABLED
     5.9  #undef SDL_THREADS_DISABLED
    5.10  #undef SDL_TIMERS_DISABLED
    5.11 @@ -215,6 +216,10 @@
    5.12  #undef SDL_JOYSTICK_WINMM
    5.13  #undef SDL_JOYSTICK_USBHID
    5.14  #undef SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
    5.15 +#undef SDL_HAPTIC_DUMMY
    5.16 +#undef SDL_HAPTIC_LINUX
    5.17 +#undef SDL_HAPTIC_IOKIT
    5.18 +#undef SDL_HAPTIC_DINPUT
    5.19  
    5.20  /* Enable various shared object loading systems */
    5.21  #undef SDL_LOADSO_BEOS
     6.1 --- a/include/SDL_config_dreamcast.h	Mon Aug 25 08:50:37 2008 +0000
     6.2 +++ b/include/SDL_config_dreamcast.h	Mon Aug 25 09:55:03 2008 +0000
     6.3 @@ -89,6 +89,7 @@
     6.4  
     6.5  /* Enable various input drivers */
     6.6  #define SDL_JOYSTICK_DC	1
     6.7 +#define SDL_HAPTIC_DUMMY	1
     6.8  
     6.9  /* Enable various shared object loading systems */
    6.10  #define SDL_LOADSO_DUMMY	1
     7.1 --- a/include/SDL_config_macosx.h	Mon Aug 25 08:50:37 2008 +0000
     7.2 +++ b/include/SDL_config_macosx.h	Mon Aug 25 09:55:03 2008 +0000
     7.3 @@ -99,6 +99,7 @@
     7.4  
     7.5  /* Enable various input drivers */
     7.6  #define SDL_JOYSTICK_IOKIT	1
     7.7 +#define SDL_HAPTIC_IOKIT	1
     7.8  
     7.9  /* Enable various shared object loading systems */
    7.10  #ifdef __ppc__
     8.1 --- a/include/SDL_config_minimal.h	Mon Aug 25 08:50:37 2008 +0000
     8.2 +++ b/include/SDL_config_minimal.h	Mon Aug 25 09:55:03 2008 +0000
     8.3 @@ -47,6 +47,9 @@
     8.4  /* Enable the stub joystick driver (src/joystick/dummy/\*.c) */
     8.5  #define SDL_JOYSTICK_DISABLED	1
     8.6  
     8.7 +/* Enable the stub haptic driver (src/haptic/dummy/\*.c) */
     8.8 +#define SDL_HAPTIC_DUMMY	1
     8.9 +
    8.10  /* Enable the stub shared object loader (src/loadso/dummy/\*.c) */
    8.11  #define SDL_LOADSO_DISABLED	1
    8.12  
     9.1 --- a/include/SDL_config_os2.h	Mon Aug 25 08:50:37 2008 +0000
     9.2 +++ b/include/SDL_config_os2.h	Mon Aug 25 09:55:03 2008 +0000
     9.3 @@ -118,6 +118,7 @@
     9.4  
     9.5  /* Enable various input drivers */
     9.6  #define SDL_JOYSTICK_OS2	1
     9.7 +#define SDL_HAPTIC_DUMMY	1
     9.8  
     9.9  /* Enable various shared object loading systems */
    9.10  #define SDL_LOADSO_OS2	1
    10.1 --- a/include/SDL_config_win32.h	Mon Aug 25 08:50:37 2008 +0000
    10.2 +++ b/include/SDL_config_win32.h	Mon Aug 25 09:55:03 2008 +0000
    10.3 @@ -139,8 +139,10 @@
    10.4  /* Enable various input drivers */
    10.5  #ifdef _WIN32_WCE
    10.6  #define SDL_JOYSTICK_DISABLED   1
    10.7 +#define SDL_HAPTIC_DUMMY	1
    10.8  #else
    10.9 -#define SDL_JOYSTICK_WINMM	1
   10.10 +#define SDL_JOYSTICK_DINPUT   1
   10.11 +#define SDL_HAPTIC_DINPUT	1
   10.12  #endif
   10.13  
   10.14  /* Enable various shared object loading systems */
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/include/SDL_haptic.h	Mon Aug 25 09:55:03 2008 +0000
    11.3 @@ -0,0 +1,1154 @@
    11.4 +/*
    11.5 +    SDL - Simple DirectMedia Layer
    11.6 +    Copyright (C) 2008 Edgar Simo
    11.7 +
    11.8 +    This library is free software; you can redistribute it and/or
    11.9 +    modify it under the terms of the GNU Lesser General Public
   11.10 +    License as published by the Free Software Foundation; either
   11.11 +    version 2.1 of the License, or (at your option) any later version.
   11.12 +
   11.13 +    This library is distributed in the hope that it will be useful,
   11.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   11.16 +    Lesser General Public License for more details.
   11.17 +
   11.18 +    You should have received a copy of the GNU Lesser General Public
   11.19 +    License along with this library; if not, write to the Free Software
   11.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   11.21 +
   11.22 +    Sam Lantinga
   11.23 +    slouken@libsdl.org
   11.24 +*/
   11.25 +
   11.26 +/**
   11.27 + * \file SDL_haptic.h
   11.28 + *
   11.29 + * \brief The SDL Haptic subsystem allows you to control haptic (force feedback)
   11.30 + *  devices.
   11.31 + *
   11.32 + * The basic usage is as follows:
   11.33 + *   - Initialize the Subsystem (SDL_INIT_HAPTIC).
   11.34 + *   - Open a Haptic Device.
   11.35 + *     - SDL_HapticOpen(...) to open from index.
   11.36 + *     - SDL_HapticOpenFromJoystick(...) to open from an existing joystick.
   11.37 + *   - Create an effect (SDL_HapticEffect).
   11.38 + *   - Upload the effect with SDL_HapticNewEffect(...).
   11.39 + *   - Run the effect with SDL_HapticRunEffect(...).
   11.40 + *   - (optional) Free the effect with SDL_HapticDestroyEffect(...).
   11.41 + *   - Close the haptic device with SDL_HapticClose(...).
   11.42 + *
   11.43 + * Example:
   11.44 + *
   11.45 + * \code
   11.46 + * int test_haptic( SDL_Joystick * joystick ) {
   11.47 + *    SDL_Haptic *haptic;
   11.48 + *    SDL_HapticEffect effect;
   11.49 + *    int effect_id;
   11.50 + *
   11.51 + *    // Open the device
   11.52 + *    haptic = SDL_HapticOpenFromJoystick( joystick );
   11.53 + *    if (haptic == NULL) return -1; // Most likely joystick isn't haptic
   11.54 + *
   11.55 + *    // See if it can do sine waves
   11.56 + *    if ((SDL_HapticQuery(haptic) & SDL_HAPTIC_SINE)==0) {
   11.57 + *       SDL_HapticClose(haptic); // No sine effect
   11.58 + *       return -1;
   11.59 + *    }
   11.60 + *
   11.61 + *    // Create the effect
   11.62 + *    memset( &effect, 0, sizeof(SDL_HapticEffect) ); // 0 is safe default
   11.63 + *    effect.type = SDL_HAPTIC_SINE;
   11.64 + *    effect.periodic.direction.type = SDL_HAPTIC_POLAR; // Polar coordinates
   11.65 + *    effect.periodic.direction.dir[0] = 18000; // Force comes from south
   11.66 + *    effect.periodic.period = 1000; // 1000 ms
   11.67 + *    effect.periodic.magnitude = 20000; // 20000/32767 strength
   11.68 + *    effect.periodic.length = 5000; // 5 seconds long
   11.69 + *    effect.periodic.attack_length = 1000; // Takes 1 second to get max strength
   11.70 + *    effect.periodic.fade_length = 1000; // Takes 1 second to fade away
   11.71 + *
   11.72 + *    // Upload the effect
   11.73 + *    effect_id = SDL_HapticNewEffect( haptic, &effect );
   11.74 + *
   11.75 + *    // Test the effect
   11.76 + *    SDL_HapticRunEffect( haptic, effect_id, 1 );
   11.77 + *    SDL_Delay( 5000); // Wait for the effect to finish
   11.78 + *
   11.79 + *    // We destroy the effect, although closing the device also does this
   11.80 + *    SDL_HapticDestroyEffect( haptic, effect_id );
   11.81 + *
   11.82 + *    // Close the device
   11.83 + *    SDL_HapticClose(haptic);
   11.84 + *
   11.85 + *    return 0; // Success
   11.86 + * }
   11.87 + * \endcode
   11.88 + *
   11.89 + * \author Edgar Simo Serra
   11.90 + */
   11.91 +
   11.92 +#ifndef _SDL_haptic_h
   11.93 +#define _SDL_haptic_h
   11.94 +
   11.95 +#include "SDL_stdinc.h"
   11.96 +#include "SDL_error.h"
   11.97 +#include "SDL_joystick.h"
   11.98 +
   11.99 +#include "begin_code.h"
  11.100 +/* Set up for C function definitions, even when using C++ */
  11.101 +#ifdef __cplusplus
  11.102 +/* *INDENT-OFF* */
  11.103 +extern "C" {
  11.104 +   /* *INDENT-ON* */                                                         
  11.105 +#endif /* __cplusplus */
  11.106 +
  11.107 +/**
  11.108 + * \typedef SDL_Haptic
  11.109 + *
  11.110 + * \brief The haptic structure used to identify an SDL haptic.
  11.111 + *
  11.112 + * \sa SDL_HapticOpen
  11.113 + * \sa SDL_HapticOpenFromJoystick
  11.114 + * \sa SDL_HapticClose
  11.115 + */
  11.116 +struct _SDL_Haptic;
  11.117 +typedef struct _SDL_Haptic SDL_Haptic;
  11.118 +
  11.119 +
  11.120 +/*
  11.121 + * Different haptic features a device can have.
  11.122 + */
  11.123 +/**
  11.124 + * \def SDL_HAPTIC_CONSTANT
  11.125 + *
  11.126 + * \brief Constant haptic effect.
  11.127 + *
  11.128 + * \sa SDL_HapticCondition
  11.129 + */
  11.130 +#define SDL_HAPTIC_CONSTANT   (1<<0)    /* Constant effect supported */
  11.131 +/**
  11.132 + * \def SDL_HAPTIC_SINE
  11.133 + *
  11.134 + * \brief Periodic haptic effect that simulates sine waves.
  11.135 + *
  11.136 + * \sa SDL_HapticPeriodic
  11.137 + */
  11.138 +#define SDL_HAPTIC_SINE       (1<<1)    /* Sine wave effect supported */
  11.139 +/**
  11.140 + * \def SDL_HAPTIC_SQUARE
  11.141 + *
  11.142 + * \brief Periodic haptic effect that simulates square waves.
  11.143 + * 
  11.144 + * \sa SDL_HapticPeriodic
  11.145 + */
  11.146 +#define SDL_HAPTIC_SQUARE     (1<<2)    /* Square wave effect supported */
  11.147 +/**
  11.148 + * \def SDL_HAPTIC_TRIANGLE
  11.149 + *
  11.150 + * \brief Periodic haptic effect that simulates triangular waves.
  11.151 + *
  11.152 + * \sa SDL_HapticPeriodic
  11.153 + */
  11.154 +#define SDL_HAPTIC_TRIANGLE   (1<<3)    /* Triangle wave effect supported */
  11.155 +/**
  11.156 + * \def SDL_HAPTIC_SAWTOOTHUP
  11.157 + *
  11.158 + * \brief Periodic haptic effect that simulates saw tooth up waves.
  11.159 + *
  11.160 + * \sa SDL_HapticPeriodic
  11.161 + */
  11.162 +#define SDL_HAPTIC_SAWTOOTHUP (1<<4)    /* Sawtoothup wave effect supported */
  11.163 +/**
  11.164 + * \def SDL_HAPTIC_SAWTOOTHDOWN
  11.165 + *
  11.166 + * \brief Periodic haptic effect that simulates saw tooth down waves.
  11.167 + *
  11.168 + * \sa SDL_HapticPeriodic
  11.169 + */
  11.170 +#define SDL_HAPTIC_SAWTOOTHDOWN (1<<5)  /* Sawtoothdown wave effect supported */
  11.171 +/**
  11.172 + * \def SDL_HAPTIC_RAMP
  11.173 + *
  11.174 + * \brief Ramp haptic effect.
  11.175 + *
  11.176 + * \sa SDL_HapticRamp
  11.177 + */
  11.178 +#define SDL_HAPTIC_RAMP       (1<<6)    /* Ramp effect supported */
  11.179 +/**
  11.180 + * \def SDL_HAPTIC_SPRING
  11.181 + *
  11.182 + * \brief Condition haptic effect that simulates a spring.  Effect is based on the
  11.183 + * axes position.
  11.184 + *
  11.185 + * \sa SDL_HapticCondition
  11.186 + */
  11.187 +#define SDL_HAPTIC_SPRING     (1<<7)    /* Spring effect supported - uses axes position */
  11.188 +/**
  11.189 + * \def SDL_HAPTIC_DAMPER
  11.190 + *
  11.191 + * \brief Condition haptic effect that simulates dampening.  Effect is based on the
  11.192 + * axes velocity.
  11.193 + *
  11.194 + * \sa SDL_HapticCondition
  11.195 + */
  11.196 +#define SDL_HAPTIC_DAMPER     (1<<8)    /* Damper effect supported - uses axes velocity */
  11.197 +/**
  11.198 + * \def SDL_HAPTIC_INERTIA
  11.199 + *
  11.200 + * \brief Condition haptic effect that simulates inertia.  Effect is based on the axes
  11.201 + * acceleration.
  11.202 + *
  11.203 + * \sa SDL_HapticCondition
  11.204 + */
  11.205 +#define SDL_HAPTIC_INERTIA    (1<<9)    /* Inertia effect supported - uses axes acceleration */
  11.206 +/**
  11.207 + * \def SDL_HAPTIC_FRICTION
  11.208 + *
  11.209 + * \brief Condition haptic effect that simulates friction.  Effect is based on the axes
  11.210 + * movement.
  11.211 + *
  11.212 + * \sa SDL_HapticCondition
  11.213 + */
  11.214 +#define SDL_HAPTIC_FRICTION   (1<<10)   /* Friction effect supported - uses axes movement */
  11.215 +/**
  11.216 + * \def SDL_HAPTIC_CUSTOM
  11.217 + *
  11.218 + * \brief User defined custom haptic effect.
  11.219 + */
  11.220 +#define SDL_HAPTIC_CUSTOM     (1<<11)   /* Custom effect is supported */
  11.221 +/* These last two are features the device has, not effects */
  11.222 +/**
  11.223 + * \def SDL_HAPTIC_GAIN
  11.224 + *
  11.225 + * \brief Device supports setting the global gain.
  11.226 + *
  11.227 + * \sa SDL_HapticSetGain
  11.228 + */
  11.229 +#define SDL_HAPTIC_GAIN       (1<<12)   /* Device can set global gain */
  11.230 +/**
  11.231 + * \def SDL_HAPTIC_AUTOCENTER
  11.232 + *
  11.233 + * \brief Device supports setting autocenter.
  11.234 + *
  11.235 + * \sa SDL_HapticSetAutocenter
  11.236 + */
  11.237 +#define SDL_HAPTIC_AUTOCENTER (1<<13)   /* Device can set autocenter */
  11.238 +/**
  11.239 + * \def SDL_HAPTIC_STATUS
  11.240 + *
  11.241 + * \brief Device can be queried for effect status.
  11.242 + *
  11.243 + * \sa SDL_HapticGetEffectStatus
  11.244 + */
  11.245 +#define SDL_HAPTIC_STATUS     (1<<14)   /* Device can be queried for effect status */
  11.246 +/**
  11.247 + * \def SDL_HAPTIC_PAUSE
  11.248 + *
  11.249 + * \brief Device can be paused.
  11.250 + *
  11.251 + * \sa SDL_HapticPause
  11.252 + * \sa SDL_HapticUnpause
  11.253 + */
  11.254 +#define SDL_HAPTIC_PAUSE      (1<<15)   /* Device can be paused. */
  11.255 +
  11.256 +
  11.257 +/*
  11.258 + * Direction encodings
  11.259 + */
  11.260 +/**
  11.261 + * \def SDL_HAPTIC_POLAR
  11.262 + *
  11.263 + * \brief Uses polar coordinates for the direction.
  11.264 + *
  11.265 + * \sa SDL_HapticDirection
  11.266 + */
  11.267 +#define SDL_HAPTIC_POLAR      0
  11.268 +/**
  11.269 + * \def SDL_HAPTIC_CARTESIAN
  11.270 + *
  11.271 + * \brief Uses cartesian coordinates for the direction.
  11.272 + *
  11.273 + * \sa SDL_HapticDirection
  11.274 + */
  11.275 +#define SDL_HAPTIC_CARTESIAN  1
  11.276 +/**
  11.277 + * \def SDL_HAPTIC_SPHERICAL
  11.278 + *
  11.279 + * \brief Uses spherical coordinates for the direction.
  11.280 + *
  11.281 + * \sa SDL_HapticDirection
  11.282 + */
  11.283 +#define SDL_HAPTIC_SPHERICAL  2
  11.284 +
  11.285 +
  11.286 +/*
  11.287 + * Misc defines.
  11.288 + */
  11.289 +/**
  11.290 + * \def SDL_HAPTIC_INFINITY
  11.291 + *
  11.292 + * \brief Used to play a device an infinite number of times.
  11.293 + *
  11.294 + * \sa SDL_HapticRunEffect
  11.295 + */
  11.296 +#define SDL_HAPTIC_INFINITY   4294967295U
  11.297 +
  11.298 +
  11.299 +/**
  11.300 + * \struct SDL_HapticDirection
  11.301 + *
  11.302 + * \brief Structure that represents a haptic direction.
  11.303 + *
  11.304 + * Directions can be specified by:
  11.305 + *   - SDL_HAPTIC_POLAR : Specified by polar coordinates.
  11.306 + *   - SDL_HAPTIC_CARTESIAN : Specified by cartesian coordinates.
  11.307 + *   - SDL_HAPTIC_SPHERICAL : Specified by spherical coordinates.
  11.308 + *
  11.309 + * Cardinal directions of the haptic device are relative to the positioning
  11.310 + *  of the device.  North is considered to be away from the user.
  11.311 + *
  11.312 + * The following diagram represents the cardinal directions:
  11.313 + * \code
  11.314 + *              .--.
  11.315 + *              |__| .-------.
  11.316 + *              |=.| |.-----.|
  11.317 + *              |--| ||     ||
  11.318 + *              |  | |'-----'|
  11.319 + *              |__|~')_____('
  11.320 + *                [ COMPUTER ]
  11.321 + *
  11.322 + *
  11.323 + *                  North (0,-1)
  11.324 + *                      ^
  11.325 + *                      |
  11.326 + *                      |
  11.327 + * (1,0)  West <----[ HAPTIC ]----> East (-1,0)
  11.328 + *                      |
  11.329 + *                      |
  11.330 + *                      v
  11.331 + *                   South (0,1)
  11.332 + *
  11.333 + *
  11.334 + *                   [ USER ]
  11.335 + *                     \|||/
  11.336 + *                     (o o)
  11.337 + *               ---ooO-(_)-Ooo---
  11.338 + * \endcode
  11.339 + *
  11.340 + * If type is SDL_HAPTIC_POLAR, direction is encoded by hundredths of a 
  11.341 + *  degree starting north and turning clockwise.  SDL_HAPTIC_POLAR only uses
  11.342 + *  the first dir parameter.  The cardinal directions would be:
  11.343 + *   - North: 0 (0 degrees)
  11.344 + *   - East: 9000 (90 degrees)
  11.345 + *   - South: 18000 (180 degrees)
  11.346 + *   - West: 27000 (270 degrees)
  11.347 + *
  11.348 + * If type is SDL_HAPTIC_CARTESIAN, direction is encoded by three positions
  11.349 + *  (X axis, Y axis and Z axis (with 3 axes)).  SDL_HAPTIC_CARTESIAN uses
  11.350 + *  the first three dir parameters.  The cardinal directions would be:
  11.351 + *   - North:  0,-1, 0
  11.352 + *   - East:  -1, 0, 0
  11.353 + *   - South:  0, 1, 0
  11.354 + *   - West:   1, 0, 0
  11.355 + *  The Z axis represents the height of the effect if supported, otherwise
  11.356 + *  it's unused.  In cartesian encoding (1,2) would be the same as (2,4), you
  11.357 + *  can use any multiple you want, only the direction matters.
  11.358 + *
  11.359 + * If type is SDL_HAPTIC_SPHERICAL, direction is encoded by two rotations.
  11.360 + *  The first two  dir parameters are used.  The dir parameters are as follows
  11.361 + *  (all values are in hundredths of degrees):
  11.362 + *    1) Degrees from (1, 0) rotated towards (0, 1).
  11.363 + *    2) Degrees towards (0, 0, 1) (device needs at least 3 axes).
  11.364 + *
  11.365 + *
  11.366 + * Example of force coming from the south with all encodings (force coming
  11.367 + *  from the south means the user will have to pull the stick to counteract):
  11.368 + * \code
  11.369 + * SDL_HapticDirection direction;
  11.370 + *
  11.371 + * // Cartesian directions
  11.372 + * direction.type = SDL_HAPTIC_CARTESIAN; // Using cartesian direction encoding.
  11.373 + * direction.dir[0] = 0; // X position
  11.374 + * direction.dir[1] = 1; // Y position
  11.375 + * // Assuming the device has 2 axes, we don't need to specify third parameter.
  11.376 + *
  11.377 + * // Polar directions
  11.378 + * direction.type = SDL_HAPTIC_POLAR; // We'll be using polar direction encoding.
  11.379 + * direction.dir[0] = 18000; // Polar only uses first parameter
  11.380 + *
  11.381 + * // Spherical coordinates
  11.382 + * direction.type = SDL_HAPTIC_SPHERICAL; // Spherical encoding
  11.383 + * direction.dir[0] = 9000; // Since we only have two axes we don't need more parameters.
  11.384 + * \endcode
  11.385 + *
  11.386 + * \sa SDL_HAPTIC_POLAR
  11.387 + * \sa SDL_HAPTIC_CARTESIAN
  11.388 + * \sa SDL_HAPTIC_SPHERICAL
  11.389 + * \sa SDL_HapticEffect
  11.390 + * \sa SDL_HapticNumAxes
  11.391 + */
  11.392 +typedef struct SDL_HapticDirection
  11.393 +{
  11.394 +    Uint8 type;         /**< The type of encoding. */
  11.395 +    Uint16 dir[3];      /**< The encoded direction. */
  11.396 +} SDL_HapticDirection;
  11.397 +
  11.398 +
  11.399 +/**
  11.400 + * \struct SDL_HapticConstant
  11.401 + *
  11.402 + * \brief A structure containing a template for a Constant effect.
  11.403 + *
  11.404 + * The struct is exclusive to the SDL_HAPTIC_CONSTANT effect.
  11.405 + *
  11.406 + * A constant effect applies a constant force in the specified direction
  11.407 + *  to the joystick.
  11.408 + *
  11.409 + * \sa SDL_HAPTIC_CONSTANT
  11.410 + * \sa SDL_HapticEffect
  11.411 + */
  11.412 +typedef struct SDL_HapticConstant
  11.413 +{
  11.414 +    /* Header */
  11.415 +    Uint16 type;            /**< SDL_HAPTIC_CONSTANT */
  11.416 +    SDL_HapticDirection direction;  /**< Direction of the effect. */
  11.417 +
  11.418 +    /* Replay */
  11.419 +    Uint32 length;          /**< Duration of the effect. */
  11.420 +    Uint16 delay;           /**< Delay before starting the effect. */
  11.421 +
  11.422 +    /* Trigger */
  11.423 +    Uint16 button;          /**< Button that triggers the effect. */
  11.424 +    Uint16 interval;        /**< How soon it can be triggered again after button. */
  11.425 +
  11.426 +    /* Constant */
  11.427 +    Sint16 level;           /**< Strength of the constant effect. */
  11.428 +
  11.429 +    /* Envelope */
  11.430 +    Uint16 attack_length;   /**< Duration of the attack. */
  11.431 +    Uint16 attack_level;    /**< Level at the start of the attack. */
  11.432 +    Uint16 fade_length;     /**< Duration of the fade. */
  11.433 +    Uint16 fade_level;      /**< Level at the end of the fade. */
  11.434 +} SDL_HapticConstant;
  11.435 +/**
  11.436 + * \struct SDL_HapticPeriodic
  11.437 + *
  11.438 + * \brief A structure containing a template for a Periodic effect.
  11.439 + *
  11.440 + * The struct handles the following effects:
  11.441 + *   - SDL_HAPTIC_SINE
  11.442 + *   - SDL_HAPTIC_SQUARE
  11.443 + *   - SDL_HAPTIC_TRIANGLE
  11.444 + *   - SDL_HAPTIC_SAWTOOTHUP
  11.445 + *   - SDL_HAPTIC_SAWTOOTHDOWN
  11.446 + *
  11.447 + * A periodic effect consists in a wave-shaped effect that repeats itself
  11.448 + *  over time.  The type determines the shape of the wave and the parameters
  11.449 + *  determine the dimensions of the wave.
  11.450 + *
  11.451 + * Phase is given by hundredth of a cyle meaning that giving the phase a value
  11.452 + *  of 9000 will displace it 25% of it's period.  Here are sample values:
  11.453 + *    -     0: No phase displacement.
  11.454 + *    -  9000: Displaced 25% of it's period.
  11.455 + *    - 18000: Displaced 50% of it's period.
  11.456 + *    - 27000: Displaced 75% of it's period.
  11.457 + *    - 36000: Displaced 100% of it's period, same as 0, but 0 is preffered.
  11.458 + *
  11.459 + * Examples:
  11.460 + * \code
  11.461 + * SDL_HAPTIC_SINE
  11.462 + *   __      __      __      __
  11.463 + *  /  \    /  \    /  \    /
  11.464 + * /    \__/    \__/    \__/
  11.465 + *
  11.466 + * SDL_HAPTIC_SQUARE
  11.467 + *  __    __    __    __    __
  11.468 + * |  |  |  |  |  |  |  |  |  |
  11.469 + * |  |__|  |__|  |__|  |__|  |
  11.470 + *
  11.471 + * SDL_HAPTIC_TRIANGLE
  11.472 + *   /\    /\    /\    /\    /\
  11.473 + *  /  \  /  \  /  \  /  \  /
  11.474 + * /    \/    \/    \/    \/
  11.475 + *
  11.476 + * SDL_HAPTIC_SAWTOOTHUP
  11.477 + *   /|  /|  /|  /|  /|  /|  /|
  11.478 + *  / | / | / | / | / | / | / |
  11.479 + * /  |/  |/  |/  |/  |/  |/  |
  11.480 + *
  11.481 + * SDL_HAPTIC_SAWTOOTHDOWN
  11.482 + * \  |\  |\  |\  |\  |\  |\  |
  11.483 + *  \ | \ | \ | \ | \ | \ | \ |
  11.484 + *   \|  \|  \|  \|  \|  \|  \|
  11.485 + * \endcode
  11.486 + *
  11.487 + * \sa SDL_HAPTIC_SINE
  11.488 + * \sa SDL_HAPTIC_SQUARE
  11.489 + * \sa SDL_HAPTIC_TRIANGLE
  11.490 + * \sa SDL_HAPTIC_SAWTOOTHUP
  11.491 + * \sa SDL_HAPTIC_SAWTOOTHDOWN
  11.492 + * \sa SDL_HapticEffect
  11.493 + */
  11.494 +typedef struct SDL_HapticPeriodic
  11.495 +{
  11.496 +    /* Header */
  11.497 +    Uint16 type;        /**< SDL_HAPTIC_SINE, SDL_HAPTIC_SQUARE,
  11.498 +                             SDL_HAPTIC_TRIANGLE, SDL_HAPTIC_SAWTOOTHUP or
  11.499 +                             SDL_HAPTIC_SAWTOOTHDOWN */
  11.500 +    SDL_HapticDirection direction;  /**< Direction of the effect. */
  11.501 +
  11.502 +    /* Replay */
  11.503 +    Uint32 length;      /**< Duration of the effect. */
  11.504 +    Uint16 delay;       /**< Delay before starting the effect. */
  11.505 +
  11.506 +    /* Trigger */
  11.507 +    Uint16 button;      /**< Button that triggers the effect. */
  11.508 +    Uint16 interval;    /**< How soon it can be triggered again after button. */
  11.509 +
  11.510 +    /* Periodic */
  11.511 +    Uint16 period;      /**< Period of the wave. */
  11.512 +    Sint16 magnitude;   /**< Peak value. */
  11.513 +    Sint16 offset;      /**< Mean value of the wave. */
  11.514 +    Uint16 phase;       /**< Horizontal shift given by hundredth of a cycle. */
  11.515 +
  11.516 +    /* Envelope */
  11.517 +    Uint16 attack_length;   /**< Duration of the attack. */
  11.518 +    Uint16 attack_level;    /**< Level at the start of the attack. */
  11.519 +    Uint16 fade_length; /**< Duration of the fade. */
  11.520 +    Uint16 fade_level;  /**< Level at the end of the fade. */
  11.521 +} SDL_HapticPeriodic;
  11.522 +/**
  11.523 + * \struct SDL_HapticCondition
  11.524 + *
  11.525 + * \brief A structure containing a template for a Condition effect.
  11.526 + *
  11.527 + * The struct handles the following effects:
  11.528 + *   - SDL_HAPTIC_SPRING: Effect based on axes position.
  11.529 + *   - SDL_HAPTIC_DAMPER: Effect based on axes velocity.
  11.530 + *   - SDL_HAPTIC_INERTIA: Effect based on axes acceleration.
  11.531 + *   - SDL_HAPTIC_FRICTION: Effect based on axes movement.
  11.532 + *
  11.533 + * Direction is handled by condition internals instead of a direction member.
  11.534 + *  The condition effect specific members have three parameters.  The first
  11.535 + *  refers to the X axis, the second refers to the Y axis and the third
  11.536 + *  refers to the Z axis.  The right terms refer to the positive side of the
  11.537 + *  axis and the left terms refer to the negative side of the axis.  Please 
  11.538 + *  refer to the SDL_HapticDirection  diagram for which side is positive and
  11.539 + *  which is negative.
  11.540 + *
  11.541 + * \sa SDL_HapticDirection
  11.542 + * \sa SDL_HAPTIC_SPRING
  11.543 + * \sa SDL_HAPTIC_DAMPER
  11.544 + * \sa SDL_HAPTIC_INERTIA
  11.545 + * \sa SDL_HAPTIC_FRICTION
  11.546 + * \sa SDL_HapticEffect
  11.547 + */
  11.548 +typedef struct SDL_HapticCondition
  11.549 +{
  11.550 +    /* Header */
  11.551 +    Uint16 type;            /**< SDL_HAPTIC_SPRING, SDL_HAPTIC_DAMPER,
  11.552 +                                 SDL_HAPTIC_INERTIA or SDL_HAPTIC_FRICTION */
  11.553 +    SDL_HapticDirection direction;  /**< Direction of the effect - Not used ATM. */
  11.554 +
  11.555 +    /* Replay */
  11.556 +    Uint32 length;          /**< Duration of the effect. */
  11.557 +    Uint16 delay;           /**< Delay before starting the effect. */
  11.558 +
  11.559 +    /* Trigger */
  11.560 +    Uint16 button;          /**< Button that triggers the effect. */
  11.561 +    Uint16 interval;        /**< How soon it can be triggered again after button. */
  11.562 +
  11.563 +    /* Condition */
  11.564 +    Uint16 right_sat[3];    /**< Level when joystick is to the positive side. */
  11.565 +    Uint16 left_sat[3];     /**< Level when joystick is to the negative side. */
  11.566 +    Sint16 right_coeff[3];  /**< How fast to increase the force towards the positive side. */
  11.567 +    Sint16 left_coeff[3];   /**< How fast to increase the force towards the negative side. */
  11.568 +    Uint16 deadband[3];     /**< Size of the dead zone. */
  11.569 +    Sint16 center[3];       /**< Position of the dead zone. */
  11.570 +} SDL_HapticCondition;
  11.571 +/**
  11.572 + * \struct SDL_HapticRamp
  11.573 + *
  11.574 + * \brief A structure containing a template for a Ramp effect.
  11.575 + *
  11.576 + * This struct is exclusively for the SDL_HAPTIC_RAMP effect.
  11.577 + *
  11.578 + * The ramp effect starts at start strength and ends at end strength.
  11.579 + *  It augments in linear fashion.  If you use attack and fade with a ramp
  11.580 + *  they effects get added to the ramp effect making the effect become
  11.581 + *  quadratic instead of linear.
  11.582 + *
  11.583 + * \sa SDL_HAPTIC_RAMP
  11.584 + * \sa SDL_HapticEffect
  11.585 + */
  11.586 +typedef struct SDL_HapticRamp
  11.587 +{
  11.588 +    /* Header */
  11.589 +    Uint16 type;            /**< SDL_HAPTIC_RAMP */
  11.590 +    SDL_HapticDirection direction;  /**< Direction of the effect. */
  11.591 +
  11.592 +    /* Replay */
  11.593 +    Uint32 length;          /**< Duration of the effect. */
  11.594 +    Uint16 delay;           /**< Delay before starting the effect. */
  11.595 +
  11.596 +    /* Trigger */
  11.597 +    Uint16 button;          /**< Button that triggers the effect. */
  11.598 +    Uint16 interval;        /**< How soon it can be triggered again after button. */
  11.599 +
  11.600 +    /* Ramp */
  11.601 +    Sint16 start;           /**< Beginning strength level. */
  11.602 +    Sint16 end;             /**< Ending strength level. */
  11.603 +
  11.604 +    /* Envelope */
  11.605 +    Uint16 attack_length;   /**< Duration of the attack. */
  11.606 +    Uint16 attack_level;    /**< Level at the start of the attack. */
  11.607 +    Uint16 fade_length;     /**< Duration of the fade. */
  11.608 +    Uint16 fade_level;      /**< Level at the end of the fade. */
  11.609 +} SDL_HapticRamp;
  11.610 +/**
  11.611 + * \struct SDL_HapticCustom
  11.612 + *
  11.613 + * \brief A structure containing a template for the SDL_HAPTIC_CUSTOM effect.
  11.614 + *
  11.615 + * A custom force feedback effect is much like a periodic effect, where the
  11.616 + *  application can define it's exact shape.  You will have to allocate the
  11.617 + *  data yourself.  Data should consist of channels * samples Uint16 samples.
  11.618 + *
  11.619 + * If channels is one, the effect is rotated using the defined direction.
  11.620 + *  Otherwise it uses the samples in data for the different axes.
  11.621 + *
  11.622 + * \sa SDL_HAPTIC_CUSTOM
  11.623 + * \sa SDL_HapticEffect
  11.624 + */
  11.625 +typedef struct SDL_HapticCustom
  11.626 +{
  11.627 +    /* Header */
  11.628 +    Uint16 type;            /**< SDL_HAPTIC_CUSTOM */
  11.629 +    SDL_HapticDirection direction;  /**< Direction of the effect. */
  11.630 +
  11.631 +    /* Replay */
  11.632 +    Uint32 length;          /**< Duration of the effect. */
  11.633 +    Uint16 delay;           /**< Delay before starting the effect. */
  11.634 +
  11.635 +    /* Trigger */
  11.636 +    Uint16 button;          /**< Button that triggers the effect. */
  11.637 +    Uint16 interval;        /**< How soon it can be triggered again after button. */
  11.638 +
  11.639 +    /* Custom */
  11.640 +    Uint8 channels;         /**< Axes to use, minimum of one. */
  11.641 +    Uint16 period;          /**< Sample periods. */
  11.642 +    Uint16 samples;         /**< Amount of samples. */
  11.643 +    Uint16 *data;           /**< Should contain channels*samples items. */
  11.644 +
  11.645 +    /* Envelope */
  11.646 +    Uint16 attack_length;   /**< Duration of the attack. */
  11.647 +    Uint16 attack_level;    /**< Level at the start of the attack. */
  11.648 +    Uint16 fade_length;     /**< Duration of the fade. */
  11.649 +    Uint16 fade_level;      /**< Level at the end of the fade. */
  11.650 +} SDL_HapticCustom;
  11.651 +/**
  11.652 + * \union SDL_HapticEffect
  11.653 + *
  11.654 + * \brief The generic template for any haptic effect.
  11.655 + *
  11.656 + * All values max at 32767 (0x7FFF).  Signed values also can be negative.
  11.657 + *  Time values unless specified otherwise are in milliseconds.
  11.658 + *
  11.659 + * You can also pass SDL_HAPTIC_INFINITY to length instead of a 0-32767 value.
  11.660 + *  Neither delay, interval, attack_length nor fade_length support 
  11.661 + *  SDL_HAPTIC_INFINITY.  Fade will also not be used since effect never ends.
  11.662 + *
  11.663 + * Additionally, the SDL_HAPTIC_RAMP effect does not support a duration of
  11.664 + *  SDL_HAPTIC_INFINITY.
  11.665 + *
  11.666 + * Button triggers may not be supported on all devices, it is advised to not
  11.667 + *  use them if possible.  Buttons start at index 1 instead of index 0 like
  11.668 + *  they joystick.
  11.669 + *
  11.670 + * If both attack_length and fade_level are 0, the envelope is not used,
  11.671 + *  otherwise both values are used.
  11.672 + *
  11.673 + * Common parts:
  11.674 + * \code
  11.675 + * // Replay - All effects have this
  11.676 + * Uint32 length;        // Duration of effect (ms).
  11.677 + * Uint16 delay;         // Delay before starting effect.
  11.678 + *
  11.679 + * // Trigger - All effects have this
  11.680 + * Uint16 button;        // Button that triggers effect.
  11.681 + * Uint16 interval;      // How soon before effect can be triggered again.
  11.682 + *
  11.683 + * // Envelope - All effects except condition effects have this
  11.684 + * Uint16 attack_length; // Duration of the attack (ms).
  11.685 + * Uint16 attack_level;  // Level at the start of the attack.
  11.686 + * Uint16 fade_length;   // Duration of the fade out (ms).
  11.687 + * Uint16 fade_level;    // Level at the end of the fade.
  11.688 + * \endcode
  11.689 + *
  11.690 + *
  11.691 + * Here we have an example of a constant effect evolution in time:
  11.692 + *
  11.693 + * \code
  11.694 + * Strength
  11.695 + * ^
  11.696 + * |
  11.697 + * |    effect level -->  _________________
  11.698 + * |                     /                 \
  11.699 + * |                    /                   \
  11.700 + * |                   /                     \
  11.701 + * |                  /                       \ 
  11.702 + * | attack_level --> |                        \
  11.703 + * |                  |                        |  <---  fade_level
  11.704 + * |
  11.705 + * +--------------------------------------------------> Time
  11.706 + *                    [--]                 [---]
  11.707 + *                    attack_length        fade_length
  11.708 + * 
  11.709 + * [------------------][-----------------------]
  11.710 + * delay               length
  11.711 + * \endcode
  11.712 + *
  11.713 + * Note either the attack_level or the fade_level may be above the actual
  11.714 + *  effect level.
  11.715 + *
  11.716 + * \sa SDL_HapticConstant
  11.717 + * \sa SDL_HapticPeriodic
  11.718 + * \sa SDL_HapticCondition
  11.719 + * \sa SDL_HapticRamp
  11.720 + * \sa SDL_HapticCustom
  11.721 + */
  11.722 +typedef union SDL_HapticEffect
  11.723 +{
  11.724 +    /* Common for all force feedback effects */
  11.725 +    Uint16 type;                    /**< Effect type. */
  11.726 +    SDL_HapticConstant constant;    /**< Constant effect. */
  11.727 +    SDL_HapticPeriodic periodic;    /**< Periodic effect. */
  11.728 +    SDL_HapticCondition condition;  /**< Condition effect. */
  11.729 +    SDL_HapticRamp ramp;            /**< Ramp effect. */
  11.730 +    SDL_HapticCustom custom;        /**< Custom effect. */
  11.731 +} SDL_HapticEffect;
  11.732 +
  11.733 +
  11.734 +/* Function prototypes */
  11.735 +/**
  11.736 + * \fn int SDL_NumHaptics(void)
  11.737 + *
  11.738 + * \brief Count the number of joysticks attached to the system.
  11.739 + *
  11.740 + *    \return Number of haptic devices detected on the system.
  11.741 + */
  11.742 +extern DECLSPEC int SDLCALL SDL_NumHaptics(void);
  11.743 +
  11.744 +/**
  11.745 + * \fn const char * SDL_HapticName(int device_index)
  11.746 + *
  11.747 + * \brief Get the implementation dependent name of a Haptic device.
  11.748 + * This can be called before any joysticks are opened.
  11.749 + * If no name can be found, this function returns NULL.
  11.750 + *
  11.751 + *    \param device_index Index of the device to get it's name.
  11.752 + *    \return Name of the device or NULL on error.
  11.753 + *
  11.754 + * \sa SDL_NumHaptics
  11.755 + */
  11.756 +extern DECLSPEC const char *SDLCALL SDL_HapticName(int device_index);
  11.757 +
  11.758 +/**
  11.759 + * \fn SDL_Haptic * SDL_HapticOpen(int device_index)
  11.760 + *
  11.761 + * \brief Opens a Haptic device for usage - the index passed as an
  11.762 + * argument refers to the N'th Haptic device on this system.
  11.763 + *
  11.764 + * When opening a haptic device, it's gain will be set to maximum and
  11.765 + *  autocenter will be disabled.  To modify these values use
  11.766 + *  SDL_HapticSetGain and SDL_HapticSetAutocenter
  11.767 + *
  11.768 + *    \param device_index Index of the device to open.
  11.769 + *    \return Device identifier or NULL on error.
  11.770 + *
  11.771 + * \sa SDL_HapticIndex
  11.772 + * \sa SDL_HapticOpenFromMouse
  11.773 + * \sa SDL_HapticOpenFromJoystick
  11.774 + * \sa SDL_HapticClose
  11.775 + * \sa SDL_HapticSetGain
  11.776 + * \sa SDL_HapticSetAutocenter
  11.777 + * \sa SDL_HapticPause
  11.778 + * \sa SDL_HapticStopAll
  11.779 + */
  11.780 +extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpen(int device_index);
  11.781 +
  11.782 +/**
  11.783 + * \fn int SDL_HapticOpened(int device_index)
  11.784 + *
  11.785 + * \brief Checks if the haptic device at index has been opened.
  11.786 + *
  11.787 + *    \param device_index Index to check to see if it has been opened.
  11.788 + *    \return 1 if it has been opened or 0 if it hasn't.
  11.789 + * 
  11.790 + * \sa SDL_HapticOpen
  11.791 + * \sa SDL_HapticIndex
  11.792 + */
  11.793 +extern DECLSPEC int SDLCALL SDL_HapticOpened(int device_index);
  11.794 +
  11.795 +/**
  11.796 + * \fn int SDL_HapticIndex(SDL_Haptic * haptic)
  11.797 + *
  11.798 + * \brief Gets the index of a haptic device.
  11.799 + *
  11.800 + *    \param haptic Haptic device to get the index of.
  11.801 + *    \return The index of the haptic device or -1 on error.
  11.802 + *
  11.803 + * \sa SDL_HapticOpen
  11.804 + * \sa SDL_HapticOpened
  11.805 + */
  11.806 +extern DECLSPEC int SDLCALL SDL_HapticIndex(SDL_Haptic * haptic);
  11.807 +
  11.808 +/**
  11.809 + * \fn int SDL_MouseIsHaptic(void)
  11.810 + *
  11.811 + * \brief Gets whether or not the current mouse has haptic capabilities.
  11.812 + *
  11.813 + *    \return SDL_TRUE if the mouse is haptic, SDL_FALSE if it isn't.
  11.814 + *
  11.815 + * \sa SDL_HapticOpenFromMouse
  11.816 + */
  11.817 +extern DECLSPEC int SDLCALL SDL_MouseIsHaptic(void);
  11.818 +
  11.819 +/**
  11.820 + * \fn SDL_Haptic * SDL_HapticOpenFromMouse(void)
  11.821 + *
  11.822 + * \brief Tries to open a haptic device from the current mouse.
  11.823 + *
  11.824 + *    \return The haptic device identifier or NULL on error.
  11.825 + *
  11.826 + * \sa SDL_MouseIsHaptic
  11.827 + * \sa SDL_HapticOpen
  11.828 + */
  11.829 +extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpenFromMouse(void);
  11.830 +
  11.831 +/**
  11.832 + * \fn int SDL_JoystickIsHaptic(SDL_Joystick * joystick)
  11.833 + *
  11.834 + * \brief Checks to see if a joystick has haptic features.
  11.835 + *
  11.836 + *    \param joystick Joystick to test for haptic capabilities.
  11.837 + *    \return SDL_TRUE if the joystick is haptic, SDL_FALSE if it isn't
  11.838 + *            or -1 if an error ocurred.
  11.839 + *
  11.840 + * \sa SDL_HapticOpenFromJoystick
  11.841 + */
  11.842 +extern DECLSPEC int SDLCALL SDL_JoystickIsHaptic(SDL_Joystick * joystick);
  11.843 +
  11.844 +/**
  11.845 + * \fn SDL_Haptic * SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
  11.846 + *
  11.847 + * \brief Opens a Haptic device for usage from a Joystick device.  Still has
  11.848 + * to be closed seperately to the joystick.
  11.849 + *
  11.850 + * When opening from a joystick you should first close the haptic device before
  11.851 + *  closing the joystick device.  If not, on some implementations the haptic
  11.852 + *  device will also get unallocated and you'll be unable to use force feedback
  11.853 + *  on that device.
  11.854 + *
  11.855 + *    \param joystick Joystick to create a haptic device from.
  11.856 + *    \return A valid haptic device identifier on success or NULL on error.
  11.857 + *
  11.858 + * \sa SDL_HapticOpen
  11.859 + * \sa SDL_HapticClose
  11.860 + */
  11.861 +extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpenFromJoystick(SDL_Joystick *
  11.862 +                                                               joystick);
  11.863 +
  11.864 +/**
  11.865 + * \fn void SDL_HapticClose(SDL_Haptic * haptic)
  11.866 + *
  11.867 + * \brief Closes a Haptic device previously opened with SDL_HapticOpen.
  11.868 + *
  11.869 + *    \param haptic Haptic device to close.
  11.870 + */
  11.871 +extern DECLSPEC void SDLCALL SDL_HapticClose(SDL_Haptic * haptic);
  11.872 +
  11.873 +/**
  11.874 + * \fn int SDL_HapticNumEffects(SDL_Haptic * haptic)
  11.875 + *
  11.876 + * \brief Returns the number of effects a haptic device can store.
  11.877 + *
  11.878 + * On some platforms this isn't fully supported, and therefore is an
  11.879 + *  aproximation.  Always check to see if your created effect was actually
  11.880 + *  created and do not rely solely on HapticNumEffects.
  11.881 + *
  11.882 + *    \param haptic The haptic device to query effect max.
  11.883 + *    \return The number of effects the haptic device can store or
  11.884 + *            -1 on error.
  11.885 + *
  11.886 + * \sa SDL_HapticNumEffectsPlaying
  11.887 + * \sa SDL_HapticQuery
  11.888 + */
  11.889 +extern DECLSPEC int SDLCALL SDL_HapticNumEffects(SDL_Haptic * haptic);
  11.890 +
  11.891 +/**
  11.892 + * \fn int SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
  11.893 + *
  11.894 + * \brief Returns the number of effects a haptic device can play at the same time.
  11.895 + *
  11.896 + * This is not supported on all platforms, but will always return a value.  Added
  11.897 + *  here for the sake of completness.
  11.898 + *
  11.899 + *    \param haptic The haptic device to query maximum playing effect.s
  11.900 + *    \return The number of effects the haptic device can play at the same time
  11.901 + *            or -1 on error.
  11.902 + *
  11.903 + * \sa SDL_HapticNumEffects
  11.904 + * \sa SDL_HapticQuery
  11.905 + */
  11.906 +extern DECLSPEC int SDLCALL SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic);
  11.907 +
  11.908 +/**
  11.909 + * \fn unsigned int SDL_HapticQuery(SDL_Haptic * haptic)
  11.910 + *
  11.911 + * \brief Gets the haptic devices supported features in bitwise matter.
  11.912 + *
  11.913 + * Example: 
  11.914 + * \code
  11.915 + * if (SDL_HapticQueryEffects(haptic) & SDL_HAPTIC_CONSTANT) {
  11.916 + *    printf("We have constant haptic effect!");
  11.917 + * }
  11.918 + * \endcode
  11.919 + *    
  11.920 + *
  11.921 + *    \param haptic The haptic device to query.
  11.922 + *    \return Haptic features in bitwise manner (OR'd).
  11.923 + *
  11.924 + * \sa SDL_HapticNumEffects
  11.925 + * \sa SDL_HapticEffectSupported
  11.926 + */
  11.927 +extern DECLSPEC unsigned int SDLCALL SDL_HapticQuery(SDL_Haptic * haptic);
  11.928 +
  11.929 +
  11.930 +/**
  11.931 + * \fn int SDL_HapticNumAxes(SDL_Haptic * haptic)
  11.932 + *
  11.933 + * \brief Gets the number of haptic axes the device has.
  11.934 + *
  11.935 + * \sa SDL_HapticDirection
  11.936 + */
  11.937 +extern DECLSPEC int SDLCALL SDL_HapticNumAxes(SDL_Haptic * haptic);
  11.938 +
  11.939 +/**
  11.940 + * \fn int SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
  11.941 + *
  11.942 + * \brief Checks to see if effect is supported by haptic.
  11.943 + *
  11.944 + *    \param haptic Haptic device to check on.
  11.945 + *    \param effect Effect to check to see if it is supported.
  11.946 + *    \return SDL_TRUE if effect is supported, SDL_FALSE if it isn't or 
  11.947 + *            -1 on error.
  11.948 + * 
  11.949 + * \sa SDL_HapticQuery
  11.950 + * \sa SDL_HapticNewEffect
  11.951 + */
  11.952 +extern DECLSPEC int SDLCALL SDL_HapticEffectSupported(SDL_Haptic * haptic,
  11.953 +                                                      SDL_HapticEffect *
  11.954 +                                                      effect);
  11.955 +
  11.956 +/**
  11.957 + * \fn int SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
  11.958 + *
  11.959 + * \brief Creates a new haptic effect on the device.
  11.960 + *
  11.961 + *    \param haptic Haptic device to create the effect on.
  11.962 + *    \param effect Properties of the effect to create.
  11.963 + *    \return The id of the effect on success or -1 on error.
  11.964 + *
  11.965 + * \sa SDL_HapticUpdateEffect
  11.966 + * \sa SDL_HapticRunEffect
  11.967 + * \sa SDL_HapticDestroyEffect
  11.968 + */
  11.969 +extern DECLSPEC int SDLCALL SDL_HapticNewEffect(SDL_Haptic * haptic,
  11.970 +                                                SDL_HapticEffect * effect);
  11.971 +
  11.972 +/**
  11.973 + * \fn int SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect, SDL_HapticEffect * data)
  11.974 + *
  11.975 + * \brief Updates the properties of an effect.
  11.976 + *
  11.977 + * Can be used dynamically, although behaviour when dynamically changing
  11.978 + * direction may be strange.  Specifically the effect may reupload itself
  11.979 + * and start playing from the start.  You cannot change the type either when
  11.980 + * running UpdateEffect.
  11.981 + *
  11.982 + *    \param haptic Haptic device that has the effect.
  11.983 + *    \param effect Effect to update.
  11.984 + *    \param data New effect properties to use.
  11.985 + *    \return The id of the effect on success or -1 on error.
  11.986 + *
  11.987 + * \sa SDL_HapticNewEffect
  11.988 + * \sa SDL_HapticRunEffect
  11.989 + * \sa SDL_HapticDestroyEffect
  11.990 + */
  11.991 +extern DECLSPEC int SDLCALL SDL_HapticUpdateEffect(SDL_Haptic * haptic,
  11.992 +                                                   int effect,
  11.993 +                                                   SDL_HapticEffect * data);
  11.994 +
  11.995 +/**
  11.996 + * \fn int SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
  11.997 + *
  11.998 + * \brief Runs the haptic effect on it's assosciated haptic device.
  11.999 + *
 11.1000 + * If iterations are SDL_HAPTIC_INFINITY, it'll run the effect over and over
 11.1001 + *  repeating the envelope (attack and fade) every time.  If you only want the
 11.1002 + *  effect to last forever, set SDL_HAPTIC_INFINITY in the effect's length
 11.1003 + *  parameter.
 11.1004 + *
 11.1005 + *    \param haptic Haptic device to run the effect on.
 11.1006 + *    \param effect Identifier of the haptic effect to run.
 11.1007 + *    \param iterations Number of iterations to run the effect. Use
 11.1008 + *           SDL_HAPTIC_INFINITY for infinity.
 11.1009 + *    \return 0 on success or -1 on error.
 11.1010 + *
 11.1011 + * \sa SDL_HapticStopEffect
 11.1012 + * \sa SDL_HapticDestroyEffect
 11.1013 + * \sa SDL_HapticGetEffectStatus
 11.1014 + */
 11.1015 +extern DECLSPEC int SDLCALL SDL_HapticRunEffect(SDL_Haptic * haptic,
 11.1016 +                                                int effect,
 11.1017 +                                                Uint32 iterations);
 11.1018 +
 11.1019 +/**
 11.1020 + * \fn int SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
 11.1021 + *
 11.1022 + * \brief Stops the haptic effect on it's assosciated haptic device.
 11.1023 + *
 11.1024 + *    \param haptic Haptic device to stop the effect on.
 11.1025 + *    \param effect Identifier of the effect to stop.
 11.1026 + *    \return 0 on success or -1 on error.
 11.1027 + *
 11.1028 + * \sa SDL_HapticRunEffect
 11.1029 + * \sa SDL_HapticDestroyEffect
 11.1030 + */
 11.1031 +extern DECLSPEC int SDLCALL SDL_HapticStopEffect(SDL_Haptic * haptic,
 11.1032 +                                                 int effect);
 11.1033 +
 11.1034 +/**
 11.1035 + * \fn void SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
 11.1036 + *
 11.1037 + * \brief Destroys a haptic effect on the device.  This will stop the effect
 11.1038 + * if it's running.  Effects are automatically destroyed when the device is
 11.1039 + * closed.
 11.1040 + *
 11.1041 + *    \param haptic Device to destroy the effect on.
 11.1042 + *    \param effect Identifier of the effect to destroy.
 11.1043 + * 
 11.1044 + * \sa SDL_HapticNewEffect
 11.1045 + */
 11.1046 +extern DECLSPEC void SDLCALL SDL_HapticDestroyEffect(SDL_Haptic * haptic,
 11.1047 +                                                     int effect);
 11.1048 +
 11.1049 +/**
 11.1050 + * \fn int SDL_HapticGetEffectStatus(SDL_Haptic *haptic, int effect)
 11.1051 + *
 11.1052 + * \brief Gets the status of the current effect on the haptic device.
 11.1053 + *
 11.1054 + * Device must support the SDL_HAPTIC_STATUS feature.
 11.1055 + *
 11.1056 + *    \param haptic Haptic device to query the effect status on.
 11.1057 + *    \param effect Identifier of the effect to query it's status.
 11.1058 + *    \return 0 if it isn't playing, SDL_HAPTIC_PLAYING if it is playing
 11.1059 + *            or -1 on error.
 11.1060 + *
 11.1061 + * \sa SDL_HapticRunEffect
 11.1062 + * \sa SDL_HapticStopEffect
 11.1063 + */
 11.1064 +extern DECLSPEC int SDLCALL SDL_HapticGetEffectStatus(SDL_Haptic * haptic,
 11.1065 +                                                      int effect);
 11.1066 +
 11.1067 +/**
 11.1068 + * \fn int SDL_HapticSetGain(SDL_Haptic * haptic, int gain)
 11.1069 + *
 11.1070 + * \brief Sets the global gain of the device.  Gain should be between 0 and 100.
 11.1071 + *
 11.1072 + * Device must support the SDL_HAPTIC_GAIN feature.
 11.1073 + *
 11.1074 + * The user may specify the maxmimum gain by setting the environment variable
 11.1075 + *  SDL_HAPTIC_GAIN_MAX which should be between 0 and 100.  All calls to
 11.1076 + *  SDL_HapticSetGain will scale linearly using SDL_HAPTIC_GAIN_MAX as the
 11.1077 + *  maximum.
 11.1078 + *
 11.1079 + *    \param haptic Haptic device to set the gain on.
 11.1080 + *    \param gain Value to set the gain to, should be between 0 and 100.
 11.1081 + *    \return 0 on success or -1 on error.
 11.1082 + *
 11.1083 + * \sa SDL_HapticQuery
 11.1084 + */
 11.1085 +extern DECLSPEC int SDLCALL SDL_HapticSetGain(SDL_Haptic * haptic, int gain);
 11.1086 +
 11.1087 +/**
 11.1088 + * \fn int SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
 11.1089 + *
 11.1090 + * \brief Sets the global autocenter of the device.  Autocenter should be between
 11.1091 + * 0 and 100.  Setting it to 0 will disable autocentering.
 11.1092 + *
 11.1093 + * Device must support the SDL_HAPTIC_AUTOCENTER feature.
 11.1094 + *
 11.1095 + *    \param haptic Haptic device to set autocentering on.
 11.1096 + *    \param autocenter Value to set autocenter to, 0 disables autocentering.
 11.1097 + *    \return 0 on success or -1 on error.
 11.1098 + *
 11.1099 + * \sa SDL_HapticQuery
 11.1100 + */
 11.1101 +extern DECLSPEC int SDLCALL SDL_HapticSetAutocenter(SDL_Haptic * haptic,
 11.1102 +                                                    int autocenter);
 11.1103 +
 11.1104 +/**
 11.1105 + * \fn extern DECLSPEC int SDLCALL SDL_HapticPause(SDL_Haptic * haptic)
 11.1106 + *
 11.1107 + * \brief Pauses a haptic device.
 11.1108 + *
 11.1109 + * Device must support the SDL_HAPTIC_PAUSE feature.  Call SDL_HapticUnpause
 11.1110 + *  to resume playback.
 11.1111 + *
 11.1112 + * Do not modify the effects nor add new ones while the device is paused.
 11.1113 + *  That can cause all sorts of weird errors.
 11.1114 + *
 11.1115 + *    \param haptic Haptic device to pause.
 11.1116 + *    \return 0 on success or -1 on error.
 11.1117 + *
 11.1118 + * \sa SDL_HapticUnpause
 11.1119 + */
 11.1120 +extern DECLSPEC int SDLCALL SDL_HapticPause(SDL_Haptic * haptic);
 11.1121 +
 11.1122 +/**
 11.1123 + * \fn extern DECLSPEC int SDLCALL SDL_HapticUnpause(SDL_Haptic * haptic)
 11.1124 + *
 11.1125 + * \brief Unpauses a haptic device.
 11.1126 + *
 11.1127 + * Call to unpause after SDL_HapticPause.
 11.1128 + *
 11.1129 + *    \param haptic Haptic device to pause.
 11.1130 + *    \return 0 on success or -1 on error.
 11.1131 + *
 11.1132 + * \sa SDL_HapticPause
 11.1133 + */
 11.1134 +extern DECLSPEC int SDLCALL SDL_HapticUnpause(SDL_Haptic * haptic);
 11.1135 +
 11.1136 +/**
 11.1137 + * \fn extern DECSLPEC int SDLCALL SDL_HapticStopAll(SDL_Haptic * haptic)
 11.1138 + *
 11.1139 + * \brief Stops all the currently playing effects on a haptic device.
 11.1140 + *
 11.1141 + *    \param haptic Haptic device to stop.
 11.1142 + *    \return 0 on success or -1 on error.
 11.1143 + */
 11.1144 +extern DECLSPEC int SDLCALL SDL_HapticStopAll(SDL_Haptic * haptic);
 11.1145 +
 11.1146 +
 11.1147 +/* Ends C function definitions when using C++ */
 11.1148 +#ifdef __cplusplus
 11.1149 +/* *INDENT-OFF* */
 11.1150 +}
 11.1151 +/* *INDENT-ON* */
 11.1152 +#endif
 11.1153 +#include "close_code.h"
 11.1154 +
 11.1155 +#endif /* _SDL_haptic_h */
 11.1156 +
 11.1157 +/* vi: set ts=4 sw=4 expandtab: */
    12.1 --- a/src/SDL.c	Mon Aug 25 08:50:37 2008 +0000
    12.2 +++ b/src/SDL.c	Mon Aug 25 09:55:03 2008 +0000
    12.3 @@ -38,6 +38,10 @@
    12.4  extern int SDL_JoystickInit(void);
    12.5  extern void SDL_JoystickQuit(void);
    12.6  #endif
    12.7 +#if !SDL_HAPTIC_DISABLED
    12.8 +extern int SDL_HapticInit(void);
    12.9 +extern int SDL_HapticQuit(void);
   12.10 +#endif
   12.11  #if !SDL_CDROM_DISABLED
   12.12  extern int SDL_CDROMInit(void);
   12.13  extern void SDL_CDROMQuit(void);
   12.14 @@ -47,6 +51,10 @@
   12.15  extern int SDL_TimerInit(void);
   12.16  extern void SDL_TimerQuit(void);
   12.17  #endif
   12.18 +#if defined(__WIN32__)
   12.19 +extern int SDL_HelperWindowCreate(void);
   12.20 +extern int SDL_HelperWindowDestroy(void);
   12.21 +#endif
   12.22  
   12.23  /* The initialized subsystems */
   12.24  static Uint32 SDL_initialized = 0;
   12.25 @@ -123,6 +131,22 @@
   12.26      }
   12.27  #endif
   12.28  
   12.29 +#if !SDL_HAPTIC_DISABLED
   12.30 +    /* Initialize the haptic subsystem */
   12.31 +    if ((flags & SDL_INIT_HAPTIC) && !(SDL_initialized & SDL_INIT_HAPTIC)) {
   12.32 +        if (SDL_HapticInit() < 0) {
   12.33 +            return (-1);
   12.34 +        }
   12.35 +        SDL_initialized |= SDL_INIT_HAPTIC;
   12.36 +    }
   12.37 +#else
   12.38 +    if (flags & SDL_INIT_HAPTIC) {
   12.39 +        SDL_SetError("SDL not built with haptic (force feedback) support");
   12.40 +        return (-1);
   12.41 +    }
   12.42 +#endif
   12.43 +
   12.44 +
   12.45  #if !SDL_CDROM_DISABLED
   12.46      /* Initialize the CD-ROM subsystem */
   12.47      if ((flags & SDL_INIT_CDROM) && !(SDL_initialized & SDL_INIT_CDROM)) {
   12.48 @@ -152,6 +176,12 @@
   12.49      /* Clear the error message */
   12.50      SDL_ClearError();
   12.51  
   12.52 +#if defined(__WIN32__)
   12.53 +    if (SDL_HelperWindowCreate() < 0) {
   12.54 +        return -1;
   12.55 +    }
   12.56 +#endif
   12.57 +
   12.58      /* Initialize the desired subsystems */
   12.59      if (SDL_InitSubSystem(flags) < 0) {
   12.60          return (-1);
   12.61 @@ -180,6 +210,12 @@
   12.62          SDL_initialized &= ~SDL_INIT_JOYSTICK;
   12.63      }
   12.64  #endif
   12.65 +#if !SDL_HAPTIC_DISABLED
   12.66 +    if ((flags & SDL_initialized & SDL_INIT_HAPTIC)) {
   12.67 +        SDL_HapticQuit();
   12.68 +        SDL_initialized &= ~SDL_INIT_HAPTIC;
   12.69 +    }
   12.70 +#endif
   12.71  #if !SDL_TIMERS_DISABLED
   12.72      if ((flags & SDL_initialized & SDL_INIT_TIMER)) {
   12.73          SDL_TimerQuit();
   12.74 @@ -217,6 +253,10 @@
   12.75      printf("[SDL_Quit] : Enter! Calling QuitSubSystem()\n");
   12.76      fflush(stdout);
   12.77  #endif
   12.78 +
   12.79 +#if defined(__WIN32__)
   12.80 +    SDL_HelperWindowDestroy();
   12.81 +#endif
   12.82      SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
   12.83  
   12.84  #ifdef CHECK_LEAKS
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/haptic/SDL_haptic.c	Mon Aug 25 09:55:03 2008 +0000
    13.3 @@ -0,0 +1,698 @@
    13.4 +/*
    13.5 +    SDL - Simple DirectMedia Layer
    13.6 +    Copyright (C) 2008 Edgar Simo
    13.7 +
    13.8 +    This library is free software; you can redistribute it and/or
    13.9 +    modify it under the terms of the GNU Lesser General Public
   13.10 +    License as published by the Free Software Foundation; either
   13.11 +    version 2.1 of the License, or (at your option) any later version.
   13.12 +
   13.13 +    This library is distributed in the hope that it will be useful,
   13.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13.16 +    Lesser General Public License for more details.
   13.17 +
   13.18 +    You should have received a copy of the GNU Lesser General Public
   13.19 +    License along with this library; if not, write to the Free Software
   13.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   13.21 +
   13.22 +    Sam Lantinga
   13.23 +    slouken@libsdl.org
   13.24 +*/
   13.25 +#include "SDL_config.h"
   13.26 +
   13.27 +#include "SDL_syshaptic.h"
   13.28 +#include "../joystick/SDL_joystick_c.h" /* For SDL_PrivateJoystickValid */
   13.29 +
   13.30 +
   13.31 +Uint8 SDL_numhaptics = 0;
   13.32 +SDL_Haptic **SDL_haptics = NULL;
   13.33 +
   13.34 +
   13.35 +/*
   13.36 + * Initializes the Haptic devices.
   13.37 + */
   13.38 +int
   13.39 +SDL_HapticInit(void)
   13.40 +{
   13.41 +    int arraylen;
   13.42 +    int status;
   13.43 +
   13.44 +    SDL_numhaptics = 0;
   13.45 +    status = SDL_SYS_HapticInit();
   13.46 +    if (status >= 0) {
   13.47 +        arraylen = (status + 1) * sizeof(*SDL_haptics);
   13.48 +        SDL_haptics = (SDL_Haptic **) SDL_malloc(arraylen);
   13.49 +        if (SDL_haptics == NULL) {      /* Out of memory. */
   13.50 +            SDL_numhaptics = 0;
   13.51 +        } else {
   13.52 +            SDL_memset(SDL_haptics, 0, arraylen);
   13.53 +            SDL_numhaptics = status;
   13.54 +        }
   13.55 +        status = 0;
   13.56 +    }
   13.57 +
   13.58 +    return status;
   13.59 +}
   13.60 +
   13.61 +
   13.62 +/*
   13.63 + * Checks to see if the haptic device is valid
   13.64 + */
   13.65 +static int
   13.66 +ValidHaptic(SDL_Haptic * haptic)
   13.67 +{
   13.68 +    int i;
   13.69 +    int valid;
   13.70 +
   13.71 +    valid = 0;
   13.72 +    for (i = 0; i < SDL_numhaptics; i++) {
   13.73 +        if (SDL_haptics[i] == haptic) {
   13.74 +            valid = 1;
   13.75 +            break;
   13.76 +        }
   13.77 +    }
   13.78 +
   13.79 +    return valid;
   13.80 +}
   13.81 +
   13.82 +
   13.83 +/*
   13.84 + * Returns the number of available devices.
   13.85 + */
   13.86 +int
   13.87 +SDL_NumHaptics(void)
   13.88 +{
   13.89 +    return SDL_numhaptics;
   13.90 +}
   13.91 +
   13.92 +
   13.93 +/*
   13.94 + * Gets the name of a Haptic device by index.
   13.95 + */
   13.96 +const char *
   13.97 +SDL_HapticName(int device_index)
   13.98 +{
   13.99 +    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
  13.100 +        SDL_SetError("Haptic: There are %d haptic devices available",
  13.101 +                     SDL_numhaptics);
  13.102 +        return NULL;
  13.103 +    }
  13.104 +    return SDL_SYS_HapticName(device_index);
  13.105 +}
  13.106 +
  13.107 +
  13.108 +/*
  13.109 + * Opens a Haptic device.
  13.110 + */
  13.111 +SDL_Haptic *
  13.112 +SDL_HapticOpen(int device_index)
  13.113 +{
  13.114 +    int i;
  13.115 +    SDL_Haptic *haptic;
  13.116 +
  13.117 +    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
  13.118 +        SDL_SetError("Haptic: There are %d haptic devices available",
  13.119 +                     SDL_numhaptics);
  13.120 +        return NULL;
  13.121 +    }
  13.122 +
  13.123 +    /* If the haptic is already open, return it */
  13.124 +    for (i = 0; SDL_haptics[i]; i++) {
  13.125 +        if (device_index == SDL_haptics[i]->index) {
  13.126 +            haptic = SDL_haptics[i];
  13.127 +            ++haptic->ref_count;
  13.128 +            return haptic;
  13.129 +        }
  13.130 +    }
  13.131 +
  13.132 +    /* Create the haptic device */
  13.133 +    haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
  13.134 +    if (haptic == NULL) {
  13.135 +        SDL_OutOfMemory();
  13.136 +        return NULL;
  13.137 +    }
  13.138 +
  13.139 +    /* Initialize the haptic device */
  13.140 +    SDL_memset(haptic, 0, (sizeof *haptic));
  13.141 +    haptic->index = device_index;
  13.142 +    if (SDL_SYS_HapticOpen(haptic) < 0) {
  13.143 +        SDL_free(haptic);
  13.144 +        return NULL;
  13.145 +    }
  13.146 +
  13.147 +    /* Disable autocenter and set gain to max. */
  13.148 +    if (haptic->supported & SDL_HAPTIC_GAIN)
  13.149 +        SDL_HapticSetGain(haptic, 100);
  13.150 +    if (haptic->supported & SDL_HAPTIC_AUTOCENTER)
  13.151 +        SDL_HapticSetAutocenter(haptic, 0);
  13.152 +
  13.153 +    /* Add haptic to list */
  13.154 +    ++haptic->ref_count;
  13.155 +    for (i = 0; SDL_haptics[i]; i++)
  13.156 +        /* Skip to next haptic */ ;
  13.157 +    SDL_haptics[i] = haptic;
  13.158 +
  13.159 +    return haptic;
  13.160 +}
  13.161 +
  13.162 +
  13.163 +/*
  13.164 + * Returns 1 if the device has been opened.
  13.165 + */
  13.166 +int
  13.167 +SDL_HapticOpened(int device_index)
  13.168 +{
  13.169 +    int i, opened;
  13.170 +
  13.171 +    opened = 0;
  13.172 +    for (i = 0; SDL_haptics[i]; i++) {
  13.173 +        if (SDL_haptics[i]->index == (Uint8) device_index) {
  13.174 +            opened = 1;
  13.175 +            break;
  13.176 +        }
  13.177 +    }
  13.178 +    return opened;
  13.179 +}
  13.180 +
  13.181 +
  13.182 +/*
  13.183 + * Returns the index to a haptic device.
  13.184 + */
  13.185 +int
  13.186 +SDL_HapticIndex(SDL_Haptic * haptic)
  13.187 +{
  13.188 +    if (!ValidHaptic(haptic)) {
  13.189 +        return -1;
  13.190 +    }
  13.191 +
  13.192 +    return haptic->index;
  13.193 +}
  13.194 +
  13.195 +
  13.196 +/*
  13.197 + * Returns SDL_TRUE if mouse is haptic, SDL_FALSE if it isn't.
  13.198 + */
  13.199 +int
  13.200 +SDL_MouseIsHaptic(void)
  13.201 +{
  13.202 +    if (SDL_SYS_HapticMouse() < 0)
  13.203 +        return SDL_FALSE;
  13.204 +    return SDL_TRUE;
  13.205 +}
  13.206 +
  13.207 +
  13.208 +/*
  13.209 + * Returns the haptic device if mouse is haptic or NULL elsewise.
  13.210 + */
  13.211 +SDL_Haptic *
  13.212 +SDL_HapticOpenFromMouse(void)
  13.213 +{
  13.214 +    int device_index;
  13.215 +
  13.216 +    device_index = SDL_SYS_HapticMouse();
  13.217 +
  13.218 +    if (device_index < 0) {
  13.219 +        SDL_SetError("Haptic: Mouse isn't a haptic device.");
  13.220 +        return NULL;
  13.221 +    }
  13.222 +
  13.223 +    return SDL_HapticOpen(device_index);
  13.224 +}
  13.225 +
  13.226 +
  13.227 +/*
  13.228 + * Returns SDL_TRUE if joystick has haptic features.
  13.229 + */
  13.230 +int
  13.231 +SDL_JoystickIsHaptic(SDL_Joystick * joystick)
  13.232 +{
  13.233 +    int ret;
  13.234 +
  13.235 +    /* Must be a valid joystick */
  13.236 +    if (!SDL_PrivateJoystickValid(&joystick)) {
  13.237 +        return -1;
  13.238 +    }
  13.239 +
  13.240 +    ret = SDL_SYS_JoystickIsHaptic(joystick);
  13.241 +
  13.242 +    if (ret > 0)
  13.243 +        return SDL_TRUE;
  13.244 +    else if (ret == 0)
  13.245 +        return SDL_FALSE;
  13.246 +    else
  13.247 +        return -1;
  13.248 +}
  13.249 +
  13.250 +
  13.251 +/*
  13.252 + * Opens a haptic device from a joystick.
  13.253 + */
  13.254 +SDL_Haptic *
  13.255 +SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
  13.256 +{
  13.257 +    int i;
  13.258 +    SDL_Haptic *haptic;
  13.259 +
  13.260 +    /* Must be a valid joystick */
  13.261 +    if (!SDL_PrivateJoystickValid(&joystick)) {
  13.262 +        return NULL;
  13.263 +    }
  13.264 +
  13.265 +    /* Joystick must be haptic */
  13.266 +    if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
  13.267 +        return NULL;
  13.268 +    }
  13.269 +
  13.270 +    /* Check to see if joystick's haptic is already open */
  13.271 +    for (i = 0; SDL_haptics[i]; i++) {
  13.272 +        if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i], joystick)) {
  13.273 +            haptic = SDL_haptics[i];
  13.274 +            ++haptic->ref_count;
  13.275 +            return haptic;
  13.276 +        }
  13.277 +    }
  13.278 +
  13.279 +    /* Create the haptic device */
  13.280 +    haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
  13.281 +    if (haptic == NULL) {
  13.282 +        SDL_OutOfMemory();
  13.283 +        return NULL;
  13.284 +    }
  13.285 +
  13.286 +    /* Initialize the haptic device */
  13.287 +    SDL_memset(haptic, 0, sizeof(SDL_Haptic));
  13.288 +    if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
  13.289 +        SDL_free(haptic);
  13.290 +        return NULL;
  13.291 +    }
  13.292 +
  13.293 +    /* Add haptic to list */
  13.294 +    ++haptic->ref_count;
  13.295 +    for (i = 0; SDL_haptics[i]; i++)
  13.296 +        /* Skip to next haptic */ ;
  13.297 +    SDL_haptics[i] = haptic;
  13.298 +
  13.299 +    return haptic;
  13.300 +}
  13.301 +
  13.302 +
  13.303 +/*
  13.304 + * Closes a SDL_Haptic device.
  13.305 + */
  13.306 +void
  13.307 +SDL_HapticClose(SDL_Haptic * haptic)
  13.308 +{
  13.309 +    int i;
  13.310 +
  13.311 +    /* Must be valid */
  13.312 +    if (!ValidHaptic(haptic)) {
  13.313 +        return;
  13.314 +    }
  13.315 +
  13.316 +    /* Check if it's still in use */
  13.317 +    if (--haptic->ref_count < 0) {
  13.318 +        return;
  13.319 +    }
  13.320 +
  13.321 +    /* Close it, properly removing effects if needed */
  13.322 +    for (i = 0; i < haptic->neffects; i++) {
  13.323 +        if (haptic->effects[i].hweffect != NULL) {
  13.324 +            SDL_HapticDestroyEffect(haptic, i);
  13.325 +        }
  13.326 +    }
  13.327 +    SDL_SYS_HapticClose(haptic);
  13.328 +
  13.329 +    /* Remove from the list */
  13.330 +    for (i = 0; SDL_haptics[i]; ++i) {
  13.331 +        if (haptic == SDL_haptics[i]) {
  13.332 +            SDL_haptics[i] = NULL;
  13.333 +            SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
  13.334 +                       (SDL_numhaptics - i) * sizeof(haptic));
  13.335 +            break;
  13.336 +        }
  13.337 +    }
  13.338 +
  13.339 +    /* Free */
  13.340 +    SDL_free(haptic);
  13.341 +}
  13.342 +
  13.343 +/*
  13.344 + * Cleans up after the subsystem.
  13.345 + */
  13.346 +void
  13.347 +SDL_HapticQuit(void)
  13.348 +{
  13.349 +    SDL_SYS_HapticQuit();
  13.350 +    if (SDL_haptics != NULL) {
  13.351 +        SDL_free(SDL_haptics);
  13.352 +        SDL_haptics = NULL;
  13.353 +    }
  13.354 +    SDL_numhaptics = 0;
  13.355 +}
  13.356 +
  13.357 +/*
  13.358 + * Returns the number of effects a haptic device has.
  13.359 + */
  13.360 +int
  13.361 +SDL_HapticNumEffects(SDL_Haptic * haptic)
  13.362 +{
  13.363 +    if (!ValidHaptic(haptic)) {
  13.364 +        return -1;
  13.365 +    }
  13.366 +
  13.367 +    return haptic->neffects;
  13.368 +}
  13.369 +
  13.370 +
  13.371 +/*
  13.372 + * Returns the number of effects a haptic device can play.
  13.373 + */
  13.374 +int
  13.375 +SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
  13.376 +{
  13.377 +    if (!ValidHaptic(haptic)) {
  13.378 +        return -1;
  13.379 +    }
  13.380 +
  13.381 +    return haptic->nplaying;
  13.382 +}
  13.383 +
  13.384 +
  13.385 +/*
  13.386 + * Returns supported effects by the device.
  13.387 + */
  13.388 +unsigned int
  13.389 +SDL_HapticQuery(SDL_Haptic * haptic)
  13.390 +{
  13.391 +    if (!ValidHaptic(haptic)) {
  13.392 +        return -1;
  13.393 +    }
  13.394 +
  13.395 +    return haptic->supported;
  13.396 +}
  13.397 +
  13.398 +
  13.399 +/*
  13.400 + * Returns the number of axis on the device.
  13.401 + */
  13.402 +int
  13.403 +SDL_HapticNumAxes(SDL_Haptic * haptic)
  13.404 +{
  13.405 +    if (!ValidHaptic(haptic)) {
  13.406 +        return -1;
  13.407 +    }
  13.408 +
  13.409 +    return haptic->naxes;
  13.410 +}
  13.411 +
  13.412 +/*
  13.413 + * Checks to see if the device can support the effect.
  13.414 + */
  13.415 +int
  13.416 +SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
  13.417 +{
  13.418 +    if (!ValidHaptic(haptic)) {
  13.419 +        return -1;
  13.420 +    }
  13.421 +
  13.422 +    if ((haptic->supported & effect->type) != 0)
  13.423 +        return SDL_TRUE;
  13.424 +    return SDL_FALSE;
  13.425 +}
  13.426 +
  13.427 +/*
  13.428 + * Creates a new haptic effect.
  13.429 + */
  13.430 +int
  13.431 +SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
  13.432 +{
  13.433 +    int i;
  13.434 +
  13.435 +    /* Check for device validity. */
  13.436 +    if (!ValidHaptic(haptic)) {
  13.437 +        return -1;
  13.438 +    }
  13.439 +
  13.440 +    /* Check to see if effect is supported */
  13.441 +    if (SDL_HapticEffectSupported(haptic, effect) == SDL_FALSE) {
  13.442 +        SDL_SetError("Haptic: Effect not supported by haptic device.");
  13.443 +        return -1;
  13.444 +    }
  13.445 +
  13.446 +    /* See if there's a free slot */
  13.447 +    for (i = 0; i < haptic->neffects; i++) {
  13.448 +        if (haptic->effects[i].hweffect == NULL) {
  13.449 +
  13.450 +            /* Now let the backend create the real effect */
  13.451 +            if (SDL_SYS_HapticNewEffect(haptic, &haptic->effects[i], effect)
  13.452 +                != 0) {
  13.453 +                return -1;      /* Backend failed to create effect */
  13.454 +            }
  13.455 +
  13.456 +            SDL_memcpy(&haptic->effects[i].effect, effect,
  13.457 +                       sizeof(SDL_HapticEffect));
  13.458 +            return i;
  13.459 +        }
  13.460 +    }
  13.461 +
  13.462 +    SDL_SetError("Haptic: Device has no free space left.");
  13.463 +    return -1;
  13.464 +}
  13.465 +
  13.466 +/*
  13.467 + * Checks to see if an effect is valid.
  13.468 + */
  13.469 +static int
  13.470 +ValidEffect(SDL_Haptic * haptic, int effect)
  13.471 +{
  13.472 +    if ((effect < 0) || (effect >= haptic->neffects)) {
  13.473 +        SDL_SetError("Haptic: Invalid effect identifier.");
  13.474 +        return 0;
  13.475 +    }
  13.476 +    return 1;
  13.477 +}
  13.478 +
  13.479 +/*
  13.480 + * Updates an effect.
  13.481 + */
  13.482 +int
  13.483 +SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect,
  13.484 +                       SDL_HapticEffect * data)
  13.485 +{
  13.486 +    if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
  13.487 +        return -1;
  13.488 +    }
  13.489 +
  13.490 +    /* Can't change type dynamically. */
  13.491 +    if (data->type != haptic->effects[effect].effect.type) {
  13.492 +        SDL_SetError("Haptic: Updating effect type is illegal.");
  13.493 +        return -1;
  13.494 +    }
  13.495 +
  13.496 +    /* Updates the effect */
  13.497 +    if (SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data) <
  13.498 +        0) {
  13.499 +        return -1;
  13.500 +    }
  13.501 +
  13.502 +    SDL_memcpy(&haptic->effects[effect].effect, data,
  13.503 +               sizeof(SDL_HapticEffect));
  13.504 +    return 0;
  13.505 +}
  13.506 +
  13.507 +
  13.508 +/*
  13.509 + * Runs the haptic effect on the device.
  13.510 + */
  13.511 +int
  13.512 +SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
  13.513 +{
  13.514 +    if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
  13.515 +        return -1;
  13.516 +    }
  13.517 +
  13.518 +    /* Run the effect */
  13.519 +    if (SDL_SYS_HapticRunEffect(haptic, &haptic->effects[effect], iterations)
  13.520 +        < 0) {
  13.521 +        return -1;
  13.522 +    }
  13.523 +
  13.524 +    return 0;
  13.525 +}
  13.526 +
  13.527 +/*
  13.528 + * Stops the haptic effect on the device.
  13.529 + */
  13.530 +int
  13.531 +SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
  13.532 +{
  13.533 +    if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
  13.534 +        return -1;
  13.535 +    }
  13.536 +
  13.537 +    /* Stop the effect */
  13.538 +    if (SDL_SYS_HapticStopEffect(haptic, &haptic->effects[effect]) < 0) {
  13.539 +        return -1;
  13.540 +    }
  13.541 +
  13.542 +    return 0;
  13.543 +}
  13.544 +
  13.545 +/*
  13.546 + * Gets rid of a haptic effect.
  13.547 + */
  13.548 +void
  13.549 +SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
  13.550 +{
  13.551 +    if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
  13.552 +        return;
  13.553 +    }
  13.554 +
  13.555 +    /* Not allocated */
  13.556 +    if (haptic->effects[effect].hweffect == NULL) {
  13.557 +        return;
  13.558 +    }
  13.559 +
  13.560 +    SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
  13.561 +}
  13.562 +
  13.563 +/*
  13.564 + * Gets the status of a haptic effect.
  13.565 + */
  13.566 +int
  13.567 +SDL_HapticGetEffectStatus(SDL_Haptic * haptic, int effect)
  13.568 +{
  13.569 +    if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
  13.570 +        return -1;
  13.571 +    }
  13.572 +
  13.573 +    if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
  13.574 +        SDL_SetError("Haptic: Device does not support status queries.");
  13.575 +        return -1;
  13.576 +    }
  13.577 +
  13.578 +    return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
  13.579 +}
  13.580 +
  13.581 +/*
  13.582 + * Sets the global gain of the device.
  13.583 + */
  13.584 +int
  13.585 +SDL_HapticSetGain(SDL_Haptic * haptic, int gain)
  13.586 +{
  13.587 +    const char *env;
  13.588 +    int real_gain, max_gain;
  13.589 +
  13.590 +    if (!ValidHaptic(haptic)) {
  13.591 +        return -1;
  13.592 +    }
  13.593 +
  13.594 +    if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
  13.595 +        SDL_SetError("Haptic: Device does not support setting gain.");
  13.596 +        return -1;
  13.597 +    }
  13.598 +
  13.599 +    if ((gain < 0) || (gain > 100)) {
  13.600 +        SDL_SetError("Haptic: Gain must be between 0 and 100.");
  13.601 +        return -1;
  13.602 +    }
  13.603 +
  13.604 +    /* We use the envvar to get the maximum gain. */
  13.605 +    env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
  13.606 +    if (env != NULL) {
  13.607 +        max_gain = SDL_atoi(env);
  13.608 +
  13.609 +        /* Check for sanity. */
  13.610 +        if (max_gain < 0)
  13.611 +            max_gain = 0;
  13.612 +        else if (max_gain > 100)
  13.613 +            max_gain = 100;
  13.614 +
  13.615 +        /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
  13.616 +        real_gain = (gain * max_gain) / 100;
  13.617 +    } else {
  13.618 +        real_gain = gain;
  13.619 +    }
  13.620 +
  13.621 +    if (SDL_SYS_HapticSetGain(haptic, real_gain) < 0) {
  13.622 +        return -1;
  13.623 +    }
  13.624 +
  13.625 +    return 0;
  13.626 +}
  13.627 +
  13.628 +/*
  13.629 + * Makes the device autocenter, 0 disables.
  13.630 + */
  13.631 +int
  13.632 +SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  13.633 +{
  13.634 +    if (!ValidHaptic(haptic)) {
  13.635 +        return -1;
  13.636 +    }
  13.637 +
  13.638 +    if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
  13.639 +        SDL_SetError("Haptic: Device does not support setting autocenter.");
  13.640 +        return -1;
  13.641 +    }
  13.642 +
  13.643 +    if ((autocenter < 0) || (autocenter > 100)) {
  13.644 +        SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
  13.645 +        return -1;
  13.646 +    }
  13.647 +
  13.648 +    if (SDL_SYS_HapticSetAutocenter(haptic, autocenter) < 0) {
  13.649 +        return -1;
  13.650 +    }
  13.651 +
  13.652 +    return 0;
  13.653 +}
  13.654 +
  13.655 +/*
  13.656 + * Pauses the haptic device.
  13.657 + */
  13.658 +int
  13.659 +SDL_HapticPause(SDL_Haptic * haptic)
  13.660 +{
  13.661 +    if (!ValidHaptic(haptic)) {
  13.662 +        return -1;
  13.663 +    }
  13.664 +
  13.665 +    if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
  13.666 +        SDL_SetError("Haptic: Device does not support setting pausing.");
  13.667 +        return -1;
  13.668 +    }
  13.669 +
  13.670 +    return SDL_SYS_HapticPause(haptic);
  13.671 +}
  13.672 +
  13.673 +/*
  13.674 + * Unpauses the haptic device.
  13.675 + */
  13.676 +int
  13.677 +SDL_HapticUnpause(SDL_Haptic * haptic)
  13.678 +{
  13.679 +    if (!ValidHaptic(haptic)) {
  13.680 +        return -1;
  13.681 +    }
  13.682 +
  13.683 +    if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
  13.684 +        return 0;               /* Not going to be paused, so we pretend it's unpaused. */
  13.685 +    }
  13.686 +
  13.687 +    return SDL_SYS_HapticUnpause(haptic);
  13.688 +}
  13.689 +
  13.690 +/*
  13.691 + * Stops all the currently playing effects.
  13.692 + */
  13.693 +int
  13.694 +SDL_HapticStopAll(SDL_Haptic * haptic)
  13.695 +{
  13.696 +    if (!ValidHaptic(haptic)) {
  13.697 +        return -1;
  13.698 +    }
  13.699 +
  13.700 +    return SDL_SYS_HapticStopAll(haptic);
  13.701 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/haptic/SDL_syshaptic.h	Mon Aug 25 09:55:03 2008 +0000
    14.3 @@ -0,0 +1,201 @@
    14.4 +/*
    14.5 +    SDL - Simple DirectMedia Layer
    14.6 +    Copyright (C) 2008 Edgar Simo
    14.7 +
    14.8 +    This library is free software; you can redistribute it and/or
    14.9 +    modify it under the terms of the GNU Lesser General Public
   14.10 +    License as published by the Free Software Foundation; either
   14.11 +    version 2.1 of the License, or (at your option) any later version.
   14.12 +
   14.13 +    This library is distributed in the hope that it will be useful,
   14.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   14.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14.16 +    Lesser General Public License for more details.
   14.17 +
   14.18 +    You should have received a copy of the GNU Lesser General Public
   14.19 +    License along with this library; if not, write to the Free Software
   14.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   14.21 +
   14.22 +    Sam Lantinga
   14.23 +    slouken@libsdl.org
   14.24 +*/
   14.25 +
   14.26 +#include "SDL_config.h"
   14.27 +
   14.28 +#include "SDL_haptic.h"
   14.29 +
   14.30 +
   14.31 +/*
   14.32 + * Number of haptic devices on the system.
   14.33 + */
   14.34 +extern Uint8 SDL_numhaptics;
   14.35 +
   14.36 +
   14.37 +struct haptic_effect
   14.38 +{
   14.39 +    SDL_HapticEffect effect;    /* The current event */
   14.40 +    struct haptic_hweffect *hweffect;   /* The hardware behind the event */
   14.41 +};
   14.42 +
   14.43 +/*
   14.44 + * The real SDL_Haptic struct.
   14.45 + */
   14.46 +struct _SDL_Haptic
   14.47 +{
   14.48 +    Uint8 index;                /* Stores index it is attached to */
   14.49 +
   14.50 +    struct haptic_effect *effects;      /* Allocated effects */
   14.51 +    int neffects;               /* Maximum amount of effects */
   14.52 +    int nplaying;               /* Maximum amount of effects to play at the same time */
   14.53 +    unsigned int supported;     /* Supported effects */
   14.54 +    int naxes;                  /* Number of axes on the device. */
   14.55 +
   14.56 +    struct haptic_hwdata *hwdata;       /* Driver dependent */
   14.57 +    int ref_count;              /* Count for multiple opens */
   14.58 +};
   14.59 +
   14.60 +/* 
   14.61 + * Scans the system for haptic devices.
   14.62 + *
   14.63 + * Returns 0 on success, -1 on error.
   14.64 + */
   14.65 +extern int SDL_SYS_HapticInit(void);
   14.66 +
   14.67 +/*
   14.68 + * Gets the device dependent name of the haptic device
   14.69 + */
   14.70 +extern const char *SDL_SYS_HapticName(int index);
   14.71 +
   14.72 +/*
   14.73 + * Opens the haptic device for usage.  The haptic device should have
   14.74 + * the index value set previously.
   14.75 + *
   14.76 + * Returns 0 on success, -1 on error.
   14.77 + */
   14.78 +extern int SDL_SYS_HapticOpen(SDL_Haptic * haptic);
   14.79 +
   14.80 +/*
   14.81 + * Returns the index of the haptic core pointer or -1 if none is found.
   14.82 + */
   14.83 +int SDL_SYS_HapticMouse(void);
   14.84 +
   14.85 +/*
   14.86 + * Checks to see if the joystick has haptic capabilities.
   14.87 + *
   14.88 + * Returns >0 if haptic capabilities are detected, 0 if haptic
   14.89 + * capabilities aren't detected and -1 on error.
   14.90 + */
   14.91 +extern int SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick);
   14.92 +
   14.93 +/*
   14.94 + * Opens the haptic device for usage using the same device as
   14.95 + * the joystick.
   14.96 + *
   14.97 + * Returns 0 on success, -1 on error.
   14.98 + */
   14.99 +extern int SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic,
  14.100 +                                          SDL_Joystick * joystick);
  14.101 +/*
  14.102 + * Checks to see if haptic device and joystick device are the same.
  14.103 + *
  14.104 + * Returns 1 if they are the same, 0 if they aren't.
  14.105 + */
  14.106 +extern int SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic,
  14.107 +                                      SDL_Joystick * joystick);
  14.108 +
  14.109 +/*
  14.110 + * Closes a haptic device after usage.
  14.111 + */
  14.112 +extern void SDL_SYS_HapticClose(SDL_Haptic * haptic);
  14.113 +
  14.114 +/*
  14.115 + * Performs a cleanup on the haptic subsystem.
  14.116 + */
  14.117 +extern void SDL_SYS_HapticQuit(void);
  14.118 +
  14.119 +/*
  14.120 + * Creates a new haptic effect on the haptic device using base
  14.121 + * as a template for the effect.
  14.122 + *
  14.123 + * Returns 0 on success, -1 on error.
  14.124 + */
  14.125 +extern int SDL_SYS_HapticNewEffect(SDL_Haptic * haptic,
  14.126 +                                   struct haptic_effect *effect,
  14.127 +                                   SDL_HapticEffect * base);
  14.128 +
  14.129 +/*
  14.130 + * Updates the haptic effect on the haptic device using data
  14.131 + * as a template.
  14.132 + *
  14.133 + * Returns 0 on success, -1 on error.
  14.134 + */
  14.135 +extern int SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
  14.136 +                                      struct haptic_effect *effect,
  14.137 +                                      SDL_HapticEffect * data);
  14.138 +
  14.139 +/*
  14.140 + * Runs the effect on the haptic device.
  14.141 + *
  14.142 + * Returns 0 on success, -1 on error.
  14.143 + */
  14.144 +extern int SDL_SYS_HapticRunEffect(SDL_Haptic * haptic,
  14.145 +                                   struct haptic_effect *effect,
  14.146 +                                   Uint32 iterations);
  14.147 +
  14.148 +/*
  14.149 + * Stops the effect on the haptic device.
  14.150 + *
  14.151 + * Returns 0 on success, -1 on error.
  14.152 + */
  14.153 +extern int SDL_SYS_HapticStopEffect(SDL_Haptic * haptic,
  14.154 +                                    struct haptic_effect *effect);
  14.155 +
  14.156 +/*
  14.157 + * Cleanups up the effect on the haptic device.
  14.158 + */
  14.159 +extern void SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic,
  14.160 +                                        struct haptic_effect *effect);
  14.161 +
  14.162 +/*
  14.163 + * Queries the device for the status of effect.
  14.164 + *
  14.165 + * Returns 0 if device is stopped, >0 if device is playing and
  14.166 + * -1 on error.
  14.167 + */
  14.168 +extern int SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
  14.169 +                                         struct haptic_effect *effect);
  14.170 +
  14.171 +/*
  14.172 + * Sets the global gain of the haptic device.
  14.173 + *
  14.174 + * Returns 0 on success, -1 on error.
  14.175 + */
  14.176 +extern int SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain);
  14.177 +
  14.178 +/*
  14.179 + * Sets the autocenter feature of the haptic device.
  14.180 + *
  14.181 + * Returns 0 on success, -1 on error.
  14.182 + */
  14.183 +extern int SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter);
  14.184 +
  14.185 +/*
  14.186 + * Pauses the haptic device.
  14.187 + *
  14.188 + * Returns 0 on success, -1 on error.
  14.189 + */
  14.190 +extern int SDL_SYS_HapticPause(SDL_Haptic * haptic);
  14.191 +
  14.192 +/*
  14.193 + * Unpauses the haptic device.
  14.194 + *
  14.195 + * Returns 0 on success, -1 on error.
  14.196 + */
  14.197 +extern int SDL_SYS_HapticUnpause(SDL_Haptic * haptic);
  14.198 +
  14.199 +/*
  14.200 + * Stops all the currently playing haptic effects on the device.
  14.201 + *
  14.202 + * Returns 0 on success, -1 on error.
  14.203 + */
  14.204 +extern int SDL_SYS_HapticStopAll(SDL_Haptic * haptic);
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/haptic/darwin/SDL_syshaptic.c	Mon Aug 25 09:55:03 2008 +0000
    15.3 @@ -0,0 +1,1317 @@
    15.4 +/*
    15.5 +    SDL - Simple DirectMedia Layer
    15.6 +    Copyright (C) 2008 Edgar Simo
    15.7 +
    15.8 +    This library is free software; you can redistribute it and/or
    15.9 +    modify it under the terms of the GNU Lesser General Public
   15.10 +    License as published by the Free Software Foundation; either
   15.11 +    version 2.1 of the License, or (at your option) any later version.
   15.12 +
   15.13 +    This library is distributed in the hope that it will be useful,
   15.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   15.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15.16 +    Lesser General Public License for more details.
   15.17 +
   15.18 +    You should have received a copy of the GNU Lesser General Public
   15.19 +    License along with this library; if not, write to the Free Software
   15.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   15.21 +
   15.22 +    Sam Lantinga
   15.23 +    slouken@libsdl.org
   15.24 +*/
   15.25 +#include "SDL_config.h"
   15.26 +
   15.27 +#ifdef SDL_HAPTIC_IOKIT
   15.28 +
   15.29 +#include "SDL_haptic.h"
   15.30 +#include "../SDL_syshaptic.h"
   15.31 +#include "SDL_joystick.h"
   15.32 +#include "../../joystick/SDL_sysjoystick.h"     /* For the real SDL_Joystick */
   15.33 +#include "../../joystick/darwin/SDL_sysjoystick_c.h"    /* For joystick hwdata */
   15.34 +
   15.35 +#include <IOKit/IOKitLib.h>
   15.36 +#include <IOKit/hid/IOHIDKeys.h>
   15.37 +#include <ForceFeedback/ForceFeedback.h>
   15.38 +#include <ForceFeedback/ForceFeedbackConstants.h>
   15.39 +
   15.40 +
   15.41 +#define MAX_HAPTICS  32
   15.42 +
   15.43 +
   15.44 +/*
   15.45 + * List of available haptic devices.
   15.46 + */
   15.47 +static struct
   15.48 +{
   15.49 +    char name[256];             /* Name of the device. */
   15.50 +
   15.51 +    io_service_t dev;           /* Node we use to create the device. */
   15.52 +    SDL_Haptic *haptic;         /* Haptic currently assosciated with it. */
   15.53 +
   15.54 +    /* Usage pages for determining if it's a mouse or not. */
   15.55 +    long usage;
   15.56 +    long usagePage;
   15.57 +} SDL_hapticlist[MAX_HAPTICS];
   15.58 +
   15.59 +
   15.60 +/*
   15.61 + * Haptic system hardware data.
   15.62 + */
   15.63 +struct haptic_hwdata
   15.64 +{
   15.65 +    FFDeviceObjectReference device;     /* Hardware device. */
   15.66 +    UInt8 axes[3];
   15.67 +};
   15.68 +
   15.69 +
   15.70 +/*
   15.71 + * Haptic system effect data.
   15.72 + */
   15.73 +struct haptic_hweffect
   15.74 +{
   15.75 +    FFEffectObjectReference ref;        /* Reference. */
   15.76 +    struct FFEFFECT effect;     /* Hardware effect. */
   15.77 +};
   15.78 +
   15.79 +/*
   15.80 + * Prototypes.
   15.81 + */
   15.82 +static void SDL_SYS_HapticFreeFFEFFECT(FFEFFECT * effect, int type);
   15.83 +static int HIDGetDeviceProduct(io_service_t dev, char *name);
   15.84 +
   15.85 +
   15.86 +/* 
   15.87 + * Like strerror but for force feedback errors.
   15.88 + */
   15.89 +static const char *
   15.90 +FFStrError(HRESULT err)
   15.91 +{
   15.92 +    switch (err) {
   15.93 +    case FFERR_DEVICEFULL:
   15.94 +        return "device full";
   15.95 +        /* This should be valid, but for some reason isn't defined... */
   15.96 +        /*case FFERR_DEVICENOTREG:
   15.97 +           return "device not registered"; */
   15.98 +    case FFERR_DEVICEPAUSED:
   15.99 +        return "device paused";
  15.100 +    case FFERR_DEVICERELEASED:
  15.101 +        return "device released";
  15.102 +    case FFERR_EFFECTPLAYING:
  15.103 +        return "effect playing";
  15.104 +    case FFERR_EFFECTTYPEMISMATCH:
  15.105 +        return "effect type mismatch";
  15.106 +    case FFERR_EFFECTTYPENOTSUPPORTED:
  15.107 +        return "effect type not supported";
  15.108 +    case FFERR_GENERIC:
  15.109 +        return "undetermined error";
  15.110 +    case FFERR_HASEFFECTS:
  15.111 +        return "device has effects";
  15.112 +    case FFERR_INCOMPLETEEFFECT:
  15.113 +        return "incomplete effect";
  15.114 +    case FFERR_INTERNAL:
  15.115 +        return "internal fault";
  15.116 +    case FFERR_INVALIDDOWNLOADID:
  15.117 +        return "invalid download id";
  15.118 +    case FFERR_INVALIDPARAM:
  15.119 +        return "invalid parameter";
  15.120 +    case FFERR_MOREDATA:
  15.121 +        return "more data";
  15.122 +    case FFERR_NOINTERFACE:
  15.123 +        return "interface not supported";
  15.124 +    case FFERR_NOTDOWNLOADED:
  15.125 +        return "effect is not downloaded";
  15.126 +    case FFERR_NOTINITIALIZED:
  15.127 +        return "object has not been initialized";
  15.128 +    case FFERR_OUTOFMEMORY:
  15.129 +        return "out of memory";
  15.130 +    case FFERR_UNPLUGGED:
  15.131 +        return "device is unplugged";
  15.132 +    case FFERR_UNSUPPORTED:
  15.133 +        return "function call unsupported";
  15.134 +    case FFERR_UNSUPPORTEDAXIS:
  15.135 +        return "axis unsupported";
  15.136 +
  15.137 +    default:
  15.138 +        return "unknown error";
  15.139 +    }
  15.140 +}
  15.141 +
  15.142 +
  15.143 +/*
  15.144 + * Initializes the haptic subsystem.
  15.145 + */
  15.146 +int
  15.147 +SDL_SYS_HapticInit(void)
  15.148 +{
  15.149 +    int numhaptics;
  15.150 +    IOReturn result;
  15.151 +    io_iterator_t iter;
  15.152 +    CFDictionaryRef match;
  15.153 +    io_service_t device;
  15.154 +    CFMutableDictionaryRef hidProperties;
  15.155 +    CFTypeRef refCF;
  15.156 +
  15.157 +    /* Clear all the memory. */
  15.158 +    SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist));
  15.159 +
  15.160 +    /* Get HID devices. */
  15.161 +    match = IOServiceMatching(kIOHIDDeviceKey);
  15.162 +    if (match == NULL) {
  15.163 +        SDL_SetError("Haptic: Failed to get IOServiceMatching.");
  15.164 +        return -1;
  15.165 +    }
  15.166 +
  15.167 +    /* Now search I/O Registry for matching devices. */
  15.168 +    result = IOServiceGetMatchingServices(kIOMasterPortDefault, match, &iter);
  15.169 +    if (result != kIOReturnSuccess) {
  15.170 +        SDL_SetError("Haptic: Couldn't create a HID object iterator.");
  15.171 +        return -1;
  15.172 +    }
  15.173 +    /* IOServiceGetMatchingServices consumes dictionary. */
  15.174 +
  15.175 +    if (!IOIteratorIsValid(iter)) {     /* No iterator. */
  15.176 +        numhaptics = 0;
  15.177 +        return 0;
  15.178 +    }
  15.179 +
  15.180 +    numhaptics = 0;
  15.181 +    while ((device = IOIteratorNext(iter)) != IO_OBJECT_NULL) {
  15.182 +
  15.183 +        /* Check for force feedback. */
  15.184 +        if (FFIsForceFeedback(device) == FF_OK) {
  15.185 +
  15.186 +            /* Set basic device data. */
  15.187 +            HIDGetDeviceProduct(device, SDL_hapticlist[numhaptics].name);
  15.188 +            SDL_hapticlist[numhaptics].dev = device;
  15.189 +            SDL_hapticlist[numhaptics].haptic = NULL;
  15.190 +
  15.191 +            /* Set usage pages. */
  15.192 +            hidProperties = 0;
  15.193 +            refCF = 0;
  15.194 +            result = IORegistryEntryCreateCFProperties(device,
  15.195 +                                                       &hidProperties,
  15.196 +                                                       kCFAllocatorDefault,
  15.197 +                                                       kNilOptions);
  15.198 +            if ((result == KERN_SUCCESS) && hidProperties) {
  15.199 +                refCF =
  15.200 +                    CFDictionaryGetValue(hidProperties,
  15.201 +                                         CFSTR(kIOHIDPrimaryUsagePageKey));
  15.202 +                if (refCF) {
  15.203 +                    if (!CFNumberGetValue(refCF, kCFNumberLongType,
  15.204 +                                          &SDL_hapticlist[numhaptics].
  15.205 +                                          usagePage))
  15.206 +                        SDL_SetError
  15.207 +                            ("Haptic: Recieving device's usage page.");
  15.208 +                    refCF =
  15.209 +                        CFDictionaryGetValue(hidProperties,
  15.210 +                                             CFSTR(kIOHIDPrimaryUsageKey));
  15.211 +                    if (refCF) {
  15.212 +                        if (!CFNumberGetValue(refCF, kCFNumberLongType,
  15.213 +                                              &SDL_hapticlist[numhaptics].
  15.214 +                                              usage))
  15.215 +                            SDL_SetError("Haptic: Recieving device's usage.");
  15.216 +                    }
  15.217 +                }
  15.218 +                CFRelease(hidProperties);
  15.219 +            }
  15.220 +
  15.221 +            /* Device has been added. */
  15.222 +            numhaptics++;
  15.223 +        } else {                /* Free the unused device. */
  15.224 +            IOObjectRelease(device);
  15.225 +        }
  15.226 +
  15.227 +        /* Reached haptic limit. */
  15.228 +        if (numhaptics >= MAX_HAPTICS)
  15.229 +            break;
  15.230 +    }
  15.231 +    IOObjectRelease(iter);
  15.232 +
  15.233 +    return numhaptics;
  15.234 +}
  15.235 +
  15.236 +
  15.237 +/*
  15.238 + * Return the name of a haptic device, does not need to be opened.
  15.239 + */
  15.240 +const char *
  15.241 +SDL_SYS_HapticName(int index)
  15.242 +{
  15.243 +    return SDL_hapticlist[index].name;
  15.244 +}
  15.245 +
  15.246 +/*
  15.247 + * Gets the device's product name.
  15.248 + */
  15.249 +static int
  15.250 +HIDGetDeviceProduct(io_service_t dev, char *name)
  15.251 +{
  15.252 +    CFMutableDictionaryRef hidProperties, usbProperties;
  15.253 +    io_registry_entry_t parent1, parent2;
  15.254 +    kern_return_t ret;
  15.255 +
  15.256 +    hidProperties = usbProperties = 0;
  15.257 +
  15.258 +    ret = IORegistryEntryCreateCFProperties(dev, &hidProperties,
  15.259 +                                            kCFAllocatorDefault, kNilOptions);
  15.260 +    if ((ret != KERN_SUCCESS) || !hidProperties) {
  15.261 +        SDL_SetError("Haptic: Unable to create CFProperties.");
  15.262 +        return -1;
  15.263 +    }
  15.264 +
  15.265 +    /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
  15.266 +     * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
  15.267 +     */
  15.268 +    if ((KERN_SUCCESS ==
  15.269 +         IORegistryEntryGetParentEntry(dev, kIOServicePlane, &parent1))
  15.270 +        && (KERN_SUCCESS ==
  15.271 +            IORegistryEntryGetParentEntry(parent1, kIOServicePlane, &parent2))
  15.272 +        && (KERN_SUCCESS ==
  15.273 +            IORegistryEntryCreateCFProperties(parent2, &usbProperties,
  15.274 +                                              kCFAllocatorDefault,
  15.275 +                                              kNilOptions))) {
  15.276 +        if (usbProperties) {
  15.277 +            CFTypeRef refCF = 0;
  15.278 +            /* get device info
  15.279 +             * try hid dictionary first, if fail then go to usb dictionary
  15.280 +             */
  15.281 +
  15.282 +
  15.283 +            /* Get product name */
  15.284 +            refCF =
  15.285 +                CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductKey));
  15.286 +            if (!refCF)
  15.287 +                refCF =
  15.288 +                    CFDictionaryGetValue(usbProperties,
  15.289 +                                         CFSTR("USB Product Name"));
  15.290 +            if (refCF) {
  15.291 +                if (!CFStringGetCString(refCF, name, 256,
  15.292 +                                        CFStringGetSystemEncoding())) {
  15.293 +                    SDL_SetError
  15.294 +                        ("Haptic: CFStringGetCString error retrieving pDevice->product.");
  15.295 +                    return -1;
  15.296 +                }
  15.297 +            }
  15.298 +
  15.299 +            CFRelease(usbProperties);
  15.300 +        } else {
  15.301 +            SDL_SetError
  15.302 +                ("Haptic: IORegistryEntryCreateCFProperties failed to create usbProperties.");
  15.303 +            return -1;
  15.304 +        }
  15.305 +
  15.306 +        /* Release stuff. */
  15.307 +        if (kIOReturnSuccess != IOObjectRelease(parent2)) {
  15.308 +            SDL_SetError("Haptic: IOObjectRelease error with parent2.");
  15.309 +        }
  15.310 +        if (kIOReturnSuccess != IOObjectRelease(parent1)) {
  15.311 +            SDL_SetError("Haptic: IOObjectRelease error with parent1.");
  15.312 +        }
  15.313 +    } else {
  15.314 +        SDL_SetError("Haptic: Error getting registry entries.");
  15.315 +        return -1;
  15.316 +    }
  15.317 +
  15.318 +    return 0;
  15.319 +}
  15.320 +
  15.321 +
  15.322 +#define FF_TEST(ff, s) \
  15.323 +if (features.supportedEffects & (ff)) supported |= (s)
  15.324 +/*
  15.325 + * Gets supported features.
  15.326 + */
  15.327 +static unsigned int
  15.328 +GetSupportedFeatures(SDL_Haptic * haptic)
  15.329 +{
  15.330 +    HRESULT ret;
  15.331 +    FFDeviceObjectReference device;
  15.332 +    FFCAPABILITIES features;
  15.333 +    unsigned int supported;
  15.334 +    Uint32 val;
  15.335 +
  15.336 +    device = haptic->hwdata->device;
  15.337 +
  15.338 +    ret = FFDeviceGetForceFeedbackCapabilities(device, &features);
  15.339 +    if (ret != FF_OK) {
  15.340 +        SDL_SetError("Haptic: Unable to get device's supported features.");
  15.341 +        return -1;
  15.342 +    }
  15.343 +
  15.344 +    supported = 0;
  15.345 +
  15.346 +    /* Get maximum effects. */
  15.347 +    haptic->neffects = features.storageCapacity;
  15.348 +    haptic->nplaying = features.playbackCapacity;
  15.349 +
  15.350 +    /* Test for effects. */
  15.351 +    FF_TEST(FFCAP_ET_CONSTANTFORCE, SDL_HAPTIC_CONSTANT);
  15.352 +    FF_TEST(FFCAP_ET_RAMPFORCE, SDL_HAPTIC_RAMP);
  15.353 +    FF_TEST(FFCAP_ET_SQUARE, SDL_HAPTIC_SQUARE);
  15.354 +    FF_TEST(FFCAP_ET_SINE, SDL_HAPTIC_SINE);
  15.355 +    FF_TEST(FFCAP_ET_TRIANGLE, SDL_HAPTIC_TRIANGLE);
  15.356 +    FF_TEST(FFCAP_ET_SAWTOOTHUP, SDL_HAPTIC_SAWTOOTHUP);
  15.357 +    FF_TEST(FFCAP_ET_SAWTOOTHDOWN, SDL_HAPTIC_SAWTOOTHDOWN);
  15.358 +    FF_TEST(FFCAP_ET_SPRING, SDL_HAPTIC_SPRING);
  15.359 +    FF_TEST(FFCAP_ET_DAMPER, SDL_HAPTIC_DAMPER);
  15.360 +    FF_TEST(FFCAP_ET_INERTIA, SDL_HAPTIC_INERTIA);
  15.361 +    FF_TEST(FFCAP_ET_FRICTION, SDL_HAPTIC_FRICTION);
  15.362 +    FF_TEST(FFCAP_ET_CUSTOMFORCE, SDL_HAPTIC_CUSTOM);
  15.363 +
  15.364 +    /* Check if supports gain. */
  15.365 +    ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_FFGAIN,
  15.366 +                                           &val, sizeof(val));
  15.367 +    if (ret == FF_OK)
  15.368 +        supported |= SDL_HAPTIC_GAIN;
  15.369 +    else if (ret != FFERR_UNSUPPORTED) {
  15.370 +        SDL_SetError("Haptic: Unable to get if device supports gain: %s.",
  15.371 +                     FFStrError(ret));
  15.372 +        return -1;
  15.373 +    }
  15.374 +
  15.375 +    /* Checks if supports autocenter. */
  15.376 +    ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_AUTOCENTER,
  15.377 +                                           &val, sizeof(val));
  15.378 +    if (ret == FF_OK)
  15.379 +        supported |= SDL_HAPTIC_AUTOCENTER;
  15.380 +    else if (ret != FFERR_UNSUPPORTED) {
  15.381 +        SDL_SetError
  15.382 +            ("Haptic: Unable to get if device supports autocenter: %s.",
  15.383 +             FFStrError(ret));
  15.384 +        return -1;
  15.385 +    }
  15.386 +
  15.387 +    /* Check for axes, we have an artificial limit on axes */
  15.388 +    haptic->naxes = ((features.numFfAxes) > 3) ? 3 : features.numFfAxes;
  15.389 +    /* Actually store the axes we want to use */
  15.390 +    SDL_memcpy(haptic->hwdata->axes, features.ffAxes,
  15.391 +               haptic->naxes * sizeof(Uint8));
  15.392 +
  15.393 +    /* Always supported features. */
  15.394 +    supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE;
  15.395 +
  15.396 +    haptic->supported = supported;
  15.397 +    return 0;;
  15.398 +}
  15.399 +
  15.400 +
  15.401 +/*
  15.402 + * Opens the haptic device from the file descriptor.
  15.403 + */
  15.404 +static int
  15.405 +SDL_SYS_HapticOpenFromService(SDL_Haptic * haptic, io_service_t service)
  15.406 +{
  15.407 +    HRESULT ret;
  15.408 +    int ret2;
  15.409 +
  15.410 +    /* Allocate the hwdata */
  15.411 +    haptic->hwdata = (struct haptic_hwdata *)
  15.412 +        SDL_malloc(sizeof(*haptic->hwdata));
  15.413 +    if (haptic->hwdata == NULL) {
  15.414 +        SDL_OutOfMemory();
  15.415 +        goto creat_err;
  15.416 +    }
  15.417 +    SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
  15.418 +
  15.419 +    /* Open the device */
  15.420 +    ret = FFCreateDevice(service, &haptic->hwdata->device);
  15.421 +    if (ret != FF_OK) {
  15.422 +        SDL_SetError("Haptic: Unable to create device from service: %s.",
  15.423 +                     FFStrError(ret));
  15.424 +        goto creat_err;
  15.425 +    }
  15.426 +
  15.427 +    /* Get supported features. */
  15.428 +    ret2 = GetSupportedFeatures(haptic);
  15.429 +    if (haptic->supported < 0) {
  15.430 +        goto open_err;
  15.431 +    }
  15.432 +
  15.433 +
  15.434 +    /* Reset and then enable actuators. */
  15.435 +    ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device,
  15.436 +                                           FFSFFC_RESET);
  15.437 +    if (ret != FF_OK) {
  15.438 +        SDL_SetError("Haptic: Unable to reset device: %s.", FFStrError(ret));
  15.439 +        goto open_err;
  15.440 +    }
  15.441 +    ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device,
  15.442 +                                           FFSFFC_SETACTUATORSON);
  15.443 +    if (ret != FF_OK) {
  15.444 +        SDL_SetError("Haptic: Unable to enable actuators: %s.",
  15.445 +                     FFStrError(ret));
  15.446 +        goto open_err;
  15.447 +    }
  15.448 +
  15.449 +
  15.450 +    /* Allocate effects memory. */
  15.451 +    haptic->effects = (struct haptic_effect *)
  15.452 +        SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
  15.453 +    if (haptic->effects == NULL) {
  15.454 +        SDL_OutOfMemory();
  15.455 +        goto open_err;
  15.456 +    }
  15.457 +    /* Clear the memory */
  15.458 +    SDL_memset(haptic->effects, 0,
  15.459 +               sizeof(struct haptic_effect) * haptic->neffects);
  15.460 +
  15.461 +    return 0;
  15.462 +
  15.463 +    /* Error handling */
  15.464 +  open_err:
  15.465 +    FFReleaseDevice(haptic->hwdata->device);
  15.466 +  creat_err:
  15.467 +    if (haptic->hwdata != NULL) {
  15.468 +        free(haptic->hwdata);
  15.469 +        haptic->hwdata = NULL;
  15.470 +    }
  15.471 +    return -1;
  15.472 +
  15.473 +}
  15.474 +
  15.475 +
  15.476 +/*
  15.477 + * Opens a haptic device for usage.
  15.478 + */
  15.479 +int
  15.480 +SDL_SYS_HapticOpen(SDL_Haptic * haptic)
  15.481 +{
  15.482 +    return SDL_SYS_HapticOpenFromService(haptic,
  15.483 +                                         SDL_hapticlist[haptic->index].dev);
  15.484 +}
  15.485 +
  15.486 +
  15.487 +/*
  15.488 + * Opens a haptic device from first mouse it finds for usage.
  15.489 + */
  15.490 +int
  15.491 +SDL_SYS_HapticMouse(void)
  15.492 +{
  15.493 +    int i;
  15.494 +
  15.495 +    for (i = 0; i < SDL_numhaptics; i++) {
  15.496 +        if ((SDL_hapticlist[i].usagePage == kHIDPage_GenericDesktop) &&
  15.497 +            (SDL_hapticlist[i].usage == kHIDUsage_GD_Mouse))
  15.498 +            return i;
  15.499 +    }
  15.500 +
  15.501 +    return -1;
  15.502 +}
  15.503 +
  15.504 +
  15.505 +/*
  15.506 + * Checks to see if a joystick has haptic features.
  15.507 + */
  15.508 +int
  15.509 +SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
  15.510 +{
  15.511 +    if (joystick->hwdata->ffservice != 0)
  15.512 +        return SDL_TRUE;
  15.513 +    return SDL_FALSE;
  15.514 +}
  15.515 +
  15.516 +
  15.517 +/*
  15.518 + * Checks to see if the haptic device and joystick and in reality the same.
  15.519 + */
  15.520 +int
  15.521 +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
  15.522 +{
  15.523 +    if (IOObjectIsEqualTo((io_object_t) haptic->hwdata->device,
  15.524 +                          joystick->hwdata->ffservice))
  15.525 +        return 1;
  15.526 +    return 0;
  15.527 +}
  15.528 +
  15.529 +
  15.530 +/*
  15.531 + * Opens a SDL_Haptic from a SDL_Joystick.
  15.532 + */
  15.533 +int
  15.534 +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
  15.535 +{
  15.536 +    return SDL_SYS_HapticOpenFromService(haptic, joystick->hwdata->ffservice);
  15.537 +}
  15.538 +
  15.539 +
  15.540 +/*
  15.541 + * Closes the haptic device.
  15.542 + */
  15.543 +void
  15.544 +SDL_SYS_HapticClose(SDL_Haptic * haptic)
  15.545 +{
  15.546 +    if (haptic->hwdata) {
  15.547 +
  15.548 +        /* Free Effects. */
  15.549 +        SDL_free(haptic->effects);
  15.550 +        haptic->effects = NULL;
  15.551 +        haptic->neffects = 0;
  15.552 +
  15.553 +        /* Clean up */
  15.554 +        FFReleaseDevice(haptic->hwdata->device);
  15.555 +
  15.556 +        /* Free */
  15.557 +        SDL_free(haptic->hwdata);
  15.558 +        haptic->hwdata = NULL;
  15.559 +    }
  15.560 +}
  15.561 +
  15.562 +
  15.563 +/* 
  15.564 + * Clean up after system specific haptic stuff
  15.565 + */
  15.566 +void
  15.567 +SDL_SYS_HapticQuit(void)
  15.568 +{
  15.569 +    int i;
  15.570 +
  15.571 +    for (i = 0; i < SDL_numhaptics; i++) {
  15.572 +        /* Opened and not closed haptics are leaked, this is on purpose.
  15.573 +         * Close your haptic devices after usage. */
  15.574 +
  15.575 +        /* Free the io_service_t */
  15.576 +        IOObjectRelease(SDL_hapticlist[i].dev);
  15.577 +    }
  15.578 +}
  15.579 +
  15.580 +
  15.581 +/*
  15.582 + * Converts an SDL trigger button to an FFEFFECT trigger button.
  15.583 + */
  15.584 +static DWORD
  15.585 +FFGetTriggerButton(Uint16 button)
  15.586 +{
  15.587 +    DWORD dwTriggerButton;
  15.588 +
  15.589 +    dwTriggerButton = FFEB_NOTRIGGER;
  15.590 +
  15.591 +    if (button != 0) {
  15.592 +        dwTriggerButton = FFJOFS_BUTTON(button - 1);
  15.593 +    }
  15.594 +
  15.595 +    return dwTriggerButton;
  15.596 +}
  15.597 +
  15.598 +
  15.599 +/*
  15.600 + * Sets the direction.
  15.601 + */
  15.602 +static int
  15.603 +SDL_SYS_SetDirection(FFEFFECT * effect, SDL_HapticDirection * dir, int naxes)
  15.604 +{
  15.605 +    LONG *rglDir;
  15.606 +
  15.607 +    /* Handle no axes a part. */
  15.608 +    if (naxes == 0) {
  15.609 +        effect->dwFlags |= FFEFF_SPHERICAL;     /* Set as default. */
  15.610 +        effect->rglDirection = NULL;
  15.611 +        return 0;
  15.612 +    }
  15.613 +
  15.614 +    /* Has axes. */
  15.615 +    rglDir = SDL_malloc(sizeof(LONG) * naxes);
  15.616 +    if (rglDir == NULL) {
  15.617 +        SDL_OutOfMemory();
  15.618 +        return -1;
  15.619 +    }
  15.620 +    SDL_memset(rglDir, 0, sizeof(LONG) * naxes);
  15.621 +    effect->rglDirection = rglDir;
  15.622 +
  15.623 +    switch (dir->type) {
  15.624 +    case SDL_HAPTIC_POLAR:
  15.625 +        effect->dwFlags |= FFEFF_POLAR;
  15.626 +        rglDir[0] = dir->dir[0];
  15.627 +        return 0;
  15.628 +    case SDL_HAPTIC_CARTESIAN:
  15.629 +        effect->dwFlags |= FFEFF_CARTESIAN;
  15.630 +        rglDir[0] = dir->dir[0];
  15.631 +        if (naxes > 1)
  15.632 +            rglDir[1] = dir->dir[1];
  15.633 +        if (naxes > 2)
  15.634 +            rglDir[2] = dir->dir[2];
  15.635 +        return 0;
  15.636 +    case SDL_HAPTIC_SPHERICAL:
  15.637 +        effect->dwFlags |= FFEFF_SPHERICAL;
  15.638 +        rglDir[0] = dir->dir[0];
  15.639 +        if (naxes > 1)
  15.640 +            rglDir[1] = dir->dir[1];
  15.641 +        if (naxes > 2)
  15.642 +            rglDir[2] = dir->dir[2];
  15.643 +        return 0;
  15.644 +
  15.645 +    default:
  15.646 +        SDL_SetError("Haptic: Unknown direction type.");
  15.647 +        return -1;
  15.648 +    }
  15.649 +}
  15.650 +
  15.651 +
  15.652 +/* Clamps and converts. */
  15.653 +#define CCONVERT(x)   (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF)
  15.654 +/* Just converts. */
  15.655 +#define CONVERT(x)    (((x)*10000) / 0x7FFF)
  15.656 +/*
  15.657 + * Creates the FFEFFECT from a SDL_HapticEffect.
  15.658 + */
  15.659 +static int
  15.660 +SDL_SYS_ToFFEFFECT(SDL_Haptic * haptic, FFEFFECT * dest,
  15.661 +                   SDL_HapticEffect * src)
  15.662 +{
  15.663 +    int i;
  15.664 +    FFCONSTANTFORCE *constant;
  15.665 +    FFPERIODIC *periodic;
  15.666 +    FFCONDITION *condition;     /* Actually an array of conditions - one per axis. */
  15.667 +    FFRAMPFORCE *ramp;
  15.668 +    FFCUSTOMFORCE *custom;
  15.669 +    FFENVELOPE *envelope;
  15.670 +    SDL_HapticConstant *hap_constant;
  15.671 +    SDL_HapticPeriodic *hap_periodic;
  15.672 +    SDL_HapticCondition *hap_condition;
  15.673 +    SDL_HapticRamp *hap_ramp;
  15.674 +    SDL_HapticCustom *hap_custom;
  15.675 +    DWORD *axes;
  15.676 +
  15.677 +    /* Set global stuff. */
  15.678 +    SDL_memset(dest, 0, sizeof(FFEFFECT));
  15.679 +    dest->dwSize = sizeof(FFEFFECT);    /* Set the structure size. */
  15.680 +    dest->dwSamplePeriod = 0;   /* Not used by us. */
  15.681 +    dest->dwGain = 10000;       /* Gain is set globally, not locally. */
  15.682 +    dest->dwFlags = FFEFF_OBJECTOFFSETS;        /* Seems obligatory. */
  15.683 +
  15.684 +    /* Envelope. */
  15.685 +    envelope = SDL_malloc(sizeof(FFENVELOPE));
  15.686 +    if (envelope == NULL) {
  15.687 +        SDL_OutOfMemory();
  15.688 +        return -1;
  15.689 +    }
  15.690 +    SDL_memset(envelope, 0, sizeof(FFENVELOPE));
  15.691 +    dest->lpEnvelope = envelope;
  15.692 +    envelope->dwSize = sizeof(FFENVELOPE);      /* Always should be this. */
  15.693 +
  15.694 +    /* Axes. */
  15.695 +    dest->cAxes = haptic->naxes;
  15.696 +    if (dest->cAxes > 0) {
  15.697 +        axes = SDL_malloc(sizeof(DWORD) * dest->cAxes);
  15.698 +        if (axes == NULL) {
  15.699 +            SDL_OutOfMemory();
  15.700 +            return -1;
  15.701 +        }
  15.702 +        axes[0] = haptic->hwdata->axes[0];      /* Always at least one axis. */
  15.703 +        if (dest->cAxes > 1) {
  15.704 +            axes[1] = haptic->hwdata->axes[1];
  15.705 +        }
  15.706 +        if (dest->cAxes > 2) {
  15.707 +            axes[2] = haptic->hwdata->axes[2];
  15.708 +        }
  15.709 +        dest->rgdwAxes = axes;
  15.710 +    }
  15.711 +
  15.712 +
  15.713 +    /* The big type handling switch, even bigger then linux's version. */
  15.714 +    switch (src->type) {
  15.715 +    case SDL_HAPTIC_CONSTANT:
  15.716 +        hap_constant = &src->constant;
  15.717 +        constant = SDL_malloc(sizeof(FFCONSTANTFORCE));
  15.718 +        if (constant == NULL) {
  15.719 +            SDL_OutOfMemory();
  15.720 +            return -1;
  15.721 +        }
  15.722 +        SDL_memset(constant, 0, sizeof(FFCONSTANTFORCE));
  15.723 +
  15.724 +        /* Specifics */
  15.725 +        constant->lMagnitude = CONVERT(hap_constant->level);
  15.726 +        dest->cbTypeSpecificParams = sizeof(FFCONSTANTFORCE);
  15.727 +        dest->lpvTypeSpecificParams = constant;
  15.728 +
  15.729 +        /* Generics */
  15.730 +        dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */
  15.731 +        dest->dwTriggerButton = FFGetTriggerButton(hap_constant->button);
  15.732 +        dest->dwTriggerRepeatInterval = hap_constant->interval;
  15.733 +        dest->dwStartDelay = hap_constant->delay * 1000;        /* In microseconds. */
  15.734 +
  15.735 +        /* Direction. */
  15.736 +        if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes)
  15.737 +            < 0) {
  15.738 +            return -1;
  15.739 +        }
  15.740 +
  15.741 +        /* Envelope */
  15.742 +        if ((hap_constant->attack_length == 0)
  15.743 +            && (hap_constant->fade_length == 0)) {
  15.744 +            SDL_free(envelope);
  15.745 +            dest->lpEnvelope = NULL;
  15.746 +        } else {
  15.747 +            envelope->dwAttackLevel = CCONVERT(hap_constant->attack_level);
  15.748 +            envelope->dwAttackTime = hap_constant->attack_length * 1000;
  15.749 +            envelope->dwFadeLevel = CCONVERT(hap_constant->fade_level);
  15.750 +            envelope->dwFadeTime = hap_constant->fade_length * 1000;
  15.751 +        }
  15.752 +
  15.753 +        break;
  15.754 +
  15.755 +    case SDL_HAPTIC_SINE:
  15.756 +    case SDL_HAPTIC_SQUARE:
  15.757 +    case SDL_HAPTIC_TRIANGLE:
  15.758 +    case SDL_HAPTIC_SAWTOOTHUP:
  15.759 +    case SDL_HAPTIC_SAWTOOTHDOWN:
  15.760 +        hap_periodic = &src->periodic;
  15.761 +        periodic = SDL_malloc(sizeof(FFPERIODIC));
  15.762 +        if (periodic == NULL) {
  15.763 +            SDL_OutOfMemory();
  15.764 +            return -1;
  15.765 +        }
  15.766 +        SDL_memset(periodic, 0, sizeof(FFPERIODIC));
  15.767 +
  15.768 +        /* Specifics */
  15.769 +        periodic->dwMagnitude = CONVERT(hap_periodic->magnitude);
  15.770 +        periodic->lOffset = CONVERT(hap_periodic->offset);
  15.771 +        periodic->dwPhase = hap_periodic->phase;
  15.772 +        periodic->dwPeriod = hap_periodic->period * 1000;
  15.773 +        dest->cbTypeSpecificParams = sizeof(FFPERIODIC);
  15.774 +        dest->lpvTypeSpecificParams = periodic;
  15.775 +
  15.776 +        /* Generics */
  15.777 +        dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */
  15.778 +        dest->dwTriggerButton = FFGetTriggerButton(hap_periodic->button);
  15.779 +        dest->dwTriggerRepeatInterval = hap_periodic->interval;
  15.780 +        dest->dwStartDelay = hap_periodic->delay * 1000;        /* In microseconds. */
  15.781 +
  15.782 +        /* Direction. */
  15.783 +        if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes)
  15.784 +            < 0) {
  15.785 +            return -1;
  15.786 +        }
  15.787 +
  15.788 +        /* Envelope */
  15.789 +        if ((hap_periodic->attack_length == 0)
  15.790 +            && (hap_periodic->fade_length == 0)) {
  15.791 +            SDL_free(envelope);
  15.792 +            dest->lpEnvelope = NULL;
  15.793 +        } else {
  15.794 +            envelope->dwAttackLevel = CCONVERT(hap_periodic->attack_level);
  15.795 +            envelope->dwAttackTime = hap_periodic->attack_length * 1000;
  15.796 +            envelope->dwFadeLevel = CCONVERT(hap_periodic->fade_level);
  15.797 +            envelope->dwFadeTime = hap_periodic->fade_length * 1000;
  15.798 +        }
  15.799 +
  15.800 +        break;
  15.801 +
  15.802 +    case SDL_HAPTIC_SPRING:
  15.803 +    case SDL_HAPTIC_DAMPER:
  15.804 +    case SDL_HAPTIC_INERTIA:
  15.805 +    case SDL_HAPTIC_FRICTION:
  15.806 +        hap_condition = &src->condition;
  15.807 +        condition = SDL_malloc(sizeof(FFCONDITION) * dest->cAxes);
  15.808 +        if (condition == NULL) {
  15.809 +            SDL_OutOfMemory();
  15.810 +            return -1;
  15.811 +        }
  15.812 +        SDL_memset(condition, 0, sizeof(FFCONDITION));
  15.813 +
  15.814 +        /* Specifics */
  15.815 +        for (i = 0; i < dest->cAxes; i++) {
  15.816 +            condition[i].lOffset = CONVERT(hap_condition->center[i]);
  15.817 +            condition[i].lPositiveCoefficient =
  15.818 +                CONVERT(hap_condition->right_coeff[i]);
  15.819 +            condition[i].lNegativeCoefficient =
  15.820 +                CONVERT(hap_condition->left_coeff[i]);
  15.821 +            condition[i].dwPositiveSaturation =
  15.822 +                CCONVERT(hap_condition->right_sat[i]);
  15.823 +            condition[i].dwNegativeSaturation =
  15.824 +                CCONVERT(hap_condition->left_sat[i]);
  15.825 +            condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i]);
  15.826 +        }
  15.827 +        dest->cbTypeSpecificParams = sizeof(FFCONDITION) * dest->cAxes;
  15.828 +        dest->lpvTypeSpecificParams = condition;
  15.829 +
  15.830 +        /* Generics */
  15.831 +        dest->dwDuration = hap_condition->length * 1000;        /* In microseconds. */
  15.832 +        dest->dwTriggerButton = FFGetTriggerButton(hap_condition->button);
  15.833 +        dest->dwTriggerRepeatInterval = hap_condition->interval;
  15.834 +        dest->dwStartDelay = hap_condition->delay * 1000;       /* In microseconds. */
  15.835 +
  15.836 +        /* Direction. */
  15.837 +        if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes)
  15.838 +            < 0) {
  15.839 +            return -1;
  15.840 +        }
  15.841 +
  15.842 +        /* Envelope - Not actually supported by most CONDITION implementations. */
  15.843 +        SDL_free(dest->lpEnvelope);
  15.844 +        dest->lpEnvelope = NULL;
  15.845 +
  15.846 +        break;
  15.847 +
  15.848 +    case SDL_HAPTIC_RAMP:
  15.849 +        hap_ramp = &src->ramp;
  15.850 +        ramp = SDL_malloc(sizeof(FFRAMPFORCE));
  15.851 +        if (ramp == NULL) {
  15.852 +            SDL_OutOfMemory();
  15.853 +            return -1;
  15.854 +        }
  15.855 +        SDL_memset(ramp, 0, sizeof(FFRAMPFORCE));
  15.856 +
  15.857 +        /* Specifics */
  15.858 +        ramp->lStart = CONVERT(hap_ramp->start);
  15.859 +        ramp->lEnd = CONVERT(hap_ramp->end);
  15.860 +        dest->cbTypeSpecificParams = sizeof(FFRAMPFORCE);
  15.861 +        dest->lpvTypeSpecificParams = ramp;
  15.862 +
  15.863 +        /* Generics */
  15.864 +        dest->dwDuration = hap_ramp->length * 1000;     /* In microseconds. */
  15.865 +        dest->dwTriggerButton = FFGetTriggerButton(hap_ramp->button);
  15.866 +        dest->dwTriggerRepeatInterval = hap_ramp->interval;
  15.867 +        dest->dwStartDelay = hap_ramp->delay * 1000;    /* In microseconds. */
  15.868 +
  15.869 +        /* Direction. */
  15.870 +        if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) {
  15.871 +            return -1;
  15.872 +        }
  15.873 +
  15.874 +        /* Envelope */
  15.875 +        if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) {
  15.876 +            SDL_free(envelope);
  15.877 +            dest->lpEnvelope = NULL;
  15.878 +        } else {
  15.879 +            envelope->dwAttackLevel = CCONVERT(hap_ramp->attack_level);
  15.880 +            envelope->dwAttackTime = hap_ramp->attack_length * 1000;
  15.881 +            envelope->dwFadeLevel = CCONVERT(hap_ramp->fade_level);
  15.882 +            envelope->dwFadeTime = hap_ramp->fade_length * 1000;
  15.883 +        }
  15.884 +
  15.885 +        break;
  15.886 +
  15.887 +    case SDL_HAPTIC_CUSTOM:
  15.888 +        hap_custom = &src->custom;
  15.889 +        custom = SDL_malloc(sizeof(FFCUSTOMFORCE));
  15.890 +        if (custom == NULL) {
  15.891 +            SDL_OutOfMemory();
  15.892 +            return -1;
  15.893 +        }
  15.894 +        SDL_memset(custom, 0, sizeof(FFCUSTOMFORCE));
  15.895 +
  15.896 +        /* Specifics */
  15.897 +        custom->cChannels = hap_custom->channels;
  15.898 +        custom->dwSamplePeriod = hap_custom->period * 1000;
  15.899 +        custom->cSamples = hap_custom->samples;
  15.900 +        custom->rglForceData =
  15.901 +            SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels);
  15.902 +        for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) {      /* Copy data. */
  15.903 +            custom->rglForceData[i] = CCONVERT(hap_custom->data[i]);
  15.904 +        }
  15.905 +        dest->cbTypeSpecificParams = sizeof(FFCUSTOMFORCE);
  15.906 +        dest->lpvTypeSpecificParams = custom;
  15.907 +
  15.908 +        /* Generics */
  15.909 +        dest->dwDuration = hap_custom->length * 1000;   /* In microseconds. */
  15.910 +        dest->dwTriggerButton = FFGetTriggerButton(hap_custom->button);
  15.911 +        dest->dwTriggerRepeatInterval = hap_custom->interval;
  15.912 +        dest->dwStartDelay = hap_custom->delay * 1000;  /* In microseconds. */
  15.913 +
  15.914 +        /* Direction. */
  15.915 +        if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) <
  15.916 +            0) {
  15.917 +            return -1;
  15.918 +        }
  15.919 +
  15.920 +        /* Envelope */
  15.921 +        if ((hap_custom->attack_length == 0)
  15.922 +            && (hap_custom->fade_length == 0)) {
  15.923 +            SDL_free(envelope);
  15.924 +            dest->lpEnvelope = NULL;
  15.925 +        } else {
  15.926 +            envelope->dwAttackLevel = CCONVERT(hap_custom->attack_level);
  15.927 +            envelope->dwAttackTime = hap_custom->attack_length * 1000;
  15.928 +            envelope->dwFadeLevel = CCONVERT(hap_custom->fade_level);
  15.929 +            envelope->dwFadeTime = hap_custom->fade_length * 1000;
  15.930 +        }
  15.931 +
  15.932 +        break;
  15.933 +
  15.934 +
  15.935 +    default:
  15.936 +        SDL_SetError("Haptic: Unknown effect type.");
  15.937 +        return -1;
  15.938 +    }
  15.939 +
  15.940 +    return 0;
  15.941 +}
  15.942 +
  15.943 +
  15.944 +/*
  15.945 + * Frees an FFEFFECT allocated by SDL_SYS_ToFFEFFECT.
  15.946 + */
  15.947 +static void
  15.948 +SDL_SYS_HapticFreeFFEFFECT(FFEFFECT * effect, int type)
  15.949 +{
  15.950 +    FFCUSTOMFORCE *custom;
  15.951 +
  15.952 +    if (effect->lpEnvelope != NULL) {
  15.953 +        SDL_free(effect->lpEnvelope);
  15.954 +        effect->lpEnvelope = NULL;
  15.955 +    }
  15.956 +    if (effect->rgdwAxes != NULL) {
  15.957 +        SDL_free(effect->rgdwAxes);
  15.958 +        effect->rgdwAxes = NULL;
  15.959 +    }
  15.960 +    if (effect->lpvTypeSpecificParams != NULL) {
  15.961 +        if (type == SDL_HAPTIC_CUSTOM) {        /* Must free the custom data. */
  15.962 +            custom = (FFCUSTOMFORCE *) effect->lpvTypeSpecificParams;
  15.963 +            SDL_free(custom->rglForceData);
  15.964 +            custom->rglForceData = NULL;
  15.965 +        }
  15.966 +        SDL_free(effect->lpvTypeSpecificParams);
  15.967 +        effect->lpvTypeSpecificParams = NULL;
  15.968 +    }
  15.969 +    if (effect->rglDirection != NULL) {
  15.970 +        SDL_free(effect->rglDirection);
  15.971 +        effect->rglDirection = NULL;
  15.972 +    }
  15.973 +}
  15.974 +
  15.975 +
  15.976 +/*
  15.977 + * Gets the effect type from the generic SDL haptic effect wrapper.
  15.978 + */
  15.979 +CFUUIDRef
  15.980 +SDL_SYS_HapticEffectType(Uint16 type)
  15.981 +{
  15.982 +    switch (type) {
  15.983 +    case SDL_HAPTIC_CONSTANT:
  15.984 +        return kFFEffectType_ConstantForce_ID;
  15.985 +
  15.986 +    case SDL_HAPTIC_RAMP:
  15.987 +        return kFFEffectType_RampForce_ID;
  15.988 +
  15.989 +    case SDL_HAPTIC_SQUARE:
  15.990 +        return kFFEffectType_Square_ID;
  15.991 +
  15.992 +    case SDL_HAPTIC_SINE:
  15.993 +        return kFFEffectType_Sine_ID;
  15.994 +
  15.995 +    case SDL_HAPTIC_TRIANGLE:
  15.996 +        return kFFEffectType_Triangle_ID;
  15.997 +
  15.998 +    case SDL_HAPTIC_SAWTOOTHUP:
  15.999 +        return kFFEffectType_SawtoothUp_ID;
 15.1000 +
 15.1001 +    case SDL_HAPTIC_SAWTOOTHDOWN:
 15.1002 +        return kFFEffectType_SawtoothDown_ID;
 15.1003 +
 15.1004 +    case SDL_HAPTIC_SPRING:
 15.1005 +        return kFFEffectType_Spring_ID;
 15.1006 +
 15.1007 +    case SDL_HAPTIC_DAMPER:
 15.1008 +        return kFFEffectType_Damper_ID;
 15.1009 +
 15.1010 +    case SDL_HAPTIC_INERTIA:
 15.1011 +        return kFFEffectType_Inertia_ID;
 15.1012 +
 15.1013 +    case SDL_HAPTIC_FRICTION:
 15.1014 +        return kFFEffectType_Friction_ID;
 15.1015 +
 15.1016 +    case SDL_HAPTIC_CUSTOM:
 15.1017 +        return kFFEffectType_CustomForce_ID;
 15.1018 +
 15.1019 +    default:
 15.1020 +        SDL_SetError("Haptic: Unknown effect type.");
 15.1021 +        return NULL;
 15.1022 +    }
 15.1023 +}
 15.1024 +
 15.1025 +
 15.1026 +/*
 15.1027 + * Creates a new haptic effect.
 15.1028 + */
 15.1029 +int
 15.1030 +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
 15.1031 +                        SDL_HapticEffect * base)
 15.1032 +{
 15.1033 +    HRESULT ret;
 15.1034 +    CFUUIDRef type;
 15.1035 +
 15.1036 +    /* Alloc the effect. */
 15.1037 +    effect->hweffect = (struct haptic_hweffect *)
 15.1038 +        SDL_malloc(sizeof(struct haptic_hweffect));
 15.1039 +    if (effect->hweffect == NULL) {
 15.1040 +        SDL_OutOfMemory();
 15.1041 +        goto err_hweffect;
 15.1042 +    }
 15.1043 +
 15.1044 +    /* Get the type. */
 15.1045 +    type = SDL_SYS_HapticEffectType(base->type);
 15.1046 +    if (type == NULL) {
 15.1047 +        goto err_hweffect;
 15.1048 +    }
 15.1049 +
 15.1050 +    /* Get the effect. */
 15.1051 +    if (SDL_SYS_ToFFEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
 15.1052 +        goto err_effectdone;
 15.1053 +    }
 15.1054 +
 15.1055 +    /* Create the actual effect. */
 15.1056 +    ret = FFDeviceCreateEffect(haptic->hwdata->device, type,
 15.1057 +                               &effect->hweffect->effect,
 15.1058 +                               &effect->hweffect->ref);
 15.1059 +    if (ret != FF_OK) {
 15.1060 +        SDL_SetError("Haptic: Unable to create effect: %s.", FFStrError(ret));
 15.1061 +        goto err_effectdone;
 15.1062 +    }
 15.1063 +
 15.1064 +    return 0;
 15.1065 +
 15.1066 +  err_effectdone:
 15.1067 +    SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, base->type);
 15.1068 +  err_hweffect:
 15.1069 +    if (effect->hweffect != NULL) {
 15.1070 +        SDL_free(effect->hweffect);
 15.1071 +        effect->hweffect = NULL;
 15.1072 +    }
 15.1073 +    return -1;
 15.1074 +}
 15.1075 +
 15.1076 +
 15.1077 +/*
 15.1078 + * Updates an effect.
 15.1079 + */
 15.1080 +int
 15.1081 +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
 15.1082 +                           struct haptic_effect *effect,
 15.1083 +                           SDL_HapticEffect * data)
 15.1084 +{
 15.1085 +    HRESULT ret;
 15.1086 +    FFEffectParameterFlag flags;
 15.1087 +    FFEFFECT temp;
 15.1088 +
 15.1089 +    /* Get the effect. */
 15.1090 +    SDL_memset(&temp, 0, sizeof(FFEFFECT));
 15.1091 +    if (SDL_SYS_ToFFEFFECT(haptic, &temp, data) < 0) {
 15.1092 +        goto err_update;
 15.1093 +    }
 15.1094 +
 15.1095 +    /* Set the flags.  Might be worthwhile to diff temp with loaded effect and
 15.1096 +     *  only change those parameters. */
 15.1097 +    flags = FFEP_DIRECTION |
 15.1098 +        FFEP_DURATION |
 15.1099 +        FFEP_ENVELOPE |
 15.1100 +        FFEP_STARTDELAY |
 15.1101 +        FFEP_TRIGGERBUTTON |
 15.1102 +        FFEP_TRIGGERREPEATINTERVAL | FFEP_TYPESPECIFICPARAMS;
 15.1103 +
 15.1104 +    /* Create the actual effect. */
 15.1105 +    ret = FFEffectSetParameters(effect->hweffect->ref, &temp, flags);
 15.1106 +    if (ret != FF_OK) {
 15.1107 +        SDL_SetError("Haptic: Unable to update effect: %s.", FFStrError(ret));
 15.1108 +        goto err_update;
 15.1109 +    }
 15.1110 +
 15.1111 +    /* Copy it over. */
 15.1112 +    SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, data->type);
 15.1113 +    SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(FFEFFECT));
 15.1114 +
 15.1115 +    return 0;
 15.1116 +
 15.1117 +  err_update:
 15.1118 +    SDL_SYS_HapticFreeFFEFFECT(&temp, data->type);
 15.1119 +    return -1;
 15.1120 +}
 15.1121 +
 15.1122 +
 15.1123 +/*
 15.1124 + * Runs an effect.
 15.1125 + */
 15.1126 +int
 15.1127 +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
 15.1128 +                        Uint32 iterations)
 15.1129 +{
 15.1130 +    HRESULT ret;
 15.1131 +    Uint32 iter;
 15.1132 +
 15.1133 +    /* Check if it's infinite. */
 15.1134 +    if (iterations == SDL_HAPTIC_INFINITY) {
 15.1135 +        iter = FF_INFINITE;
 15.1136 +    } else
 15.1137 +        iter = iterations;
 15.1138 +
 15.1139 +    /* Run the effect. */
 15.1140 +    ret = FFEffectStart(effect->hweffect->ref, iter, 0);
 15.1141 +    if (ret != FF_OK) {
 15.1142 +        SDL_SetError("Haptic: Unable to run the effect: %s.",
 15.1143 +                     FFStrError(ret));
 15.1144 +        return -1;
 15.1145 +    }
 15.1146 +
 15.1147 +    return 0;
 15.1148 +}
 15.1149 +
 15.1150 +
 15.1151 +/*
 15.1152 + * Stops an effect.
 15.1153 + */
 15.1154 +int
 15.1155 +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
 15.1156 +{
 15.1157 +    HRESULT ret;
 15.1158 +
 15.1159 +    ret = FFEffectStop(effect->hweffect->ref);
 15.1160 +    if (ret != FF_OK) {
 15.1161 +        SDL_SetError("Haptic: Unable to stop the effect: %s.",
 15.1162 +                     FFStrError(ret));
 15.1163 +        return -1;
 15.1164 +    }
 15.1165 +
 15.1166 +    return 0;
 15.1167 +}
 15.1168 +
 15.1169 +
 15.1170 +/*
 15.1171 + * Frees the effect.
 15.1172 + */
 15.1173 +void
 15.1174 +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
 15.1175 +{
 15.1176 +    HRESULT ret;
 15.1177 +
 15.1178 +    ret =
 15.1179 +        FFDeviceReleaseEffect(haptic->hwdata->device, effect->hweffect->ref);
 15.1180 +    if (ret != FF_OK) {
 15.1181 +        SDL_SetError("Haptic: Error removing the effect from the device: %s.",
 15.1182 +                     FFStrError(ret));
 15.1183 +    }
 15.1184 +    SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect,
 15.1185 +                               effect->effect.type);
 15.1186 +    SDL_free(effect->hweffect);
 15.1187 +    effect->hweffect = NULL;
 15.1188 +}
 15.1189 +
 15.1190 +
 15.1191 +/*
 15.1192 + * Gets the status of a haptic effect.
 15.1193 + */
 15.1194 +int
 15.1195 +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
 15.1196 +                              struct haptic_effect *effect)
 15.1197 +{
 15.1198 +    HRESULT ret;
 15.1199 +    FFEffectStatusFlag status;
 15.1200 +
 15.1201 +    ret = FFEffectGetEffectStatus(effect->hweffect->ref, &status);
 15.1202 +    if (ret != FF_OK) {
 15.1203 +        SDL_SetError("Haptic: Unable to get effect status: %s.",
 15.1204 +                     FFStrError(ret));
 15.1205 +        return -1;
 15.1206 +    }
 15.1207 +
 15.1208 +    if (status == 0)
 15.1209 +        return SDL_FALSE;
 15.1210 +    return SDL_TRUE;            /* Assume it's playing or emulated. */
 15.1211 +}
 15.1212 +
 15.1213 +
 15.1214 +/*
 15.1215 + * Sets the gain.
 15.1216 + */
 15.1217 +int
 15.1218 +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
 15.1219 +{
 15.1220 +    HRESULT ret;
 15.1221 +    Uint32 val;
 15.1222 +
 15.1223 +    val = gain * 100;           /* Mac OS X uses 0 to 10,000 */
 15.1224 +    ret =
 15.1225 +        FFDeviceSetForceFeedbackProperty(haptic->hwdata->device,
 15.1226 +                                         FFPROP_FFGAIN, &val);
 15.1227 +    if (ret != FF_OK) {
 15.1228 +        SDL_SetError("Haptic: Error setting gain: %s.", FFStrError(ret));
 15.1229 +        return -1;
 15.1230 +    }
 15.1231 +
 15.1232 +    return 0;
 15.1233 +}
 15.1234 +
 15.1235 +
 15.1236 +/*
 15.1237 + * Sets the autocentering.
 15.1238 + */
 15.1239 +int
 15.1240 +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
 15.1241 +{
 15.1242 +    HRESULT ret;
 15.1243 +    Uint32 val;
 15.1244 +
 15.1245 +    /* Mac OS X only has 0 (off) and 1 (on) */
 15.1246 +    if (autocenter == 0)
 15.1247 +        val = 0;
 15.1248 +    else
 15.1249 +        val = 1;
 15.1250 +
 15.1251 +    ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device,
 15.1252 +                                           FFPROP_AUTOCENTER, &val);
 15.1253 +    if (ret != FF_OK) {
 15.1254 +        SDL_SetError("Haptic: Error setting autocenter: %s.",
 15.1255 +                     FFStrError(ret));
 15.1256 +        return -1;
 15.1257 +    }
 15.1258 +
 15.1259 +    return 0;
 15.1260 +}
 15.1261 +
 15.1262 +
 15.1263 +/*
 15.1264 + * Pauses the device.
 15.1265 + */
 15.1266 +int
 15.1267 +SDL_SYS_HapticPause(SDL_Haptic * haptic)
 15.1268 +{
 15.1269 +    HRESULT ret;
 15.1270 +
 15.1271 +    ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device,
 15.1272 +                                           FFSFFC_PAUSE);
 15.1273 +    if (ret != FF_OK) {
 15.1274 +        SDL_SetError("Haptic: Error pausing device: %s.", FFStrError(ret));
 15.1275 +        return -1;
 15.1276 +    }
 15.1277 +
 15.1278 +    return 0;
 15.1279 +}
 15.1280 +
 15.1281 +
 15.1282 +/*
 15.1283 + * Unpauses the device.
 15.1284 + */
 15.1285 +int
 15.1286 +SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
 15.1287 +{
 15.1288 +    HRESULT ret;
 15.1289 +
 15.1290 +    ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device,
 15.1291 +                                           FFSFFC_CONTINUE);
 15.1292 +    if (ret != FF_OK) {
 15.1293 +        SDL_SetError("Haptic: Error pausing device: %s.", FFStrError(ret));
 15.1294 +        return -1;
 15.1295 +    }
 15.1296 +
 15.1297 +    return 0;
 15.1298 +}
 15.1299 +
 15.1300 +
 15.1301 +/*
 15.1302 + * Stops all currently playing effects.
 15.1303 + */
 15.1304 +int
 15.1305 +SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
 15.1306 +{
 15.1307 +    HRESULT ret;
 15.1308 +
 15.1309 +    ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device,
 15.1310 +                                           FFSFFC_STOPALL);
 15.1311 +    if (ret != FF_OK) {
 15.1312 +        SDL_SetError("Haptic: Error stopping device: %s.", FFStrError(ret));
 15.1313 +        return -1;
 15.1314 +    }
 15.1315 +
 15.1316 +    return 0;
 15.1317 +}
 15.1318 +
 15.1319 +
 15.1320 +#endif /* SDL_HAPTIC_IOKIT */
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/haptic/dummy/SDL_syshaptic.c	Mon Aug 25 09:55:03 2008 +0000
    16.3 @@ -0,0 +1,194 @@
    16.4 +/*
    16.5 +    SDL - Simple DirectMedia Layer
    16.6 +    Copyright (C) 2008 Edgar Simo
    16.7 +
    16.8 +    This library is free software; you can redistribute it and/or
    16.9 +    modify it under the terms of the GNU Lesser General Public
   16.10 +    License as published by the Free Software Foundation; either
   16.11 +    version 2.1 of the License, or (at your option) any later version.
   16.12 +
   16.13 +    This library is distributed in the hope that it will be useful,
   16.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   16.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   16.16 +    Lesser General Public License for more details.
   16.17 +
   16.18 +    You should have received a copy of the GNU Lesser General Public
   16.19 +    License along with this library; if not, write to the Free Software
   16.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   16.21 +
   16.22 +    Sam Lantinga
   16.23 +    slouken@libsdl.org
   16.24 +*/
   16.25 +#include "SDL_config.h"
   16.26 +
   16.27 +#if defined(SDL_HAPTIC_DUMMY) || defined(SDL_HAPTIC_DISABLED)
   16.28 +
   16.29 +#include "SDL_haptic.h"
   16.30 +#include "../SDL_syshaptic.h"
   16.31 +
   16.32 +
   16.33 +static int
   16.34 +SDL_SYS_LogicError(void)
   16.35 +{
   16.36 +    SDL_SetError("Logic error: No haptic devices available.");;
   16.37 +}
   16.38 +
   16.39 +
   16.40 +int
   16.41 +SDL_SYS_HapticInit(void)
   16.42 +{
   16.43 +    return 0;
   16.44 +}
   16.45 +
   16.46 +
   16.47 +const char *
   16.48 +SDL_SYS_HapticName(int index)
   16.49 +{
   16.50 +    SDL_SYS_LogicError();
   16.51 +    return NULL;
   16.52 +}
   16.53 +
   16.54 +
   16.55 +int
   16.56 +SDL_SYS_HapticOpen(SDL_Haptic * haptic)
   16.57 +{
   16.58 +    SDL_SYS_LogicError();
   16.59 +    return -1;
   16.60 +}
   16.61 +
   16.62 +
   16.63 +int
   16.64 +SDL_SYS_HapticMouse(void)
   16.65 +{
   16.66 +    return -1;
   16.67 +}
   16.68 +
   16.69 +
   16.70 +int
   16.71 +SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
   16.72 +{
   16.73 +    return 0;
   16.74 +}
   16.75 +
   16.76 +
   16.77 +int
   16.78 +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
   16.79 +{
   16.80 +    SDL_SYS_LogicError();
   16.81 +    return -1;
   16.82 +}
   16.83 +
   16.84 +
   16.85 +int
   16.86 +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
   16.87 +{
   16.88 +    return 0;
   16.89 +}
   16.90 +
   16.91 +
   16.92 +void
   16.93 +SDL_SYS_HapticClose(SDL_Haptic * haptic)
   16.94 +{
   16.95 +    return;
   16.96 +}
   16.97 +
   16.98 +
   16.99 +void
  16.100 +SDL_SYS_HapticQuit(void)
  16.101 +{
  16.102 +    return;
  16.103 +}
  16.104 +
  16.105 +
  16.106 +int
  16.107 +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic,
  16.108 +                        struct haptic_effect *effect, SDL_HapticEffect * base)
  16.109 +{
  16.110 +    SDL_SYS_LogicError();
  16.111 +    return -1;
  16.112 +}
  16.113 +
  16.114 +
  16.115 +int
  16.116 +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
  16.117 +                           struct haptic_effect *effect,
  16.118 +                           SDL_HapticEffect * data)
  16.119 +{
  16.120 +    SDL_SYS_LogicError();
  16.121 +    return -1;
  16.122 +}
  16.123 +
  16.124 +
  16.125 +int
  16.126 +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
  16.127 +                        Uint32 iterations)
  16.128 +{
  16.129 +    SDL_SYS_LogicError();
  16.130 +    return -1;
  16.131 +}
  16.132 +
  16.133 +
  16.134 +int
  16.135 +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  16.136 +{
  16.137 +    SDL_SYS_LogicError();
  16.138 +    return -1;
  16.139 +}
  16.140 +
  16.141 +
  16.142 +void
  16.143 +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  16.144 +{
  16.145 +    SDL_SYS_LogicError();
  16.146 +    return;
  16.147 +}
  16.148 +
  16.149 +
  16.150 +int
  16.151 +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
  16.152 +                              struct haptic_effect *effect)
  16.153 +{
  16.154 +    SDL_SYS_LogicError();
  16.155 +    return -1;
  16.156 +}
  16.157 +
  16.158 +
  16.159 +int
  16.160 +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
  16.161 +{
  16.162 +    SDL_SYS_LogicError();
  16.163 +    return -1;
  16.164 +}
  16.165 +
  16.166 +
  16.167 +int
  16.168 +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  16.169 +{
  16.170 +    SDL_SYS_LogicError();
  16.171 +    return -1;
  16.172 +}
  16.173 +
  16.174 +int
  16.175 +SDL_SYS_HapticPause(SDL_Haptic * haptic)
  16.176 +{
  16.177 +    SDL_SYS_LogicError();
  16.178 +    return -1;
  16.179 +}
  16.180 +
  16.181 +int
  16.182 +SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
  16.183 +{
  16.184 +    SDL_SYS_LogicError();
  16.185 +    return -1;
  16.186 +}
  16.187 +
  16.188 +int
  16.189 +SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
  16.190 +{
  16.191 +    SDL_SYS_LogicError();
  16.192 +    return -1;
  16.193 +}
  16.194 +
  16.195 +
  16.196 +
  16.197 +#endif /* SDL_HAPTIC_DUMMY || SDL_HAPTIC_DISABLED */
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/haptic/linux/SDL_syshaptic.c	Mon Aug 25 09:55:03 2008 +0000
    17.3 @@ -0,0 +1,956 @@
    17.4 +/*
    17.5 +    SDL - Simple DirectMedia Layer
    17.6 +    Copyright (C) 2008 Edgar Simo
    17.7 +
    17.8 +    This library is free software; you can redistribute it and/or
    17.9 +    modify it under the terms of the GNU Lesser General Public
   17.10 +    License as published by the Free Software Foundation; either
   17.11 +    version 2.1 of the License, or (at your option) any later version.
   17.12 +
   17.13 +    This library is distributed in the hope that it will be useful,
   17.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   17.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   17.16 +    Lesser General Public License for more details.
   17.17 +
   17.18 +    You should have received a copy of the GNU Lesser General Public
   17.19 +    License along with this library; if not, write to the Free Software
   17.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   17.21 +
   17.22 +    Sam Lantinga
   17.23 +    slouken@libsdl.org
   17.24 +*/
   17.25 +#include "SDL_config.h"
   17.26 +
   17.27 +#ifdef SDL_HAPTIC_LINUX
   17.28 +
   17.29 +#include "SDL_haptic.h"
   17.30 +#include "../SDL_syshaptic.h"
   17.31 +#include "SDL_joystick.h"
   17.32 +#include "../../joystick/SDL_sysjoystick.h"     /* For the real SDL_Joystick */
   17.33 +#include "../../joystick/linux/SDL_sysjoystick_c.h"     /* For joystick hwdata */
   17.34 +
   17.35 +#include <unistd.h>             /* close */
   17.36 +#include <linux/input.h>        /* Force feedback linux stuff. */
   17.37 +#include <fcntl.h>              /* O_RDWR */
   17.38 +#include <limits.h>             /* INT_MAX */
   17.39 +#include <errno.h>              /* errno, strerror */
   17.40 +#include <math.h>               /* atan2 */
   17.41 +
   17.42 +/* Just in case. */
   17.43 +#ifndef M_PI
   17.44 +#  define M_PI     3.14159265358979323846
   17.45 +#endif
   17.46 +
   17.47 +
   17.48 +#define MAX_HAPTICS  32         /* It's doubtful someone has more then 32 evdev */
   17.49 +
   17.50 +
   17.51 +/*
   17.52 + * List of available haptic devices.
   17.53 + */
   17.54 +static struct
   17.55 +{
   17.56 +    char *fname;                /* Dev path name (like /dev/input/event1) */
   17.57 +    SDL_Haptic *haptic;         /* Assosciated haptic. */
   17.58 +} SDL_hapticlist[MAX_HAPTICS];
   17.59 +
   17.60 +
   17.61 +/*
   17.62 + * Haptic system hardware data.
   17.63 + */
   17.64 +struct haptic_hwdata
   17.65 +{
   17.66 +    int fd;                     /* File descriptor of the device. */
   17.67 +    char *fname;                /* Points to the name in SDL_hapticlist. */
   17.68 +};
   17.69 +
   17.70 +
   17.71 +/*
   17.72 + * Haptic system effect data.
   17.73 + */
   17.74 +struct haptic_hweffect
   17.75 +{
   17.76 +    struct ff_effect effect;    /* The linux kernel effect structure. */
   17.77 +};
   17.78 +
   17.79 +
   17.80 +
   17.81 +#define test_bit(nr, addr) \
   17.82 +   (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
   17.83 +#define EV_TEST(ev,f) \
   17.84 +   if (test_bit((ev), features)) ret |= (f);
   17.85 +/*
   17.86 + * Test whether a device has haptic properties.
   17.87 + * Returns available properties or 0 if there are none.
   17.88 + */
   17.89 +static int
   17.90 +EV_IsHaptic(int fd)
   17.91 +{
   17.92 +    unsigned int ret;
   17.93 +    unsigned long features[1 + FF_MAX / sizeof(unsigned long)];
   17.94 +
   17.95 +    /* Ask device for what it has. */
   17.96 +    ret = 0;
   17.97 +    if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) {
   17.98 +        SDL_SetError("Haptic: Unable to get device's features: %s",
   17.99 +                     strerror(errno));
  17.100 +        return -1;
  17.101 +    }
  17.102 +
  17.103 +    /* Convert supported features to SDL_HAPTIC platform-neutral features. */
  17.104 +    EV_TEST(FF_CONSTANT, SDL_HAPTIC_CONSTANT);
  17.105 +    EV_TEST(FF_SINE, SDL_HAPTIC_SINE);
  17.106 +    EV_TEST(FF_SQUARE, SDL_HAPTIC_SQUARE);
  17.107 +    EV_TEST(FF_TRIANGLE, SDL_HAPTIC_TRIANGLE);
  17.108 +    EV_TEST(FF_SAW_UP, SDL_HAPTIC_SAWTOOTHUP);
  17.109 +    EV_TEST(FF_SAW_DOWN, SDL_HAPTIC_SAWTOOTHDOWN);
  17.110 +    EV_TEST(FF_RAMP, SDL_HAPTIC_RAMP);
  17.111 +    EV_TEST(FF_SPRING, SDL_HAPTIC_SPRING);
  17.112 +    EV_TEST(FF_FRICTION, SDL_HAPTIC_FRICTION);
  17.113 +    EV_TEST(FF_DAMPER, SDL_HAPTIC_DAMPER);
  17.114 +    EV_TEST(FF_INERTIA, SDL_HAPTIC_INERTIA);
  17.115 +    EV_TEST(FF_CUSTOM, SDL_HAPTIC_CUSTOM);
  17.116 +    EV_TEST(FF_GAIN, SDL_HAPTIC_GAIN);
  17.117 +    EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER);
  17.118 +
  17.119 +    /* Return what it supports. */
  17.120 +    return ret;
  17.121 +}
  17.122 +
  17.123 +
  17.124 +/*
  17.125 + * Tests whether a device is a mouse or not.
  17.126 + */
  17.127 +static int
  17.128 +EV_IsMouse(int fd)
  17.129 +{
  17.130 +    unsigned long argp[40];
  17.131 +
  17.132 +    /* Ask for supported features. */
  17.133 +    if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(argp)), argp) < 0) {
  17.134 +        return -1;
  17.135 +    }
  17.136 +
  17.137 +    /* Currently we only test for BTN_MOUSE which can give fake positives. */
  17.138 +    if (test_bit(BTN_MOUSE, argp) != 0) {
  17.139 +        return 1;
  17.140 +    }
  17.141 +
  17.142 +    return 0;
  17.143 +}
  17.144 +
  17.145 +/*
  17.146 + * Initializes the haptic subsystem by finding available devices.
  17.147 + */
  17.148 +int
  17.149 +SDL_SYS_HapticInit(void)
  17.150 +{
  17.151 +    const char joydev_pattern[] = "/dev/input/event%d";
  17.152 +    dev_t dev_nums[MAX_HAPTICS];
  17.153 +    char path[PATH_MAX];
  17.154 +    struct stat sb;
  17.155 +    int fd;
  17.156 +    int i, j, k;
  17.157 +    int duplicate;
  17.158 +    int numhaptics;
  17.159 +
  17.160 +    numhaptics = 0;
  17.161 +
  17.162 +    /* 
  17.163 +     * Limit amount of checks to MAX_HAPTICS since we may or may not have
  17.164 +     * permission to some or all devices.
  17.165 +     */
  17.166 +    i = 0;
  17.167 +    for (j = 0; j < MAX_HAPTICS; ++j) {
  17.168 +
  17.169 +        snprintf(path, PATH_MAX, joydev_pattern, i++);
  17.170 +
  17.171 +        /* check to see if file exists */
  17.172 +        if (stat(path, &sb) != 0)
  17.173 +            break;
  17.174 +
  17.175 +        /* check for duplicates */
  17.176 +        duplicate = 0;
  17.177 +        for (k = 0; (k < numhaptics) && !duplicate; ++k) {
  17.178 +            if (sb.st_rdev == dev_nums[k]) {
  17.179 +                duplicate = 1;
  17.180 +            }
  17.181 +        }
  17.182 +        if (duplicate) {
  17.183 +            continue;
  17.184 +        }
  17.185 +
  17.186 +        /* try to open */
  17.187 +        fd = open(path, O_RDWR, 0);
  17.188 +        if (fd < 0)
  17.189 +            continue;
  17.190 +
  17.191 +#ifdef DEBUG_INPUT_EVENTS
  17.192 +        printf("Checking %s\n", path);
  17.193 +#endif
  17.194 +
  17.195 +        /* see if it works */
  17.196 +        if (EV_IsHaptic(fd) > 0) {
  17.197 +            SDL_hapticlist[numhaptics].fname = SDL_strdup(path);
  17.198 +            SDL_hapticlist[numhaptics].haptic = NULL;
  17.199 +            dev_nums[numhaptics] = sb.st_rdev;
  17.200 +            ++numhaptics;
  17.201 +        }
  17.202 +        close(fd);
  17.203 +    }
  17.204 +
  17.205 +    return numhaptics;
  17.206 +}
  17.207 +
  17.208 +
  17.209 +/*
  17.210 + * Gets the name from a file descriptor.
  17.211 + */
  17.212 +static const char *
  17.213 +SDL_SYS_HapticNameFromFD(int fd)
  17.214 +{
  17.215 +    static char namebuf[128];
  17.216 +
  17.217 +    /* We use the evdev name ioctl. */
  17.218 +    if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) {
  17.219 +        return NULL;
  17.220 +    }
  17.221 +
  17.222 +    return namebuf;
  17.223 +}
  17.224 +
  17.225 +
  17.226 +/*
  17.227 + * Return the name of a haptic device, does not need to be opened.
  17.228 + */
  17.229 +const char *
  17.230 +SDL_SYS_HapticName(int index)
  17.231 +{
  17.232 +    int fd;
  17.233 +    const char *name;
  17.234 +
  17.235 +    /* Open the haptic device. */
  17.236 +    name = NULL;
  17.237 +    fd = open(SDL_hapticlist[index].fname, O_RDONLY, 0);
  17.238 +
  17.239 +    if (fd >= 0) {
  17.240 +
  17.241 +        name = SDL_SYS_HapticNameFromFD(fd);
  17.242 +        if (name == NULL) {
  17.243 +            /* No name found, return device character device */
  17.244 +            name = SDL_hapticlist[index].fname;
  17.245 +        }
  17.246 +    }
  17.247 +    close(fd);
  17.248 +
  17.249 +    return name;
  17.250 +}
  17.251 +
  17.252 +
  17.253 +/*
  17.254 + * Opens the haptic device from the file descriptor.
  17.255 + */
  17.256 +static int
  17.257 +SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd)
  17.258 +{
  17.259 +    const char *name;
  17.260 +
  17.261 +    /* Allocate the hwdata */
  17.262 +    haptic->hwdata = (struct haptic_hwdata *)
  17.263 +        SDL_malloc(sizeof(*haptic->hwdata));
  17.264 +    if (haptic->hwdata == NULL) {
  17.265 +        SDL_OutOfMemory();
  17.266 +        goto open_err;
  17.267 +    }
  17.268 +    SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
  17.269 +
  17.270 +    /* Set the data. */
  17.271 +    haptic->hwdata->fd = fd;
  17.272 +    haptic->supported = EV_IsHaptic(fd);
  17.273 +    haptic->naxes = 2;          /* Hardcoded for now, not sure if it's possible to find out. */
  17.274 +
  17.275 +    /* Set the effects */
  17.276 +    if (ioctl(fd, EVIOCGEFFECTS, &haptic->neffects) < 0) {
  17.277 +        SDL_SetError("Haptic: Unable to query device memory: %s",
  17.278 +                     strerror(errno));
  17.279 +        goto open_err;
  17.280 +    }
  17.281 +    haptic->nplaying = haptic->neffects;        /* Linux makes no distinction. */
  17.282 +    haptic->effects = (struct haptic_effect *)
  17.283 +        SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
  17.284 +    if (haptic->effects == NULL) {
  17.285 +        SDL_OutOfMemory();
  17.286 +        goto open_err;
  17.287 +    }
  17.288 +    /* Clear the memory */
  17.289 +    SDL_memset(haptic->effects, 0,
  17.290 +               sizeof(struct haptic_effect) * haptic->neffects);
  17.291 +
  17.292 +    return 0;
  17.293 +
  17.294 +    /* Error handling */
  17.295 +  open_err:
  17.296 +    close(fd);
  17.297 +    if (haptic->hwdata != NULL) {
  17.298 +        free(haptic->hwdata);
  17.299 +        haptic->hwdata = NULL;
  17.300 +    }
  17.301 +    return -1;
  17.302 +}
  17.303 +
  17.304 +
  17.305 +/*
  17.306 + * Opens a haptic device for usage.
  17.307 + */
  17.308 +int
  17.309 +SDL_SYS_HapticOpen(SDL_Haptic * haptic)
  17.310 +{
  17.311 +    int fd;
  17.312 +    int ret;
  17.313 +
  17.314 +    /* Open the character device */
  17.315 +    fd = open(SDL_hapticlist[haptic->index].fname, O_RDWR, 0);
  17.316 +    if (fd < 0) {
  17.317 +        SDL_SetError("Haptic: Unable to open %s: %s",
  17.318 +                     SDL_hapticlist[haptic->index], strerror(errno));
  17.319 +        return -1;
  17.320 +    }
  17.321 +
  17.322 +    /* Try to create the haptic. */
  17.323 +    ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
  17.324 +    if (ret < 0) {
  17.325 +        return -1;
  17.326 +    }
  17.327 +
  17.328 +    /* Set the fname. */
  17.329 +    haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
  17.330 +    return 0;
  17.331 +}
  17.332 +
  17.333 +
  17.334 +/*
  17.335 + * Opens a haptic device from first mouse it finds for usage.
  17.336 + */
  17.337 +int
  17.338 +SDL_SYS_HapticMouse(void)
  17.339 +{
  17.340 +    int fd;
  17.341 +    int i;
  17.342 +
  17.343 +    for (i = 0; i < SDL_numhaptics; i++) {
  17.344 +
  17.345 +        /* Open the device. */
  17.346 +        fd = open(SDL_hapticlist[i].fname, O_RDWR, 0);
  17.347 +        if (fd < 0) {
  17.348 +            SDL_SetError("Haptic: Unable to open %s: %s",
  17.349 +                         SDL_hapticlist[i], strerror(errno));
  17.350 +            return -1;
  17.351 +        }
  17.352 +
  17.353 +        /* Is it a mouse? */
  17.354 +        if (EV_IsMouse(fd)) {
  17.355 +            close(fd);
  17.356 +            return i;
  17.357 +        }
  17.358 +
  17.359 +        close(fd);
  17.360 +    }
  17.361 +
  17.362 +    return -1;
  17.363 +}
  17.364 +
  17.365 +
  17.366 +/*
  17.367 + * Checks to see if a joystick has haptic features.
  17.368 + */
  17.369 +int
  17.370 +SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
  17.371 +{
  17.372 +    return EV_IsHaptic(joystick->hwdata->fd);
  17.373 +}
  17.374 +
  17.375 +
  17.376 +/*
  17.377 + * Checks to see if the haptic device and joystick and in reality the same.
  17.378 + */
  17.379 +int
  17.380 +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
  17.381 +{
  17.382 +    /* We are assuming linux is using evdev which should trump the old
  17.383 +     * joystick methods. */
  17.384 +    if (SDL_strcmp(joystick->hwdata->fname, haptic->hwdata->fname) == 0) {
  17.385 +        return 1;
  17.386 +    }
  17.387 +    return 0;
  17.388 +}
  17.389 +
  17.390 +
  17.391 +/*
  17.392 + * Opens a SDL_Haptic from a SDL_Joystick.
  17.393 + */
  17.394 +int
  17.395 +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
  17.396 +{
  17.397 +    int i;
  17.398 +    int fd;
  17.399 +    int ret;
  17.400 +
  17.401 +    /* Find the joystick in the haptic list. */
  17.402 +    for (i = 0; i < MAX_HAPTICS; i++) {
  17.403 +        if (SDL_hapticlist[i].fname != NULL) {
  17.404 +            if (SDL_strcmp(SDL_hapticlist[i].fname, joystick->hwdata->fname)
  17.405 +                == 0) {
  17.406 +                haptic->index = i;
  17.407 +            }
  17.408 +        }
  17.409 +    }
  17.410 +
  17.411 +    fd = open(joystick->hwdata->fname, O_RDWR, 0);
  17.412 +    ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
  17.413 +    if (ret < 0) {
  17.414 +        return -1;
  17.415 +    }
  17.416 +
  17.417 +    haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
  17.418 +    return 0;
  17.419 +}
  17.420 +
  17.421 +
  17.422 +/*
  17.423 + * Closes the haptic device.
  17.424 + */
  17.425 +void
  17.426 +SDL_SYS_HapticClose(SDL_Haptic * haptic)
  17.427 +{
  17.428 +    if (haptic->hwdata) {
  17.429 +
  17.430 +        /* Free effects. */
  17.431 +        SDL_free(haptic->effects);
  17.432 +        haptic->effects = NULL;
  17.433 +        haptic->neffects = 0;
  17.434 +
  17.435 +        /* Clean up */
  17.436 +        close(haptic->hwdata->fd);
  17.437 +
  17.438 +        /* Free */
  17.439 +        SDL_free(haptic->hwdata);
  17.440 +        haptic->hwdata = NULL;
  17.441 +    }
  17.442 +
  17.443 +    /* Clear the rest. */
  17.444 +    SDL_memset(haptic, 0, sizeof(SDL_Haptic));
  17.445 +}
  17.446 +
  17.447 +
  17.448 +/* 
  17.449 + * Clean up after system specific haptic stuff
  17.450 + */
  17.451 +void
  17.452 +SDL_SYS_HapticQuit(void)
  17.453 +{
  17.454 +    int i;
  17.455 +
  17.456 +    for (i = 0; SDL_hapticlist[i].fname != NULL; i++) {
  17.457 +        /* Opened and not closed haptics are leaked, this is on purpose.
  17.458 +         * Close your haptic devices after usage. */
  17.459 +
  17.460 +        SDL_free(SDL_hapticlist[i].fname);
  17.461 +    }
  17.462 +    SDL_hapticlist[0].fname = NULL;
  17.463 +}
  17.464 +
  17.465 +
  17.466 +/*
  17.467 + * Converts an SDL button to a ff_trigger button.
  17.468 + */
  17.469 +static Uint16
  17.470 +SDL_SYS_ToButton(Uint16 button)
  17.471 +{
  17.472 +    Uint16 ff_button;
  17.473 +
  17.474 +    ff_button = 0;
  17.475 +
  17.476 +    /*
  17.477 +     * Not sure what the proper syntax is because this actually isn't implemented
  17.478 +     * in the current kernel from what I've seen (2.6.26).
  17.479 +     */
  17.480 +    if (button != 0) {
  17.481 +        ff_button = BTN_GAMEPAD + button - 1;
  17.482 +    }
  17.483 +
  17.484 +    return ff_button;
  17.485 +}
  17.486 +
  17.487 +
  17.488 +/*
  17.489 + * Returns the ff_effect usable direction from a SDL_HapticDirection.
  17.490 + */
  17.491 +static Uint16
  17.492 +SDL_SYS_ToDirection(SDL_HapticDirection * dir)
  17.493 +{
  17.494 +    Uint32 tmp;
  17.495 +    float f;                    /* Ideally we'd use fixed point math instead of floats... */
  17.496 +
  17.497 +    switch (dir->type) {
  17.498 +    case SDL_HAPTIC_POLAR:
  17.499 +        /* Linux directions are inverted. */
  17.500 +        tmp = (((18000 + dir->dir[0]) % 36000) * 0xFFFF) / 36000;
  17.501 +        return (Uint16) tmp;
  17.502 +
  17.503 +    case SDL_HAPTIC_CARTESIAN:
  17.504 +        /* We must invert "x" and "y" to go clockwise. */
  17.505 +        f = atan2(dir->dir[0], dir->dir[1]);
  17.506 +        tmp = (int) (f * 18000. / M_PI) % 36000;
  17.507 +        tmp = (tmp * 0xFFFF) / 36000;
  17.508 +        return (Uint16) tmp;
  17.509 +
  17.510 +    case SDL_HAPTIC_SPHERICAL:
  17.511 +        tmp = (36000 - dir->dir[0]) + 27000;    /* Convert to polars */
  17.512 +        tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000;
  17.513 +        return (Uint16) tmp;
  17.514 +
  17.515 +    default:
  17.516 +        SDL_SetError("Haptic: Unsupported direction type.");
  17.517 +        return (Uint16) - 1;
  17.518 +    }
  17.519 +
  17.520 +    return 0;
  17.521 +}
  17.522 +
  17.523 +
  17.524 +#define  CLAMP(x)    (((x) > 32767) ? 32767 : x)
  17.525 +/*
  17.526 + * Initializes the linux effect struct from a haptic_effect.
  17.527 + * Values above 32767 (for unsigned) are unspecified so we must clamp.
  17.528 + */
  17.529 +static int
  17.530 +SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src)
  17.531 +{
  17.532 +    Uint32 tmp;
  17.533 +    SDL_HapticConstant *constant;
  17.534 +    SDL_HapticPeriodic *periodic;
  17.535 +    SDL_HapticCondition *condition;
  17.536 +    SDL_HapticRamp *ramp;
  17.537 +
  17.538 +    /* Clear up */
  17.539 +    SDL_memset(dest, 0, sizeof(struct ff_effect));
  17.540 +
  17.541 +    switch (src->type) {
  17.542 +    case SDL_HAPTIC_CONSTANT:
  17.543 +        constant = &src->constant;
  17.544 +
  17.545 +        /* Header */
  17.546 +        dest->type = FF_CONSTANT;
  17.547 +        dest->direction = SDL_SYS_ToDirection(&constant->direction);
  17.548 +        if (dest->direction == (Uint16) - 1)
  17.549 +            return -1;
  17.550 +
  17.551 +        /* Replay */
  17.552 +        dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ?
  17.553 +            0 : CLAMP(constant->length);
  17.554 +        dest->replay.delay = CLAMP(constant->delay);
  17.555 +
  17.556 +        /* Trigger */
  17.557 +        dest->trigger.button = SDL_SYS_ToButton(constant->button);
  17.558 +        dest->trigger.interval = CLAMP(constant->interval);
  17.559 +
  17.560 +        /* Constant */
  17.561 +        dest->u.constant.level = constant->level;
  17.562 +
  17.563 +        /* Envelope */
  17.564 +        dest->u.constant.envelope.attack_length =
  17.565 +            CLAMP(constant->attack_length);
  17.566 +        dest->u.constant.envelope.attack_level =
  17.567 +            CLAMP(constant->attack_level);
  17.568 +        dest->u.constant.envelope.fade_length = CLAMP(constant->fade_length);
  17.569 +        dest->u.constant.envelope.fade_level = CLAMP(constant->fade_level);
  17.570 +
  17.571 +        break;
  17.572 +
  17.573 +    case SDL_HAPTIC_SINE:
  17.574 +    case SDL_HAPTIC_SQUARE:
  17.575 +    case SDL_HAPTIC_TRIANGLE:
  17.576 +    case SDL_HAPTIC_SAWTOOTHUP:
  17.577 +    case SDL_HAPTIC_SAWTOOTHDOWN:
  17.578 +        periodic = &src->periodic;
  17.579 +
  17.580 +        /* Header */
  17.581 +        dest->type = FF_PERIODIC;
  17.582 +        dest->direction = SDL_SYS_ToDirection(&periodic->direction);
  17.583 +        if (dest->direction == (Uint16) - 1)
  17.584 +            return -1;
  17.585 +
  17.586 +        /* Replay */
  17.587 +        dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ?
  17.588 +            0 : CLAMP(periodic->length);
  17.589 +        dest->replay.delay = CLAMP(periodic->delay);
  17.590 +
  17.591 +        /* Trigger */
  17.592 +        dest->trigger.button = SDL_SYS_ToButton(periodic->button);
  17.593 +        dest->trigger.interval = CLAMP(periodic->interval);
  17.594 +
  17.595 +        /* Periodic */
  17.596 +        if (periodic->type == SDL_HAPTIC_SINE)
  17.597 +            dest->u.periodic.waveform = FF_SINE;
  17.598 +        else if (periodic->type == SDL_HAPTIC_SQUARE)
  17.599 +            dest->u.periodic.waveform = FF_SQUARE;
  17.600 +        else if (periodic->type == SDL_HAPTIC_TRIANGLE)
  17.601 +            dest->u.periodic.waveform = FF_TRIANGLE;
  17.602 +        else if (periodic->type == SDL_HAPTIC_SAWTOOTHUP)
  17.603 +            dest->u.periodic.waveform = FF_SAW_UP;
  17.604 +        else if (periodic->type == SDL_HAPTIC_SAWTOOTHDOWN)
  17.605 +            dest->u.periodic.waveform = FF_SAW_DOWN;
  17.606 +        dest->u.periodic.period = CLAMP(periodic->period);
  17.607 +        dest->u.periodic.magnitude = periodic->magnitude;
  17.608 +        dest->u.periodic.offset = periodic->offset;
  17.609 +        /* Phase is calculated based of offset from period and then clamped. */
  17.610 +        tmp = ((periodic->phase % 36000) * dest->u.periodic.period) / 36000;
  17.611 +        dest->u.periodic.phase = CLAMP(tmp);
  17.612 +
  17.613 +        /* Envelope */
  17.614 +        dest->u.periodic.envelope.attack_length =
  17.615 +            CLAMP(periodic->attack_length);
  17.616 +        dest->u.periodic.envelope.attack_level =
  17.617 +            CLAMP(periodic->attack_level);
  17.618 +        dest->u.periodic.envelope.fade_length = CLAMP(periodic->fade_length);
  17.619 +        dest->u.periodic.envelope.fade_level = CLAMP(periodic->fade_level);
  17.620 +
  17.621 +        break;
  17.622 +
  17.623 +    case SDL_HAPTIC_SPRING:
  17.624 +    case SDL_HAPTIC_DAMPER:
  17.625 +    case SDL_HAPTIC_INERTIA:
  17.626 +    case SDL_HAPTIC_FRICTION:
  17.627 +        condition = &src->condition;
  17.628 +
  17.629 +        /* Header */
  17.630 +        if (condition->type == SDL_HAPTIC_SPRING)
  17.631 +            dest->type = FF_SPRING;
  17.632 +        else if (condition->type == SDL_HAPTIC_DAMPER)
  17.633 +            dest->type = FF_DAMPER;
  17.634 +        else if (condition->type == SDL_HAPTIC_INERTIA)
  17.635 +            dest->type = FF_INERTIA;
  17.636 +        else if (condition->type == SDL_HAPTIC_FRICTION)
  17.637 +            dest->type = FF_FRICTION;
  17.638 +        dest->direction = 0;    /* Handled by the condition-specifics. */
  17.639 +
  17.640 +        /* Replay */
  17.641 +        dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ?
  17.642 +            0 : CLAMP(condition->length);
  17.643 +        dest->replay.delay = CLAMP(condition->delay);
  17.644 +
  17.645 +        /* Trigger */
  17.646 +        dest->trigger.button = SDL_SYS_ToButton(condition->button);
  17.647 +        dest->trigger.interval = CLAMP(condition->interval);
  17.648 +
  17.649 +        /* Condition */
  17.650 +        /* X axis */
  17.651 +        dest->u.condition[0].right_saturation =
  17.652 +            CLAMP(condition->right_sat[0]);
  17.653 +        dest->u.condition[0].left_saturation = CLAMP(condition->left_sat[0]);
  17.654 +        dest->u.condition[0].right_coeff = condition->right_coeff[0];
  17.655 +        dest->u.condition[0].left_coeff = condition->left_coeff[0];
  17.656 +        dest->u.condition[0].deadband = CLAMP(condition->deadband[0]);
  17.657 +        dest->u.condition[0].center = condition->center[0];
  17.658 +        /* Y axis */
  17.659 +        dest->u.condition[1].right_saturation =
  17.660 +            CLAMP(condition->right_sat[1]);
  17.661 +        dest->u.condition[1].left_saturation = CLAMP(condition->left_sat[1]);
  17.662 +        dest->u.condition[1].right_coeff = condition->right_coeff[1];
  17.663 +        dest->u.condition[1].left_coeff = condition->left_coeff[1];
  17.664 +        dest->u.condition[1].deadband = CLAMP(condition->deadband[1]);
  17.665 +        dest->u.condition[1].center = condition->center[1];
  17.666 +
  17.667 +        /*
  17.668 +         * There is no envelope in the linux force feedback api for conditions.
  17.669 +         */
  17.670 +
  17.671 +        break;
  17.672 +
  17.673 +    case SDL_HAPTIC_RAMP:
  17.674 +        ramp = &src->ramp;
  17.675 +
  17.676 +        /* Header */
  17.677 +        dest->type = FF_RAMP;
  17.678 +        dest->direction = SDL_SYS_ToDirection(&ramp->direction);
  17.679 +        if (dest->direction == (Uint16) - 1)
  17.680 +            return -1;
  17.681 +
  17.682 +        /* Replay */
  17.683 +        dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ?
  17.684 +            0 : CLAMP(ramp->length);
  17.685 +        dest->replay.delay = CLAMP(ramp->delay);
  17.686 +
  17.687 +        /* Trigger */
  17.688 +        dest->trigger.button = SDL_SYS_ToButton(ramp->button);
  17.689 +        dest->trigger.interval = CLAMP(ramp->interval);
  17.690 +
  17.691 +        /* Ramp */
  17.692 +        dest->u.ramp.start_level = ramp->start;
  17.693 +        dest->u.ramp.end_level = ramp->end;
  17.694 +
  17.695 +        /* Envelope */
  17.696 +        dest->u.ramp.envelope.attack_length = CLAMP(ramp->attack_length);
  17.697 +        dest->u.ramp.envelope.attack_level = CLAMP(ramp->attack_level);
  17.698 +        dest->u.ramp.envelope.fade_length = CLAMP(ramp->fade_length);
  17.699 +        dest->u.ramp.envelope.fade_level = CLAMP(ramp->fade_level);
  17.700 +
  17.701 +        break;
  17.702 +
  17.703 +
  17.704 +    default:
  17.705 +        SDL_SetError("Haptic: Unknown effect type.");
  17.706 +        return -1;
  17.707 +    }
  17.708 +
  17.709 +    return 0;
  17.710 +}
  17.711 +
  17.712 +
  17.713 +/*
  17.714 + * Creates a new haptic effect.
  17.715 + */
  17.716 +int
  17.717 +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
  17.718 +                        SDL_HapticEffect * base)
  17.719 +{
  17.720 +    struct ff_effect *linux_effect;
  17.721 +
  17.722 +    /* Allocate the hardware effect */
  17.723 +    effect->hweffect = (struct haptic_hweffect *)
  17.724 +        SDL_malloc(sizeof(struct haptic_hweffect));
  17.725 +    if (effect->hweffect == NULL) {
  17.726 +        SDL_OutOfMemory();
  17.727 +        return -1;
  17.728 +    }
  17.729 +
  17.730 +    /* Prepare the ff_effect */
  17.731 +    linux_effect = &effect->hweffect->effect;
  17.732 +    if (SDL_SYS_ToFFEffect(linux_effect, base) != 0) {
  17.733 +        goto new_effect_err;
  17.734 +    }
  17.735 +    linux_effect->id = -1;      /* Have the kernel give it an id */
  17.736 +
  17.737 +    /* Upload the effect */
  17.738 +    if (ioctl(haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) {
  17.739 +        SDL_SetError("Haptic: Error uploading effect to the device: %s",
  17.740 +                     strerror(errno));
  17.741 +        goto new_effect_err;
  17.742 +    }
  17.743 +
  17.744 +    return 0;
  17.745 +
  17.746 +  new_effect_err:
  17.747 +    free(effect->hweffect);
  17.748 +    effect->hweffect = NULL;
  17.749 +    return -1;
  17.750 +}
  17.751 +
  17.752 +
  17.753 +/*
  17.754 + * Updates an effect.
  17.755 + *
  17.756 + * Note: Dynamically updating the direction can in some cases force
  17.757 + * the effect to restart and run once.
  17.758 + */
  17.759 +int
  17.760 +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
  17.761 +                           struct haptic_effect *effect,
  17.762 +                           SDL_HapticEffect * data)
  17.763 +{
  17.764 +    struct ff_effect linux_effect;
  17.765 +
  17.766 +    /* Create the new effect */
  17.767 +    if (SDL_SYS_ToFFEffect(&linux_effect, data) != 0) {
  17.768 +        return -1;
  17.769 +    }
  17.770 +    linux_effect.id = effect->hweffect->effect.id;
  17.771 +
  17.772 +    /* See if it can be uploaded. */
  17.773 +    if (ioctl(haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) {
  17.774 +        SDL_SetError("Haptic: Error updating the effect: %s",
  17.775 +                     strerror(errno));
  17.776 +        return -1;
  17.777 +    }
  17.778 +
  17.779 +    /* Copy the new effect into memory. */
  17.780 +    SDL_memcpy(&effect->hweffect->effect, &linux_effect,
  17.781 +               sizeof(struct ff_effect));
  17.782 +
  17.783 +    return effect->hweffect->effect.id;
  17.784 +}
  17.785 +
  17.786 +
  17.787 +/*
  17.788 + * Runs an effect.
  17.789 + */
  17.790 +int
  17.791 +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
  17.792 +                        Uint32 iterations)
  17.793 +{
  17.794 +    struct input_event run;
  17.795 +
  17.796 +    /* Prepare to run the effect */
  17.797 +    run.type = EV_FF;
  17.798 +    run.code = effect->hweffect->effect.id;
  17.799 +    /* We don't actually have infinity here, so we just do INT_MAX which is pretty damn close. */
  17.800 +    run.value = (iterations > INT_MAX) ? INT_MAX : iterations;
  17.801 +
  17.802 +    if (write(haptic->hwdata->fd, (const void *) &run, sizeof(run)) < 0) {
  17.803 +        SDL_SetError("Haptic: Unable to run the effect: %s", strerror(errno));
  17.804 +        return -1;
  17.805 +    }
  17.806 +
  17.807 +    return 0;
  17.808 +}
  17.809 +
  17.810 +
  17.811 +/*
  17.812 + * Stops an effect.
  17.813 + */
  17.814 +int
  17.815 +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  17.816 +{
  17.817 +    struct input_event stop;
  17.818 +
  17.819 +    stop.type = EV_FF;
  17.820 +    stop.code = effect->hweffect->effect.id;
  17.821 +    stop.value = 0;
  17.822 +
  17.823 +    if (write(haptic->hwdata->fd, (const void *) &stop, sizeof(stop)) < 0) {
  17.824 +        SDL_SetError("Haptic: Unable to stop the effect: %s",
  17.825 +                     strerror(errno));
  17.826 +        return -1;
  17.827 +    }
  17.828 +
  17.829 +    return 0;
  17.830 +}
  17.831 +
  17.832 +
  17.833 +/*
  17.834 + * Frees the effect.
  17.835 + */
  17.836 +void
  17.837 +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  17.838 +{
  17.839 +    if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) {
  17.840 +        SDL_SetError("Haptic: Error removing the effect from the device: %s",
  17.841 +                     strerror(errno));
  17.842 +    }
  17.843 +    SDL_free(effect->hweffect);
  17.844 +    effect->hweffect = NULL;
  17.845 +}
  17.846 +
  17.847 +
  17.848 +/*
  17.849 + * Gets the status of a haptic effect.
  17.850 + */
  17.851 +int
  17.852 +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
  17.853 +                              struct haptic_effect *effect)
  17.854 +{
  17.855 +#if 0                           /* Not supported atm. */
  17.856 +    struct input_event ie;
  17.857 +
  17.858 +    ie.type = EV_FF;
  17.859 +    ie.type = EV_FF_STATUS;
  17.860 +    ie.code = effect->hweffect->effect.id;
  17.861 +
  17.862 +    if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
  17.863 +        SDL_SetError("Haptic: Error getting device status.");
  17.864 +        return -1;
  17.865 +    }
  17.866 +
  17.867 +    return 0;
  17.868 +#endif
  17.869 +
  17.870 +    return -1;
  17.871 +}
  17.872 +
  17.873 +
  17.874 +/*
  17.875 + * Sets the gain.
  17.876 + */
  17.877 +int
  17.878 +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
  17.879 +{
  17.880 +    struct input_event ie;
  17.881 +
  17.882 +    ie.type = EV_FF;
  17.883 +    ie.code = FF_GAIN;
  17.884 +    ie.value = (0xFFFFUL * gain) / 100;
  17.885 +
  17.886 +    if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
  17.887 +        SDL_SetError("Haptic: Error setting gain: %s", strerror(errno));
  17.888 +        return -1;
  17.889 +    }
  17.890 +
  17.891 +    return 0;
  17.892 +}
  17.893 +
  17.894 +
  17.895 +/*
  17.896 + * Sets the autocentering.
  17.897 + */
  17.898 +int
  17.899 +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  17.900 +{
  17.901 +    struct input_event ie;
  17.902 +
  17.903 +    ie.type = EV_FF;
  17.904 +    ie.code = FF_AUTOCENTER;
  17.905 +    ie.value = (0xFFFFUL * autocenter) / 100;
  17.906 +
  17.907 +    if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
  17.908 +        SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno));
  17.909 +        return -1;
  17.910 +    }
  17.911 +
  17.912 +    return 0;
  17.913 +}
  17.914 +
  17.915 +
  17.916 +/*
  17.917 + * Pausing is not supported atm by linux.
  17.918 + */
  17.919 +int
  17.920 +SDL_SYS_HapticPause(SDL_Haptic * haptic)
  17.921 +{
  17.922 +    return -1;
  17.923 +}
  17.924 +
  17.925 +
  17.926 +/*
  17.927 + * Unpausing is not supported atm by linux.
  17.928 + */
  17.929 +int
  17.930 +SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
  17.931 +{
  17.932 +    return -1;
  17.933 +}
  17.934 +
  17.935 +
  17.936 +/*
  17.937 + * Stops all the currently playing effects.
  17.938 + */
  17.939 +int
  17.940 +SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
  17.941 +{
  17.942 +    int i, ret;
  17.943 +
  17.944 +    /* Linux does not support this natively so we have to loop. */
  17.945 +    for (i = 0; i < haptic->neffects; i++) {
  17.946 +        if (haptic->effects[i].hweffect != NULL) {
  17.947 +            ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]);
  17.948 +            if (ret < 0) {
  17.949 +                SDL_SetError
  17.950 +                    ("Haptic: Error while trying to stop all playing effects.");
  17.951 +                return -1;
  17.952 +            }
  17.953 +        }
  17.954 +    }
  17.955 +    return 0;
  17.956 +}
  17.957 +
  17.958 +
  17.959 +#endif /* SDL_HAPTIC_LINUX */
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/haptic/win32/SDL_syshaptic.c	Mon Aug 25 09:55:03 2008 +0000
    18.3 @@ -0,0 +1,1392 @@
    18.4 +/*
    18.5 +    SDL - Simple DirectMedia Layer
    18.6 +    Copyright (C) 2008 Edgar Simo
    18.7 +
    18.8 +    This library is free software; you can redistribute it and/or
    18.9 +    modify it under the terms of the GNU Lesser General Public
   18.10 +    License as published by the Free Software Foundation; either
   18.11 +    version 2.1 of the License, or (at your option) any later version.
   18.12 +
   18.13 +    This library is distributed in the hope that it will be useful,
   18.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   18.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   18.16 +    Lesser General Public License for more details.
   18.17 +
   18.18 +    You should have received a copy of the GNU Lesser General Public
   18.19 +    License along with this library; if not, write to the Free Software
   18.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   18.21 +
   18.22 +    Sam Lantinga
   18.23 +    slouken@libsdl.org
   18.24 +*/
   18.25 +#include "SDL_config.h"
   18.26 +
   18.27 +#ifdef SDL_HAPTIC_DINPUT
   18.28 +
   18.29 +#include "SDL_haptic.h"
   18.30 +#include "../SDL_syshaptic.h"
   18.31 +#include "SDL_joystick.h"
   18.32 +#include "../../joystick/SDL_sysjoystick.h"     /* For the real SDL_Joystick */
   18.33 +#include "../../joystick/win32/SDL_dxjoystick_c.h"      /* For joystick hwdata */
   18.34 +
   18.35 +#define WIN32_LEAN_AND_MEAN
   18.36 +#include <windows.h>
   18.37 +
   18.38 +#define DIRECTINPUT_VERSION 0x0700      /* Need at least DirectX 7 for dwStartDelay */
   18.39 +#include <dinput.h>
   18.40 +#include <dxerr.h>
   18.41 +#ifdef _MSC_VER
   18.42 +#  pragma comment (lib, "dinput8.lib")
   18.43 +#  pragma comment (lib, "dxguid.lib")
   18.44 +#  pragma comment (lib, "dxerr.lib")
   18.45 +#endif /* _MSC_VER */
   18.46 +
   18.47 +    /* an ISO hack for VisualC++ */
   18.48 +#ifdef _MSC_VER
   18.49 +#define   snprintf   _snprintf
   18.50 +#endif /* _MSC_VER */
   18.51 +
   18.52 +
   18.53 +#define MAX_HAPTICS  32
   18.54 +
   18.55 +
   18.56 +/*
   18.57 + * List of available haptic devices.
   18.58 + */
   18.59 +static struct
   18.60 +{
   18.61 +    DIDEVICEINSTANCE instance;
   18.62 +    SDL_Haptic *haptic;
   18.63 +    DIDEVCAPS capabilities;
   18.64 +} SDL_hapticlist[MAX_HAPTICS];
   18.65 +
   18.66 +
   18.67 +/*
   18.68 + * Haptic system hardware data.
   18.69 + */
   18.70 +struct haptic_hwdata
   18.71 +{
   18.72 +    LPDIRECTINPUTDEVICE2 device;
   18.73 +    DWORD axes[3];              /* Axes to use. */
   18.74 +    int is_joystick;            /* Device is loaded as joystick. */
   18.75 +};
   18.76 +
   18.77 +
   18.78 +/*
   18.79 + * Haptic system effect data.
   18.80 + */
   18.81 +struct haptic_hweffect
   18.82 +{
   18.83 +    DIEFFECT effect;
   18.84 +    LPDIRECTINPUTEFFECT ref;
   18.85 +};
   18.86 +
   18.87 +
   18.88 +/*
   18.89 + * Internal stuff.
   18.90 + */
   18.91 +static LPDIRECTINPUT dinput = NULL;
   18.92 +
   18.93 +
   18.94 +/*
   18.95 + * External stuff.
   18.96 + */
   18.97 +extern HWND SDL_HelperWindow;
   18.98 +
   18.99 +
  18.100 +/*
  18.101 + * Prototypes.
  18.102 + */
  18.103 +static void DI_SetError(const char *str, HRESULT err);
  18.104 +static int DI_GUIDIsSame(const GUID * a, const GUID * b);
  18.105 +static int SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic,
  18.106 +                                          DIDEVICEINSTANCE instance);
  18.107 +static int SDL_SYS_HapticOpenFromDevice2(SDL_Haptic * haptic,
  18.108 +                                         LPDIRECTINPUTDEVICE2 device2);
  18.109 +static DWORD DIGetTriggerButton(Uint16 button);
  18.110 +static int SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir,
  18.111 +                                int naxes);
  18.112 +static int SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest,
  18.113 +                              SDL_HapticEffect * src);
  18.114 +static void SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type);
  18.115 +static REFGUID SDL_SYS_HapticEffectType(SDL_HapticEffect * effect);
  18.116 +/* Callbacks. */
  18.117 +static BOOL CALLBACK EnumHapticsCallback(const DIDEVICEINSTANCE *
  18.118 +                                         pdidInstance, VOID * pContext);
  18.119 +static BOOL CALLBACK DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv);
  18.120 +
  18.121 +
  18.122 +/* 
  18.123 + * Like SDL_SetError but for DX error codes.
  18.124 + */
  18.125 +static void
  18.126 +DI_SetError(const char *str, HRESULT err)
  18.127 +{
  18.128 +    SDL_SetError("Haptic: %s - %s: %s", str,
  18.129 +                 DXGetErrorString(err), DXGetErrorDescription(err));
  18.130 +}
  18.131 +
  18.132 +
  18.133 +/*
  18.134 + * Checks to see if two GUID are the same.
  18.135 + */
  18.136 +static int
  18.137 +DI_GUIDIsSame(const GUID * a, const GUID * b)
  18.138 +{
  18.139 +    if (((a)->Data1 == (b)->Data1) &&
  18.140 +        ((a)->Data2 == (b)->Data2) &&
  18.141 +        ((a)->Data3 == (b)->Data3) &&
  18.142 +        (SDL_strcmp((a)->Data4, (b)->Data4) == 0))
  18.143 +        return 1;
  18.144 +    return 0;
  18.145 +}
  18.146 +
  18.147 +
  18.148 +/*
  18.149 + * Initializes the haptic subsystem.
  18.150 + */
  18.151 +int
  18.152 +SDL_SYS_HapticInit(void)
  18.153 +{
  18.154 +    HRESULT ret;
  18.155 +    HINSTANCE instance;
  18.156 +
  18.157 +    if (dinput != NULL) {       /* Already open. */
  18.158 +        SDL_SetError("Haptic: SubSystem already open.");
  18.159 +        return -1;
  18.160 +    }
  18.161 +
  18.162 +    /* Clear all the memory. */
  18.163 +    SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist));
  18.164 +
  18.165 +    SDL_numhaptics = 0;
  18.166 +
  18.167 +    ret = CoInitialize(NULL);
  18.168 +    if (FAILED(ret)) {
  18.169 +        DI_SetError("Coinitialize", ret);
  18.170 +        return -1;
  18.171 +    }
  18.172 +
  18.173 +    ret = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER,
  18.174 +                           &IID_IDirectInput, &dinput);
  18.175 +    if (FAILED(ret)) {
  18.176 +        DI_SetError("CoCreateInstance", ret);
  18.177 +        return -1;
  18.178 +    }
  18.179 +
  18.180 +    /* Because we used CoCreateInstance, we need to Initialize it, first. */
  18.181 +    instance = GetModuleHandle(NULL);
  18.182 +    if (instance == NULL) {
  18.183 +        SDL_SetError("GetModuleHandle() failed with error code %d.",
  18.184 +                     GetLastError());
  18.185 +        return -1;
  18.186 +    }
  18.187 +    ret = IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION);
  18.188 +    if (FAILED(ret)) {
  18.189 +        DI_SetError("Initializing DirectInput device", ret);
  18.190 +        return -1;
  18.191 +    }
  18.192 +
  18.193 +    /* Look for haptic devices. */
  18.194 +    ret = IDirectInput_EnumDevices(dinput, 0,   /* Not sure if this is legal, but gets all devices. */
  18.195 +                                   EnumHapticsCallback,
  18.196 +                                   NULL,
  18.197 +                                   DIEDFL_FORCEFEEDBACK |
  18.198 +                                   DIEDFL_ATTACHEDONLY);
  18.199 +    if (FAILED(ret)) {
  18.200 +        DI_SetError("Enumerating DirectInput devices", ret);
  18.201 +        return -1;
  18.202 +    }
  18.203 +
  18.204 +    return SDL_numhaptics;
  18.205 +}
  18.206 +
  18.207 +/*
  18.208 + * Callback to find the haptic devices.
  18.209 + */
  18.210 +static BOOL CALLBACK
  18.211 +EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
  18.212 +{
  18.213 +    HRESULT ret;
  18.214 +    LPDIRECTINPUTDEVICE device;
  18.215 +
  18.216 +    /* Copy the instance over, useful for creating devices. */
  18.217 +    SDL_memcpy(&SDL_hapticlist[SDL_numhaptics].instance, pdidInstance,
  18.218 +               sizeof(DIDEVICEINSTANCE));
  18.219 +
  18.220 +    /* Open the device */
  18.221 +    ret = IDirectInput_CreateDevice(dinput, &pdidInstance->guidInstance,
  18.222 +                                    &device, NULL);
  18.223 +    if (FAILED(ret)) {
  18.224 +        /* DI_SetError("Creating DirectInput device",ret); */
  18.225 +        return DIENUM_CONTINUE;
  18.226 +    }
  18.227 +
  18.228 +    /* Get capabilities. */
  18.229 +    SDL_hapticlist[SDL_numhaptics].capabilities.dwSize = sizeof(DIDEVCAPS);
  18.230 +    ret = IDirectInputDevice_GetCapabilities(device,
  18.231 +                                             &SDL_hapticlist[SDL_numhaptics].
  18.232 +                                             capabilities);
  18.233 +    if (FAILED(ret)) {
  18.234 +        /* DI_SetError("Getting device capabilities",ret); */
  18.235 +        IDirectInputDevice_Release(device);
  18.236 +        return DIENUM_CONTINUE;
  18.237 +    }
  18.238 +
  18.239 +    /* Close up device and count it. */
  18.240 +    IDirectInputDevice_Release(device);
  18.241 +    SDL_numhaptics++;
  18.242 +
  18.243 +    /* Watch out for hard limit. */
  18.244 +    if (SDL_numhaptics >= MAX_HAPTICS)
  18.245 +        return DIENUM_STOP;
  18.246 +
  18.247 +    return DIENUM_CONTINUE;
  18.248 +}
  18.249 +
  18.250 +
  18.251 +/*
  18.252 + * Return the name of a haptic device, does not need to be opened.
  18.253 + */
  18.254 +const char *
  18.255 +SDL_SYS_HapticName(int index)
  18.256 +{
  18.257 +    return SDL_hapticlist[index].instance.tszProductName;
  18.258 +}
  18.259 +
  18.260 +
  18.261 +/*
  18.262 + * Callback to get all supported effects.
  18.263 + */
  18.264 +#define EFFECT_TEST(e,s)               \
  18.265 +if (DI_GUIDIsSame(&pei->guid, &(e)))   \
  18.266 +   haptic->supported |= (s)
  18.267 +static BOOL CALLBACK
  18.268 +DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv)
  18.269 +{
  18.270 +    /* Prepare the haptic device. */
  18.271 +    SDL_Haptic *haptic = (SDL_Haptic *) pv;
  18.272 +
  18.273 +    /* Get supported. */
  18.274 +    EFFECT_TEST(GUID_Spring, SDL_HAPTIC_SPRING);
  18.275 +    EFFECT_TEST(GUID_Damper, SDL_HAPTIC_DAMPER);
  18.276 +    EFFECT_TEST(GUID_Inertia, SDL_HAPTIC_INERTIA);
  18.277 +    EFFECT_TEST(GUID_Friction, SDL_HAPTIC_FRICTION);
  18.278 +    EFFECT_TEST(GUID_ConstantForce, SDL_HAPTIC_CONSTANT);
  18.279 +    EFFECT_TEST(GUID_CustomForce, SDL_HAPTIC_CUSTOM);
  18.280 +    EFFECT_TEST(GUID_Sine, SDL_HAPTIC_SINE);
  18.281 +    EFFECT_TEST(GUID_Square, SDL_HAPTIC_SQUARE);
  18.282 +    EFFECT_TEST(GUID_Triangle, SDL_HAPTIC_TRIANGLE);
  18.283 +    EFFECT_TEST(GUID_SawtoothUp, SDL_HAPTIC_SAWTOOTHUP);
  18.284 +    EFFECT_TEST(GUID_SawtoothDown, SDL_HAPTIC_SAWTOOTHDOWN);
  18.285 +    EFFECT_TEST(GUID_RampForce, SDL_HAPTIC_RAMP);
  18.286 +
  18.287 +    /* Check for more. */
  18.288 +    return DIENUM_CONTINUE;
  18.289 +}
  18.290 +
  18.291 +
  18.292 +/*
  18.293 + * Callback to get supported axes.
  18.294 + */
  18.295 +static BOOL CALLBACK
  18.296 +DI_DeviceObjectCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
  18.297 +{
  18.298 +    SDL_Haptic *haptic = (SDL_Haptic *) pvRef;
  18.299 +
  18.300 +    if ((dev->dwType & DIDFT_AXIS) && (dev->dwFlags & DIDOI_FFACTUATOR)) {
  18.301 +
  18.302 +        haptic->hwdata->axes[haptic->naxes] = dev->dwOfs;
  18.303 +        haptic->naxes++;
  18.304 +
  18.305 +        /* Currently using the artificial limit of 3 axes. */
  18.306 +        if (haptic->naxes >= 3) {
  18.307 +            return DIENUM_STOP;
  18.308 +        }
  18.309 +    }
  18.310 +
  18.311 +    return DIENUM_CONTINUE;
  18.312 +}
  18.313 +
  18.314 +
  18.315 +/*
  18.316 + * Opens the haptic device from the file descriptor.
  18.317 + *
  18.318 + *    Steps:
  18.319 + *       - Open temporary DirectInputDevice interface.
  18.320 + *       - Create DirectInputDevice2 interface.
  18.321 + *       - Release DirectInputDevice interface.
  18.322 + *       - Call SDL_SYS_HapticOpenFromDevice2
  18.323 + */
  18.324 +static int
  18.325 +SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance)
  18.326 +{
  18.327 +    HRESULT ret;
  18.328 +    int ret2;
  18.329 +    LPDIRECTINPUTDEVICE device;
  18.330 +
  18.331 +    /* Allocate the hwdata */
  18.332 +    haptic->hwdata = (struct haptic_hwdata *)
  18.333 +        SDL_malloc(sizeof(*haptic->hwdata));
  18.334 +    if (haptic->hwdata == NULL) {
  18.335 +        SDL_OutOfMemory();
  18.336 +        goto creat_err;
  18.337 +    }
  18.338 +    SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
  18.339 +
  18.340 +    /* Open the device */
  18.341 +    ret = IDirectInput_CreateDevice(dinput, &instance.guidInstance,
  18.342 +                                    &device, NULL);
  18.343 +    if (FAILED(ret)) {
  18.344 +        DI_SetError("Creating DirectInput device", ret);
  18.345 +        goto creat_err;
  18.346 +    }
  18.347 +
  18.348 +    /* Now get the IDirectInputDevice2 interface, instead. */
  18.349 +    ret = IDirectInputDevice_QueryInterface(device,
  18.350 +                                            &IID_IDirectInputDevice2,
  18.351 +                                            (LPVOID *) & haptic->hwdata->
  18.352 +                                            device);
  18.353 +    /* Done with the temporary one now. */
  18.354 +    IDirectInputDevice_Release(device);
  18.355 +    if (FAILED(ret)) {
  18.356 +        DI_SetError("Querying DirectInput interface", ret);
  18.357 +        goto creat_err;
  18.358 +    }
  18.359 +
  18.360 +    ret2 = SDL_SYS_HapticOpenFromDevice2(haptic, haptic->hwdata->device);
  18.361 +    if (ret2 < 0) {
  18.362 +        goto query_err;
  18.363 +    }
  18.364 +
  18.365 +    return 0;
  18.366 +
  18.367 +  query_err:
  18.368 +    IDirectInputDevice2_Release(haptic->hwdata->device);
  18.369 +  creat_err:
  18.370 +    if (haptic->hwdata != NULL) {
  18.371 +        SDL_free(haptic->hwdata);
  18.372 +        haptic->hwdata = NULL;
  18.373 +    }
  18.374 +    return -1;
  18.375 +}
  18.376 +
  18.377 +
  18.378 +/*
  18.379 + * Opens the haptic device from the file descriptor.
  18.380 + *
  18.381 + *    Steps:
  18.382 + *       - Set cooperative level.
  18.383 + *       - Set data format.
  18.384 + *       - Acquire exclusiveness.
  18.385 + *       - Reset actuators.
  18.386 + *       - Get supported featuers.
  18.387 + */
  18.388 +static int
  18.389 +SDL_SYS_HapticOpenFromDevice2(SDL_Haptic * haptic,
  18.390 +                              LPDIRECTINPUTDEVICE2 device2)
  18.391 +{
  18.392 +    HRESULT ret;
  18.393 +    DIPROPDWORD dipdw;
  18.394 +
  18.395 +    /* We'll use the device2 from now on. */
  18.396 +    haptic->hwdata->device = device2;
  18.397 +
  18.398 +    /* Grab it exclusively to use force feedback stuff. */
  18.399 +    ret = IDirectInputDevice2_SetCooperativeLevel(haptic->hwdata->device,
  18.400 +                                                  SDL_HelperWindow,
  18.401 +                                                  DISCL_EXCLUSIVE |
  18.402 +                                                  DISCL_BACKGROUND);
  18.403 +    if (FAILED(ret)) {
  18.404 +        DI_SetError("Setting cooperative level to exclusive", ret);
  18.405 +        goto acquire_err;
  18.406 +    }
  18.407 +
  18.408 +    /* Set data format. */
  18.409 +    ret = IDirectInputDevice2_SetDataFormat(haptic->hwdata->device,
  18.410 +                                            &c_dfDIJoystick2);
  18.411 +    if (FAILED(ret)) {
  18.412 +        DI_SetError("Setting data format", ret);
  18.413 +        goto acquire_err;
  18.414 +    }
  18.415 +
  18.416 +    /* Get number of axes. */
  18.417 +    ret = IDirectInputDevice2_EnumObjects(haptic->hwdata->device,
  18.418 +                                          DI_DeviceObjectCallback,
  18.419 +                                          haptic, DIDFT_AXIS);
  18.420 +    if (FAILED(ret)) {
  18.421 +        DI_SetError("Getting device axes", ret);
  18.422 +        goto acquire_err;
  18.423 +    }
  18.424 +
  18.425 +    /* Acquire the device. */
  18.426 +    ret = IDirectInputDevice2_Acquire(haptic->hwdata->device);
  18.427 +    if (FAILED(ret)) {
  18.428 +        DI_SetError("Acquiring DirectInput device", ret);
  18.429 +        goto acquire_err;
  18.430 +    }
  18.431 +
  18.432 +    /* Reset all actuators - just in case. */
  18.433 +    ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
  18.434 +                                                       DISFFC_RESET);
  18.435 +    if (FAILED(ret)) {
  18.436 +        DI_SetError("Resetting device", ret);
  18.437 +        goto acquire_err;
  18.438 +    }
  18.439 +
  18.440 +    /* Enabling actuators. */
  18.441 +    ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
  18.442 +                                                       DISFFC_SETACTUATORSON);
  18.443 +    if (FAILED(ret)) {
  18.444 +        DI_SetError("Enabling actuators", ret);
  18.445 +        goto acquire_err;
  18.446 +    }
  18.447 +
  18.448 +    /* Get supported effects. */
  18.449 +    ret = IDirectInputDevice2_EnumEffects(haptic->hwdata->device,
  18.450 +                                          DI_EffectCallback, haptic,
  18.451 +                                          DIEFT_ALL);
  18.452 +    if (FAILED(ret)) {
  18.453 +        DI_SetError("Enumerating supported effects", ret);
  18.454 +        goto acquire_err;
  18.455 +    }
  18.456 +    if (haptic->supported == 0) {       /* Error since device supports nothing. */
  18.457 +        SDL_SetError("Haptic: Internal error on finding supported effects.");
  18.458 +        goto acquire_err;
  18.459 +    }
  18.460 +
  18.461 +    /* Check autogain and autocenter. */
  18.462 +    dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  18.463 +    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  18.464 +    dipdw.diph.dwObj = 0;
  18.465 +    dipdw.diph.dwHow = DIPH_DEVICE;
  18.466 +    dipdw.dwData = 10000;
  18.467 +    ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
  18.468 +                                          DIPROP_FFGAIN, &dipdw.diph);
  18.469 +    if (!FAILED(ret)) {         /* Gain is supported. */
  18.470 +        haptic->supported |= SDL_HAPTIC_GAIN;
  18.471 +    }
  18.472 +    dipdw.diph.dwObj = 0;
  18.473 +    dipdw.diph.dwHow = DIPH_DEVICE;
  18.474 +    dipdw.dwData = DIPROPAUTOCENTER_OFF;
  18.475 +    ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
  18.476 +                                          DIPROP_AUTOCENTER, &dipdw.diph);
  18.477 +    if (!FAILED(ret)) {         /* Autocenter is supported. */
  18.478 +        haptic->supported |= SDL_HAPTIC_AUTOCENTER;
  18.479 +    }
  18.480 +
  18.481 +    /* Status is always supported. */
  18.482 +    haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE;
  18.483 +
  18.484 +    /* Check maximum effects. */
  18.485 +    haptic->neffects = 128;     /* This is not actually supported as thus under windows,
  18.486 +                                   there is no way to tell the number of EFFECTS that a
  18.487 +                                   device can hold, so we'll just use a "random" number
  18.488 +                                   instead and put warnings in SDL_haptic.h */
  18.489 +    haptic->nplaying = 128;     /* Even more impossible to get this then neffects. */
  18.490 +
  18.491 +    /* Prepare effects memory. */
  18.492 +    haptic->effects = (struct haptic_effect *)
  18.493 +        SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
  18.494 +    if (haptic->effects == NULL) {
  18.495 +        SDL_OutOfMemory();
  18.496 +        goto acquire_err;
  18.497 +    }
  18.498 +    /* Clear the memory */
  18.499 +    SDL_memset(haptic->effects, 0,
  18.500 +               sizeof(struct haptic_effect) * haptic->neffects);
  18.501 +
  18.502 +    return 0;
  18.503 +
  18.504 +    /* Error handling */
  18.505 +  acquire_err:
  18.506 +    IDirectInputDevice2_Unacquire(haptic->hwdata->device);
  18.507 +    return -1;
  18.508 +
  18.509 +}
  18.510 +
  18.511 +
  18.512 +/*
  18.513 + * Opens a haptic device for usage.
  18.514 + */
  18.515 +int
  18.516 +SDL_SYS_HapticOpen(SDL_Haptic * haptic)
  18.517 +{
  18.518 +    return SDL_SYS_HapticOpenFromInstance(haptic,
  18.519 +                                          SDL_hapticlist[haptic->index].
  18.520 +                                          instance);
  18.521 +}
  18.522 +
  18.523 +
  18.524 +/*
  18.525 + * Opens a haptic device from first mouse it finds for usage.
  18.526 + */
  18.527 +int
  18.528 +SDL_SYS_HapticMouse(void)
  18.529 +{
  18.530 +    int i;
  18.531 +
  18.532 +    /* Grab the first mouse haptic device we find. */
  18.533 +    for (i = 0; i < SDL_numhaptics; i++) {
  18.534 +        if (SDL_hapticlist[i].capabilities.dwDevType == DIDEVTYPE_MOUSE) {
  18.535 +            return i;
  18.536 +        }
  18.537 +    }
  18.538 +
  18.539 +    return -1;
  18.540 +}
  18.541 +
  18.542 +
  18.543 +/*
  18.544 + * Checks to see if a joystick has haptic features.
  18.545 + */
  18.546 +int
  18.547 +SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
  18.548 +{
  18.549 +    if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
  18.550 +        return SDL_TRUE;
  18.551 +    }
  18.552 +
  18.553 +    return SDL_FALSE;
  18.554 +}
  18.555 +
  18.556 +
  18.557 +/*
  18.558 + * Checks to see if the haptic device and joystick and in reality the same.
  18.559 + */
  18.560 +int
  18.561 +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
  18.562 +{
  18.563 +    HRESULT ret;
  18.564 +    DIDEVICEINSTANCE hap_instance, joy_instance;
  18.565 +
  18.566 +    /* Get the device instances. */
  18.567 +    ret = IDirectInputDevice2_GetDeviceInfo(haptic->hwdata->device,
  18.568 +                                            &hap_instance);
  18.569 +    if (FAILED(ret)) {
  18.570 +        return 0;
  18.571 +    }
  18.572 +    ret = IDirectInputDevice2_GetDeviceInfo(joystick->hwdata->InputDevice,
  18.573 +                                            &joy_instance);
  18.574 +    if (FAILED(ret)) {
  18.575 +        return 0;
  18.576 +    }
  18.577 +
  18.578 +    if (DI_GUIDIsSame(&hap_instance.guidInstance, &joy_instance.guidInstance))
  18.579 +        return 1;
  18.580 +
  18.581 +    return 0;
  18.582 +}
  18.583 +
  18.584 +
  18.585 +/*
  18.586 + * Opens a SDL_Haptic from a SDL_Joystick.
  18.587 + */
  18.588 +int
  18.589 +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
  18.590 +{
  18.591 +    int ret;
  18.592 +
  18.593 +    /* Allocate the hwdata */
  18.594 +    haptic->hwdata = (struct haptic_hwdata *)
  18.595 +        SDL_malloc(sizeof(*haptic->hwdata));
  18.596 +    if (haptic->hwdata == NULL) {
  18.597 +        SDL_OutOfMemory();
  18.598 +        return -1;
  18.599 +    }
  18.600 +    SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
  18.601 +
  18.602 +    /* Now open the device. */
  18.603 +    ret =
  18.604 +        SDL_SYS_HapticOpenFromDevice2(haptic, joystick->hwdata->InputDevice);
  18.605 +    if (ret < 0) {
  18.606 +        return -1;
  18.607 +    }
  18.608 +
  18.609 +    /* It's using the joystick device. */
  18.610 +    haptic->hwdata->is_joystick = 1;
  18.611 +
  18.612 +    return 0;
  18.613 +}
  18.614 +
  18.615 +
  18.616 +/*
  18.617 + * Closes the haptic device.
  18.618 + */
  18.619 +void
  18.620 +SDL_SYS_HapticClose(SDL_Haptic * haptic)
  18.621 +{
  18.622 +    if (haptic->hwdata) {
  18.623 +
  18.624 +        /* Free effects. */
  18.625 +        SDL_free(haptic->effects);
  18.626 +        haptic->effects = NULL;
  18.627 +        haptic->neffects = 0;
  18.628 +
  18.629 +        /* Clean up */
  18.630 +        IDirectInputDevice2_Unacquire(haptic->hwdata->device);
  18.631 +        /* Only release if isn't grabbed by a joystick. */
  18.632 +        if (haptic->hwdata->is_joystick == 0) {
  18.633 +            IDirectInputDevice2_Release(haptic->hwdata->device);
  18.634 +        }
  18.635 +
  18.636 +        /* Free */
  18.637 +        SDL_free(haptic->hwdata);
  18.638 +        haptic->hwdata = NULL;
  18.639 +    }
  18.640 +}
  18.641 +
  18.642 +
  18.643 +/* 
  18.644 + * Clean up after system specific haptic stuff
  18.645 + */
  18.646 +void
  18.647 +SDL_SYS_HapticQuit(void)
  18.648 +{
  18.649 +    IDirectInput_Release(dinput);
  18.650 +    dinput = NULL;
  18.651 +}
  18.652 +
  18.653 +
  18.654 +/*
  18.655 + * Converts an SDL trigger button to an DIEFFECT trigger button.
  18.656 + */
  18.657 +static DWORD
  18.658 +DIGetTriggerButton(Uint16 button)
  18.659 +{
  18.660 +    DWORD dwTriggerButton;
  18.661 +
  18.662 +    dwTriggerButton = DIEB_NOTRIGGER;
  18.663 +
  18.664 +    if (button != 0) {
  18.665 +        dwTriggerButton = DIJOFS_BUTTON(button - 1);
  18.666 +    }
  18.667 +
  18.668 +    return dwTriggerButton;
  18.669 +}
  18.670 +
  18.671 +
  18.672 +/*
  18.673 + * Sets the direction.
  18.674 + */
  18.675 +static int
  18.676 +SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir, int naxes)
  18.677 +{
  18.678 +    LONG *rglDir;
  18.679 +
  18.680 +    /* Handle no axes a part. */
  18.681 +    if (naxes == 0) {
  18.682 +        effect->dwFlags |= DIEFF_SPHERICAL;     /* Set as default. */
  18.683 +        effect->rglDirection = NULL;
  18.684 +        return 0;
  18.685 +    }
  18.686 +
  18.687 +    /* Has axes. */
  18.688 +    rglDir = SDL_malloc(sizeof(LONG) * naxes);
  18.689 +    if (rglDir == NULL) {
  18.690 +        SDL_OutOfMemory();
  18.691 +        return -1;
  18.692 +    }
  18.693 +    SDL_memset(rglDir, 0, sizeof(LONG) * naxes);
  18.694 +    effect->rglDirection = rglDir;
  18.695 +
  18.696 +    switch (dir->type) {
  18.697 +    case SDL_HAPTIC_POLAR:
  18.698 +        effect->dwFlags |= DIEFF_POLAR;
  18.699 +        rglDir[0] = dir->dir[0];
  18.700 +        return 0;
  18.701 +    case SDL_HAPTIC_CARTESIAN:
  18.702 +        effect->dwFlags |= DIEFF_CARTESIAN;
  18.703 +        rglDir[0] = dir->dir[0];
  18.704 +        if (naxes > 1)
  18.705 +            rglDir[1] = dir->dir[1];
  18.706 +        if (naxes > 2)
  18.707 +            rglDir[2] = dir->dir[2];
  18.708 +        return 0;
  18.709 +    case SDL_HAPTIC_SPHERICAL:
  18.710 +        effect->dwFlags |= DIEFF_SPHERICAL;
  18.711 +        rglDir[0] = dir->dir[0];
  18.712 +        if (naxes > 1)
  18.713 +            rglDir[1] = dir->dir[1];
  18.714 +        if (naxes > 2)
  18.715 +            rglDir[2] = dir->dir[2];
  18.716 +        return 0;
  18.717 +
  18.718 +    default:
  18.719 +        SDL_SetError("Haptic: Unknown direction type.");
  18.720 +        return -1;
  18.721 +    }
  18.722 +}
  18.723 +
  18.724 +#define CONVERT(x)   (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF)
  18.725 +/*
  18.726 + * Creates the DIEFFECT from a SDL_HapticEffect.
  18.727 + */
  18.728 +static int
  18.729 +SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest,
  18.730 +                   SDL_HapticEffect * src)
  18.731 +{
  18.732 +    int i;
  18.733 +    DICONSTANTFORCE *constant;
  18.734 +    DIPERIODIC *periodic;
  18.735 +    DICONDITION *condition;     /* Actually an array of conditions - one per axis. */
  18.736 +    DIRAMPFORCE *ramp;
  18.737 +    DICUSTOMFORCE *custom;
  18.738 +    DIENVELOPE *envelope;
  18.739 +    SDL_HapticConstant *hap_constant;
  18.740 +    SDL_HapticPeriodic *hap_periodic;
  18.741 +    SDL_HapticCondition *hap_condition;
  18.742 +    SDL_HapticRamp *hap_ramp;
  18.743 +    SDL_HapticCustom *hap_custom;
  18.744 +    DWORD *axes;
  18.745 +
  18.746 +    /* Set global stuff. */
  18.747 +    SDL_memset(dest, 0, sizeof(DIEFFECT));
  18.748 +    dest->dwSize = sizeof(DIEFFECT);    /* Set the structure size. */
  18.749 +    dest->dwSamplePeriod = 0;   /* Not used by us. */
  18.750 +    dest->dwGain = 10000;       /* Gain is set globally, not locally. */
  18.751 +    dest->dwFlags = DIEFF_OBJECTOFFSETS;        /* Seems obligatory. */
  18.752 +
  18.753 +    /* Envelope. */
  18.754 +    envelope = SDL_malloc(sizeof(DIENVELOPE));
  18.755 +    if (envelope == NULL) {
  18.756 +        SDL_OutOfMemory();
  18.757 +        return -1;
  18.758 +    }
  18.759 +    SDL_memset(envelope, 0, sizeof(DIENVELOPE));
  18.760 +    dest->lpEnvelope = envelope;
  18.761 +    envelope->dwSize = sizeof(DIENVELOPE);      /* Always should be this. */
  18.762 +
  18.763 +    /* Axes. */
  18.764 +    dest->cAxes = haptic->naxes;
  18.765 +    if (dest->cAxes > 0) {
  18.766 +        axes = SDL_malloc(sizeof(DWORD) * dest->cAxes);
  18.767 +        if (axes == NULL) {
  18.768 +            SDL_OutOfMemory();
  18.769 +            return -1;
  18.770 +        }
  18.771 +        axes[0] = haptic->hwdata->axes[0];      /* Always at least one axis. */
  18.772 +        if (dest->cAxes > 1) {
  18.773 +            axes[1] = haptic->hwdata->axes[1];
  18.774 +        }
  18.775 +        if (dest->cAxes > 2) {
  18.776 +            axes[2] = haptic->hwdata->axes[2];
  18.777 +        }
  18.778 +        dest->rgdwAxes = axes;
  18.779 +    }
  18.780 +
  18.781 +
  18.782 +    /* The big type handling switch, even bigger then linux's version. */
  18.783 +    switch (src->type) {
  18.784 +    case SDL_HAPTIC_CONSTANT:
  18.785 +        hap_constant = &src->constant;
  18.786 +        constant = SDL_malloc(sizeof(DICONSTANTFORCE));
  18.787 +        if (constant == NULL) {
  18.788 +            SDL_OutOfMemory();
  18.789 +            return -1;
  18.790 +        }
  18.791 +        SDL_memset(constant, 0, sizeof(DICONSTANTFORCE));
  18.792 +
  18.793 +        /* Specifics */
  18.794 +        constant->lMagnitude = CONVERT(hap_constant->level);
  18.795 +        dest->cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
  18.796 +        dest->lpvTypeSpecificParams = constant;
  18.797 +
  18.798 +        /* Generics */
  18.799 +        dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */
  18.800 +        dest->dwTriggerButton = DIGetTriggerButton(hap_constant->button);
  18.801 +        dest->dwTriggerRepeatInterval = hap_constant->interval;
  18.802 +        dest->dwStartDelay = hap_constant->delay * 1000;        /* In microseconds. */
  18.803 +
  18.804 +        /* Direction. */
  18.805 +        if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes)
  18.806 +            < 0) {
  18.807 +            return -1;
  18.808 +        }
  18.809 +
  18.810 +        /* Envelope */
  18.811 +        if ((hap_constant->attack_length == 0)
  18.812 +            && (hap_constant->fade_length == 0)) {
  18.813 +            SDL_free(dest->lpEnvelope);
  18.814 +            dest->lpEnvelope = NULL;
  18.815 +        } else {
  18.816 +            envelope->dwAttackLevel = CONVERT(hap_constant->attack_level);
  18.817 +            envelope->dwAttackTime = hap_constant->attack_length * 1000;
  18.818 +            envelope->dwFadeLevel = CONVERT(hap_constant->fade_level);
  18.819 +            envelope->dwFadeTime = hap_constant->fade_length * 1000;
  18.820 +        }
  18.821 +
  18.822 +        break;
  18.823 +
  18.824 +    case SDL_HAPTIC_SINE:
  18.825 +    case SDL_HAPTIC_SQUARE:
  18.826 +    case SDL_HAPTIC_TRIANGLE:
  18.827 +    case SDL_HAPTIC_SAWTOOTHUP:
  18.828 +    case SDL_HAPTIC_SAWTOOTHDOWN:
  18.829 +        hap_periodic = &src->periodic;
  18.830 +        periodic = SDL_malloc(sizeof(DIPERIODIC));
  18.831 +        if (periodic == NULL) {
  18.832 +            SDL_OutOfMemory();
  18.833 +            return -1;
  18.834 +        }
  18.835 +        SDL_memset(periodic, 0, sizeof(DIPERIODIC));
  18.836 +
  18.837 +        /* Specifics */
  18.838 +        periodic->dwMagnitude = CONVERT(hap_periodic->magnitude);
  18.839 +        periodic->lOffset = CONVERT(hap_periodic->offset);
  18.840 +        periodic->dwPhase = hap_periodic->phase;
  18.841 +        periodic->dwPeriod = hap_periodic->period * 1000;
  18.842 +        dest->cbTypeSpecificParams = sizeof(DIPERIODIC);
  18.843 +        dest->lpvTypeSpecificParams = periodic;
  18.844 +
  18.845 +        /* Generics */
  18.846 +        dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */
  18.847 +        dest->dwTriggerButton = DIGetTriggerButton(hap_periodic->button);
  18.848 +        dest->dwTriggerRepeatInterval = hap_periodic->interval;
  18.849 +        dest->dwStartDelay = hap_periodic->delay * 1000;        /* In microseconds. */
  18.850 +
  18.851 +        /* Direction. */
  18.852 +        if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes)
  18.853 +            < 0) {
  18.854 +            return -1;
  18.855 +        }
  18.856 +
  18.857 +        /* Envelope */
  18.858 +        if ((hap_periodic->attack_length == 0)
  18.859 +            && (hap_periodic->fade_length == 0)) {
  18.860 +            SDL_free(dest->lpEnvelope);
  18.861 +            dest->lpEnvelope = NULL;
  18.862 +        } else {
  18.863 +            envelope->dwAttackLevel = CONVERT(hap_periodic->attack_level);
  18.864 +            envelope->dwAttackTime = hap_periodic->attack_length * 1000;
  18.865 +            envelope->dwFadeLevel = CONVERT(hap_periodic->fade_level);
  18.866 +            envelope->dwFadeTime = hap_periodic->fade_length * 1000;
  18.867 +        }
  18.868 +
  18.869 +        break;
  18.870 +
  18.871 +    case SDL_HAPTIC_SPRING:
  18.872 +    case SDL_HAPTIC_DAMPER:
  18.873 +    case SDL_HAPTIC_INERTIA:
  18.874 +    case SDL_HAPTIC_FRICTION:
  18.875 +        hap_condition = &src->condition;
  18.876 +        condition = SDL_malloc(sizeof(DICONDITION) * dest->cAxes);
  18.877 +        if (condition == NULL) {
  18.878 +            SDL_OutOfMemory();
  18.879 +            return -1;
  18.880 +        }
  18.881 +        SDL_memset(condition, 0, sizeof(DICONDITION));
  18.882 +
  18.883 +        /* Specifics */
  18.884 +        for (i = 0; i < (int) dest->cAxes; i++) {
  18.885 +            condition[i].lOffset = CONVERT(hap_condition->center[i]);
  18.886 +            condition[i].lPositiveCoefficient =
  18.887 +                CONVERT(hap_condition->right_coeff[i]);
  18.888 +            condition[i].lNegativeCoefficient =
  18.889 +                CONVERT(hap_condition->left_coeff[i]);
  18.890 +            condition[i].dwPositiveSaturation =
  18.891 +                CONVERT(hap_condition->right_sat[i]);
  18.892 +            condition[i].dwNegativeSaturation =
  18.893 +                CONVERT(hap_condition->left_sat[i]);
  18.894 +            condition[i].lDeadBand = CONVERT(hap_condition->deadband[i]);
  18.895 +        }
  18.896 +        dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes;
  18.897 +        dest->lpvTypeSpecificParams = condition;
  18.898 +
  18.899 +        /* Generics */
  18.900 +        dest->dwDuration = hap_condition->length * 1000;        /* In microseconds. */
  18.901 +        dest->dwTriggerButton = DIGetTriggerButton(hap_condition->button);
  18.902 +        dest->dwTriggerRepeatInterval = hap_condition->interval;
  18.903 +        dest->dwStartDelay = hap_condition->delay * 1000;       /* In microseconds. */
  18.904 +
  18.905 +        /* Direction. */
  18.906 +        if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes)
  18.907 +            < 0) {
  18.908 +            return -1;
  18.909 +        }
  18.910 +
  18.911 +        /* Envelope - Not actually supported by most CONDITION implementations. */
  18.912 +        SDL_free(dest->lpEnvelope);
  18.913 +        dest->lpEnvelope = NULL;
  18.914 +
  18.915 +        break;
  18.916 +
  18.917 +    case SDL_HAPTIC_RAMP:
  18.918 +        hap_ramp = &src->ramp;
  18.919 +        ramp = SDL_malloc(sizeof(DIRAMPFORCE));
  18.920 +        if (ramp == NULL) {
  18.921 +            SDL_OutOfMemory();
  18.922 +            return -1;
  18.923 +        }
  18.924 +        SDL_memset(ramp, 0, sizeof(DIRAMPFORCE));
  18.925 +
  18.926 +        /* Specifics */
  18.927 +        ramp->lStart = CONVERT(hap_ramp->start);
  18.928 +        ramp->lEnd = CONVERT(hap_ramp->end);
  18.929 +        dest->cbTypeSpecificParams = sizeof(DIRAMPFORCE);
  18.930 +        dest->lpvTypeSpecificParams = ramp;
  18.931 +
  18.932 +        /* Generics */
  18.933 +        dest->dwDuration = hap_ramp->length * 1000;     /* In microseconds. */
  18.934 +        dest->dwTriggerButton = DIGetTriggerButton(hap_ramp->button);
  18.935 +        dest->dwTriggerRepeatInterval = hap_ramp->interval;
  18.936 +        dest->dwStartDelay = hap_ramp->delay * 1000;    /* In microseconds. */
  18.937 +
  18.938 +        /* Direction. */
  18.939 +        if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) {
  18.940 +            return -1;
  18.941 +        }
  18.942 +
  18.943 +        /* Envelope */
  18.944 +        if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) {
  18.945 +            SDL_free(dest->lpEnvelope);
  18.946 +            dest->lpEnvelope = NULL;
  18.947 +        } else {
  18.948 +            envelope->dwAttackLevel = CONVERT(hap_ramp->attack_level);
  18.949 +            envelope->dwAttackTime = hap_ramp->attack_length * 1000;
  18.950 +            envelope->dwFadeLevel = CONVERT(hap_ramp->fade_level);
  18.951 +            envelope->dwFadeTime = hap_ramp->fade_length * 1000;
  18.952 +        }
  18.953 +
  18.954 +        break;
  18.955 +
  18.956 +    case SDL_HAPTIC_CUSTOM:
  18.957 +        hap_custom = &src->custom;
  18.958 +        custom = SDL_malloc(sizeof(DICUSTOMFORCE));
  18.959 +        if (custom == NULL) {
  18.960 +            SDL_OutOfMemory();
  18.961 +            return -1;
  18.962 +        }
  18.963 +        SDL_memset(custom, 0, sizeof(DICUSTOMFORCE));
  18.964 +
  18.965 +        /* Specifics */
  18.966 +        custom->cChannels = hap_custom->channels;
  18.967 +        custom->dwSamplePeriod = hap_custom->period * 1000;
  18.968 +        custom->cSamples = hap_custom->samples;
  18.969 +        custom->rglForceData =
  18.970 +            SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels);
  18.971 +        for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) {      /* Copy data. */
  18.972 +            custom->rglForceData[i] = CONVERT(hap_custom->data[i]);
  18.973 +        }
  18.974 +        dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE);
  18.975 +        dest->lpvTypeSpecificParams = custom;
  18.976 +
  18.977 +        /* Generics */
  18.978 +        dest->dwDuration = hap_custom->length * 1000;   /* In microseconds. */
  18.979 +        dest->dwTriggerButton = DIGetTriggerButton(hap_custom->button);
  18.980 +        dest->dwTriggerRepeatInterval = hap_custom->interval;
  18.981 +        dest->dwStartDelay = hap_custom->delay * 1000;  /* In microseconds. */
  18.982 +
  18.983 +        /* Direction. */
  18.984 +        if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) <
  18.985 +            0) {
  18.986 +            return -1;
  18.987 +        }
  18.988 +
  18.989 +        /* Envelope */
  18.990 +        if ((hap_custom->attack_length == 0)
  18.991 +            && (hap_custom->fade_length == 0)) {
  18.992 +            SDL_free(dest->lpEnvelope);
  18.993 +            dest->lpEnvelope = NULL;
  18.994 +        } else {
  18.995 +            envelope->dwAttackLevel = CONVERT(hap_custom->attack_level);
  18.996 +            envelope->dwAttackTime = hap_custom->attack_length * 1000;
  18.997 +            envelope->dwFadeLevel = CONVERT(hap_custom->fade_level);
  18.998 +            envelope->dwFadeTime = hap_custom->fade_length * 1000;
  18.999 +        }
 18.1000 +
 18.1001 +        break;
 18.1002 +
 18.1003 +
 18.1004 +    default:
 18.1005 +        SDL_SetError("Haptic: Unknown effect type.");
 18.1006 +        return -1;
 18.1007 +    }
 18.1008 +
 18.1009 +    return 0;
 18.1010 +}
 18.1011 +
 18.1012 +
 18.1013 +/*
 18.1014 + * Frees an DIEFFECT allocated by SDL_SYS_ToDIEFFECT.
 18.1015 + */
 18.1016 +static void
 18.1017 +SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type)
 18.1018 +{
 18.1019 +    DICUSTOMFORCE *custom;
 18.1020 +
 18.1021 +    if (effect->lpEnvelope != NULL) {
 18.1022 +        SDL_free(effect->lpEnvelope);
 18.1023 +        effect->lpEnvelope = NULL;
 18.1024 +    }
 18.1025 +    if (effect->rgdwAxes != NULL) {
 18.1026 +        SDL_free(effect->rgdwAxes);
 18.1027 +        effect->rgdwAxes = NULL;
 18.1028 +    }
 18.1029 +    if (effect->lpvTypeSpecificParams != NULL) {
 18.1030 +        if (type == SDL_HAPTIC_CUSTOM) {        /* Must free the custom data. */
 18.1031 +            custom = (DICUSTOMFORCE *) effect->lpvTypeSpecificParams;
 18.1032 +            SDL_free(custom->rglForceData);
 18.1033 +            custom->rglForceData = NULL;
 18.1034 +        }
 18.1035 +        SDL_free(effect->lpvTypeSpecificParams);
 18.1036 +        effect->lpvTypeSpecificParams = NULL;
 18.1037 +    }
 18.1038 +    if (effect->rglDirection != NULL) {
 18.1039 +        SDL_free(effect->rglDirection);
 18.1040 +        effect->rglDirection = NULL;
 18.1041 +    }
 18.1042 +}
 18.1043 +
 18.1044 +
 18.1045 +/*
 18.1046 + * Gets the effect type from the generic SDL haptic effect wrapper.
 18.1047 + */
 18.1048 +static REFGUID
 18.1049 +SDL_SYS_HapticEffectType(SDL_HapticEffect * effect)
 18.1050 +{
 18.1051 +    switch (effect->type) {
 18.1052 +    case SDL_HAPTIC_CONSTANT:
 18.1053 +        return &GUID_ConstantForce;
 18.1054 +
 18.1055 +    case SDL_HAPTIC_RAMP:
 18.1056 +        return &GUID_RampForce;
 18.1057 +
 18.1058 +    case SDL_HAPTIC_SQUARE:
 18.1059 +        return &GUID_Square;
 18.1060 +
 18.1061 +    case SDL_HAPTIC_SINE:
 18.1062 +        return &GUID_Sine;
 18.1063 +
 18.1064 +    case SDL_HAPTIC_TRIANGLE:
 18.1065 +        return &GUID_Triangle;
 18.1066 +
 18.1067 +    case SDL_HAPTIC_SAWTOOTHUP:
 18.1068 +        return &GUID_SawtoothUp;
 18.1069 +
 18.1070 +    case SDL_HAPTIC_SAWTOOTHDOWN:
 18.1071 +        return &GUID_SawtoothDown;
 18.1072 +
 18.1073 +    case SDL_HAPTIC_SPRING:
 18.1074 +        return &GUID_Spring;
 18.1075 +
 18.1076 +    case SDL_HAPTIC_DAMPER:
 18.1077 +        return &GUID_Damper;
 18.1078 +
 18.1079 +    case SDL_HAPTIC_INERTIA:
 18.1080 +        return &GUID_Inertia;
 18.1081 +
 18.1082 +    case SDL_HAPTIC_FRICTION:
 18.1083 +        return &GUID_Friction;
 18.1084 +
 18.1085 +    case SDL_HAPTIC_CUSTOM:
 18.1086 +        return &GUID_CustomForce;
 18.1087 +
 18.1088 +    default:
 18.1089 +        SDL_SetError("Haptic: Unknown effect type.");
 18.1090 +        return NULL;
 18.1091 +    }
 18.1092 +}
 18.1093 +
 18.1094 +
 18.1095 +/*
 18.1096 + * Creates a new haptic effect.
 18.1097 + */
 18.1098 +int
 18.1099 +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
 18.1100 +                        SDL_HapticEffect * base)
 18.1101 +{
 18.1102 +    HRESULT ret;
 18.1103 +
 18.1104 +    /* Get the type. */
 18.1105 +    REFGUID type = SDL_SYS_HapticEffectType(base);
 18.1106 +    if (type == NULL) {
 18.1107 +        goto err_hweffect;
 18.1108 +    }
 18.1109 +
 18.1110 +    /* Alloc the effect. */
 18.1111 +    effect->hweffect = (struct haptic_hweffect *)
 18.1112 +        SDL_malloc(sizeof(struct haptic_hweffect));
 18.1113 +    if (effect->hweffect == NULL) {
 18.1114 +        SDL_OutOfMemory();
 18.1115 +        goto err_hweffect;
 18.1116 +    }
 18.1117 +
 18.1118 +    /* Get the effect. */
 18.1119 +    if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
 18.1120 +        goto err_effectdone;
 18.1121 +    }
 18.1122 +
 18.1123 +    /* Create the actual effect. */
 18.1124 +    ret = IDirectInputDevice2_CreateEffect(haptic->hwdata->device, type,
 18.1125 +                                           &effect->hweffect->effect,
 18.1126 +                                           &effect->hweffect->ref, NULL);
 18.1127 +    if (FAILED(ret)) {
 18.1128 +        DI_SetError("Unable to create effect", ret);
 18.1129 +        goto err_effectdone;
 18.1130 +    }
 18.1131 +
 18.1132 +    return 0;
 18.1133 +
 18.1134 +  err_effectdone:
 18.1135 +    SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type);
 18.1136 +  err_hweffect:
 18.1137 +    if (effect->hweffect != NULL) {
 18.1138 +        SDL_free(effect->hweffect);
 18.1139 +        effect->hweffect = NULL;
 18.1140 +    }
 18.1141 +    return -1;
 18.1142 +}
 18.1143 +
 18.1144 +
 18.1145 +/*
 18.1146 + * Updates an effect.
 18.1147 + */
 18.1148 +int
 18.1149 +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
 18.1150 +                           struct haptic_effect *effect,
 18.1151 +                           SDL_HapticEffect * data)
 18.1152 +{
 18.1153 +    HRESULT ret;
 18.1154 +    DWORD flags;
 18.1155 +    DIEFFECT temp;
 18.1156 +
 18.1157 +    /* Get the effect. */
 18.1158 +    SDL_memset(&temp, 0, sizeof(DIEFFECT));
 18.1159 +    if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) {
 18.1160 +        goto err_update;
 18.1161 +    }
 18.1162 +
 18.1163 +    /* Set the flags.  Might be worthwhile to diff temp with loaded effect and
 18.1164 +     *  only change those parameters. */
 18.1165 +    flags = DIEP_DIRECTION |
 18.1166 +        DIEP_DURATION |
 18.1167 +        DIEP_ENVELOPE |
 18.1168 +        DIEP_STARTDELAY |
 18.1169 +        DIEP_TRIGGERBUTTON |
 18.1170 +        DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS;
 18.1171 +
 18.1172 +    /* Create the actual effect. */
 18.1173 +    ret =
 18.1174 +        IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags);
 18.1175 +    if (FAILED(ret)) {
 18.1176 +        DI_SetError("Unable to update effect", ret);
 18.1177 +        goto err_update;
 18.1178 +    }
 18.1179 +
 18.1180 +    /* Copy it over. */
 18.1181 +    SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type);
 18.1182 +    SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT));
 18.1183 +
 18.1184 +    return 0;
 18.1185 +
 18.1186 +  err_update:
 18.1187 +    SDL_SYS_HapticFreeDIEFFECT(&temp, data->type);
 18.1188 +    return -1;
 18.1189 +}
 18.1190 +
 18.1191 +
 18.1192 +/*
 18.1193 + * Runs an effect.
 18.1194 + */
 18.1195 +int
 18.1196 +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
 18.1197 +                        Uint32 iterations)
 18.1198 +{
 18.1199 +    HRESULT ret;
 18.1200 +    DWORD iter;
 18.1201 +
 18.1202 +    /* Check if it's infinite. */
 18.1203 +    if (iterations == SDL_HAPTIC_INFINITY) {
 18.1204 +        iter = INFINITE;
 18.1205 +    } else
 18.1206 +        iter = iterations;
 18.1207 +
 18.1208 +    /* Run the effect. */
 18.1209 +    ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0);
 18.1210 +    if (FAILED(ret)) {
 18.1211 +        DI_SetError("Running the effect", ret);
 18.1212 +        return -1;
 18.1213 +    }
 18.1214 +
 18.1215 +    return 0;
 18.1216 +}
 18.1217 +
 18.1218 +
 18.1219 +/*
 18.1220 + * Stops an effect.
 18.1221 + */
 18.1222 +int
 18.1223 +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
 18.1224 +{
 18.1225 +    HRESULT ret;
 18.1226 +
 18.1227 +    ret = IDirectInputEffect_Stop(effect->hweffect->ref);
 18.1228 +    if (FAILED(ret)) {
 18.1229 +        DI_SetError("Unable to stop effect", ret);
 18.1230 +        return -1;
 18.1231 +    }
 18.1232 +
 18.1233 +    return 0;
 18.1234 +}
 18.1235 +
 18.1236 +
 18.1237 +/*
 18.1238 + * Frees the effect.
 18.1239 + */
 18.1240 +void
 18.1241 +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
 18.1242 +{
 18.1243 +    HRESULT ret;
 18.1244 +
 18.1245 +    ret = IDirectInputEffect_Unload(effect->hweffect->ref);
 18.1246 +    if (FAILED(ret)) {
 18.1247 +        DI_SetError("Removing effect from the device", ret);
 18.1248 +    }
 18.1249 +    SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect,
 18.1250 +                               effect->effect.type);
 18.1251 +    SDL_free(effect->hweffect);
 18.1252 +    effect->hweffect = NULL;
 18.1253 +}
 18.1254 +
 18.1255 +
 18.1256 +/*
 18.1257 + * Gets the status of a haptic effect.
 18.1258 + */
 18.1259 +int
 18.1260 +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
 18.1261 +                              struct haptic_effect *effect)
 18.1262 +{
 18.1263 +    HRESULT ret;
 18.1264 +    DWORD status;
 18.1265 +
 18.1266 +    ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status);
 18.1267 +    if (FAILED(ret)) {
 18.1268 +        DI_SetError("Getting effect status", ret);
 18.1269 +        return -1;
 18.1270 +    }
 18.1271 +
 18.1272 +    if (status == 0)
 18.1273 +        return SDL_FALSE;
 18.1274 +    return SDL_TRUE;
 18.1275 +}
 18.1276 +
 18.1277 +
 18.1278 +/*
 18.1279 + * Sets the gain.
 18.1280 + */
 18.1281 +int
 18.1282 +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
 18.1283 +{
 18.1284 +    HRESULT ret;
 18.1285 +    DIPROPDWORD dipdw;
 18.1286 +
 18.1287 +    /* Create the weird structure thingy. */
 18.1288 +    dipdw.diph.dwSize = sizeof(DIPROPDWORD);
 18.1289 +    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
 18.1290 +    dipdw.diph.dwObj = 0;
 18.1291 +    dipdw.diph.dwHow = DIPH_DEVICE;
 18.1292 +    dipdw.dwData = gain * 100;  /* 0 to 10,000 */
 18.1293 +
 18.1294 +    /* Try to set the autocenter. */
 18.1295 +    ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
 18.1296 +                                          DIPROP_FFGAIN, &dipdw.diph);
 18.1297 +    if (FAILED(ret)) {
 18.1298 +        DI_SetError("Setting gain", ret);
 18.1299 +        return -1;
 18.1300 +    }
 18.1301 +
 18.1302 +    return 0;
 18.1303 +}
 18.1304 +
 18.1305 +
 18.1306 +/*
 18.1307 + * Sets the autocentering.
 18.1308 + */
 18.1309 +int
 18.1310 +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
 18.1311 +{
 18.1312 +    HRESULT ret;
 18.1313 +    DIPROPDWORD dipdw;
 18.1314 +
 18.1315 +    /* Create the weird structure thingy. */
 18.1316 +    dipdw.diph.dwSize = sizeof(DIPROPDWORD);
 18.1317 +    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
 18.1318 +    dipdw.diph.dwObj = 0;
 18.1319 +    dipdw.diph.dwHow = DIPH_DEVICE;
 18.1320 +    dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF :
 18.1321 +        DIPROPAUTOCENTER_ON;
 18.1322 +
 18.1323 +    /* Try to set the autocenter. */
 18.1324 +    ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
 18.1325 +                                          DIPROP_AUTOCENTER, &dipdw.diph);
 18.1326 +    if (FAILED(ret)) {
 18.1327 +        DI_SetError("Setting autocenter", ret);
 18.1328 +        return -1;
 18.1329 +    }
 18.1330 +
 18.1331 +    return 0;
 18.1332 +}
 18.1333 +
 18.1334 +
 18.1335 +/*
 18.1336 + * Pauses the device.
 18.1337 + */
 18.1338 +int
 18.1339 +SDL_SYS_HapticPause(SDL_Haptic * haptic)
 18.1340 +{
 18.1341 +    HRESULT ret;
 18.1342 +
 18.1343 +    /* Pause the device. */
 18.1344 +    ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
 18.1345 +                                                       DISFFC_PAUSE);
 18.1346 +    if (FAILED(ret)) {
 18.1347 +        DI_SetError("Pausing the device", ret);
 18.1348 +        return -1;
 18.1349 +    }
 18.1350 +
 18.1351 +    return 0;
 18.1352 +}
 18.1353 +
 18.1354 +
 18.1355 +/*
 18.1356 + * Pauses the device.
 18.1357 + */
 18.1358 +int
 18.1359 +SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
 18.1360 +{
 18.1361 +    HRESULT ret;
 18.1362 +
 18.1363 +    /* Unpause the device. */
 18.1364 +    ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
 18.1365 +                                                       DISFFC_CONTINUE);
 18.1366 +    if (FAILED(ret)) {
 18.1367 +        DI_SetError("Pausing the device", ret);
 18.1368 +        return -1;
 18.1369 +    }
 18.1370 +
 18.1371 +    return 0;
 18.1372 +}
 18.1373 +
 18.1374 +
 18.1375 +/*
 18.1376 + * Stops all the playing effects on the device.
 18.1377 + */
 18.1378 +int
 18.1379 +SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
 18.1380 +{
 18.1381 +    HRESULT ret;
 18.1382 +
 18.1383 +    /* Try to stop the effects. */
 18.1384 +    ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
 18.1385 +                                                       DISFFC_STOPALL);
 18.1386 +    if (FAILED(ret)) {
 18.1387 +        DI_SetError("Stopping the device", ret);
 18.1388 +        return -1;
 18.1389 +    }
 18.1390 +
 18.1391 +    return 0;
 18.1392 +}
 18.1393 +
 18.1394 +
 18.1395 +#endif /* SDL_HAPTIC_DINPUT */
    19.1 --- a/src/joystick/SDL_joystick.c	Mon Aug 25 08:50:37 2008 +0000
    19.2 +++ b/src/joystick/SDL_joystick.c	Mon Aug 25 09:55:03 2008 +0000
    19.3 @@ -193,8 +193,12 @@
    19.4      return (opened);
    19.5  }
    19.6  
    19.7 -static int
    19.8 -ValidJoystick(SDL_Joystick ** joystick)
    19.9 +
   19.10 +/*
   19.11 + * Checks to make sure the joystick is valid.
   19.12 + */
   19.13 +int
   19.14 +SDL_PrivateJoystickValid(SDL_Joystick ** joystick)
   19.15  {
   19.16      int valid;
   19.17  
   19.18 @@ -216,7 +220,7 @@
   19.19  int
   19.20  SDL_JoystickIndex(SDL_Joystick * joystick)
   19.21  {
   19.22 -    if (!ValidJoystick(&joystick)) {
   19.23 +    if (!SDL_PrivateJoystickValid(&joystick)) {
   19.24          return (-1);
   19.25      }
   19.26      return (joystick->index);
   19.27 @@ -228,7 +232,7 @@
   19.28  int
   19.29  SDL_JoystickNumAxes(SDL_Joystick * joystick)
   19.30  {
   19.31 -    if (!ValidJoystick(&joystick)) {
   19.32 +    if (!SDL_PrivateJoystickValid(&joystick)) {
   19.33          return (-1);
   19.34      }
   19.35      return (joystick->naxes);
   19.36 @@ -240,7 +244,7 @@
   19.37  int
   19.38  SDL_JoystickNumHats(SDL_Joystick * joystick)
   19.39  {
   19.40 -    if (!ValidJoystick(&joystick)) {
   19.41 +    if (!SDL_PrivateJoystickValid(&joystick)) {
   19.42          return (-1);
   19.43      }
   19.44      return (joystick->nhats);
   19.45 @@ -252,7 +256,7 @@
   19.46  int
   19.47  SDL_JoystickNumBalls(SDL_Joystick * joystick)
   19.48  {
   19.49 -    if (!ValidJoystick(&joystick)) {
   19.50 +    if (!SDL_PrivateJoystickValid(&joystick)) {
   19.51          return (-1);
   19.52      }
   19.53      return (joystick->nballs);
   19.54 @@ -264,7 +268,7 @@
   19.55  int
   19.56  SDL_JoystickNumButtons(SDL_Joystick * joystick)
   19.57  {
   19.58 -    if (!ValidJoystick(&joystick)) {
   19.59 +    if (!SDL_PrivateJoystickValid(&joystick)) {
   19.60          return (-1);
   19.61      }
   19.62      return (joystick->nbuttons);
   19.63 @@ -278,7 +282,7 @@
   19.64  {
   19.65      Sint16 state;
   19.66  
   19.67 -    if (!ValidJoystick(&joystick)) {
   19.68 +    if (!SDL_PrivateJoystickValid(&joystick)) {
   19.69          return (0);
   19.70      }
   19.71      if (axis < joystick->naxes) {
   19.72 @@ -298,7 +302,7 @@
   19.73  {
   19.74      Uint8 state;
   19.75  
   19.76 -    if (!ValidJoystick(&joystick)) {
   19.77 +    if (!SDL_PrivateJoystickValid(&joystick)) {
   19.78          return (0);
   19.79      }
   19.80      if (hat < joystick->nhats) {
   19.81 @@ -318,7 +322,7 @@
   19.82  {
   19.83      int retval;
   19.84  
   19.85 -    if (!ValidJoystick(&joystick)) {
   19.86 +    if (!SDL_PrivateJoystickValid(&joystick)) {
   19.87          return (-1);
   19.88      }
   19.89  
   19.90 @@ -347,7 +351,7 @@
   19.91  {
   19.92      Uint8 state;
   19.93  
   19.94 -    if (!ValidJoystick(&joystick)) {
   19.95 +    if (!SDL_PrivateJoystickValid(&joystick)) {
   19.96          return (0);
   19.97      }
   19.98      if (button < joystick->nbuttons) {
   19.99 @@ -367,7 +371,7 @@
  19.100  {
  19.101      int i;
  19.102  
  19.103 -    if (!ValidJoystick(&joystick)) {
  19.104 +    if (!SDL_PrivateJoystickValid(&joystick)) {
  19.105          return;
  19.106      }
  19.107  
    20.1 --- a/src/joystick/SDL_joystick_c.h	Mon Aug 25 08:50:37 2008 +0000
    20.2 +++ b/src/joystick/SDL_joystick_c.h	Mon Aug 25 09:55:03 2008 +0000
    20.3 @@ -36,4 +36,8 @@
    20.4                                    Uint8 hat, Uint8 value);
    20.5  extern int SDL_PrivateJoystickButton(SDL_Joystick * joystick,
    20.6                                       Uint8 button, Uint8 state);
    20.7 +
    20.8 +/* Internal sanity checking functions */
    20.9 +extern int SDL_PrivateJoystickValid(SDL_Joystick ** joystick);
   20.10 +
   20.11  /* vi: set ts=4 sw=4 expandtab: */
    21.1 --- a/src/joystick/darwin/SDL_sysjoystick.c	Mon Aug 25 08:50:37 2008 +0000
    21.2 +++ b/src/joystick/darwin/SDL_sysjoystick.c	Mon Aug 25 09:55:03 2008 +0000
    21.3 @@ -48,59 +48,14 @@
    21.4  #include <CoreFoundation/CoreFoundation.h>
    21.5  #include <Carbon/Carbon.h>      /* for NewPtrClear, DisposePtr */
    21.6  
    21.7 +/* For force feedback testing. */
    21.8 +#include <ForceFeedback/ForceFeedback.h>
    21.9 +#include <ForceFeedback/ForceFeedbackConstants.h>
   21.10 +
   21.11  #include "SDL_joystick.h"
   21.12  #include "../SDL_sysjoystick.h"
   21.13  #include "../SDL_joystick_c.h"
   21.14 -
   21.15 -struct recElement
   21.16 -{
   21.17 -    IOHIDElementCookie cookie;  /* unique value which identifies element, will NOT change */
   21.18 -    long min;                   /* reported min value possible */
   21.19 -    long max;                   /* reported max value possible */
   21.20 -#if 0
   21.21 -    /* TODO: maybe should handle the following stuff somehow? */
   21.22 -
   21.23 -    long scaledMin;             /* reported scaled min value possible */
   21.24 -    long scaledMax;             /* reported scaled max value possible */
   21.25 -    long size;                  /* size in bits of data return from element */
   21.26 -    Boolean relative;           /* are reports relative to last report (deltas) */
   21.27 -    Boolean wrapping;           /* does element wrap around (one value higher than max is min) */
   21.28 -    Boolean nonLinear;          /* are the values reported non-linear relative to element movement */
   21.29 -    Boolean preferredState;     /* does element have a preferred state (such as a button) */
   21.30 -    Boolean nullState;          /* does element have null state */
   21.31 -#endif                          /* 0 */
   21.32 -
   21.33 -    /* runtime variables used for auto-calibration */
   21.34 -    long minReport;             /* min returned value */
   21.35 -    long maxReport;             /* max returned value */
   21.36 -
   21.37 -    struct recElement *pNext;   /* next element in list */
   21.38 -};
   21.39 -typedef struct recElement recElement;
   21.40 -
   21.41 -struct joystick_hwdata
   21.42 -{
   21.43 -    IOHIDDeviceInterface **interface;   /* interface to device, NULL = no interface */
   21.44 -
   21.45 -    char product[256];          /* name of product */
   21.46 -    long usage;                 /* usage page from IOUSBHID Parser.h which defines general usage */
   21.47 -    long usagePage;             /* usage within above page from IOUSBHID Parser.h which defines specific usage */
   21.48 -
   21.49 -    long axes;                  /* number of axis (calculated, not reported by device) */
   21.50 -    long buttons;               /* number of buttons (calculated, not reported by device) */
   21.51 -    long hats;                  /* number of hat switches (calculated, not reported by device) */
   21.52 -    long elements;              /* number of total elements (shouldbe total of above) (calculated, not reported by device) */
   21.53 -
   21.54 -    recElement *firstAxis;
   21.55 -    recElement *firstButton;
   21.56 -    recElement *firstHat;
   21.57 -
   21.58 -    int removed;
   21.59 -    int uncentered;
   21.60 -
   21.61 -    struct joystick_hwdata *pNext;      /* next device */
   21.62 -};
   21.63 -typedef struct joystick_hwdata recDevice;
   21.64 +#include "SDL_sysjoystick_c.h"
   21.65  
   21.66  
   21.67  /* Linked list of all available devices */
   21.68 @@ -594,6 +549,12 @@
   21.69          /* save next device prior to disposing of this device */
   21.70          pDeviceNext = (*ppDevice)->pNext;
   21.71  
   21.72 +        /* free posible io_service_t */
   21.73 +        if ((*ppDevice)->ffservice) {
   21.74 +            IOObjectRelease((*ppDevice)->ffservice);
   21.75 +            (*ppDevice)->ffservice = 0;
   21.76 +        }
   21.77 +
   21.78          /* free element lists */
   21.79          HIDDisposeElementList(&(*ppDevice)->firstAxis);
   21.80          HIDDisposeElementList(&(*ppDevice)->firstButton);
   21.81 @@ -686,12 +647,6 @@
   21.82          if (!device)
   21.83              continue;
   21.84  
   21.85 -        /* dump device object, it is no longer needed */
   21.86 -        result = IOObjectRelease(ioHIDDeviceObject);
   21.87 -/*		if (KERN_SUCCESS != result)
   21.88 -			HIDReportErrorNum ("IOObjectRelease error with ioHIDDeviceObject.", result);
   21.89 -*/
   21.90 -
   21.91          /* Filter device list to non-keyboard/mouse stuff */
   21.92          if ((device->usagePage != kHIDPage_GenericDesktop) ||
   21.93              ((device->usage != kHIDUsage_GD_Joystick &&
   21.94 @@ -704,6 +659,14 @@
   21.95              continue;
   21.96          }
   21.97  
   21.98 +        /* We have to do some storage of the io_service_t for
   21.99 +         * SDL_HapticOpenFromJoystick */
  21.100 +        if (FFIsForceFeedback(ioHIDDeviceObject) == FF_OK) {
  21.101 +            device->ffservice = ioHIDDeviceObject;
  21.102 +        } else {
  21.103 +            device->ffservice = 0;
  21.104 +        }
  21.105 +
  21.106          /* Add device to the end of the list */
  21.107          if (lastDevice)
  21.108              lastDevice->pNext = device;
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/src/joystick/darwin/SDL_sysjoystick_c.h	Mon Aug 25 09:55:03 2008 +0000
    22.3 @@ -0,0 +1,87 @@
    22.4 +/*
    22.5 +	SDL - Simple DirectMedia Layer
    22.6 +    Copyright (C) 1997-2004 Sam Lantinga
    22.7 +
    22.8 +	This library is free software; you can redistribute it and/or
    22.9 +	modify it under the terms of the GNU Library General Public
   22.10 +	License as published by the Free Software Foundation; either
   22.11 +	version 2 of the License, or (at your option) any later version.
   22.12 +
   22.13 +	This library is distributed in the hope that it will be useful,
   22.14 +	but WITHOUT ANY WARRANTY; without even the implied warranty of
   22.15 +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   22.16 +	Library General Public License for more details.
   22.17 +
   22.18 +	You should have received a copy of the GNU Library General Public
   22.19 +	License along with this library; if not, write to the Free
   22.20 +	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22.21 +
   22.22 +	Sam Lantinga
   22.23 +	slouken@libsdl.org
   22.24 +*/
   22.25 +#include "SDL_config.h"
   22.26 +
   22.27 +#ifndef SDL_JOYSTICK_IOKIT_H
   22.28 +
   22.29 +
   22.30 +#if MAC_OS_X_VERSION_MIN_REQUIRED == 1030
   22.31 +#include "10.3.9-FIX/IOHIDLib.h"
   22.32 +#else
   22.33 +#include <IOKit/hid/IOHIDLib.h>
   22.34 +#endif
   22.35 +#include <IOKit/hid/IOHIDKeys.h>
   22.36 +
   22.37 +
   22.38 +struct recElement
   22.39 +{
   22.40 +    IOHIDElementCookie cookie;  /* unique value which identifies element, will NOT change */
   22.41 +    long min;                   /* reported min value possible */
   22.42 +    long max;                   /* reported max value possible */
   22.43 +#if 0
   22.44 +    /* TODO: maybe should handle the following stuff somehow? */
   22.45 +
   22.46 +    long scaledMin;             /* reported scaled min value possible */
   22.47 +    long scaledMax;             /* reported scaled max value possible */
   22.48 +    long size;                  /* size in bits of data return from element */
   22.49 +    Boolean relative;           /* are reports relative to last report (deltas) */
   22.50 +    Boolean wrapping;           /* does element wrap around (one value higher than max is min) */
   22.51 +    Boolean nonLinear;          /* are the values reported non-linear relative to element movement */
   22.52 +    Boolean preferredState;     /* does element have a preferred state (such as a button) */
   22.53 +    Boolean nullState;          /* does element have null state */
   22.54 +#endif                          /* 0 */
   22.55 +
   22.56 +    /* runtime variables used for auto-calibration */
   22.57 +    long minReport;             /* min returned value */
   22.58 +    long maxReport;             /* max returned value */
   22.59 +
   22.60 +    struct recElement *pNext;   /* next element in list */
   22.61 +};
   22.62 +typedef struct recElement recElement;
   22.63 +
   22.64 +struct joystick_hwdata
   22.65 +{
   22.66 +    io_service_t ffservice;     /* Interface for force feedback, 0 = no ff */
   22.67 +    IOHIDDeviceInterface **interface;   /* interface to device, NULL = no interface */
   22.68 +
   22.69 +    char product[256];          /* name of product */
   22.70 +    long usage;                 /* usage page from IOUSBHID Parser.h which defines general usage */
   22.71 +    long usagePage;             /* usage within above page from IOUSBHID Parser.h which defines specific usage */
   22.72 +
   22.73 +    long axes;                  /* number of axis (calculated, not reported by device) */
   22.74 +    long buttons;               /* number of buttons (calculated, not reported by device) */
   22.75 +    long hats;                  /* number of hat switches (calculated, not reported by device) */
   22.76 +    long elements;              /* number of total elements (shouldbe total of above) (calculated, not reported by device) */
   22.77 +
   22.78 +    recElement *firstAxis;
   22.79 +    recElement *firstButton;
   22.80 +    recElement *firstHat;
   22.81 +
   22.82 +    int removed;
   22.83 +    int uncentered;
   22.84 +
   22.85 +    struct joystick_hwdata *pNext;      /* next device */
   22.86 +};
   22.87 +typedef struct joystick_hwdata recDevice;
   22.88 +
   22.89 +
   22.90 +#endif /* SDL_JOYSTICK_IOKIT_H */
    23.1 --- a/src/joystick/linux/SDL_sysjoystick.c	Mon Aug 25 08:50:37 2008 +0000
    23.2 +++ b/src/joystick/linux/SDL_sysjoystick.c	Mon Aug 25 09:55:03 2008 +0000
    23.3 @@ -31,13 +31,11 @@
    23.4  #include <sys/ioctl.h>
    23.5  #include <limits.h>             /* For the definition of PATH_MAX */
    23.6  #include <linux/joystick.h>
    23.7 -#if SDL_INPUT_LINUXEV
    23.8 -#include <linux/input.h>
    23.9 -#endif
   23.10  
   23.11  #include "SDL_joystick.h"
   23.12  #include "../SDL_sysjoystick.h"
   23.13  #include "../SDL_joystick_c.h"
   23.14 +#include "SDL_sysjoystick_c.h"
   23.15  
   23.16  /* Special joystick configurations */
   23.17  static struct
   23.18 @@ -278,35 +276,6 @@
   23.19  } SDL_joylist[MAX_JOYSTICKS];
   23.20  
   23.21  
   23.22 -/* The private structure used to keep track of a joystick */
   23.23 -struct joystick_hwdata
   23.24 -{
   23.25 -    int fd;
   23.26 -    /* The current linux joystick driver maps hats to two axes */
   23.27 -    struct hwdata_hat
   23.28 -    {
   23.29 -        int axis[2];
   23.30 -    } *hats;
   23.31 -    /* The current linux joystick driver maps balls to two axes */
   23.32 -    struct hwdata_ball
   23.33 -    {
   23.34 -        int axis[2];
   23.35 -    } *balls;
   23.36 -
   23.37 -    /* Support for the Linux 2.4 unified input interface */
   23.38 -#if SDL_INPUT_LINUXEV
   23.39 -    SDL_bool is_hid;
   23.40 -    Uint8 key_map[KEY_MAX - BTN_MISC];
   23.41 -    Uint8 abs_map[ABS_MAX];
   23.42 -    struct axis_correct
   23.43 -    {
   23.44 -        int used;
   23.45 -        int coef[3];
   23.46 -    } abs_correct[ABS_MAX];
   23.47 -#endif
   23.48 -};
   23.49 -
   23.50 -
   23.51  #ifndef NO_LOGICAL_JOYSTICKS
   23.52  
   23.53  static int
   23.54 @@ -805,6 +774,7 @@
   23.55  SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
   23.56  {
   23.57      int fd;
   23.58 +    char *fname;
   23.59      SDL_logical_joydecl(int realindex);
   23.60      SDL_logical_joydecl(SDL_Joystick * realjoy = NULL);
   23.61  
   23.62 @@ -818,13 +788,16 @@
   23.63              return (-1);
   23.64  
   23.65          fd = realjoy->hwdata->fd;
   23.66 +        fname = realjoy->hwdata->fname;
   23.67  
   23.68      } else {
   23.69          fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0);
   23.70 +        fname = SDL_joylist[joystick->index].fname;
   23.71      }
   23.72      SDL_joylist[joystick->index].joy = joystick;
   23.73  #else
   23.74      fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0);
   23.75 +    fname = SDL_joylist[joystick->index].fname;
   23.76  #endif
   23.77  
   23.78      if (fd < 0) {
   23.79 @@ -840,6 +813,7 @@
   23.80      }
   23.81      SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
   23.82      joystick->hwdata->fd = fd;
   23.83 +    joystick->hwdata->fname = fname;
   23.84  
   23.85      /* Set the joystick to non-blocking read mode */
   23.86      fcntl(fd, F_SETFL, O_NONBLOCK);
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/src/joystick/linux/SDL_sysjoystick_c.h	Mon Aug 25 09:55:03 2008 +0000
    24.3 @@ -0,0 +1,55 @@
    24.4 +/*
    24.5 +    SDL - Simple DirectMedia Layer
    24.6 +    Copyright (C) 1997-2006 Sam Lantinga
    24.7 +
    24.8 +    This library is free software; you can redistribute it and/or
    24.9 +    modify it under the terms of the GNU Lesser General Public
   24.10 +    License as published by the Free Software Foundation; either
   24.11 +    version 2.1 of the License, or (at your option) any later version.
   24.12 +
   24.13 +    This library is distributed in the hope that it will be useful,
   24.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   24.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   24.16 +    Lesser General Public License for more details.
   24.17 +
   24.18 +    You should have received a copy of the GNU Lesser General Public
   24.19 +    License along with this library; if not, write to the Free Software
   24.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   24.21 +
   24.22 +    Sam Lantinga
   24.23 +    slouken@libsdl.org
   24.24 +*/
   24.25 +
   24.26 +#if SDL_INPUT_LINUXEV
   24.27 +#include <linux/input.h>
   24.28 +#endif
   24.29 +
   24.30 +/* The private structure used to keep track of a joystick */
   24.31 +struct joystick_hwdata
   24.32 +{
   24.33 +    int fd;
   24.34 +    char *fname;                /* Used in haptic subsystem */
   24.35 +
   24.36 +    /* The current linux joystick driver maps hats to two axes */
   24.37 +    struct hwdata_hat
   24.38 +    {
   24.39 +        int axis[2];
   24.40 +    } *hats;
   24.41 +    /* The current linux joystick driver maps balls to two axes */
   24.42 +    struct hwdata_ball
   24.43 +    {
   24.44 +        int axis[2];
   24.45 +    } *balls;
   24.46 +
   24.47 +    /* Support for the Linux 2.4 unified input interface */
   24.48 +#if SDL_INPUT_LINUXEV
   24.49 +    SDL_bool is_hid;
   24.50 +    Uint8 key_map[KEY_MAX - BTN_MISC];
   24.51 +    Uint8 abs_map[ABS_MAX];
   24.52 +    struct axis_correct
   24.53 +    {
   24.54 +        int used;
   24.55 +        int coef[3];
   24.56 +    } abs_correct[ABS_MAX];
   24.57 +#endif
   24.58 +};
    25.1 --- a/src/joystick/win32/SDL_dxjoystick.c	Mon Aug 25 08:50:37 2008 +0000
    25.2 +++ b/src/joystick/win32/SDL_dxjoystick.c	Mon Aug 25 09:55:03 2008 +0000
    25.3 @@ -38,20 +38,7 @@
    25.4  #include "SDL_joystick.h"
    25.5  #include "../SDL_sysjoystick.h"
    25.6  #include "../SDL_joystick_c.h"
    25.7 -
    25.8 -#define WIN32_LEAN_AND_MEAN
    25.9 -#include <windows.h>
   25.10 -
   25.11 -#define DIRECTINPUT_VERSION 0x0500
   25.12 -#include <dinput.h>
   25.13 -#ifdef _MSC_VER
   25.14 -    /* Used for the c_dfDIJoystick2 symbol (no imports are used) */
   25.15 -#   pragma comment (lib, "dinput.lib")
   25.16 -#endif
   25.17 -#include <dxerr9.h>             /* From DirectX SDK 9c */
   25.18 -#ifdef _MSC_VER
   25.19 -#   pragma comment (lib, "dxerr9.lib")
   25.20 -#endif
   25.21 +#include "SDL_dxjoystick_c.h"
   25.22  
   25.23  /* an ISO hack for VisualC++ */
   25.24  #ifdef _MSC_VER
   25.25 @@ -60,14 +47,12 @@
   25.26  
   25.27  #define INPUT_QSIZE	32      /* Buffer up to 32 input messages */
   25.28  #define MAX_JOYSTICKS	8
   25.29 -#define MAX_INPUTS	256     /* each joystick can have up to 256 inputs */
   25.30  #define AXIS_MIN	-32768  /* minimum value for axis coordinate */
   25.31  #define AXIS_MAX	32767   /* maximum value for axis coordinate */
   25.32  #define JOY_AXIS_THRESHOLD	(((AXIS_MAX)-(AXIS_MIN))/100)   /* 1% motion */
   25.33  
   25.34  /* external variables referenced. */
   25.35 -extern HINSTANCE SDL_Instance;
   25.36 -extern HWND SDL_Window;
   25.37 +extern HWND SDL_HelperWindow;
   25.38  
   25.39  
   25.40  /* local variables */
   25.41 @@ -95,39 +80,12 @@
   25.42                                           Uint8 button, Uint8 state);
   25.43  
   25.44  
   25.45 -/* local types */
   25.46 -typedef enum Type
   25.47 -{ BUTTON, AXIS, HAT } Type;
   25.48 -
   25.49 -typedef struct input_t
   25.50 -{
   25.51 -    /* DirectInput offset for this input type: */
   25.52 -    DWORD ofs;
   25.53 -
   25.54 -    /* Button, axis or hat: */
   25.55 -    Type type;
   25.56 -
   25.57 -    /* SDL input offset: */
   25.58 -    Uint8 num;
   25.59 -} input_t;
   25.60 -
   25.61 -/* The private structure used to keep track of a joystick */
   25.62 -struct joystick_hwdata
   25.63 -{
   25.64 -    LPDIRECTINPUTDEVICE2 InputDevice;
   25.65 -    DIDEVCAPS Capabilities;
   25.66 -    int buffered;
   25.67 -
   25.68 -    input_t Inputs[MAX_INPUTS];
   25.69 -    int NumInputs;
   25.70 -};
   25.71 -
   25.72  /* Convert a DirectInput return code to a text message */
   25.73  static void
   25.74  SetDIerror(const char *function, HRESULT code)
   25.75  {
   25.76      SDL_SetError("%s() [%s]: %s", function,
   25.77 -                 DXGetErrorString9(code), DXGetErrorDescription9(code));
   25.78 +                 DXGetErrorString(code), DXGetErrorDescription(code));
   25.79  }
   25.80  
   25.81  
   25.82 @@ -140,6 +98,7 @@
   25.83  SDL_SYS_JoystickInit(void)
   25.84  {
   25.85      HRESULT result;
   25.86 +    HINSTANCE instance;
   25.87  
   25.88      SYS_NumJoysticks = 0;
   25.89  
   25.90 @@ -158,8 +117,13 @@
   25.91      }
   25.92  
   25.93      /* Because we used CoCreateInstance, we need to Initialize it, first. */
   25.94 -    result =
   25.95 -        IDirectInput_Initialize(dinput, SDL_Instance, DIRECTINPUT_VERSION);
   25.96 +    instance = GetModuleHandle(NULL);
   25.97 +    if (instance == NULL) {
   25.98 +        SDL_SetError("GetModuleHandle() failed with error code %d.",
   25.99 +                     GetLastError());
  25.100 +        return (-1);
  25.101 +    }
  25.102 +    result = IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION);
  25.103  
  25.104      if (FAILED(result)) {
  25.105          SetDIerror("IDirectInput::Initialize", result);
  25.106 @@ -178,8 +142,8 @@
  25.107  static BOOL CALLBACK
  25.108  EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
  25.109  {
  25.110 -    memcpy(&SYS_Joystick[SYS_NumJoysticks], pdidInstance,
  25.111 -           sizeof(DIDEVICEINSTANCE));
  25.112 +    SDL_memcpy(&SYS_Joystick[SYS_NumJoysticks], pdidInstance,
  25.113 +               sizeof(DIDEVICEINSTANCE));
  25.114      SYS_NumJoysticks++;
  25.115  
  25.116      if (SYS_NumJoysticks >= MAX_JOYSTICKS)
  25.117 @@ -208,19 +172,19 @@
  25.118      LPDIRECTINPUTDEVICE device;
  25.119      DIPROPDWORD dipdw;
  25.120  
  25.121 -    ZeroMemory(&dipdw, sizeof(DIPROPDWORD));
  25.122 +    SDL_memset(&dipdw, 0, sizeof(DIPROPDWORD));
  25.123      dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  25.124      dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  25.125  
  25.126  
  25.127      /* allocate memory for system specific hardware data */
  25.128      joystick->hwdata =
  25.129 -        (struct joystick_hwdata *) malloc(sizeof(struct joystick_hwdata));
  25.130 +        (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata));
  25.131      if (joystick->hwdata == NULL) {
  25.132          SDL_OutOfMemory();
  25.133          return (-1);
  25.134      }
  25.135 -    ZeroMemory(joystick->hwdata, sizeof(struct joystick_hwdata));
  25.136 +    SDL_memset(joystick->hwdata, 0, sizeof(struct joystick_hwdata));
  25.137      joystick->hwdata->buffered = 1;
  25.138      joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
  25.139  
  25.140 @@ -250,7 +214,7 @@
  25.141       * though. */
  25.142      result =
  25.143          IDirectInputDevice2_SetCooperativeLevel(joystick->hwdata->
  25.144 -                                                InputDevice, SDL_Window,
  25.145 +                                                InputDevice, SDL_HelperWindow,
  25.146                                                  DISCL_EXCLUSIVE |
  25.147                                                  DISCL_BACKGROUND);
  25.148      if (FAILED(result)) {
  25.149 @@ -635,7 +599,7 @@
  25.150  
  25.151      if (joystick->hwdata != NULL) {
  25.152          /* free system specific hardware data */
  25.153 -        free(joystick->hwdata);
  25.154 +        SDL_free(joystick->hwdata);
  25.155      }
  25.156  }
  25.157  
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/joystick/win32/SDL_dxjoystick_c.h	Mon Aug 25 09:55:03 2008 +0000
    26.3 @@ -0,0 +1,81 @@
    26.4 +/*
    26.5 +    SDL - Simple DirectMedia Layer
    26.6 +    Copyright (C) 1997-2006 Sam Lantinga
    26.7 +
    26.8 +    This library is free software; you can redistribute it and/or
    26.9 +    modify it under the terms of the GNU Lesser General Public
   26.10 +    License as published by the Free Software Foundation; either
   26.11 +    version 2.1 of the License, or (at your option) any later version.
   26.12 +
   26.13 +    This library is distributed in the hope that it will be useful,
   26.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
   26.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   26.16 +    Lesser General Public License for more details.
   26.17 +
   26.18 +    You should have received a copy of the GNU Lesser General Public
   26.19 +    License along with this library; if not, write to the Free Software
   26.20 +    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   26.21 +
   26.22 +    Sam Lantinga
   26.23 +    slouken@libsdl.org
   26.24 +*/
   26.25 +#include "SDL_config.h"
   26.26 +
   26.27 +#ifndef SDL_JOYSTICK_DINPUT_H
   26.28 +
   26.29 +/* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de
   26.30 + * A. Formiga's WINMM driver. 
   26.31 + *
   26.32 + * Hats and sliders are completely untested; the app I'm writing this for mostly
   26.33 + * doesn't use them and I don't own any joysticks with them. 
   26.34 + *
   26.35 + * We don't bother to use event notification here.  It doesn't seem to work
   26.36 + * with polled devices, and it's fine to call IDirectInputDevice2_GetDeviceData and
   26.37 + * let it return 0 events. */
   26.38 +
   26.39 +#define WIN32_LEAN_AND_MEAN
   26.40 +#include <windows.h>
   26.41 +
   26.42 +#define DIRECTINPUT_VERSION 0x0700      /* Need version 7 for force feedback. */
   26.43 +#include <dinput.h>
   26.44 +#ifdef _MSC_VER
   26.45 +    /* Used for the c_dfDIJoystick2 symbol (no imports are used) */
   26.46 +#   pragma comment (lib, "dinput.lib")
   26.47 +#endif
   26.48 +#include <dxerr.h>
   26.49 +#ifdef _MSC_VER
   26.50 +#   pragma comment (lib, "dxerr.lib")
   26.51 +#endif
   26.52 +
   26.53 +
   26.54 +#define MAX_INPUTS	256     /* each joystick can have up to 256 inputs */
   26.55 +
   26.56 +
   26.57 +/* local types */
   26.58 +typedef enum Type
   26.59 +{ BUTTON, AXIS, HAT } Type;
   26.60 +
   26.61 +typedef struct input_t
   26.62 +{
   26.63 +    /* DirectInput offset for this input type: */
   26.64 +    DWORD ofs;
   26.65 +
   26.66 +    /* Button, axis or hat: */
   26.67 +    Type type;
   26.68 +
   26.69 +    /* SDL input offset: */
   26.70 +    Uint8 num;
   26.71 +} input_t;
   26.72 +
   26.73 +/* The private structure used to keep track of a joystick */
   26.74 +struct joystick_hwdata
   26.75 +{
   26.76 +    LPDIRECTINPUTDEVICE2 InputDevice;
   26.77 +    DIDEVCAPS Capabilities;
   26.78 +    int buffered;
   26.79 +
   26.80 +    input_t Inputs[MAX_INPUTS];
   26.81 +    int NumInputs;
   26.82 +};
   26.83 +
   26.84 +#endif /* SDL_JOYSTICK_DINPUT_H */
    27.1 --- a/src/video/win32/SDL_win32window.c	Mon Aug 25 08:50:37 2008 +0000
    27.2 +++ b/src/video/win32/SDL_win32window.c	Mon Aug 25 09:55:03 2008 +0000
    27.3 @@ -47,6 +47,12 @@
    27.4  extern HCTX *g_hCtx;            /* the table of tablet event contexts, each windows has to have it's own tablet context */
    27.5  int highestId = 0;              /* the highest id of the tablet context */
    27.6  
    27.7 +/* Fake window to help with DirectInput events. */
    27.8 +HWND SDL_HelperWindow = NULL;
    27.9 +static const char *SDL_HelperWindowClassName = "SDLHelperWindowInputCatcher";
   27.10 +static const char *SDL_HelperWindowName = "SDLHelperWindowInputMsgWindow";
   27.11 +static ATOM SDL_HelperWindowClass = 0;
   27.12 +
   27.13  static int
   27.14  SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created)
   27.15  {
   27.16 @@ -470,4 +476,66 @@
   27.17      }
   27.18  }
   27.19  
   27.20 +
   27.21 +/*
   27.22 + * Creates a HelperWindow used for DirectInput events.
   27.23 + */
   27.24 +int
   27.25 +SDL_HelperWindowCreate(void)
   27.26 +{
   27.27 +    HINSTANCE hInstance = GetModuleHandleA(NULL);
   27.28 +    WNDCLASSEX wce;
   27.29 +
   27.30 +    /* Create the class. */
   27.31 +    SDL_memset(&wce, 0, sizeof(wce));
   27.32 +    wce.cbSize = sizeof(WNDCLASSEX);
   27.33 +    wce.lpfnWndProc = DefWindowProcA;
   27.34 +    wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
   27.35 +    wce.hInstance = hInstance;
   27.36 +
   27.37 +    /* Register the class. */
   27.38 +    SDL_HelperWindowClass = RegisterClassExA(&wce);
   27.39 +    if (SDL_HelperWindowClass == 0) {
   27.40 +        SDL_SetError("Unable to create Helper Window Class: error %d.",
   27.41 +                     GetLastError());
   27.42 +        return -1;
   27.43 +    }
   27.44 +
   27.45 +    /* Create the window. */
   27.46 +    SDL_HelperWindow = CreateWindowExA(0, SDL_HelperWindowClassName,
   27.47 +                                       SDL_HelperWindowName,
   27.48 +                                       WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
   27.49 +                                       CW_USEDEFAULT, CW_USEDEFAULT,
   27.50 +                                       CW_USEDEFAULT, HWND_MESSAGE, NULL,
   27.51 +                                       hInstance, NULL);
   27.52 +    if (SDL_HelperWindow == NULL) {
   27.53 +        SDL_SetError("Unable to create Helper Window: error %d.",
   27.54 +                     GetLastError());
   27.55 +        return -1;
   27.56 +    }
   27.57 +
   27.58 +    return 0;
   27.59 +}
   27.60 +
   27.61 +
   27.62 +/*
   27.63 + * Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
   27.64 + */
   27.65 +void
   27.66 +SDL_HelperWindowDestroy(void)
   27.67 +{
   27.68 +    /* Destroy the window. */
   27.69 +    if (SDL_HelperWindow) {
   27.70 +        DestroyWindow(SDL_HelperWindow);
   27.71 +        SDL_HelperWindow = NULL;
   27.72 +    }
   27.73 +
   27.74 +    /* Unregister the class. */
   27.75 +    if (SDL_HelperWindowClass) {
   27.76 +        UnregisterClassA(SDL_HelperWindowClassName, GetModuleHandleA(NULL));
   27.77 +        SDL_HelperWindowClass = 0;
   27.78 +    }
   27.79 +}
   27.80 +
   27.81 +
   27.82  /* vi: set ts=4 sw=4 expandtab: */
    28.1 --- a/test/Makefile.in	Mon Aug 25 08:50:37 2008 +0000
    28.2 +++ b/test/Makefile.in	Mon Aug 25 09:55:03 2008 +0000
    28.3 @@ -7,7 +7,7 @@
    28.4  CFLAGS  = @CFLAGS@
    28.5  LIBS	= @LIBS@
    28.6  
    28.7 -TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testaudioinfo$(EXE) testmultiaudio$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcdrom$(EXE) testcursor$(EXE) testdyngl$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE) testloadso$(EXE)
    28.8 +TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testaudioinfo$(EXE) testmultiaudio$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcdrom$(EXE) testcursor$(EXE) testdyngl$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE) testloadso$(EXE) testhaptic$(EXE)
    28.9  
   28.10  all: Makefile $(TARGETS)
   28.11  
   28.12 @@ -125,6 +125,9 @@
   28.13  testloadso$(EXE): $(srcdir)/testloadso.c
   28.14  	$(CC) -o $@ $? $(CFLAGS) $(LIBS)
   28.15  
   28.16 +testhaptic$(EXE): $(srcdir)/testhaptic.c
   28.17 +	$(CC) -o $@ $? $(CFLAGS) $(LIBS)
   28.18 +
   28.19  
   28.20  clean:
   28.21  	rm -f $(TARGETS)
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/test/testhaptic.c	Mon Aug 25 09:55:03 2008 +0000
    29.3 @@ -0,0 +1,266 @@
    29.4 +/*
    29.5 +Copyright (c) 2008, Edgar Simo Serra
    29.6 +All rights reserved.
    29.7 +
    29.8 +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
    29.9 +
   29.10 +    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
   29.11 +    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
   29.12 +    * Neither the name of the Simple Directmedia Layer (SDL) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
   29.13 +
   29.14 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29.15 +*/
   29.16 +
   29.17 +/*
   29.18 + * includes
   29.19 + */
   29.20 +#include "SDL.h"
   29.21 +#include "SDL_haptic.h"
   29.22 +
   29.23 +#include <stdio.h>              /* printf */
   29.24 +#include <string.h>             /* strstr */
   29.25 +
   29.26 +
   29.27 +
   29.28 +static SDL_Haptic *haptic;
   29.29 +
   29.30 +
   29.31 +/*
   29.32 + * prototypes
   29.33 + */
   29.34 +static void abort_execution(void);
   29.35 +static void HapticPrintSupported(SDL_Haptic * haptic);
   29.36 +
   29.37 +
   29.38 +/**
   29.39 + * @brief The entry point of this force feedback demo.
   29.40 + * @param[in] argc Number of arguments.
   29.41 + * @param[in] argv Array of argc arguments.
   29.42 + */
   29.43 +int
   29.44 +main(int argc, char **argv)
   29.45 +{
   29.46 +    int i;
   29.47 +    char *name;
   29.48 +    SDL_HapticEffect efx[5];
   29.49 +    int id[5];
   29.50 +    int nefx;
   29.51 +    unsigned int supported;
   29.52 +
   29.53 +    name = NULL;
   29.54 +    if (argc > 1) {
   29.55 +        name = argv[1];
   29.56 +        if ((strcmp(name, "--help") == 0) || (strcmp(name, "-h") == 0)) {
   29.57 +            printf("USAGE: %s [device name]\n"
   29.58 +                   "If device name is specified, it will try to find a device whose name\n"
   29.59 +                   "contains device name for testing.\n", argv[0]);
   29.60 +            return 0;
   29.61 +        }
   29.62 +    }
   29.63 +
   29.64 +    /* Initialize the force feedbackness */
   29.65 +    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK |
   29.66 +             SDL_INIT_HAPTIC);
   29.67 +    printf("%d Haptic devices detected.\n", SDL_NumHaptics());
   29.68 +    if (SDL_NumHaptics() > 0) {
   29.69 +        /* We'll just use the first force feedback device found */
   29.70 +        if (name == NULL) {
   29.71 +            i = 0;
   29.72 +        }
   29.73 +        /* Try to find matching device */
   29.74 +        else {
   29.75 +            for (i = 0; i < SDL_NumHaptics(); i++) {
   29.76 +                if (strstr(SDL_HapticName(i), name) != NULL)
   29.77 +                    break;
   29.78 +            }
   29.79 +
   29.80 +            if (i >= SDL_NumHaptics()) {
   29.81 +                printf("Unable to find device matching '%s', aborting.\n",
   29.82 +                       name);
   29.83 +                return 1;
   29.84 +            }
   29.85 +        }
   29.86 +
   29.87 +        haptic = SDL_HapticOpen(i);
   29.88 +        if (haptic == NULL) {
   29.89 +            perror("Unable to create the haptic device");
   29.90 +            return 1;
   29.91 +        }
   29.92 +        printf("Device: %s\n", SDL_HapticName(i));
   29.93 +        HapticPrintSupported(haptic);
   29.94 +    } else {
   29.95 +        printf("No Haptic devices found!\n");
   29.96 +        return 1;
   29.97 +    }
   29.98 +
   29.99 +    /* We only want force feedback errors. */
  29.100 +    SDL_ClearError();
  29.101 +
  29.102 +    /* Create effects. */
  29.103 +    memset(&efx, 0, sizeof(efx));
  29.104 +    nefx = 0;
  29.105 +    supported = SDL_HapticQuery(haptic);
  29.106 +
  29.107 +    printf("\nUploading effects\n");
  29.108 +    /* First we'll try a SINE effect. */
  29.109 +    if (supported & SDL_HAPTIC_SINE) {
  29.110 +        printf("   effect %d: Sine Wave\n", nefx);
  29.111 +        efx[nefx].type = SDL_HAPTIC_SINE;
  29.112 +        efx[nefx].periodic.period = 1000;
  29.113 +        efx[nefx].periodic.magnitude = 0x4000;
  29.114 +        efx[nefx].periodic.length = 5000;
  29.115 +        efx[nefx].periodic.attack_length = 1000;
  29.116 +        efx[nefx].periodic.fade_length = 1000;
  29.117 +        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
  29.118 +        if (id[nefx] < 0) {
  29.119 +            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
  29.120 +            abort_execution();
  29.121 +        }
  29.122 +        nefx++;
  29.123 +    }
  29.124 +    /* Now we'll try a SAWTOOTHUP */
  29.125 +    if (supported & SDL_HAPTIC_SAWTOOTHUP) {
  29.126 +        printf("   effect %d: Sawtooth Up\n", nefx);
  29.127 +        efx[nefx].type = SDL_HAPTIC_SQUARE;
  29.128 +        efx[nefx].periodic.period = 500;
  29.129 +        efx[nefx].periodic.magnitude = 0x5000;
  29.130 +        efx[nefx].periodic.length = 5000;
  29.131 +        efx[nefx].periodic.attack_length = 1000;
  29.132 +        efx[nefx].periodic.fade_length = 1000;
  29.133 +        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
  29.134 +        if (id[nefx] < 0) {
  29.135 +            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
  29.136 +            abort_execution();
  29.137 +        }
  29.138 +        nefx++;
  29.139 +    }
  29.140 +    /* Now the classical constant effect. */
  29.141 +    if (supported & SDL_HAPTIC_CONSTANT) {
  29.142 +        printf("   effect %d: Constant Force\n", nefx);
  29.143 +        efx[nefx].type = SDL_HAPTIC_CONSTANT;
  29.144 +        efx[nefx].constant.direction.type = SDL_HAPTIC_POLAR;
  29.145 +        efx[nefx].constant.direction.dir[0] = 20000;    /* Force comes from the south-west. */
  29.146 +        efx[nefx].constant.length = 5000;
  29.147 +        efx[nefx].constant.level = 0x6000;
  29.148 +        efx[nefx].constant.attack_length = 1000;
  29.149 +        efx[nefx].constant.fade_length = 1000;
  29.150 +        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
  29.151 +        if (id[nefx] < 0) {
  29.152 +            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
  29.153 +            abort_execution();
  29.154 +        }
  29.155 +        nefx++;
  29.156 +    }
  29.157 +    /* The cute spring effect. */
  29.158 +    if (supported & SDL_HAPTIC_SPRING) {
  29.159 +        printf("   effect %d: Condition Spring\n", nefx);
  29.160 +        efx[nefx].type = SDL_HAPTIC_SPRING;
  29.161 +        efx[nefx].condition.length = 5000;
  29.162 +        for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
  29.163 +            efx[nefx].condition.right_sat[i] = 0x7FFF;
  29.164 +            efx[nefx].condition.left_sat[i] = 0x7FFF;
  29.165 +            efx[nefx].condition.right_coeff[i] = 0x2000;
  29.166 +            efx[nefx].condition.left_coeff[i] = 0x2000;
  29.167 +            efx[nefx].condition.center[i] = 0x1000;     /* Displace the center for it to move. */
  29.168 +        }
  29.169 +        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
  29.170 +        if (id[nefx] < 0) {
  29.171 +            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
  29.172 +            abort_execution();
  29.173 +        }
  29.174 +        nefx++;
  29.175 +    }
  29.176 +    /* The pretty awesome inertia effect. */
  29.177 +    if (supported & SDL_HAPTIC_INERTIA) {
  29.178 +        printf("   effect %d: Condition Inertia\n", nefx);
  29.179 +        efx[nefx].type = SDL_HAPTIC_SPRING;
  29.180 +        efx[nefx].condition.length = 5000;
  29.181 +        for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
  29.182 +            efx[nefx].condition.right_sat[i] = 0x7FFF;
  29.183 +            efx[nefx].condition.left_sat[i] = 0x7FFF;
  29.184 +            efx[nefx].condition.right_coeff[i] = 0x2000;
  29.185 +            efx[nefx].condition.left_coeff[i] = 0x2000;
  29.186 +        }
  29.187 +        id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
  29.188 +        if (id[nefx] < 0) {
  29.189 +            printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
  29.190 +            abort_execution();
  29.191 +        }
  29.192 +        nefx++;
  29.193 +    }
  29.194 +
  29.195 +    printf
  29.196 +        ("\nNow playing effects for 5 seconds each with 1 second delay between\n");
  29.197 +    for (i = 0; i < nefx; i++) {
  29.198 +        printf("   Playing effect %d\n", i);
  29.199 +        SDL_HapticRunEffect(haptic, id[i], 1);
  29.200 +        SDL_Delay(6000);        /* Effects only have length 5000 */
  29.201 +    }
  29.202 +
  29.203 +    /* Quit */
  29.204 +    if (haptic != NULL)
  29.205 +        SDL_HapticClose(haptic);
  29.206 +    SDL_Quit();
  29.207 +
  29.208 +    return 0;
  29.209 +}
  29.210 +
  29.211 +
  29.212 +/*
  29.213 + * Cleans up a bit.
  29.214 + */
  29.215 +static void
  29.216 +abort_execution(void)
  29.217 +{
  29.218 +    printf("\nAborting program execution.\n");
  29.219 +
  29.220 +    SDL_HapticClose(haptic);
  29.221 +    SDL_Quit();
  29.222 +
  29.223 +    exit(1);
  29.224 +}
  29.225 +
  29.226 +
  29.227 +/*
  29.228 + * Displays information about the haptic device.
  29.229 + */
  29.230 +static void
  29.231 +HapticPrintSupported(SDL_Haptic * haptic)
  29.232 +{
  29.233 +    unsigned int supported;
  29.234 +
  29.235 +    supported = SDL_HapticQuery(haptic);
  29.236 +    printf("   Supported effects [%d effects, %d playing]:\n",
  29.237 +           SDL_HapticNumEffects(haptic), SDL_HapticNumEffectsPlaying(haptic));
  29.238 +    if (supported & SDL_HAPTIC_CONSTANT)
  29.239 +        printf("      constant\n");
  29.240 +    if (supported & SDL_HAPTIC_SINE)
  29.241 +        printf("      sine\n");
  29.242 +    if (supported & SDL_HAPTIC_SQUARE)
  29.243 +        printf("      square\n");
  29.244 +    if (supported & SDL_HAPTIC_TRIANGLE)
  29.245 +        printf("      triangle\n");
  29.246 +    if (supported & SDL_HAPTIC_SAWTOOTHUP)
  29.247 +        printf("      sawtoothup\n");
  29.248 +    if (supported & SDL_HAPTIC_SAWTOOTHDOWN)
  29.249 +        printf("      sawtoothdown\n");
  29.250 +    if (supported & SDL_HAPTIC_RAMP)
  29.251 +        printf("      ramp\n");
  29.252 +    if (supported & SDL_HAPTIC_FRICTION)
  29.253 +        printf("      friction\n");
  29.254 +    if (supported & SDL_HAPTIC_SPRING)
  29.255 +        printf("      spring\n");
  29.256 +    if (supported & SDL_HAPTIC_DAMPER)
  29.257 +        printf("      damper\n");
  29.258 +    if (supported & SDL_HAPTIC_INERTIA)
  29.259 +        printf("      intertia\n");
  29.260 +    if (supported & SDL_HAPTIC_CUSTOM)
  29.261 +        printf("      custom\n");
  29.262 +    printf("   Supported capabilities:\n");
  29.263 +    if (supported & SDL_HAPTIC_GAIN)
  29.264 +        printf("      gain\n");
  29.265 +    if (supported & SDL_HAPTIC_AUTOCENTER)
  29.266 +        printf("      autocenter\n");
  29.267 +    if (supported & SDL_HAPTIC_STATUS)
  29.268 +        printf("      status\n");
  29.269 +}