diff --git a/Makefile b/Makefile index e1ec770a0..fbc771a2d 100644 --- a/Makefile +++ b/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 diff --git a/src/InputManager.cpp b/src/InputManager.cpp index 029858210..7f5c258e1 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -1,8 +1,13 @@ #include "InputManager.h" #include "GuiComponent.h" #include +#include +#include std::vector InputManager::inputVector; +SDL_Event* InputManager::lastEvent = NULL; + +std::map 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); + } +} diff --git a/src/InputManager.h b/src/InputManager.h index eedc5b44c..eabb17256 100644 --- a/src/InputManager.h +++ b/src/InputManager.h @@ -3,6 +3,8 @@ #include #include +#include +#include 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 inputVector; + extern SDL_Event* lastEvent; //mostly for GuiInputConfig + + extern std::map joystickButtonMap; + extern std::map joystickAxisMap; } #endif diff --git a/src/Renderer.cpp b/src/Renderer.cpp index 685779fd8..ad4c5bf45 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -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++) diff --git a/src/Renderer.h b/src/Renderer.h index ac34d09bf..4edc58519 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -16,6 +16,7 @@ namespace Renderer { void registerComponent(GuiComponent* comp); void unregisterComponent(GuiComponent* comp); + void deleteAll(); void render(); diff --git a/src/components/GuiInputConfig.cpp b/src/components/GuiInputConfig.cpp new file mode 100644 index 000000000..a4041c20f --- /dev/null +++ b/src/components/GuiInputConfig.cpp @@ -0,0 +1,94 @@ +#include "GuiInputConfig.h" +#include "GuiGameList.h" +#include +#include + +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::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"; + } + +} diff --git a/src/components/GuiInputConfig.h b/src/components/GuiInputConfig.h new file mode 100644 index 000000000..0e0624614 --- /dev/null +++ b/src/components/GuiInputConfig.h @@ -0,0 +1,29 @@ +#ifndef _GUIINPUTCONFIG_H_ +#define _GUIINPUTCONFIG_H_ + +#include "../GuiComponent.h" +#include "../InputManager.h" +#include +#include + +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 mButtonMap; + std::map mAxisMap; + void writeConfig(std::string path); +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index bc243e446..7e1c460f6 100644 --- a/src/main.cpp +++ b/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";