mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 06:05:38 +00:00
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:
parent
ac0407c059
commit
b3fb58ebdb
2
Makefile
2
Makefile
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Renderer
|
|||
{
|
||||
void registerComponent(GuiComponent* comp);
|
||||
void unregisterComponent(GuiComponent* comp);
|
||||
void deleteAll();
|
||||
|
||||
void render();
|
||||
|
||||
|
|
94
src/components/GuiInputConfig.cpp
Normal file
94
src/components/GuiInputConfig.cpp
Normal 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";
|
||||
}
|
||||
|
||||
}
|
29
src/components/GuiInputConfig.h
Normal file
29
src/components/GuiInputConfig.h
Normal 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
|
12
src/main.cpp
12
src/main.cpp
|
@ -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";
|
||||
|
|
Loading…
Reference in a new issue