2013-11-05 12:49:23 +00:00
|
|
|
#include "SDL/SDLJoystick.h"
|
2016-09-03 05:15:25 +00:00
|
|
|
#include "Core/Config.h"
|
2016-09-20 20:50:45 +00:00
|
|
|
#include "Common/FileUtil.h"
|
2017-03-21 14:54:19 +00:00
|
|
|
#include "file/vfs.h"
|
2013-11-05 12:49:23 +00:00
|
|
|
|
|
|
|
#include <iostream>
|
2016-09-20 20:50:45 +00:00
|
|
|
#include <string>
|
|
|
|
|
|
|
|
using namespace std;
|
2013-11-05 12:49:23 +00:00
|
|
|
|
2017-02-01 06:19:18 +00:00
|
|
|
static int SDLJoystickEventHandlerWrapper(void* userdata, SDL_Event* event)
|
|
|
|
{
|
|
|
|
static_cast<SDLJoystick *>(userdata)->ProcessInput(*event);
|
|
|
|
return 0;
|
2013-11-05 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
2017-02-01 06:19:18 +00:00
|
|
|
SDLJoystick::SDLJoystick(bool init_SDL ) : registeredAsEventHandler(false) {
|
2017-02-22 21:18:21 +00:00
|
|
|
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
2016-09-19 23:28:28 +00:00
|
|
|
if (init_SDL) {
|
2016-09-17 23:33:28 +00:00
|
|
|
SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER);
|
|
|
|
}
|
2017-03-21 14:54:19 +00:00
|
|
|
|
|
|
|
const char *dbPath = "gamecontrollerdb.txt";
|
2016-09-20 20:50:45 +00:00
|
|
|
cout << "loading control pad mappings from " << dbPath << ": ";
|
2017-01-30 20:26:24 +00:00
|
|
|
|
2017-03-21 14:54:19 +00:00
|
|
|
size_t size;
|
|
|
|
u8 *mappingData = VFSReadFile(dbPath, &size);
|
|
|
|
if (mappingData) {
|
|
|
|
SDL_RWops *rw = SDL_RWFromConstMem(mappingData, size);
|
|
|
|
// 1 to free the rw after use
|
|
|
|
if (SDL_GameControllerAddMappingsFromRW(rw, 1) == -1) {
|
|
|
|
cout << "Failed to read mapping data - corrupt?" << endl;
|
|
|
|
}
|
|
|
|
delete[] mappingData;
|
|
|
|
} else {
|
|
|
|
cout << "gamecontrollerdb.txt missing" << endl;
|
2013-11-05 12:49:23 +00:00
|
|
|
}
|
2017-01-30 20:26:24 +00:00
|
|
|
cout << "SUCCESS!" << endl;
|
|
|
|
setUpControllers();
|
2016-09-18 22:23:36 +00:00
|
|
|
}
|
2013-11-05 12:49:23 +00:00
|
|
|
|
2016-09-19 23:28:28 +00:00
|
|
|
void SDLJoystick::setUpControllers() {
|
2013-11-05 12:49:23 +00:00
|
|
|
int numjoys = SDL_NumJoysticks();
|
2014-05-30 21:50:03 +00:00
|
|
|
for (int i = 0; i < numjoys; i++) {
|
2016-09-19 23:28:28 +00:00
|
|
|
setUpController(i);
|
2016-09-18 22:23:36 +00:00
|
|
|
}
|
2016-09-19 23:28:28 +00:00
|
|
|
if (controllers.size() > 0) {
|
2016-09-20 20:50:45 +00:00
|
|
|
cout << "pad 1 has been assigned to control pad: " << SDL_GameControllerName(controllers.front()) << endl;
|
2016-09-19 23:28:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SDLJoystick::setUpController(int deviceIndex) {
|
|
|
|
if (SDL_IsGameController(deviceIndex)) {
|
|
|
|
SDL_GameController *controller = SDL_GameControllerOpen(deviceIndex);
|
|
|
|
if (controller) {
|
|
|
|
if (SDL_GameControllerGetAttached(controller)) {
|
|
|
|
controllers.push_back(controller);
|
|
|
|
controllerDeviceMap[SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))] = deviceIndex;
|
2016-09-20 20:50:45 +00:00
|
|
|
cout << "found control pad: " << SDL_GameControllerName(controller) << ", loading mapping: ";
|
|
|
|
auto mapping = SDL_GameControllerMapping(controller);
|
2016-09-19 23:28:28 +00:00
|
|
|
if (mapping == NULL) {
|
2016-09-20 20:50:45 +00:00
|
|
|
cout << "FAILED" << endl;
|
2016-09-19 23:28:28 +00:00
|
|
|
} else {
|
2016-09-20 20:50:45 +00:00
|
|
|
cout << "SUCCESS, mapping is:" << endl << mapping << endl;
|
2016-09-19 23:28:28 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
SDL_GameControllerClose(controller);
|
2016-09-18 22:23:36 +00:00
|
|
|
}
|
|
|
|
}
|
2013-11-05 12:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-19 23:28:28 +00:00
|
|
|
SDLJoystick::~SDLJoystick() {
|
2017-02-01 06:19:18 +00:00
|
|
|
if (registeredAsEventHandler) {
|
|
|
|
SDL_DelEventWatch(SDLJoystickEventHandlerWrapper, this);
|
2013-11-05 12:49:23 +00:00
|
|
|
}
|
2016-09-20 20:50:45 +00:00
|
|
|
for (auto & controller : controllers) {
|
2016-09-19 23:28:28 +00:00
|
|
|
SDL_GameControllerClose(controller);
|
|
|
|
}
|
2013-11-05 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
2017-02-01 06:19:18 +00:00
|
|
|
void SDLJoystick::registerEventHandler() {
|
|
|
|
SDL_AddEventWatch(SDLJoystickEventHandlerWrapper, this);
|
|
|
|
registeredAsEventHandler = true;
|
2013-11-05 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
2016-09-19 23:28:28 +00:00
|
|
|
keycode_t SDLJoystick::getKeycodeForButton(SDL_GameControllerButton button) {
|
|
|
|
switch (button) {
|
|
|
|
case SDL_CONTROLLER_BUTTON_DPAD_UP:
|
|
|
|
return NKCODE_DPAD_UP;
|
|
|
|
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
|
|
|
|
return NKCODE_DPAD_DOWN;
|
|
|
|
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
|
|
|
|
return NKCODE_DPAD_LEFT;
|
|
|
|
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
|
|
|
|
return NKCODE_DPAD_RIGHT;
|
|
|
|
case SDL_CONTROLLER_BUTTON_A:
|
|
|
|
return NKCODE_BUTTON_2;
|
|
|
|
case SDL_CONTROLLER_BUTTON_B:
|
|
|
|
return NKCODE_BUTTON_3;
|
|
|
|
case SDL_CONTROLLER_BUTTON_X:
|
|
|
|
return NKCODE_BUTTON_4;
|
|
|
|
case SDL_CONTROLLER_BUTTON_Y:
|
|
|
|
return NKCODE_BUTTON_1;
|
|
|
|
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
|
|
|
|
return NKCODE_BUTTON_5;
|
|
|
|
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
|
|
|
|
return NKCODE_BUTTON_6;
|
|
|
|
case SDL_CONTROLLER_BUTTON_START:
|
|
|
|
return NKCODE_BUTTON_10;
|
|
|
|
case SDL_CONTROLLER_BUTTON_BACK:
|
|
|
|
return NKCODE_BUTTON_9; // select button
|
|
|
|
case SDL_CONTROLLER_BUTTON_GUIDE:
|
|
|
|
return NKCODE_BACK; // pause menu
|
2016-11-20 17:50:06 +00:00
|
|
|
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
|
|
|
|
return NKCODE_BUTTON_THUMBL;
|
|
|
|
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
|
|
|
|
return NKCODE_BUTTON_THUMBR;
|
2017-03-21 14:54:19 +00:00
|
|
|
case SDL_CONTROLLER_BUTTON_INVALID:
|
|
|
|
default:
|
|
|
|
return NKCODE_UNKNOWN;
|
2016-09-18 22:23:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-05 12:49:23 +00:00
|
|
|
void SDLJoystick::ProcessInput(SDL_Event &event){
|
|
|
|
switch (event.type) {
|
2016-09-19 23:28:28 +00:00
|
|
|
case SDL_CONTROLLERBUTTONDOWN:
|
|
|
|
if (event.cbutton.state == SDL_PRESSED) {
|
2016-09-20 20:50:45 +00:00
|
|
|
auto code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button);
|
2016-09-19 23:28:28 +00:00
|
|
|
if (code != NKCODE_UNKNOWN) {
|
|
|
|
KeyInput key;
|
|
|
|
key.flags = KEY_DOWN;
|
|
|
|
key.keyCode = code;
|
|
|
|
key.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.cbutton.which);
|
|
|
|
NativeKey(key);
|
2014-03-28 16:16:44 +00:00
|
|
|
}
|
2013-11-05 12:49:23 +00:00
|
|
|
}
|
2016-09-19 23:28:28 +00:00
|
|
|
break;
|
|
|
|
case SDL_CONTROLLERBUTTONUP:
|
|
|
|
if (event.cbutton.state == SDL_RELEASED) {
|
2016-09-20 20:50:45 +00:00
|
|
|
auto code = getKeycodeForButton((SDL_GameControllerButton)event.cbutton.button);
|
2016-09-19 23:28:28 +00:00
|
|
|
if (code != NKCODE_UNKNOWN) {
|
|
|
|
KeyInput key;
|
|
|
|
key.flags = KEY_UP;
|
|
|
|
key.keyCode = code;
|
|
|
|
key.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.cbutton.which);
|
|
|
|
NativeKey(key);
|
2014-03-28 16:16:44 +00:00
|
|
|
}
|
2013-11-05 12:49:23 +00:00
|
|
|
}
|
2016-09-19 23:28:28 +00:00
|
|
|
break;
|
|
|
|
case SDL_CONTROLLERAXISMOTION:
|
|
|
|
AxisInput axis;
|
|
|
|
axis.axisId = event.caxis.axis;
|
|
|
|
// 1.2 to try to approximate the PSP's clamped rectangular range.
|
|
|
|
axis.value = 1.2 * event.caxis.value / 32767.0f;
|
|
|
|
if (axis.value > 1.0f) axis.value = 1.0f;
|
|
|
|
if (axis.value < -1.0f) axis.value = -1.0f;
|
|
|
|
axis.deviceId = DEVICE_ID_PAD_0 + getDeviceIndex(event.caxis.which);
|
|
|
|
axis.flags = 0;
|
|
|
|
NativeAxis(axis);
|
|
|
|
break;
|
|
|
|
case SDL_CONTROLLERDEVICEREMOVED:
|
2016-09-20 20:50:45 +00:00
|
|
|
// for removal events, "which" is the instance ID for SDL_CONTROLLERDEVICEREMOVED
|
|
|
|
for (auto it = controllers.begin(); it != controllers.end(); ++it) {
|
|
|
|
if (SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(*it)) == event.cdevice.which) {
|
|
|
|
SDL_GameControllerClose(*it);
|
|
|
|
controllers.erase(it);
|
2015-06-23 14:13:23 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-11-05 12:49:23 +00:00
|
|
|
}
|
2016-09-19 23:28:28 +00:00
|
|
|
break;
|
|
|
|
case SDL_CONTROLLERDEVICEADDED:
|
|
|
|
// for add events, "which" is the device index!
|
|
|
|
int prevNumControllers = controllers.size();
|
|
|
|
setUpController(event.cdevice.which);
|
|
|
|
if (prevNumControllers == 0 && controllers.size() > 0) {
|
2016-09-20 20:50:45 +00:00
|
|
|
cout << "pad 1 has been assigned to control pad: " << SDL_GameControllerName(controllers.front()) << endl;
|
2015-06-23 14:13:23 +00:00
|
|
|
}
|
2016-09-19 23:28:28 +00:00
|
|
|
break;
|
2015-06-23 14:13:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-28 07:44:48 +00:00
|
|
|
int SDLJoystick::getDeviceIndex(int instanceId) {
|
2016-09-20 20:50:45 +00:00
|
|
|
auto it = controllerDeviceMap.find(instanceId);
|
2016-09-19 23:28:28 +00:00
|
|
|
if (it == controllerDeviceMap.end()) {
|
|
|
|
// could not find device
|
|
|
|
return -1;
|
2013-11-05 12:49:23 +00:00
|
|
|
}
|
2016-09-19 23:28:28 +00:00
|
|
|
return it->second;
|
2013-11-05 12:49:23 +00:00
|
|
|
}
|