From 11ff4b30fbe65b8fb9330586a75d2f06bb2595c3 Mon Sep 17 00:00:00 2001 From: Hannes Mann Date: Wed, 15 Jun 2016 18:16:25 +0200 Subject: [PATCH] Add rebindable keyboard keys --- data/games/rayman2_openrayman/manifest.json | 3 +- src/config/config.cc | 95 ++++++++++++++++++--- src/config/config.h | 7 +- src/engine.h | 9 +- src/input/input_state.h | 9 +- src/input/standalone_input_provider.cc | 43 ++++------ src/input/standalone_input_provider.h | 10 ++- src/window/sdl_window.cc | 6 +- src/window/sdl_window.h | 7 +- src/window/window.h | 4 +- 10 files changed, 136 insertions(+), 57 deletions(-) diff --git a/data/games/rayman2_openrayman/manifest.json b/data/games/rayman2_openrayman/manifest.json index 8db0b65..6a6df04 100644 --- a/data/games/rayman2_openrayman/manifest.json +++ b/data/games/rayman2_openrayman/manifest.json @@ -1,6 +1,5 @@ { - "info": - { + "info": { "name": "Rayman 2: The Great Escape (OpenRayman)", "description": "Rayman 2: The Great Escape with modifications for OpenRayman" }, diff --git a/src/config/config.cc b/src/config/config.cc index 075c195..a818d1f 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -3,6 +3,9 @@ #include #include #include +#ifndef USE_LIBRETRO +#include +#endif namespace openrayman { @@ -13,6 +16,28 @@ namespace openrayman max_fps(0), game("rayman2_openrayman") { +#ifndef USE_LIBRETRO + keyboard_map["stick(strength)"] = SDL_GetScancodeName(SDL_SCANCODE_LSHIFT); + + keyboard_map["stick(x, -)"] = SDL_GetScancodeName(SDL_SCANCODE_LEFT); + keyboard_map["stick(x, +)"] = SDL_GetScancodeName(SDL_SCANCODE_RIGHT); + keyboard_map["stick(y, -)"] = SDL_GetScancodeName(SDL_SCANCODE_UP); + keyboard_map["stick(y, +)"] = SDL_GetScancodeName(SDL_SCANCODE_DOWN); + + keyboard_map["start"] = SDL_GetScancodeName(SDL_SCANCODE_ESCAPE); + + keyboard_map["a"] = SDL_GetScancodeName(SDL_SCANCODE_A); + keyboard_map["b"] = SDL_GetScancodeName(SDL_SCANCODE_SPACE); + + keyboard_map["l"] = SDL_GetScancodeName(SDL_SCANCODE_LCTRL); + keyboard_map["r"] = SDL_GetScancodeName(SDL_SCANCODE_F1); + keyboard_map["z"] = SDL_GetScancodeName(SDL_SCANCODE_J); + + keyboard_map["cbtn(x, -)"] = SDL_GetScancodeName(SDL_SCANCODE_Q); + keyboard_map["cbtn(x, +)"] = SDL_GetScancodeName(SDL_SCANCODE_W); + keyboard_map["cbtn(y, -)"] = SDL_GetScancodeName(SDL_SCANCODE_O); + keyboard_map["cbtn(y, +)"] = SDL_GetScancodeName(SDL_SCANCODE_END); +#endif if(!reload()) save(); } @@ -32,14 +57,37 @@ namespace openrayman if(config_stream.is_open()) { config_stream >> config_json; - if(config_json.count("vsync") > 0) - vsync = config_json["vsync"]; - if(config_json.count("fullscreen") > 0) - fullscreen = config_json["fullscreen"]; - if(config_json.count("max_fps") > 0) - max_fps = config_json["max_fps"]; if(config_json.count("game") > 0) game = config_json["game"]; + if(config_json.count("gfx") > 0) + { + vsync = config_json["gfx"]["vsync"]; + fullscreen = config_json["gfx"]["fullscreen"]; + max_fps = config_json["gfx"]["max_fps"]; + } + if(config_json.count("keyboard_map") > 0) + { + keyboard_map["stick(strength)"] = config_json["keyboard_map"]["stick(strength)"]; + + keyboard_map["stick(x, -)"] = config_json["keyboard_map"]["stick(x, -)"]; + keyboard_map["stick(x, +)"] = config_json["keyboard_map"]["stick(x, +)"]; + keyboard_map["stick(y, -)"] = config_json["keyboard_map"]["stick(y, -)"]; + keyboard_map["stick(y, +)"] = config_json["keyboard_map"]["stick(y, +)"]; + + keyboard_map["start"] = config_json["keyboard_map"]["start"]; + + keyboard_map["a"] = config_json["keyboard_map"]["a"]; + keyboard_map["b"] = config_json["keyboard_map"]["b"]; + + keyboard_map["l"] = config_json["keyboard_map"]["l"]; + keyboard_map["r"] = config_json["keyboard_map"]["r"]; + keyboard_map["z"] = config_json["keyboard_map"]["z"]; + + keyboard_map["cbtn(x, -)"] = config_json["keyboard_map"]["cbtn(x, -)"]; + keyboard_map["cbtn(x, +)"] = config_json["keyboard_map"]["cbtn(x, +)"]; + keyboard_map["cbtn(y, -)"] = config_json["keyboard_map"]["cbtn(y, -)"]; + keyboard_map["cbtn(y, +)"] = config_json["keyboard_map"]["cbtn(y, +)"]; + } return true; } } @@ -47,14 +95,41 @@ namespace openrayman return false; } - bool config::save() const + bool config::save() { std::string config_json_file = file::fix_string(m_backend_specifics.get_storage_path() + "/config.json"); nlohmann::json config_json; - config_json["vsync"] = vsync; - config_json["fullscreen"] = fullscreen; - config_json["max_fps"] = max_fps; config_json["game"] = game; + + config_json["gfx"] = nlohmann::json::object(); + + config_json["gfx"]["vsync"] = vsync; + config_json["gfx"]["fullscreen"] = fullscreen; + config_json["gfx"]["max_fps"] = max_fps; + + config_json["keyboard_map"] = nlohmann::json::object(); + + config_json["keyboard_map"]["stick(strength)"] = keyboard_map["stick(strength)"]; + + config_json["keyboard_map"]["stick(x, -)"] = keyboard_map["stick(x, -)"]; + config_json["keyboard_map"]["stick(x, +)"] = keyboard_map["stick(x, +)"]; + config_json["keyboard_map"]["stick(y, -)"] = keyboard_map["stick(y, -)"]; + config_json["keyboard_map"]["stick(y, +)"] = keyboard_map["stick(y, +)"]; + + config_json["keyboard_map"]["start"] = keyboard_map["start"]; + + config_json["keyboard_map"]["a"] = keyboard_map["a"]; + config_json["keyboard_map"]["b"] = keyboard_map["b"]; + + config_json["keyboard_map"]["l"] = keyboard_map["l"]; + config_json["keyboard_map"]["r"] = keyboard_map["r"]; + config_json["keyboard_map"]["z"] = keyboard_map["z"]; + + config_json["keyboard_map"]["cbtn(x, -)"] = keyboard_map["cbtn(x, -"]; + config_json["keyboard_map"]["cbtn(x, +)"] = keyboard_map["cbtn(x, +)"]; + config_json["keyboard_map"]["cbtn(y, -)"] = keyboard_map["cbtn(y, -)"]; + config_json["keyboard_map"]["cbtn(y, +)"] = keyboard_map["cbtn(y, +)"]; + std::ofstream config_stream(config_json_file, std::ofstream::out | std::ofstream::trunc); if(config_stream.is_open()) config_stream << std::setw(4) << config_json; diff --git a/src/config/config.h b/src/config/config.h index a74ac1b..dcfa424 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -2,7 +2,9 @@ #define CONFIG_H #include +#include #include +#include namespace openrayman { @@ -23,7 +25,7 @@ public: // Saves the config file and all changes to the disk. // Returns true if the config was saved successfully. // This is done automatically in the destructor. - bool save() const; + bool save(); // If the game should be synchronized to the vertical blank of the screen. // This might introduce additional input lag (though we do use glFinish to minimize it). @@ -39,6 +41,9 @@ public: // The user selected game to load. // Defaults to the game "rayman2_openrayman". std::string game; + + // User mappings for keyboard when running standalone. + std::unordered_map keyboard_map; private: const backend_specifics& m_backend_specifics; }; diff --git a/src/engine.h b/src/engine.h index 552e8a6..751abcf 100644 --- a/src/engine.h +++ b/src/engine.h @@ -26,12 +26,11 @@ public: engine() : m_exit_requested(false), #ifdef LIBRETRO_CORE - m_window(*(new libretro_window())), m_backend_specifics(*(new libretro_backend_specifics())), #else - m_window(*(new sdl_window())), m_backend_specifics(*(new standalone_backend_specifics())), #endif + m_config(m_backend_specifics), m_current_input(0, 0, 0), m_last_input(0, 0, 0), m_last_timer_value(0), @@ -43,7 +42,11 @@ public: m_total_fixed_updates(0), m_accumulated_frames_fps(0), m_fps(0), - m_config(m_backend_specifics) +#ifdef LIBRETRO_CORE + m_window(*(new libretro_window())) +#else + m_window(*(new sdl_window(m_config))) +#endif { }; // Starts the game loop and loads the specified game. diff --git a/src/input/input_state.h b/src/input/input_state.h index 94c2433..972ad2a 100644 --- a/src/input/input_state.h +++ b/src/input/input_state.h @@ -10,10 +10,11 @@ namespace openrayman enum input_button : std::uint16_t { // All four dpad axises. - dpad_left = (1 << 1), - dpad_right = (1 << 2), - dpad_up = (1 << 3), - dpad_down = (1 << 4), + // These are never used in Rayman 2 + // dpad_left = (1 << 1), + // dpad_right = (1 << 2), + // dpad_up = (1 << 3), + // dpad_down = (1 << 4), // The start button. Used for pausing. start = (1 << 5), diff --git a/src/input/standalone_input_provider.cc b/src/input/standalone_input_provider.cc index 88bea26..12784fc 100644 --- a/src/input/standalone_input_provider.cc +++ b/src/input/standalone_input_provider.cc @@ -3,16 +3,6 @@ namespace openrayman { - standalone_input_provider::standalone_input_provider(SDL_Window* window) : - m_input(0, 0, 0), - m_window(window) - { - } - - standalone_input_provider::~standalone_input_provider() - { - } - const std::string standalone_input_provider::get_description() const { return "SDL2 input provider (standalone)"; @@ -38,18 +28,18 @@ namespace openrayman // This simulates a slower walk done by the control stick // Used in some areas to avoid pirates // TODO: Is half (64) accurate?!?! - int walk_strength = keyboard_state[SDL_SCANCODE_LSHIFT] ? 64 : 127; + int walk_strength = keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["stick(strength)"].c_str())] ? 64 : 127; int new_stick_x = m_input.stick_x; int new_stick_y = m_input.stick_y; - if(keyboard_state[SDL_SCANCODE_LEFT]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["stick(x, -)"].c_str())]) new_stick_x -= walk_strength; - if(keyboard_state[SDL_SCANCODE_RIGHT]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["stick(x, +)"].c_str())]) new_stick_x += walk_strength; - if(keyboard_state[SDL_SCANCODE_UP]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["stick(y, -)"].c_str())]) new_stick_y -= walk_strength; - if(keyboard_state[SDL_SCANCODE_DOWN]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["stick(y, +)"].c_str())]) new_stick_y += walk_strength; new_stick_x = std::min(127, std::max(-127, new_stick_x)); @@ -59,31 +49,31 @@ namespace openrayman m_input.stick_y = new_stick_y; // Front buttons - if(keyboard_state[SDL_SCANCODE_SPACE]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["a"].c_str())]) m_input.buttons |= input_button::a; - if(keyboard_state[SDL_SCANCODE_A]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["b"].c_str())]) m_input.buttons |= input_button::b; // Triggers - if(keyboard_state[SDL_SCANCODE_LCTRL]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["z"].c_str())]) m_input.buttons |= input_button::z; - if(keyboard_state[SDL_SCANCODE_F1]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["l"].c_str())]) m_input.buttons |= input_button::l; - if(keyboard_state[SDL_SCANCODE_J]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["r"].c_str())]) m_input.buttons |= input_button::r; // Start button - if(keyboard_state[SDL_SCANCODE_ESCAPE]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["start"].c_str())]) m_input.buttons |= input_button::start; // C buttons - if(keyboard_state[SDL_SCANCODE_Q]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["cbtn(x, -)"].c_str())]) m_input.commands |= input_button::cbtn_left; - if(keyboard_state[SDL_SCANCODE_W]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["cbtn(x, +)"].c_str())]) m_input.commands |= input_button::cbtn_right; - if(keyboard_state[SDL_SCANCODE_O]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["cbtn(y, -)"].c_str())]) m_input.commands |= input_button::cbtn_up; - if(keyboard_state[SDL_SCANCODE_END]) + if(keyboard_state[SDL_GetScancodeFromName(m_config.keyboard_map["cbtn(y, +)"].c_str())]) m_input.commands |= input_button::cbtn_down; // Commands @@ -98,6 +88,9 @@ namespace openrayman // the N64 version is not the same as the PC version and the original game // was not meant to be played with Xbox controllers and frankly, the original // layout is shit and doesn't work most of the time (dinput) + // TODO: rebindable? + // probably not... + // GUIDs? for(const std::pair& pair : m_game_controllers) { diff --git a/src/input/standalone_input_provider.h b/src/input/standalone_input_provider.h index f95b4a1..70780ad 100644 --- a/src/input/standalone_input_provider.h +++ b/src/input/standalone_input_provider.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -15,8 +16,11 @@ namespace openrayman { friend class sdl_window; public: - standalone_input_provider(SDL_Window* window); - ~standalone_input_provider(); + standalone_input_provider(config& config) : + m_input(0, 0, 0), + m_config(config) + { + } const std::string get_description() const override; const input_state& poll() override; @@ -24,7 +28,7 @@ private: void poll_keyboard(); void poll_game_controller(); input_state m_input; - SDL_Window* m_window; + config& m_config; std::unordered_map m_game_controllers; }; } diff --git a/src/window/sdl_window.cc b/src/window/sdl_window.cc index 1117384..c7301da 100644 --- a/src/window/sdl_window.cc +++ b/src/window/sdl_window.cc @@ -6,12 +6,12 @@ namespace openrayman { int sdl_window::m_sdl_ref_count = 0; - sdl_window::sdl_window() : + sdl_window::sdl_window(config& config) : m_window(nullptr), m_current_fullscreen(false), m_vsync_enabled(false), m_wants_close(false), - m_input_provider(nullptr) + m_input_provider(config) { if(m_sdl_ref_count <= 0) { @@ -61,8 +61,6 @@ namespace openrayman return false; } - m_input_provider = standalone_input_provider(m_window); - SDL_GL_SetSwapInterval(0); SDL_ShowCursor(SDL_DISABLE); diff --git a/src/window/sdl_window.h b/src/window/sdl_window.h index 8a9ab90..d4b9b62 100644 --- a/src/window/sdl_window.h +++ b/src/window/sdl_window.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -15,12 +16,12 @@ namespace openrayman class sdl_window : public window { public: + sdl_window(config& config); + ~sdl_window(); + bool open(const std::string& title, int w, int h, bool initial_fullscreen) override; void close() override; - sdl_window(); - ~sdl_window(); - void gl_make_current() override; void present() override; void poll_events() override; diff --git a/src/window/window.h b/src/window/window.h index 9e05146..454e534 100644 --- a/src/window/window.h +++ b/src/window/window.h @@ -11,14 +11,14 @@ namespace openrayman class window { public: + virtual ~window() { }; + // Opens or reopens the window, and creates a GL context. virtual bool open(const std::string& title, int w, int h, bool initial_fullscreen) = 0; // Closes the window if it's not already closed. virtual void close() = 0; - virtual ~window() { }; - // Makes the GL context associated with the window the current one. virtual void gl_make_current() = 0;