1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-11-15 22:19:07 +00:00
Aquaria/BBGE/Joystick.cpp
fgenesis 03f99058c3 Apply SDL2 patch by ryan, with some adjustments to apply properly.
The fix as suggested by Jonas Kulla on the mailing list is also in.
There hasn't been any extensive testing, and it may not yet compile
on platforms other than win32.
2013-07-18 23:29:55 +02:00

556 lines
13 KiB
C++

/*
Copyright (C) 2007, 2010 - Bit-Blot
This file is part of Aquaria.
Aquaria is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "Core.h"
#if defined(BBGE_BUILD_WINDOWS) && defined(BBGE_BUILD_XINPUT)
#include "Xinput.h"
#if defined(BBGE_BUILD_DELAYXINPUT)
#include <DelayImp.h>
#endif
/*
HRESULT (WINAPI *XInputGetState)(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter) = 0;
if ( (winp.hInstDI = LoadLibrary( "dinput.dll" )) == 0 )
if (!pDirectInput8Create) {
pDirectInput8Create = (HRESULT (__stdcall *)(HINSTANCE, DWORD ,REFIID, LPVOID *, LPUNKNOWN)) GetProcAddress(winp.hInstDI,"DirectInput8Create");
if (!pDirectInput8Create) {
error(L"Couldn't get DI proc addr\n");
}
}
bool importXInput()
{
}
*/
bool tryXInput()
{
__try
{
XINPUT_STATE xinp;
XInputGetState(0, &xinp);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return false;
}
return true;
}
#endif
#ifdef __LINUX__
#include <sys/types.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <errno.h>
#include <iostream>
#define BITS_TO_LONGS(x) \
(((x) + 8 * sizeof (unsigned long) - 1) / (8 * sizeof (unsigned long)))
#define AQUARIA_BITS_PER_LONG (sizeof(long) * 8)
#define AQUARIA_OFF(x) ((x)%AQUARIA_BITS_PER_LONG)
#define AQUARIA_BIT(x) (1UL<<AQUARIA_OFF(x))
#define AQUARIA_LONG(x) ((x)/AQUARIA_BITS_PER_LONG)
#define test_bit(bit, array) ((array[AQUARIA_LONG(bit)] >> AQUARIA_OFF(bit)) & 1)
#endif
Joystick::Joystick()
{
xinited = false;
stickIndex = -1;
#ifdef BBGE_BUILD_SDL
# ifdef BBGE_BUILD_SDL2
sdl_controller = NULL;
sdl_haptic = NULL;
# endif
sdl_joy = NULL;
#endif
#if defined(__LINUX__) && !defined(BBGE_BUILD_SDL2)
eventfd = -1;
effectid = -1;
#endif
inited = false;
for (int i = 0; i < maxJoyBtns; i++)
{
buttons[i] = UP;
}
deadZone1 = 0.3;
deadZone2 = 0.3;
clearRumbleTime= 0;
leftThumb = rightThumb = false;
leftTrigger = rightTrigger = 0;
rightShoulder = leftShoulder = false;
dpadRight = dpadLeft = dpadUp = dpadDown = false;
btnStart = false;
btnSelect = false;
s1ax = 0;
s1ay = 1;
s2ax = 4;
s2ay = 3;
}
void Joystick::init(int stick)
{
#if defined(BBGE_BUILD_SDL) || defined(__LINUX__)
std::ostringstream os;
#endif
#ifdef BBGE_BUILD_SDL
stickIndex = stick;
const int numJoy = SDL_NumJoysticks();
os << "Found [" << numJoy << "] joysticks";
debugLog(os.str());
if (numJoy > stick)
{
#ifdef BBGE_BUILD_SDL2
if (SDL_IsGameController(stick))
{
sdl_controller = SDL_GameControllerOpen(stick);
if (sdl_controller)
sdl_joy = SDL_GameControllerGetJoystick(sdl_controller);
}
if (!sdl_joy)
sdl_joy = SDL_JoystickOpen(stick);
if (sdl_joy && SDL_JoystickIsHaptic(sdl_joy))
{
sdl_haptic = SDL_HapticOpenFromJoystick(sdl_joy);
bool rumbleok = false;
if (sdl_haptic && SDL_HapticRumbleSupported(sdl_haptic))
rumbleok = (SDL_HapticRumbleInit(sdl_haptic) == 0);
if (!rumbleok)
{
SDL_HapticClose(sdl_haptic);
sdl_haptic = NULL;
}
}
#endif
if (!sdl_joy)
sdl_joy = SDL_JoystickOpen(stick);
if (sdl_joy)
{
inited = true;
#ifdef BBGE_BUILD_SDL2
debugLog(std::string("Initialized Joystick [") + std::string(SDL_JoystickName(sdl_joy)) + std::string("]"));
if (sdl_controller) debugLog(std::string("Joystick is a Game Controller"));
if (sdl_haptic) debugLog(std::string("Joystick has force feedback support"));
#else
debugLog(std::string("Initialized Joystick [") + std::string(SDL_JoystickName(stick)) + std::string("]"));
#endif
}
else
{
std::ostringstream os;
os << "Failed to init Joystick [" << stick << "]";
debugLog(os.str());
}
}
else
{
debugLog("Not enough Joystick(s) found");
}
#endif
#if defined(__LINUX__) && !defined(BBGE_BUILD_SDL2)
os.seekp(0);
os << "AQUARIA_EVENT_JOYSTICK" << stick;
std::string envkey = os.str();
const char* evdevice = getenv(envkey.c_str());
if (evdevice != NULL) {
eventfd = open(evdevice, O_RDWR, 0);
if (eventfd < 0) {
debugLog(std::string("Could not open rumble device [") + evdevice + "]: " + strerror(errno));
}
else {
debugLog(std::string("Successfully opened rumble device [") + evdevice + "]");
unsigned long features[BITS_TO_LONGS(FF_CNT)];
if (ioctl(eventfd, EVIOCGBIT(EV_FF, sizeof(features)), features) == -1) {
debugLog(std::string("Cannot query joystick/gamepad features: ") + strerror(errno));
close(eventfd);
eventfd = -1;
}
else if (!test_bit(FF_RUMBLE, features)) {
debugLog("Rumble is not supported by your gamepad/joystick.");
close(eventfd);
eventfd = -1;
}
}
}
else {
std::cout <<
"Environment varialbe " << envkey << " is not set.\n"
"Set this environment variable to the device file that shall be used for joystick number " << stick << " in order to enable rumble support.\n"
"Example:\n"
"\texport " << envkey << "=/dev/input/event6\n\n";
}
#endif
#ifdef BBGE_BUILD_XINPUT
debugLog("about to init xinput");
xinited = tryXInput();
if (!xinited)
debugLog("XInput not found, not installed?");
debugLog("after catch");
#if !defined(BBGE_BUILD_SDL)
inited = xinited;
#endif
#endif
}
void Joystick::shutdown()
{
#if defined(__LINUX__) && !defined(BBGE_BUILD_SDL2)
if (eventfd >= 0) {
if (effectid != -1 && ioctl(eventfd, EVIOCRMFF, effectid) == -1) {
debugLog(std::string("Remove rumble effect: ") + strerror(errno));
}
close(eventfd);
eventfd = -1;
}
#endif
#ifdef BBGE_BUILD_SDL
if (sdl_joy)
{
SDL_JoystickClose(sdl_joy);
sdl_joy = 0;
}
#endif
}
void Joystick::rumble(float leftMotor, float rightMotor, float time)
{
if (core->joystickEnabled && inited)
{
#ifdef BBGE_BUILD_SDL2
if (sdl_haptic)
{
const float power = (leftMotor + rightMotor) / 2.0f;
if ((power > 0.0f) && (time > 0.0f))
SDL_HapticRumblePlay(sdl_haptic, power, (Uint32) (time * 1000.0f));
else
SDL_HapticRumbleStop(sdl_haptic);
}
#elif defined(BBGE_BUILD_WINDOWS) && defined(BBGE_BUILD_XINPUT)
XINPUT_VIBRATION vib;
vib.wLeftMotorSpeed = WORD(leftMotor*65535);
vib.wRightMotorSpeed = WORD(rightMotor*65535);
clearRumbleTime = time;
DWORD d = XInputSetState(0, &vib);
if (d == ERROR_SUCCESS)
{
//debugLog("success");
}
else if (d == ERROR_DEVICE_NOT_CONNECTED)
{
//debugLog("joystick not connected");
}
else
{
//unknown error
}
#elif defined(__LINUX__)
if (eventfd >= 0) {
struct ff_effect effect;
struct input_event event;
effect.type = FF_RUMBLE;
effect.id = effectid;
effect.direction = 0;
effect.trigger.button = 0;
effect.trigger.interval = 0;
effect.replay.length = (uint16_t) (time * 1000);
effect.replay.delay = 0;
if (leftMotor > rightMotor) {
effect.u.rumble.strong_magnitude = (uint16_t) (leftMotor * 0xffff);
effect.u.rumble.weak_magnitude = (uint16_t) (rightMotor * 0xffff);
}
else {
effect.u.rumble.strong_magnitude = (uint16_t) (rightMotor * 0xffff);
effect.u.rumble.weak_magnitude = (uint16_t) (leftMotor * 0xffff);
}
if (ioctl(eventfd, EVIOCSFF, &effect) == -1) {
debugLog(std::string("Upload rumble effect: ") + strerror(errno));
return;
}
event.time.tv_sec = 0;
event.time.tv_usec = 0;
event.type = EV_FF;
event.code = effectid = effect.id;
if (leftMotor == 0 && rightMotor == 0) {
event.value = 0;
}
else {
event.value = 1;
}
if (write(eventfd, (const void*) &event, sizeof(event)) == -1) {
debugLog(std::string("Play rumble effect: ") + strerror(errno));
}
}
#endif
}
}
void Joystick::callibrate(Vector &calvec, float deadZone)
{
//float len = position.getLength2D();
if (calvec.isLength2DIn(deadZone))
{
calvec = Vector(0,0,0);
}
else
{
if (!calvec.isZero())
{
Vector pos2 = calvec;
pos2.setLength2D(deadZone);
calvec -= pos2;
float mult = 1.0f/float(1.0f-deadZone);
calvec.x *= mult;
calvec.y *= mult;
if (calvec.x > 1)
calvec.x = 1;
else if (calvec.x < -1)
calvec.x = -1;
if (calvec.y > 1)
calvec.y = 1;
else if (calvec.y < -1)
calvec.y = -1;
}
}
}
void Joystick::update(float dt)
{
#ifdef BBGE_BUILD_SDL
if (core->joystickEnabled && inited && sdl_joy && stickIndex != -1)
{
#ifdef BBGE_BUILD_SDL2
if (!SDL_JoystickGetAttached(sdl_joy))
{
debugLog("Lost Joystick");
if (sdl_haptic) { SDL_HapticClose(sdl_haptic); sdl_haptic = NULL; }
if (!sdl_controller)
SDL_JoystickClose(sdl_joy);
else
{
SDL_GameControllerClose(sdl_controller);
sdl_controller = NULL;
}
sdl_joy = NULL;
return;
}
if (sdl_controller)
{
Sint16 xaxis = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_LEFTX);
Sint16 yaxis = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_LEFTY);
position.x = double(xaxis)/32768.0;
position.y = double(yaxis)/32768.0;
Sint16 xaxis2 = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_RIGHTX);
Sint16 yaxis2 = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_RIGHTY);
rightStick.x = double(xaxis2)/32768.0;
rightStick.y = double(yaxis2)/32768.0;
}
else
{
Sint16 xaxis = SDL_JoystickGetAxis(sdl_joy, s1ax);
Sint16 yaxis = SDL_JoystickGetAxis(sdl_joy, s1ay);
position.x = double(xaxis)/32768.0;
position.y = double(yaxis)/32768.0;
Sint16 xaxis2 = SDL_JoystickGetAxis(sdl_joy, s2ax);
Sint16 yaxis2 = SDL_JoystickGetAxis(sdl_joy, s2ay);
rightStick.x = double(xaxis2)/32768.0;
rightStick.y = double(yaxis2)/32768.0;
}
#else
if (!SDL_JoystickOpened(stickIndex))
{
debugLog("Lost Joystick");
sdl_joy = NULL;
return;
}
Sint16 xaxis = SDL_JoystickGetAxis(sdl_joy, s1ax);
Sint16 yaxis = SDL_JoystickGetAxis(sdl_joy, s1ay);
position.x = xaxis/32768.0f;
position.y = yaxis/32768.0f;
Sint16 xaxis2 = SDL_JoystickGetAxis(sdl_joy, s2ax);
Sint16 yaxis2 = SDL_JoystickGetAxis(sdl_joy, s2ay);
rightStick.x = xaxis2/32768.0f;
rightStick.y = yaxis2/32768.0f;
#endif
/*
std::ostringstream os;
os << "joy(" << position.x << ", " << position.y << ")";
debugLog(os.str());
*/
callibrate(position, deadZone1);
callibrate(rightStick, deadZone2);
/*
std::ostringstream os2;
os2 << "joy2(" << position.x << ", " << position.y << ")";
debugLog(os2.str());
*/
#ifdef BBGE_BUILD_SDL2
if (sdl_controller)
{
for (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++)
buttons[i] = SDL_GameControllerGetButton(sdl_controller, (SDL_GameControllerButton)i)?DOWN:UP;
for (int i = SDL_CONTROLLER_BUTTON_MAX; i < maxJoyBtns; i++)
buttons[i] = UP;
}
else
{
for (int i = 0; i < maxJoyBtns; i++)
buttons[i] = SDL_JoystickGetButton(sdl_joy, i)?DOWN:UP;
}
#else
for (int i = 0; i < maxJoyBtns; i++)
buttons[i] = SDL_JoystickGetButton(sdl_joy, i)?DOWN:UP;
#endif
/*
unsigned char btns[maxJoyBtns];
glfwGetJoystickButtons(GLFW_JOYSTICK_1, btns, maxJoyBtns);
for (int i = 0; i < maxJoyBtns; i++)
{
if (btns[i] == GLFW_PRESS)
buttons[i] = DOWN;
else
buttons[i] = UP;
}
*/
}
#endif
if (clearRumbleTime > 0)
{
clearRumbleTime -= dt;
if (clearRumbleTime < 0)
{
rumble(0,0,0);
}
}
#if defined(BBGE_BUILD_WINDOWS) && defined(BBGE_BUILD_XINPUT)
if (inited && xinited)
{
XINPUT_STATE xinp;
XInputGetState(0, &xinp);
leftTrigger = float(xinp.Gamepad.bLeftTrigger)/255.0f;
rightTrigger = float(xinp.Gamepad.bRightTrigger)/255.0f;
leftShoulder = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER;
rightShoulder = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER;
leftThumb = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB;
rightThumb = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB;
dpadUp = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP;
dpadDown = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN;
dpadLeft = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT;
dpadRight = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT;
#if !defined(BBGE_BUILD_SDL)
buttons[0] = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_A?DOWN:UP;
buttons[1] = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_B?DOWN:UP;
buttons[2] = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_X?DOWN:UP;
buttons[3] = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_Y?DOWN:UP;
position = Vector(xinp.Gamepad.sThumbLX, xinp.Gamepad.sThumbLY)/32768.0f;
position.y = -rightStick.y;
rightStick = Vector(xinp.Gamepad.sThumbRX, xinp.Gamepad.sThumbRY)/32768.0f;
rightStick.y = -rightStick.y;
callibrate(position, deadZone1);
callibrate(rightStick, deadZone2);
#endif
btnStart = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_START;
btnSelect = xinp.Gamepad.wButtons & XINPUT_GAMEPAD_BACK;
}
#endif
/*
std::ostringstream os;
os << "j-pos(" << position.x << ", " << position.y << " - b0[" << buttons[0] << "]) - len[" << len << "]";
debugLog(os.str());
*/
}
bool Joystick::anyButton()
{
for (int i = 0; i < maxJoyBtns; i++)
{
if (buttons[i]) return true;
}
return false;
}