Add rebindable keyboard keys

This commit is contained in:
Hannes Mann 2016-06-15 18:16:25 +02:00
parent c277fb918d
commit 11ff4b30fb
10 changed files with 136 additions and 57 deletions

View file

@ -1,6 +1,5 @@
{
"info":
{
"info": {
"name": "Rayman 2: The Great Escape (OpenRayman)",
"description": "Rayman 2: The Great Escape with modifications for OpenRayman"
},

View file

@ -3,6 +3,9 @@
#include <iostream>
#include <fstream>
#include <json.hpp>
#ifndef USE_LIBRETRO
#include <SDL2/SDL.h>
#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;

View file

@ -2,7 +2,9 @@
#define CONFIG_H
#include <string>
#include <input/input_state.h>
#include <platform/backend_specifics.h>
#include <unordered_map>
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<std::string, std::string> keyboard_map;
private:
const backend_specifics& m_backend_specifics;
};

View file

@ -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.

View file

@ -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),

View file

@ -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<int, SDL_GameController*>& pair : m_game_controllers)
{

View file

@ -3,6 +3,7 @@
#include <input/input_state.h>
#include <input/input_provider.h>
#include <config/config.h>
#include <SDL2/SDL.h>
#include <string>
#include <unordered_map>
@ -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<int, SDL_GameController*> m_game_controllers;
};
}

View file

@ -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);

View file

@ -5,6 +5,7 @@
#include <SDL2/SDL_opengl.h>
#include <string>
#include <cstdint>
#include <config/config.h>
#include <window/window.h>
#include <input/input_provider.h>
#include <input/standalone_input_provider.h>
@ -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;

View file

@ -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;