From ff4d794ca262ba0b383a7cdfaf95f5cfe29faeb0 Mon Sep 17 00:00:00 2001 From: "SND\\edgbla_cp" Date: Sun, 17 Apr 2011 19:19:31 +0000 Subject: Patch 9013 (Edomato). git-svn-id: https://pcsxr.svn.codeplex.com/svn/pcsxr@65925 e17a0e51-4ae3-4d35-97c3-1a29b211df97 --- plugins/dfinput/pad.c | 183 +++++++++++++++++++++++++++++++++++++++++++++-- plugins/dfinput/pad.h | 18 +++++ plugins/dfinput/sdljoy.c | 82 +++++++++++++++++++++ 3 files changed, 279 insertions(+), 4 deletions(-) (limited to 'plugins/dfinput') diff --git a/plugins/dfinput/pad.c b/plugins/dfinput/pad.c index 302560e8..a4cd908a 100644 --- a/plugins/dfinput/pad.c +++ b/plugins/dfinput/pad.c @@ -17,6 +17,11 @@ */ #include "pad.h" +#if !SDL_VERSION_ATLEAST(1,3,0) && defined(__linux__) +#include +#include +#include +#endif static void (*gpuVisualVibration)(uint32_t, uint32_t) = NULL; @@ -81,6 +86,12 @@ long PADopen(unsigned long *Disp) { } else if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE) == -1) { return PSE_PAD_ERR_FAILURE; } + +#if SDL_VERSION_ATLEAST(1,3,0) + has_haptic = 0; + if (SDL_InitSubSystem(SDL_INIT_HAPTIC) == 0) + has_haptic = 1; +#endif InitSDLJoy(); InitKeyboard(); @@ -193,6 +204,152 @@ static uint8_t stdmodel[2][8] = { 0x01, 0x00} }; + +#if !SDL_VERSION_ATLEAST(1,3,0) && defined(__linux__) +/* lifted from SDL; but it's GPL as well */ +/* added ffbit, though */ +#define test_bit(nr, addr) \ + (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0) +#define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1) +static int EV_IsJoystick(int fd) +{ + unsigned long evbit[NBITS(EV_MAX)] = { 0 }; + unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; + unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; + unsigned long ffbit[NBITS(FF_MAX)] = { 0 }; + + if ( (ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) || + (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || + (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0) ) { + return(0); + } + if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) && + test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) && + (test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_A, keybit) || test_bit(BTN_1, keybit)))) return 0; + if ( (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) < 0) || + !test_bit(FF_RUMBLE, ffbit) ) + return(1); + return(2); +} + +static void linux_set_vibrate(int pad) +{ + int jno = 0, devno, dev; + const char *sdlj; + int tjno = g.cfg.PadDef[pad].DevNum; + + g.PadState[pad].VibrateDev = -2; + /* simulate SDL device opening; probably not very accurate */ + /* works for me, though */ + sdlj = getenv("SDL_JOYSTICK_DEVICE"); + if(sdlj) { + dev = open(sdlj, O_RDONLY); + if(dev >= 0) { + if(!tjno) { + close(dev); + dev = open(sdlj, O_RDWR); + if(dev < 0) { + printf("%s has no permission to rumble\n", sdlj); + return; + } + if(EV_IsJoystick(dev) != 2) { + printf("%s has no rumble\n", sdlj); + close(dev); + return; + } + g.PadState[pad].VibrateDev = dev; + return; + } + close(dev); + jno++; + } else + perror(sdlj); + } + for(devno = 0; devno < 32; devno++) { + char buf[20]; + + sprintf(buf, "/dev/input/event%d", devno); + dev = open(buf, O_RDONLY); + if(dev >= 0) { + int isj = EV_IsJoystick(dev); + if(isj) { + if(tjno == jno) { + close(dev); + if(isj != 2) { + printf("%s has no rumble\n", buf); + return; + } + dev = open(buf, O_RDWR); + if(dev < 0) { + printf("%s has no permission to rumble\n", buf); + return; + } + g.PadState[pad].VibrateDev = dev; + return; + } + jno++; + } + close(dev); + } + } +} + +static int linux_vibrate(PADSTATE *pad) +{ + struct ff_effect ffe = { 0 }; + struct input_event ev = { { 0 } }; + struct timespec t; + uint32_t stime; + + if(pad->VibrateDev < 0) + return 0; + ev.type = EV_FF; + if(!pad->VibF[0] && !pad->VibF[1] && pad->VibrateEffect < 0) { + return 1; + } + clock_gettime(CLOCK_REALTIME, &t); + stime = (uint32_t)(t.tv_sec * 1000 + t.tv_nsec / 1000000); + if(pad->VibrateEffect >= 0 && + pad->VibrLow == pad->VibF[0] && pad->VibrHigh == pad->VibF[1]) { + if(stime - pad->VibrSetTime < 300) + return 1; + } + if(pad->VibrateEffect < 0 || pad->VibrLow != pad->VibF[0] || + pad->VibrHigh != pad->VibF[1]) { + if(pad->VibrateEffect >= 0) { + ev.code = pad->VibrateEffect; + ev.value = 0; + if(write(pad->VibrateDev, &ev, sizeof(ev)) < 0) + perror("ev write"); + } + ffe.type = FF_RUMBLE; + ffe.id = pad->VibrateEffect; + /* DG says refresh 1/vsync = 166, but add for delays/etc. */ + ffe.replay.length = 500; + ffe.replay.delay = 0; + ffe.u.rumble.strong_magnitude = pad->VibF[1] * 256; + ffe.u.rumble.weak_magnitude = pad->VibF[0] * 256; + pad->VibrLow = pad->VibF[0]; + pad->VibrHigh = pad->VibF[1]; + if(ioctl(pad->VibrateDev, EVIOCSFF,&ffe) < 0) { + perror("SFF ioctl"); + close(pad->VibrateDev); + pad->VibrateDev = -2; + return 0; + } + } + pad->VibrSetTime = stime; + ev.code = pad->VibrateEffect = ffe.id; + ev.value = 1; + if(write(pad->VibrateDev, &ev, sizeof(ev)) != sizeof(ev)) { + close(pad->VibrateDev); + pad->VibrateDev = -2; + perror("ev write"); + return 0; + } + return 1; +} +#endif static uint8_t CurPad = 0, CurByte = 0, CurCmd = 0, CmdLen = 0; @@ -287,16 +444,34 @@ unsigned char PADpoll(unsigned char value) { if (CurByte == g.PadState[CurPad].Vib0) { g.PadState[CurPad].VibF[0] = value; - if (gpuVisualVibration != NULL && (g.PadState[CurPad].VibF[0] != 0 || g.PadState[CurPad].VibF[1] != 0)) { - gpuVisualVibration(g.PadState[CurPad].VibF[0], g.PadState[CurPad].VibF[1]); + if (g.PadState[CurPad].VibF[0] != 0 || g.PadState[CurPad].VibF[1] != 0) { +#if !SDL_VERSION_ATLEAST(1,3,0) && defined(__linux__) + if (g.PadState[CurPad].VibrateDev == -1 && + g.PadState[CurPad].JoyDev != NULL) { + linux_set_vibrate(CurPad); + } + if (!linux_vibrate(&g.PadState[CurPad])) + /* only do visual if joy fails */ +#endif + if (!JoyHapticRumble(CurPad, g.PadState[CurPad].VibF[0], g.PadState[CurPad].VibF[1]) && gpuVisualVibration != NULL) + gpuVisualVibration(g.PadState[CurPad].VibF[0], g.PadState[CurPad].VibF[1]); } } if (CurByte == g.PadState[CurPad].Vib1) { g.PadState[CurPad].VibF[1] = value; - if (gpuVisualVibration != NULL && (g.PadState[CurPad].VibF[0] != 0 || g.PadState[CurPad].VibF[1] != 0)) { - gpuVisualVibration(g.PadState[CurPad].VibF[0], g.PadState[CurPad].VibF[1]); + if (g.PadState[CurPad].VibF[0] != 0 || g.PadState[CurPad].VibF[1] != 0) { +#if !SDL_VERSION_ATLEAST(1,3,0) && defined(__linux__) + if (g.PadState[CurPad].VibrateDev == -1 && + g.PadState[CurPad].JoyDev != NULL) { + linux_set_vibrate(CurPad); + } + if (!linux_vibrate(&g.PadState[CurPad])) + /* only do visual if joy fails */ +#endif + if (!JoyHapticRumble(CurPad, g.PadState[CurPad].VibF[0], g.PadState[CurPad].VibF[1]) && gpuVisualVibration != NULL) + gpuVisualVibration(g.PadState[CurPad].VibF[0], g.PadState[CurPad].VibF[1]); } } } diff --git a/plugins/dfinput/pad.h b/plugins/dfinput/pad.h index 7c1b0e64..1ad35a43 100644 --- a/plugins/dfinput/pad.h +++ b/plugins/dfinput/pad.h @@ -36,6 +36,9 @@ extern "C" { #include #include +#if SDL_VERSION_ATLEAST(1,3,0) +#include +#endif #ifdef _MACOSX #include @@ -59,6 +62,11 @@ typedef void *Display; #define _(x) (x) #define N_(x) (x) #endif + +#if SDL_VERSION_ATLEAST(1,3,0) +int has_haptic; +#endif +int JoyHapticRumble(int pad, uint32_t low, uint32_t high); enum { DKEY_SELECT = 0, @@ -128,6 +136,16 @@ typedef struct tagPadState { volatile uint8_t AnalogKeyStatus[ANALOG_TOTAL][4]; uint8_t Vib0, Vib1; volatile uint8_t VibF[2]; +#if SDL_VERSION_ATLEAST(1,3,0) + SDL_Haptic *haptic; +#else +#ifdef __linux__ + int VibrateDev; + int VibrateEffect; + uint8_t VibrLow, VibrHigh; + uint32_t VibrSetTime; +#endif +#endif } PADSTATE; typedef struct tagGlobalData { diff --git a/plugins/dfinput/sdljoy.c b/plugins/dfinput/sdljoy.c index 750f26bb..a8bd9ce8 100644 --- a/plugins/dfinput/sdljoy.c +++ b/plugins/dfinput/sdljoy.c @@ -18,6 +18,70 @@ #include "pad.h" +#if SDL_VERSION_ATLEAST(1,3,0) +static SDL_HapticEffect haptic_rumbleEffect; +#endif + +void JoyInitHaptic() +{ +#if SDL_VERSION_ATLEAST(1,3,0) + uint8_t i; + unsigned int haptic_query = 0; + for (i = 0; i < 2; i++) + { + if (g.PadState[i].JoyDev && SDL_JoystickIsHaptic(g.PadState[i].JoyDev)) + { + if (g.PadState[i].haptic != NULL) + { + SDL_HapticClose(g.PadState[i].haptic); + g.PadState[i].haptic = NULL; + } + + g.PadState[i].haptic = SDL_HapticOpenFromJoystick(g.PadState[i].JoyDev); + if (g.PadState[i].haptic == NULL) + continue; + + if (SDL_HapticRumbleSupported(g.PadState[i].haptic) == SDL_FALSE) + { + printf("\nRumble not supported\n"); + g.PadState[i].haptic = NULL; + continue; + } + + if (SDL_HapticRumbleInit(g.PadState[i].haptic) != 0) + { + printf("\nFailed to initialize rumble: %s\n", SDL_GetError()); + g.PadState[i].haptic = NULL; + continue; + } + } + } +#endif +} + +int JoyHapticRumble(int pad, uint32_t low, uint32_t high) +{ +#if SDL_VERSION_ATLEAST(1,3,0) + float mag; + + if (g.PadState[pad].haptic) { + + /* Stop the effect if it was playing. */ + SDL_HapticRumbleStop(g.PadState[pad].haptic); + + mag = ((high * 2 + low) / 6) / 127.5; + //printf("low: %d high: %d mag: %f\n", low, high, mag); + + if(SDL_HapticRumblePlay(g.PadState[pad].haptic, mag, 500) != 0) + { + printf("\nFailed to play rumble: %s\n", SDL_GetError()); + return 1; + } + } +#endif + return 0; +} + void InitSDLJoy() { uint8_t i; @@ -30,8 +94,19 @@ void InitSDLJoy() { } else { g.PadState[i].JoyDev = NULL; } +#if !SDL_VERSION_ATLEAST(1,3,0) && defined(__linux__) + g.PadState[i].VibrateDev = -1; + g.PadState[i].VibrateEffect = -1; +#endif } +#if SDL_VERSION_ATLEAST(1,3,0) + if (has_haptic) + { + JoyInitHaptic(); + } +#endif + SDL_JoystickEventState(SDL_IGNORE); InitAnalog(); @@ -43,6 +118,13 @@ void DestroySDLJoy() { if (SDL_WasInit(SDL_INIT_JOYSTICK)) { for (i = 0; i < 2; i++) { if (g.PadState[i].JoyDev != NULL) { +#if SDL_VERSION_ATLEAST(1,3,0) + if (g.PadState[i].haptic != NULL) + { + SDL_HapticClose(g.PadState[i].haptic); + g.PadState[i].haptic = NULL; + } +#endif SDL_JoystickClose(g.PadState[i].JoyDev); } } -- cgit v1.2.3