2012-07-20 01:08:29 +00:00
|
|
|
#include "InputManager.h"
|
2013-04-08 14:41:25 +00:00
|
|
|
#include "InputConfig.h"
|
|
|
|
#include "Window.h"
|
2013-04-11 22:27:27 +00:00
|
|
|
#include "Log.h"
|
|
|
|
#include "pugiXML/pugixml.hpp"
|
|
|
|
#include <boost/filesystem.hpp>
|
2013-05-13 19:53:28 +00:00
|
|
|
#include "platform.h"
|
2013-04-11 22:27:27 +00:00
|
|
|
|
2013-05-24 11:44:40 +00:00
|
|
|
#if defined(WIN32) || defined(_WIN32)
|
|
|
|
#include <Windows.h>
|
|
|
|
#endif
|
|
|
|
|
2013-04-11 22:27:27 +00:00
|
|
|
namespace fs = boost::filesystem;
|
2012-12-20 18:29:05 +00:00
|
|
|
|
2013-05-24 11:44:40 +00:00
|
|
|
//----- InputDevice ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
InputDevice::InputDevice(const std::string & deviceName, unsigned long vendorId, unsigned long productId)
|
|
|
|
: name(deviceName), vendor(vendorId), product(productId)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InputDevice::operator==(const InputDevice & b) const
|
|
|
|
{
|
|
|
|
return (name == b.name && vendor == b.vendor && product == b.product);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----- InputManager ---------------------------------------------------------------------------
|
|
|
|
|
2013-05-14 19:45:56 +00:00
|
|
|
InputManager::InputManager(Window* window) : mWindow(window),
|
|
|
|
mJoysticks(NULL), mInputConfigs(NULL), mKeyboardInputConfig(NULL), mPrevAxisValues(NULL),
|
2013-06-30 01:37:18 +00:00
|
|
|
mNumJoysticks(0), mNumPlayers(0), devicePollingTimer(NULL)
|
2012-07-20 01:08:29 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
InputManager::~InputManager()
|
2012-07-20 01:08:29 +00:00
|
|
|
{
|
2013-04-08 14:41:25 +00:00
|
|
|
deinit();
|
2012-07-20 01:08:29 +00:00
|
|
|
}
|
|
|
|
|
2013-05-24 11:44:40 +00:00
|
|
|
std::vector<InputDevice> InputManager::getInputDevices() const
|
|
|
|
{
|
|
|
|
std::vector<InputDevice> currentDevices;
|
|
|
|
|
|
|
|
//retrieve all input devices from system
|
|
|
|
#if defined (__APPLE__)
|
|
|
|
#error TODO: Not implemented for MacOS yet!!!
|
|
|
|
#elif defined(__linux__)
|
|
|
|
//open linux input devices file system
|
|
|
|
const std::string inputPath("/dev/input");
|
|
|
|
fs::directory_iterator dirIt(inputPath);
|
|
|
|
while (dirIt != fs::directory_iterator()) {
|
|
|
|
//get directory entry
|
|
|
|
std::string deviceName = (*dirIt).path().string();
|
|
|
|
//remove parent path
|
|
|
|
deviceName.erase(0, inputPath.length() + 1);
|
|
|
|
//check if it start with "js"
|
|
|
|
if (deviceName.length() >= 3 && deviceName.find("js") == 0) {
|
|
|
|
//looks like a joystick. add to devices.
|
|
|
|
currentDevices.push_back(InputDevice(deviceName, 0, 0));
|
|
|
|
}
|
2013-06-27 08:26:56 +00:00
|
|
|
++dirIt;
|
2013-05-24 11:44:40 +00:00
|
|
|
}
|
|
|
|
//or dump /proc/bus/input/devices anbd search for a Handler=..."js"... entry
|
|
|
|
#elif defined(WIN32) || defined(_WIN32)
|
|
|
|
RAWINPUTDEVICELIST * deviceList = nullptr;
|
|
|
|
UINT nrOfDevices = 0;
|
|
|
|
//get number of input devices
|
|
|
|
if (GetRawInputDeviceList(deviceList, &nrOfDevices, sizeof(RAWINPUTDEVICELIST)) != -1 && nrOfDevices > 0)
|
|
|
|
{
|
|
|
|
//get list of input devices
|
|
|
|
deviceList = new RAWINPUTDEVICELIST[nrOfDevices];
|
|
|
|
if (GetRawInputDeviceList(deviceList, &nrOfDevices, sizeof(RAWINPUTDEVICELIST)) != -1)
|
|
|
|
{
|
|
|
|
//loop through input devices
|
2013-05-27 17:13:38 +00:00
|
|
|
for (unsigned int i = 0; i < nrOfDevices; i++)
|
2013-05-24 11:44:40 +00:00
|
|
|
{
|
|
|
|
//get device name
|
|
|
|
char * rawName = new char[2048];
|
|
|
|
UINT rawNameSize = 2047;
|
|
|
|
GetRawInputDeviceInfo(deviceList[i].hDevice, RIDI_DEVICENAME, (void *)rawName, &rawNameSize);
|
|
|
|
//null-terminate string
|
|
|
|
rawName[rawNameSize] = '\0';
|
|
|
|
//convert to string
|
|
|
|
std::string deviceName = rawName;
|
|
|
|
delete [] rawName;
|
|
|
|
//get deviceType
|
|
|
|
RID_DEVICE_INFO deviceInfo;
|
|
|
|
UINT deviceInfoSize = sizeof(RID_DEVICE_INFO);
|
|
|
|
GetRawInputDeviceInfo(deviceList[i].hDevice, RIDI_DEVICEINFO, (void *)&deviceInfo, &deviceInfoSize);
|
|
|
|
//check if it is a HID. we ignore keyboards and mice...
|
|
|
|
if (deviceInfo.dwType == RIM_TYPEHID)
|
|
|
|
{
|
|
|
|
//check if the vendor/product already exists in list. yes. could be more elegant...
|
|
|
|
std::vector<InputDevice>::const_iterator cdIt = currentDevices.cbegin();
|
|
|
|
while (cdIt != currentDevices.cend())
|
|
|
|
{
|
|
|
|
if (cdIt->name == deviceName && cdIt->product == deviceInfo.hid.dwProductId && cdIt->vendor == deviceInfo.hid.dwVendorId)
|
|
|
|
{
|
|
|
|
//device already there
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++cdIt;
|
|
|
|
}
|
|
|
|
//was the device found?
|
|
|
|
if (cdIt == currentDevices.cend())
|
|
|
|
{
|
|
|
|
//no. add it.
|
|
|
|
currentDevices.push_back(InputDevice(deviceName, deviceInfo.hid.dwProductId, deviceInfo.hid.dwVendorId));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete [] deviceList;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return currentDevices;
|
|
|
|
}
|
|
|
|
|
|
|
|
Uint32 InputManager::devicePollingCallback(Uint32 interval, void* param)
|
|
|
|
{
|
|
|
|
//this thing my be running in a different thread, so we're not allowed to call
|
|
|
|
//any functions or change/allocate/delete stuff, but can send a user event
|
|
|
|
SDL_Event event;
|
2013-06-27 08:26:56 +00:00
|
|
|
event.user.type = SDL_USEREVENT;
|
|
|
|
event.user.code = SDL_USEREVENT_POLLDEVICES;
|
|
|
|
event.user.data1 = nullptr;
|
|
|
|
event.user.data2 = nullptr;
|
|
|
|
if (SDL_PushEvent(&event) != 0) {
|
|
|
|
LOG(LogError) << "InputManager::devicePollingCallback - SDL event queue is full!";
|
|
|
|
}
|
2013-05-24 11:44:40 +00:00
|
|
|
|
|
|
|
return interval;
|
|
|
|
}
|
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
void InputManager::init()
|
2012-07-20 01:08:29 +00:00
|
|
|
{
|
2013-04-08 14:41:25 +00:00
|
|
|
if(mJoysticks != NULL)
|
|
|
|
deinit();
|
2012-07-22 21:15:55 +00:00
|
|
|
|
2013-05-24 11:44:40 +00:00
|
|
|
//get current input devices from system
|
|
|
|
inputDevices = getInputDevices();
|
|
|
|
|
|
|
|
SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_TIMER);
|
2012-07-22 21:15:55 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
mNumJoysticks = SDL_NumJoysticks();
|
|
|
|
mJoysticks = new SDL_Joystick*[mNumJoysticks];
|
|
|
|
mInputConfigs = new InputConfig*[mNumJoysticks];
|
|
|
|
mPrevAxisValues = new std::map<int, int>[mNumJoysticks];
|
2012-07-20 01:08:29 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
for(int i = 0; i < mNumJoysticks; i++)
|
|
|
|
{
|
|
|
|
mJoysticks[i] = SDL_JoystickOpen(i);
|
|
|
|
mInputConfigs[i] = new InputConfig(i);
|
2012-07-20 01:08:29 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
for(int k = 0; k < SDL_JoystickNumAxes(mJoysticks[i]); k++)
|
2012-07-22 21:15:55 +00:00
|
|
|
{
|
2013-04-08 14:41:25 +00:00
|
|
|
mPrevAxisValues[i][k] = 0;
|
2012-07-22 21:15:55 +00:00
|
|
|
}
|
|
|
|
}
|
2012-07-20 01:08:29 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
mKeyboardInputConfig = new InputConfig(DEVICE_KEYBOARD);
|
2013-03-25 13:16:54 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
2013-04-10 17:29:07 +00:00
|
|
|
|
2013-05-24 11:44:40 +00:00
|
|
|
//start timer for input device polling
|
2013-06-30 01:37:18 +00:00
|
|
|
startPolling();
|
2013-05-24 11:44:40 +00:00
|
|
|
|
2013-04-11 22:27:27 +00:00
|
|
|
loadConfig();
|
2012-07-20 01:08:29 +00:00
|
|
|
}
|
|
|
|
|
2013-06-30 01:37:18 +00:00
|
|
|
void InputManager::startPolling()
|
|
|
|
{
|
|
|
|
if(devicePollingTimer != NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
devicePollingTimer = SDL_AddTimer(POLLING_INTERVAL, devicePollingCallback, (void *)this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputManager::stopPolling()
|
2012-07-22 21:15:55 +00:00
|
|
|
{
|
2013-06-30 01:37:18 +00:00
|
|
|
if(devicePollingTimer == NULL)
|
|
|
|
return;
|
|
|
|
|
2013-05-24 11:44:40 +00:00
|
|
|
SDL_RemoveTimer(devicePollingTimer);
|
2013-06-30 01:37:18 +00:00
|
|
|
devicePollingTimer = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputManager::deinit()
|
|
|
|
{
|
|
|
|
stopPolling();
|
2013-05-24 11:44:40 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
SDL_JoystickEventState(SDL_DISABLE);
|
2012-07-22 21:15:55 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
if(!SDL_WasInit(SDL_INIT_JOYSTICK))
|
|
|
|
return;
|
2012-09-14 18:22:01 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
if(mJoysticks != NULL)
|
2012-07-22 21:15:55 +00:00
|
|
|
{
|
2013-04-08 14:41:25 +00:00
|
|
|
for(int i = 0; i < mNumJoysticks; i++)
|
|
|
|
{
|
|
|
|
SDL_JoystickClose(mJoysticks[i]);
|
|
|
|
delete mInputConfigs[i];
|
|
|
|
}
|
2012-07-22 21:15:55 +00:00
|
|
|
|
2013-05-14 19:45:56 +00:00
|
|
|
delete[] mInputConfigs;
|
|
|
|
mInputConfigs = NULL;
|
2012-07-22 21:15:55 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
delete[] mJoysticks;
|
|
|
|
mJoysticks = NULL;
|
2013-05-14 19:45:56 +00:00
|
|
|
|
|
|
|
delete mKeyboardInputConfig;
|
2013-04-08 14:41:25 +00:00
|
|
|
mKeyboardInputConfig = NULL;
|
2013-05-14 19:45:56 +00:00
|
|
|
|
|
|
|
delete[] mPrevAxisValues;
|
|
|
|
mPrevAxisValues = NULL;
|
2013-04-08 14:41:25 +00:00
|
|
|
}
|
2012-07-22 21:15:55 +00:00
|
|
|
|
2013-05-24 11:44:40 +00:00
|
|
|
SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_TIMER);
|
|
|
|
|
|
|
|
inputDevices.clear();
|
2013-04-08 14:41:25 +00:00
|
|
|
}
|
2012-09-14 18:22:01 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
int InputManager::getNumJoysticks() { return mNumJoysticks; }
|
2013-04-13 23:10:23 +00:00
|
|
|
int InputManager::getButtonCountByDevice(int id)
|
|
|
|
{
|
|
|
|
if(id == DEVICE_KEYBOARD)
|
|
|
|
return 120; //it's a lot, okay.
|
|
|
|
else
|
|
|
|
return SDL_JoystickNumButtons(mJoysticks[id]);
|
|
|
|
}
|
2012-09-14 18:22:01 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
int InputManager::getNumPlayers() { return mNumPlayers; }
|
|
|
|
void InputManager::setNumPlayers(int num) { mNumPlayers = num; }
|
2012-07-22 21:15:55 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
InputConfig* InputManager::getInputConfigByDevice(int device)
|
|
|
|
{
|
|
|
|
if(device == DEVICE_KEYBOARD)
|
|
|
|
return mKeyboardInputConfig;
|
|
|
|
else
|
|
|
|
return mInputConfigs[device];
|
|
|
|
}
|
2012-07-22 21:15:55 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
InputConfig* InputManager::getInputConfigByPlayer(int player)
|
|
|
|
{
|
|
|
|
if(mKeyboardInputConfig->getPlayerNum() == player)
|
|
|
|
return mKeyboardInputConfig;
|
2012-07-22 21:15:55 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
for(int i = 0; i < mNumJoysticks; i++)
|
|
|
|
{
|
|
|
|
if(mInputConfigs[i]->getPlayerNum() == player)
|
|
|
|
return mInputConfigs[i];
|
2012-07-22 21:15:55 +00:00
|
|
|
}
|
|
|
|
|
2013-04-13 18:19:06 +00:00
|
|
|
LOG(LogError) << "Could not find input config for player number " << player << "!";
|
2013-04-08 14:41:25 +00:00
|
|
|
return NULL;
|
2013-01-08 02:24:59 +00:00
|
|
|
}
|
|
|
|
|
2013-04-08 16:52:40 +00:00
|
|
|
bool InputManager::parseEvent(const SDL_Event& ev)
|
2013-01-08 02:24:59 +00:00
|
|
|
{
|
2013-04-08 16:52:40 +00:00
|
|
|
bool causedEvent = false;
|
2013-04-08 14:41:25 +00:00
|
|
|
switch(ev.type)
|
2012-07-22 21:15:55 +00:00
|
|
|
{
|
2013-04-08 14:41:25 +00:00
|
|
|
case SDL_JOYAXISMOTION:
|
|
|
|
//if it switched boundaries
|
|
|
|
if((abs(ev.jaxis.value) > DEADZONE) != (abs(mPrevAxisValues[ev.jaxis.which][ev.jaxis.axis]) > DEADZONE))
|
2012-09-14 18:22:01 +00:00
|
|
|
{
|
2013-04-08 14:41:25 +00:00
|
|
|
int normValue;
|
|
|
|
if(abs(ev.jaxis.value) <= DEADZONE)
|
|
|
|
normValue = 0;
|
|
|
|
else
|
|
|
|
if(ev.jaxis.value > 0)
|
|
|
|
normValue = 1;
|
|
|
|
else
|
|
|
|
normValue = -1;
|
|
|
|
|
|
|
|
mWindow->input(getInputConfigByDevice(ev.jaxis.which), Input(ev.jaxis.which, TYPE_AXIS, ev.jaxis.axis, normValue, false));
|
2013-04-08 16:52:40 +00:00
|
|
|
causedEvent = true;
|
2013-04-08 14:41:25 +00:00
|
|
|
}
|
2012-12-20 18:29:05 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
mPrevAxisValues[ev.jaxis.which][ev.jaxis.axis] = ev.jaxis.value;
|
2013-04-08 16:52:40 +00:00
|
|
|
return causedEvent;
|
2012-12-20 18:29:05 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
case SDL_JOYBUTTONDOWN:
|
|
|
|
case SDL_JOYBUTTONUP:
|
|
|
|
mWindow->input(getInputConfigByDevice(ev.jbutton.which), Input(ev.jbutton.which, TYPE_BUTTON, ev.jbutton.button, ev.jbutton.state == SDL_PRESSED, false));
|
2013-04-08 16:52:40 +00:00
|
|
|
return true;
|
2012-12-20 18:29:05 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
case SDL_JOYHATMOTION:
|
|
|
|
mWindow->input(getInputConfigByDevice(ev.jhat.which), Input(ev.jhat.which, TYPE_HAT, ev.jhat.hat, ev.jhat.value, false));
|
2013-04-08 16:52:40 +00:00
|
|
|
return true;
|
2012-12-20 18:29:05 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
case SDL_KEYDOWN:
|
|
|
|
if(ev.key.keysym.sym == SDLK_F4)
|
|
|
|
{
|
|
|
|
SDL_Event* quit = new SDL_Event();
|
|
|
|
quit->type = SDL_QUIT;
|
|
|
|
SDL_PushEvent(quit);
|
2013-04-08 16:52:40 +00:00
|
|
|
return false;
|
2012-09-14 18:22:01 +00:00
|
|
|
}
|
2013-03-29 02:55:29 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
mWindow->input(getInputConfigByDevice(DEVICE_KEYBOARD), Input(DEVICE_KEYBOARD, TYPE_KEY, ev.key.keysym.sym, 1, false));
|
2013-04-08 16:52:40 +00:00
|
|
|
return true;
|
2012-07-23 23:53:33 +00:00
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
case SDL_KEYUP:
|
|
|
|
mWindow->input(getInputConfigByDevice(DEVICE_KEYBOARD), Input(DEVICE_KEYBOARD, TYPE_KEY, ev.key.keysym.sym, 0, false));
|
2013-04-08 16:52:40 +00:00
|
|
|
return true;
|
2013-05-24 11:44:40 +00:00
|
|
|
|
2013-06-27 08:26:56 +00:00
|
|
|
case SDL_USEREVENT:
|
|
|
|
if (ev.user.code == SDL_USEREVENT_POLLDEVICES) {
|
|
|
|
//poll joystick / HID again
|
|
|
|
std::vector<InputDevice> currentDevices = getInputDevices();
|
|
|
|
//compare device lists to see if devices were added/deleted
|
|
|
|
if (currentDevices != inputDevices) {
|
|
|
|
LOG(LogInfo) << "Device configuration changed!";
|
|
|
|
inputDevices = currentDevices;
|
|
|
|
//deinit and reinit InputManager
|
|
|
|
deinit();
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
return true;
|
2013-05-24 11:44:40 +00:00
|
|
|
}
|
2013-04-08 14:41:25 +00:00
|
|
|
}
|
2013-04-08 16:52:40 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InputManager::loadConfig()
|
|
|
|
{
|
2013-04-11 22:27:27 +00:00
|
|
|
if(!mJoysticks)
|
|
|
|
{
|
2013-04-13 18:19:06 +00:00
|
|
|
LOG(LogError) << "ERROR - cannot load InputManager config without being initialized!";
|
2013-04-11 22:27:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string path = getConfigPath();
|
|
|
|
if(!fs::exists(path))
|
|
|
|
return;
|
2013-04-08 16:52:40 +00:00
|
|
|
|
2013-04-11 22:27:27 +00:00
|
|
|
pugi::xml_document doc;
|
|
|
|
pugi::xml_parse_result res = doc.load_file(path.c_str());
|
|
|
|
|
|
|
|
if(!res)
|
|
|
|
{
|
|
|
|
LOG(LogError) << "Error loading input config: " << res.description();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mNumPlayers = 0;
|
|
|
|
|
2013-05-13 19:53:28 +00:00
|
|
|
bool* configuredDevice = new bool[mNumJoysticks];
|
2013-04-13 18:19:06 +00:00
|
|
|
for(int i = 0; i < mNumJoysticks; i++)
|
|
|
|
{
|
|
|
|
mInputConfigs[i]->setPlayerNum(-1);
|
|
|
|
configuredDevice[i] = false;
|
|
|
|
}
|
|
|
|
|
2013-04-11 22:27:27 +00:00
|
|
|
pugi::xml_node root = doc.child("inputList");
|
|
|
|
|
|
|
|
for(pugi::xml_node node = root.child("inputConfig"); node; node = node.next_sibling("inputConfig"))
|
|
|
|
{
|
|
|
|
std::string type = node.attribute("type").as_string();
|
|
|
|
|
|
|
|
if(type == "keyboard")
|
|
|
|
{
|
|
|
|
getInputConfigByDevice(DEVICE_KEYBOARD)->loadFromXML(node, mNumPlayers);
|
|
|
|
mNumPlayers++;
|
|
|
|
}else if(type == "joystick")
|
|
|
|
{
|
|
|
|
bool found = false;
|
2013-04-12 02:59:19 +00:00
|
|
|
std::string devName = node.attribute("deviceName").as_string();
|
2013-04-11 22:27:27 +00:00
|
|
|
for(int i = 0; i < mNumJoysticks; i++)
|
|
|
|
{
|
2013-04-13 18:19:06 +00:00
|
|
|
if(!configuredDevice[i] && SDL_JoystickName(i) == devName)
|
2013-04-11 22:27:27 +00:00
|
|
|
{
|
|
|
|
mInputConfigs[i]->loadFromXML(node, mNumPlayers);
|
|
|
|
mNumPlayers++;
|
|
|
|
found = true;
|
2013-04-13 18:19:06 +00:00
|
|
|
configuredDevice[i] = true;
|
2013-04-11 22:27:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!found)
|
|
|
|
{
|
2013-04-13 18:19:06 +00:00
|
|
|
LOG(LogWarning) << "Could not find unconfigured joystick named \"" << devName << "\"! Skipping it.\n";
|
2013-04-11 22:27:27 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
LOG(LogWarning) << "Device type \"" << type << "\" unknown!\n";
|
|
|
|
}
|
|
|
|
}
|
2013-04-13 18:19:06 +00:00
|
|
|
|
2013-05-13 19:53:28 +00:00
|
|
|
delete[] configuredDevice;
|
|
|
|
|
2013-04-13 18:19:06 +00:00
|
|
|
if(mNumPlayers == 0)
|
|
|
|
{
|
|
|
|
LOG(LogInfo) << "No input configs loaded. Loading default keyboard config.";
|
|
|
|
loadDefaultConfig();
|
|
|
|
}
|
2013-06-30 01:37:18 +00:00
|
|
|
|
|
|
|
LOG(LogInfo) << "Loaded InputConfig data for " << getNumPlayers() << " devices.";
|
2013-04-13 18:19:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//used in an "emergency" where no configs could be loaded from the inputmanager config file
|
|
|
|
//allows the user to select to reconfigure in menus if this happens without having to delete es_input.cfg manually
|
|
|
|
void InputManager::loadDefaultConfig()
|
|
|
|
{
|
|
|
|
InputConfig* cfg = getInputConfigByDevice(DEVICE_KEYBOARD);
|
|
|
|
|
|
|
|
mNumPlayers++;
|
|
|
|
cfg->setPlayerNum(0);
|
|
|
|
cfg->mapInput("up", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_UP, 1, true));
|
|
|
|
cfg->mapInput("down", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_DOWN, 1, true));
|
|
|
|
cfg->mapInput("left", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_LEFT, 1, true));
|
|
|
|
cfg->mapInput("right", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_RIGHT, 1, true));
|
|
|
|
|
|
|
|
cfg->mapInput("a", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_RETURN, 1, true));
|
|
|
|
cfg->mapInput("b", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_ESCAPE, 1, true));
|
|
|
|
cfg->mapInput("menu", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_F1, 1, true));
|
|
|
|
cfg->mapInput("select", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_F2, 1, true));
|
2013-04-13 23:10:23 +00:00
|
|
|
cfg->mapInput("pageup", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_RIGHTBRACKET, 1, true));
|
|
|
|
cfg->mapInput("pagedown", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_LEFTBRACKET, 1, true));
|
2013-05-23 09:43:50 +00:00
|
|
|
|
|
|
|
cfg->mapInput("mastervolup", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_PLUS, 1, true));
|
|
|
|
cfg->mapInput("mastervoldown", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_MINUS, 1, true));
|
Support sorting of game list via input
You can now map the functions "sortordernext" and "sortorderprevious" to
inputs (in es_input.cfg) and toggle the game list sort order with them.
The order is: "file name, ascending" (default), "file name, descending",
"rating ascending", "rating descending", "user rating ascending", "user
rating descending", "time played ascending", "times played descending",
"last played time ascending", "last played time descending".
2013-06-28 17:44:28 +00:00
|
|
|
|
|
|
|
cfg->mapInput("sortordernext", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_F7, 1, true));
|
|
|
|
cfg->mapInput("sortorderprevious", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_F8, 1, true));
|
2013-04-11 22:27:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void InputManager::writeConfig()
|
|
|
|
{
|
|
|
|
if(!mJoysticks)
|
|
|
|
{
|
2013-04-13 18:19:06 +00:00
|
|
|
LOG(LogError) << "ERROR - cannot write config without being initialized!";
|
2013-04-11 22:27:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string path = getConfigPath();
|
|
|
|
|
|
|
|
pugi::xml_document doc;
|
|
|
|
|
|
|
|
pugi::xml_node root = doc.append_child("inputList");
|
|
|
|
|
|
|
|
mKeyboardInputConfig->writeToXML(root);
|
|
|
|
for(int i = 0; i < mNumJoysticks; i++)
|
|
|
|
{
|
|
|
|
mInputConfigs[i]->writeToXML(root);
|
|
|
|
}
|
|
|
|
|
|
|
|
doc.save_file(path.c_str());
|
2012-07-23 23:53:33 +00:00
|
|
|
}
|
2013-04-08 16:52:40 +00:00
|
|
|
|
|
|
|
std::string InputManager::getConfigPath()
|
|
|
|
{
|
2013-05-13 19:53:28 +00:00
|
|
|
std::string path = getHomePath();
|
2013-04-08 16:52:40 +00:00
|
|
|
path += "/.emulationstation/es_input.cfg";
|
|
|
|
return path;
|
|
|
|
}
|