An input configuration GUI was added, which allows a user to map an SDL Joystick's buttons to InputManager buttons.

This config file is saved/loaded from ./input.cfg.
Coming soon - axis support!
This commit is contained in:
Aloshi 2012-07-22 16:15:55 -05:00
parent ac0407c059
commit b3fb58ebdb
8 changed files with 260 additions and 41 deletions

View file

@ -1,7 +1,7 @@
CC=g++
CFLAGS=-c -Wall
LDFLAGS=-lSDL -lSDL_ttf -lboost_system -lboost_filesystem
SRCSOURCES=main.cpp Renderer.cpp Renderer_draw.cpp GuiComponent.cpp InputManager.cpp SystemData.cpp GameData.cpp components/GuiTitleScreen.cpp components/GuiList.cpp components/GuiGameList.cpp
SRCSOURCES=main.cpp Renderer.cpp Renderer_draw.cpp GuiComponent.cpp InputManager.cpp SystemData.cpp GameData.cpp components/GuiTitleScreen.cpp components/GuiList.cpp components/GuiGameList.cpp components/GuiInputConfig.cpp
SOURCES=$(addprefix src/,$(SRCSOURCES))
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=emulationstation

View file

@ -1,8 +1,13 @@
#include "InputManager.h"
#include "GuiComponent.h"
#include <iostream>
#include <fstream>
#include <sstream>
std::vector<GuiComponent*> InputManager::inputVector;
SDL_Event* InputManager::lastEvent = NULL;
std::map<int, InputManager::InputButton> InputManager::joystickButtonMap, InputManager::joystickAxisMap;
void InputManager::registerComponent(GuiComponent* comp)
{
@ -24,49 +29,116 @@ void InputManager::unregisterComponent(GuiComponent* comp)
void InputManager::processEvent(SDL_Event* event)
{
bool keyDown = false;
if(event->key.state == SDL_PRESSED)
keyDown = true;
//get InputButton from the event
InputButton button;
switch(event->key.keysym.sym)
lastEvent = event;
//keyboard events
if(event->type == SDL_KEYDOWN || event->type == SDL_KEYUP)
{
case SDLK_LEFT:
button = LEFT;
break;
case SDLK_RIGHT:
button = RIGHT;
break;
case SDLK_UP:
button = UP;
break;
case SDLK_DOWN:
button = DOWN;
break;
case SDLK_RETURN:
button = BUTTON1;
break;
if(event->key.state == SDL_PRESSED)
keyDown = true;
//so the compiler doesn't complain
default:
break;
//get InputButton from the event
switch(event->key.keysym.sym)
{
case SDLK_LEFT:
button = LEFT;
break;
case SDLK_RIGHT:
button = RIGHT;
break;
case SDLK_UP:
button = UP;
break;
case SDLK_DOWN:
button = DOWN;
break;
case SDLK_RETURN:
button = BUTTON1;
break;
default:
button = UNKNOWN;
break;
}
//catch emergency quit event
if(event->key.keysym.sym == SDLK_F4)
{
//I have no idea if SDL will delete this event, but we're quitting, so I don't think it really matters
SDL_Event* quit = new SDL_Event();
quit->type = SDL_QUIT;
SDL_PushEvent(quit);
std::cout << "Pushing quit event\n";
}
}else{
if(event->type == SDL_JOYBUTTONDOWN || event->type == SDL_JOYBUTTONUP) //joystick button events
{
if(event->type == SDL_JOYBUTTONDOWN) //defaults to false, so no else
keyDown = true;
//hurr no config yet durr
button = joystickButtonMap[event->jbutton.button];
}
}
//catch emergency quit event
if(event->key.keysym.sym == SDLK_F4)
{
//I have no idea if SDL will delete this event, but we're quitting, so I don't think it really matters
SDL_Event* quit = new SDL_Event();
quit->type = SDL_QUIT;
SDL_PushEvent(quit);
std::cout << "Pushing quit event\n";
}
for(unsigned int i = 0; i < inputVector.size(); i++)
{
inputVector.at(i)->onInput(button, keyDown);
}
}
void InputManager::loadConfig(std::string path)
{
//clear any old config
joystickButtonMap.clear();
joystickAxisMap.clear();
std::ifstream file(path.c_str());
while(file.good())
{
std::string line;
std::getline(file, line);
//skip blank lines and comments
if(line.empty() || line[0] == *"#")
continue;
//I know I could probably just read from the file stream directly, but I feel it would be harder to catch errors in a readable way
std::istringstream stream(line);
std::string token[3];
int tokNum = 0;
while(std::getline(stream, token[tokNum], ' '))
{
tokNum++;
if(tokNum > 3)
{
std::cerr << "Error - input config line \"" << line << "\" has more than three tokens!\n";
break;
}
}
if(token[0] == "BUTTON")
{
joystickButtonMap[atoi(token[1].c_str())] = (InputButton)atoi(token[2].c_str());
}else if(token[0] == "AXIS")
{
}else{
std::cerr << "Invalid input type - " << token[0] << "\n";
return;
}
}
if(SDL_NumJoysticks() > 0)
{
SDL_JoystickOpen(0);
}
}

View file

@ -3,6 +3,8 @@
#include <vector>
#include <SDL/SDL.h>
#include <map>
#include <string>
class GuiComponent;
@ -10,14 +12,18 @@ namespace InputManager {
void registerComponent(GuiComponent* comp);
void unregisterComponent(GuiComponent* comp);
void loadConfig(std::string path);
//enum for identifying input type, regardless of configuration
enum InputButton { UP, DOWN, LEFT, RIGHT, BUTTON1, BUTTON2};
//enum for identifying input, regardless of configuration
enum InputButton { UP, DOWN, LEFT, RIGHT, BUTTON1, BUTTON2, UNKNOWN};
void processEvent(SDL_Event* event);
extern std::vector<GuiComponent*> inputVector;
extern SDL_Event* lastEvent; //mostly for GuiInputConfig
extern std::map<int, InputButton> joystickButtonMap;
extern std::map<int, InputButton> joystickAxisMap;
}
#endif

View file

@ -23,6 +23,15 @@ void Renderer::unregisterComponent(GuiComponent* comp)
}
}
void Renderer::deleteAll()
{
for(unsigned int i = 0; i < renderVector.size(); i++)
{
delete renderVector.at(i);
}
renderVector.clear();
}
void Renderer::render()
{
for(unsigned int layer = 0; layer < LAYER_COUNT; layer++)

View file

@ -16,6 +16,7 @@ namespace Renderer
{
void registerComponent(GuiComponent* comp);
void unregisterComponent(GuiComponent* comp);
void deleteAll();
void render();

View file

@ -0,0 +1,94 @@
#include "GuiInputConfig.h"
#include "GuiGameList.h"
#include <iostream>
#include <fstream>
std::string GuiInputConfig::sConfigPath = "./input.cfg";
std::string GuiInputConfig::sInputs[] = { "UP", "DOWN", "LEFT", "RIGHT", "BUTTON1", "BUTTON2" };
int GuiInputConfig::sInputCount = 6;
GuiInputConfig::GuiInputConfig()
{
mInputNum = 0;
mDone = false;
Renderer::registerComponent(this);
InputManager::registerComponent(this);
if(SDL_NumJoysticks() < 1)
{
std::cerr << "Error - GuiInputConfig found no SDL joysticks!\n";
mJoystick = NULL;
mDone = true;
return;
}else{
std::cout << "Opening joystick \"" << SDL_JoystickName(0) << "\"\n";
mJoystick = SDL_JoystickOpen(0);
}
}
GuiInputConfig::~GuiInputConfig()
{
Renderer::unregisterComponent(this);
InputManager::unregisterComponent(this);
}
void GuiInputConfig::onRender()
{
Renderer::drawRect(0, 0, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0xFFFFFF);
if(mDone)
Renderer::drawCenteredText("All done!", 2, 0x000000);
else
Renderer::drawCenteredText("Please press the axis/button for " + sInputs[mInputNum], 2, 0x000000);
}
void GuiInputConfig::onInput(InputManager::InputButton button, bool keyDown)
{
if(mDone)
{
if(keyDown)
{
writeConfig(sConfigPath);
if(mJoystick)
SDL_JoystickClose(mJoystick);
InputManager::loadConfig(sConfigPath);
delete this;
new GuiGameList();
}
return;
}
SDL_Event* event = InputManager::lastEvent;
if(event->type == SDL_JOYBUTTONDOWN)
{
mButtonMap[event->jbutton.button] = (InputManager::InputButton)mInputNum;
std::cout << " Mapping " << sInputs[mInputNum] << " to button " << event->jbutton.button << "\n";
mInputNum++;
}
if(mInputNum >= sInputCount)
{
mDone = true;
return;
}
}
void GuiInputConfig::writeConfig(std::string path)
{
std::ofstream file(path.c_str());
typedef std::map<int, InputManager::InputButton>::iterator it_type;
for(it_type iter = mButtonMap.begin(); iter != mButtonMap.end(); iter++)
{
file << "BUTTON " << iter->first << " " << iter->second << "\n";
}
for(it_type iter = mAxisMap.begin(); iter != mAxisMap.end(); iter++)
{
file << "AXIS " << iter->first << " " << iter->second << "\n";
}
}

View file

@ -0,0 +1,29 @@
#ifndef _GUIINPUTCONFIG_H_
#define _GUIINPUTCONFIG_H_
#include "../GuiComponent.h"
#include "../InputManager.h"
#include <map>
#include <SDL/SDL.h>
class GuiInputConfig : GuiComponent {
public:
GuiInputConfig();
~GuiInputConfig();
void onRender();
void onInput(InputManager::InputButton button, bool keyDown);
private:
bool mDone;
int mInputNum;
SDL_Joystick* mJoystick;
static std::string sInputs[];
static int sInputCount;
static std::string sConfigPath;
std::map<int, InputManager::InputButton> mButtonMap;
std::map<int, InputManager::InputButton> mAxisMap;
void writeConfig(std::string path);
};
#endif

View file

@ -5,6 +5,8 @@
#include "components/GuiGameList.h"
#include "SystemData.h"
#include "components/GuiInputConfig.h"
int main()
{
if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
@ -31,12 +33,16 @@ int main()
SDL_ShowCursor(false);
SDL_EnableKeyRepeat(500, 100);
SDL_JoystickEventState(SDL_ENABLE);
//GuiTitleScreen* testGui = new GuiTitleScreen();
SystemData::loadConfig("./systems.cfg");
GuiGameList* testGui = new GuiGameList();
//InputManager::loadConfig("./input.cfg");
//GuiGameList* testGui = new GuiGameList();
GuiInputConfig* testGui = new GuiInputConfig();
bool running = true;
while(running)
@ -46,6 +52,8 @@ int main()
{
switch(event.type)
{
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
case SDL_KEYDOWN:
InputManager::processEvent(&event);
break;
@ -63,7 +71,7 @@ int main()
SDL_Flip(Renderer::screen);
}
delete testGui;
Renderer::deleteAll();
SystemData::deleteSystems();
std::cout << "EmulationStation cleanly shutting down...\n";