From 7ed3ac26ecd67f9a79efe740a08a8ecf2fb395b7 Mon Sep 17 00:00:00 2001 From: mcarans Date: Sun, 10 Aug 2025 17:19:00 +1200 Subject: [PATCH 1/4] Oolite changes --- Makefile.in | 2 +- Makefile.minimal | 2 + configure.ac | 44 +- include/SDL.h | 1 + include/SDL_config.h.in | 5 + include/SDL_config_dreamcast.h | 1 + include/SDL_config_macosx.h | 2 + include/SDL_config_minimal.h | 3 + include/SDL_config_os2.h | 1 + include/SDL_config_win32.h | 2 + include/SDL_haptic.h | 1136 +++++++++++++++++++++++ include/SDL_video.h | 1 + src/SDL.c | 40 + src/SDL_HelperWindow.c | 154 +++ src/events/SDL_resize.c | 5 + src/joystick/SDL_joystick.c | 22 +- src/joystick/SDL_joystick_c.h | 3 + src/joystick/darwin/SDL_sysjoystick.c | 75 +- src/joystick/darwin/SDL_sysjoystick_c.h | 87 ++ src/joystick/linux/SDL_sysjoystick.c | 37 +- src/joystick/linux/SDL_sysjoystick_c.h | 55 ++ src/joystick/win32/SDL_dxjoystick_c.h | 81 ++ src/video/SDL_sysvideo.h | 1 + src/video/SDL_video.c | 4 + src/video/wincommon/SDL_wingl.c | 36 +- src/video/wincommon/SDL_wingl_c.h | 1 + test/Makefile.in | 5 +- test/testhaptic.c | 247 +++++ 28 files changed, 1946 insertions(+), 107 deletions(-) create mode 100644 include/SDL_haptic.h create mode 100644 src/SDL_HelperWindow.c create mode 100644 src/joystick/darwin/SDL_sysjoystick_c.h create mode 100644 src/joystick/linux/SDL_sysjoystick_c.h create mode 100644 src/joystick/win32/SDL_dxjoystick_c.h create mode 100644 test/testhaptic.c diff --git a/Makefile.in b/Makefile.in index f3452ab96..bcf58aeac 100644 --- a/Makefile.in +++ b/Makefile.in @@ -45,7 +45,7 @@ SDLMAIN_LDFLAGS = @SDLMAIN_LDFLAGS@ SRC_DIST = acinclude autogen.sh BUGS build-scripts configure configure.ac COPYING CREDITS CWprojects.sea.bin docs docs.html include INSTALL Makefile.dc Makefile.minimal Makefile.in MPWmake.sea.bin README* sdl-config.in sdl.m4 sdl.pc.in SDL.qpg.in SDL.spec.in src test TODO VisualCE VisualC.html VisualC os2 Makefile.os2 Watcom-Win32.zip symbian.zip WhatsNew Xcode GEN_DIST = SDL.spec -HDRS = SDL.h SDL_active.h SDL_audio.h SDL_byteorder.h SDL_cdrom.h SDL_cpuinfo.h SDL_endian.h SDL_error.h SDL_events.h SDL_getenv.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_platform.h SDL_quit.h SDL_rwops.h SDL_stdinc.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 +HDRS = SDL.h SDL_active.h SDL_audio.h SDL_byteorder.h SDL_cdrom.h SDL_cpuinfo.h SDL_endian.h SDL_error.h SDL_events.h SDL_getenv.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_platform.h SDL_quit.h SDL_rwops.h SDL_stdinc.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 LT_AGE = @LT_AGE@ LT_CURRENT = @LT_CURRENT@ diff --git a/Makefile.minimal b/Makefile.minimal index 827621c3f..c8057894a 100644 --- a/Makefile.minimal +++ b/Makefile.minimal @@ -15,6 +15,7 @@ SOURCES = \ src/events/*.c \ src/file/*.c \ src/joystick/*.c \ + src/haptic/*.c \ src/stdlib/*.c \ src/thread/*.c \ src/timer/*.c \ @@ -22,6 +23,7 @@ SOURCES = \ src/audio/dummy/*.c \ src/video/dummy/*.c \ src/joystick/dummy/*.c \ + src/haptic/dummy/*.c \ src/cdrom/dummy/*.c \ src/thread/generic/*.c \ src/timer/dummy/*.c \ diff --git a/configure.ac b/configure.ac index ec5b531af..9c56f81f7 100644 --- a/configure.ac +++ b/configure.ac @@ -263,6 +263,14 @@ if test x$enable_joystick != xyes; then else SOURCES="$SOURCES $srcdir/src/joystick/*.c" fi +AC_ARG_ENABLE(haptic, +AC_HELP_STRING([--enable-haptic], [Enable the haptic (force feedback) subsystem [[default=yes]]]), + , enable_haptic=yes) +if test x$enable_haptic != xyes; then + AC_DEFINE(SDL_HAPTIC_DISABLED) +else + SOURCES="$SOURCES $srcdir/src/haptic/*.c" +fi AC_ARG_ENABLE(cdrom, [AS_HELP_STRING([--enable-cdrom], [Enable the cdrom subsystem [default=yes]])], , enable_cdrom=yes) @@ -2139,8 +2147,8 @@ CheckDIRECTX() have_directx=no AC_CHECK_HEADER(ddraw.h, have_ddraw=yes) AC_CHECK_HEADER(dsound.h, have_dsound=yes) - AC_CHECK_HEADER(dinput.h, use_dinput=yes) - if test x$have_ddraw = xyes -a x$have_dsound = xyes -a x$use_dinput = xyes; then + AC_CHECK_HEADER(dinput.h, have_dinput=yes) + if test x$have_ddraw = xyes -a x$have_dsound = xyes -a x$have_dinput = xyes; then have_directx=yes fi if test x$enable_video = xyes -a x$have_directx = xyes; then @@ -2481,6 +2489,18 @@ case "$host" in ;; esac fi + # Set up files for the haptic library + if test x$enable_haptic = xyes; then + if test x$use_input_events = xyes; then + case $ARCH in + linux) + AC_DEFINE(SDL_HAPTIC_LINUX) + SOURCES="$SOURCES $srcdir/src/haptic/linux/*.c" + have_haptic=yes + ;; + esac + fi + fi # Set up files for the cdrom library if test x$enable_cdrom = xyes; then case $ARCH in @@ -2645,6 +2665,13 @@ case "$host" in SOURCES="$SOURCES $srcdir/src/joystick/win32/*.c" have_joystick=yes fi + if test x$enable_haptic = xyes; then + if test x$have_dinput = xyes; then + AC_DEFINE(SDL_HAPTIC_DINPUT) + SOURCES="$SOURCES $srcdir/src/haptic/win32/SDL_syshaptic.c" + have_haptic=yes + fi + fi # Set up files for the cdrom library if test x$enable_cdrom = xyes; then AC_DEFINE(SDL_CDROM_WIN32) @@ -2706,6 +2733,13 @@ case "$host" in SOURCES="$SOURCES $srcdir/src/joystick/beos/*.cc" have_joystick=yes fi + # Set up files for the haptic library + if test x$enable_haptic = xyes; then + AC_DEFINE(SDL_HAPTIC_IOKIT) + SOURCES="$SOURCES $srcdir/src/haptic/darwin/*.c" + have_haptic=yes + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,ForceFeedback" + fi # Set up files for the cdrom library if test x$enable_cdrom = xyes; then AC_DEFINE(SDL_CDROM_BEOS) @@ -2996,6 +3030,12 @@ if test x$enable_joystick = xyes; then SOURCES="$SOURCES $srcdir/src/joystick/dummy/*.c" fi fi +if test x$have_haptic != xyes; then + if test x$enable_haptic = xyes; then + AC_DEFINE(SDL_HAPTIC_DISABLED) + fi + SOURCES="$SOURCES $srcdir/src/haptic/dummy/*.c" +fi if test x$have_cdrom != xyes; then if test x$enable_cdrom = xyes; then AC_DEFINE(SDL_CDROM_DISABLED) diff --git a/include/SDL.h b/include/SDL.h index 6087b7cdd..a9e477f4b 100644 --- a/include/SDL.h +++ b/include/SDL.h @@ -63,6 +63,7 @@ extern "C" { #define SDL_INIT_VIDEO 0x00000020 #define SDL_INIT_CDROM 0x00000100 #define SDL_INIT_JOYSTICK 0x00000200 +#define SDL_INIT_HAPTIC 0x00001000 #define SDL_INIT_NOPARACHUTE 0x00100000 /**< Don't catch fatal signals */ #define SDL_INIT_EVENTTHREAD 0x01000000 /**< Not supported on all OS's */ #define SDL_INIT_EVERYTHING 0x0000FFFF diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 7453e1add..78dca1b7e 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -156,6 +156,7 @@ #undef SDL_EVENTS_DISABLED #undef SDL_FILE_DISABLED #undef SDL_JOYSTICK_DISABLED +#undef SDL_HAPTIC_DISABLED #undef SDL_LOADSO_DISABLED #undef SDL_THREADS_DISABLED #undef SDL_TIMERS_DISABLED @@ -224,6 +225,10 @@ #undef SDL_JOYSTICK_WINMM #undef SDL_JOYSTICK_USBHID #undef SDL_HAVE_MACHINE_JOYSTICK_H +#undef SDL_HAPTIC_DUMMY +#undef SDL_HAPTIC_LINUX +#undef SDL_HAPTIC_IOKIT +#undef SDL_HAPTIC_DINPUT /* Enable various shared object loading systems */ #undef SDL_LOADSO_BEOS diff --git a/include/SDL_config_dreamcast.h b/include/SDL_config_dreamcast.h index fb03098e7..46bf51abd 100644 --- a/include/SDL_config_dreamcast.h +++ b/include/SDL_config_dreamcast.h @@ -89,6 +89,7 @@ typedef unsigned long uintptr_t; /* Enable various input drivers */ #define SDL_JOYSTICK_DC 1 +#define SDL_HAPTIC_DUMMY 1 /* Enable various shared object loading systems */ #define SDL_LOADSO_DUMMY 1 diff --git a/include/SDL_config_macosx.h b/include/SDL_config_macosx.h index c05712ee4..5862efd03 100644 --- a/include/SDL_config_macosx.h +++ b/include/SDL_config_macosx.h @@ -98,6 +98,7 @@ /* Enable various input drivers */ #define SDL_JOYSTICK_IOKIT 1 +#define SDL_HAPTIC_IOKIT 1 /* Enable various shared object loading systems */ #ifdef __ppc__ @@ -138,6 +139,7 @@ /* Enable OpenGL support */ #define SDL_VIDEO_OPENGL 1 #define SDL_VIDEO_OPENGL_GLX 1 +#define SDL_VIDEO_RENDER_OGL 1 /* Disable screensaver */ #define SDL_VIDEO_DISABLE_SCREENSAVER 1 diff --git a/include/SDL_config_minimal.h b/include/SDL_config_minimal.h index d10db7c62..d275a2069 100644 --- a/include/SDL_config_minimal.h +++ b/include/SDL_config_minimal.h @@ -47,6 +47,9 @@ typedef unsigned long uintptr_t; /* Enable the stub joystick driver (src/joystick/dummy/\*.c) */ #define SDL_JOYSTICK_DISABLED 1 +/* Enable the stub haptic driver (src/haptic/dummy/\*.c) */ +#define SDL_HAPTIC_DUMMY 1 + /* Enable the stub shared object loader (src/loadso/dummy/\*.c) */ #define SDL_LOADSO_DISABLED 1 diff --git a/include/SDL_config_os2.h b/include/SDL_config_os2.h index 56eb7872a..2da03eb3f 100644 --- a/include/SDL_config_os2.h +++ b/include/SDL_config_os2.h @@ -107,6 +107,7 @@ /* Enable various input drivers */ #define SDL_JOYSTICK_OS2 1 +#define SDL_HAPTIC_DUMMY 1 /* Enable various shared object loading systems */ #define SDL_LOADSO_OS2 1 diff --git a/include/SDL_config_win32.h b/include/SDL_config_win32.h index 6d2ae2d67..ffc007dd2 100644 --- a/include/SDL_config_win32.h +++ b/include/SDL_config_win32.h @@ -149,8 +149,10 @@ typedef unsigned int uintptr_t; /* Enable various input drivers */ #ifdef _WIN32_WCE #define SDL_JOYSTICK_DISABLED 1 +#define SDL_HAPTIC_DUMMY 1 #else #define SDL_JOYSTICK_WINMM 1 +#define SDL_HAPTIC_DINPUT 1 #endif /* Enable various shared object loading systems */ diff --git a/include/SDL_haptic.h b/include/SDL_haptic.h new file mode 100644 index 000000000..c70a99ed1 --- /dev/null +++ b/include/SDL_haptic.h @@ -0,0 +1,1136 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 2008 Edgar Simo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +/** + * \file SDL_haptic.h + * + * \brief The SDL Haptic subsystem allows you to control haptic (force feedback) + * devices. + * + * The basic usage is as follows: + * - Initialize the Subsystem (SDL_INIT_HAPTIC). + * - Open a Haptic Device. + * - SDL_HapticOpen(...) to open from index. + * - SDL_HapticOpenFromJoystick(...) to open from an existing joystick. + * - Create an effect (SDL_HapticEffect). + * - Upload the effect with SDL_HapticNewEffect(...). + * - Run the effect with SDL_HapticRunEffect(...). + * - (optional) Free the effect with SDL_HapticDestroyEffect(...). + * - Close the haptic device with SDL_HapticClose(...). + * + * Example: + * + * \code + * int test_haptic( SDL_Joystick * joystick ) { + * SDL_Haptic *haptic; + * SDL_HapticEffect effect; + * int effect_id; + * + * // Open the device + * haptic = SDL_HapticOpenFromJoystick( joystick ); + * if (haptic == NULL) return -1; // Most likely joystick isn't haptic + * + * // See if it can do sine waves + * if ((SDL_HapticQuery(haptic) & SDL_HAPTIC_SINE)==0) { + * SDL_HapticClose(haptic); // No sine effect + * return -1; + * } + * + * // Create the effect + * memset( &effect, 0, sizeof(SDL_HapticEffect) ); // 0 is safe default + * effect.type = SDL_HAPTIC_SINE; + * effect.periodic.direction.type = SDL_HAPTIC_POLAR; // Polar coordinates + * effect.periodic.direction.dir[0] = 18000; // Force comes from south + * effect.periodic.period = 1000; // 1000 ms + * effect.periodic.magnitude = 20000; // 20000/32767 strength + * effect.periodic.length = 5000; // 5 seconds long + * effect.periodic.attack_length = 1000; // Takes 1 second to get max strength + * effect.periodic.fade_length = 1000; // Takes 1 second to fade away + * + * // Upload the effect + * effect_id = SDL_HapticNewEffect( haptic, &effect ); + * + * // Test the effect + * SDL_HapticRunEffect( haptic, effect_id, 1 ); + * SDL_Delay( 5000); // Wait for the effect to finish + * + * // We destroy the effect, although closing the device also does this + * SDL_HapticDestroyEffect( haptic, effect_id ); + * + * // Close the device + * SDL_HapticClose(haptic); + * + * return 0; // Success + * } + * \endcode + * + * \author Edgar Simo Serra + */ + +#ifndef _SDL_haptic_h +#define _SDL_haptic_h + +#include "SDL_stdinc.h" +#include "SDL_error.h" +#include "SDL_joystick.h" + +#include "begin_code.h" +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { + /* *INDENT-ON* */ +#endif /* __cplusplus */ + +/** + * \typedef SDL_Haptic + * + * \brief The haptic structure used to identify an SDL haptic. + * + * \sa SDL_HapticOpen + * \sa SDL_HapticOpenFromJoystick + * \sa SDL_HapticClose + */ +struct _SDL_Haptic; +typedef struct _SDL_Haptic SDL_Haptic; + + +/* + * Different haptic features a device can have. + */ +/** + * \def SDL_HAPTIC_CONSTANT + * + * \brief Constant haptic effect. + * + * \sa SDL_HapticCondition + */ +#define SDL_HAPTIC_CONSTANT (1<<0) /* Constant effect supported */ +/** + * \def SDL_HAPTIC_SINE + * + * \brief Periodic haptic effect that simulates sine waves. + * + * \sa SDL_HapticPeriodic + */ +#define SDL_HAPTIC_SINE (1<<1) /* Sine wave effect supported */ +/** + * \def SDL_HAPTIC_SQUARE + * + * \brief Periodic haptic effect that simulates square waves. + * + * \sa SDL_HapticPeriodic + */ +#define SDL_HAPTIC_SQUARE (1<<2) /* Square wave effect supported */ +/** + * \def SDL_HAPTIC_TRIANGLE + * + * \brief Periodic haptic effect that simulates triangular waves. + * + * \sa SDL_HapticPeriodic + */ +#define SDL_HAPTIC_TRIANGLE (1<<3) /* Triangle wave effect supported */ +/** + * \def SDL_HAPTIC_SAWTOOTHUP + * + * \brief Periodic haptic effect that simulates saw tooth up waves. + * + * \sa SDL_HapticPeriodic + */ +#define SDL_HAPTIC_SAWTOOTHUP (1<<4) /* Sawtoothup wave effect supported */ +/** + * \def SDL_HAPTIC_SAWTOOTHDOWN + * + * \brief Periodic haptic effect that simulates saw tooth down waves. + * + * \sa SDL_HapticPeriodic + */ +#define SDL_HAPTIC_SAWTOOTHDOWN (1<<5) /* Sawtoothdown wave effect supported */ +/** + * \def SDL_HAPTIC_RAMP + * + * \brief Ramp haptic effect. + * + * \sa SDL_HapticRamp + */ +#define SDL_HAPTIC_RAMP (1<<6) /* Ramp effect supported */ +/** + * \def SDL_HAPTIC_SPRING + * + * \brief Condition haptic effect that simulates a spring. Effect is based on the + * axes position. + * + * \sa SDL_HapticCondition + */ +#define SDL_HAPTIC_SPRING (1<<7) /* Spring effect supported - uses axes position */ +/** + * \def SDL_HAPTIC_DAMPER + * + * \brief Condition haptic effect that simulates dampening. Effect is based on the + * axes velocity. + * + * \sa SDL_HapticCondition + */ +#define SDL_HAPTIC_DAMPER (1<<8) /* Damper effect supported - uses axes velocity */ +/** + * \def SDL_HAPTIC_INERTIA + * + * \brief Condition haptic effect that simulates inertia. Effect is based on the axes + * acceleration. + * + * \sa SDL_HapticCondition + */ +#define SDL_HAPTIC_INERTIA (1<<9) /* Inertia effect supported - uses axes acceleration */ +/** + * \def SDL_HAPTIC_FRICTION + * + * \brief Condition haptic effect that simulates friction. Effect is based on the axes + * movement. + * + * \sa SDL_HapticCondition + */ +#define SDL_HAPTIC_FRICTION (1<<10) /* Friction effect supported - uses axes movement */ +/** + * \def SDL_HAPTIC_CUSTOM + * + * \brief User defined custom haptic effect. + */ +#define SDL_HAPTIC_CUSTOM (1<<11) /* Custom effect is supported */ +/* These last two are features the device has, not effects */ +/** + * \def SDL_HAPTIC_GAIN + * + * \brief Device supports setting the global gain. + * + * \sa SDL_HapticSetGain + */ +#define SDL_HAPTIC_GAIN (1<<12) /* Device can set global gain */ +/** + * \def SDL_HAPTIC_AUTOCENTER + * + * \brief Device supports setting autocenter. + * + * \sa SDL_HapticSetAutocenter + */ +#define SDL_HAPTIC_AUTOCENTER (1<<13) /* Device can set autocenter */ +/** + * \def SDL_HAPTIC_STATUS + * + * \brief Device can be queried for effect status. + * + * \sa SDL_HapticGetEffectStatus + */ +#define SDL_HAPTIC_STATUS (1<<14) /* Device can be queried for effect status */ +/** + * \def SDL_HAPTIC_PAUSE + * + * \brief Device can be paused. + * + * \sa SDL_HapticPause + * \sa SDL_HapticUnpause + */ +#define SDL_HAPTIC_PAUSE (1<<15) /* Device can be paused. */ + + +/* + * Direction encodings + */ +/** + * \def SDL_HAPTIC_POLAR + * + * \brief Uses polar coordinates for the direction. + * + * \sa SDL_HapticDirection + */ +#define SDL_HAPTIC_POLAR 0 +/** + * \def SDL_HAPTIC_CARTESIAN + * + * \brief Uses cartesian coordinates for the direction. + * + * \sa SDL_HapticDirection + */ +#define SDL_HAPTIC_CARTESIAN 1 +/** + * \def SDL_HAPTIC_SPHERICAL + * + * \brief Uses spherical coordinates for the direction. + * + * \sa SDL_HapticDirection + */ +#define SDL_HAPTIC_SPHERICAL 2 + + +/* + * Misc defines. + */ +/** + * \def SDL_HAPTIC_INFINITY + * + * \brief Used to play a device an infinite number of times. + * + * \sa SDL_HapticRunEffect + */ +#define SDL_HAPTIC_INFINITY 4294967295U + + +/** + * \struct SDL_HapticDirection + * + * \brief Structure that represents a haptic direction. + * + * Directions can be specified by: + * - SDL_HAPTIC_POLAR : Specified by polar coordinates. + * - SDL_HAPTIC_CARTESIAN : Specified by cartesian coordinates. + * - SDL_HAPTIC_SPHERICAL : Specified by spherical coordinates. + * + * Cardinal directions of the haptic device are relative to the positioning + * of the device. North is considered to be away from the user. + * + * The following diagram represents the cardinal directions: + * \code + * .--. + * |__| .-------. + * |=.| |.-----.| + * |--| || || + * | | |'-----'| + * |__|~')_____(' + * [ COMPUTER ] + * + * + * North (0,-1) + * ^ + * | + * | + * (1,0) West <----[ HAPTIC ]----> East (-1,0) + * | + * | + * v + * South (0,1) + * + * + * [ USER ] + * \|||/ + * (o o) + * ---ooO-(_)-Ooo--- + * \endcode + * + * If type is SDL_HAPTIC_POLAR, direction is encoded by hundredths of a + * degree starting north and turning clockwise. SDL_HAPTIC_POLAR only uses + * the first dir parameter. The cardinal directions would be: + * - North: 0 (0 degrees) + * - East: 9000 (90 degrees) + * - South: 18000 (180 degrees) + * - West: 27000 (270 degrees) + * + * If type is SDL_HAPTIC_CARTESIAN, direction is encoded by three positions + * (X axis, Y axis and Z axis (with 3 axes)). SDL_HAPTIC_CARTESIAN uses + * the first three dir parameters. The cardinal directions would be: + * - North: 0,-1, 0 + * - East: -1, 0, 0 + * - South: 0, 1, 0 + * - West: 1, 0, 0 + * The Z axis represents the height of the effect if supported, otherwise + * it's unused. In cartesian encoding (1,2) would be the same as (2,4), you + * can use any multiple you want, only the direction matters. + * + * If type is SDL_HAPTIC_SPHERICAL, direction is encoded by two rotations. + * The first two dir parameters are used. The dir parameters are as follows + * (all values are in hundredths of degrees): + * 1) Degrees from (1, 0) rotated towards (0, 1). + * 2) Degrees towards (0, 0, 1) (device needs at least 3 axes). + * + * + * Example of force coming from the south with all encodings (force coming + * from the south means the user will have to pull the stick to counteract): + * \code + * SDL_HapticDirection direction; + * + * // Cartesian directions + * direction.type = SDL_HAPTIC_CARTESIAN; // Using cartesian direction encoding. + * direction.dir[0] = 0; // X position + * direction.dir[1] = 1; // Y position + * // Assuming the device has 2 axes, we don't need to specify third parameter. + * + * // Polar directions + * direction.type = SDL_HAPTIC_POLAR; // We'll be using polar direction encoding. + * direction.dir[0] = 18000; // Polar only uses first parameter + * + * // Spherical coordinates + * direction.type = SDL_HAPTIC_SPHERICAL; // Spherical encoding + * direction.dir[0] = 9000; // Since we only have two axes we don't need more parameters. + * \endcode + * + * \sa SDL_HAPTIC_POLAR + * \sa SDL_HAPTIC_CARTESIAN + * \sa SDL_HAPTIC_SPHERICAL + * \sa SDL_HapticEffect + * \sa SDL_HapticNumAxes + */ +typedef struct SDL_HapticDirection { + Uint8 type; /**< The type of encoding. */ + Sint16 dir[3]; /**< The encoded direction. */ +} SDL_HapticDirection; + + +/** + * \struct SDL_HapticConstant + * + * \brief A structure containing a template for a Constant effect. + * + * The struct is exclusive to the SDL_HAPTIC_CONSTANT effect. + * + * A constant effect applies a constant force in the specified direction + * to the joystick. + * + * \sa SDL_HAPTIC_CONSTANT + * \sa SDL_HapticEffect + */ +typedef struct SDL_HapticConstant { + /* Header */ + Uint16 type; /**< SDL_HAPTIC_CONSTANT */ + SDL_HapticDirection direction; /**< Direction of the effect. */ + + /* Replay */ + Uint32 length; /**< Duration of the effect. */ + Uint16 delay; /**< Delay before starting the effect. */ + + /* Trigger */ + Uint16 button; /**< Button that triggers the effect. */ + Uint16 interval; /**< How soon it can be triggered again after button. */ + + /* Constant */ + Sint16 level; /**< Strength of the constant effect. */ + + /* Envelope */ + Uint16 attack_length; /**< Duration of the attack. */ + Uint16 attack_level; /**< Level at the start of the attack. */ + Uint16 fade_length; /**< Duration of the fade. */ + Uint16 fade_level; /**< Level at the end of the fade. */ +} SDL_HapticConstant; +/** + * \struct SDL_HapticPeriodic + * + * \brief A structure containing a template for a Periodic effect. + * + * The struct handles the following effects: + * - SDL_HAPTIC_SINE + * - SDL_HAPTIC_SQUARE + * - SDL_HAPTIC_TRIANGLE + * - SDL_HAPTIC_SAWTOOTHUP + * - SDL_HAPTIC_SAWTOOTHDOWN + * + * A periodic effect consists in a wave-shaped effect that repeats itself + * over time. The type determines the shape of the wave and the parameters + * determine the dimensions of the wave. + * + * Phase is given by hundredth of a cyle meaning that giving the phase a value + * of 9000 will displace it 25% of it's period. Here are sample values: + * - 0: No phase displacement. + * - 9000: Displaced 25% of it's period. + * - 18000: Displaced 50% of it's period. + * - 27000: Displaced 75% of it's period. + * - 36000: Displaced 100% of it's period, same as 0, but 0 is preffered. + * + * Examples: + * \code + * SDL_HAPTIC_SINE + * __ __ __ __ + * / \ / \ / \ / + * / \__/ \__/ \__/ + * + * SDL_HAPTIC_SQUARE + * __ __ __ __ __ + * | | | | | | | | | | + * | |__| |__| |__| |__| | + * + * SDL_HAPTIC_TRIANGLE + * /\ /\ /\ /\ /\ + * / \ / \ / \ / \ / + * / \/ \/ \/ \/ + * + * SDL_HAPTIC_SAWTOOTHUP + * /| /| /| /| /| /| /| + * / | / | / | / | / | / | / | + * / |/ |/ |/ |/ |/ |/ | + * + * SDL_HAPTIC_SAWTOOTHDOWN + * \ |\ |\ |\ |\ |\ |\ | + * \ | \ | \ | \ | \ | \ | \ | + * \| \| \| \| \| \| \| + * \endcode + * + * \sa SDL_HAPTIC_SINE + * \sa SDL_HAPTIC_SQUARE + * \sa SDL_HAPTIC_TRIANGLE + * \sa SDL_HAPTIC_SAWTOOTHUP + * \sa SDL_HAPTIC_SAWTOOTHDOWN + * \sa SDL_HapticEffect + */ +typedef struct SDL_HapticPeriodic { + /* Header */ + Uint16 type; /**< SDL_HAPTIC_SINE, SDL_HAPTIC_SQUARE, + SDL_HAPTIC_TRIANGLE, SDL_HAPTIC_SAWTOOTHUP or + SDL_HAPTIC_SAWTOOTHDOWN */ + SDL_HapticDirection direction; /**< Direction of the effect. */ + + /* Replay */ + Uint32 length; /**< Duration of the effect. */ + Uint16 delay; /**< Delay before starting the effect. */ + + /* Trigger */ + Uint16 button; /**< Button that triggers the effect. */ + Uint16 interval; /**< How soon it can be triggered again after button. */ + + /* Periodic */ + Uint16 period; /**< Period of the wave. */ + Sint16 magnitude; /**< Peak value. */ + Sint16 offset; /**< Mean value of the wave. */ + Uint16 phase; /**< Horizontal shift given by hundredth of a cycle. */ + + /* Envelope */ + Uint16 attack_length; /**< Duration of the attack. */ + Uint16 attack_level; /**< Level at the start of the attack. */ + Uint16 fade_length; /**< Duration of the fade. */ + Uint16 fade_level; /**< Level at the end of the fade. */ +} SDL_HapticPeriodic; +/** + * \struct SDL_HapticCondition + * + * \brief A structure containing a template for a Condition effect. + * + * The struct handles the following effects: + * - SDL_HAPTIC_SPRING: Effect based on axes position. + * - SDL_HAPTIC_DAMPER: Effect based on axes velocity. + * - SDL_HAPTIC_INERTIA: Effect based on axes acceleration. + * - SDL_HAPTIC_FRICTION: Effect based on axes movement. + * + * Direction is handled by condition internals instead of a direction member. + * The condition effect specific members have three parameters. The first + * refers to the X axis, the second refers to the Y axis and the third + * refers to the Z axis. The right terms refer to the positive side of the + * axis and the left terms refer to the negative side of the axis. Please + * refer to the SDL_HapticDirection diagram for which side is positive and + * which is negative. + * + * \sa SDL_HapticDirection + * \sa SDL_HAPTIC_SPRING + * \sa SDL_HAPTIC_DAMPER + * \sa SDL_HAPTIC_INERTIA + * \sa SDL_HAPTIC_FRICTION + * \sa SDL_HapticEffect + */ +typedef struct SDL_HapticCondition { + /* Header */ + Uint16 type; /**< SDL_HAPTIC_SPRING, SDL_HAPTIC_DAMPER, + SDL_HAPTIC_INERTIA or SDL_HAPTIC_FRICTION */ + SDL_HapticDirection direction; /**< Direction of the effect - Not used ATM. */ + + /* Replay */ + Uint32 length; /**< Duration of the effect. */ + Uint16 delay; /**< Delay before starting the effect. */ + + /* Trigger */ + Uint16 button; /**< Button that triggers the effect. */ + Uint16 interval; /**< How soon it can be triggered again after button. */ + + /* Condition */ + Uint16 right_sat[3]; /**< Level when joystick is to the positive side. */ + Uint16 left_sat[3]; /**< Level when joystick is to the negative side. */ + Sint16 right_coeff[3]; /**< How fast to increase the force towards the positive side. */ + Sint16 left_coeff[3]; /**< How fast to increase the force towards the negative side. */ + Uint16 deadband[3]; /**< Size of the dead zone. */ + Sint16 center[3]; /**< Position of the dead zone. */ +} SDL_HapticCondition; +/** + * \struct SDL_HapticRamp + * + * \brief A structure containing a template for a Ramp effect. + * + * This struct is exclusively for the SDL_HAPTIC_RAMP effect. + * + * The ramp effect starts at start strength and ends at end strength. + * It augments in linear fashion. If you use attack and fade with a ramp + * they effects get added to the ramp effect making the effect become + * quadratic instead of linear. + * + * \sa SDL_HAPTIC_RAMP + * \sa SDL_HapticEffect + */ +typedef struct SDL_HapticRamp { + /* Header */ + Uint16 type; /**< SDL_HAPTIC_RAMP */ + SDL_HapticDirection direction; /**< Direction of the effect. */ + + /* Replay */ + Uint32 length; /**< Duration of the effect. */ + Uint16 delay; /**< Delay before starting the effect. */ + + /* Trigger */ + Uint16 button; /**< Button that triggers the effect. */ + Uint16 interval; /**< How soon it can be triggered again after button. */ + + /* Ramp */ + Sint16 start; /**< Beginning strength level. */ + Sint16 end; /**< Ending strength level. */ + + /* Envelope */ + Uint16 attack_length; /**< Duration of the attack. */ + Uint16 attack_level; /**< Level at the start of the attack. */ + Uint16 fade_length; /**< Duration of the fade. */ + Uint16 fade_level; /**< Level at the end of the fade. */ +} SDL_HapticRamp; +/** + * \struct SDL_HapticCustom + * + * \brief A structure containing a template for the SDL_HAPTIC_CUSTOM effect. + * + * A custom force feedback effect is much like a periodic effect, where the + * application can define it's exact shape. You will have to allocate the + * data yourself. Data should consist of channels * samples Uint16 samples. + * + * If channels is one, the effect is rotated using the defined direction. + * Otherwise it uses the samples in data for the different axes. + * + * \sa SDL_HAPTIC_CUSTOM + * \sa SDL_HapticEffect + */ +typedef struct SDL_HapticCustom { + /* Header */ + Uint16 type; /**< SDL_HAPTIC_CUSTOM */ + SDL_HapticDirection direction; /**< Direction of the effect. */ + + /* Replay */ + Uint32 length; /**< Duration of the effect. */ + Uint16 delay; /**< Delay before starting the effect. */ + + /* Trigger */ + Uint16 button; /**< Button that triggers the effect. */ + Uint16 interval; /**< How soon it can be triggered again after button. */ + + /* Custom */ + Uint8 channels; /**< Axes to use, minimum of one. */ + Uint16 period; /**< Sample periods. */ + Uint16 samples; /**< Amount of samples. */ + Uint16 *data; /**< Should contain channels*samples items. */ + + /* Envelope */ + Uint16 attack_length; /**< Duration of the attack. */ + Uint16 attack_level; /**< Level at the start of the attack. */ + Uint16 fade_length; /**< Duration of the fade. */ + Uint16 fade_level; /**< Level at the end of the fade. */ +} SDL_HapticCustom; +/** + * \union SDL_HapticEffect + * + * \brief The generic template for any haptic effect. + * + * All values max at 32767 (0x7FFF). Signed values also can be negative. + * Time values unless specified otherwise are in milliseconds. + * + * You can also pass SDL_HAPTIC_INFINITY to length instead of a 0-32767 value. + * Neither delay, interval, attack_length nor fade_length support + * SDL_HAPTIC_INFINITY. Fade will also not be used since effect never ends. + * + * Additionally, the SDL_HAPTIC_RAMP effect does not support a duration of + * SDL_HAPTIC_INFINITY. + * + * Button triggers may not be supported on all devices, it is advised to not + * use them if possible. Buttons start at index 1 instead of index 0 like + * they joystick. + * + * If both attack_length and fade_level are 0, the envelope is not used, + * otherwise both values are used. + * + * Common parts: + * \code + * // Replay - All effects have this + * Uint32 length; // Duration of effect (ms). + * Uint16 delay; // Delay before starting effect. + * + * // Trigger - All effects have this + * Uint16 button; // Button that triggers effect. + * Uint16 interval; // How soon before effect can be triggered again. + * + * // Envelope - All effects except condition effects have this + * Uint16 attack_length; // Duration of the attack (ms). + * Uint16 attack_level; // Level at the start of the attack. + * Uint16 fade_length; // Duration of the fade out (ms). + * Uint16 fade_level; // Level at the end of the fade. + * \endcode + * + * + * Here we have an example of a constant effect evolution in time: + * + * \code + * Strength + * ^ + * | + * | effect level --> _________________ + * | / \ + * | / \ + * | / \ + * | / \ + * | attack_level --> | \ + * | | | <--- fade_level + * | + * +--------------------------------------------------> Time + * [--] [---] + * attack_length fade_length + * + * [------------------][-----------------------] + * delay length + * \endcode + * + * Note either the attack_level or the fade_level may be above the actual + * effect level. + * + * \sa SDL_HapticConstant + * \sa SDL_HapticPeriodic + * \sa SDL_HapticCondition + * \sa SDL_HapticRamp + * \sa SDL_HapticCustom + */ +typedef union SDL_HapticEffect { + /* Common for all force feedback effects */ + Uint16 type; /**< Effect type. */ + SDL_HapticConstant constant; /**< Constant effect. */ + SDL_HapticPeriodic periodic; /**< Periodic effect. */ + SDL_HapticCondition condition; /**< Condition effect. */ + SDL_HapticRamp ramp; /**< Ramp effect. */ + SDL_HapticCustom custom; /**< Custom effect. */ +} SDL_HapticEffect; + + +/* Function prototypes */ +/** + * \fn int SDL_NumHaptics(void) + * + * \brief Count the number of joysticks attached to the system. + * + * \return Number of haptic devices detected on the system. + */ +extern DECLSPEC int SDLCALL SDL_NumHaptics(void); + +/** + * \fn const char * SDL_HapticName(int device_index) + * + * \brief Get the implementation dependent name of a Haptic device. + * This can be called before any joysticks are opened. + * If no name can be found, this function returns NULL. + * + * \param device_index Index of the device to get it's name. + * \return Name of the device or NULL on error. + * + * \sa SDL_NumHaptics + */ +extern DECLSPEC const char *SDLCALL SDL_HapticName(int device_index); + +/** + * \fn SDL_Haptic * SDL_HapticOpen(int device_index) + * + * \brief Opens a Haptic device for usage - the index passed as an + * argument refers to the N'th Haptic device on this system. + * + * When opening a haptic device, it's gain will be set to maximum and + * autocenter will be disabled. To modify these values use + * SDL_HapticSetGain and SDL_HapticSetAutocenter + * + * \param device_index Index of the device to open. + * \return Device identifier or NULL on error. + * + * \sa SDL_HapticIndex + * \sa SDL_HapticOpenFromMouse + * \sa SDL_HapticOpenFromJoystick + * \sa SDL_HapticClose + * \sa SDL_HapticSetGain + * \sa SDL_HapticSetAutocenter + * \sa SDL_HapticPause + * \sa SDL_HapticStopAll + */ +extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpen(int device_index); + +/** + * \fn int SDL_HapticOpened(int device_index) + * + * \brief Checks if the haptic device at index has been opened. + * + * \param device_index Index to check to see if it has been opened. + * \return 1 if it has been opened or 0 if it hasn't. + * + * \sa SDL_HapticOpen + * \sa SDL_HapticIndex + */ +extern DECLSPEC int SDLCALL SDL_HapticOpened(int device_index); + +/** + * \fn int SDL_HapticIndex(SDL_Haptic * haptic) + * + * \brief Gets the index of a haptic device. + * + * \param haptic Haptic device to get the index of. + * \return The index of the haptic device or -1 on error. + * + * \sa SDL_HapticOpen + * \sa SDL_HapticOpened + */ +extern DECLSPEC int SDLCALL SDL_HapticIndex(SDL_Haptic * haptic); + +/** + * \fn int SDL_MouseIsHaptic(void) + * + * \brief Gets whether or not the current mouse has haptic capabilities. + * + * \return SDL_TRUE if the mouse is haptic, SDL_FALSE if it isn't. + * + * \sa SDL_HapticOpenFromMouse + */ +extern DECLSPEC int SDLCALL SDL_MouseIsHaptic(void); + +/** + * \fn SDL_Haptic * SDL_HapticOpenFromMouse(void) + * + * \brief Tries to open a haptic device from the current mouse. + * + * \return The haptic device identifier or NULL on error. + * + * \sa SDL_MouseIsHaptic + * \sa SDL_HapticOpen + */ +extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpenFromMouse(void); + +/** + * \fn int SDL_JoystickIsHaptic(SDL_Joystick * joystick) + * + * \brief Checks to see if a joystick has haptic features. + * + * \param joystick Joystick to test for haptic capabilities. + * \return SDL_TRUE if the joystick is haptic, SDL_FALSE if it isn't + * or -1 if an error ocurred. + * + * \sa SDL_HapticOpenFromJoystick + */ +extern DECLSPEC int SDLCALL SDL_JoystickIsHaptic(SDL_Joystick * joystick); + +/** + * \fn SDL_Haptic * SDL_HapticOpenFromJoystick(SDL_Joystick * joystick) + * + * \brief Opens a Haptic device for usage from a Joystick device. Still has + * to be closed seperately to the joystick. + * + * When opening from a joystick you should first close the haptic device before + * closing the joystick device. If not, on some implementations the haptic + * device will also get unallocated and you'll be unable to use force feedback + * on that device. + * + * \param joystick Joystick to create a haptic device from. + * \return A valid haptic device identifier on success or NULL on error. + * + * \sa SDL_HapticOpen + * \sa SDL_HapticClose + */ +extern DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpenFromJoystick(SDL_Joystick * joystick); + +/** + * \fn void SDL_HapticClose(SDL_Haptic * haptic) + * + * \brief Closes a Haptic device previously opened with SDL_HapticOpen. + * + * \param haptic Haptic device to close. + */ +extern DECLSPEC void SDLCALL SDL_HapticClose(SDL_Haptic * haptic); + +/** + * \fn int SDL_HapticNumEffects(SDL_Haptic * haptic) + * + * \brief Returns the number of effects a haptic device can store. + * + * On some platforms this isn't fully supported, and therefore is an + * aproximation. Always check to see if your created effect was actually + * created and do not rely solely on HapticNumEffects. + * + * \param haptic The haptic device to query effect max. + * \return The number of effects the haptic device can store or + * -1 on error. + * + * \sa SDL_HapticNumEffectsPlaying + * \sa SDL_HapticQuery + */ +extern DECLSPEC int SDLCALL SDL_HapticNumEffects(SDL_Haptic * haptic); + +/** + * \fn int SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic) + * + * \brief Returns the number of effects a haptic device can play at the same time. + * + * This is not supported on all platforms, but will always return a value. Added + * here for the sake of completness. + * + * \param haptic The haptic device to query maximum playing effect.s + * \return The number of effects the haptic device can play at the same time + * or -1 on error. + * + * \sa SDL_HapticNumEffects + * \sa SDL_HapticQuery + */ +extern DECLSPEC int SDLCALL SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic); + +/** + * \fn unsigned int SDL_HapticQuery(SDL_Haptic * haptic) + * + * \brief Gets the haptic devices supported features in bitwise matter. + * + * Example: + * \code + * if (SDL_HapticQueryEffects(haptic) & SDL_HAPTIC_CONSTANT) { + * printf("We have constant haptic effect!"); + * } + * \endcode + * + * + * \param haptic The haptic device to query. + * \return Haptic features in bitwise manner (OR'd). + * + * \sa SDL_HapticNumEffects + * \sa SDL_HapticEffectSupported + */ +extern DECLSPEC unsigned int SDLCALL SDL_HapticQuery(SDL_Haptic * haptic); + + +/** + * \fn int SDL_HapticNumAxes(SDL_Haptic * haptic) + * + * \brief Gets the number of haptic axes the device has. + * + * \sa SDL_HapticDirection + */ +extern DECLSPEC int SDLCALL SDL_HapticNumAxes(SDL_Haptic * haptic); + +/** + * \fn int SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect) + * + * \brief Checks to see if effect is supported by haptic. + * + * \param haptic Haptic device to check on. + * \param effect Effect to check to see if it is supported. + * \return SDL_TRUE if effect is supported, SDL_FALSE if it isn't or + * -1 on error. + * + * \sa SDL_HapticQuery + * \sa SDL_HapticNewEffect + */ +extern DECLSPEC int SDLCALL SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect); + +/** + * \fn int SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect) + * + * \brief Creates a new haptic effect on the device. + * + * \param haptic Haptic device to create the effect on. + * \param effect Properties of the effect to create. + * \return The id of the effect on success or -1 on error. + * + * \sa SDL_HapticUpdateEffect + * \sa SDL_HapticRunEffect + * \sa SDL_HapticDestroyEffect + */ +extern DECLSPEC int SDLCALL SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect); + +/** + * \fn int SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect, SDL_HapticEffect * data) + * + * \brief Updates the properties of an effect. + * + * Can be used dynamically, although behaviour when dynamically changing + * direction may be strange. Specifically the effect may reupload itself + * and start playing from the start. You cannot change the type either when + * running UpdateEffect. + * + * \param haptic Haptic device that has the effect. + * \param effect Effect to update. + * \param data New effect properties to use. + * \return The id of the effect on success or -1 on error. + * + * \sa SDL_HapticNewEffect + * \sa SDL_HapticRunEffect + * \sa SDL_HapticDestroyEffect + */ +extern DECLSPEC int SDLCALL SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect, SDL_HapticEffect * data); + +/** + * \fn int SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations) + * + * \brief Runs the haptic effect on it's assosciated haptic device. + * + * If iterations are SDL_HAPTIC_INFINITY, it'll run the effect over and over + * repeating the envelope (attack and fade) every time. If you only want the + * effect to last forever, set SDL_HAPTIC_INFINITY in the effect's length + * parameter. + * + * \param haptic Haptic device to run the effect on. + * \param effect Identifier of the haptic effect to run. + * \param iterations Number of iterations to run the effect. Use + * SDL_HAPTIC_INFINITY for infinity. + * \return 0 on success or -1 on error. + * + * \sa SDL_HapticStopEffect + * \sa SDL_HapticDestroyEffect + * \sa SDL_HapticGetEffectStatus + */ +extern DECLSPEC int SDLCALL SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations); + +/** + * \fn int SDL_HapticStopEffect(SDL_Haptic * haptic, int effect) + * + * \brief Stops the haptic effect on it's assosciated haptic device. + * + * \param haptic Haptic device to stop the effect on. + * \param effect Identifier of the effect to stop. + * \return 0 on success or -1 on error. + * + * \sa SDL_HapticRunEffect + * \sa SDL_HapticDestroyEffect + */ +extern DECLSPEC int SDLCALL SDL_HapticStopEffect(SDL_Haptic * haptic, int effect); + +/** + * \fn void SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect) + * + * \brief Destroys a haptic effect on the device. This will stop the effect + * if it's running. Effects are automatically destroyed when the device is + * closed. + * + * \param haptic Device to destroy the effect on. + * \param effect Identifier of the effect to destroy. + * + * \sa SDL_HapticNewEffect + */ +extern DECLSPEC void SDLCALL SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect); + +/** + * \fn int SDL_HapticGetEffectStatus(SDL_Haptic *haptic, int effect) + * + * \brief Gets the status of the current effect on the haptic device. + * + * Device must support the SDL_HAPTIC_STATUS feature. + * + * \param haptic Haptic device to query the effect status on. + * \param effect Identifier of the effect to query it's status. + * \return 0 if it isn't playing, SDL_HAPTIC_PLAYING if it is playing + * or -1 on error. + * + * \sa SDL_HapticRunEffect + * \sa SDL_HapticStopEffect + */ +extern DECLSPEC int SDLCALL SDL_HapticGetEffectStatus(SDL_Haptic *haptic, int effect); + +/** + * \fn int SDL_HapticSetGain(SDL_Haptic * haptic, int gain) + * + * \brief Sets the global gain of the device. Gain should be between 0 and 100. + * + * Device must support the SDL_HAPTIC_GAIN feature. + * + * The user may specify the maxmimum gain by setting the environment variable + * SDL_HAPTIC_GAIN_MAX which should be between 0 and 100. All calls to + * SDL_HapticSetGain will scale linearly using SDL_HAPTIC_GAIN_MAX as the + * maximum. + * + * \param haptic Haptic device to set the gain on. + * \param gain Value to set the gain to, should be between 0 and 100. + * \return 0 on success or -1 on error. + * + * \sa SDL_HapticQuery + */ +extern DECLSPEC int SDLCALL SDL_HapticSetGain(SDL_Haptic * haptic, int gain); + +/** + * \fn int SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) + * + * \brief Sets the global autocenter of the device. Autocenter should be between + * 0 and 100. Setting it to 0 will disable autocentering. + * + * Device must support the SDL_HAPTIC_AUTOCENTER feature. + * + * \param haptic Haptic device to set autocentering on. + * \param autocenter Value to set autocenter to, 0 disables autocentering. + * \return 0 on success or -1 on error. + * + * \sa SDL_HapticQuery + */ +extern DECLSPEC int SDLCALL SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter); + +/** + * \fn extern DECLSPEC int SDLCALL SDL_HapticPause(SDL_Haptic * haptic) + * + * \brief Pauses a haptic device. + * + * Device must support the SDL_HAPTIC_PAUSE feature. Call SDL_HapticUnpause + * to resume playback. + * + * Do not modify the effects nor add new ones while the device is paused. + * That can cause all sorts of weird errors. + * + * \param haptic Haptic device to pause. + * \return 0 on success or -1 on error. + * + * \sa SDL_HapticUnpause + */ +extern DECLSPEC int SDLCALL SDL_HapticPause(SDL_Haptic * haptic); + +/** + * \fn extern DECLSPEC int SDLCALL SDL_HapticUnpause(SDL_Haptic * haptic) + * + * \brief Unpauses a haptic device. + * + * Call to unpause after SDL_HapticPause. + * + * \param haptic Haptic device to pause. + * \return 0 on success or -1 on error. + * + * \sa SDL_HapticPause + */ +extern DECLSPEC int SDLCALL SDL_HapticUnpause(SDL_Haptic * haptic); + +/** + * \fn extern DECSLPEC int SDLCALL SDL_HapticStopAll(SDL_Haptic * haptic) + * + * \brief Stops all the currently playing effects on a haptic device. + * + * \param haptic Haptic device to stop. + * \return 0 on success or -1 on error. + */ +extern DECLSPEC int SDLCALL SDL_HapticStopAll(SDL_Haptic * haptic); + + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif +#include "close_code.h" + +#endif /* _SDL_haptic_h */ + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/include/SDL_video.h b/include/SDL_video.h index 66b486a85..2f161ebb8 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -233,6 +233,7 @@ typedef enum { SDL_GL_GREEN_SIZE, SDL_GL_BLUE_SIZE, SDL_GL_ALPHA_SIZE, + SDL_GL_PIXEL_TYPE_FLOAT, SDL_GL_BUFFER_SIZE, SDL_GL_DOUBLEBUFFER, SDL_GL_DEPTH_SIZE, diff --git a/src/SDL.c b/src/SDL.c index 87f1b1af2..234c22faf 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -38,6 +38,10 @@ extern int SDL_JoystickInit(void); extern void SDL_JoystickQuit(void); #endif +#if !SDL_HAPTIC_DISABLED +extern int SDL_HapticInit(void); +extern int SDL_HapticQuit(void); +#endif #if !SDL_CDROM_DISABLED extern int SDL_CDROMInit(void); extern void SDL_CDROMQuit(void); @@ -47,6 +51,10 @@ extern void SDL_StartTicks(void); extern int SDL_TimerInit(void); extern void SDL_TimerQuit(void); #endif +#if defined(__WIN32__) +extern int SDL_HelperWindowCreate(void); +extern int SDL_HelperWindowDestroy(void); +#endif /* The current SDL version */ static SDL_version version = @@ -130,6 +138,21 @@ int SDL_InitSubSystem(Uint32 flags) } #endif +#if !SDL_HAPTIC_DISABLED + /* Initialize the haptic subsystem */ + if ((flags & SDL_INIT_HAPTIC) && !(SDL_initialized & SDL_INIT_HAPTIC)) { + if (SDL_HapticInit() < 0) { + return (-1); + } + SDL_initialized |= SDL_INIT_HAPTIC; + } +#else + if (flags & SDL_INIT_HAPTIC) { + SDL_SetError("SDL not built with haptic (force feedback) support"); + return (-1); + } +#endif + #if !SDL_CDROM_DISABLED /* Initialize the CD-ROM subsystem */ if ( (flags & SDL_INIT_CDROM) && !(SDL_initialized & SDL_INIT_CDROM) ) { @@ -158,6 +181,12 @@ int SDL_Init(Uint32 flags) /* Clear the error message */ SDL_ClearError(); + #if defined(__WIN32__) + if (SDL_HelperWindowCreate() < 0) { + return -1; + } + #endif + /* Initialize the desired subsystems */ if ( SDL_InitSubSystem(flags) < 0 ) { return(-1); @@ -197,6 +226,12 @@ void SDL_QuitSubSystem(Uint32 flags) SDL_initialized &= ~SDL_INIT_VIDEO; } #endif +#if !SDL_HAPTIC_DISABLED + if ((flags & SDL_initialized & SDL_INIT_HAPTIC)) { + SDL_HapticQuit(); + SDL_initialized &= ~SDL_INIT_HAPTIC; + } +#endif #if !SDL_TIMERS_DISABLED if ( (flags & SDL_initialized & SDL_INIT_TIMER) ) { SDL_TimerQuit(); @@ -219,6 +254,11 @@ void SDL_Quit(void) #ifdef DEBUG_BUILD printf("[SDL_Quit] : Enter! Calling QuitSubSystem()\n"); fflush(stdout); #endif + +#if defined(__WIN32__) + SDL_HelperWindowDestroy(); +#endif + SDL_QuitSubSystem(SDL_INIT_EVERYTHING); #ifdef CHECK_LEAKS diff --git a/src/SDL_HelperWindow.c b/src/SDL_HelperWindow.c new file mode 100644 index 000000000..778132fe8 --- /dev/null +++ b/src/SDL_HelperWindow.c @@ -0,0 +1,154 @@ +#define UNICODE 1 +#include "SDL_config.h" +#include + +/* Some compilers use a special export keyword */ +#ifndef DECLSPEC +# if defined(__BEOS__) +# if defined(__GNUC__) +# define DECLSPEC __declspec(dllexport) +# else +# define DECLSPEC __declspec(export) +# endif +# elif defined(__WIN32__) +# ifdef __BORLANDC__ +# ifdef BUILD_SDL +# define DECLSPEC +# else +# define DECLSPEC __declspec(dllimport) +# endif +# else +# define DECLSPEC __declspec(dllexport) +# endif +# elif defined(__OS2__) +# ifdef __WATCOMC__ +# ifdef BUILD_SDL +# define DECLSPEC __declspec(dllexport) +# else +# define DECLSPEC +# endif +# else +# define DECLSPEC +# endif +# else +# if defined(__GNUC__) && __GNUC__ >= 4 +# define DECLSPEC __attribute__ ((visibility("default"))) +# else +# define DECLSPEC +# endif +# endif +#endif + +extern DECLSPEC char * SDL_iconv_string(const char *tocode, const char *fromcode, const char *inbuf, size_t inbytesleft); + +#define SDL_arraysize(array) (sizeof(array)/sizeof(array[0])) +#define SDL_free free + +/* Routines to convert from UTF8 to native Windows text */ +#if UNICODE +#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(S), (wcslen(S)+1)*sizeof(WCHAR)) +#define WIN_UTF8ToString(S) (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (char *)(S), strlen(S)+1) +#else +/* !!! FIXME: UTF8ToString() can just be a SDL_strdup() here. */ +#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "ASCII", (char *)(S), (strlen(S)+1)) +#define WIN_UTF8ToString(S) SDL_iconv_string("ASCII", "UTF-8", (char *)(S), strlen(S)+1) +#endif + +/* Fake window to help with DirectInput events. */ +HWND SDL_HelperWindow = NULL; +static WCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher"); +static WCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow"); +static ATOM SDL_HelperWindowClass = 0; + +/* + * Creates a HelperWindow used for DirectInput events. + */ +int +SDL_HelperWindowCreate(void) +{ + HINSTANCE hInstance = GetModuleHandle(NULL); + WNDCLASS wce; + + /* Make sure window isn't created twice. */ + if (SDL_HelperWindow != NULL) { + return 0; + } + + /* Create the class. */ + memset(&wce, 0, sizeof(wce)); + wce.lpfnWndProc = DefWindowProc; + wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName; + wce.hInstance = hInstance; + + /* Register the class. */ + SDL_HelperWindowClass = RegisterClass(&wce); + if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) { + return WIN_SetError("Unable to create Helper Window Class"); + } + + /* Create the window. */ + SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName, + SDL_HelperWindowName, + WS_OVERLAPPED, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, HWND_MESSAGE, NULL, + hInstance, NULL); + if (SDL_HelperWindow == NULL) { + UnregisterClass(SDL_HelperWindowClassName, hInstance); + return WIN_SetError("Unable to create Helper Window"); + } + + return 0; +} + + +/* + * Destroys the HelperWindow previously created with SDL_HelperWindowCreate. + */ +void +SDL_HelperWindowDestroy(void) +{ + HINSTANCE hInstance = GetModuleHandle(NULL); + + /* Destroy the window. */ + if (SDL_HelperWindow != NULL) { + if (DestroyWindow(SDL_HelperWindow) == 0) { + WIN_SetError("Unable to destroy Helper Window"); + return; + } + SDL_HelperWindow = NULL; + } + + /* Unregister the class. */ + if (SDL_HelperWindowClass != 0) { + if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) { + WIN_SetError("Unable to destroy Helper Window Class"); + return; + } + SDL_HelperWindowClass = 0; + } +} + + +/* Sets an error message based on GetLastError() */ +int +WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr) +{ + TCHAR buffer[1024]; + char *message; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, + buffer, SDL_arraysize(buffer), NULL); + message = SDL_iconv_string("UTF-8", "UTF-16LE", (char *)buffer, (wcslen(buffer)+1)*sizeof(WCHAR)); + //WIN_StringToUTF8(buffer); + SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ": " : "", message); + SDL_free(message); + return -1; +} + + +/* Sets an error message based on GetLastError() */ +int +WIN_SetError(const char *prefix) +{ + return WIN_SetErrorFromHRESULT(prefix, GetLastError()); +} diff --git a/src/events/SDL_resize.c b/src/events/SDL_resize.c index e754a07d3..8a29cf02f 100644 --- a/src/events/SDL_resize.c +++ b/src/events/SDL_resize.c @@ -49,6 +49,11 @@ int SDL_PrivateResize(int w, int h) last_resize.w = w; last_resize.h = h; +#ifdef __WIN32__ + SDL_VideoSurface->w = w; + SDL_VideoSurface->h = h; +#endif + SDL_SetMouseRange(w, h); /* Pull out all old resize events */ diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 083b01701..a0e09994b 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -195,7 +195,7 @@ int SDL_JoystickOpened(int device_index) return(opened); } -static int ValidJoystick(SDL_Joystick **joystick) +int SDL_PrivateJoystickValid(SDL_Joystick **joystick) { int valid; @@ -213,7 +213,7 @@ static int ValidJoystick(SDL_Joystick **joystick) */ int SDL_JoystickIndex(SDL_Joystick *joystick) { - if ( ! ValidJoystick(&joystick) ) { + if ( ! SDL_PrivateJoystickValid(&joystick) ) { return(-1); } return(joystick->index); @@ -224,7 +224,7 @@ int SDL_JoystickIndex(SDL_Joystick *joystick) */ int SDL_JoystickNumAxes(SDL_Joystick *joystick) { - if ( ! ValidJoystick(&joystick) ) { + if ( ! SDL_PrivateJoystickValid(&joystick) ) { return(-1); } return(joystick->naxes); @@ -235,7 +235,7 @@ int SDL_JoystickNumAxes(SDL_Joystick *joystick) */ int SDL_JoystickNumHats(SDL_Joystick *joystick) { - if ( ! ValidJoystick(&joystick) ) { + if ( ! SDL_PrivateJoystickValid(&joystick) ) { return(-1); } return(joystick->nhats); @@ -246,7 +246,7 @@ int SDL_JoystickNumHats(SDL_Joystick *joystick) */ int SDL_JoystickNumBalls(SDL_Joystick *joystick) { - if ( ! ValidJoystick(&joystick) ) { + if ( ! SDL_PrivateJoystickValid(&joystick) ) { return(-1); } return(joystick->nballs); @@ -257,7 +257,7 @@ int SDL_JoystickNumBalls(SDL_Joystick *joystick) */ int SDL_JoystickNumButtons(SDL_Joystick *joystick) { - if ( ! ValidJoystick(&joystick) ) { + if ( ! SDL_PrivateJoystickValid(&joystick) ) { return(-1); } return(joystick->nbuttons); @@ -270,7 +270,7 @@ Sint16 SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis) { Sint16 state; - if ( ! ValidJoystick(&joystick) ) { + if ( ! SDL_PrivateJoystickValid(&joystick) ) { return(0); } if ( axis < joystick->naxes ) { @@ -289,7 +289,7 @@ Uint8 SDL_JoystickGetHat(SDL_Joystick *joystick, int hat) { Uint8 state; - if ( ! ValidJoystick(&joystick) ) { + if ( ! SDL_PrivateJoystickValid(&joystick) ) { return(0); } if ( hat < joystick->nhats ) { @@ -308,7 +308,7 @@ int SDL_JoystickGetBall(SDL_Joystick *joystick, int ball, int *dx, int *dy) { int retval; - if ( ! ValidJoystick(&joystick) ) { + if ( ! SDL_PrivateJoystickValid(&joystick) ) { return(-1); } @@ -336,7 +336,7 @@ Uint8 SDL_JoystickGetButton(SDL_Joystick *joystick, int button) { Uint8 state; - if ( ! ValidJoystick(&joystick) ) { + if ( ! SDL_PrivateJoystickValid(&joystick) ) { return(0); } if ( button < joystick->nbuttons ) { @@ -355,7 +355,7 @@ void SDL_JoystickClose(SDL_Joystick *joystick) { int i; - if ( ! ValidJoystick(&joystick) ) { + if ( ! SDL_PrivateJoystickValid(&joystick) ) { return; } diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index 9a9d13086..7713da11c 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -36,3 +36,6 @@ extern int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value); extern int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state); + +/* Internal sanity checking functions */ +extern int SDL_PrivateJoystickValid(SDL_Joystick ** joystick); diff --git a/src/joystick/darwin/SDL_sysjoystick.c b/src/joystick/darwin/SDL_sysjoystick.c index 461639408..b066a7bee 100644 --- a/src/joystick/darwin/SDL_sysjoystick.c +++ b/src/joystick/darwin/SDL_sysjoystick.c @@ -46,60 +46,15 @@ #include #include /* for NewPtrClear, DisposePtr */ +/* For force feedback testing. */ +#include +#include + + #include "SDL_joystick.h" #include "../SDL_sysjoystick.h" #include "../SDL_joystick_c.h" - -struct recElement -{ - IOHIDElementCookie cookie; /* unique value which identifies element, will NOT change */ - long min; /* reported min value possible */ - long max; /* reported max value possible */ -#if 0 - /* TODO: maybe should handle the following stuff somehow? */ - - long scaledMin; /* reported scaled min value possible */ - long scaledMax; /* reported scaled max value possible */ - long size; /* size in bits of data return from element */ - Boolean relative; /* are reports relative to last report (deltas) */ - Boolean wrapping; /* does element wrap around (one value higher than max is min) */ - Boolean nonLinear; /* are the values reported non-linear relative to element movement */ - Boolean preferredState; /* does element have a preferred state (such as a button) */ - Boolean nullState; /* does element have null state */ -#endif /* 0 */ - - /* runtime variables used for auto-calibration */ - long minReport; /* min returned value */ - long maxReport; /* max returned value */ - - struct recElement * pNext; /* next element in list */ -}; -typedef struct recElement recElement; - -struct joystick_hwdata -{ - IOHIDDeviceInterface ** interface; /* interface to device, NULL = no interface */ - - char product[256]; /* name of product */ - long usage; /* usage page from IOUSBHID Parser.h which defines general usage */ - long usagePage; /* usage within above page from IOUSBHID Parser.h which defines specific usage */ - - long axes; /* number of axis (calculated, not reported by device) */ - long buttons; /* number of buttons (calculated, not reported by device) */ - long hats; /* number of hat switches (calculated, not reported by device) */ - long elements; /* number of total elements (shouldbe total of above) (calculated, not reported by device) */ - - recElement* firstAxis; - recElement* firstButton; - recElement* firstHat; - - int removed; - int uncentered; - - struct joystick_hwdata* pNext; /* next device */ -}; -typedef struct joystick_hwdata recDevice; - +#include "SDL_sysjoystick_c.h" /* Linked list of all available devices */ static recDevice *gpDeviceList = NULL; @@ -552,7 +507,13 @@ static recDevice *HIDDisposeDevice (recDevice **ppDevice) { /* save next device prior to disposing of this device */ pDeviceNext = (*ppDevice)->pNext; - + + /* free posible io_service_t */ + if ((*ppDevice)->ffservice) { + IOObjectRelease((*ppDevice)->ffservice); + (*ppDevice)->ffservice = 0; + } + /* free element lists */ HIDDisposeElementList (&(*ppDevice)->firstAxis); HIDDisposeElementList (&(*ppDevice)->firstButton); @@ -672,6 +633,16 @@ int SDL_SYS_JoystickInit(void) CFRelease(hidProperties); if (!device) continue; + + /* We have to do some storage of the io_service_t for + * SDL_HapticOpenFromJoystick */ + if (FFIsForceFeedback(ioHIDDeviceObject) == FF_OK) { + device->ffservice = ioHIDDeviceObject; + } + else { + device->ffservice = 0; + } + /* Add device to the end of the list */ if (lastDevice) lastDevice->pNext = device; diff --git a/src/joystick/darwin/SDL_sysjoystick_c.h b/src/joystick/darwin/SDL_sysjoystick_c.h new file mode 100644 index 000000000..a48e936b3 --- /dev/null +++ b/src/joystick/darwin/SDL_sysjoystick_c.h @@ -0,0 +1,87 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2004 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifndef SDL_JOYSTICK_IOKIT_H + + +#if MAC_OS_X_VERSION_MIN_REQUIRED == 1030 +#include "10.3.9-FIX/IOHIDLib.h" +#else +#include +#endif +#include + + +struct recElement +{ + IOHIDElementCookie cookie; /* unique value which identifies element, will NOT change */ + long min; /* reported min value possible */ + long max; /* reported max value possible */ +#if 0 + /* TODO: maybe should handle the following stuff somehow? */ + + long scaledMin; /* reported scaled min value possible */ + long scaledMax; /* reported scaled max value possible */ + long size; /* size in bits of data return from element */ + Boolean relative; /* are reports relative to last report (deltas) */ + Boolean wrapping; /* does element wrap around (one value higher than max is min) */ + Boolean nonLinear; /* are the values reported non-linear relative to element movement */ + Boolean preferredState; /* does element have a preferred state (such as a button) */ + Boolean nullState; /* does element have null state */ +#endif /* 0 */ + + /* runtime variables used for auto-calibration */ + long minReport; /* min returned value */ + long maxReport; /* max returned value */ + + struct recElement *pNext; /* next element in list */ +}; +typedef struct recElement recElement; + +struct joystick_hwdata +{ + io_service_t ffservice; /* Interface for force feedback, 0 = no ff */ + IOHIDDeviceInterface **interface; /* interface to device, NULL = no interface */ + + char product[256]; /* name of product */ + long usage; /* usage page from IOUSBHID Parser.h which defines general usage */ + long usagePage; /* usage within above page from IOUSBHID Parser.h which defines specific usage */ + + long axes; /* number of axis (calculated, not reported by device) */ + long buttons; /* number of buttons (calculated, not reported by device) */ + long hats; /* number of hat switches (calculated, not reported by device) */ + long elements; /* number of total elements (shouldbe total of above) (calculated, not reported by device) */ + + recElement *firstAxis; + recElement *firstButton; + recElement *firstHat; + + int removed; + int uncentered; + + struct joystick_hwdata *pNext; /* next device */ +}; +typedef struct joystick_hwdata recDevice; + + +#endif /* SDL_JOYSTICK_IOKIT_H */ diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index 18b5761c4..ddf721f18 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -32,13 +32,11 @@ #include #include /* For the definition of PATH_MAX */ #include -#if SDL_INPUT_LINUXEV -#include -#endif #include "SDL_joystick.h" #include "../SDL_sysjoystick.h" #include "../SDL_joystick_c.h" +#include "SDL_sysjoystick_c.h" /* Special joystick configurations */ static struct { @@ -272,32 +270,6 @@ static struct } SDL_joylist[MAX_JOYSTICKS]; -/* The private structure used to keep track of a joystick */ -struct joystick_hwdata { - int fd; - /* The current linux joystick driver maps hats to two axes */ - struct hwdata_hat { - int axis[2]; - } *hats; - /* The current linux joystick driver maps balls to two axes */ - struct hwdata_ball { - int axis[2]; - } *balls; - - /* Support for the Linux 2.4 unified input interface */ -#if SDL_INPUT_LINUXEV - SDL_bool is_hid; - Uint8 key_map[KEY_MAX-BTN_MISC]; - Uint8 abs_map[ABS_MAX]; - struct axis_correct { - int used; - int minimum; - int maximum; - } abs_correct[ABS_MAX]; -#endif -}; - - #ifndef NO_LOGICAL_JOYSTICKS static int CountLogicalJoysticks(int max) @@ -787,6 +759,7 @@ static void ConfigLogicalJoystick(SDL_Joystick *joystick) int SDL_SYS_JoystickOpen(SDL_Joystick *joystick) { int fd; + char *fname; SDL_logical_joydecl(int realindex); SDL_logical_joydecl(SDL_Joystick *realjoy = NULL); @@ -800,9 +773,11 @@ int SDL_SYS_JoystickOpen(SDL_Joystick *joystick) return(-1); fd = realjoy->hwdata->fd; + fname = realjoy->hwdata->fname; } else { fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0); + fname = SDL_joylist[joystick->index].fname; } SDL_joylist[joystick->index].joy = joystick; #else @@ -822,10 +797,8 @@ int SDL_SYS_JoystickOpen(SDL_Joystick *joystick) return(-1); } SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata)); -#if SDL_INPUT_LINUXEV - SDL_memset(joystick->hwdata->abs_map, ABS_MAX, sizeof(*joystick->hwdata->abs_map)*ABS_MAX); -#endif joystick->hwdata->fd = fd; + joystick->hwdata->fname = fname; /* Set the joystick to non-blocking read mode */ fcntl(fd, F_SETFL, O_NONBLOCK); diff --git a/src/joystick/linux/SDL_sysjoystick_c.h b/src/joystick/linux/SDL_sysjoystick_c.h new file mode 100644 index 000000000..a6ace615a --- /dev/null +++ b/src/joystick/linux/SDL_sysjoystick_c.h @@ -0,0 +1,55 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2006 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +#if SDL_INPUT_LINUXEV +#include +#endif + +/* The private structure used to keep track of a joystick */ +struct joystick_hwdata +{ + int fd; + char *fname; /* Used in haptic subsystem */ + + /* The current linux joystick driver maps hats to two axes */ + struct hwdata_hat + { + int axis[2]; + } *hats; + /* The current linux joystick driver maps balls to two axes */ + struct hwdata_ball + { + int axis[2]; + } *balls; + + /* Support for the Linux 2.4 unified input interface */ +#if SDL_INPUT_LINUXEV + SDL_bool is_hid; + Uint8 key_map[KEY_MAX - BTN_MISC]; + Uint8 abs_map[ABS_MAX]; + struct axis_correct + { + int used; + int coef[3]; + } abs_correct[ABS_MAX]; +#endif +}; \ No newline at end of file diff --git a/src/joystick/win32/SDL_dxjoystick_c.h b/src/joystick/win32/SDL_dxjoystick_c.h new file mode 100644 index 000000000..7501a280f --- /dev/null +++ b/src/joystick/win32/SDL_dxjoystick_c.h @@ -0,0 +1,81 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2006 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifndef SDL_JOYSTICK_DINPUT_H + +/* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de + * A. Formiga's WINMM driver. + * + * Hats and sliders are completely untested; the app I'm writing this for mostly + * doesn't use them and I don't own any joysticks with them. + * + * We don't bother to use event notification here. It doesn't seem to work + * with polled devices, and it's fine to call IDirectInputDevice2_GetDeviceData and + * let it return 0 events. */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define DIRECTINPUT_VERSION 0x0700 /* Need version 7 for force feedback. */ +#include +#ifdef _MSC_VER + /* Used for the c_dfDIJoystick2 symbol (no imports are used) */ +# pragma comment (lib, "dinput.lib") +#endif +#include +#ifdef _MSC_VER +# pragma comment (lib, "dxerr8.lib") +#endif + + +#define MAX_INPUTS 256 /* each joystick can have up to 256 inputs */ + + +/* local types */ +typedef enum Type +{ BUTTON, AXIS, HAT } Type; + +typedef struct input_t +{ + /* DirectInput offset for this input type: */ + DWORD ofs; + + /* Button, axis or hat: */ + Type type; + + /* SDL input offset: */ + Uint8 num; +} input_t; + +/* The private structure used to keep track of a joystick */ +struct joystick_hwdata +{ + LPDIRECTINPUTDEVICE2 InputDevice; + DIDEVCAPS Capabilities; + int buffered; + + input_t Inputs[MAX_INPUTS]; + int NumInputs; +}; + +#endif /* SDL_JOYSTICK_DINPUT_H */ diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index a98fdc3db..45c005bff 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -281,6 +281,7 @@ struct SDL_VideoDevice { int green_size; int blue_size; int alpha_size; + int pixel_type_rgba_float; int depth_size; int buffer_size; int stencil_size; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 4618f5dec..dbd2a4dcf 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -243,6 +243,7 @@ int SDL_VideoInit (const char *driver_name, Uint32 flags) video->gl_config.green_size = 3; video->gl_config.blue_size = 2; video->gl_config.alpha_size = 0; + video->gl_config.pixel_type_rgba_float = 0; video->gl_config.buffer_size = 0; video->gl_config.depth_size = 16; video->gl_config.stencil_size = 0; @@ -1481,6 +1482,9 @@ int SDL_GL_SetAttribute( SDL_GLattr attr, int value ) case SDL_GL_ALPHA_SIZE: video->gl_config.alpha_size = value; break; + case SDL_GL_PIXEL_TYPE_FLOAT: + video->gl_config.pixel_type_rgba_float = value; + break; case SDL_GL_DOUBLEBUFFER: video->gl_config.double_buffer = value; break; diff --git a/src/video/wincommon/SDL_wingl.c b/src/video/wincommon/SDL_wingl.c index 6a22ea39f..f62806ae7 100644 --- a/src/video/wincommon/SDL_wingl.c +++ b/src/video/wincommon/SDL_wingl.c @@ -241,6 +241,11 @@ int WIN_GL_SetupWindow(_THIS) *iAttr++ = this->gl_config.alpha_size; } + if ( this->gl_config.pixel_type_rgba_float ) { + *iAttr++ = WGL_PIXEL_TYPE_ARB; + *iAttr++ = WGL_TYPE_RGBA_FLOAT_ARB; + } + *iAttr++ = WGL_DOUBLE_BUFFER_ARB; *iAttr++ = this->gl_config.double_buffer; @@ -477,15 +482,26 @@ int WIN_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value) case SDL_GL_MULTISAMPLESAMPLES: wgl_attrib = WGL_SAMPLES_ARB; break; - case SDL_GL_ACCELERATED_VISUAL: - wgl_attrib = WGL_ACCELERATION_ARB; - this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value); - if ( *value == WGL_NO_ACCELERATION_ARB ) { - *value = SDL_FALSE; - } else { - *value = SDL_TRUE; + case SDL_GL_ACCELERATED_VISUAL: { + wgl_attrib = WGL_ACCELERATION_ARB; + this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value); + if ( *value == WGL_NO_ACCELERATION_ARB ) { + *value = SDL_FALSE; + } else { + *value = SDL_TRUE; + } + return 0; + } + case SDL_GL_PIXEL_TYPE_FLOAT: { + wgl_attrib = WGL_PIXEL_TYPE_ARB; + this->gl_data->wglGetPixelFormatAttribivARB(GL_hdc, pixel_format, 0, 1, &wgl_attrib, value); + if ( *value == WGL_TYPE_RGBA_FLOAT_ARB ) { + *value = SDL_TRUE; + } else { + *value = SDL_FALSE; + } + return 0; } - return 0; default: return(-1); } @@ -557,6 +573,10 @@ int WIN_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value) return -1; } break; + case SDL_GL_PIXEL_TYPE_FLOAT: + // cannot query attribute unless WGL_ARB_pixel_format is 1 + *value = -1; + break; default: retval = -1; break; diff --git a/src/video/wincommon/SDL_wingl_c.h b/src/video/wincommon/SDL_wingl_c.h index c3f2291db..9a246cb92 100644 --- a/src/video/wincommon/SDL_wingl_c.h +++ b/src/video/wincommon/SDL_wingl_c.h @@ -124,6 +124,7 @@ extern void *WIN_GL_GetProcAddress(_THIS, const char* proc); #define WGL_SWAP_COPY_ARB 0x2029 #define WGL_SWAP_UNDEFINED_ARB 0x202A #define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 #define WGL_TYPE_COLORINDEX_ARB 0x202C #endif diff --git a/test/Makefile.in b/test/Makefile.in index c4414b142..835b67d73 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -7,10 +7,13 @@ EXE = @EXE@ CFLAGS = @CFLAGS@ LIBS = @LIBS@ -TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcdrom$(EXE) testcursor$(EXE) testdyngl$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) threadwin$(EXE) torturethread$(EXE) testloadso$(EXE) +TARGETS = testhaptic$(EXE) checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcdrom$(EXE) testcursor$(EXE) testdyngl$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) threadwin$(EXE) torturethread$(EXE) testloadso$(EXE) all: $(TARGETS) +testhaptic$(EXE): $(srcdir)/testhaptic.c + $(CC) -o $@ $? $(CFLAGS) $(LIBS) + checkkeys$(EXE): $(srcdir)/checkkeys.c $(CC) -o $@ $? $(CFLAGS) $(LIBS) diff --git a/test/testhaptic.c b/test/testhaptic.c new file mode 100644 index 000000000..f49dbd105 --- /dev/null +++ b/test/testhaptic.c @@ -0,0 +1,247 @@ +/* +Copyright (c) 2008, Edgar Simo Serra +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 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. + * 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. + +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. +*/ + +/* + * includes + */ +#include "SDL.h" +#include "SDL_haptic.h" + +#include /* printf */ +#include /* strstr */ + + + +static SDL_Haptic *haptic; + + +/* + * prototypes + */ +static void abort_execution (void); +static void HapticPrintSupported( SDL_Haptic * haptic ); + + +/** + * @brief The entry point of this force feedback demo. + * @param[in] argc Number of arguments. + * @param[in] argv Array of argc arguments. + */ +int main( int argc, char** argv ) +{ + int i; + char *name; + SDL_HapticEffect efx[5]; + int id[5]; + int nefx; + unsigned int supported; + + name = NULL; + if (argc > 1) { + name = argv[1]; + if ((strcmp(name,"--help")==0) || (strcmp(name,"-h")==0)) { + printf("USAGE: %s [device name]\n" + "If device name is specified, it will try to find a device whose name\n" + "contains device name for testing.\n", argv[0]); + return 0; + } + } + + /* Initialize the force feedbackness */ + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC); + printf("%d Haptic devices detected.\n", SDL_NumHaptics()); + if (SDL_NumHaptics() > 0) { + /* We'll just use the first force feedback device found */ + if (name == NULL) { + i = 0; + } + /* Try to find matching device */ + else { + for (i=0; i= SDL_NumHaptics()) { + printf("Unable to find device matching '%s', aborting.\n", name); + return 1; + } + } + + haptic = SDL_HapticOpen(i); + if (haptic==NULL) { + perror("Unable to create the haptic device"); + return 1; + } + printf("Device: %s\n",SDL_HapticName(i)); + HapticPrintSupported(haptic); + } + else { + printf("No Haptic devices found!\n"); + return 1; + } + + /* We only want force feedback errors. */ + SDL_ClearError(); + + /* Create effects. */ + memset(&efx,0,sizeof(efx)); + nefx = 0; + supported = SDL_HapticQuery(haptic); + + printf("\nUploading effects\n"); + /* First we'll try a SINE effect. */ + if (supported & SDL_HAPTIC_SINE) { + printf(" effect %d: Sine Wave\n",nefx); + efx[nefx].type = SDL_HAPTIC_SINE; + efx[nefx].periodic.period = 1000; + efx[nefx].periodic.magnitude = 0x4000; + efx[nefx].periodic.length = 5000; + efx[nefx].periodic.attack_length = 1000; + efx[nefx].periodic.fade_length = 1000; + id[nefx] = SDL_HapticNewEffect(haptic,&efx[nefx]); + if (id[nefx] < 0) { + printf("UPLOADING EFFECT ERROR: %s\n",SDL_GetError()); + abort_execution(); + } + nefx++; + } + /* Now we'll try a SAWTOOTHUP */ + if (supported & SDL_HAPTIC_SAWTOOTHUP) { + printf(" effect %d: Sawtooth Up\n",nefx); + efx[nefx].type = SDL_HAPTIC_SQUARE; + efx[nefx].periodic.period = 500; + efx[nefx].periodic.magnitude = 0x5000; + efx[nefx].periodic.length = 5000; + efx[nefx].periodic.attack_length = 1000; + efx[nefx].periodic.fade_length = 1000; + id[nefx] = SDL_HapticNewEffect(haptic,&efx[nefx]); + if (id[nefx] < 0) { + printf("UPLOADING EFFECT ERROR: %s\n",SDL_GetError()); + abort_execution(); + } + nefx++; + } + /* Now the classical constant effect. */ + if (supported & SDL_HAPTIC_CONSTANT) { + printf(" effect %d: Constant Force\n",nefx); + efx[nefx].type = SDL_HAPTIC_CONSTANT; + efx[nefx].constant.direction.type = SDL_HAPTIC_POLAR; + efx[nefx].constant.direction.dir[0] = 20000; /* Force comes from the south-west. */ + efx[nefx].constant.length = 5000; + efx[nefx].constant.level = 0x6000; + efx[nefx].constant.attack_length = 1000; + efx[nefx].constant.fade_length = 1000; + id[nefx] = SDL_HapticNewEffect(haptic,&efx[nefx]); + if (id[nefx] < 0) { + printf("UPLOADING EFFECT ERROR: %s\n",SDL_GetError()); + abort_execution(); + } + nefx++; + } + /* The cute spring effect. */ + if (supported & SDL_HAPTIC_SPRING) { + printf(" effect %d: Condition Spring\n",nefx); + efx[nefx].type = SDL_HAPTIC_SPRING; + efx[nefx].condition.length = 5000; + for (i=0; i Date: Fri, 15 Aug 2025 09:02:15 +1200 Subject: [PATCH 2/4] Missing files, forward reference fixes and adding additional libs to allow SDL to compile and link --- configure | 580 +++++------ configure.ac | 2 +- sdl-config.in | 2 +- src/SDL_HelperWindow.c | 47 +- src/haptic/SDL_haptic.c | 689 +++++++++++++ src/haptic/SDL_syshaptic.h | 202 ++++ src/haptic/darwin/SDL_syshaptic.c | 1284 +++++++++++++++++++++++ src/haptic/darwin/SDL_syshaptic.c.bak | 1284 +++++++++++++++++++++++ src/haptic/dummy/SDL_syshaptic.c | 193 ++++ src/haptic/dummy/SDL_syshaptic.c.bak | 193 ++++ src/haptic/linux/SDL_syshaptic.c | 961 +++++++++++++++++ src/haptic/linux/SDL_syshaptic.c.bak | 961 +++++++++++++++++ src/haptic/win32/SDL_syshaptic.c | 1368 +++++++++++++++++++++++++ test/configure | 84 +- 14 files changed, 7477 insertions(+), 373 deletions(-) create mode 100644 src/haptic/SDL_haptic.c create mode 100644 src/haptic/SDL_syshaptic.h create mode 100644 src/haptic/darwin/SDL_syshaptic.c create mode 100644 src/haptic/darwin/SDL_syshaptic.c.bak create mode 100644 src/haptic/dummy/SDL_syshaptic.c create mode 100644 src/haptic/dummy/SDL_syshaptic.c.bak create mode 100644 src/haptic/linux/SDL_syshaptic.c create mode 100644 src/haptic/linux/SDL_syshaptic.c.bak create mode 100644 src/haptic/win32/SDL_syshaptic.c diff --git a/configure b/configure index c3e4657c6..16a643671 100755 --- a/configure +++ b/configure @@ -923,6 +923,7 @@ enable_audio enable_video enable_events enable_joystick +enable_haptic enable_cdrom enable_threads enable_timers @@ -1653,6 +1654,8 @@ Optional Features: --enable-video Enable the video subsystem [default=yes] --enable-events Enable the events subsystem [default=yes] --enable-joystick Enable the joystick subsystem [default=yes] + --enable-haptic Enable the haptic (force feedback) subsystem + [[default=yes]] --enable-cdrom Enable the cdrom subsystem [default=yes] --enable-threads Enable the threading subsystem [default=yes] --enable-timers Enable the timer subsystem [default=yes] @@ -2027,8 +2030,8 @@ fi # ac_fn_c_try_run LINENO # ---------------------- -# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that -# executables *can* be run. +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack @@ -2162,7 +2165,7 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. + which can conflict with char $2 (void); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ @@ -2180,7 +2183,7 @@ else #ifdef __cplusplus extern "C" #endif -char $2 (); +char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ @@ -2189,7 +2192,7 @@ choke me #endif int -main () +main (void) { return $2 (); ; @@ -2349,7 +2352,7 @@ else /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof ($2)) return 0; @@ -2362,7 +2365,7 @@ if ac_fn_c_try_compile "$LINENO"; then : /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof (($2))) return 0; @@ -2402,7 +2405,7 @@ else /* end confdefs.h. */ $5 int -main () +main (void) { static $2 ac_aggr; if (ac_aggr.$3) @@ -2418,7 +2421,7 @@ else /* end confdefs.h. */ $5 int -main () +main (void) { static $2 ac_aggr; if (sizeof ac_aggr.$3) @@ -2457,7 +2460,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; @@ -2474,7 +2477,7 @@ if ac_fn_c_try_compile "$LINENO"; then : /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2501,7 +2504,7 @@ else /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; @@ -2518,7 +2521,7 @@ if ac_fn_c_try_compile "$LINENO"; then : /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; @@ -2553,7 +2556,7 @@ while test "x$ac_lo" != "x$ac_hi"; do /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2578,12 +2581,12 @@ esac cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } +static long int longval (void) { return $2; } +static unsigned long int ulongval (void) { return $2; } #include #include int -main () +main (void) { FILE *f = fopen ("conftest.val", "w"); @@ -2736,8 +2739,6 @@ done # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? - # Sanitize IFS. - IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo @@ -3314,7 +3315,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3454,11 +3455,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); - if (!f) - return 1; return ferror (f) || fclose (f) != 0; ; @@ -3470,9 +3469,7 @@ ac_clean_files="$ac_clean_files conftest.out" # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" = maybe && test "x$build" != "x$host"; then - cross_compiling=yes -elif test "$cross_compiling" != yes; then +if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; @@ -3522,7 +3519,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -3573,7 +3570,7 @@ else /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3614,7 +3611,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -3629,7 +3626,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -3645,7 +3642,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -3694,9 +3691,7 @@ struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; +static char *e (char **p, int i) { return p[i]; } @@ -3731,7 +3726,7 @@ int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, i int argc; char **argv; int -main () +main (void) { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; @@ -4057,7 +4052,7 @@ else #include int -main () +main (void) { ; @@ -4127,7 +4122,7 @@ else #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int -main () +main (void) { int i; for (i = 0; i < 256; i++) @@ -4206,7 +4201,7 @@ else # define __EXTENSIONS__ 1 $ac_includes_default int -main () +main (void) { ; @@ -4839,13 +4834,13 @@ if ${lt_cv_nm_interface+:} false; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:4842: $ac_compile\"" >&5) + (eval echo "\"\$as_me:4837: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:4845: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:4840: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:4848: output\"" >&5) + (eval echo "\"\$as_me:4843: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -6058,7 +6053,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 6061 "configure"' > conftest.$ac_ext + echo '#line 6056 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -6168,7 +6163,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu /* end confdefs.h. */ int -main () +main (void) { ; @@ -6754,7 +6749,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -6786,7 +6781,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -7653,11 +7648,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7656: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7651: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7660: \$? = $ac_status" >&5 + echo "$as_me:7655: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -8002,11 +7997,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:8005: $lt_compile\"" >&5) + (eval echo "\"\$as_me:8000: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:8009: \$? = $ac_status" >&5 + echo "$as_me:8004: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -8107,11 +8102,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:8110: $lt_compile\"" >&5) + (eval echo "\"\$as_me:8105: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:8114: \$? = $ac_status" >&5 + echo "$as_me:8109: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -8162,11 +8157,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:8165: $lt_compile\"" >&5) + (eval echo "\"\$as_me:8160: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:8169: \$? = $ac_status" >&5 + echo "$as_me:8164: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -8695,7 +8690,7 @@ _LT_EOF /* end confdefs.h. */ int -main () +main (void) { ; @@ -8735,7 +8730,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi /* end confdefs.h. */ int -main () +main (void) { ; @@ -9915,7 +9910,7 @@ linux* | k*bsd*-gnu) /* end confdefs.h. */ int -main () +main (void) { ; @@ -10353,9 +10348,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char dlopen (); +char dlopen (void); int -main () +main (void) { return dlopen (); ; @@ -10406,9 +10401,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char shl_load (); +char shl_load (void); int -main () +main (void) { return shl_load (); ; @@ -10449,9 +10444,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char dlopen (); +char dlopen (void); int -main () +main (void) { return dlopen (); ; @@ -10488,9 +10483,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char dlopen (); +char dlopen (void); int -main () +main (void) { return dlopen (); ; @@ -10527,9 +10522,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char dld_link (); +char dld_link (void); int -main () +main (void) { return dld_link (); ; @@ -10597,7 +10592,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10600 "configure" +#line 10595 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10693,7 +10688,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10696 "configure" +#line 10691 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10981,7 +10976,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include int -main () +main (void) { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ @@ -11001,7 +10996,7 @@ if ac_fn_c_try_compile "$LINENO"; then : #include int -main () +main (void) { #if BYTE_ORDER != BIG_ENDIAN not big endian @@ -11027,7 +11022,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include int -main () +main (void) { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros @@ -11044,7 +11039,7 @@ if ac_fn_c_try_compile "$LINENO"; then : #include int -main () +main (void) { #ifndef _BIG_ENDIAN not big endian @@ -11069,36 +11064,35 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -unsigned short int ascii_mm[] = +short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; - unsigned short int ascii_ii[] = + short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } - unsigned short int ebcdic_ii[] = + short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; - unsigned short int ebcdic_mm[] = + short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } - int - main (int argc, char **argv) - { - /* Intimidate the compiler so that it does not - optimize the arrays away. */ - char *p = argv[0]; - ascii_mm[1] = *p++; ebcdic_mm[1] = *p++; - ascii_ii[1] = *p++; ebcdic_ii[1] = *p++; - return use_ascii (argc) == use_ebcdic (*p); - } + extern int foo; + +int +main (void) +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - if grep BIGenDianSyS conftest$ac_exeext >/dev/null; then +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi - if grep LiTTleEnDian conftest$ac_exeext >/dev/null ; then + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else @@ -11107,14 +11101,13 @@ if ac_fn_c_try_link "$LINENO"; then : fi fi fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int -main () +main (void) { /* Are we little or big endian? From Harbison&Steele. */ @@ -11504,7 +11497,7 @@ else /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -11545,7 +11538,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -11560,7 +11553,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -11576,7 +11569,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -11625,9 +11618,7 @@ struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; +static char *e (char **p, int i) { return p[i]; } @@ -11662,7 +11653,7 @@ int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, i int argc; char **argv; int -main () +main (void) { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; @@ -11851,7 +11842,7 @@ else /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -11892,7 +11883,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -11907,7 +11898,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -11923,7 +11914,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -12109,7 +12100,7 @@ else /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -12150,7 +12141,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -12165,7 +12156,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -12181,7 +12172,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -12746,7 +12737,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie /* end confdefs.h. */ int -main () +main (void) { ; @@ -12787,7 +12778,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi /* end confdefs.h. */ int -main () +main (void) { ; @@ -14144,11 +14135,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14147: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14138: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14151: \$? = $ac_status" >&5 + echo "$as_me:14142: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -14243,11 +14234,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14246: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14237: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14250: \$? = $ac_status" >&5 + echo "$as_me:14241: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -14295,11 +14286,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14298: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14289: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14302: \$? = $ac_status" >&5 + echo "$as_me:14293: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -14886,7 +14877,7 @@ linux* | k*bsd*-gnu) /* end confdefs.h. */ int -main () +main (void) { ; @@ -15666,7 +15657,7 @@ else /* end confdefs.h. */ int -main () +main (void) { #ifndef __cplusplus @@ -15749,8 +15740,8 @@ for ac_kw in inline __inline__ __inline; do /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; -static $ac_kw foo_t static_foo () {return 0; } -$ac_kw foo_t foo () {return 0; } +static $ac_kw foo_t static_foo (void) {return 0; } +$ac_kw foo_t foo (void) {return 0; } #endif _ACEOF @@ -15789,7 +15780,7 @@ else /* end confdefs.h. */ int -main () +main (void) { volatile int x; @@ -15839,7 +15830,7 @@ else #include int -main () +main (void) { ; @@ -15909,7 +15900,7 @@ else #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int -main () +main (void) { int i; for (i = 0; i < 256; i++) @@ -15987,7 +15978,7 @@ else /* end confdefs.h. */ #include int -main () +main (void) { char *p = (char *) alloca (2 * sizeof (int)); if (p) return 0; @@ -16015,32 +16006,32 @@ fi $as_echo_n "checking for alloca... " >&6; } if ${ac_cv_func_alloca_works+:} false; then : $as_echo_n "(cached) " >&6 -else - if test $ac_cv_working_alloca_h = yes; then - ac_cv_func_alloca_works=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#if defined STDC_HEADERS || defined HAVE_STDLIB_H -# include -#endif -#include -#ifndef alloca -# ifdef __GNUC__ -# define alloca __builtin_alloca -# elif defined _MSC_VER +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER # include # define alloca _alloca # else -# ifdef __cplusplus -extern "C" -# endif +# ifdef HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ void *alloca (size_t); +# endif +# endif +# endif # endif #endif int -main () +main (void) { char *p = (char *) alloca (1); if (p) return 0; @@ -16052,13 +16043,10 @@ if ac_fn_c_try_link "$LINENO"; then : ac_cv_func_alloca_works=yes else ac_cv_func_alloca_works=no - fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi - -fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 $as_echo "$ac_cv_func_alloca_works" >&6; } @@ -16175,7 +16163,7 @@ if test "x$ac_cv_func_mprotect" = xyes; then : #include int -main () +main (void) { ; @@ -16220,9 +16208,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char libiconv_open (); +char libiconv_open (void); int -main () +main (void) { return libiconv_open (); ; @@ -16260,9 +16248,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char pow (); +char pow (void); int -main () +main (void) { return pow (); ; @@ -16574,6 +16562,19 @@ if test x$enable_joystick != xyes; then else SOURCES="$SOURCES $srcdir/src/joystick/*.c" fi +# Check whether --enable-haptic was given. +if test "${enable_haptic+set}" = set; then : + enableval=$enable_haptic; +else + enable_haptic=yes +fi + +if test x$enable_haptic != xyes; then + $as_echo "#define SDL_HAPTIC_DISABLED 1" >>confdefs.h + +else + SOURCES="$SOURCES $srcdir/src/haptic/*.c" +fi # Check whether --enable-cdrom was given. if test "${enable_cdrom+set}" = set; then : enableval=$enable_cdrom; @@ -16672,7 +16673,7 @@ $as_echo_n "checking for OSS audio support... " >&6; } #include int -main () +main (void) { int arg = SNDCTL_DSP_SETFRAGMENT; @@ -16693,7 +16694,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext #include int -main () +main (void) { int arg = SNDCTL_DSP_SETFRAGMENT; @@ -16818,7 +16819,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #include int -main () +main (void) { /* ensure backward compatibility */ @@ -16892,9 +16893,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char snd_ctl_open (); +char snd_ctl_open (void); int -main () +main (void) { return snd_ctl_open (); ; @@ -16995,7 +16996,7 @@ $as_echo_n "checking for dmedia audio support... " >&6; } #include int -main () +main (void) { ALport audio_port; @@ -17044,7 +17045,7 @@ $as_echo_n "checking for MME audio support... " >&6; } #include int -main () +main (void) { HWAVEOUT sound; @@ -17277,7 +17278,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu #include int -main () +main (void) { return 0; ; @@ -17386,9 +17387,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char sio_open (); +char sio_open (void); int -main () +main (void) { return sio_open (); ; @@ -17623,7 +17624,7 @@ $as_echo_n "checking for aRts development environment... " >&6; } #include int -main () +main (void) { arts_stream_t stream; @@ -17706,9 +17707,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char AuOpenServer (); +char AuOpenServer (void); int -main () +main (void) { return AuOpenServer (); ; @@ -18032,7 +18033,7 @@ $as_echo_n "checking for Altivec with GCC altivec.h and -maltivec option... " >& } int -main () +main (void) { ; @@ -18060,7 +18061,7 @@ $as_echo_n "checking for Altivec with GCC -maltivec option... " >&6; } } int -main () +main (void) { ; @@ -18113,7 +18114,7 @@ $as_echo_n "checking for Altivec with GCC -faltivec option... " >&6; } } int -main () +main (void) { ; @@ -18253,7 +18254,7 @@ $as_echo_n "checking for GCC -fvisibility=hidden option... " >&6; } #endif int -main () +main (void) { ; @@ -18285,7 +18286,7 @@ $as_echo_n "checking for GCC -Wall option... " >&6; } /* end confdefs.h. */ int x = 0; int -main () +main (void) { ; @@ -18429,34 +18430,8 @@ else $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. -ac_x_includes=no -ac_x_libraries=no -# Do we need to do anything special at all? -ac_save_LIBS=$LIBS -LIBS="-lX11 $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -XrmInitialize () - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - # We can compile and link X programs with no special options. - ac_x_includes= - ac_x_libraries= -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS="$ac_save_LIBS" -# If that didn't work, only try xmkmf and filesystem searches -# for native compilation. -if test x"$ac_x_includes" = xno && test "$cross_compiling" = no; then : - rm -f -r conftest.dir +ac_x_includes=no ac_x_libraries=no +rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' @@ -18495,7 +18470,7 @@ _ACEOF rm -f -r conftest.dir fi - # Standard set of common directories for X headers. +# Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include @@ -18522,8 +18497,6 @@ ac_x_header_dirs=' /usr/local/include/X11R5 /usr/local/include/X11R4 -/opt/X11/include - /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 @@ -18569,7 +18542,7 @@ if test "$ac_x_libraries" = no; then /* end confdefs.h. */ #include int -main () +main (void) { XrmInitialize () ; @@ -18597,17 +18570,15 @@ rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no -fi -# Record the results. case $ac_x_includes,$ac_x_libraries in #( - no,* | *,no | *\'*) : + no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. - ac_cv_have_x="have_x=no" ;; #( - *) : + ac_cv_have_x="have_x=no";; #( + *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ - ac_x_libraries='$ac_x_libraries'" ;; + ac_x_libraries='$ac_x_libraries'" esac fi ;; #( @@ -18657,7 +18628,7 @@ $as_echo_n "checking whether -R must be followed by a space... " >&6; } /* end confdefs.h. */ int -main () +main (void) { ; @@ -18674,7 +18645,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -18718,9 +18689,9 @@ rm -f core conftest.err conftest.$ac_objext \ #ifdef __cplusplus extern "C" #endif -char XOpenDisplay (); +char XOpenDisplay (void); int -main () +main (void) { return XOpenDisplay (); ; @@ -18746,9 +18717,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char dnet_ntoa (); +char dnet_ntoa (void); int -main () +main (void) { return dnet_ntoa (); ; @@ -18787,9 +18758,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char dnet_ntoa (); +char dnet_ntoa (void); int -main () +main (void) { return dnet_ntoa (); ; @@ -18847,9 +18818,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char gethostbyname (); +char gethostbyname (void); int -main () +main (void) { return gethostbyname (); ; @@ -18888,9 +18859,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char gethostbyname (); +char gethostbyname (void); int -main () +main (void) { return gethostbyname (); ; @@ -18944,9 +18915,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char connect (); +char connect (void); int -main () +main (void) { return connect (); ; @@ -18993,9 +18964,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char remove (); +char remove (void); int -main () +main (void) { return remove (); ; @@ -19042,9 +19013,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char shmat (); +char shmat (void); int -main () +main (void) { return shmat (); ; @@ -19094,9 +19065,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char IceConnectionNumber (); +char IceConnectionNumber (void); int -main () +main (void) { return IceConnectionNumber (); ; @@ -19342,9 +19313,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char XRenderQueryExtension (); +char XRenderQueryExtension (void); int -main () +main (void) { return XRenderQueryExtension (); ; @@ -19382,9 +19353,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char XRRQueryExtension (); +char XRRQueryExtension (void); int -main () +main (void) { return XRRQueryExtension (); ; @@ -19427,7 +19398,7 @@ $as_echo_n "checking for const parameter to _XData32... " >&6; } extern int _XData32(Display *dpy,register _Xconst long *data,unsigned len); int -main () +main (void) { ; @@ -19470,7 +19441,7 @@ $as_echo_n "checking for QNX Photon support... " >&6; } #include int -main () +main (void) { PgDisplaySettings_t *visual; @@ -19526,7 +19497,7 @@ $as_echo_n "checking for Carbon framework... " >&6; } #include int -main () +main (void) { ; @@ -19570,7 +19541,7 @@ $as_echo_n "checking for Cocoa framework... " >&6; } #import int -main () +main (void) { ; @@ -19626,7 +19597,7 @@ $as_echo_n "checking for framebuffer console support... " >&6; } #include int -main () +main (void) { ; @@ -19788,7 +19759,7 @@ $as_echo_n "checking for PlayStation 2 GS support... " >&6; } #include int -main () +main (void) { ; @@ -19831,7 +19802,7 @@ $as_echo_n "checking for PlayStation 3 Cell support... " >&6; } #include int -main () +main (void) { ; @@ -19875,7 +19846,7 @@ $as_echo_n "checking for GGI support... " >&6; } #include int -main () +main (void) { ; @@ -19919,7 +19890,7 @@ $as_echo_n "checking for SVGAlib (1.4.0+) support... " >&6; } #include int -main () +main (void) { if ( SCANCODE_RIGHTWIN && SCANCODE_LEFTWIN ) { @@ -19968,7 +19939,7 @@ $as_echo_n "checking for libVGL support... " >&6; } #include int -main () +main (void) { VGLBitmap bitmap; @@ -20017,7 +19988,7 @@ $as_echo_n "checking for wscons support... " >&6; } #include int -main () +main (void) { int wsmode = WSDISPLAYIO_MODE_DUMBFB; @@ -20061,7 +20032,7 @@ $as_echo_n "checking for AAlib support... " >&6; } #include int -main () +main (void) { ; @@ -20148,7 +20119,7 @@ $as_echo_n "checking for libcaca support... " >&6; } #include int -main () +main (void) { ; @@ -20201,7 +20172,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu #include int -main () +main (void) { ; @@ -20254,7 +20225,7 @@ $as_echo_n "checking for PicoGUI support... " >&6; } #include int -main () +main (void) { ; @@ -20335,9 +20306,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char appl_init (); +char appl_init (void); int -main () +main (void) { return appl_init (); ; @@ -20409,7 +20380,7 @@ $as_echo_n "checking for OpenGL (GLX) support... " >&6; } #include int -main () +main (void) { ; @@ -20443,7 +20414,7 @@ $as_echo_n "checking for OpenGL (Photon) support... " >&6; } #include int -main () +main (void) { ; @@ -20525,9 +20496,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char OSMesaCreateContext (); +char OSMesaCreateContext (void); int -main () +main (void) { return OSMesaCreateContext (); ; @@ -20659,7 +20630,7 @@ $as_echo_n "checking for Linux 2.4 unified input interface... " >&6; } #include int -main () +main (void) { #ifndef EVIOCGNAME @@ -20702,7 +20673,7 @@ $as_echo_n "checking for Touchscreen library support... " >&6; } #include "tslib.h" int -main () +main (void) { ; @@ -20900,7 +20871,7 @@ $as_echo_n "checking for pthreads... " >&6; } #include int -main () +main (void) { pthread_attr_t type; @@ -20946,7 +20917,7 @@ $as_echo_n "checking for recursive mutexes... " >&6; } #include int -main () +main (void) { pthread_mutexattr_t attr; @@ -20974,7 +20945,7 @@ rm -f core conftest.err conftest.$ac_objext \ #include int -main () +main (void) { pthread_mutexattr_t attr; @@ -21009,7 +20980,7 @@ $as_echo_n "checking for pthread semaphores... " >&6; } #include int -main () +main (void) { ; @@ -21034,7 +21005,7 @@ $as_echo_n "checking for sem_timedwait... " >&6; } #include int -main () +main (void) { sem_timedwait(NULL, NULL); @@ -21096,7 +21067,7 @@ $as_echo_n "checking Win32 compiler... " >&6; } #include int -main () +main (void) { ; @@ -21121,7 +21092,7 @@ $as_echo "$have_win32_gcc" >&6; } /* end confdefs.h. */ #include int -main () +main (void) { return (int) _strtoi64 (NULL,NULL,0); ; @@ -21138,7 +21109,7 @@ rm -f core conftest.err conftest.$ac_objext \ /* end confdefs.h. */ #include int -main () +main (void) { return (int) _strtoui64(NULL,NULL,0); ; @@ -21182,7 +21153,7 @@ $as_echo_n "checking OS/2 compiler... " >&6; } /* end confdefs.h. */ #include int -main () +main (void) { ; @@ -21242,11 +21213,11 @@ fi ac_fn_c_check_header_mongrel "$LINENO" "dinput.h" "ac_cv_header_dinput_h" "$ac_includes_default" if test "x$ac_cv_header_dinput_h" = xyes; then : - use_dinput=yes + have_dinput=yes fi - if test x$have_ddraw = xyes -a x$have_dsound = xyes -a x$use_dinput = xyes; then + if test x$have_ddraw = xyes -a x$have_dsound = xyes -a x$have_dinput = xyes; then have_directx=yes fi if test x$enable_video = xyes -a x$have_directx = xyes; then @@ -21288,7 +21259,7 @@ $as_echo_n "checking for dlopen... " >&6; } #include int -main () +main (void) { #if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED <= 1020 @@ -21323,9 +21294,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char dlopen (); +char dlopen (void); int -main () +main (void) { return dlopen (); ; @@ -21362,9 +21333,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char dlopen (); +char dlopen (void); int -main () +main (void) { return dlopen (); ; @@ -21438,9 +21409,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char ldg_open (); +char ldg_open (void); int -main () +main (void) { return ldg_open (); ; @@ -21493,9 +21464,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char hid_init (); +char hid_init (void); int -main () +main (void) { return hid_init (); ; @@ -21560,9 +21531,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char hid_init (); +char hid_init (void); int -main () +main (void) { return hid_init (); ; @@ -21615,7 +21586,7 @@ $as_echo_n "checking for usbhid... " >&6; } #endif int -main () +main (void) { struct report_desc *repdesc; @@ -21660,7 +21631,7 @@ $as_echo_n "checking for ucr_data member of usb_ctl_report... " >&6; } #endif int -main () +main (void) { struct usb_ctl_report buf; @@ -21706,7 +21677,7 @@ $as_echo_n "checking for new usbhid API... " >&6; } #endif int -main () +main (void) { report_desc_t d; @@ -21735,7 +21706,7 @@ $as_echo_n "checking for struct joystick in machine/joystick.h... " >&6; } #include int -main () +main (void) { struct joystick t; @@ -21792,9 +21763,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char clock_gettime (); +char clock_gettime (void); int -main () +main (void) { return clock_gettime (); ; @@ -21836,9 +21807,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char clock_gettime (); +char clock_gettime (void); int -main () +main (void) { return clock_gettime (); ; @@ -22000,6 +21971,19 @@ case "$host" in ;; esac fi + # Set up files for the haptic library + if test x$enable_haptic = xyes; then + if test x$use_input_events = xyes; then + case $ARCH in + linux) + $as_echo "#define SDL_HAPTIC_LINUX 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/haptic/linux/*.c" + have_haptic=yes + ;; + esac + fi + fi # Set up files for the cdrom library if test x$enable_cdrom = xyes; then case $ARCH in @@ -22183,6 +22167,14 @@ case "$host" in SOURCES="$SOURCES $srcdir/src/joystick/win32/*.c" have_joystick=yes fi + if test x$enable_haptic = xyes; then + if test x$have_dinput = xyes; then + $as_echo "#define SDL_HAPTIC_DINPUT 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/haptic/win32/SDL_syshaptic.c" + have_haptic=yes + fi + fi # Set up files for the cdrom library if test x$enable_cdrom = xyes; then $as_echo "#define SDL_CDROM_WIN32 1" >>confdefs.h @@ -22217,7 +22209,7 @@ case "$host" in # Set up the system libraries we need EXTRA_LDFLAGS="$EXTRA_LDFLAGS -luser32 -lgdi32 -lwinmm" if test x$have_directx = xyes; then - EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ldxguid" + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ldxguid -ldinput8 -ldxerr8 -lole32" fi BUILD_LDFLAGS="$BUILD_LDFLAGS -Wc,-static-libgcc" # The Win32 platform requires special setup @@ -22250,6 +22242,14 @@ case "$host" in SOURCES="$SOURCES $srcdir/src/joystick/beos/*.cc" have_joystick=yes fi + # Set up files for the haptic library + if test x$enable_haptic = xyes; then + $as_echo "#define SDL_HAPTIC_IOKIT 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/haptic/darwin/*.c" + have_haptic=yes + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,ForceFeedback" + fi # Set up files for the cdrom library if test x$enable_cdrom = xyes; then $as_echo "#define SDL_CDROM_BEOS 1" >>confdefs.h @@ -22566,6 +22566,13 @@ if test x$enable_joystick = xyes; then SOURCES="$SOURCES $srcdir/src/joystick/dummy/*.c" fi fi +if test x$have_haptic != xyes; then + if test x$enable_haptic = xyes; then + $as_echo "#define SDL_HAPTIC_DISABLED 1" >>confdefs.h + + fi + SOURCES="$SOURCES $srcdir/src/haptic/dummy/*.c" +fi if test x$have_cdrom != xyes; then if test x$enable_cdrom = xyes; then $as_echo "#define SDL_CDROM_DISABLED 1" >>confdefs.h @@ -22675,7 +22682,7 @@ fi -ac_config_files="$ac_config_files Makefile sdl-config SDL.spec SDL.qpg sdl.pc" +ac_config_files="$ac_config_files Makefile sdl-config SDL.spec SDL.qpg sdl.pc " ac_config_commands="$ac_config_commands default" @@ -23732,11 +23739,12 @@ do case $ac_config_target in "include/SDL_config.h") CONFIG_HEADERS="$CONFIG_HEADERS include/SDL_config.h" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + " ") CONFIG_FILES="$CONFIG_FILES " ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "sdl-config") CONFIG_FILES="$CONFIG_FILES sdl-config" ;; "SDL.spec") CONFIG_FILES="$CONFIG_FILES SDL.spec" ;; "SDL.qpg") CONFIG_FILES="$CONFIG_FILES SDL.qpg" ;; - "sdl.pc") CONFIG_FILES="$CONFIG_FILES sdl.pc" ;; + "sdl.pc ") CONFIG_FILES="$CONFIG_FILES sdl.pc " ;; "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; @@ -24525,7 +24533,7 @@ shlibpath_overrides_runpath=$shlibpath_overrides_runpath libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME +# The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. @@ -24634,7 +24642,7 @@ allow_undefined_flag=$lt_allow_undefined_flag no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist +# This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # If ld is used when linking, flag to hardcode \$libdir into a binary @@ -25019,7 +25027,7 @@ allow_undefined_flag=$lt_allow_undefined_flag_CXX no_undefined_flag=$lt_no_undefined_flag_CXX # Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist +# This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX # If ld is used when linking, flag to hardcode \$libdir into a binary diff --git a/configure.ac b/configure.ac index 9c56f81f7..90dbe9acd 100644 --- a/configure.ac +++ b/configure.ac @@ -2702,7 +2702,7 @@ case "$host" in # Set up the system libraries we need EXTRA_LDFLAGS="$EXTRA_LDFLAGS -luser32 -lgdi32 -lwinmm" if test x$have_directx = xyes; then - EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ldxguid" + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ldxguid -ldinput8 -ldxerr8 -lole32" fi BUILD_LDFLAGS="$BUILD_LDFLAGS -Wc,-static-libgcc" # The Win32 platform requires special setup diff --git a/sdl-config.in b/sdl-config.in index e0fcc0ced..1f98376a3 100644 --- a/sdl-config.in +++ b/sdl-config.in @@ -1,6 +1,6 @@ #!/bin/sh -prefix=@prefix@ +prefix="$(cygpath -m @prefix@)" exec_prefix=@exec_prefix@ exec_prefix_set=no libdir=@libdir@ diff --git a/src/SDL_HelperWindow.c b/src/SDL_HelperWindow.c index 778132fe8..6a3f6a454 100644 --- a/src/SDL_HelperWindow.c +++ b/src/SDL_HelperWindow.c @@ -1,5 +1,6 @@ #define UNICODE 1 #include "SDL_config.h" +#include "SDL.h" #include /* Some compilers use a special export keyword */ @@ -60,6 +61,28 @@ static WCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher"); static WCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow"); static ATOM SDL_HelperWindowClass = 0; +/* Sets an error message based on GetLastError() */ +int +WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr) +{ + TCHAR buffer[1024]; + char *message; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, + buffer, SDL_arraysize(buffer), NULL); + message = SDL_iconv_string("UTF-8", "UTF-16LE", (char *)buffer, (wcslen(buffer)+1)*sizeof(WCHAR)); + //WIN_StringToUTF8(buffer); + SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ": " : "", message); + SDL_free(message); + return -1; +} + +/* Sets an error message based on GetLastError() */ +int +WIN_SetError(const char *prefix) +{ + return WIN_SetErrorFromHRESULT(prefix, GetLastError()); +} + /* * Creates a HelperWindow used for DirectInput events. */ @@ -128,27 +151,3 @@ SDL_HelperWindowDestroy(void) SDL_HelperWindowClass = 0; } } - - -/* Sets an error message based on GetLastError() */ -int -WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr) -{ - TCHAR buffer[1024]; - char *message; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, - buffer, SDL_arraysize(buffer), NULL); - message = SDL_iconv_string("UTF-8", "UTF-16LE", (char *)buffer, (wcslen(buffer)+1)*sizeof(WCHAR)); - //WIN_StringToUTF8(buffer); - SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ": " : "", message); - SDL_free(message); - return -1; -} - - -/* Sets an error message based on GetLastError() */ -int -WIN_SetError(const char *prefix) -{ - return WIN_SetErrorFromHRESULT(prefix, GetLastError()); -} diff --git a/src/haptic/SDL_haptic.c b/src/haptic/SDL_haptic.c new file mode 100644 index 000000000..2b33cdc2b --- /dev/null +++ b/src/haptic/SDL_haptic.c @@ -0,0 +1,689 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 2008 Edgar Simo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_syshaptic.h" +#include "../joystick/SDL_joystick_c.h" /* For SDL_PrivateJoystickValid */ + + +Uint8 SDL_numhaptics = 0; +SDL_Haptic **SDL_haptics = NULL; + + +/* + * Initializes the Haptic devices. + */ +int +SDL_HapticInit(void) +{ + int arraylen; + int status; + + SDL_numhaptics = 0; + status = SDL_SYS_HapticInit(); + if (status >= 0) { + arraylen = (status + 1) * sizeof(*SDL_haptics); + SDL_haptics = (SDL_Haptic **) SDL_malloc(arraylen); + if (SDL_haptics == NULL) { /* Out of memory. */ + SDL_numhaptics = 0; + } + else { + SDL_memset(SDL_haptics, 0, arraylen); + SDL_numhaptics = status; + } + status = 0; + } + + return status; +} + + +/* + * Checks to see if the haptic device is valid + */ +static int +ValidHaptic(SDL_Haptic * haptic) +{ + int i; + int valid; + + valid = 0; + for (i=0; i= SDL_numhaptics)) { + SDL_SetError("Haptic: There are %d haptic devices available", SDL_numhaptics); + return NULL; + } + return SDL_SYS_HapticName(device_index); +} + + +/* + * Opens a Haptic device. + */ +SDL_Haptic * +SDL_HapticOpen(int device_index) +{ + int i; + SDL_Haptic *haptic; + + if ((device_index < 0) || (device_index >= SDL_numhaptics)) { + SDL_SetError("Haptic: There are %d haptic devices available", SDL_numhaptics); + return NULL; + } + + /* If the haptic is already open, return it */ + for (i=0; SDL_haptics[i]; i++) { + if (device_index == SDL_haptics[i]->index) { + haptic = SDL_haptics[i]; + ++haptic->ref_count; + return haptic; + } + } + + /* Create the haptic device */ + haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic)); + if (haptic == NULL) { + SDL_OutOfMemory(); + return NULL; + } + + /* Initialize the haptic device */ + SDL_memset(haptic, 0, (sizeof *haptic)); + haptic->index = device_index; + if (SDL_SYS_HapticOpen(haptic) < 0) { + SDL_free(haptic); + return NULL; + } + + /* Disable autocenter and set gain to max. */ + if (haptic->supported & SDL_HAPTIC_GAIN) + SDL_HapticSetGain(haptic,100); + if (haptic->supported & SDL_HAPTIC_AUTOCENTER) + SDL_HapticSetAutocenter(haptic,0); + + /* Add haptic to list */ + ++haptic->ref_count; + for (i=0; SDL_haptics[i]; i++) + /* Skip to next haptic */ ; + SDL_haptics[i] = haptic; + + return haptic; +} + + +/* + * Returns 1 if the device has been opened. + */ +int +SDL_HapticOpened(int device_index) +{ + int i, opened; + + opened = 0; + for (i=0; SDL_haptics[i]; i++) { + if (SDL_haptics[i]->index == (Uint8) device_index) { + opened = 1; + break; + } + } + return opened; +} + + +/* + * Returns the index to a haptic device. + */ +int +SDL_HapticIndex(SDL_Haptic * haptic) +{ + if (!ValidHaptic(haptic)) { + return -1; + } + + return haptic->index; +} + + +/* + * Returns SDL_TRUE if mouse is haptic, SDL_FALSE if it isn't. + */ +int +SDL_MouseIsHaptic(void) +{ + if (SDL_SYS_HapticMouse() < 0) + return SDL_FALSE; + return SDL_TRUE; +} + + +/* + * Returns the haptic device if mouse is haptic or NULL elsewise. + */ +SDL_Haptic * +SDL_HapticOpenFromMouse(void) +{ + int device_index; + + device_index = SDL_SYS_HapticMouse(); + + if (device_index < 0) { + SDL_SetError("Haptic: Mouse isn't a haptic device."); + return NULL; + } + + return SDL_HapticOpen(device_index); +} + + +/* + * Returns SDL_TRUE if joystick has haptic features. + */ +int +SDL_JoystickIsHaptic(SDL_Joystick * joystick) +{ + int ret; + + /* Must be a valid joystick */ + if (!SDL_PrivateJoystickValid(&joystick)) { + return -1; + } + + ret = SDL_SYS_JoystickIsHaptic(joystick); + + if (ret > 0) return SDL_TRUE; + else if (ret == 0) return SDL_FALSE; + else return -1; +} + + +/* + * Opens a haptic device from a joystick. + */ +SDL_Haptic * +SDL_HapticOpenFromJoystick(SDL_Joystick * joystick) +{ + int i; + SDL_Haptic *haptic; + + /* Must be a valid joystick */ + if (!SDL_PrivateJoystickValid(&joystick)) { + SDL_SetError("Haptic: Joystick isn't valid."); + return NULL; + } + + /* Joystick must be haptic */ + if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) { + SDL_SetError("Haptic: Joystick isn't a haptic device."); + return NULL; + } + + /* Check to see if joystick's haptic is already open */ + for (i=0; SDL_haptics[i]; i++) { + if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i],joystick)) { + haptic = SDL_haptics[i]; + ++haptic->ref_count; + return haptic; + } + } + + /* Create the haptic device */ + haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic)); + if (haptic == NULL) { + SDL_OutOfMemory(); + return NULL; + } + + /* Initialize the haptic device */ + SDL_memset(haptic, 0, sizeof(SDL_Haptic)); + if (SDL_SYS_HapticOpenFromJoystick(haptic,joystick) < 0) { + SDL_free(haptic); + return NULL; + } + + /* Add haptic to list */ + ++haptic->ref_count; + for (i=0; SDL_haptics[i]; i++) + /* Skip to next haptic */ ; + SDL_haptics[i] = haptic; + + return haptic; +} + + +/* + * Closes a SDL_Haptic device. + */ +void +SDL_HapticClose(SDL_Haptic * haptic) +{ + int i; + + /* Must be valid */ + if (!ValidHaptic(haptic)) { + return; + } + + /* Check if it's still in use */ + if (--haptic->ref_count < 0) { + return; + } + + /* Close it, properly removing effects if needed */ + for (i=0; ineffects; i++) { + if (haptic->effects[i].hweffect != NULL) { + SDL_HapticDestroyEffect(haptic,i); + } + } + SDL_SYS_HapticClose(haptic); + + /* Remove from the list */ + for (i = 0; SDL_haptics[i]; ++i) { + if (haptic == SDL_haptics[i]) { + SDL_haptics[i] = NULL; + SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1], + (SDL_numhaptics - i) * sizeof(haptic)); + break; + } + } + + /* Free */ + SDL_free(haptic); +} + +/* + * Cleans up after the subsystem. + */ +void +SDL_HapticQuit(void) +{ + SDL_SYS_HapticQuit(); + if (SDL_haptics != NULL) { + SDL_free(SDL_haptics); + SDL_haptics = NULL; + } + SDL_numhaptics = 0; +} + +/* + * Returns the number of effects a haptic device has. + */ +int +SDL_HapticNumEffects(SDL_Haptic * haptic) +{ + if (!ValidHaptic(haptic)) { + return -1; + } + + return haptic->neffects; +} + + +/* + * Returns the number of effects a haptic device can play. + */ +int +SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic) +{ + if (!ValidHaptic(haptic)) { + return -1; + } + + return haptic->nplaying; +} + + +/* + * Returns supported effects by the device. + */ +unsigned int +SDL_HapticQuery(SDL_Haptic * haptic) +{ + if (!ValidHaptic(haptic)) { + return -1; + } + + return haptic->supported; +} + + +/* + * Returns the number of axis on the device. + */ +int +SDL_HapticNumAxes(SDL_Haptic * haptic) +{ + if (!ValidHaptic(haptic)) { + return -1; + } + + return haptic->naxes; +} + +/* + * Checks to see if the device can support the effect. + */ +int +SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect) +{ + if (!ValidHaptic(haptic)) { + return -1; + } + + if ((haptic->supported & effect->type) != 0) + return SDL_TRUE; + return SDL_FALSE; +} + +/* + * Creates a new haptic effect. + */ +int +SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect) +{ + int i; + + /* Check for device validity. */ + if (!ValidHaptic(haptic)) { + return -1; + } + + /* Check to see if effect is supported */ + if (SDL_HapticEffectSupported(haptic,effect)==SDL_FALSE) { + SDL_SetError("Haptic: Effect not supported by haptic device."); + return -1; + } + + /* See if there's a free slot */ + for (i=0; ineffects; i++) { + if (haptic->effects[i].hweffect == NULL) { + + /* Now let the backend create the real effect */ + if (SDL_SYS_HapticNewEffect(haptic,&haptic->effects[i],effect) != 0) { + return -1; /* Backend failed to create effect */ + } + + SDL_memcpy(&haptic->effects[i].effect, effect, sizeof(SDL_HapticEffect)); + return i; + } + } + + SDL_SetError("Haptic: Device has no free space left."); + return -1; +} + +/* + * Checks to see if an effect is valid. + */ +static int +ValidEffect(SDL_Haptic * haptic, int effect) +{ + if ((effect < 0) || (effect >= haptic->neffects)) { + SDL_SetError("Haptic: Invalid effect identifier."); + return 0; + } + return 1; +} + +/* + * Updates an effect. + */ +int +SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect, SDL_HapticEffect * data) +{ + if (!ValidHaptic(haptic) || !ValidEffect(haptic,effect)) { + return -1; + } + + /* Can't change type dynamically. */ + if (data->type != haptic->effects[effect].effect.type) { + SDL_SetError("Haptic: Updating effect type is illegal."); + return -1; + } + + /* Updates the effect */ + if (SDL_SYS_HapticUpdateEffect(haptic,&haptic->effects[effect],data) < 0) { + return -1; + } + + SDL_memcpy(&haptic->effects[effect].effect, data, sizeof(SDL_HapticEffect)); + return 0; +} + + +/* + * Runs the haptic effect on the device. + */ +int +SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations) +{ + if (!ValidHaptic(haptic) || !ValidEffect(haptic,effect)) { + return -1; + } + + /* Run the effect */ + if (SDL_SYS_HapticRunEffect(haptic,&haptic->effects[effect], iterations) < 0) { + return -1; + } + + return 0; +} + +/* + * Stops the haptic effect on the device. + */ +int +SDL_HapticStopEffect(SDL_Haptic * haptic, int effect) +{ + if (!ValidHaptic(haptic) || !ValidEffect(haptic,effect)) { + return -1; + } + + /* Stop the effect */ + if (SDL_SYS_HapticStopEffect(haptic,&haptic->effects[effect]) < 0) { + return -1; + } + + return 0; +} + +/* + * Gets rid of a haptic effect. + */ +void +SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect) +{ + if (!ValidHaptic(haptic) || !ValidEffect(haptic,effect)) { + return; + } + + /* Not allocated */ + if (haptic->effects[effect].hweffect == NULL) { + return; + } + + SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]); +} + +/* + * Gets the status of a haptic effect. + */ +int +SDL_HapticGetEffectStatus(SDL_Haptic *haptic, int effect) +{ + if (!ValidHaptic(haptic) || !ValidEffect(haptic,effect)) { + return -1; + } + + if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) { + SDL_SetError("Haptic: Device does not support status queries."); + return -1; + } + + return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]); +} + +/* + * Sets the global gain of the device. + */ +int +SDL_HapticSetGain(SDL_Haptic * haptic, int gain ) +{ + const char *env; + int real_gain, max_gain; + + if (!ValidHaptic(haptic)) { + return -1; + } + + if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) { + SDL_SetError("Haptic: Device does not support setting gain."); + return -1; + } + + if ((gain < 0) || (gain > 100)) { + SDL_SetError("Haptic: Gain must be between 0 and 100."); + return -1; + } + + /* We use the envvar to get the maximum gain. */ + env = SDL_getenv("SDL_HAPTIC_GAIN_MAX"); + if (env != NULL) { + max_gain = SDL_atoi(env); + + /* Check for sanity. */ + if (max_gain < 0) max_gain = 0; + else if (max_gain > 100) max_gain = 100; + + /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */ + real_gain = (gain * max_gain) / 100; + } + else { + real_gain = gain; + } + + if (SDL_SYS_HapticSetGain(haptic,real_gain) < 0) { + return -1; + } + + return 0; +} + +/* + * Makes the device autocenter, 0 disables. + */ +int +SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter ) +{ + if (!ValidHaptic(haptic)) { + return -1; + } + + if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) { + SDL_SetError("Haptic: Device does not support setting autocenter."); + return -1; + } + + if ((autocenter < 0) || (autocenter > 100)) { + SDL_SetError("Haptic: Autocenter must be between 0 and 100."); + return -1; + } + + if (SDL_SYS_HapticSetAutocenter(haptic,autocenter) < 0) { + return -1; + } + + return 0; +} + +/* + * Pauses the haptic device. + */ +int +SDL_HapticPause(SDL_Haptic * haptic) +{ + if (!ValidHaptic(haptic)) { + return -1; + } + + if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) { + SDL_SetError("Haptic: Device does not support setting pausing."); + return -1; + } + + return SDL_SYS_HapticPause(haptic); +} + +/* + * Unpauses the haptic device. + */ +int +SDL_HapticUnpause(SDL_Haptic * haptic) +{ + if (!ValidHaptic(haptic)) { + return -1; + } + + if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) { + return 0; /* Not going to be paused, so we pretend it's unpaused. */ + } + + return SDL_SYS_HapticUnpause(haptic); +} + +/* + * Stops all the currently playing effects. + */ +int +SDL_HapticStopAll(SDL_Haptic * haptic) +{ + if (!ValidHaptic(haptic)) { + return -1; + } + + return SDL_SYS_HapticStopAll(haptic); +} diff --git a/src/haptic/SDL_syshaptic.h b/src/haptic/SDL_syshaptic.h new file mode 100644 index 000000000..ee4db1eb2 --- /dev/null +++ b/src/haptic/SDL_syshaptic.h @@ -0,0 +1,202 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 2008 Edgar Simo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +#include "SDL_config.h" + +#include "SDL_haptic.h" + + +/* + * Number of haptic devices on the system. + */ +extern Uint8 SDL_numhaptics; + + +struct haptic_effect +{ + SDL_HapticEffect effect; /* The current event */ + struct haptic_hweffect *hweffect; /* The hardware behind the event */ +}; + +/* + * The real SDL_Haptic struct. + */ +struct _SDL_Haptic +{ + Uint8 index; /* Stores index it is attached to */ + + struct haptic_effect *effects; /* Allocated effects */ + int neffects; /* Maximum amount of effects */ + int nplaying; /* Maximum amount of effects to play at the same time */ + unsigned int supported; /* Supported effects */ + int naxes; /* Number of axes on the device. */ + + struct haptic_hwdata *hwdata; /* Driver dependent */ + int ref_count; /* Count for multiple opens */ +}; + +/* + * Scans the system for haptic devices. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticInit(void); + +/* + * Gets the device dependent name of the haptic device + */ +extern const char * SDL_SYS_HapticName(int index); + +/* + * Opens the haptic device for usage. The haptic device should have + * the index value set previously. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticOpen(SDL_Haptic * haptic); + +/* + * Returns the index of the haptic core pointer or -1 if none is found. + */ +int SDL_SYS_HapticMouse(void); + +/* + * Checks to see if the joystick has haptic capabilities. + * + * Returns >0 if haptic capabilities are detected, 0 if haptic + * capabilities aren't detected and -1 on error. + */ +extern int SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick); + +/* + * Opens the haptic device for usage using the same device as + * the joystick. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, + SDL_Joystick * joystick); +/* + * Checks to see if haptic device and joystick device are the same. + * + * Returns 1 if they are the same, 0 if they aren't. + */ +extern int SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, + SDL_Joystick * joystick); + +/* + * Closes a haptic device after usage. + */ +extern void SDL_SYS_HapticClose(SDL_Haptic * haptic); + +/* + * Performs a cleanup on the haptic subsystem. + */ +extern void SDL_SYS_HapticQuit(void); + +/* + * Creates a new haptic effect on the haptic device using base + * as a template for the effect. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, + SDL_HapticEffect * base); + +/* + * Updates the haptic effect on the haptic device using data + * as a template. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, + SDL_HapticEffect * data); + +/* + * Runs the effect on the haptic device. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, + Uint32 iterations); + +/* + * Stops the effect on the haptic device. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, + struct haptic_effect * effect); + +/* + * Cleanups up the effect on the haptic device. + */ +extern void SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, + struct haptic_effect * effect); + +/* + * Queries the device for the status of effect. + * + * Returns 0 if device is stopped, >0 if device is playing and + * -1 on error. + */ +extern int SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, + struct haptic_effect * effect); + +/* + * Sets the global gain of the haptic device. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain); + +/* + * Sets the autocenter feature of the haptic device. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, + int autocenter); + +/* + * Pauses the haptic device. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticPause(SDL_Haptic * haptic); + +/* + * Unpauses the haptic device. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticUnpause(SDL_Haptic * haptic); + +/* + * Stops all the currently playing haptic effects on the device. + * + * Returns 0 on success, -1 on error. + */ +extern int SDL_SYS_HapticStopAll(SDL_Haptic * haptic); diff --git a/src/haptic/darwin/SDL_syshaptic.c b/src/haptic/darwin/SDL_syshaptic.c new file mode 100644 index 000000000..e47c21f58 --- /dev/null +++ b/src/haptic/darwin/SDL_syshaptic.c @@ -0,0 +1,1284 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 2008 Edgar Simo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_HAPTIC_IOKIT + +#include "SDL_haptic.h" +#include "../SDL_syshaptic.h" +#include "SDL_joystick.h" +#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */ +#include "../../joystick/darwin/SDL_sysjoystick_c.h" /* For joystick hwdata */ + +#include +#include +#include +#include + + +#define MAX_HAPTICS 32 + + +/* + * List of available haptic devices. + */ +static struct +{ + char name[256]; /* Name of the device. */ + + io_service_t dev; /* Node we use to create the device. */ + SDL_Haptic *haptic; /* Haptic currently assosciated with it. */ + + /* Usage pages for determining if it's a mouse or not. */ + long usage; + long usagePage; +} SDL_hapticlist[MAX_HAPTICS]; + + +/* + * Haptic system hardware data. + */ +struct haptic_hwdata +{ + FFDeviceObjectReference device; /* Hardware device. */ + UInt8 axes[3]; +}; + + +/* + * Haptic system effect data. + */ +struct haptic_hweffect +{ + FFEffectObjectReference ref; /* Reference. */ + struct FFEFFECT effect; /* Hardware effect. */ +}; + +/* + * Prototypes. + */ +static void SDL_SYS_HapticFreeFFEFFECT(FFEFFECT * effect, int type); +static int HIDGetDeviceProduct(io_service_t dev, char * name); + + +/* + * Like strerror but for force feedback errors. + */ +static const char * +FFStrError(HRESULT err) +{ + switch (err) { + case FFERR_DEVICEFULL: + return "device full"; + /* This should be valid, but for some reason isn't defined... */ + /*case FFERR_DEVICENOTREG: + return "device not registered";*/ + case FFERR_DEVICEPAUSED: + return "device paused"; + case FFERR_DEVICERELEASED: + return "device released"; + case FFERR_EFFECTPLAYING: + return "effect playing"; + case FFERR_EFFECTTYPEMISMATCH: + return "effect type mismatch"; + case FFERR_EFFECTTYPENOTSUPPORTED: + return "effect type not supported"; + case FFERR_GENERIC: + return "undetermined error"; + case FFERR_HASEFFECTS: + return "device has effects"; + case FFERR_INCOMPLETEEFFECT: + return "incomplete effect"; + case FFERR_INTERNAL: + return "internal fault"; + case FFERR_INVALIDDOWNLOADID: + return "invalid download id"; + case FFERR_INVALIDPARAM: + return "invalid parameter"; + case FFERR_MOREDATA: + return "more data"; + case FFERR_NOINTERFACE: + return "interface not supported"; + case FFERR_NOTDOWNLOADED: + return "effect is not downloaded"; + case FFERR_NOTINITIALIZED: + return "object has not been initialized"; + case FFERR_OUTOFMEMORY: + return "out of memory"; + case FFERR_UNPLUGGED: + return "device is unplugged"; + case FFERR_UNSUPPORTED: + return "function call unsupported"; + case FFERR_UNSUPPORTEDAXIS: + return "axis unsupported"; + + default: + return "unknown error"; + } +} + + +/* + * Initializes the haptic subsystem. + */ +int +SDL_SYS_HapticInit(void) +{ + int numhaptics; + IOReturn result; + io_iterator_t iter; + CFDictionaryRef match; + io_service_t device; + CFMutableDictionaryRef hidProperties; + CFTypeRef refCF; + + /* Clear all the memory. */ + SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist)); + + /* Get HID devices. */ + match = IOServiceMatching(kIOHIDDeviceKey); + if (match == NULL) { + SDL_SetError("Haptic: Failed to get IOServiceMatching."); + return -1; + } + + /* Now search I/O Registry for matching devices. */ + result = IOServiceGetMatchingServices(kIOMasterPortDefault, match, &iter); + if (result != kIOReturnSuccess) { + SDL_SetError("Haptic: Couldn't create a HID object iterator."); + return -1; + } + /* IOServiceGetMatchingServices consumes dictionary. */ + + if (!IOIteratorIsValid(iter)) { /* No iterator. */ + numhaptics = 0; + return 0; + } + + numhaptics = 0; + while ((device = IOIteratorNext(iter)) != IO_OBJECT_NULL) { + + /* Check for force feedback. */ + if (FFIsForceFeedback(device) == FF_OK) { + + /* Set basic device data. */ + HIDGetDeviceProduct(device, SDL_hapticlist[numhaptics].name); + SDL_hapticlist[numhaptics].dev = device; + SDL_hapticlist[numhaptics].haptic = NULL; + + /* Set usage pages. */ + hidProperties = 0; + refCF = 0; + result = IORegistryEntryCreateCFProperties(device, + &hidProperties, kCFAllocatorDefault, kNilOptions); + if ((result == KERN_SUCCESS) && hidProperties) { + refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey)); + if (refCF) { + if (!CFNumberGetValue(refCF, kCFNumberLongType, + &SDL_hapticlist[numhaptics].usagePage)) + SDL_SetError("Haptic: Recieving device's usage page."); + refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsageKey)); + if (refCF) { + if (!CFNumberGetValue(refCF, kCFNumberLongType, + &SDL_hapticlist[numhaptics].usage)) + SDL_SetError("Haptic: Recieving device's usage."); + } + } + CFRelease(hidProperties); + } + + /* Device has been added. */ + numhaptics++; + } + else { /* Free the unused device. */ + IOObjectRelease(device); + } + + /* Reached haptic limit. */ + if (numhaptics >= MAX_HAPTICS) + break; + } + IOObjectRelease(iter); + + return numhaptics; +} + + +/* + * Return the name of a haptic device, does not need to be opened. + */ +const char * +SDL_SYS_HapticName(int index) +{ + return SDL_hapticlist[index].name; +} + +/* + * Gets the device's product name. + */ +static int +HIDGetDeviceProduct(io_service_t dev, char *name) +{ + CFMutableDictionaryRef hidProperties, usbProperties; + io_registry_entry_t parent1, parent2; + kern_return_t ret; + + hidProperties = usbProperties = 0; + + ret = IORegistryEntryCreateCFProperties(dev, &hidProperties, + kCFAllocatorDefault, + kNilOptions); + if ((ret != KERN_SUCCESS) || !hidProperties) { + SDL_SetError("Haptic: Unable to create CFProperties."); + return -1; + } + + /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also + * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties + */ + if ((KERN_SUCCESS == + IORegistryEntryGetParentEntry(dev, kIOServicePlane, &parent1)) + && (KERN_SUCCESS == + IORegistryEntryGetParentEntry(parent1, kIOServicePlane, &parent2)) + && (KERN_SUCCESS == + IORegistryEntryCreateCFProperties(parent2, &usbProperties, + kCFAllocatorDefault, + kNilOptions))) { + if (usbProperties) { + CFTypeRef refCF = 0; + /* get device info + * try hid dictionary first, if fail then go to usb dictionary + */ + + + /* Get product name */ + refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductKey)); + if (!refCF) + refCF = + CFDictionaryGetValue(usbProperties, CFSTR("USB Product Name")); + if (refCF) { + if (!CFStringGetCString(refCF, name, 256, + CFStringGetSystemEncoding())) { + SDL_SetError("Haptic: CFStringGetCString error retrieving pDevice->product."); + return -1; + } + } + + CFRelease(usbProperties); + } + else { + SDL_SetError("Haptic: IORegistryEntryCreateCFProperties failed to create usbProperties."); + return -1; + } + + /* Release stuff. */ + if (kIOReturnSuccess != IOObjectRelease(parent2)) { + SDL_SetError("Haptic: IOObjectRelease error with parent2."); + } + if (kIOReturnSuccess != IOObjectRelease(parent1)) { + SDL_SetError("Haptic: IOObjectRelease error with parent1."); + } + } + else { + SDL_SetError("Haptic: Error getting registry entries."); + return -1; + } + + return 0; +} + + +#define FF_TEST(ff, s) \ +if (features.supportedEffects & (ff)) supported |= (s) +/* + * Gets supported features. + */ +static unsigned int +GetSupportedFeatures(SDL_Haptic* haptic) +{ + HRESULT ret; + FFDeviceObjectReference device; + FFCAPABILITIES features; + unsigned int supported; + Uint32 val; + + device = haptic->hwdata->device; + + ret = FFDeviceGetForceFeedbackCapabilities(device, &features); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to get device's supported features."); + return -1; + } + + supported = 0; + + /* Get maximum effects. */ + haptic->neffects = features.storageCapacity; + haptic->nplaying = features.playbackCapacity; + + /* Test for effects. */ + FF_TEST(FFCAP_ET_CONSTANTFORCE, SDL_HAPTIC_CONSTANT); + FF_TEST(FFCAP_ET_RAMPFORCE, SDL_HAPTIC_RAMP); + FF_TEST(FFCAP_ET_SQUARE, SDL_HAPTIC_SQUARE); + FF_TEST(FFCAP_ET_SINE, SDL_HAPTIC_SINE); + FF_TEST(FFCAP_ET_TRIANGLE, SDL_HAPTIC_TRIANGLE); + FF_TEST(FFCAP_ET_SAWTOOTHUP, SDL_HAPTIC_SAWTOOTHUP); + FF_TEST(FFCAP_ET_SAWTOOTHDOWN, SDL_HAPTIC_SAWTOOTHDOWN); + FF_TEST(FFCAP_ET_SPRING, SDL_HAPTIC_SPRING); + FF_TEST(FFCAP_ET_DAMPER, SDL_HAPTIC_DAMPER); + FF_TEST(FFCAP_ET_INERTIA, SDL_HAPTIC_INERTIA); + FF_TEST(FFCAP_ET_FRICTION, SDL_HAPTIC_FRICTION); + FF_TEST(FFCAP_ET_CUSTOMFORCE, SDL_HAPTIC_CUSTOM); + + /* Check if supports gain. */ + ret = FFDeviceGetForceFeedbackProperty( device, FFPROP_FFGAIN, + &val, sizeof(val)); + if (ret == FF_OK) supported |= SDL_HAPTIC_GAIN; + else if (ret != FFERR_UNSUPPORTED) { + SDL_SetError("Haptic: Unable to get if device supports gain: %s.", + FFStrError(ret)); + return -1; + } + + /* Checks if supports autocenter. */ + ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_AUTOCENTER, + &val, sizeof(val)); + if (ret == FF_OK) supported |= SDL_HAPTIC_AUTOCENTER; + else if (ret != FFERR_UNSUPPORTED) { + SDL_SetError("Haptic: Unable to get if device supports autocenter: %s.", + FFStrError(ret)); + return -1; + } + + /* Check for axes, we have an artificial limit on axes */ + haptic->naxes = ((features.numFfAxes) > 3) ? + 3 : features.numFfAxes; + /* Actually store the axes we want to use */ + SDL_memcpy( haptic->hwdata->axes, features.ffAxes, haptic->naxes * sizeof(Uint8)); + + /* Always supported features. */ + supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE; + + haptic->supported = supported; + return 0;; +} + + +/* + * Opens the haptic device from the file descriptor. + */ +static int +SDL_SYS_HapticOpenFromService(SDL_Haptic * haptic, io_service_t service) +{ + HRESULT ret; + int ret2; + + /* Allocate the hwdata */ + haptic->hwdata = (struct haptic_hwdata *) + SDL_malloc(sizeof(*haptic->hwdata)); + if (haptic->hwdata == NULL) { + SDL_OutOfMemory(); + goto creat_err; + } + SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); + + /* Open the device */ + ret = FFCreateDevice( service, &haptic->hwdata->device); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to create device from service: %s.", + FFStrError(ret)); + goto creat_err; + } + + /* Get supported features. */ + ret2 = GetSupportedFeatures( haptic ); + if (haptic->supported < 0) { + goto open_err; + } + + + /* Reset and then enable actuators. */ + ret = FFDeviceSendForceFeedbackCommand( haptic->hwdata->device, + FFSFFC_RESET ); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to reset device: %s.", FFStrError(ret)); + goto open_err; + } + ret = FFDeviceSendForceFeedbackCommand( haptic->hwdata->device, + FFSFFC_SETACTUATORSON ); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to enable actuators: %s.", FFStrError(ret)); + goto open_err; + } + + + /* Allocate effects memory. */ + haptic->effects = (struct haptic_effect *) + SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); + if (haptic->effects == NULL) { + SDL_OutOfMemory(); + goto open_err; + } + /* Clear the memory */ + SDL_memset(haptic->effects, 0, + sizeof(struct haptic_effect) * haptic->neffects); + + return 0; + + /* Error handling */ +open_err: + FFReleaseDevice(haptic->hwdata->device); +creat_err: + if (haptic->hwdata != NULL) { + free(haptic->hwdata); + haptic->hwdata = NULL; + } + return -1; + +} + + +/* + * Opens a haptic device for usage. + */ +int +SDL_SYS_HapticOpen(SDL_Haptic * haptic) +{ + return SDL_SYS_HapticOpenFromService(haptic, + SDL_hapticlist[haptic->index].dev); +} + + +/* + * Opens a haptic device from first mouse it finds for usage. + */ +int +SDL_SYS_HapticMouse(void) +{ + int i; + + for (i=0; ihwdata->ffservice != 0) + return SDL_TRUE; + return SDL_FALSE; +} + + +/* + * Checks to see if the haptic device and joystick and in reality the same. + */ +int +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + if (IOObjectIsEqualTo((io_object_t) haptic->hwdata->device, + joystick->hwdata->ffservice)) + return 1; + return 0; +} + + +/* + * Opens a SDL_Haptic from a SDL_Joystick. + */ +int +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + return SDL_SYS_HapticOpenFromService(haptic, + joystick->hwdata->ffservice); +} + + +/* + * Closes the haptic device. + */ +void +SDL_SYS_HapticClose(SDL_Haptic * haptic) +{ + if (haptic->hwdata) { + + /* Free Effects. */ + SDL_free(haptic->effects); + haptic->effects = NULL; + haptic->neffects = 0; + + /* Clean up */ + FFReleaseDevice(haptic->hwdata->device); + + /* Free */ + SDL_free(haptic->hwdata); + haptic->hwdata = NULL; + } +} + + +/* + * Clean up after system specific haptic stuff + */ +void +SDL_SYS_HapticQuit(void) +{ + int i; + + for (i=0; i < SDL_numhaptics; i++) { + /* Opened and not closed haptics are leaked, this is on purpose. + * Close your haptic devices after usage. */ + + /* Free the io_service_t */ + IOObjectRelease(SDL_hapticlist[i].dev); + } +} + + +/* + * Converts an SDL trigger button to an FFEFFECT trigger button. + */ +static DWORD +FFGetTriggerButton( Uint16 button ) +{ + DWORD dwTriggerButton; + + dwTriggerButton = FFEB_NOTRIGGER; + + if (button != 0) { + dwTriggerButton = FFJOFS_BUTTON(button - 1); + } + + return dwTriggerButton; +} + + +/* + * Sets the direction. + */ +static int +SDL_SYS_SetDirection( FFEFFECT * effect, SDL_HapticDirection *dir, int naxes ) +{ + LONG *rglDir; + + /* Handle no axes a part. */ + if (naxes == 0) { + effect->dwFlags |= FFEFF_SPHERICAL; /* Set as default. */ + effect->rglDirection = NULL; + return 0; + } + + /* Has axes. */ + rglDir = SDL_malloc( sizeof(LONG) * naxes ); + if (rglDir == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset( rglDir, 0, sizeof(LONG) * naxes ); + effect->rglDirection = rglDir; + + switch (dir->type) { + case SDL_HAPTIC_POLAR: + effect->dwFlags |= FFEFF_POLAR; + rglDir[0] = dir->dir[0]; + return 0; + case SDL_HAPTIC_CARTESIAN: + effect->dwFlags |= FFEFF_CARTESIAN; + rglDir[0] = dir->dir[0]; + if (naxes > 1) + rglDir[1] = dir->dir[1]; + if (naxes > 2) + rglDir[2] = dir->dir[2]; + return 0; + case SDL_HAPTIC_SPHERICAL: + effect->dwFlags |= FFEFF_SPHERICAL; + rglDir[0] = dir->dir[0]; + if (naxes > 1) + rglDir[1] = dir->dir[1]; + if (naxes > 2) + rglDir[2] = dir->dir[2]; + return 0; + + default: + SDL_SetError("Haptic: Unknown direction type."); + return -1; + } +} + + +/* Clamps and converts. */ +#define CCONVERT(x) (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF) +/* Just converts. */ +#define CONVERT(x) (((x)*10000) / 0x7FFF) +/* + * Creates the FFEFFECT from a SDL_HapticEffect. + */ +static int +SDL_SYS_ToFFEFFECT( SDL_Haptic * haptic, FFEFFECT * dest, SDL_HapticEffect * src ) +{ + int i; + FFCONSTANTFORCE *constant; + FFPERIODIC *periodic; + FFCONDITION *condition; /* Actually an array of conditions - one per axis. */ + FFRAMPFORCE *ramp; + FFCUSTOMFORCE *custom; + FFENVELOPE *envelope; + SDL_HapticConstant *hap_constant; + SDL_HapticPeriodic *hap_periodic; + SDL_HapticCondition *hap_condition; + SDL_HapticRamp *hap_ramp; + SDL_HapticCustom *hap_custom; + DWORD *axes; + + /* Set global stuff. */ + SDL_memset(dest, 0, sizeof(FFEFFECT)); + dest->dwSize = sizeof(FFEFFECT); /* Set the structure size. */ + dest->dwSamplePeriod = 0; /* Not used by us. */ + dest->dwGain = 10000; /* Gain is set globally, not locally. */ + dest->dwFlags = FFEFF_OBJECTOFFSETS; /* Seems obligatory. */ + + /* Envelope. */ + envelope = SDL_malloc( sizeof(FFENVELOPE) ); + if (envelope == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(envelope, 0, sizeof(FFENVELOPE)); + dest->lpEnvelope = envelope; + envelope->dwSize = sizeof(FFENVELOPE); /* Always should be this. */ + + /* Axes. */ + dest->cAxes = haptic->naxes; + if (dest->cAxes > 0) { + axes = SDL_malloc(sizeof(DWORD) * dest->cAxes); + if (axes == NULL) { + SDL_OutOfMemory(); + return -1; + } + axes[0] = haptic->hwdata->axes[0]; /* Always at least one axis. */ + if (dest->cAxes > 1) { + axes[1] = haptic->hwdata->axes[1]; + } + if (dest->cAxes > 2) { + axes[2] = haptic->hwdata->axes[2]; + } + dest->rgdwAxes = axes; + } + + + /* The big type handling switch, even bigger then linux's version. */ + switch (src->type) { + case SDL_HAPTIC_CONSTANT: + hap_constant = &src->constant; + constant = SDL_malloc( sizeof(FFCONSTANTFORCE) ); + if (constant == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(constant, 0, sizeof(FFCONSTANTFORCE)); + + /* Specifics */ + constant->lMagnitude = CONVERT(hap_constant->level); + dest->cbTypeSpecificParams = sizeof(FFCONSTANTFORCE); + dest->lpvTypeSpecificParams = constant; + + /* Generics */ + dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = FFGetTriggerButton(hap_constant->button); + dest->dwTriggerRepeatInterval = hap_constant->interval; + dest->dwStartDelay = hap_constant->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_constant->attack_length==0) && (hap_constant->fade_length==0)) { + SDL_free(envelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CCONVERT(hap_constant->attack_level); + envelope->dwAttackTime = hap_constant->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_constant->fade_level); + envelope->dwFadeTime = hap_constant->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_SINE: + case SDL_HAPTIC_SQUARE: + case SDL_HAPTIC_TRIANGLE: + case SDL_HAPTIC_SAWTOOTHUP: + case SDL_HAPTIC_SAWTOOTHDOWN: + hap_periodic = &src->periodic; + periodic = SDL_malloc(sizeof(FFPERIODIC)); + if (periodic == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(periodic, 0, sizeof(FFPERIODIC)); + + /* Specifics */ + periodic->dwMagnitude = CONVERT(hap_periodic->magnitude); + periodic->lOffset = CONVERT(hap_periodic->offset); + periodic->dwPhase = hap_periodic->phase; + periodic->dwPeriod = hap_periodic->period * 1000; + dest->cbTypeSpecificParams = sizeof(FFPERIODIC); + dest->lpvTypeSpecificParams = periodic; + + /* Generics */ + dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = FFGetTriggerButton(hap_periodic->button); + dest->dwTriggerRepeatInterval = hap_periodic->interval; + dest->dwStartDelay = hap_periodic->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_periodic->attack_length==0) && (hap_periodic->fade_length==0)) { + SDL_free(envelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CCONVERT(hap_periodic->attack_level); + envelope->dwAttackTime = hap_periodic->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_periodic->fade_level); + envelope->dwFadeTime = hap_periodic->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_SPRING: + case SDL_HAPTIC_DAMPER: + case SDL_HAPTIC_INERTIA: + case SDL_HAPTIC_FRICTION: + hap_condition = &src->condition; + condition = SDL_malloc(sizeof(FFCONDITION) * dest->cAxes); + if (condition == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(condition, 0, sizeof(FFCONDITION)); + + /* Specifics */ + for (i=0; icAxes; i++) { + condition[i].lOffset = CONVERT(hap_condition->center[i]); + condition[i].lPositiveCoefficient = CONVERT(hap_condition->right_coeff[i]); + condition[i].lNegativeCoefficient = CONVERT(hap_condition->left_coeff[i]); + condition[i].dwPositiveSaturation = CCONVERT(hap_condition->right_sat[i]); + condition[i].dwNegativeSaturation = CCONVERT(hap_condition->left_sat[i]); + condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i]); + } + dest->cbTypeSpecificParams = sizeof(FFCONDITION) * dest->cAxes; + dest->lpvTypeSpecificParams = condition; + + /* Generics */ + dest->dwDuration = hap_condition->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = FFGetTriggerButton(hap_condition->button); + dest->dwTriggerRepeatInterval = hap_condition->interval; + dest->dwStartDelay = hap_condition->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope - Not actually supported by most CONDITION implementations. */ + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + + break; + + case SDL_HAPTIC_RAMP: + hap_ramp = &src->ramp; + ramp = SDL_malloc(sizeof(FFRAMPFORCE)); + if (ramp == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(ramp, 0, sizeof(FFRAMPFORCE)); + + /* Specifics */ + ramp->lStart = CONVERT(hap_ramp->start); + ramp->lEnd = CONVERT(hap_ramp->end); + dest->cbTypeSpecificParams = sizeof(FFRAMPFORCE); + dest->lpvTypeSpecificParams = ramp; + + /* Generics */ + dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = FFGetTriggerButton(hap_ramp->button); + dest->dwTriggerRepeatInterval = hap_ramp->interval; + dest->dwStartDelay = hap_ramp->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_ramp->attack_length==0) && (hap_ramp->fade_length==0)) { + SDL_free(envelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CCONVERT(hap_ramp->attack_level); + envelope->dwAttackTime = hap_ramp->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_ramp->fade_level); + envelope->dwFadeTime = hap_ramp->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_CUSTOM: + hap_custom = &src->custom; + custom = SDL_malloc(sizeof(FFCUSTOMFORCE)); + if (custom == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(custom, 0, sizeof(FFCUSTOMFORCE)); + + /* Specifics */ + custom->cChannels = hap_custom->channels; + custom->dwSamplePeriod = hap_custom->period * 1000; + custom->cSamples = hap_custom->samples; + custom->rglForceData = SDL_malloc(sizeof(LONG)*custom->cSamples*custom->cChannels); + for (i=0; isamples*hap_custom->channels; i++) { /* Copy data. */ + custom->rglForceData[i] = CCONVERT(hap_custom->data[i]); + } + dest->cbTypeSpecificParams = sizeof(FFCUSTOMFORCE); + dest->lpvTypeSpecificParams = custom; + + /* Generics */ + dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = FFGetTriggerButton(hap_custom->button); + dest->dwTriggerRepeatInterval = hap_custom->interval; + dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_custom->attack_length==0) && (hap_custom->fade_length==0)) { + SDL_free(envelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CCONVERT(hap_custom->attack_level); + envelope->dwAttackTime = hap_custom->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_custom->fade_level); + envelope->dwFadeTime = hap_custom->fade_length * 1000; + } + + break; + + + default: + SDL_SetError("Haptic: Unknown effect type."); + return -1; + } + + return 0; +} + + +/* + * Frees an FFEFFECT allocated by SDL_SYS_ToFFEFFECT. + */ +static void +SDL_SYS_HapticFreeFFEFFECT( FFEFFECT * effect, int type ) +{ + FFCUSTOMFORCE *custom; + + if (effect->lpEnvelope != NULL) { + SDL_free(effect->lpEnvelope); + effect->lpEnvelope = NULL; + } + if (effect->rgdwAxes != NULL) { + SDL_free(effect->rgdwAxes); + effect->rgdwAxes = NULL; + } + if (effect->lpvTypeSpecificParams != NULL) { + if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */ + custom = (FFCUSTOMFORCE*) effect->lpvTypeSpecificParams; + SDL_free(custom->rglForceData); + custom->rglForceData = NULL; + } + SDL_free(effect->lpvTypeSpecificParams); + effect->lpvTypeSpecificParams = NULL; + } + if (effect->rglDirection != NULL) { + SDL_free(effect->rglDirection); + effect->rglDirection = NULL; + } +} + + +/* + * Gets the effect type from the generic SDL haptic effect wrapper. + */ +CFUUIDRef +SDL_SYS_HapticEffectType( Uint16 type ) +{ + switch (type) { + case SDL_HAPTIC_CONSTANT: + return kFFEffectType_ConstantForce_ID; + + case SDL_HAPTIC_RAMP: + return kFFEffectType_RampForce_ID; + + case SDL_HAPTIC_SQUARE: + return kFFEffectType_Square_ID; + + case SDL_HAPTIC_SINE: + return kFFEffectType_Sine_ID; + + case SDL_HAPTIC_TRIANGLE: + return kFFEffectType_Triangle_ID; + + case SDL_HAPTIC_SAWTOOTHUP: + return kFFEffectType_SawtoothUp_ID; + + case SDL_HAPTIC_SAWTOOTHDOWN: + return kFFEffectType_SawtoothDown_ID; + + case SDL_HAPTIC_SPRING: + return kFFEffectType_Spring_ID; + + case SDL_HAPTIC_DAMPER: + return kFFEffectType_Damper_ID; + + case SDL_HAPTIC_INERTIA: + return kFFEffectType_Inertia_ID; + + case SDL_HAPTIC_FRICTION: + return kFFEffectType_Friction_ID; + + case SDL_HAPTIC_CUSTOM: + return kFFEffectType_CustomForce_ID; + + default: + SDL_SetError("Haptic: Unknown effect type."); + return NULL; + } +} + + +/* + * Creates a new haptic effect. + */ +int +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect * effect, + SDL_HapticEffect * base) +{ + HRESULT ret; + CFUUIDRef type; + + /* Alloc the effect. */ + effect->hweffect = (struct haptic_hweffect *) + SDL_malloc(sizeof(struct haptic_hweffect)); + if (effect->hweffect == NULL) { + SDL_OutOfMemory(); + goto err_hweffect; + } + + /* Get the type. */ + type = SDL_SYS_HapticEffectType(base->type); + if (type == NULL) { + goto err_hweffect; + } + + /* Get the effect. */ + if (SDL_SYS_ToFFEFFECT(haptic, &effect->hweffect->effect, base) < 0) { + goto err_effectdone; + } + + /* Create the actual effect. */ + ret = FFDeviceCreateEffect(haptic->hwdata->device, type, + &effect->hweffect->effect, &effect->hweffect->ref); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to create effect: %s.", FFStrError(ret)); + goto err_effectdone; + } + + return 0; + +err_effectdone: + SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, base->type); +err_hweffect: + if (effect->hweffect != NULL) { + SDL_free(effect->hweffect); + effect->hweffect = NULL; + } + return -1; +} + + +/* + * Updates an effect. + */ +int +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, SDL_HapticEffect * data) +{ + HRESULT ret; + FFEffectParameterFlag flags; + FFEFFECT temp; + + /* Get the effect. */ + SDL_memset(&temp, 0, sizeof(FFEFFECT)); + if (SDL_SYS_ToFFEFFECT(haptic, &temp, data) < 0) { + goto err_update; + } + + /* Set the flags. Might be worthwhile to diff temp with loaded effect and + * only change those parameters. */ + flags = FFEP_DIRECTION | + FFEP_DURATION | + FFEP_ENVELOPE | + FFEP_STARTDELAY | + FFEP_TRIGGERBUTTON | + FFEP_TRIGGERREPEATINTERVAL | + FFEP_TYPESPECIFICPARAMS; + + /* Create the actual effect. */ + ret = FFEffectSetParameters(effect->hweffect->ref, &temp, flags); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to update effect: %s.", FFStrError(ret)); + goto err_update; + } + + /* Copy it over. */ + SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, data->type); + SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(FFEFFECT)); + + return 0; + +err_update: + SDL_SYS_HapticFreeFFEFFECT(&temp, data->type); + return -1; +} + + +/* + * Runs an effect. + */ +int +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect, + Uint32 iterations) +{ + HRESULT ret; + Uint32 iter; + + /* Check if it's infinite. */ + if (iterations == SDL_HAPTIC_INFINITY) { + iter = FF_INFINITE; + } + else + iter = iterations; + + /* Run the effect. */ + ret = FFEffectStart(effect->hweffect->ref, iter, 0); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to run the effect: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Stops an effect. + */ +int +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + HRESULT ret; + + ret = FFEffectStop(effect->hweffect->ref); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to stop the effect: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Frees the effect. + */ +void +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + HRESULT ret; + + ret = FFDeviceReleaseEffect(haptic->hwdata->device, effect->hweffect->ref); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error removing the effect from the device: %s.", + FFStrError(ret)); + } + SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, effect->effect.type); + SDL_free(effect->hweffect); + effect->hweffect = NULL; +} + + +/* + * Gets the status of a haptic effect. + */ +int +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + HRESULT ret; + FFEffectStatusFlag status; + + ret = FFEffectGetEffectStatus(effect->hweffect->ref, &status); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to get effect status: %s.", FFStrError(ret)); + return -1; + } + + if (status == 0) return SDL_FALSE; + return SDL_TRUE; /* Assume it's playing or emulated. */ +} + + +/* + * Sets the gain. + */ +int +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) +{ + HRESULT ret; + Uint32 val; + + val = gain * 100; /* Mac OS X uses 0 to 10,000 */ + ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device, FFPROP_FFGAIN, &val); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error setting gain: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Sets the autocentering. + */ +int +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) +{ + HRESULT ret; + Uint32 val; + + /* Mac OS X only has 0 (off) and 1 (on) */ + if (autocenter == 0) val = 0; + else val = 1; + + ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device, + FFPROP_AUTOCENTER, &val); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error setting autocenter: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Pauses the device. + */ +int +SDL_SYS_HapticPause(SDL_Haptic * haptic) +{ + HRESULT ret; + + ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device, + FFSFFC_PAUSE); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error pausing device: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Unpauses the device. + */ +int +SDL_SYS_HapticUnpause(SDL_Haptic * haptic) +{ + HRESULT ret; + + ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device, + FFSFFC_CONTINUE); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error pausing device: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Stops all currently playing effects. + */ +int +SDL_SYS_HapticStopAll(SDL_Haptic * haptic) +{ + HRESULT ret; + + ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device, + FFSFFC_STOPALL); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error stopping device: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +#endif /* SDL_HAPTIC_IOKIT */ \ No newline at end of file diff --git a/src/haptic/darwin/SDL_syshaptic.c.bak b/src/haptic/darwin/SDL_syshaptic.c.bak new file mode 100644 index 000000000..0ec731296 --- /dev/null +++ b/src/haptic/darwin/SDL_syshaptic.c.bak @@ -0,0 +1,1284 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 2008 Edgar Simo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_HAPTIC_IOKIT + +#include "SDL_haptic.h" +#include "../SDL_syshaptic.h" +#include "SDL_joystick.h" +#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */ +#include "../../joystick/darwin/SDL_sysjoystick_c.h" /* For joystick hwdata */ + +#include +#include +#include +#include + + +#define MAX_HAPTICS 32 + + +/* + * List of available haptic devices. + */ +static struct +{ + char name[256]; /* Name of the device. */ + + io_service_t dev; /* Node we use to create the device. */ + SDL_Haptic *haptic; /* Haptic currently assosciated with it. */ + + /* Usage pages for determining if it's a mouse or not. */ + long usage; + long usagePage; +} SDL_hapticlist[MAX_HAPTICS]; + + +/* + * Haptic system hardware data. + */ +struct haptic_hwdata +{ + FFDeviceObjectReference device; /* Hardware device. */ + UInt8 axes[3]; +}; + + +/* + * Haptic system effect data. + */ +struct haptic_hweffect +{ + FFEffectObjectReference ref; /* Reference. */ + struct FFEFFECT effect; /* Hardware effect. */ +}; + +/* + * Prototypes. + */ +static void SDL_SYS_HapticFreeFFEFFECT(FFEFFECT * effect, int type); +static int HIDGetDeviceProduct(io_service_t dev, char * name); + + +/* + * Like strerror but for force feedback errors. + */ +static const char * +FFStrError(HRESULT err) +{ + switch (err) { + case FFERR_DEVICEFULL: + return "device full"; + /* This should be valid, but for some reason isn't defined... */ + /*case FFERR_DEVICENOTREG: + return "device not registered";*/ + case FFERR_DEVICEPAUSED: + return "device paused"; + case FFERR_DEVICERELEASED: + return "device released"; + case FFERR_EFFECTPLAYING: + return "effect playing"; + case FFERR_EFFECTTYPEMISMATCH: + return "effect type mismatch"; + case FFERR_EFFECTTYPENOTSUPPORTED: + return "effect type not supported"; + case FFERR_GENERIC: + return "undetermined error"; + case FFERR_HASEFFECTS: + return "device has effects"; + case FFERR_INCOMPLETEEFFECT: + return "incomplete effect"; + case FFERR_INTERNAL: + return "internal fault"; + case FFERR_INVALIDDOWNLOADID: + return "invalid download id"; + case FFERR_INVALIDPARAM: + return "invalid parameter"; + case FFERR_MOREDATA: + return "more data"; + case FFERR_NOINTERFACE: + return "interface not supported"; + case FFERR_NOTDOWNLOADED: + return "effect is not downloaded"; + case FFERR_NOTINITIALIZED: + return "object has not been initialized"; + case FFERR_OUTOFMEMORY: + return "out of memory"; + case FFERR_UNPLUGGED: + return "device is unplugged"; + case FFERR_UNSUPPORTED: + return "function call unsupported"; + case FFERR_UNSUPPORTEDAXIS: + return "axis unsupported"; + + default: + return "unknown error"; + } +} + + +/* + * Initializes the haptic subsystem. + */ +int +SDL_SYS_HapticInit(void) +{ + int numhaptics; + IOReturn result; + io_iterator_t iter; + CFDictionaryRef match; + io_service_t device; + CFMutableDictionaryRef hidProperties; + CFTypeRef refCF; + + /* Clear all the memory. */ + SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist)); + + /* Get HID devices. */ + match = IOServiceMatching(kIOHIDDeviceKey); + if (match == NULL) { + SDL_SetError("Haptic: Failed to get IOServiceMatching."); + return -1; + } + + /* Now search I/O Registry for matching devices. */ + result = IOServiceGetMatchingServices(kIOMasterPortDefault, match, &iter); + if (result != kIOReturnSuccess) { + SDL_SetError("Haptic: Couldn't create a HID object iterator."); + return -1; + } + /* IOServiceGetMatchingServices consumes dictionary. */ + + if (!IOIteratorIsValid(iter)) { /* No iterator. */ + numhaptics = 0; + return 0; + } + + numhaptics = 0; + while ((device = IOIteratorNext(iter)) != IO_OBJECT_NULL) { + + /* Check for force feedback. */ + if (FFIsForceFeedback(device) == FF_OK) { + + /* Set basic device data. */ + HIDGetDeviceProduct(device, SDL_hapticlist[numhaptics].name); + SDL_hapticlist[numhaptics].dev = device; + SDL_hapticlist[numhaptics].haptic = NULL; + + /* Set usage pages. */ + hidProperties = 0; + refCF = 0; + result = IORegistryEntryCreateCFProperties(device, + &hidProperties, kCFAllocatorDefault, kNilOptions); + if ((result == KERN_SUCCESS) && hidProperties) { + refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey)); + if (refCF) { + if (!CFNumberGetValue(refCF, kCFNumberLongType, + &SDL_hapticlist[numhaptics].usagePage)) + SDL_SetError("Haptic: Recieving device's usage page."); + refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsageKey)); + if (refCF) { + if (!CFNumberGetValue(refCF, kCFNumberLongType, + &SDL_hapticlist[numhaptics].usage)) + SDL_SetError("Haptic: Recieving device's usage."); + } + } + CFRelease(hidProperties); + } + + /* Device has been added. */ + numhaptics++; + } + else { /* Free the unused device. */ + IOObjectRelease(device); + } + + /* Reached haptic limit. */ + if (numhaptics >= MAX_HAPTICS) + break; + } + IOObjectRelease(iter); + + return numhaptics; +} + + +/* + * Return the name of a haptic device, does not need to be opened. + */ +const char * +SDL_SYS_HapticName(int index) +{ + return SDL_hapticlist[index].name; +} + +/* + * Gets the device's product name. + */ +static int +HIDGetDeviceProduct(io_service_t dev, char *name) +{ + CFMutableDictionaryRef hidProperties, usbProperties; + io_registry_entry_t parent1, parent2; + kern_return_t ret; + + hidProperties = usbProperties = 0; + + ret = IORegistryEntryCreateCFProperties(dev, &hidProperties, + kCFAllocatorDefault, + kNilOptions); + if ((ret != KERN_SUCCESS) || !hidProperties) { + SDL_SetError("Haptic: Unable to create CFProperties."); + return -1; + } + + /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also + * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties + */ + if ((KERN_SUCCESS == + IORegistryEntryGetParentEntry(dev, kIOServicePlane, &parent1)) + && (KERN_SUCCESS == + IORegistryEntryGetParentEntry(parent1, kIOServicePlane, &parent2)) + && (KERN_SUCCESS == + IORegistryEntryCreateCFProperties(parent2, &usbProperties, + kCFAllocatorDefault, + kNilOptions))) { + if (usbProperties) { + CFTypeRef refCF = 0; + /* get device info + * try hid dictionary first, if fail then go to usb dictionary + */ + + + /* Get product name */ + refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductKey)); + if (!refCF) + refCF = + CFDictionaryGetValue(usbProperties, CFSTR("USB Product Name")); + if (refCF) { + if (!CFStringGetCString(refCF, name, 256, + CFStringGetSystemEncoding())) { + SDL_SetError("Haptic: CFStringGetCString error retrieving pDevice->product."); + return -1; + } + } + + CFRelease(usbProperties); + } + else { + SDL_SetError("Haptic: IORegistryEntryCreateCFProperties failed to create usbProperties."); + return -1; + } + + /* Release stuff. */ + if (kIOReturnSuccess != IOObjectRelease(parent2)) { + SDL_SetError("Haptic: IOObjectRelease error with parent2."); + } + if (kIOReturnSuccess != IOObjectRelease(parent1)) { + SDL_SetError("Haptic: IOObjectRelease error with parent1."); + } + } + else { + SDL_SetError("Haptic: Error getting registry entries."); + return -1; + } + + return 0; +} + + +#define FF_TEST(ff, s) \ +if (features.supportedEffects & (ff)) supported |= (s) +/* + * Gets supported features. + */ +static unsigned int +GetSupportedFeatures(SDL_Haptic* haptic) +{ + HRESULT ret; + FFDeviceObjectReference device; + FFCAPABILITIES features; + unsigned int supported; + Uint32 val; + + device = haptic->hwdata->device; + + ret = FFDeviceGetForceFeedbackCapabilities(device, &features); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to get device's supported features."); + return -1; + } + + supported = 0; + + /* Get maximum effects. */ + haptic->neffects = features.storageCapacity; + haptic->nplaying = features.playbackCapacity; + + /* Test for effects. */ + FF_TEST(FFCAP_ET_CONSTANTFORCE, SDL_HAPTIC_CONSTANT); + FF_TEST(FFCAP_ET_RAMPFORCE, SDL_HAPTIC_RAMP); + FF_TEST(FFCAP_ET_SQUARE, SDL_HAPTIC_SQUARE); + FF_TEST(FFCAP_ET_SINE, SDL_HAPTIC_SINE); + FF_TEST(FFCAP_ET_TRIANGLE, SDL_HAPTIC_TRIANGLE); + FF_TEST(FFCAP_ET_SAWTOOTHUP, SDL_HAPTIC_SAWTOOTHUP); + FF_TEST(FFCAP_ET_SAWTOOTHDOWN, SDL_HAPTIC_SAWTOOTHDOWN); + FF_TEST(FFCAP_ET_SPRING, SDL_HAPTIC_SPRING); + FF_TEST(FFCAP_ET_DAMPER, SDL_HAPTIC_DAMPER); + FF_TEST(FFCAP_ET_INERTIA, SDL_HAPTIC_INERTIA); + FF_TEST(FFCAP_ET_FRICTION, SDL_HAPTIC_FRICTION); + FF_TEST(FFCAP_ET_CUSTOMFORCE, SDL_HAPTIC_CUSTOM); + + /* Check if supports gain. */ + ret = FFDeviceGetForceFeedbackProperty( device, FFPROP_FFGAIN, + &val, sizeof(val)); + if (ret == FF_OK) supported |= SDL_HAPTIC_GAIN; + else if (ret != FFERR_UNSUPPORTED) { + SDL_SetError("Haptic: Unable to get if device supports gain: %s.", + FFStrError(ret)); + return -1; + } + + /* Checks if supports autocenter. */ + ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_AUTOCENTER, + &val, sizeof(val)); + if (ret == FF_OK) supported |= SDL_HAPTIC_AUTOCENTER; + else if (ret != FFERR_UNSUPPORTED) { + SDL_SetError("Haptic: Unable to get if device supports autocenter: %s.", + FFStrError(ret)); + return -1; + } + + /* Check for axes, we have an artificial limit on axes */ + haptic->naxes = ((features.numFfAxes) > 3) ? + 3 : features.numFfAxes; + /* Actually store the axes we want to use */ + SDL_memcpy( haptic->hwdata->axes, features.ffAxes, haptic->naxes * sizeof(Uint8)); + + /* Always supported features. */ + supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE; + + haptic->supported = supported; + return 0;; +} + + +/* + * Opens the haptic device from the file descriptor. + */ +static int +SDL_SYS_HapticOpenFromService(SDL_Haptic * haptic, io_service_t service) +{ + HRESULT ret; + int ret2; + + /* Allocate the hwdata */ + haptic->hwdata = (struct haptic_hwdata *) + SDL_malloc(sizeof(*haptic->hwdata)); + if (haptic->hwdata == NULL) { + SDL_OutOfMemory(); + goto creat_err; + } + SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); + + /* Open the device */ + ret = FFCreateDevice( service, &haptic->hwdata->device); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to create device from service: %s.", + FFStrError(ret)); + goto creat_err; + } + + /* Get supported features. */ + ret2 = GetSupportedFeatures( haptic ); + if (haptic->supported < 0) { + goto open_err; + } + + + /* Reset and then enable actuators. */ + ret = FFDeviceSendForceFeedbackCommand( haptic->hwdata->device, + FFSFFC_RESET ); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to reset device: %s.", FFStrError(ret)); + goto open_err; + } + ret = FFDeviceSendForceFeedbackCommand( haptic->hwdata->device, + FFSFFC_SETACTUATORSON ); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to enable actuators: %s.", FFStrError(ret)); + goto open_err; + } + + + /* Allocate effects memory. */ + haptic->effects = (struct haptic_effect *) + SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); + if (haptic->effects == NULL) { + SDL_OutOfMemory(); + goto open_err; + } + /* Clear the memory */ + SDL_memset(haptic->effects, 0, + sizeof(struct haptic_effect) * haptic->neffects); + + return 0; + + /* Error handling */ +open_err: + FFReleaseDevice(haptic->hwdata->device); +creat_err: + if (haptic->hwdata != NULL) { + free(haptic->hwdata); + haptic->hwdata = NULL; + } + return -1; + +} + + +/* + * Opens a haptic device for usage. + */ +int +SDL_SYS_HapticOpen(SDL_Haptic * haptic) +{ + return SDL_SYS_HapticOpenFromService(haptic, + SDL_hapticlist[haptic->index].dev); +} + + +/* + * Opens a haptic device from first mouse it finds for usage. + */ +int +SDL_SYS_HapticMouse(void) +{ + int i; + + for (i=0; ihwdata->ffservice != 0) + return SDL_TRUE; + return SDL_FALSE; +} + + +/* + * Checks to see if the haptic device and joystick and in reality the same. + */ +int +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + if (IOObjectIsEqualTo((io_object_t) haptic->hwdata->device, + joystick->hwdata->ffservice)) + return 1; + return 0; +} + + +/* + * Opens a SDL_Haptic from a SDL_Joystick. + */ +int +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + return SDL_SYS_HapticOpenFromService(haptic, + joystick->hwdata->ffservice); +} + + +/* + * Closes the haptic device. + */ +void +SDL_SYS_HapticClose(SDL_Haptic * haptic) +{ + if (haptic->hwdata) { + + /* Free Effects. */ + SDL_free(haptic->effects); + haptic->effects = NULL; + haptic->neffects = 0; + + /* Clean up */ + FFReleaseDevice(haptic->hwdata->device); + + /* Free */ + SDL_free(haptic->hwdata); + haptic->hwdata = NULL; + } +} + + +/* + * Clean up after system specific haptic stuff + */ +void +SDL_SYS_HapticQuit(void) +{ + int i; + + for (i=0; i < SDL_numhaptics; i++) { + /* Opened and not closed haptics are leaked, this is on purpose. + * Close your haptic devices after usage. */ + + /* Free the io_service_t */ + IOObjectRelease(SDL_hapticlist[i].dev); + } +} + + +/* + * Converts an SDL trigger button to an FFEFFECT trigger button. + */ +static DWORD +FFGetTriggerButton( Uint16 button ) +{ + DWORD dwTriggerButton; + + dwTriggerButton = FFEB_NOTRIGGER; + + if (button != 0) { + dwTriggerButton = FFJOFS_BUTTON(button - 1); + } + + return dwTriggerButton; +} + + +/* + * Sets the direction. + */ +static int +SDL_SYS_SetDirection( FFEFFECT * effect, SDL_HapticDirection *dir, int naxes ) +{ + LONG *rglDir; + + /* Handle no axes a part. */ + if (naxes == 0) { + effect->dwFlags |= FFEFF_SPHERICAL; /* Set as default. */ + effect->rglDirection = NULL; + return 0; + } + + /* Has axes. */ + rglDir = SDL_malloc( sizeof(LONG) * naxes ); + if (rglDir == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset( rglDir, 0, sizeof(LONG) * naxes ); + effect->rglDirection = rglDir; + + switch (dir->type) { + case SDL_HAPTIC_POLAR: + effect->dwFlags |= FFEFF_POLAR; + rglDir[0] = dir->dir[0]; + return 0; + case SDL_HAPTIC_CARTESIAN: + effect->dwFlags |= FFEFF_CARTESIAN; + rglDir[0] = dir->dir[0]; + if (naxes > 1) + rglDir[1] = dir->dir[1]; + if (naxes > 2) + rglDir[2] = dir->dir[2]; + return 0; + case SDL_HAPTIC_SPHERICAL: + effect->dwFlags |= FFEFF_SPHERICAL; + rglDir[0] = dir->dir[0]; + if (naxes > 1) + rglDir[1] = dir->dir[1]; + if (naxes > 2) + rglDir[2] = dir->dir[2]; + return 0; + + default: + SDL_SetError("Haptic: Unknown direction type."); + return -1; + } +} + + +/* Clamps and converts. */ +#define CCONVERT(x) (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF) +/* Just converts. */ +#define CONVERT(x) (((x)*10000) / 0x7FFF) +/* + * Creates the FFEFFECT from a SDL_HapticEffect. + */ +static int +SDL_SYS_ToFFEFFECT( SDL_Haptic * haptic, FFEFFECT * dest, SDL_HapticEffect * src ) +{ + int i; + FFCONSTANTFORCE *constant; + FFPERIODIC *periodic; + FFCONDITION *condition; /* Actually an array of conditions - one per axis. */ + FFRAMPFORCE *ramp; + FFCUSTOMFORCE *custom; + FFENVELOPE *envelope; + SDL_HapticConstant *hap_constant; + SDL_HapticPeriodic *hap_periodic; + SDL_HapticCondition *hap_condition; + SDL_HapticRamp *hap_ramp; + SDL_HapticCustom *hap_custom; + DWORD *axes; + + /* Set global stuff. */ + SDL_memset(dest, 0, sizeof(FFEFFECT)); + dest->dwSize = sizeof(FFEFFECT); /* Set the structure size. */ + dest->dwSamplePeriod = 0; /* Not used by us. */ + dest->dwGain = 10000; /* Gain is set globally, not locally. */ + dest->dwFlags = FFEFF_OBJECTOFFSETS; /* Seems obligatory. */ + + /* Envelope. */ + envelope = SDL_malloc( sizeof(FFENVELOPE) ); + if (envelope == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(envelope, 0, sizeof(FFENVELOPE)); + dest->lpEnvelope = envelope; + envelope->dwSize = sizeof(FFENVELOPE); /* Always should be this. */ + + /* Axes. */ + dest->cAxes = haptic->naxes; + if (dest->cAxes > 0) { + axes = SDL_malloc(sizeof(DWORD) * dest->cAxes); + if (axes == NULL) { + SDL_OutOfMemory(); + return -1; + } + axes[0] = haptic->hwdata->axes[0]; /* Always at least one axis. */ + if (dest->cAxes > 1) { + axes[1] = haptic->hwdata->axes[1]; + } + if (dest->cAxes > 2) { + axes[2] = haptic->hwdata->axes[2]; + } + dest->rgdwAxes = axes; + } + + + /* The big type handling switch, even bigger then linux's version. */ + switch (src->type) { + case SDL_HAPTIC_CONSTANT: + hap_constant = &src->constant; + constant = SDL_malloc( sizeof(FFCONSTANTFORCE) ); + if (constant == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(constant, 0, sizeof(FFCONSTANTFORCE)); + + /* Specifics */ + constant->lMagnitude = CONVERT(hap_constant->level); + dest->cbTypeSpecificParams = sizeof(FFCONSTANTFORCE); + dest->lpvTypeSpecificParams = constant; + + /* Generics */ + dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = FFGetTriggerButton(hap_constant->button); + dest->dwTriggerRepeatInterval = hap_constant->interval; + dest->dwStartDelay = hap_constant->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_constant->attack_length==0) && (hap_constant->fade_length==0)) { + SDL_free(envelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CCONVERT(hap_constant->attack_level); + envelope->dwAttackTime = hap_constant->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_constant->fade_level); + envelope->dwFadeTime = hap_constant->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_SINE: + case SDL_HAPTIC_SQUARE: + case SDL_HAPTIC_TRIANGLE: + case SDL_HAPTIC_SAWTOOTHUP: + case SDL_HAPTIC_SAWTOOTHDOWN: + hap_periodic = &src->periodic; + periodic = SDL_malloc(sizeof(FFPERIODIC)); + if (periodic == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(periodic, 0, sizeof(FFPERIODIC)); + + /* Specifics */ + periodic->dwMagnitude = CONVERT(hap_periodic->magnitude); + periodic->lOffset = CONVERT(hap_periodic->offset); + periodic->dwPhase = hap_periodic->phase; + periodic->dwPeriod = hap_periodic->period * 1000; + dest->cbTypeSpecificParams = sizeof(FFPERIODIC); + dest->lpvTypeSpecificParams = periodic; + + /* Generics */ + dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = FFGetTriggerButton(hap_periodic->button); + dest->dwTriggerRepeatInterval = hap_periodic->interval; + dest->dwStartDelay = hap_periodic->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_periodic->attack_length==0) && (hap_periodic->fade_length==0)) { + SDL_free(envelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CCONVERT(hap_periodic->attack_level); + envelope->dwAttackTime = hap_periodic->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_periodic->fade_level); + envelope->dwFadeTime = hap_periodic->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_SPRING: + case SDL_HAPTIC_DAMPER: + case SDL_HAPTIC_INERTIA: + case SDL_HAPTIC_FRICTION: + hap_condition = &src->condition; + condition = SDL_malloc(sizeof(FFCONDITION) * dest->cAxes); + if (condition == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(condition, 0, sizeof(FFCONDITION)); + + /* Specifics */ + for (i=0; icAxes; i++) { + condition[i].lOffset = CONVERT(hap_condition->center[i]); + condition[i].lPositiveCoefficient = CONVERT(hap_condition->right_coeff[i]); + condition[i].lNegativeCoefficient = CONVERT(hap_condition->left_coeff[i]); + condition[i].dwPositiveSaturation = CCONVERT(hap_condition->right_sat[i]); + condition[i].dwNegativeSaturation = CCONVERT(hap_condition->left_sat[i]); + condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i]); + } + dest->cbTypeSpecificParams = sizeof(FFCONDITION) * dest->cAxes; + dest->lpvTypeSpecificParams = condition; + + /* Generics */ + dest->dwDuration = hap_condition->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = FFGetTriggerButton(hap_condition->button); + dest->dwTriggerRepeatInterval = hap_condition->interval; + dest->dwStartDelay = hap_condition->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope - Not actually supported by most CONDITION implementations. */ + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + + break; + + case SDL_HAPTIC_RAMP: + hap_ramp = &src->ramp; + ramp = SDL_malloc(sizeof(FFRAMPFORCE)); + if (ramp == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(ramp, 0, sizeof(FFRAMPFORCE)); + + /* Specifics */ + ramp->lStart = CONVERT(hap_ramp->start); + ramp->lEnd = CONVERT(hap_ramp->end); + dest->cbTypeSpecificParams = sizeof(FFRAMPFORCE); + dest->lpvTypeSpecificParams = ramp; + + /* Generics */ + dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = FFGetTriggerButton(hap_ramp->button); + dest->dwTriggerRepeatInterval = hap_ramp->interval; + dest->dwStartDelay = hap_ramp->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_ramp->attack_length==0) && (hap_ramp->fade_length==0)) { + SDL_free(envelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CCONVERT(hap_ramp->attack_level); + envelope->dwAttackTime = hap_ramp->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_ramp->fade_level); + envelope->dwFadeTime = hap_ramp->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_CUSTOM: + hap_custom = &src->custom; + custom = SDL_malloc(sizeof(FFCUSTOMFORCE)); + if (custom == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(custom, 0, sizeof(FFCUSTOMFORCE)); + + /* Specifics */ + custom->cChannels = hap_custom->channels; + custom->dwSamplePeriod = hap_custom->period * 1000; + custom->cSamples = hap_custom->samples; + custom->rglForceData = SDL_malloc(sizeof(LONG)*custom->cSamples*custom->cChannels); + for (i=0; isamples*hap_custom->channels; i++) { /* Copy data. */ + custom->rglForceData[i] = CCONVERT(hap_custom->data[i]); + } + dest->cbTypeSpecificParams = sizeof(FFCUSTOMFORCE); + dest->lpvTypeSpecificParams = custom; + + /* Generics */ + dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = FFGetTriggerButton(hap_custom->button); + dest->dwTriggerRepeatInterval = hap_custom->interval; + dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_custom->attack_length==0) && (hap_custom->fade_length==0)) { + SDL_free(envelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CCONVERT(hap_custom->attack_level); + envelope->dwAttackTime = hap_custom->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_custom->fade_level); + envelope->dwFadeTime = hap_custom->fade_length * 1000; + } + + break; + + + default: + SDL_SetError("Haptic: Unknown effect type."); + return -1; + } + + return 0; +} + + +/* + * Frees an FFEFFECT allocated by SDL_SYS_ToFFEFFECT. + */ +static void +SDL_SYS_HapticFreeFFEFFECT( FFEFFECT * effect, int type ) +{ + FFCUSTOMFORCE *custom; + + if (effect->lpEnvelope != NULL) { + SDL_free(effect->lpEnvelope); + effect->lpEnvelope = NULL; + } + if (effect->rgdwAxes != NULL) { + SDL_free(effect->rgdwAxes); + effect->rgdwAxes = NULL; + } + if (effect->lpvTypeSpecificParams != NULL) { + if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */ + custom = (FFCUSTOMFORCE*) effect->lpvTypeSpecificParams; + SDL_free(custom->rglForceData); + custom->rglForceData = NULL; + } + SDL_free(effect->lpvTypeSpecificParams); + effect->lpvTypeSpecificParams = NULL; + } + if (effect->rglDirection != NULL) { + SDL_free(effect->rglDirection); + effect->rglDirection = NULL; + } +} + + +/* + * Gets the effect type from the generic SDL haptic effect wrapper. + */ +CFUUIDRef +SDL_SYS_HapticEffectType( Uint16 type ) +{ + switch (type) { + case SDL_HAPTIC_CONSTANT: + return kFFEffectType_ConstantForce_ID; + + case SDL_HAPTIC_RAMP: + return kFFEffectType_RampForce_ID; + + case SDL_HAPTIC_SQUARE: + return kFFEffectType_Square_ID; + + case SDL_HAPTIC_SINE: + return kFFEffectType_Sine_ID; + + case SDL_HAPTIC_TRIANGLE: + return kFFEffectType_Triangle_ID; + + case SDL_HAPTIC_SAWTOOTHUP: + return kFFEffectType_SawtoothUp_ID; + + case SDL_HAPTIC_SAWTOOTHDOWN: + return kFFEffectType_SawtoothDown_ID; + + case SDL_HAPTIC_SPRING: + return kFFEffectType_Spring_ID; + + case SDL_HAPTIC_DAMPER: + return kFFEffectType_Damper_ID; + + case SDL_HAPTIC_INERTIA: + return kFFEffectType_Inertia_ID; + + case SDL_HAPTIC_FRICTION: + return kFFEffectType_Friction_ID; + + case SDL_HAPTIC_CUSTOM: + return kFFEffectType_CustomForce_ID; + + default: + SDL_SetError("Haptic: Unknown effect type."); + return NULL; + } +} + + +/* + * Creates a new haptic effect. + */ +int +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect * effect, + SDL_HapticEffect * base) +{ + HRESULT ret; + CFUUIDRef type; + + /* Alloc the effect. */ + effect->hweffect = (struct haptic_hweffect *) + SDL_malloc(sizeof(struct haptic_hweffect)); + if (effect->hweffect == NULL) { + SDL_OutOfMemory(); + goto err_hweffect; + } + + /* Get the type. */ + type = SDL_SYS_HapticEffectType(base->type); + if (type == NULL) { + goto err_hweffect; + } + + /* Get the effect. */ + if (SDL_SYS_ToFFEFFECT(haptic, &effect->hweffect->effect, base) < 0) { + goto err_effectdone; + } + + /* Create the actual effect. */ + ret = FFDeviceCreateEffect(haptic->hwdata->device, type, + &effect->hweffect->effect, &effect->hweffect->ref); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to create effect: %s.", FFStrError(ret)); + goto err_effectdone; + } + + return 0; + +err_effectdone: + SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, base->type); +err_hweffect: + if (effect->hweffect != NULL) { + SDL_free(effect->hweffect); + effect->hweffect = NULL; + } + return -1; +} + + +/* + * Updates an effect. + */ +int +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, SDL_HapticEffect * data) +{ + HRESULT ret; + FFEffectParameterFlag flags; + FFEFFECT temp; + + /* Get the effect. */ + SDL_memset(&temp, 0, sizeof(FFEFFECT)); + if (SDL_SYS_ToFFEFFECT(haptic, &temp, data) < 0) { + goto err_update; + } + + /* Set the flags. Might be worthwhile to diff temp with loaded effect and + * only change those parameters. */ + flags = FFEP_DIRECTION | + FFEP_DURATION | + FFEP_ENVELOPE | + FFEP_STARTDELAY | + FFEP_TRIGGERBUTTON | + FFEP_TRIGGERREPEATINTERVAL | + FFEP_TYPESPECIFICPARAMS; + + /* Create the actual effect. */ + ret = FFEffectSetParameters(effect->hweffect->ref, &temp, flags); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to update effect: %s.", FFStrError(ret)); + goto err_update; + } + + /* Copy it over. */ + SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, data->type); + SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(FFEFFECT)); + + return 0; + +err_update: + SDL_SYS_HapticFreeFFEFFECT(&temp, data->type); + return -1; +} + + +/* + * Runs an effect. + */ +int +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect, + Uint32 iterations) +{ + HRESULT ret; + Uint32 iter; + + /* Check if it's infinite. */ + if (iterations == SDL_HAPTIC_INFINITY) { + iter = FF_INFINITE; + } + else + iter = iterations; + + /* Run the effect. */ + ret = FFEffectStart(effect->hweffect->ref, iter, 0); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to run the effect: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Stops an effect. + */ +int +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + HRESULT ret; + + ret = FFEffectStop(effect->hweffect->ref); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to stop the effect: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Frees the effect. + */ +void +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + HRESULT ret; + + ret = FFDeviceReleaseEffect(haptic->hwdata->device, effect->hweffect->ref); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error removing the effect from the device: %s.", + FFStrError(ret)); + } + SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, effect->effect.type); + SDL_free(effect->hweffect); + effect->hweffect = NULL; +} + + +/* + * Gets the status of a haptic effect. + */ +int +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + HRESULT ret; + FFEffectStatusFlag status; + + ret = FFEffectGetEffectStatus(effect->hweffect->ref, &status); + if (ret != FF_OK) { + SDL_SetError("Haptic: Unable to get effect status: %s.", FFStrError(ret)); + return -1; + } + + if (status == 0) return SDL_FALSE; + return SDL_TRUE; /* Assume it's playing or emulated. */ +} + + +/* + * Sets the gain. + */ +int +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) +{ + HRESULT ret; + Uint32 val; + + val = gain * 100; /* Mac OS X uses 0 to 10,000 */ + ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device, FFPROP_FFGAIN, &val); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error setting gain: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Sets the autocentering. + */ +int +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) +{ + HRESULT ret; + Uint32 val; + + /* Mac OS X only has 0 (off) and 1 (on) */ + if (autocenter == 0) val = 0; + else val = 1; + + ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device, + FFPROP_AUTOCENTER, &val); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error setting autocenter: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Pauses the device. + */ +int +SDL_SYS_HapticPause(SDL_Haptic * haptic) +{ + HRESULT ret; + + ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device, + FFSFFC_PAUSE); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error pausing device: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Unpauses the device. + */ +int +SDL_SYS_HapticUnpause(SDL_Haptic * haptic) +{ + HRESULT ret; + + ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device, + FFSFFC_CONTINUE); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error pausing device: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +/* + * Stops all currently playing effects. + */ +int +SDL_SYS_HapticStopAll(SDL_Haptic * haptic) +{ + HRESULT ret; + + ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device, + FFSFFC_STOPALL); + if (ret != FF_OK) { + SDL_SetError("Haptic: Error stopping device: %s.", FFStrError(ret)); + return -1; + } + + return 0; +} + + +#endif /* SDL_HAPTIC_IOKIT */ diff --git a/src/haptic/dummy/SDL_syshaptic.c b/src/haptic/dummy/SDL_syshaptic.c new file mode 100644 index 000000000..4d0bf0d6f --- /dev/null +++ b/src/haptic/dummy/SDL_syshaptic.c @@ -0,0 +1,193 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 2008 Edgar Simo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#if defined(SDL_HAPTIC_DUMMY) || defined(SDL_HAPTIC_DISABLED) + +#include "SDL_haptic.h" +#include "../SDL_syshaptic.h" + + +static int +SDL_SYS_LogicError(void) +{ + SDL_SetError("Logic error: No haptic devices available."); + return 0; +} + + +int +SDL_SYS_HapticInit(void) +{ + return 0; +} + + +const char * +SDL_SYS_HapticName(int index) +{ + SDL_SYS_LogicError(); + return NULL; +} + + +int +SDL_SYS_HapticOpen(SDL_Haptic * haptic) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticMouse(void) +{ + return -1; +} + + +int +SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick) +{ + return 0; +} + + +int +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + return 0; +} + + +void +SDL_SYS_HapticClose(SDL_Haptic * haptic) +{ + return; +} + + +void +SDL_SYS_HapticQuit(void) +{ + return; +} + + +int +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, + SDL_HapticEffect * base) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, + SDL_HapticEffect * data) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect, Uint32 iterations) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + SDL_SYS_LogicError(); + return -1; +} + + +void +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + SDL_SYS_LogicError(); + return; +} + + +int SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) +{ + SDL_SYS_LogicError(); + return -1; +} + +int +SDL_SYS_HapticPause(SDL_Haptic * haptic) +{ + SDL_SYS_LogicError(); + return -1; +} + +int +SDL_SYS_HapticUnpause(SDL_Haptic * haptic) +{ + SDL_SYS_LogicError(); + return -1; +} + +int +SDL_SYS_HapticStopAll(SDL_Haptic * haptic) +{ + SDL_SYS_LogicError(); + return -1; +} + + + +#endif /* SDL_HAPTIC_DUMMY || SDL_HAPTIC_DISABLED */ \ No newline at end of file diff --git a/src/haptic/dummy/SDL_syshaptic.c.bak b/src/haptic/dummy/SDL_syshaptic.c.bak new file mode 100644 index 000000000..f23f369e4 --- /dev/null +++ b/src/haptic/dummy/SDL_syshaptic.c.bak @@ -0,0 +1,193 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 2008 Edgar Simo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#if defined(SDL_HAPTIC_DUMMY) || defined(SDL_HAPTIC_DISABLED) + +#include "SDL_haptic.h" +#include "../SDL_syshaptic.h" + + +static int +SDL_SYS_LogicError(void) +{ + SDL_SetError("Logic error: No haptic devices available."); + return 0; +} + + +int +SDL_SYS_HapticInit(void) +{ + return 0; +} + + +const char * +SDL_SYS_HapticName(int index) +{ + SDL_SYS_LogicError(); + return NULL; +} + + +int +SDL_SYS_HapticOpen(SDL_Haptic * haptic) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticMouse(void) +{ + return -1; +} + + +int +SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick) +{ + return 0; +} + + +int +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + return 0; +} + + +void +SDL_SYS_HapticClose(SDL_Haptic * haptic) +{ + return; +} + + +void +SDL_SYS_HapticQuit(void) +{ + return; +} + + +int +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, + SDL_HapticEffect * base) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, + SDL_HapticEffect * data) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect, Uint32 iterations) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + SDL_SYS_LogicError(); + return -1; +} + + +void +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + SDL_SYS_LogicError(); + return; +} + + +int SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) +{ + SDL_SYS_LogicError(); + return -1; +} + + +int +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) +{ + SDL_SYS_LogicError(); + return -1; +} + +int +SDL_SYS_HapticPause(SDL_Haptic * haptic) +{ + SDL_SYS_LogicError(); + return -1; +} + +int +SDL_SYS_HapticUnpause(SDL_Haptic * haptic) +{ + SDL_SYS_LogicError(); + return -1; +} + +int +SDL_SYS_HapticStopAll(SDL_Haptic * haptic) +{ + SDL_SYS_LogicError(); + return -1; +} + + + +#endif /* SDL_HAPTIC_DUMMY || SDL_HAPTIC_DISABLED */ diff --git a/src/haptic/linux/SDL_syshaptic.c b/src/haptic/linux/SDL_syshaptic.c new file mode 100644 index 000000000..39d59b031 --- /dev/null +++ b/src/haptic/linux/SDL_syshaptic.c @@ -0,0 +1,961 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 2008 Edgar Simo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_HAPTIC_LINUX + +#include "SDL_haptic.h" +#include "../SDL_syshaptic.h" +#include "SDL_joystick.h" +#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */ +#include "../../joystick/linux/SDL_sysjoystick_c.h" /* For joystick hwdata */ + +#include /* close */ +#include /* Force feedback linux stuff. */ +#include /* O_RDWR */ +#include /* INT_MAX */ +#include /* errno, strerror */ +#include /* atan2 */ +#include /* stat */ + +/* Just in case. */ +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + + +#define MAX_HAPTICS 32 /* It's doubtful someone has more then 32 evdev */ + + +/* + * List of available haptic devices. + */ +static struct +{ + char *fname; /* Dev path name (like /dev/input/event1) */ + SDL_Haptic *haptic; /* Assosciated haptic. */ +} SDL_hapticlist[MAX_HAPTICS]; + + +/* + * Haptic system hardware data. + */ +struct haptic_hwdata +{ + int fd; /* File descriptor of the device. */ + char *fname; /* Points to the name in SDL_hapticlist. */ +}; + + +/* + * Haptic system effect data. + */ +struct haptic_hweffect +{ + struct ff_effect effect; /* The linux kernel effect structure. */ +}; + + + +#define test_bit(nr, addr) \ + (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0) +#define EV_TEST(ev,f) \ + if (test_bit((ev), features)) ret |= (f); +/* + * Test whether a device has haptic properties. + * Returns available properties or 0 if there are none. + */ +static int +EV_IsHaptic(int fd) +{ + unsigned int ret; + unsigned long features[1 + FF_MAX/sizeof(unsigned long)]; + + /* Ask device for what it has. */ + ret = 0; + if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) { + SDL_SetError("Haptic: Unable to get device's features: %s", strerror(errno)); + return -1; + } + + /* Convert supported features to SDL_HAPTIC platform-neutral features. */ + EV_TEST(FF_CONSTANT, SDL_HAPTIC_CONSTANT); + EV_TEST(FF_SINE, SDL_HAPTIC_SINE); + EV_TEST(FF_SQUARE, SDL_HAPTIC_SQUARE); + EV_TEST(FF_TRIANGLE, SDL_HAPTIC_TRIANGLE); + EV_TEST(FF_SAW_UP, SDL_HAPTIC_SAWTOOTHUP); + EV_TEST(FF_SAW_DOWN, SDL_HAPTIC_SAWTOOTHDOWN); + EV_TEST(FF_RAMP, SDL_HAPTIC_RAMP); + EV_TEST(FF_SPRING, SDL_HAPTIC_SPRING); + EV_TEST(FF_FRICTION, SDL_HAPTIC_FRICTION); + EV_TEST(FF_DAMPER, SDL_HAPTIC_DAMPER); + EV_TEST(FF_INERTIA, SDL_HAPTIC_INERTIA); + EV_TEST(FF_CUSTOM, SDL_HAPTIC_CUSTOM); + EV_TEST(FF_GAIN, SDL_HAPTIC_GAIN); + EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER); + + /* Return what it supports. */ + return ret; +} + + +/* + * Tests whether a device is a mouse or not. + */ +static int +EV_IsMouse(int fd) +{ + unsigned long argp[40]; + + /* Ask for supported features. */ + if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(argp)), argp) < 0) { + return -1; + } + + /* Currently we only test for BTN_MOUSE which can give fake positives. */ + if (test_bit(BTN_MOUSE,argp) != 0) { + return 1; + } + + return 0; +} + +/* + * Initializes the haptic subsystem by finding available devices. + */ +int +SDL_SYS_HapticInit(void) +{ + const char joydev_pattern[] = "/dev/input/event%d"; + dev_t dev_nums[MAX_HAPTICS]; + char path[PATH_MAX]; + struct stat sb; + int fd; + int i, j, k; + int duplicate; + int numhaptics; + + numhaptics = 0; + + /* + * Limit amount of checks to MAX_HAPTICS since we may or may not have + * permission to some or all devices. + */ + i = 0; + for (j = 0; j < MAX_HAPTICS; ++j) { + + snprintf(path, PATH_MAX, joydev_pattern, i++); + + /* check to see if file exists */ + if (stat(path,&sb) != 0) + break; + + /* check for duplicates */ + duplicate = 0; + for (k = 0; (k < numhaptics) && !duplicate; ++k) { + if (sb.st_rdev == dev_nums[k]) { + duplicate = 1; + } + } + if (duplicate) { + continue; + } + + /* try to open */ + fd = open(path, O_RDWR, 0); + if (fd < 0) continue; + +#ifdef DEBUG_INPUT_EVENTS + printf("Checking %s\n", path); +#endif + + /* see if it works */ + if (EV_IsHaptic(fd) > 0) { + SDL_hapticlist[numhaptics].fname = SDL_strdup(path); + SDL_hapticlist[numhaptics].haptic = NULL; + dev_nums[numhaptics] = sb.st_rdev; + ++numhaptics; + } + close(fd); + } + + return numhaptics; +} + + +/* + * Gets the name from a file descriptor. + */ +static const char * +SDL_SYS_HapticNameFromFD(int fd) +{ + static char namebuf[128]; + + /* We use the evdev name ioctl. */ + if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) { + return NULL; + } + + return namebuf; +} + + +/* + * Return the name of a haptic device, does not need to be opened. + */ +const char * +SDL_SYS_HapticName(int index) +{ + int fd; + const char *name; + + /* Open the haptic device. */ + name = NULL; + fd = open(SDL_hapticlist[index].fname, O_RDONLY, 0); + + if (fd >= 0) { + + name = SDL_SYS_HapticNameFromFD(fd); + if (name==NULL) { + /* No name found, return device character device */ + name = SDL_hapticlist[index].fname; + } + } + close(fd); + + return name; +} + + +/* + * Opens the haptic device from the file descriptor. + */ +static int +SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd) +{ + const char *name; + + /* Allocate the hwdata */ + haptic->hwdata = (struct haptic_hwdata *) + SDL_malloc(sizeof(*haptic->hwdata)); + if (haptic->hwdata == NULL) { + SDL_OutOfMemory(); + goto open_err; + } + SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); + + /* Set the data. */ + haptic->hwdata->fd = fd; + haptic->supported = EV_IsHaptic(fd); + haptic->naxes = 2; /* Hardcoded for now, not sure if it's possible to find out. */ + + /* Set the effects */ + if (ioctl(fd, EVIOCGEFFECTS, &haptic->neffects) < 0) { + SDL_SetError("Haptic: Unable to query device memory: %s", strerror(errno)); + goto open_err; + } + haptic->nplaying = haptic->neffects; /* Linux makes no distinction. */ + haptic->effects = (struct haptic_effect *) + SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); + if (haptic->effects == NULL) { + SDL_OutOfMemory(); + goto open_err; + } + /* Clear the memory */ + SDL_memset(haptic->effects, 0, + sizeof(struct haptic_effect) * haptic->neffects); + + return 0; + + /* Error handling */ +open_err: + close(fd); + if (haptic->hwdata != NULL) { + free(haptic->hwdata); + haptic->hwdata = NULL; + } + return -1; +} + + +/* + * Opens a haptic device for usage. + */ +int +SDL_SYS_HapticOpen(SDL_Haptic * haptic) +{ + int fd; + int ret; + + /* Open the character device */ + fd = open(SDL_hapticlist[haptic->index].fname, O_RDWR, 0); + if (fd < 0) { + SDL_SetError("Haptic: Unable to open %s: %s", + SDL_hapticlist[haptic->index], strerror(errno)); + return -1; + } + + /* Try to create the haptic. */ + ret = SDL_SYS_HapticOpenFromFD(haptic,fd); /* Already closes on error. */ + if (ret < 0) { + return -1; + } + + /* Set the fname. */ + haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname; + return 0; +} + + +/* + * Opens a haptic device from first mouse it finds for usage. + */ +int +SDL_SYS_HapticMouse(void) +{ + int fd; + int i; + + for (i=0; ihwdata->fd); +} + + +/* + * Checks to see if the haptic device and joystick and in reality the same. + */ +int +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + /* We are assuming linux is using evdev which should trump the old + * joystick methods. */ + if (SDL_strcmp(joystick->hwdata->fname,haptic->hwdata->fname)==0) { + return 1; + } + return 0; +} + + +/* + * Opens a SDL_Haptic from a SDL_Joystick. + */ +int +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + int i; + int fd; + int ret; + + /* Find the joystick in the haptic list. */ + for (i=0; ihwdata->fname)==0) { + haptic->index = i; + } + } + } + + fd = open(joystick->hwdata->fname, O_RDWR, 0); + ret = SDL_SYS_HapticOpenFromFD(haptic,fd); /* Already closes on error. */ + if (ret < 0) { + return -1; + } + + haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname; + return 0; +} + + +/* + * Closes the haptic device. + */ +void +SDL_SYS_HapticClose(SDL_Haptic * haptic) +{ + if (haptic->hwdata) { + + /* Free effects. */ + SDL_free(haptic->effects); + haptic->effects = NULL; + haptic->neffects = 0; + + /* Clean up */ + close(haptic->hwdata->fd); + + /* Free */ + SDL_free(haptic->hwdata); + haptic->hwdata = NULL; + } + + /* Clear the rest. */ + SDL_memset(haptic, 0, sizeof(SDL_Haptic)); +} + + +/* + * Clean up after system specific haptic stuff + */ +void +SDL_SYS_HapticQuit(void) +{ + int i; + + for (i=0; SDL_hapticlist[i].fname != NULL; i++) { + /* Opened and not closed haptics are leaked, this is on purpose. + * Close your haptic devices after usage. */ + + SDL_free(SDL_hapticlist[i].fname); + } + SDL_hapticlist[0].fname = NULL; +} + + +/* + * Converts an SDL button to a ff_trigger button. + */ +static Uint16 +SDL_SYS_ToButton( Uint16 button ) +{ + Uint16 ff_button; + + ff_button = 0; + + /* + * Not sure what the proper syntax is because this actually isn't implemented + * in the current kernel from what I've seen (2.6.26). + */ + if (button != 0) { + ff_button = BTN_GAMEPAD + button - 1; + } + + return ff_button; +} + + +/* + * Returns the ff_effect usable direction from a SDL_HapticDirection. + */ +static Uint16 +SDL_SYS_ToDirection( SDL_HapticDirection * dir ) +{ + Uint32 tmp; + float f; /* Ideally we'd use fixed point math instead of floats... */ + + switch (dir->type) { + case SDL_HAPTIC_POLAR: + /* Linux directions start from south. + (and range from 0 to 0xFFFF) + Quoting include/linux/input.h, line 926: + Direction of the effect is encoded as follows: + 0 deg -> 0x0000 (down) + 90 deg -> 0x4000 (left) + 180 deg -> 0x8000 (up) + 270 deg -> 0xC000 (right) + */ + tmp = (((18000 + dir->dir[0]) % 36000) * 0xFFFF) / 36000; // convert to range [0,0xFFFF] + return (Uint16) tmp; + + case SDL_HAPTIC_CARTESIAN: + f = atan2(dir->dir[1], dir->dir[0]); + /* + atan2 takes the parameters: Y-axis-value and X-axis-value (in that order) + - Y-axis-value is the second coordinate (from center to SOUTH) + - X-axis-value is the first coordinate (from center to EAST) + We add 36000, because atan2 also returns negative values. Then we practically + have the first spherical value. Therefore we proceed as in case + SDL_HAPTIC_SPHERICAL and add another 9000 to get the polar value. + --> add 45000 in total + --> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR. + */ + tmp = (((int) (f * 18000. / M_PI)) + 45000) % 36000; + tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; // convert to range [0,0xFFFF] + return (Uint16) tmp; + + case SDL_HAPTIC_SPHERICAL: + /* + We convert to polar, because that's the only supported direction on Linux. + The first value of a spherical direction is practically the same as a + Polar direction, except that we have to add 90 degrees. It is the angle + from EAST {1,0} towards SOUTH {0,1}. + --> add 9000 + --> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR. + */ + tmp = ((dir->dir[0]) + 9000) % 36000; /* Convert to polars */ + tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; // convert to range [0,0xFFFF] + return (Uint16) tmp; + + default: + SDL_SetError("Haptic: Unsupported direction type."); + return (Uint16)-1; + } + + return 0; +} + + +#define CLAMP(x) (((x) > 32767) ? 32767 : x) +/* + * Initializes the linux effect struct from a haptic_effect. + * Values above 32767 (for unsigned) are unspecified so we must clamp. + */ +static int +SDL_SYS_ToFFEffect( struct ff_effect * dest, SDL_HapticEffect * src ) +{ + Uint32 tmp; + SDL_HapticConstant *constant; + SDL_HapticPeriodic *periodic; + SDL_HapticCondition *condition; + SDL_HapticRamp *ramp; + + /* Clear up */ + SDL_memset(dest, 0, sizeof(struct ff_effect)); + + switch (src->type) { + case SDL_HAPTIC_CONSTANT: + constant = &src->constant; + + /* Header */ + dest->type = FF_CONSTANT; + dest->direction = SDL_SYS_ToDirection(&constant->direction); + if (dest->direction == (Uint16)-1) return -1; + + /* Replay */ + dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ? + 0 : CLAMP(constant->length); + dest->replay.delay = CLAMP(constant->delay); + + /* Trigger */ + dest->trigger.button = SDL_SYS_ToButton(constant->button); + dest->trigger.interval = CLAMP(constant->interval); + + /* Constant */ + dest->u.constant.level = constant->level; + + /* Envelope */ + dest->u.constant.envelope.attack_length = CLAMP(constant->attack_length); + dest->u.constant.envelope.attack_level = CLAMP(constant->attack_level); + dest->u.constant.envelope.fade_length = CLAMP(constant->fade_length); + dest->u.constant.envelope.fade_level = CLAMP(constant->fade_level); + + break; + + case SDL_HAPTIC_SINE: + case SDL_HAPTIC_SQUARE: + case SDL_HAPTIC_TRIANGLE: + case SDL_HAPTIC_SAWTOOTHUP: + case SDL_HAPTIC_SAWTOOTHDOWN: + periodic = &src->periodic; + + /* Header */ + dest->type = FF_PERIODIC; + dest->direction = SDL_SYS_ToDirection(&periodic->direction); + if (dest->direction == (Uint16)-1) return -1; + + /* Replay */ + dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ? + 0 : CLAMP(periodic->length); + dest->replay.delay = CLAMP(periodic->delay); + + /* Trigger */ + dest->trigger.button = SDL_SYS_ToButton(periodic->button); + dest->trigger.interval = CLAMP(periodic->interval); + + /* Periodic */ + if (periodic->type == SDL_HAPTIC_SINE) + dest->u.periodic.waveform = FF_SINE; + else if (periodic->type == SDL_HAPTIC_SQUARE) + dest->u.periodic.waveform = FF_SQUARE; + else if (periodic->type == SDL_HAPTIC_TRIANGLE) + dest->u.periodic.waveform = FF_TRIANGLE; + else if (periodic->type == SDL_HAPTIC_SAWTOOTHUP) + dest->u.periodic.waveform = FF_SAW_UP; + else if (periodic->type == SDL_HAPTIC_SAWTOOTHDOWN) + dest->u.periodic.waveform = FF_SAW_DOWN; + dest->u.periodic.period = CLAMP(periodic->period); + dest->u.periodic.magnitude = periodic->magnitude; + dest->u.periodic.offset = periodic->offset; + /* Phase is calculated based of offset from period and then clamped. */ + tmp = ((periodic->phase % 36000) * dest->u.periodic.period) / 36000; + dest->u.periodic.phase = CLAMP(tmp); + + /* Envelope */ + dest->u.periodic.envelope.attack_length = CLAMP(periodic->attack_length); + dest->u.periodic.envelope.attack_level = CLAMP(periodic->attack_level); + dest->u.periodic.envelope.fade_length = CLAMP(periodic->fade_length); + dest->u.periodic.envelope.fade_level = CLAMP(periodic->fade_level); + + break; + + case SDL_HAPTIC_SPRING: + case SDL_HAPTIC_DAMPER: + case SDL_HAPTIC_INERTIA: + case SDL_HAPTIC_FRICTION: + condition = &src->condition; + + /* Header */ + if (condition->type == SDL_HAPTIC_SPRING) + dest->type = FF_SPRING; + else if (condition->type == SDL_HAPTIC_DAMPER) + dest->type = FF_DAMPER; + else if (condition->type == SDL_HAPTIC_INERTIA) + dest->type = FF_INERTIA; + else if (condition->type == SDL_HAPTIC_FRICTION) + dest->type = FF_FRICTION; + dest->direction = 0; /* Handled by the condition-specifics. */ + + /* Replay */ + dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ? + 0 : CLAMP(condition->length); + dest->replay.delay = CLAMP(condition->delay); + + /* Trigger */ + dest->trigger.button = SDL_SYS_ToButton(condition->button); + dest->trigger.interval = CLAMP(condition->interval); + + /* Condition */ + /* X axis */ + dest->u.condition[0].right_saturation = CLAMP(condition->right_sat[0]); + dest->u.condition[0].left_saturation = CLAMP(condition->left_sat[0]); + dest->u.condition[0].right_coeff = condition->right_coeff[0]; + dest->u.condition[0].left_coeff = condition->left_coeff[0]; + dest->u.condition[0].deadband = CLAMP(condition->deadband[0]); + dest->u.condition[0].center = condition->center[0]; + /* Y axis */ + dest->u.condition[1].right_saturation = CLAMP(condition->right_sat[1]); + dest->u.condition[1].left_saturation = CLAMP(condition->left_sat[1]); + dest->u.condition[1].right_coeff = condition->right_coeff[1]; + dest->u.condition[1].left_coeff = condition->left_coeff[1]; + dest->u.condition[1].deadband = CLAMP(condition->deadband[1]); + dest->u.condition[1].center = condition->center[1]; + + /* + * There is no envelope in the linux force feedback api for conditions. + */ + + break; + + case SDL_HAPTIC_RAMP: + ramp = &src->ramp; + + /* Header */ + dest->type = FF_RAMP; + dest->direction = SDL_SYS_ToDirection(&ramp->direction); + if (dest->direction == (Uint16)-1) return -1; + + /* Replay */ + dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ? + 0 : CLAMP(ramp->length); + dest->replay.delay = CLAMP(ramp->delay); + + /* Trigger */ + dest->trigger.button = SDL_SYS_ToButton(ramp->button); + dest->trigger.interval = CLAMP(ramp->interval); + + /* Ramp */ + dest->u.ramp.start_level = ramp->start; + dest->u.ramp.end_level = ramp->end; + + /* Envelope */ + dest->u.ramp.envelope.attack_length = CLAMP(ramp->attack_length); + dest->u.ramp.envelope.attack_level = CLAMP(ramp->attack_level); + dest->u.ramp.envelope.fade_length = CLAMP(ramp->fade_length); + dest->u.ramp.envelope.fade_level = CLAMP(ramp->fade_level); + + break; + + + default: + SDL_SetError("Haptic: Unknown effect type."); + return -1; + } + + return 0; +} + + +/* + * Creates a new haptic effect. + */ +int +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect * effect, + SDL_HapticEffect * base) +{ + struct ff_effect * linux_effect; + + /* Allocate the hardware effect */ + effect->hweffect = (struct haptic_hweffect *) + SDL_malloc(sizeof(struct haptic_hweffect)); + if (effect->hweffect == NULL) { + SDL_OutOfMemory(); + return -1; + } + + /* Prepare the ff_effect */ + linux_effect = &effect->hweffect->effect; + if (SDL_SYS_ToFFEffect( linux_effect, base ) != 0) { + goto new_effect_err; + } + linux_effect->id = -1; /* Have the kernel give it an id */ + + /* Upload the effect */ + if (ioctl(haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) { + SDL_SetError("Haptic: Error uploading effect to the device: %s", strerror(errno)); + goto new_effect_err; + } + + return 0; + +new_effect_err: + free(effect->hweffect); + effect->hweffect = NULL; + return -1; +} + + +/* + * Updates an effect. + * + * Note: Dynamically updating the direction can in some cases force + * the effect to restart and run once. + */ +int SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, SDL_HapticEffect * data) +{ + struct ff_effect linux_effect; + + /* Create the new effect */ + if (SDL_SYS_ToFFEffect( &linux_effect, data ) != 0) { + return -1; + } + linux_effect.id = effect->hweffect->effect.id; + + /* See if it can be uploaded. */ + if (ioctl(haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) { + SDL_SetError("Haptic: Error updating the effect: %s", strerror(errno)); + return -1; + } + + /* Copy the new effect into memory. */ + SDL_memcpy( &effect->hweffect->effect, &linux_effect, sizeof(struct ff_effect) ); + + return effect->hweffect->effect.id; +} + + +/* + * Runs an effect. + */ +int +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect, + Uint32 iterations) +{ + struct input_event run; + + /* Prepare to run the effect */ + run.type = EV_FF; + run.code = effect->hweffect->effect.id; + /* We don't actually have infinity here, so we just do INT_MAX which is pretty damn close. */ + run.value = (iterations > INT_MAX) ? INT_MAX : iterations; + + if (write(haptic->hwdata->fd, (const void*) &run, sizeof(run)) < 0) { + SDL_SetError("Haptic: Unable to run the effect: %s", strerror(errno)); + return -1; + } + + return 0; +} + + +/* + * Stops an effect. + */ +int +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + struct input_event stop; + + stop.type = EV_FF; + stop.code = effect->hweffect->effect.id; + stop.value = 0; + + if (write(haptic->hwdata->fd, (const void*) &stop, sizeof(stop)) < 0) { + SDL_SetError("Haptic: Unable to stop the effect: %s", strerror(errno)); + return -1; + } + + return 0; +} + + +/* + * Frees the effect. + */ +void +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) { + SDL_SetError("Haptic: Error removing the effect from the device: %s", + strerror(errno)); + } + SDL_free(effect->hweffect); + effect->hweffect = NULL; +} + + +/* + * Gets the status of a haptic effect. + */ +int +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect) +{ +#if 0 /* Not supported atm. */ + struct input_event ie; + + ie.type = EV_FF; + ie.type = EV_FF_STATUS; + ie.code = effect->hweffect->effect.id; + + if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) { + SDL_SetError("Haptic: Error getting device status."); + return -1; + } + + return 0; +#endif + + return -1; +} + + +/* + * Sets the gain. + */ +int +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) +{ + struct input_event ie; + + ie.type = EV_FF; + ie.code = FF_GAIN; + ie.value = (0xFFFFUL * gain) / 100; + + if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) { + SDL_SetError("Haptic: Error setting gain: %s", strerror(errno)); + return -1; + } + + return 0; +} + + +/* + * Sets the autocentering. + */ +int +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) +{ + struct input_event ie; + + ie.type = EV_FF; + ie.code = FF_AUTOCENTER; + ie.value = (0xFFFFUL * autocenter) / 100; + + if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) { + SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno)); + return -1; + } + + return 0; +} + + +/* + * Pausing is not supported atm by linux. + */ +int +SDL_SYS_HapticPause(SDL_Haptic * haptic) +{ + return -1; +} + + +/* + * Unpausing is not supported atm by linux. + */ +int +SDL_SYS_HapticUnpause(SDL_Haptic * haptic) +{ + return -1; +} + + +/* + * Stops all the currently playing effects. + */ +int +SDL_SYS_HapticStopAll(SDL_Haptic * haptic) +{ + int i, ret; + + /* Linux does not support this natively so we have to loop. */ + for (i=0; ineffects; i++) { + if (haptic->effects[i].hweffect != NULL) { + ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]); + if (ret < 0) { + SDL_SetError("Haptic: Error while trying to stop all playing effects."); + return -1; + } + } + } + return 0; +} + + +#endif /* SDL_HAPTIC_LINUX */ \ No newline at end of file diff --git a/src/haptic/linux/SDL_syshaptic.c.bak b/src/haptic/linux/SDL_syshaptic.c.bak new file mode 100644 index 000000000..4cc07be21 --- /dev/null +++ b/src/haptic/linux/SDL_syshaptic.c.bak @@ -0,0 +1,961 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 2008 Edgar Simo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_HAPTIC_LINUX + +#include "SDL_haptic.h" +#include "../SDL_syshaptic.h" +#include "SDL_joystick.h" +#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */ +#include "../../joystick/linux/SDL_sysjoystick_c.h" /* For joystick hwdata */ + +#include /* close */ +#include /* Force feedback linux stuff. */ +#include /* O_RDWR */ +#include /* INT_MAX */ +#include /* errno, strerror */ +#include /* atan2 */ +#include /* stat */ + +/* Just in case. */ +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + + +#define MAX_HAPTICS 32 /* It's doubtful someone has more then 32 evdev */ + + +/* + * List of available haptic devices. + */ +static struct +{ + char *fname; /* Dev path name (like /dev/input/event1) */ + SDL_Haptic *haptic; /* Assosciated haptic. */ +} SDL_hapticlist[MAX_HAPTICS]; + + +/* + * Haptic system hardware data. + */ +struct haptic_hwdata +{ + int fd; /* File descriptor of the device. */ + char *fname; /* Points to the name in SDL_hapticlist. */ +}; + + +/* + * Haptic system effect data. + */ +struct haptic_hweffect +{ + struct ff_effect effect; /* The linux kernel effect structure. */ +}; + + + +#define test_bit(nr, addr) \ + (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0) +#define EV_TEST(ev,f) \ + if (test_bit((ev), features)) ret |= (f); +/* + * Test whether a device has haptic properties. + * Returns available properties or 0 if there are none. + */ +static int +EV_IsHaptic(int fd) +{ + unsigned int ret; + unsigned long features[1 + FF_MAX/sizeof(unsigned long)]; + + /* Ask device for what it has. */ + ret = 0; + if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) { + SDL_SetError("Haptic: Unable to get device's features: %s", strerror(errno)); + return -1; + } + + /* Convert supported features to SDL_HAPTIC platform-neutral features. */ + EV_TEST(FF_CONSTANT, SDL_HAPTIC_CONSTANT); + EV_TEST(FF_SINE, SDL_HAPTIC_SINE); + EV_TEST(FF_SQUARE, SDL_HAPTIC_SQUARE); + EV_TEST(FF_TRIANGLE, SDL_HAPTIC_TRIANGLE); + EV_TEST(FF_SAW_UP, SDL_HAPTIC_SAWTOOTHUP); + EV_TEST(FF_SAW_DOWN, SDL_HAPTIC_SAWTOOTHDOWN); + EV_TEST(FF_RAMP, SDL_HAPTIC_RAMP); + EV_TEST(FF_SPRING, SDL_HAPTIC_SPRING); + EV_TEST(FF_FRICTION, SDL_HAPTIC_FRICTION); + EV_TEST(FF_DAMPER, SDL_HAPTIC_DAMPER); + EV_TEST(FF_INERTIA, SDL_HAPTIC_INERTIA); + EV_TEST(FF_CUSTOM, SDL_HAPTIC_CUSTOM); + EV_TEST(FF_GAIN, SDL_HAPTIC_GAIN); + EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER); + + /* Return what it supports. */ + return ret; +} + + +/* + * Tests whether a device is a mouse or not. + */ +static int +EV_IsMouse(int fd) +{ + unsigned long argp[40]; + + /* Ask for supported features. */ + if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(argp)), argp) < 0) { + return -1; + } + + /* Currently we only test for BTN_MOUSE which can give fake positives. */ + if (test_bit(BTN_MOUSE,argp) != 0) { + return 1; + } + + return 0; +} + +/* + * Initializes the haptic subsystem by finding available devices. + */ +int +SDL_SYS_HapticInit(void) +{ + const char joydev_pattern[] = "/dev/input/event%d"; + dev_t dev_nums[MAX_HAPTICS]; + char path[PATH_MAX]; + struct stat sb; + int fd; + int i, j, k; + int duplicate; + int numhaptics; + + numhaptics = 0; + + /* + * Limit amount of checks to MAX_HAPTICS since we may or may not have + * permission to some or all devices. + */ + i = 0; + for (j = 0; j < MAX_HAPTICS; ++j) { + + snprintf(path, PATH_MAX, joydev_pattern, i++); + + /* check to see if file exists */ + if (stat(path,&sb) != 0) + break; + + /* check for duplicates */ + duplicate = 0; + for (k = 0; (k < numhaptics) && !duplicate; ++k) { + if (sb.st_rdev == dev_nums[k]) { + duplicate = 1; + } + } + if (duplicate) { + continue; + } + + /* try to open */ + fd = open(path, O_RDWR, 0); + if (fd < 0) continue; + +#ifdef DEBUG_INPUT_EVENTS + printf("Checking %s\n", path); +#endif + + /* see if it works */ + if (EV_IsHaptic(fd) > 0) { + SDL_hapticlist[numhaptics].fname = SDL_strdup(path); + SDL_hapticlist[numhaptics].haptic = NULL; + dev_nums[numhaptics] = sb.st_rdev; + ++numhaptics; + } + close(fd); + } + + return numhaptics; +} + + +/* + * Gets the name from a file descriptor. + */ +static const char * +SDL_SYS_HapticNameFromFD(int fd) +{ + static char namebuf[128]; + + /* We use the evdev name ioctl. */ + if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) { + return NULL; + } + + return namebuf; +} + + +/* + * Return the name of a haptic device, does not need to be opened. + */ +const char * +SDL_SYS_HapticName(int index) +{ + int fd; + const char *name; + + /* Open the haptic device. */ + name = NULL; + fd = open(SDL_hapticlist[index].fname, O_RDONLY, 0); + + if (fd >= 0) { + + name = SDL_SYS_HapticNameFromFD(fd); + if (name==NULL) { + /* No name found, return device character device */ + name = SDL_hapticlist[index].fname; + } + } + close(fd); + + return name; +} + + +/* + * Opens the haptic device from the file descriptor. + */ +static int +SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd) +{ + const char *name; + + /* Allocate the hwdata */ + haptic->hwdata = (struct haptic_hwdata *) + SDL_malloc(sizeof(*haptic->hwdata)); + if (haptic->hwdata == NULL) { + SDL_OutOfMemory(); + goto open_err; + } + SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); + + /* Set the data. */ + haptic->hwdata->fd = fd; + haptic->supported = EV_IsHaptic(fd); + haptic->naxes = 2; /* Hardcoded for now, not sure if it's possible to find out. */ + + /* Set the effects */ + if (ioctl(fd, EVIOCGEFFECTS, &haptic->neffects) < 0) { + SDL_SetError("Haptic: Unable to query device memory: %s", strerror(errno)); + goto open_err; + } + haptic->nplaying = haptic->neffects; /* Linux makes no distinction. */ + haptic->effects = (struct haptic_effect *) + SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); + if (haptic->effects == NULL) { + SDL_OutOfMemory(); + goto open_err; + } + /* Clear the memory */ + SDL_memset(haptic->effects, 0, + sizeof(struct haptic_effect) * haptic->neffects); + + return 0; + + /* Error handling */ +open_err: + close(fd); + if (haptic->hwdata != NULL) { + free(haptic->hwdata); + haptic->hwdata = NULL; + } + return -1; +} + + +/* + * Opens a haptic device for usage. + */ +int +SDL_SYS_HapticOpen(SDL_Haptic * haptic) +{ + int fd; + int ret; + + /* Open the character device */ + fd = open(SDL_hapticlist[haptic->index].fname, O_RDWR, 0); + if (fd < 0) { + SDL_SetError("Haptic: Unable to open %s: %s", + SDL_hapticlist[haptic->index], strerror(errno)); + return -1; + } + + /* Try to create the haptic. */ + ret = SDL_SYS_HapticOpenFromFD(haptic,fd); /* Already closes on error. */ + if (ret < 0) { + return -1; + } + + /* Set the fname. */ + haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname; + return 0; +} + + +/* + * Opens a haptic device from first mouse it finds for usage. + */ +int +SDL_SYS_HapticMouse(void) +{ + int fd; + int i; + + for (i=0; ihwdata->fd); +} + + +/* + * Checks to see if the haptic device and joystick and in reality the same. + */ +int +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + /* We are assuming linux is using evdev which should trump the old + * joystick methods. */ + if (SDL_strcmp(joystick->hwdata->fname,haptic->hwdata->fname)==0) { + return 1; + } + return 0; +} + + +/* + * Opens a SDL_Haptic from a SDL_Joystick. + */ +int +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + int i; + int fd; + int ret; + + /* Find the joystick in the haptic list. */ + for (i=0; ihwdata->fname)==0) { + haptic->index = i; + } + } + } + + fd = open(joystick->hwdata->fname, O_RDWR, 0); + ret = SDL_SYS_HapticOpenFromFD(haptic,fd); /* Already closes on error. */ + if (ret < 0) { + return -1; + } + + haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname; + return 0; +} + + +/* + * Closes the haptic device. + */ +void +SDL_SYS_HapticClose(SDL_Haptic * haptic) +{ + if (haptic->hwdata) { + + /* Free effects. */ + SDL_free(haptic->effects); + haptic->effects = NULL; + haptic->neffects = 0; + + /* Clean up */ + close(haptic->hwdata->fd); + + /* Free */ + SDL_free(haptic->hwdata); + haptic->hwdata = NULL; + } + + /* Clear the rest. */ + SDL_memset(haptic, 0, sizeof(SDL_Haptic)); +} + + +/* + * Clean up after system specific haptic stuff + */ +void +SDL_SYS_HapticQuit(void) +{ + int i; + + for (i=0; SDL_hapticlist[i].fname != NULL; i++) { + /* Opened and not closed haptics are leaked, this is on purpose. + * Close your haptic devices after usage. */ + + SDL_free(SDL_hapticlist[i].fname); + } + SDL_hapticlist[0].fname = NULL; +} + + +/* + * Converts an SDL button to a ff_trigger button. + */ +static Uint16 +SDL_SYS_ToButton( Uint16 button ) +{ + Uint16 ff_button; + + ff_button = 0; + + /* + * Not sure what the proper syntax is because this actually isn't implemented + * in the current kernel from what I've seen (2.6.26). + */ + if (button != 0) { + ff_button = BTN_GAMEPAD + button - 1; + } + + return ff_button; +} + + +/* + * Returns the ff_effect usable direction from a SDL_HapticDirection. + */ +static Uint16 +SDL_SYS_ToDirection( SDL_HapticDirection * dir ) +{ + Uint32 tmp; + float f; /* Ideally we'd use fixed point math instead of floats... */ + + switch (dir->type) { + case SDL_HAPTIC_POLAR: + /* Linux directions start from south. + (and range from 0 to 0xFFFF) + Quoting include/linux/input.h, line 926: + Direction of the effect is encoded as follows: + 0 deg -> 0x0000 (down) + 90 deg -> 0x4000 (left) + 180 deg -> 0x8000 (up) + 270 deg -> 0xC000 (right) + */ + tmp = (((18000 + dir->dir[0]) % 36000) * 0xFFFF) / 36000; // convert to range [0,0xFFFF] + return (Uint16) tmp; + + case SDL_HAPTIC_CARTESIAN: + f = atan2(dir->dir[1], dir->dir[0]); + /* + atan2 takes the parameters: Y-axis-value and X-axis-value (in that order) + - Y-axis-value is the second coordinate (from center to SOUTH) + - X-axis-value is the first coordinate (from center to EAST) + We add 36000, because atan2 also returns negative values. Then we practically + have the first spherical value. Therefore we proceed as in case + SDL_HAPTIC_SPHERICAL and add another 9000 to get the polar value. + --> add 45000 in total + --> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR. + */ + tmp = (((int) (f * 18000. / M_PI)) + 45000) % 36000; + tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; // convert to range [0,0xFFFF] + return (Uint16) tmp; + + case SDL_HAPTIC_SPHERICAL: + /* + We convert to polar, because that's the only supported direction on Linux. + The first value of a spherical direction is practically the same as a + Polar direction, except that we have to add 90 degrees. It is the angle + from EAST {1,0} towards SOUTH {0,1}. + --> add 9000 + --> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR. + */ + tmp = ((dir->dir[0]) + 9000) % 36000; /* Convert to polars */ + tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; // convert to range [0,0xFFFF] + return (Uint16) tmp; + + default: + SDL_SetError("Haptic: Unsupported direction type."); + return (Uint16)-1; + } + + return 0; +} + + +#define CLAMP(x) (((x) > 32767) ? 32767 : x) +/* + * Initializes the linux effect struct from a haptic_effect. + * Values above 32767 (for unsigned) are unspecified so we must clamp. + */ +static int +SDL_SYS_ToFFEffect( struct ff_effect * dest, SDL_HapticEffect * src ) +{ + Uint32 tmp; + SDL_HapticConstant *constant; + SDL_HapticPeriodic *periodic; + SDL_HapticCondition *condition; + SDL_HapticRamp *ramp; + + /* Clear up */ + SDL_memset(dest, 0, sizeof(struct ff_effect)); + + switch (src->type) { + case SDL_HAPTIC_CONSTANT: + constant = &src->constant; + + /* Header */ + dest->type = FF_CONSTANT; + dest->direction = SDL_SYS_ToDirection(&constant->direction); + if (dest->direction == (Uint16)-1) return -1; + + /* Replay */ + dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ? + 0 : CLAMP(constant->length); + dest->replay.delay = CLAMP(constant->delay); + + /* Trigger */ + dest->trigger.button = SDL_SYS_ToButton(constant->button); + dest->trigger.interval = CLAMP(constant->interval); + + /* Constant */ + dest->u.constant.level = constant->level; + + /* Envelope */ + dest->u.constant.envelope.attack_length = CLAMP(constant->attack_length); + dest->u.constant.envelope.attack_level = CLAMP(constant->attack_level); + dest->u.constant.envelope.fade_length = CLAMP(constant->fade_length); + dest->u.constant.envelope.fade_level = CLAMP(constant->fade_level); + + break; + + case SDL_HAPTIC_SINE: + case SDL_HAPTIC_SQUARE: + case SDL_HAPTIC_TRIANGLE: + case SDL_HAPTIC_SAWTOOTHUP: + case SDL_HAPTIC_SAWTOOTHDOWN: + periodic = &src->periodic; + + /* Header */ + dest->type = FF_PERIODIC; + dest->direction = SDL_SYS_ToDirection(&periodic->direction); + if (dest->direction == (Uint16)-1) return -1; + + /* Replay */ + dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ? + 0 : CLAMP(periodic->length); + dest->replay.delay = CLAMP(periodic->delay); + + /* Trigger */ + dest->trigger.button = SDL_SYS_ToButton(periodic->button); + dest->trigger.interval = CLAMP(periodic->interval); + + /* Periodic */ + if (periodic->type == SDL_HAPTIC_SINE) + dest->u.periodic.waveform = FF_SINE; + else if (periodic->type == SDL_HAPTIC_SQUARE) + dest->u.periodic.waveform = FF_SQUARE; + else if (periodic->type == SDL_HAPTIC_TRIANGLE) + dest->u.periodic.waveform = FF_TRIANGLE; + else if (periodic->type == SDL_HAPTIC_SAWTOOTHUP) + dest->u.periodic.waveform = FF_SAW_UP; + else if (periodic->type == SDL_HAPTIC_SAWTOOTHDOWN) + dest->u.periodic.waveform = FF_SAW_DOWN; + dest->u.periodic.period = CLAMP(periodic->period); + dest->u.periodic.magnitude = periodic->magnitude; + dest->u.periodic.offset = periodic->offset; + /* Phase is calculated based of offset from period and then clamped. */ + tmp = ((periodic->phase % 36000) * dest->u.periodic.period) / 36000; + dest->u.periodic.phase = CLAMP(tmp); + + /* Envelope */ + dest->u.periodic.envelope.attack_length = CLAMP(periodic->attack_length); + dest->u.periodic.envelope.attack_level = CLAMP(periodic->attack_level); + dest->u.periodic.envelope.fade_length = CLAMP(periodic->fade_length); + dest->u.periodic.envelope.fade_level = CLAMP(periodic->fade_level); + + break; + + case SDL_HAPTIC_SPRING: + case SDL_HAPTIC_DAMPER: + case SDL_HAPTIC_INERTIA: + case SDL_HAPTIC_FRICTION: + condition = &src->condition; + + /* Header */ + if (condition->type == SDL_HAPTIC_SPRING) + dest->type = FF_SPRING; + else if (condition->type == SDL_HAPTIC_DAMPER) + dest->type = FF_DAMPER; + else if (condition->type == SDL_HAPTIC_INERTIA) + dest->type = FF_INERTIA; + else if (condition->type == SDL_HAPTIC_FRICTION) + dest->type = FF_FRICTION; + dest->direction = 0; /* Handled by the condition-specifics. */ + + /* Replay */ + dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ? + 0 : CLAMP(condition->length); + dest->replay.delay = CLAMP(condition->delay); + + /* Trigger */ + dest->trigger.button = SDL_SYS_ToButton(condition->button); + dest->trigger.interval = CLAMP(condition->interval); + + /* Condition */ + /* X axis */ + dest->u.condition[0].right_saturation = CLAMP(condition->right_sat[0]); + dest->u.condition[0].left_saturation = CLAMP(condition->left_sat[0]); + dest->u.condition[0].right_coeff = condition->right_coeff[0]; + dest->u.condition[0].left_coeff = condition->left_coeff[0]; + dest->u.condition[0].deadband = CLAMP(condition->deadband[0]); + dest->u.condition[0].center = condition->center[0]; + /* Y axis */ + dest->u.condition[1].right_saturation = CLAMP(condition->right_sat[1]); + dest->u.condition[1].left_saturation = CLAMP(condition->left_sat[1]); + dest->u.condition[1].right_coeff = condition->right_coeff[1]; + dest->u.condition[1].left_coeff = condition->left_coeff[1]; + dest->u.condition[1].deadband = CLAMP(condition->deadband[1]); + dest->u.condition[1].center = condition->center[1]; + + /* + * There is no envelope in the linux force feedback api for conditions. + */ + + break; + + case SDL_HAPTIC_RAMP: + ramp = &src->ramp; + + /* Header */ + dest->type = FF_RAMP; + dest->direction = SDL_SYS_ToDirection(&ramp->direction); + if (dest->direction == (Uint16)-1) return -1; + + /* Replay */ + dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ? + 0 : CLAMP(ramp->length); + dest->replay.delay = CLAMP(ramp->delay); + + /* Trigger */ + dest->trigger.button = SDL_SYS_ToButton(ramp->button); + dest->trigger.interval = CLAMP(ramp->interval); + + /* Ramp */ + dest->u.ramp.start_level = ramp->start; + dest->u.ramp.end_level = ramp->end; + + /* Envelope */ + dest->u.ramp.envelope.attack_length = CLAMP(ramp->attack_length); + dest->u.ramp.envelope.attack_level = CLAMP(ramp->attack_level); + dest->u.ramp.envelope.fade_length = CLAMP(ramp->fade_length); + dest->u.ramp.envelope.fade_level = CLAMP(ramp->fade_level); + + break; + + + default: + SDL_SetError("Haptic: Unknown effect type."); + return -1; + } + + return 0; +} + + +/* + * Creates a new haptic effect. + */ +int +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect * effect, + SDL_HapticEffect * base) +{ + struct ff_effect * linux_effect; + + /* Allocate the hardware effect */ + effect->hweffect = (struct haptic_hweffect *) + SDL_malloc(sizeof(struct haptic_hweffect)); + if (effect->hweffect == NULL) { + SDL_OutOfMemory(); + return -1; + } + + /* Prepare the ff_effect */ + linux_effect = &effect->hweffect->effect; + if (SDL_SYS_ToFFEffect( linux_effect, base ) != 0) { + goto new_effect_err; + } + linux_effect->id = -1; /* Have the kernel give it an id */ + + /* Upload the effect */ + if (ioctl(haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) { + SDL_SetError("Haptic: Error uploading effect to the device: %s", strerror(errno)); + goto new_effect_err; + } + + return 0; + +new_effect_err: + free(effect->hweffect); + effect->hweffect = NULL; + return -1; +} + + +/* + * Updates an effect. + * + * Note: Dynamically updating the direction can in some cases force + * the effect to restart and run once. + */ +int SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, SDL_HapticEffect * data) +{ + struct ff_effect linux_effect; + + /* Create the new effect */ + if (SDL_SYS_ToFFEffect( &linux_effect, data ) != 0) { + return -1; + } + linux_effect.id = effect->hweffect->effect.id; + + /* See if it can be uploaded. */ + if (ioctl(haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) { + SDL_SetError("Haptic: Error updating the effect: %s", strerror(errno)); + return -1; + } + + /* Copy the new effect into memory. */ + SDL_memcpy( &effect->hweffect->effect, &linux_effect, sizeof(struct ff_effect) ); + + return effect->hweffect->effect.id; +} + + +/* + * Runs an effect. + */ +int +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect, + Uint32 iterations) +{ + struct input_event run; + + /* Prepare to run the effect */ + run.type = EV_FF; + run.code = effect->hweffect->effect.id; + /* We don't actually have infinity here, so we just do INT_MAX which is pretty damn close. */ + run.value = (iterations > INT_MAX) ? INT_MAX : iterations; + + if (write(haptic->hwdata->fd, (const void*) &run, sizeof(run)) < 0) { + SDL_SetError("Haptic: Unable to run the effect: %s", strerror(errno)); + return -1; + } + + return 0; +} + + +/* + * Stops an effect. + */ +int +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + struct input_event stop; + + stop.type = EV_FF; + stop.code = effect->hweffect->effect.id; + stop.value = 0; + + if (write(haptic->hwdata->fd, (const void*) &stop, sizeof(stop)) < 0) { + SDL_SetError("Haptic: Unable to stop the effect: %s", strerror(errno)); + return -1; + } + + return 0; +} + + +/* + * Frees the effect. + */ +void +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) { + SDL_SetError("Haptic: Error removing the effect from the device: %s", + strerror(errno)); + } + SDL_free(effect->hweffect); + effect->hweffect = NULL; +} + + +/* + * Gets the status of a haptic effect. + */ +int +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect) +{ +#if 0 /* Not supported atm. */ + struct input_event ie; + + ie.type = EV_FF; + ie.type = EV_FF_STATUS; + ie.code = effect->hweffect->effect.id; + + if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) { + SDL_SetError("Haptic: Error getting device status."); + return -1; + } + + return 0; +#endif + + return -1; +} + + +/* + * Sets the gain. + */ +int +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) +{ + struct input_event ie; + + ie.type = EV_FF; + ie.code = FF_GAIN; + ie.value = (0xFFFFUL * gain) / 100; + + if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) { + SDL_SetError("Haptic: Error setting gain: %s", strerror(errno)); + return -1; + } + + return 0; +} + + +/* + * Sets the autocentering. + */ +int +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) +{ + struct input_event ie; + + ie.type = EV_FF; + ie.code = FF_AUTOCENTER; + ie.value = (0xFFFFUL * autocenter) / 100; + + if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) { + SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno)); + return -1; + } + + return 0; +} + + +/* + * Pausing is not supported atm by linux. + */ +int +SDL_SYS_HapticPause(SDL_Haptic * haptic) +{ + return -1; +} + + +/* + * Unpausing is not supported atm by linux. + */ +int +SDL_SYS_HapticUnpause(SDL_Haptic * haptic) +{ + return -1; +} + + +/* + * Stops all the currently playing effects. + */ +int +SDL_SYS_HapticStopAll(SDL_Haptic * haptic) +{ + int i, ret; + + /* Linux does not support this natively so we have to loop. */ + for (i=0; ineffects; i++) { + if (haptic->effects[i].hweffect != NULL) { + ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]); + if (ret < 0) { + SDL_SetError("Haptic: Error while trying to stop all playing effects."); + return -1; + } + } + } + return 0; +} + + +#endif /* SDL_HAPTIC_LINUX */ diff --git a/src/haptic/win32/SDL_syshaptic.c b/src/haptic/win32/SDL_syshaptic.c new file mode 100644 index 000000000..ca06773b0 --- /dev/null +++ b/src/haptic/win32/SDL_syshaptic.c @@ -0,0 +1,1368 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 2008 Edgar Simo + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_HAPTIC_DINPUT + +#include "SDL_haptic.h" +#include "../SDL_syshaptic.h" +#include "SDL_joystick.h" +#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */ +#include "../../joystick/win32/SDL_dxjoystick_c.h" /* For joystick hwdata */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define DIRECTINPUT_VERSION 0x0700 /* Need at least DirectX 7 for dwStartDelay */ +#include +#include +#ifdef _MSC_VER +# pragma comment (lib, "dinput8.lib") +# pragma comment (lib, "dxguid.lib") +# pragma comment (lib, "dxerr8.lib") +#endif /* _MSC_VER */ + + /* an ISO hack for VisualC++ */ +#ifdef _MSC_VER +#define snprintf _snprintf +#endif /* _MSC_VER */ + + +#define MAX_HAPTICS 32 + + +/* + * List of available haptic devices. + */ +static struct +{ + DIDEVICEINSTANCE instance; + SDL_Haptic *haptic; + DIDEVCAPS capabilities; +} SDL_hapticlist[MAX_HAPTICS]; + + +/* + * Haptic system hardware data. + */ +struct haptic_hwdata +{ + LPDIRECTINPUTDEVICE2 device; + DWORD axes[3]; /* Axes to use. */ + int is_joystick; /* Device is loaded as joystick. */ +}; + + +/* + * Haptic system effect data. + */ +struct haptic_hweffect +{ + DIEFFECT effect; + LPDIRECTINPUTEFFECT ref; +}; + + +/* + * Internal stuff. + */ +static LPDIRECTINPUT dinput = NULL; + + +/* + * External stuff. + */ +extern HWND SDL_HelperWindow; + + +/* + * Prototypes. + */ +static void DI_SetError(const char *str, HRESULT err); +static int DI_GUIDIsSame(const GUID * a, const GUID * b); +static int SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance); +static int SDL_SYS_HapticOpenFromDevice2(SDL_Haptic * haptic, LPDIRECTINPUTDEVICE2 device2); +static DWORD DIGetTriggerButton( Uint16 button ); +static int SDL_SYS_SetDirection( DIEFFECT * effect, SDL_HapticDirection *dir, int naxes ); +static int SDL_SYS_ToDIEFFECT( SDL_Haptic * haptic, DIEFFECT * dest, SDL_HapticEffect * src ); +static void SDL_SYS_HapticFreeDIEFFECT( DIEFFECT * effect, int type ); +static REFGUID SDL_SYS_HapticEffectType(SDL_HapticEffect * effect); +/* Callbacks. */ +static BOOL CALLBACK EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext); +static BOOL CALLBACK DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv); + + +/* + * Like SDL_SetError but for DX error codes. + */ +static void +DI_SetError(const char *str, HRESULT err) +{ + SDL_SetError( "Haptic: %s - %s: %s", str, + DXGetErrorString8A(err), + DXGetErrorDescription8A(err)); +} + + +/* + * Checks to see if two GUID are the same. + */ +static int +DI_GUIDIsSame(const GUID * a, const GUID * b) +{ + if (((a)->Data1 == (b)->Data1) && + ((a)->Data2 == (b)->Data2) && + ((a)->Data3 == (b)->Data3) && + (SDL_strcmp((a)->Data4, (b)->Data4)==0)) + return 1; + return 0; +} + + +/* + * Initializes the haptic subsystem. + */ +int +SDL_SYS_HapticInit(void) +{ + HRESULT ret; + HINSTANCE instance; + + if (dinput != NULL) { /* Already open. */ + SDL_SetError("Haptic: SubSystem already open."); + return -1; + } + + /* Clear all the memory. */ + SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist)); + + SDL_numhaptics = 0; + + ret = CoInitialize(NULL); + if (FAILED(ret)) { + DI_SetError("Coinitialize",ret); + return -1; + } + + ret = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectInput, (LPVOID)&dinput); + if (FAILED(ret)) { + DI_SetError("CoCreateInstance",ret); + return -1; + } + + /* Because we used CoCreateInstance, we need to Initialize it, first. */ + instance = GetModuleHandle(NULL); + if (instance == NULL) { + SDL_SetError("GetModuleHandle() failed with error code %d.", GetLastError()); + return -1; + } + ret = IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION); + if (FAILED(ret)) { + DI_SetError("Initializing DirectInput device",ret); + return -1; + } + + /* Look for haptic devices. */ + ret = IDirectInput_EnumDevices( dinput, + 0, + EnumHapticsCallback, + NULL, DIEDFL_FORCEFEEDBACK | DIEDFL_ATTACHEDONLY); + if (FAILED(ret)) { + DI_SetError("Enumerating DirectInput devices",ret); + return -1; + } + + return SDL_numhaptics; +} + +/* + * Callback to find the haptic devices. + */ +static BOOL CALLBACK +EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext) +{ + HRESULT ret; + LPDIRECTINPUTDEVICE device; + + /* Copy the instance over, useful for creating devices. */ + SDL_memcpy(&SDL_hapticlist[SDL_numhaptics].instance, pdidInstance, + sizeof(DIDEVICEINSTANCE)); + + /* Open the device */ + ret = IDirectInput_CreateDevice( dinput, &pdidInstance->guidInstance, + &device, NULL ); + if (FAILED(ret)) { + /* DI_SetError("Creating DirectInput device",ret); */ + return DIENUM_CONTINUE; + } + + /* Get capabilities. */ + SDL_hapticlist[SDL_numhaptics].capabilities.dwSize = sizeof(DIDEVCAPS); + ret = IDirectInputDevice_GetCapabilities( device, + &SDL_hapticlist[SDL_numhaptics].capabilities ); + if (FAILED(ret)) { + /* DI_SetError("Getting device capabilities",ret); */ + IDirectInputDevice_Release(device); + return DIENUM_CONTINUE; + } + + /* Close up device and count it. */ + IDirectInputDevice_Release(device); + SDL_numhaptics++; + + /* Watch out for hard limit. */ + if (SDL_numhaptics >= MAX_HAPTICS) + return DIENUM_STOP; + + return DIENUM_CONTINUE; +} + + +/* + * Return the name of a haptic device, does not need to be opened. + */ +const char * +SDL_SYS_HapticName(int index) +{ + return SDL_hapticlist[index].instance.tszProductName; +} + + +/* + * Callback to get all supported effects. + */ +#define EFFECT_TEST(e,s) \ +if (DI_GUIDIsSame(&pei->guid, &(e))) \ + haptic->supported |= (s) +static BOOL CALLBACK +DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv) +{ + /* Prepare the haptic device. */ + SDL_Haptic *haptic = (SDL_Haptic*) pv; + + /* Get supported. */ + EFFECT_TEST(GUID_Spring, SDL_HAPTIC_SPRING); + EFFECT_TEST(GUID_Damper, SDL_HAPTIC_DAMPER); + EFFECT_TEST(GUID_Inertia, SDL_HAPTIC_INERTIA); + EFFECT_TEST(GUID_Friction, SDL_HAPTIC_FRICTION); + EFFECT_TEST(GUID_ConstantForce, SDL_HAPTIC_CONSTANT); + EFFECT_TEST(GUID_CustomForce, SDL_HAPTIC_CUSTOM); + EFFECT_TEST(GUID_Sine, SDL_HAPTIC_SINE); + EFFECT_TEST(GUID_Square, SDL_HAPTIC_SQUARE); + EFFECT_TEST(GUID_Triangle, SDL_HAPTIC_TRIANGLE); + EFFECT_TEST(GUID_SawtoothUp, SDL_HAPTIC_SAWTOOTHUP); + EFFECT_TEST(GUID_SawtoothDown, SDL_HAPTIC_SAWTOOTHDOWN); + EFFECT_TEST(GUID_RampForce, SDL_HAPTIC_RAMP); + + /* Check for more. */ + return DIENUM_CONTINUE; +} + + +/* + * Callback to get supported axes. + */ +static BOOL CALLBACK +DI_DeviceObjectCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef) +{ + SDL_Haptic *haptic = (SDL_Haptic *) pvRef; + + if ((dev->dwType & DIDFT_AXIS) && (dev->dwFlags & DIDOI_FFACTUATOR)) { + + haptic->hwdata->axes[haptic->naxes] = dev->dwOfs; + haptic->naxes++; + + /* Currently using the artificial limit of 3 axes. */ + if (haptic->naxes >= 3) { + return DIENUM_STOP; + } + } + + return DIENUM_CONTINUE; +} + + +/* + * Opens the haptic device from the file descriptor. + * + * Steps: + * - Open temporary DirectInputDevice interface. + * - Create DirectInputDevice2 interface. + * - Release DirectInputDevice interface. + * - Call SDL_SYS_HapticOpenFromDevice2 + */ +static int +SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance) +{ + HRESULT ret; + int ret2; + LPDIRECTINPUTDEVICE device; + + /* Allocate the hwdata */ + haptic->hwdata = (struct haptic_hwdata *) + SDL_malloc(sizeof(*haptic->hwdata)); + if (haptic->hwdata == NULL) { + SDL_OutOfMemory(); + goto creat_err; + } + SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); + + /* Open the device */ + ret = IDirectInput_CreateDevice( dinput, &instance.guidInstance, + &device, NULL ); + if (FAILED(ret)) { + DI_SetError("Creating DirectInput device",ret); + goto creat_err; + } + + /* Now get the IDirectInputDevice2 interface, instead. */ + ret = IDirectInputDevice_QueryInterface( device, + &IID_IDirectInputDevice2, + (LPVOID *) &haptic->hwdata->device ); + /* Done with the temporary one now. */ + IDirectInputDevice_Release(device); + if (FAILED(ret)) { + DI_SetError("Querying DirectInput interface",ret); + goto creat_err; + } + + ret2 = SDL_SYS_HapticOpenFromDevice2( haptic, haptic->hwdata->device ); + if (ret2 < 0) { + goto query_err; + } + + return 0; + +query_err: + IDirectInputDevice2_Release(haptic->hwdata->device); +creat_err: + if (haptic->hwdata != NULL) { + SDL_free(haptic->hwdata); + haptic->hwdata = NULL; + } + return -1; +} + + +/* + * Opens the haptic device from the file descriptor. + * + * Steps: + * - Set cooperative level. + * - Set data format. + * - Acquire exclusiveness. + * - Reset actuators. + * - Get supported featuers. + */ +static int +SDL_SYS_HapticOpenFromDevice2(SDL_Haptic * haptic, LPDIRECTINPUTDEVICE2 device2) + +{ + HRESULT ret; + DIPROPDWORD dipdw; + + /* We'll use the device2 from now on. */ + haptic->hwdata->device = device2; + + /* Grab it exclusively to use force feedback stuff. */ + ret =IDirectInputDevice2_SetCooperativeLevel( haptic->hwdata->device, + SDL_HelperWindow, + DISCL_EXCLUSIVE | DISCL_BACKGROUND ); + if (FAILED(ret)) { + DI_SetError("Setting cooperative level to exclusive",ret); + goto acquire_err; + } + + /* Set data format. */ + ret = IDirectInputDevice2_SetDataFormat( haptic->hwdata->device, + &c_dfDIJoystick2 ); + if (FAILED(ret)) { + DI_SetError("Setting data format",ret); + goto acquire_err; + } + + /* Get number of axes. */ + ret = IDirectInputDevice2_EnumObjects( haptic->hwdata->device, + DI_DeviceObjectCallback, + haptic, DIDFT_AXIS ); + if (FAILED(ret)) { + DI_SetError("Getting device axes",ret); + goto acquire_err; + } + + /* Acquire the device. */ + ret = IDirectInputDevice2_Acquire(haptic->hwdata->device); + if (FAILED(ret)) { + DI_SetError("Acquiring DirectInput device",ret); + goto acquire_err; + } + + /* Reset all actuators - just in case. */ + ret = IDirectInputDevice2_SendForceFeedbackCommand( haptic->hwdata->device, + DISFFC_RESET ); + if (FAILED(ret)) { + DI_SetError("Resetting device",ret); + goto acquire_err; + } + + /* Enabling actuators. */ + ret = IDirectInputDevice2_SendForceFeedbackCommand( haptic->hwdata->device, + DISFFC_SETACTUATORSON ); + if (FAILED(ret)) { + DI_SetError("Enabling actuators",ret); + goto acquire_err; + } + + /* Get supported effects. */ + ret = IDirectInputDevice2_EnumEffects( haptic->hwdata->device, + DI_EffectCallback, haptic, DIEFT_ALL ); + if (FAILED(ret)) { + DI_SetError("Enumerating supported effects",ret); + goto acquire_err; + } + if (haptic->supported == 0) { /* Error since device supports nothing. */ + SDL_SetError("Haptic: Internal error on finding supported effects."); + goto acquire_err; + } + + /* Check autogain and autocenter. */ + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = 10000; + ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device, + DIPROP_FFGAIN, &dipdw.diph ); + if (!FAILED(ret)) { /* Gain is supported. */ + haptic->supported |= SDL_HAPTIC_GAIN; + } + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = DIPROPAUTOCENTER_OFF; + ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device, + DIPROP_AUTOCENTER, &dipdw.diph ); + if (!FAILED(ret)) { /* Autocenter is supported. */ + haptic->supported |= SDL_HAPTIC_AUTOCENTER; + } + + /* Status is always supported. */ + haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE; + + /* Check maximum effects. */ + haptic->neffects = 128; /* This is not actually supported as thus under windows, + there is no way to tell the number of EFFECTS that a + device can hold, so we'll just use a "random" number + instead and put warnings in SDL_haptic.h */ + haptic->nplaying = 128; /* Even more impossible to get this then neffects. */ + + /* Prepare effects memory. */ + haptic->effects = (struct haptic_effect *) + SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); + if (haptic->effects == NULL) { + SDL_OutOfMemory(); + goto acquire_err; + } + /* Clear the memory */ + SDL_memset(haptic->effects, 0, + sizeof(struct haptic_effect) * haptic->neffects); + + return 0; + + /* Error handling */ +acquire_err: + IDirectInputDevice2_Unacquire(haptic->hwdata->device); + return -1; + +} + + +/* + * Opens a haptic device for usage. + */ +int +SDL_SYS_HapticOpen(SDL_Haptic * haptic) +{ + return SDL_SYS_HapticOpenFromInstance( haptic, + SDL_hapticlist[haptic->index].instance ); +} + + +/* + * Opens a haptic device from first mouse it finds for usage. + */ +int +SDL_SYS_HapticMouse(void) +{ + int i; + + /* Grab the first mouse haptic device we find. */ + for (i=0; ihwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) { + return SDL_TRUE; + } + + return SDL_FALSE; +} + + +/* + * Checks to see if the haptic device and joystick and in reality the same. + */ +int +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + HRESULT ret; + DIDEVICEINSTANCE hap_instance, joy_instance; + + /* Get the device instances. */ + ret = IDirectInputDevice2_GetDeviceInfo( haptic->hwdata->device, + &hap_instance ); + if (FAILED(ret)) { + return 0; + } + ret = IDirectInputDevice2_GetDeviceInfo( joystick->hwdata->InputDevice, + &joy_instance ); + if (FAILED(ret)) { + return 0; + } + + if (DI_GUIDIsSame(&hap_instance.guidInstance, &joy_instance.guidInstance)) + return 1; + + return 0; +} + + +/* + * Opens a SDL_Haptic from a SDL_Joystick. + */ +int +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + int ret; + + /* Allocate the hwdata */ + haptic->hwdata = (struct haptic_hwdata *) + SDL_malloc(sizeof(*haptic->hwdata)); + if (haptic->hwdata == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); + + /* Now open the device. */ + ret = SDL_SYS_HapticOpenFromDevice2( haptic, joystick->hwdata->InputDevice ); + if (ret < 0) { + return -1; + } + + /* It's using the joystick device. */ + haptic->hwdata->is_joystick = 1; + + return 0; +} + + +/* + * Closes the haptic device. + */ +void +SDL_SYS_HapticClose(SDL_Haptic * haptic) +{ + if (haptic->hwdata) { + + /* Free effects. */ + SDL_free(haptic->effects); + haptic->effects = NULL; + haptic->neffects = 0; + + /* Clean up */ + IDirectInputDevice2_Unacquire(haptic->hwdata->device); + /* Only release if isn't grabbed by a joystick. */ + if (haptic->hwdata->is_joystick == 0) { + IDirectInputDevice2_Release(haptic->hwdata->device); + } + + /* Free */ + SDL_free(haptic->hwdata); + haptic->hwdata = NULL; + } +} + + +/* + * Clean up after system specific haptic stuff + */ +void +SDL_SYS_HapticQuit(void) +{ + IDirectInput_Release(dinput); + dinput = NULL; +} + + +/* + * Converts an SDL trigger button to an DIEFFECT trigger button. + */ +static DWORD +DIGetTriggerButton( Uint16 button ) +{ + DWORD dwTriggerButton; + + dwTriggerButton = DIEB_NOTRIGGER; + + if (button != 0) { + dwTriggerButton = DIJOFS_BUTTON(button - 1); + } + + return dwTriggerButton; +} + + +/* + * Sets the direction. + */ +static int +SDL_SYS_SetDirection( DIEFFECT * effect, SDL_HapticDirection *dir, int naxes ) +{ + LONG *rglDir; + + /* Handle no axes a part. */ + if (naxes == 0) { + effect->dwFlags |= DIEFF_SPHERICAL; /* Set as default. */ + effect->rglDirection = NULL; + return 0; + } + + /* Has axes. */ + rglDir = SDL_malloc( sizeof(LONG) * naxes ); + if (rglDir == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset( rglDir, 0, sizeof(LONG) * naxes ); + effect->rglDirection = rglDir; + + switch (dir->type) { + case SDL_HAPTIC_POLAR: + effect->dwFlags |= DIEFF_POLAR; + rglDir[0] = dir->dir[0]; + return 0; + case SDL_HAPTIC_CARTESIAN: + effect->dwFlags |= DIEFF_CARTESIAN; + rglDir[0] = dir->dir[0]; + if (naxes > 1) + rglDir[1] = dir->dir[1]; + if (naxes > 2) + rglDir[2] = dir->dir[2]; + return 0; + case SDL_HAPTIC_SPHERICAL: + effect->dwFlags |= DIEFF_SPHERICAL; + rglDir[0] = dir->dir[0]; + if (naxes > 1) + rglDir[1] = dir->dir[1]; + if (naxes > 2) + rglDir[2] = dir->dir[2]; + return 0; + + default: + SDL_SetError("Haptic: Unknown direction type."); + return -1; + } +} + +#define CONVERT(x) (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF) +/* + * Creates the DIEFFECT from a SDL_HapticEffect. + */ + +static int +SDL_SYS_ToDIEFFECT( SDL_Haptic * haptic, DIEFFECT * dest, SDL_HapticEffect * src ) +{ + int i; + DICONSTANTFORCE *constant; + DIPERIODIC *periodic; + DICONDITION *condition; /* Actually an array of conditions - one per axis. */ + DIRAMPFORCE *ramp; + DICUSTOMFORCE *custom; + DIENVELOPE *envelope; + SDL_HapticConstant *hap_constant; + SDL_HapticPeriodic *hap_periodic; + SDL_HapticCondition *hap_condition; + SDL_HapticRamp *hap_ramp; + SDL_HapticCustom *hap_custom; + DWORD *axes; + + /* Set global stuff. */ + SDL_memset(dest, 0, sizeof(DIEFFECT)); + dest->dwSize = sizeof(DIEFFECT); /* Set the structure size. */ + dest->dwSamplePeriod = 0; /* Not used by us. */ + dest->dwGain = 10000; /* Gain is set globally, not locally. */ + dest->dwFlags = DIEFF_OBJECTOFFSETS; /* Seems obligatory. */ + + /* Envelope. */ + envelope = SDL_malloc( sizeof(DIENVELOPE) ); + if (envelope == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(envelope, 0, sizeof(DIENVELOPE)); + dest->lpEnvelope = envelope; + envelope->dwSize = sizeof(DIENVELOPE); /* Always should be this. */ + + /* Axes. */ + dest->cAxes = haptic->naxes; + if (dest->cAxes > 0) { + axes = SDL_malloc(sizeof(DWORD) * dest->cAxes); + if (axes == NULL) { + SDL_OutOfMemory(); + return -1; + } + axes[0] = haptic->hwdata->axes[0]; /* Always at least one axis. */ + if (dest->cAxes > 1) { + axes[1] = haptic->hwdata->axes[1]; + } + if (dest->cAxes > 2) { + axes[2] = haptic->hwdata->axes[2]; + } + dest->rgdwAxes = axes; + } + + + /* The big type handling switch, even bigger then linux's version. */ + switch (src->type) { + case SDL_HAPTIC_CONSTANT: + hap_constant = &src->constant; + constant = SDL_malloc( sizeof(DICONSTANTFORCE) ); + if (constant == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(constant, 0, sizeof(DICONSTANTFORCE)); + + /* Specifics */ + constant->lMagnitude = CONVERT(hap_constant->level); + dest->cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + dest->lpvTypeSpecificParams = constant; + + /* Generics */ + dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = DIGetTriggerButton(hap_constant->button); + dest->dwTriggerRepeatInterval = hap_constant->interval; + dest->dwStartDelay = hap_constant->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_constant->attack_length==0) && (hap_constant->fade_length==0)) { + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CONVERT(hap_constant->attack_level); + envelope->dwAttackTime = hap_constant->attack_length * 1000; + envelope->dwFadeLevel = CONVERT(hap_constant->fade_level); + envelope->dwFadeTime = hap_constant->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_SINE: + case SDL_HAPTIC_SQUARE: + case SDL_HAPTIC_TRIANGLE: + case SDL_HAPTIC_SAWTOOTHUP: + case SDL_HAPTIC_SAWTOOTHDOWN: + hap_periodic = &src->periodic; + periodic = SDL_malloc(sizeof(DIPERIODIC)); + if (periodic == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(periodic, 0, sizeof(DIPERIODIC)); + + /* Specifics */ + periodic->dwMagnitude = CONVERT(hap_periodic->magnitude); + periodic->lOffset = CONVERT(hap_periodic->offset); + periodic->dwPhase = hap_periodic->phase; + periodic->dwPeriod = hap_periodic->period * 1000; + dest->cbTypeSpecificParams = sizeof(DIPERIODIC); + dest->lpvTypeSpecificParams = periodic; + + /* Generics */ + dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = DIGetTriggerButton(hap_periodic->button); + dest->dwTriggerRepeatInterval = hap_periodic->interval; + dest->dwStartDelay = hap_periodic->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_periodic->attack_length==0) && (hap_periodic->fade_length==0)) { + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CONVERT(hap_periodic->attack_level); + envelope->dwAttackTime = hap_periodic->attack_length * 1000; + envelope->dwFadeLevel = CONVERT(hap_periodic->fade_level); + envelope->dwFadeTime = hap_periodic->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_SPRING: + case SDL_HAPTIC_DAMPER: + case SDL_HAPTIC_INERTIA: + case SDL_HAPTIC_FRICTION: + hap_condition = &src->condition; + condition = SDL_malloc(sizeof(DICONDITION) * dest->cAxes); + if (condition == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(condition, 0, sizeof(DICONDITION)); + + /* Specifics */ + for (i=0; i<(int)dest->cAxes; i++) { + condition[i].lOffset = CONVERT(hap_condition->center[i]); + condition[i].lPositiveCoefficient = CONVERT(hap_condition->right_coeff[i]); + condition[i].lNegativeCoefficient = CONVERT(hap_condition->left_coeff[i]); + condition[i].dwPositiveSaturation = CONVERT(hap_condition->right_sat[i]); + condition[i].dwNegativeSaturation = CONVERT(hap_condition->left_sat[i]); + condition[i].lDeadBand = CONVERT(hap_condition->deadband[i]); + } + dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes; + dest->lpvTypeSpecificParams = condition; + + /* Generics */ + dest->dwDuration = hap_condition->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = DIGetTriggerButton(hap_condition->button); + dest->dwTriggerRepeatInterval = hap_condition->interval; + dest->dwStartDelay = hap_condition->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope - Not actually supported by most CONDITION implementations. */ + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + + break; + + case SDL_HAPTIC_RAMP: + hap_ramp = &src->ramp; + ramp = SDL_malloc(sizeof(DIRAMPFORCE)); + if (ramp == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(ramp, 0, sizeof(DIRAMPFORCE)); + + /* Specifics */ + ramp->lStart = CONVERT(hap_ramp->start); + ramp->lEnd = CONVERT(hap_ramp->end); + dest->cbTypeSpecificParams = sizeof(DIRAMPFORCE); + dest->lpvTypeSpecificParams = ramp; + + /* Generics */ + dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = DIGetTriggerButton(hap_ramp->button); + dest->dwTriggerRepeatInterval = hap_ramp->interval; + dest->dwStartDelay = hap_ramp->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_ramp->attack_length==0) && (hap_ramp->fade_length==0)) { + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CONVERT(hap_ramp->attack_level); + envelope->dwAttackTime = hap_ramp->attack_length * 1000; + envelope->dwFadeLevel = CONVERT(hap_ramp->fade_level); + envelope->dwFadeTime = hap_ramp->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_CUSTOM: + hap_custom = &src->custom; + custom = SDL_malloc(sizeof(DICUSTOMFORCE)); + if (custom == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(custom, 0, sizeof(DICUSTOMFORCE)); + + /* Specifics */ + custom->cChannels = hap_custom->channels; + custom->dwSamplePeriod = hap_custom->period * 1000; + custom->cSamples = hap_custom->samples; + custom->rglForceData = SDL_malloc(sizeof(LONG)*custom->cSamples*custom->cChannels); + for (i=0; isamples*hap_custom->channels; i++) { /* Copy data. */ + custom->rglForceData[i] = CONVERT(hap_custom->data[i]); + } + dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE); + dest->lpvTypeSpecificParams = custom; + + /* Generics */ + dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = DIGetTriggerButton(hap_custom->button); + dest->dwTriggerRepeatInterval = hap_custom->interval; + dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_custom->attack_length==0) && (hap_custom->fade_length==0)) { + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + } + else { + envelope->dwAttackLevel = CONVERT(hap_custom->attack_level); + envelope->dwAttackTime = hap_custom->attack_length * 1000; + envelope->dwFadeLevel = CONVERT(hap_custom->fade_level); + envelope->dwFadeTime = hap_custom->fade_length * 1000; + } + + break; + + + default: + SDL_SetError("Haptic: Unknown effect type."); + return -1; + } + + return 0; +} + + +/* + * Frees an DIEFFECT allocated by SDL_SYS_ToDIEFFECT. + */ +static void +SDL_SYS_HapticFreeDIEFFECT( DIEFFECT * effect, int type ) +{ + DICUSTOMFORCE *custom; + + if (effect->lpEnvelope != NULL) { + SDL_free(effect->lpEnvelope); + effect->lpEnvelope = NULL; + } + if (effect->rgdwAxes != NULL) { + SDL_free(effect->rgdwAxes); + effect->rgdwAxes = NULL; + } + if (effect->lpvTypeSpecificParams != NULL) { + if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */ + custom = (DICUSTOMFORCE*) effect->lpvTypeSpecificParams; + SDL_free(custom->rglForceData); + custom->rglForceData = NULL; + } + SDL_free(effect->lpvTypeSpecificParams); + effect->lpvTypeSpecificParams = NULL; + } + if (effect->rglDirection != NULL) { + SDL_free(effect->rglDirection); + effect->rglDirection = NULL; + } +} + + +/* + * Gets the effect type from the generic SDL haptic effect wrapper. + */ +static REFGUID +SDL_SYS_HapticEffectType(SDL_HapticEffect * effect) +{ + switch (effect->type) { + case SDL_HAPTIC_CONSTANT: + return &GUID_ConstantForce; + + case SDL_HAPTIC_RAMP: + return &GUID_RampForce; + + case SDL_HAPTIC_SQUARE: + return &GUID_Square; + + case SDL_HAPTIC_SINE: + return &GUID_Sine; + + case SDL_HAPTIC_TRIANGLE: + return &GUID_Triangle; + + case SDL_HAPTIC_SAWTOOTHUP: + return &GUID_SawtoothUp; + + case SDL_HAPTIC_SAWTOOTHDOWN: + return &GUID_SawtoothDown; + + case SDL_HAPTIC_SPRING: + return &GUID_Spring; + + case SDL_HAPTIC_DAMPER: + return &GUID_Damper; + + case SDL_HAPTIC_INERTIA: + return &GUID_Inertia; + + case SDL_HAPTIC_FRICTION: + return &GUID_Friction; + + case SDL_HAPTIC_CUSTOM: + return &GUID_CustomForce; + + default: + SDL_SetError("Haptic: Unknown effect type."); + return NULL; + } +} + + +/* + * Creates a new haptic effect. + */ +int +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect * effect, + SDL_HapticEffect * base) +{ + HRESULT ret; + + /* Get the type. */ + REFGUID type = SDL_SYS_HapticEffectType(base); + if (type == NULL) { + goto err_hweffect; + } + + /* Alloc the effect. */ + effect->hweffect = (struct haptic_hweffect *) + SDL_malloc(sizeof(struct haptic_hweffect)); + if (effect->hweffect == NULL) { + SDL_OutOfMemory(); + goto err_hweffect; + } + + /* Get the effect. */ + if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) { + goto err_effectdone; + } + + /* Create the actual effect. */ + ret = IDirectInputDevice2_CreateEffect(haptic->hwdata->device, type, + &effect->hweffect->effect, &effect->hweffect->ref, NULL); + if (FAILED(ret)) { + DI_SetError("Unable to create effect",ret); + goto err_effectdone; + } + + return 0; + +err_effectdone: + SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type); +err_hweffect: + if (effect->hweffect != NULL) { + SDL_free(effect->hweffect); + effect->hweffect = NULL; + } + return -1; +} + + +/* + * Updates an effect. + */ +int +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, + struct haptic_effect * effect, SDL_HapticEffect * data) +{ + HRESULT ret; + DWORD flags; + DIEFFECT temp; + + /* Get the effect. */ + SDL_memset(&temp, 0, sizeof(DIEFFECT)); + if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) { + goto err_update; + } + + /* Set the flags. Might be worthwhile to diff temp with loaded effect and + * only change those parameters. */ + flags = DIEP_DIRECTION | + DIEP_DURATION | + DIEP_ENVELOPE | + DIEP_STARTDELAY | + DIEP_TRIGGERBUTTON | + DIEP_TRIGGERREPEATINTERVAL | + DIEP_TYPESPECIFICPARAMS; + + /* Create the actual effect. */ + ret = IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags); + if (FAILED(ret)) { + DI_SetError("Unable to update effect",ret); + goto err_update; + } + + /* Copy it over. */ + SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type); + SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT)); + + return 0; + +err_update: + SDL_SYS_HapticFreeDIEFFECT(&temp, data->type); + return -1; +} + + +/* + * Runs an effect. + */ +int +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect, + Uint32 iterations) +{ + HRESULT ret; + DWORD iter; + + /* Check if it's infinite. */ + if (iterations == SDL_HAPTIC_INFINITY) { + iter = INFINITE; + } + else + iter = iterations; + + /* Run the effect. */ + ret = IDirectInputEffect_Start( effect->hweffect->ref, iter, 0 ); + if (FAILED(ret)) { + DI_SetError("Running the effect",ret); + return -1; + } + + return 0; +} + + +/* + * Stops an effect. + */ +int +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + HRESULT ret; + + ret = IDirectInputEffect_Stop(effect->hweffect->ref); + if (FAILED(ret)) { + DI_SetError("Unable to stop effect",ret); + return -1; + } + + return 0; +} + + +/* + * Frees the effect. + */ +void +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + HRESULT ret; + + ret = IDirectInputEffect_Unload(effect->hweffect->ref); + if (FAILED(ret)) { + DI_SetError("Removing effect from the device",ret); + } + SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, effect->effect.type); + SDL_free(effect->hweffect); + effect->hweffect = NULL; +} + + +/* + * Gets the status of a haptic effect. + */ +int +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect) +{ + HRESULT ret; + DWORD status; + + ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status); + if (FAILED(ret)) { + DI_SetError("Getting effect status",ret); + return -1; + } + + if (status == 0) return SDL_FALSE; + return SDL_TRUE; +} + + +/* + * Sets the gain. + */ +int +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) +{ + HRESULT ret; + DIPROPDWORD dipdw; + + /* Create the weird structure thingy. */ + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = gain * 100; /* 0 to 10,000 */ + + /* Try to set the autocenter. */ + ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device, + DIPROP_FFGAIN, &dipdw.diph ); + if (FAILED(ret)) { + DI_SetError("Setting gain",ret); + return -1; + } + + return 0; +} + + +/* + * Sets the autocentering. + */ +int +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) +{ + HRESULT ret; + DIPROPDWORD dipdw; + + /* Create the weird structure thingy. */ + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF : + DIPROPAUTOCENTER_ON; + + /* Try to set the autocenter. */ + ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device, + DIPROP_AUTOCENTER, &dipdw.diph ); + if (FAILED(ret)) { + DI_SetError("Setting autocenter",ret); + return -1; + } + + return 0; +} + + +/* + * Pauses the device. + */ +int +SDL_SYS_HapticPause(SDL_Haptic * haptic) +{ + HRESULT ret; + + /* Pause the device. */ + ret = IDirectInputDevice2_SendForceFeedbackCommand( haptic->hwdata->device, + DISFFC_PAUSE ); + if (FAILED(ret)) { + DI_SetError("Pausing the device",ret); + return -1; + } + + return 0; +} + + +/* + * Pauses the device. + */ +int +SDL_SYS_HapticUnpause(SDL_Haptic * haptic) +{ + HRESULT ret; + + /* Unpause the device. */ + ret = IDirectInputDevice2_SendForceFeedbackCommand( haptic->hwdata->device, + DISFFC_CONTINUE ); + if (FAILED(ret)) { + DI_SetError("Pausing the device",ret); + return -1; + } + + return 0; +} + + +/* + * Stops all the playing effects on the device. + */ +int +SDL_SYS_HapticStopAll(SDL_Haptic * haptic) +{ + HRESULT ret; + + /* Try to stop the effects. */ + ret = IDirectInputDevice2_SendForceFeedbackCommand( haptic->hwdata->device, + DISFFC_STOPALL ); + if (FAILED(ret)) { + DI_SetError("Stopping the device",ret); + return -1; + } + + return 0; +} + + +#endif /* SDL_HAPTIC_DINPUT */ \ No newline at end of file diff --git a/test/configure b/test/configure index 618b0e306..0db50ce45 100755 --- a/test/configure +++ b/test/configure @@ -1434,8 +1434,8 @@ fi # ac_fn_c_try_run LINENO # ---------------------- -# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that -# executables *can* be run. +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack @@ -1667,8 +1667,6 @@ done # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? - # Sanitize IFS. - IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo @@ -2345,7 +2343,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -2485,11 +2483,9 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); - if (!f) - return 1; return ferror (f) || fclose (f) != 0; ; @@ -2501,9 +2497,7 @@ ac_clean_files="$ac_clean_files conftest.out" # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" = maybe && test "x$build" != "x$host"; then - cross_compiling=yes -elif test "$cross_compiling" != yes; then +if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; @@ -2553,7 +2547,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -2604,7 +2598,7 @@ else /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -2645,7 +2639,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -2660,7 +2654,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -2676,7 +2670,7 @@ else /* end confdefs.h. */ int -main () +main (void) { ; @@ -2725,9 +2719,7 @@ struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; +static char *e (char **p, int i) { return p[i]; } @@ -2762,7 +2754,7 @@ int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, i int argc; char **argv; int -main () +main (void) { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; @@ -2817,7 +2809,7 @@ else /* end confdefs.h. */ int -main () +main (void) { #ifndef __cplusplus @@ -3383,7 +3375,7 @@ int main(int argc, char *argv[]) #define main K_and_R_C_main int -main () +main (void) { return 0; ; @@ -3583,34 +3575,8 @@ else $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. -ac_x_includes=no -ac_x_libraries=no -# Do we need to do anything special at all? -ac_save_LIBS=$LIBS -LIBS="-lX11 $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -XrmInitialize () - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - # We can compile and link X programs with no special options. - ac_x_includes= - ac_x_libraries= -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS="$ac_save_LIBS" -# If that didn't work, only try xmkmf and filesystem searches -# for native compilation. -if test x"$ac_x_includes" = xno && test "$cross_compiling" = no; then : - rm -f -r conftest.dir +ac_x_includes=no ac_x_libraries=no +rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' @@ -3649,7 +3615,7 @@ _ACEOF rm -f -r conftest.dir fi - # Standard set of common directories for X headers. +# Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include @@ -3676,8 +3642,6 @@ ac_x_header_dirs=' /usr/local/include/X11R5 /usr/local/include/X11R4 -/opt/X11/include - /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 @@ -3723,7 +3687,7 @@ if test "$ac_x_libraries" = no; then /* end confdefs.h. */ #include int -main () +main (void) { XrmInitialize () ; @@ -3751,17 +3715,15 @@ rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no -fi -# Record the results. case $ac_x_includes,$ac_x_libraries in #( - no,* | *,no | *\'*) : + no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. - ac_cv_have_x="have_x=no" ;; #( - *) : + ac_cv_have_x="have_x=no";; #( + *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ - ac_x_libraries='$ac_x_libraries'" ;; + ac_x_libraries='$ac_x_libraries'" esac fi ;; #( @@ -3808,7 +3770,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #include "SDL_opengl.h" int -main () +main (void) { From cd6c6b2d6eb99ca1c76f03d1a8cc59b32dd8c77c Mon Sep 17 00:00:00 2001 From: mcarans Date: Sat, 16 Aug 2025 17:36:53 +1200 Subject: [PATCH 3/4] Mouse delta wheel and other missed changes --- include/SDL_events.h | 1 + src/events/SDL_events_c.h | 2 +- src/events/SDL_mouse.c | 5 ++-- src/events/SDL_resize.c | 4 +-- src/hermes/mmx_main.asm | 4 +-- src/hermes/mmxp2_32.asm | 20 +++++++------- src/hermes/x86_main.asm | 4 +-- src/hermes/x86p_16.asm | 18 ++++++------- src/hermes/x86p_32.asm | 40 ++++++++++++++-------------- src/joystick/linux/SDL_sysjoystick.c | 1 + src/video/windx5/SDL_dx5events.c | 13 ++++----- 11 files changed, 58 insertions(+), 54 deletions(-) diff --git a/include/SDL_events.h b/include/SDL_events.h index 94b420251..4c5fc3cec 100644 --- a/include/SDL_events.h +++ b/include/SDL_events.h @@ -147,6 +147,7 @@ typedef struct SDL_MouseButtonEvent { Uint8 button; /**< The mouse button index */ Uint8 state; /**< SDL_PRESSED or SDL_RELEASED */ Uint16 x, y; /**< The X/Y coordinates of the mouse at press time */ + short wheelDelta; /* The delta of the mousewheel movement */ } SDL_MouseButtonEvent; /** Joystick axis motion event structure */ diff --git a/src/events/SDL_events_c.h b/src/events/SDL_events_c.h index 437845150..6890433e8 100644 --- a/src/events/SDL_events_c.h +++ b/src/events/SDL_events_c.h @@ -57,7 +57,7 @@ extern Uint8 SDL_ProcessEvents[SDL_NUMEVENTS]; extern int SDL_PrivateAppActive(Uint8 gain, Uint8 state); extern int SDL_PrivateMouseMotion(Uint8 buttonstate, int relative, Sint16 x, Sint16 y); -extern int SDL_PrivateMouseButton(Uint8 state, Uint8 button,Sint16 x,Sint16 y); +extern int SDL_PrivateMouseButton(Uint8 state, Uint8 button,Sint16 x,Sint16 y, short wDelta); extern int SDL_PrivateKeyboard(Uint8 state, SDL_keysym *key); extern int SDL_PrivateResize(int w, int h); extern int SDL_PrivateExpose(void); diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 0320d6167..6cc06d4fb 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -64,7 +64,7 @@ void SDL_ResetMouse(void) Uint8 i; for ( i = 1; i < sizeof(SDL_ButtonState)*8; ++i ) { if ( SDL_ButtonState & SDL_BUTTON(i) ) { - SDL_PrivateMouseButton(SDL_RELEASED, i, 0, 0); + SDL_PrivateMouseButton(SDL_RELEASED, i, 0, 0, 0); } } } @@ -194,7 +194,7 @@ printf("Mouse event didn't change state - dropped!\n"); return(posted); } -int SDL_PrivateMouseButton(Uint8 state, Uint8 button, Sint16 x, Sint16 y) +int SDL_PrivateMouseButton(Uint8 state, Uint8 button, Sint16 x, Sint16 y, short wDelta) { SDL_Event event; int posted; @@ -258,6 +258,7 @@ int SDL_PrivateMouseButton(Uint8 state, Uint8 button, Sint16 x, Sint16 y) event.button.button = button; event.button.x = x; event.button.y = y; + event.button.wheelDelta = button == SDL_BUTTON_WHEELUP || SDL_BUTTON_WHEELDOWN ? wDelta : 0; if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) { posted = 1; SDL_PushEvent(&event); diff --git a/src/events/SDL_resize.c b/src/events/SDL_resize.c index 8a29cf02f..226714abc 100644 --- a/src/events/SDL_resize.c +++ b/src/events/SDL_resize.c @@ -49,13 +49,13 @@ int SDL_PrivateResize(int w, int h) last_resize.w = w; last_resize.h = h; + SDL_SetMouseRange(w, h); + #ifdef __WIN32__ SDL_VideoSurface->w = w; SDL_VideoSurface->h = h; #endif - SDL_SetMouseRange(w, h); - /* Pull out all old resize events */ SDL_PeepEvents(events, sizeof(events)/sizeof(events[0]), SDL_GETEVENT, SDL_VIDEORESIZEMASK); diff --git a/src/hermes/mmx_main.asm b/src/hermes/mmx_main.asm index 00032b95c..417c9281d 100644 --- a/src/hermes/mmx_main.asm +++ b/src/hermes/mmx_main.asm @@ -11,7 +11,7 @@ BITS 32 %include "common.inc" -SDL_FUNC _ConvertMMX +SDL_FUNC ConvertMMX SECTION .text @@ -30,7 +30,7 @@ SECTION .text ;; 32: void (*converter_function)() ;; 36: int32 *lookup -_ConvertMMX: +ConvertMMX: push ebp mov ebp,esp diff --git a/src/hermes/mmxp2_32.asm b/src/hermes/mmxp2_32.asm index 20c3277a2..22df107bd 100644 --- a/src/hermes/mmxp2_32.asm +++ b/src/hermes/mmxp2_32.asm @@ -22,11 +22,11 @@ BITS 32 %include "common.inc" -SDL_FUNC _ConvertMMXpII32_24RGB888 -SDL_FUNC _ConvertMMXpII32_16RGB565 -SDL_FUNC _ConvertMMXpII32_16BGR565 -SDL_FUNC _ConvertMMXpII32_16RGB555 -SDL_FUNC _ConvertMMXpII32_16BGR555 +SDL_FUNC ConvertMMXpII32_24RGB888 +SDL_FUNC ConvertMMXpII32_16RGB565 +SDL_FUNC ConvertMMXpII32_16BGR565 +SDL_FUNC ConvertMMXpII32_16RGB555 +SDL_FUNC ConvertMMXpII32_16BGR555 ;; Macros for conversion routines @@ -60,7 +60,7 @@ SDL_FUNC _ConvertMMXpII32_16BGR555 SECTION .text -_ConvertMMXpII32_24RGB888: +ConvertMMXpII32_24RGB888: ; set up mm6 as the mask, mm7 as zero load_immq mm6, mmx32_rgb888_mask @@ -123,7 +123,7 @@ _ConvertMMXpII32_24RGB888: -_ConvertMMXpII32_16RGB565: +ConvertMMXpII32_16RGB565: ; set up masks load_immq mm5, mmx32_rgb565_b @@ -191,7 +191,7 @@ _ConvertMMXpII32_16RGB565: retn -_ConvertMMXpII32_16BGR565: +ConvertMMXpII32_16BGR565: load_immq mm5, mmx32_rgb565_r load_immq mm6, mmx32_rgb565_g @@ -260,7 +260,7 @@ _ConvertMMXpII32_16BGR565: .L4: retn -_ConvertMMXpII32_16BGR555: +ConvertMMXpII32_16BGR555: ; the 16BGR555 converter is identical to the RGB555 one, ; except it uses a different multiplier for the pmaddwd @@ -274,7 +274,7 @@ _ConvertMMXpII32_16BGR555: ; would almost certainly be faster, even if only a little. ; I did rename 'mmx32_rgb555_add' to 'mmx32_rgb555_mul', which is ; (I think) a more accurate name.. -_ConvertMMXpII32_16RGB555: +ConvertMMXpII32_16RGB555: load_immq mm7, mmx32_rgb555_mul _convert_bgr555_cheat: diff --git a/src/hermes/x86_main.asm b/src/hermes/x86_main.asm index f7dd3db70..65299aa81 100644 --- a/src/hermes/x86_main.asm +++ b/src/hermes/x86_main.asm @@ -13,7 +13,7 @@ BITS 32 %include "common.inc" -SDL_FUNC _ConvertX86 +SDL_FUNC ConvertX86 SECTION .text @@ -32,7 +32,7 @@ SECTION .text ;; 32: void (*converter_function)() ;; 36: int32 *lookup -_ConvertX86: +ConvertX86: push ebp mov ebp,esp diff --git a/src/hermes/x86p_16.asm b/src/hermes/x86p_16.asm index 1801bcd15..b027ef57e 100644 --- a/src/hermes/x86p_16.asm +++ b/src/hermes/x86p_16.asm @@ -14,16 +14,16 @@ BITS 32 %include "common.inc" -SDL_FUNC _ConvertX86p16_16BGR565 -SDL_FUNC _ConvertX86p16_16RGB555 -SDL_FUNC _ConvertX86p16_16BGR555 -SDL_FUNC _ConvertX86p16_8RGB332 +SDL_FUNC ConvertX86p16_16BGR565 +SDL_FUNC ConvertX86p16_16RGB555 +SDL_FUNC ConvertX86p16_16BGR555 +SDL_FUNC ConvertX86p16_8RGB332 -EXTERN _ConvertX86 +EXTERN ConvertX86 SECTION .text -_ConvertX86p16_16BGR565: +ConvertX86p16_16BGR565: ; check short cmp ecx,BYTE 16 @@ -133,7 +133,7 @@ _ConvertX86p16_16BGR565: -_ConvertX86p16_16RGB555: +ConvertX86p16_16RGB555: ; check short cmp ecx,BYTE 32 @@ -241,7 +241,7 @@ _ConvertX86p16_16RGB555: -_ConvertX86p16_16BGR555: +ConvertX86p16_16BGR555: ; check short cmp ecx,BYTE 16 @@ -359,7 +359,7 @@ _ConvertX86p16_16BGR555: -_ConvertX86p16_8RGB332: +ConvertX86p16_8RGB332: ; check short cmp ecx,BYTE 16 diff --git a/src/hermes/x86p_32.asm b/src/hermes/x86p_32.asm index 2b478802d..ac0b60641 100644 --- a/src/hermes/x86p_32.asm +++ b/src/hermes/x86p_32.asm @@ -13,16 +13,16 @@ BITS 32 %include "common.inc" -SDL_FUNC _ConvertX86p32_32BGR888 -SDL_FUNC _ConvertX86p32_32RGBA888 -SDL_FUNC _ConvertX86p32_32BGRA888 -SDL_FUNC _ConvertX86p32_24RGB888 -SDL_FUNC _ConvertX86p32_24BGR888 -SDL_FUNC _ConvertX86p32_16RGB565 -SDL_FUNC _ConvertX86p32_16BGR565 -SDL_FUNC _ConvertX86p32_16RGB555 -SDL_FUNC _ConvertX86p32_16BGR555 -SDL_FUNC _ConvertX86p32_8RGB332 +SDL_FUNC ConvertX86p32_32BGR888 +SDL_FUNC ConvertX86p32_32RGBA888 +SDL_FUNC ConvertX86p32_32BGRA888 +SDL_FUNC ConvertX86p32_24RGB888 +SDL_FUNC ConvertX86p32_24BGR888 +SDL_FUNC ConvertX86p32_16RGB565 +SDL_FUNC ConvertX86p32_16BGR565 +SDL_FUNC ConvertX86p32_16RGB555 +SDL_FUNC ConvertX86p32_16BGR555 +SDL_FUNC ConvertX86p32_8RGB332 SECTION .text @@ -35,7 +35,7 @@ SECTION .text ;; EAX, EBX, EDX -_ConvertX86p32_32BGR888: +ConvertX86p32_32BGR888: ; check short cmp ecx,BYTE 32 @@ -116,7 +116,7 @@ _ConvertX86p32_32BGR888: -_ConvertX86p32_32RGBA888: +ConvertX86p32_32RGBA888: ; check short cmp ecx,BYTE 32 @@ -187,7 +187,7 @@ _ConvertX86p32_32RGBA888: -_ConvertX86p32_32BGRA888: +ConvertX86p32_32BGRA888: ; check short cmp ecx,BYTE 32 @@ -262,7 +262,7 @@ _ConvertX86p32_32BGRA888: ;; 32 bit RGB 888 to 24 BIT RGB 888 -_ConvertX86p32_24RGB888: +ConvertX86p32_24RGB888: ; check short cmp ecx,BYTE 32 @@ -359,7 +359,7 @@ _ConvertX86p32_24RGB888: ;; 32 bit RGB 888 to 24 bit BGR 888 -_ConvertX86p32_24BGR888: +ConvertX86p32_24BGR888: ; check short cmp ecx,BYTE 32 @@ -459,7 +459,7 @@ _ConvertX86p32_24BGR888: ;; 32 bit RGB 888 to 16 BIT RGB 565 -_ConvertX86p32_16RGB565: +ConvertX86p32_16RGB565: ; check short cmp ecx,BYTE 16 ja .L3 @@ -574,7 +574,7 @@ _ConvertX86p32_16RGB565: ;; 32 bit RGB 888 to 16 BIT BGR 565 -_ConvertX86p32_16BGR565: +ConvertX86p32_16BGR565: ; check short cmp ecx,BYTE 16 @@ -688,7 +688,7 @@ _ConvertX86p32_16BGR565: ;; 32 BIT RGB TO 16 BIT RGB 555 -_ConvertX86p32_16RGB555: +ConvertX86p32_16RGB555: ; check short cmp ecx,BYTE 16 @@ -799,7 +799,7 @@ _ConvertX86p32_16RGB555: ;; 32 BIT RGB TO 16 BIT BGR 555 -_ConvertX86p32_16BGR555: +ConvertX86p32_16BGR555: ; check short cmp ecx,BYTE 16 @@ -916,7 +916,7 @@ _ConvertX86p32_16BGR555: ;; FROM 32 BIT RGB to 8 BIT RGB (rrrgggbbb) ;; This routine writes FOUR pixels at once (dword) and then, if they exist ;; the trailing three pixels -_ConvertX86p32_8RGB332: +ConvertX86p32_8RGB332: .L_ALIGNED: diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index ddf721f18..078636942 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -782,6 +782,7 @@ int SDL_SYS_JoystickOpen(SDL_Joystick *joystick) SDL_joylist[joystick->index].joy = joystick; #else fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0); + fname = SDL_joylist[joystick->index].fname; #endif if ( fd < 0 ) { diff --git a/src/video/windx5/SDL_dx5events.c b/src/video/windx5/SDL_dx5events.c index 284cd9f15..12121e8ab 100644 --- a/src/video/windx5/SDL_dx5events.c +++ b/src/video/windx5/SDL_dx5events.c @@ -443,7 +443,7 @@ static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *ptrbuf) if ( button == 3 ) button = 1; } posted = SDL_PrivateMouseButton(state, button, - 0, 0); + 0, 0, 0); } old_state >>= 1; new_state >>= 1; @@ -486,14 +486,15 @@ static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *ptrbuf) yrel = 0; } timestamp = 0; - if((int)ptrbuf[i].dwData > 0) - button = SDL_BUTTON_WHEELUP; + int move = (int)ptrbuf[i].dwData; + if(move > 0) + button = SDL_BUTTON_WHEELUP; else button = SDL_BUTTON_WHEELDOWN; posted = SDL_PrivateMouseButton( - SDL_PRESSED, button, 0, 0); + SDL_PRESSED, button, 0, 0, move); posted |= SDL_PrivateMouseButton( - SDL_RELEASED, button, 0, 0); + SDL_RELEASED, button, 0, 0, move); break; case DIMOFS_BUTTON0: case DIMOFS_BUTTON1: @@ -540,7 +541,7 @@ static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *ptrbuf) if ( button == 3 ) button = 1; } posted = SDL_PrivateMouseButton(state, button, - 0, 0); + 0, 0, 0); break; } } From 69462516492394388f452e252e460d8c4f8d8af6 Mon Sep 17 00:00:00 2001 From: mcarans Date: Sat, 16 Aug 2025 17:50:40 +1200 Subject: [PATCH 4/4] Missed changes --- src/video/wincommon/SDL_sysevents.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/video/wincommon/SDL_sysevents.c b/src/video/wincommon/SDL_sysevents.c index 4b6b7779f..0f5080fd5 100644 --- a/src/video/wincommon/SDL_sysevents.c +++ b/src/video/wincommon/SDL_sysevents.c @@ -453,7 +453,7 @@ LRESULT CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) #endif } posted = SDL_PrivateMouseButton( - state, button, x, y); + state, button, x, y, 0); /* * MSDN says: @@ -475,7 +475,7 @@ LRESULT CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) case WM_MOUSEWHEEL: if ( SDL_VideoSurface && ! DINPUT() ) { - int move = (short)HIWORD(wParam); + short move = GET_WHEEL_DELTA_WPARAM(wParam); if ( move ) { Uint8 button; if ( move > 0 ) @@ -483,9 +483,9 @@ LRESULT CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) else button = SDL_BUTTON_WHEELDOWN; posted = SDL_PrivateMouseButton( - SDL_PRESSED, button, 0, 0); + SDL_PRESSED, button, 0, 0, move); posted |= SDL_PrivateMouseButton( - SDL_RELEASED, button, 0, 0); + SDL_RELEASED, button, 0, 0, move); } } return(0);