1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-12-01 15:35:47 +00:00
Aquaria/BBGE/Joystick.cpp
2016-05-05 19:57:50 +02:00

417 lines
9.9 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"
#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_SDL2
sdl_controller = NULL;
sdl_haptic = NULL;
# endif
sdl_joy = NULL;
#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)
{
std::ostringstream os;
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");
}
#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
}
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_SDL2
if (sdl_haptic)
{
SDL_HapticClose(sdl_haptic);
sdl_haptic = 0;
}
if (sdl_controller)
{
SDL_GameControllerClose(sdl_controller);
sdl_controller = 0;
sdl_joy = 0; // SDL_GameControllerClose() frees this
}
#endif
if (sdl_joy)
{
SDL_JoystickClose(sdl_joy);
sdl_joy = 0;
}
}
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))
{
clearRumbleTime = time;
SDL_HapticRumblePlay(sdl_haptic, power, (Uint32) (time * 1000.0f));
}
else
{
clearRumbleTime = -1;
SDL_HapticRumbleStop(sdl_haptic);
}
}
#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)
{
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)
{
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 = float(xaxis)/32768.0f;
position.y = float(yaxis)/32768.0f;
Sint16 xaxis2 = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_RIGHTX);
Sint16 yaxis2 = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_RIGHTY);
rightStick.x = float(xaxis2)/32768.0f;
rightStick.y = float(yaxis2)/32768.0f;
}
else
{
Sint16 xaxis = SDL_JoystickGetAxis(sdl_joy, s1ax);
Sint16 yaxis = SDL_JoystickGetAxis(sdl_joy, s1ay);
position.x = float(xaxis)/32768.0f;
position.y = float(yaxis)/32768.0f;
Sint16 xaxis2 = SDL_JoystickGetAxis(sdl_joy, s2ax);
Sint16 yaxis2 = SDL_JoystickGetAxis(sdl_joy, s2ay);
rightStick.x = float(xaxis2)/32768.0f;
rightStick.y = float(yaxis2)/32768.0f;
}
#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
callibrate(position, deadZone1);
callibrate(rightStick, deadZone2);
#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
}
if (clearRumbleTime >= 0)
{
clearRumbleTime -= dt;
if (clearRumbleTime <= 0)
{
rumble(0,0,0);
}
}
}
bool Joystick::anyButton()
{
for (int i = 0; i < maxJoyBtns; i++)
{
if (buttons[i]) return true;
}
return false;
}