Introduce F1 menu to reconfigure key bindings at runtime
This commit is contained in:
parent
af145c3a01
commit
dd73db2e9d
|
@ -135,6 +135,8 @@ set(MAIN_HEADERS
|
||||||
src/gl-util.h
|
src/gl-util.h
|
||||||
src/util.h
|
src/util.h
|
||||||
src/config.h
|
src/config.h
|
||||||
|
src/settingsmenu.h
|
||||||
|
src/keybindings.h
|
||||||
src/tileatlas.h
|
src/tileatlas.h
|
||||||
src/sharedstate.h
|
src/sharedstate.h
|
||||||
src/al-util.h
|
src/al-util.h
|
||||||
|
@ -180,6 +182,8 @@ set(MAIN_SOURCE
|
||||||
src/debuglogger.cpp
|
src/debuglogger.cpp
|
||||||
src/etc.cpp
|
src/etc.cpp
|
||||||
src/config.cpp
|
src/config.cpp
|
||||||
|
src/settingsmenu.cpp
|
||||||
|
src/keybindings.cpp
|
||||||
src/tileatlas.cpp
|
src/tileatlas.cpp
|
||||||
src/sharedstate.cpp
|
src/sharedstate.cpp
|
||||||
src/gl-fun.cpp
|
src/gl-fun.cpp
|
||||||
|
|
|
@ -111,6 +111,19 @@
|
||||||
# allowSymlinks=false
|
# allowSymlinks=false
|
||||||
|
|
||||||
|
|
||||||
|
# Organisation / company and application / game
|
||||||
|
# name to build the directory path where mkxp
|
||||||
|
# will store game specific data (eg. key bindings).
|
||||||
|
# If not specified, mkxp will save to a common
|
||||||
|
# directory shared by all games. Note that these
|
||||||
|
# are TWO individual config entries, and both need
|
||||||
|
# to be defined for this to take effect.
|
||||||
|
# (default: none)
|
||||||
|
#
|
||||||
|
# dataPathOrg=mycompany
|
||||||
|
# dataPathApp=mygame
|
||||||
|
|
||||||
|
|
||||||
# Set the game window icon to 'path/to/icon.png'
|
# Set the game window icon to 'path/to/icon.png'
|
||||||
# (default: none)
|
# (default: none)
|
||||||
#
|
#
|
||||||
|
|
4
mkxp.pro
4
mkxp.pro
|
@ -114,6 +114,8 @@ HEADERS += \
|
||||||
src/gl-util.h \
|
src/gl-util.h \
|
||||||
src/util.h \
|
src/util.h \
|
||||||
src/config.h \
|
src/config.h \
|
||||||
|
src/settingsmenu.h \
|
||||||
|
src/keybindings.h \
|
||||||
src/tileatlas.h \
|
src/tileatlas.h \
|
||||||
src/sharedstate.h \
|
src/sharedstate.h \
|
||||||
src/al-util.h \
|
src/al-util.h \
|
||||||
|
@ -158,6 +160,8 @@ SOURCES += \
|
||||||
src/debuglogger.cpp \
|
src/debuglogger.cpp \
|
||||||
src/etc.cpp \
|
src/etc.cpp \
|
||||||
src/config.cpp \
|
src/config.cpp \
|
||||||
|
src/settingsmenu.cpp \
|
||||||
|
src/keybindings.cpp \
|
||||||
src/tileatlas.cpp \
|
src/tileatlas.cpp \
|
||||||
src/sharedstate.cpp \
|
src/sharedstate.cpp \
|
||||||
src/gl-fun.cpp \
|
src/gl-fun.cpp \
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#include <boost/program_options/parsers.hpp>
|
#include <boost/program_options/parsers.hpp>
|
||||||
#include <boost/program_options/variables_map.hpp>
|
#include <boost/program_options/variables_map.hpp>
|
||||||
|
|
||||||
|
#include <SDL_filesystem.h>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -118,6 +120,15 @@ static bool validUtf8(const char *string)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string prefPath(const char *org, const char *app)
|
||||||
|
{
|
||||||
|
char *path = SDL_GetPrefPath(org, app);
|
||||||
|
std::string str(path);
|
||||||
|
SDL_free(path);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
typedef std::vector<std::string> StringVec;
|
typedef std::vector<std::string> StringVec;
|
||||||
namespace po = boost::program_options;
|
namespace po = boost::program_options;
|
||||||
|
|
||||||
|
@ -167,6 +178,8 @@ void Config::read(int argc, char *argv[])
|
||||||
PO_DESC(anyAltToggleFS, bool) \
|
PO_DESC(anyAltToggleFS, bool) \
|
||||||
PO_DESC(enableReset, bool) \
|
PO_DESC(enableReset, bool) \
|
||||||
PO_DESC(allowSymlinks, bool) \
|
PO_DESC(allowSymlinks, bool) \
|
||||||
|
PO_DESC(dataPathOrg, std::string) \
|
||||||
|
PO_DESC(dataPathApp, std::string) \
|
||||||
PO_DESC(iconPath, std::string) \
|
PO_DESC(iconPath, std::string) \
|
||||||
PO_DESC(titleLanguage, std::string) \
|
PO_DESC(titleLanguage, std::string) \
|
||||||
PO_DESC(midi.soundFont, std::string) \
|
PO_DESC(midi.soundFont, std::string) \
|
||||||
|
@ -243,6 +256,11 @@ void Config::read(int argc, char *argv[])
|
||||||
rgssVersion = clamp(rgssVersion, 0, 3);
|
rgssVersion = clamp(rgssVersion, 0, 3);
|
||||||
|
|
||||||
SE.sourceCount = clamp(SE.sourceCount, 1, 64);
|
SE.sourceCount = clamp(SE.sourceCount, 1, 64);
|
||||||
|
|
||||||
|
if (!dataPathOrg.empty() && !dataPathApp.empty())
|
||||||
|
customDataPath = prefPath(dataPathOrg.c_str(), dataPathApp.c_str());
|
||||||
|
|
||||||
|
commonDataPath = prefPath(".", "mkxp");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string baseName(const std::string &path)
|
static std::string baseName(const std::string &path)
|
||||||
|
|
|
@ -51,6 +51,9 @@ struct Config
|
||||||
bool allowSymlinks;
|
bool allowSymlinks;
|
||||||
bool pathCache;
|
bool pathCache;
|
||||||
|
|
||||||
|
std::string dataPathOrg;
|
||||||
|
std::string dataPathApp;
|
||||||
|
|
||||||
std::string iconPath;
|
std::string iconPath;
|
||||||
std::string titleLanguage;
|
std::string titleLanguage;
|
||||||
|
|
||||||
|
@ -82,6 +85,10 @@ struct Config
|
||||||
std::string title;
|
std::string title;
|
||||||
} game;
|
} game;
|
||||||
|
|
||||||
|
/* Internal */
|
||||||
|
std::string customDataPath;
|
||||||
|
std::string commonDataPath;
|
||||||
|
|
||||||
Config();
|
Config();
|
||||||
|
|
||||||
void read(int argc, char *argv[]);
|
void read(int argc, char *argv[]);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include "sharedstate.h"
|
#include "sharedstate.h"
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
|
#include "settingsmenu.h"
|
||||||
#include "debugwriter.h"
|
#include "debugwriter.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -37,7 +38,7 @@ bool EventThread::keyStates[] = { false };
|
||||||
|
|
||||||
EventThread::JoyState EventThread::joyState =
|
EventThread::JoyState EventThread::joyState =
|
||||||
{
|
{
|
||||||
0, 0, { false }
|
{ 0 }, { false }
|
||||||
};
|
};
|
||||||
|
|
||||||
EventThread::MouseState EventThread::mouseState =
|
EventThread::MouseState EventThread::mouseState =
|
||||||
|
@ -108,6 +109,8 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
|
|
||||||
bool resetting = false;
|
bool resetting = false;
|
||||||
|
|
||||||
|
SettingsMenu *sMenu = 0;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!SDL_WaitEvent(&event))
|
if (!SDL_WaitEvent(&event))
|
||||||
|
@ -116,6 +119,19 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sMenu && sMenu->onEvent(event))
|
||||||
|
{
|
||||||
|
if (sMenu->destroyReq())
|
||||||
|
{
|
||||||
|
delete sMenu;
|
||||||
|
sMenu = 0;
|
||||||
|
|
||||||
|
updateCursorState(cursorInWindow && windowFocused);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
switch (event.type)
|
switch (event.type)
|
||||||
{
|
{
|
||||||
case SDL_WINDOWEVENT :
|
case SDL_WINDOWEVENT :
|
||||||
|
@ -129,14 +145,14 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
case SDL_WINDOWEVENT_ENTER :
|
case SDL_WINDOWEVENT_ENTER :
|
||||||
cursorInWindow = true;
|
cursorInWindow = true;
|
||||||
mouseState.inWindow = true;
|
mouseState.inWindow = true;
|
||||||
updateCursorState(cursorInWindow && windowFocused);
|
updateCursorState(cursorInWindow && windowFocused && !sMenu);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_WINDOWEVENT_LEAVE :
|
case SDL_WINDOWEVENT_LEAVE :
|
||||||
cursorInWindow = false;
|
cursorInWindow = false;
|
||||||
mouseState.inWindow = false;
|
mouseState.inWindow = false;
|
||||||
updateCursorState(cursorInWindow && windowFocused);
|
updateCursorState(cursorInWindow && windowFocused && !sMenu);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -147,13 +163,13 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
|
|
||||||
case SDL_WINDOWEVENT_FOCUS_GAINED :
|
case SDL_WINDOWEVENT_FOCUS_GAINED :
|
||||||
windowFocused = true;
|
windowFocused = true;
|
||||||
updateCursorState(cursorInWindow && windowFocused);
|
updateCursorState(cursorInWindow && windowFocused && !sMenu);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_WINDOWEVENT_FOCUS_LOST :
|
case SDL_WINDOWEVENT_FOCUS_LOST :
|
||||||
windowFocused = false;
|
windowFocused = false;
|
||||||
updateCursorState(cursorInWindow && windowFocused);
|
updateCursorState(cursorInWindow && windowFocused && !sMenu);
|
||||||
resetInputStates();
|
resetInputStates();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -181,6 +197,17 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.key.keysym.scancode == SDL_SCANCODE_F1)
|
||||||
|
{
|
||||||
|
if (!sMenu)
|
||||||
|
{
|
||||||
|
sMenu = new SettingsMenu(rtData);
|
||||||
|
updateCursorState(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
sMenu->raise();
|
||||||
|
}
|
||||||
|
|
||||||
if (event.key.keysym.scancode == SDL_SCANCODE_F2)
|
if (event.key.keysym.scancode == SDL_SCANCODE_F2)
|
||||||
{
|
{
|
||||||
if (!fps.displaying)
|
if (!fps.displaying)
|
||||||
|
@ -248,11 +275,7 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_JOYAXISMOTION :
|
case SDL_JOYAXISMOTION :
|
||||||
if (event.jaxis.axis == 0)
|
joyState.axis[event.jaxis.axis] = event.jaxis.value;
|
||||||
joyState.xAxis = event.jaxis.value;
|
|
||||||
else
|
|
||||||
joyState.yAxis = event.jaxis.value;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_JOYDEVICEADDED :
|
case SDL_JOYDEVICEADDED :
|
||||||
|
@ -333,6 +356,8 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
|
|
||||||
if (SDL_JoystickGetAttached(js))
|
if (SDL_JoystickGetAttached(js))
|
||||||
SDL_JoystickClose(js);
|
SDL_JoystickClose(js);
|
||||||
|
|
||||||
|
delete sMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventThread::cleanup()
|
void EventThread::cleanup()
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "etc-internal.h"
|
#include "etc-internal.h"
|
||||||
#include "sdl-util.h"
|
#include "sdl-util.h"
|
||||||
|
#include "keybindings.h"
|
||||||
|
|
||||||
#include <SDL_scancode.h>
|
#include <SDL_scancode.h>
|
||||||
#include <SDL_joystick.h>
|
#include <SDL_joystick.h>
|
||||||
|
@ -45,10 +46,8 @@ public:
|
||||||
|
|
||||||
struct JoyState
|
struct JoyState
|
||||||
{
|
{
|
||||||
int xAxis;
|
int axis[256];
|
||||||
int yAxis;
|
bool buttons[256];
|
||||||
|
|
||||||
bool buttons[16];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static JoyState joyState;
|
static JoyState joyState;
|
||||||
|
@ -155,6 +154,55 @@ struct WindowSizeNotify
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BindingNotify
|
||||||
|
{
|
||||||
|
BindingNotify()
|
||||||
|
{
|
||||||
|
mut = SDL_CreateMutex();
|
||||||
|
}
|
||||||
|
~BindingNotify()
|
||||||
|
{
|
||||||
|
SDL_DestroyMutex(mut);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool poll(BDescVec &out) const
|
||||||
|
{
|
||||||
|
if (!changed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SDL_LockMutex(mut);
|
||||||
|
|
||||||
|
out = data;
|
||||||
|
changed.clear();
|
||||||
|
|
||||||
|
SDL_UnlockMutex(mut);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get(BDescVec &out) const
|
||||||
|
{
|
||||||
|
SDL_LockMutex(mut);
|
||||||
|
out = data;
|
||||||
|
SDL_UnlockMutex(mut);
|
||||||
|
}
|
||||||
|
|
||||||
|
void post(const BDescVec &d)
|
||||||
|
{
|
||||||
|
SDL_LockMutex(mut);
|
||||||
|
|
||||||
|
changed.set();
|
||||||
|
data = d;
|
||||||
|
|
||||||
|
SDL_UnlockMutex(mut);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDL_mutex *mut;
|
||||||
|
BDescVec data;
|
||||||
|
mutable AtomicFlag changed;
|
||||||
|
};
|
||||||
|
|
||||||
struct RGSSThreadData
|
struct RGSSThreadData
|
||||||
{
|
{
|
||||||
/* Main thread sets this to request RGSS thread to terminate */
|
/* Main thread sets this to request RGSS thread to terminate */
|
||||||
|
@ -171,6 +219,7 @@ struct RGSSThreadData
|
||||||
|
|
||||||
EventThread *ethread;
|
EventThread *ethread;
|
||||||
WindowSizeNotify windowSizeMsg;
|
WindowSizeNotify windowSizeMsg;
|
||||||
|
BindingNotify bindingUpdateMsg;
|
||||||
|
|
||||||
const char *argv0;
|
const char *argv0;
|
||||||
|
|
||||||
|
|
|
@ -195,6 +195,13 @@ bool SharedFontState::fontPresent(std::string family)
|
||||||
return !(set.regular.empty() && set.other.empty());
|
return !(set.regular.empty() && set.other.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_TTF_Font *SharedFontState::openBundled(int size)
|
||||||
|
{
|
||||||
|
SDL_RWops *ops = openBundledFont();
|
||||||
|
|
||||||
|
return TTF_OpenFontRW(ops, 1, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct FontPrivate
|
struct FontPrivate
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,6 +49,8 @@ public:
|
||||||
|
|
||||||
bool fontPresent(std::string family);
|
bool fontPresent(std::string family);
|
||||||
|
|
||||||
|
static _TTF_Font *openBundled(int size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SharedFontStatePrivate *p;
|
SharedFontStatePrivate *p;
|
||||||
};
|
};
|
||||||
|
|
225
src/input.cpp
225
src/input.cpp
|
@ -22,6 +22,7 @@
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "sharedstate.h"
|
#include "sharedstate.h"
|
||||||
#include "eventthread.h"
|
#include "eventthread.h"
|
||||||
|
#include "keybindings.h"
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#define BUTTON_CODE_COUNT 24
|
#define BUTTON_CODE_COUNT 24
|
||||||
|
|
||||||
|
@ -52,12 +54,6 @@ struct KbBindingData
|
||||||
Input::ButtonCode target;
|
Input::ButtonCode target;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JsBindingData
|
|
||||||
{
|
|
||||||
int source;
|
|
||||||
Input::ButtonCode target;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Binding
|
struct Binding
|
||||||
{
|
{
|
||||||
Binding(Input::ButtonCode target = Input::None)
|
Binding(Input::ButtonCode target = Input::None)
|
||||||
|
@ -82,6 +78,15 @@ struct KbBinding : public Binding
|
||||||
|
|
||||||
bool sourceActive() const
|
bool sourceActive() const
|
||||||
{
|
{
|
||||||
|
/* Special case aliases */
|
||||||
|
if (source == SDL_SCANCODE_LSHIFT)
|
||||||
|
return EventThread::keyStates[source]
|
||||||
|
|| EventThread::keyStates[SDL_SCANCODE_RSHIFT];
|
||||||
|
|
||||||
|
if (source == SDL_SCANCODE_RETURN)
|
||||||
|
return EventThread::keyStates[source]
|
||||||
|
|| EventThread::keyStates[SDL_SCANCODE_KP_ENTER];
|
||||||
|
|
||||||
return EventThread::keyStates[source];
|
return EventThread::keyStates[source];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,11 +105,6 @@ struct JsButtonBinding : public Binding
|
||||||
{
|
{
|
||||||
JsButtonBinding() {}
|
JsButtonBinding() {}
|
||||||
|
|
||||||
JsButtonBinding(const JsBindingData &data)
|
|
||||||
: Binding(data.target),
|
|
||||||
source(data.source)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool sourceActive() const
|
bool sourceActive() const
|
||||||
{
|
{
|
||||||
return EventThread::joyState.buttons[source];
|
return EventThread::joyState.buttons[source];
|
||||||
|
@ -115,7 +115,7 @@ struct JsButtonBinding : public Binding
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int source;
|
uint8_t source;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Joystick axis binding */
|
/* Joystick axis binding */
|
||||||
|
@ -123,17 +123,22 @@ struct JsAxisBinding : public Binding
|
||||||
{
|
{
|
||||||
JsAxisBinding() {}
|
JsAxisBinding() {}
|
||||||
|
|
||||||
JsAxisBinding(int *source,
|
JsAxisBinding(uint8_t source,
|
||||||
int compareValue,
|
AxisDir dir,
|
||||||
Input::ButtonCode target)
|
Input::ButtonCode target)
|
||||||
: Binding(target),
|
: Binding(target),
|
||||||
source(source),
|
source(source),
|
||||||
compareValue(compareValue)
|
dir(dir)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool sourceActive() const
|
bool sourceActive() const
|
||||||
{
|
{
|
||||||
return (*source == compareValue);
|
int val = EventThread::joyState.axis[source];
|
||||||
|
|
||||||
|
if (dir == Negative)
|
||||||
|
return val < -JAXIS_THRESHOLD;
|
||||||
|
else /* dir == Positive */
|
||||||
|
return val > JAXIS_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sourceRepeatable() const
|
bool sourceRepeatable() const
|
||||||
|
@ -141,8 +146,8 @@ struct JsAxisBinding : public Binding
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int *source;
|
uint8_t source;
|
||||||
int compareValue;
|
AxisDir dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mouse button binding */
|
/* Mouse button binding */
|
||||||
|
@ -172,10 +177,6 @@ struct MsBinding : public Binding
|
||||||
/* Not rebindable */
|
/* Not rebindable */
|
||||||
static const KbBindingData staticKbBindings[] =
|
static const KbBindingData staticKbBindings[] =
|
||||||
{
|
{
|
||||||
{ SDL_SCANCODE_LEFT, Input::Left },
|
|
||||||
{ SDL_SCANCODE_RIGHT, Input::Right },
|
|
||||||
{ SDL_SCANCODE_UP, Input::Up },
|
|
||||||
{ SDL_SCANCODE_DOWN, Input::Down },
|
|
||||||
{ SDL_SCANCODE_LSHIFT, Input::Shift },
|
{ SDL_SCANCODE_LSHIFT, Input::Shift },
|
||||||
{ SDL_SCANCODE_RSHIFT, Input::Shift },
|
{ SDL_SCANCODE_RSHIFT, Input::Shift },
|
||||||
{ SDL_SCANCODE_LCTRL, Input::Ctrl },
|
{ SDL_SCANCODE_LCTRL, Input::Ctrl },
|
||||||
|
@ -191,61 +192,6 @@ static const KbBindingData staticKbBindings[] =
|
||||||
|
|
||||||
static elementsN(staticKbBindings);
|
static elementsN(staticKbBindings);
|
||||||
|
|
||||||
/* Rebindable */
|
|
||||||
static const KbBindingData defaultKbBindings[] =
|
|
||||||
{
|
|
||||||
{ SDL_SCANCODE_SPACE, Input::C },
|
|
||||||
{ SDL_SCANCODE_RETURN, Input::C },
|
|
||||||
{ SDL_SCANCODE_KP_ENTER, Input::C }, /* Treated as alias of RETURN */
|
|
||||||
{ SDL_SCANCODE_ESCAPE, Input::B },
|
|
||||||
{ SDL_SCANCODE_KP_0, Input::B },
|
|
||||||
{ SDL_SCANCODE_LSHIFT, Input::A },
|
|
||||||
{ SDL_SCANCODE_RSHIFT, Input::A },
|
|
||||||
{ SDL_SCANCODE_X, Input::B },
|
|
||||||
{ SDL_SCANCODE_B, Input::None },
|
|
||||||
{ SDL_SCANCODE_D, Input::Z },
|
|
||||||
{ SDL_SCANCODE_Q, Input::L },
|
|
||||||
{ SDL_SCANCODE_W, Input::R },
|
|
||||||
{ SDL_SCANCODE_V, Input::None },
|
|
||||||
{ SDL_SCANCODE_A, Input::X },
|
|
||||||
{ SDL_SCANCODE_S, Input::Y }
|
|
||||||
};
|
|
||||||
|
|
||||||
/* RGSS1 */
|
|
||||||
static const KbBindingData defaultKbBindings1[] =
|
|
||||||
{
|
|
||||||
{ SDL_SCANCODE_Z, Input::A },
|
|
||||||
{ SDL_SCANCODE_C, Input::C },
|
|
||||||
};
|
|
||||||
|
|
||||||
/* RGSS2 and higher */
|
|
||||||
static const KbBindingData defaultKbBindings2[] =
|
|
||||||
{
|
|
||||||
{ SDL_SCANCODE_Z, Input::C },
|
|
||||||
{ SDL_SCANCODE_C, Input::None },
|
|
||||||
};
|
|
||||||
|
|
||||||
static elementsN(defaultKbBindings);
|
|
||||||
static elementsN(defaultKbBindings1);
|
|
||||||
static elementsN(defaultKbBindings2);
|
|
||||||
|
|
||||||
/* Rebindable */
|
|
||||||
static const JsBindingData defaultJsBindings[] =
|
|
||||||
{
|
|
||||||
{ 0, Input::A },
|
|
||||||
{ 1, Input::B },
|
|
||||||
{ 2, Input::C },
|
|
||||||
{ 3, Input::X },
|
|
||||||
{ 4, Input::Y },
|
|
||||||
{ 5, Input::Z },
|
|
||||||
{ 6, Input::L },
|
|
||||||
{ 7, Input::R },
|
|
||||||
{ 8, Input::None },
|
|
||||||
{ 9, Input::None }
|
|
||||||
};
|
|
||||||
|
|
||||||
static elementsN(defaultJsBindings);
|
|
||||||
|
|
||||||
/* Maps ButtonCode enum values to indices
|
/* Maps ButtonCode enum values to indices
|
||||||
* in the button state array */
|
* in the button state array */
|
||||||
static const int mapToIndex[] =
|
static const int mapToIndex[] =
|
||||||
|
@ -292,6 +238,7 @@ static const Input::ButtonCode otherDirs[4][3] =
|
||||||
|
|
||||||
struct InputPrivate
|
struct InputPrivate
|
||||||
{
|
{
|
||||||
|
std::vector<KbBinding> kbStatBindings;
|
||||||
std::vector<KbBinding> kbBindings;
|
std::vector<KbBinding> kbBindings;
|
||||||
std::vector<JsAxisBinding> jsABindings;
|
std::vector<JsAxisBinding> jsABindings;
|
||||||
std::vector<JsButtonBinding> jsBBindings;
|
std::vector<JsButtonBinding> jsBBindings;
|
||||||
|
@ -320,12 +267,14 @@ struct InputPrivate
|
||||||
} dir8Data;
|
} dir8Data;
|
||||||
|
|
||||||
|
|
||||||
InputPrivate()
|
InputPrivate(const RGSSThreadData &rtData)
|
||||||
{
|
{
|
||||||
initKbBindings();
|
initStaticKbBindings();
|
||||||
initJsBindings();
|
|
||||||
initMsBindings();
|
initMsBindings();
|
||||||
|
|
||||||
|
/* Main thread should have these posted by now */
|
||||||
|
checkBindingChange(rtData);
|
||||||
|
|
||||||
states = stateArray;
|
states = stateArray;
|
||||||
statesOld = stateArray + BUTTON_CODE_COUNT;
|
statesOld = stateArray + BUTTON_CODE_COUNT;
|
||||||
|
|
||||||
|
@ -378,51 +327,90 @@ struct InputPrivate
|
||||||
memset(states, 0, size);
|
memset(states, 0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initKbBindings()
|
void checkBindingChange(const RGSSThreadData &rtData)
|
||||||
{
|
{
|
||||||
kbBindings.clear();
|
BDescVec d;
|
||||||
|
|
||||||
for (size_t i = 0; i < staticKbBindingsN; ++i)
|
if (!rtData.bindingUpdateMsg.poll(d))
|
||||||
kbBindings.push_back(KbBinding(staticKbBindings[i]));
|
return;
|
||||||
|
|
||||||
for (size_t i = 0; i < defaultKbBindingsN; ++i)
|
applyBindingDesc(d);
|
||||||
kbBindings.push_back(KbBinding(defaultKbBindings[i]));
|
|
||||||
|
|
||||||
if (rgssVer == 1)
|
|
||||||
for (size_t i = 0; i < defaultKbBindings1N; ++i)
|
|
||||||
kbBindings.push_back(KbBinding(defaultKbBindings1[i]));
|
|
||||||
else
|
|
||||||
for (size_t i = 0; i < defaultKbBindings2N; ++i)
|
|
||||||
kbBindings.push_back(KbBinding(defaultKbBindings2[i]));
|
|
||||||
|
|
||||||
/* Add to binging array */
|
|
||||||
for (size_t i = 0; i < kbBindings.size(); ++i)
|
|
||||||
bindings.push_back(&kbBindings[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initJsBindings()
|
template<class B>
|
||||||
|
void appendBindings(std::vector<B> &bind)
|
||||||
{
|
{
|
||||||
/* Create axis bindings */
|
for (size_t i = 0; i < bind.size(); ++i)
|
||||||
jsABindings.resize(4);
|
bindings.push_back(&bind[i]);
|
||||||
|
}
|
||||||
|
|
||||||
size_t i = 0;
|
void applyBindingDesc(const BDescVec &d)
|
||||||
jsABindings[i++] = JsAxisBinding(&EventThread::joyState.xAxis, 0x7FFF, Input::Right);
|
{
|
||||||
jsABindings[i++] = JsAxisBinding(&EventThread::joyState.xAxis, -0x8000, Input::Left);
|
kbBindings.clear();
|
||||||
jsABindings[i++] = JsAxisBinding(&EventThread::joyState.yAxis, 0x7FFF, Input::Down);
|
jsABindings.clear();
|
||||||
jsABindings[i++] = JsAxisBinding(&EventThread::joyState.yAxis, -0x8000, Input::Up);
|
jsBBindings.clear();
|
||||||
|
|
||||||
/* Create button bindings */
|
for (size_t i = 0; i < d.size(); ++i)
|
||||||
jsBBindings.resize(defaultJsBindingsN);
|
{
|
||||||
|
const BindingDesc &desc = d[i];
|
||||||
|
const SourceDesc &src = desc.src;
|
||||||
|
|
||||||
for (size_t i = 0; i < defaultJsBindingsN; ++i)
|
if (desc.target == Input::None)
|
||||||
jsBBindings[i] = JsButtonBinding(defaultJsBindings[i]);
|
continue;
|
||||||
|
|
||||||
/* Add to binging array */
|
switch (desc.src.type)
|
||||||
for (size_t i = 0; i < jsABindings.size(); ++i)
|
{
|
||||||
bindings.push_back(&jsABindings[i]);
|
case Invalid :
|
||||||
|
break;
|
||||||
|
case Key :
|
||||||
|
{
|
||||||
|
KbBinding bind;
|
||||||
|
bind.source = src.d.scan;
|
||||||
|
bind.target = desc.target;
|
||||||
|
kbBindings.push_back(bind);
|
||||||
|
|
||||||
for (size_t i = 0; i < jsBBindings.size(); ++i)
|
break;
|
||||||
bindings.push_back(&jsBBindings[i]);
|
}
|
||||||
|
case JAxis :
|
||||||
|
{
|
||||||
|
JsAxisBinding bind;
|
||||||
|
bind.source = src.d.ja.axis;
|
||||||
|
bind.dir = src.d.ja.dir;
|
||||||
|
bind.target = desc.target;
|
||||||
|
jsABindings.push_back(bind);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JButton :
|
||||||
|
{
|
||||||
|
JsButtonBinding bind;
|
||||||
|
bind.source = src.d.jb;
|
||||||
|
bind.target = desc.target;
|
||||||
|
jsBBindings.push_back(bind);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default :
|
||||||
|
assert(!"unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bindings.clear();
|
||||||
|
|
||||||
|
appendBindings(kbStatBindings);
|
||||||
|
appendBindings(msBindings);
|
||||||
|
|
||||||
|
appendBindings(kbBindings);
|
||||||
|
appendBindings(jsABindings);
|
||||||
|
appendBindings(jsBBindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initStaticKbBindings()
|
||||||
|
{
|
||||||
|
kbStatBindings.clear();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < staticKbBindingsN; ++i)
|
||||||
|
kbStatBindings.push_back(KbBinding(staticKbBindings[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void initMsBindings()
|
void initMsBindings()
|
||||||
|
@ -433,10 +421,6 @@ struct InputPrivate
|
||||||
msBindings[i++] = MsBinding(SDL_BUTTON_LEFT, Input::MouseLeft);
|
msBindings[i++] = MsBinding(SDL_BUTTON_LEFT, Input::MouseLeft);
|
||||||
msBindings[i++] = MsBinding(SDL_BUTTON_MIDDLE, Input::MouseMiddle);
|
msBindings[i++] = MsBinding(SDL_BUTTON_MIDDLE, Input::MouseMiddle);
|
||||||
msBindings[i++] = MsBinding(SDL_BUTTON_RIGHT, Input::MouseRight);
|
msBindings[i++] = MsBinding(SDL_BUTTON_RIGHT, Input::MouseRight);
|
||||||
|
|
||||||
/* Add to binding array */
|
|
||||||
for (size_t i = 0; i < msBindings.size(); ++i)
|
|
||||||
bindings.push_back(&msBindings[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pollBindings(Input::ButtonCode &repeatCand)
|
void pollBindings(Input::ButtonCode &repeatCand)
|
||||||
|
@ -564,14 +548,15 @@ struct InputPrivate
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Input::Input()
|
Input::Input(const RGSSThreadData &rtData)
|
||||||
{
|
{
|
||||||
p = new InputPrivate;
|
p = new InputPrivate(rtData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::update()
|
void Input::update()
|
||||||
{
|
{
|
||||||
shState->checkShutdown();
|
shState->checkShutdown();
|
||||||
|
p->checkBindingChange(shState->rtData());
|
||||||
|
|
||||||
p->swapBuffers();
|
p->swapBuffers();
|
||||||
p->clearBuffer();
|
p->clearBuffer();
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#define INPUT_H
|
#define INPUT_H
|
||||||
|
|
||||||
struct InputPrivate;
|
struct InputPrivate;
|
||||||
|
struct RGSSThreadData;
|
||||||
|
|
||||||
class Input
|
class Input
|
||||||
{
|
{
|
||||||
|
@ -59,7 +60,7 @@ public:
|
||||||
int mouseY();
|
int mouseY();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Input();
|
Input(const RGSSThreadData &rtData);
|
||||||
~Input();
|
~Input();
|
||||||
|
|
||||||
friend struct SharedStatePrivate;
|
friend struct SharedStatePrivate;
|
||||||
|
|
|
@ -0,0 +1,311 @@
|
||||||
|
/*
|
||||||
|
** keybindings.cpp
|
||||||
|
**
|
||||||
|
** This file is part of mkxp.
|
||||||
|
**
|
||||||
|
** Copyright (C) 2014 Jonas Kulla <Nyocurio@gmail.com>
|
||||||
|
**
|
||||||
|
** mkxp is free software: you can redistribute it and/or modify
|
||||||
|
** it under the terms of the GNU General Public License as published by
|
||||||
|
** the Free Software Foundation, either version 2 of the License, or
|
||||||
|
** (at your option) any later version.
|
||||||
|
**
|
||||||
|
** mkxp is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "keybindings.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
struct KbBindingData
|
||||||
|
{
|
||||||
|
SDL_Scancode source;
|
||||||
|
Input::ButtonCode target;
|
||||||
|
|
||||||
|
void add(BDescVec &d) const
|
||||||
|
{
|
||||||
|
SourceDesc src;
|
||||||
|
src.type = Key;
|
||||||
|
src.d.scan = source;
|
||||||
|
|
||||||
|
BindingDesc desc;
|
||||||
|
desc.src = src;
|
||||||
|
desc.target = target;
|
||||||
|
|
||||||
|
d.push_back(desc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JsBindingData
|
||||||
|
{
|
||||||
|
int source;
|
||||||
|
Input::ButtonCode target;
|
||||||
|
|
||||||
|
void add(BDescVec &d) const
|
||||||
|
{
|
||||||
|
SourceDesc src;
|
||||||
|
src.type = JButton;
|
||||||
|
src.d.jb = source;
|
||||||
|
|
||||||
|
BindingDesc desc;
|
||||||
|
desc.src = src;
|
||||||
|
desc.target = target;
|
||||||
|
|
||||||
|
d.push_back(desc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Common */
|
||||||
|
static const KbBindingData defaultKbBindings[] =
|
||||||
|
{
|
||||||
|
{ SDL_SCANCODE_LEFT, Input::Left },
|
||||||
|
{ SDL_SCANCODE_RIGHT, Input::Right },
|
||||||
|
{ SDL_SCANCODE_UP, Input::Up },
|
||||||
|
{ SDL_SCANCODE_DOWN, Input::Down },
|
||||||
|
{ SDL_SCANCODE_SPACE, Input::C },
|
||||||
|
{ SDL_SCANCODE_RETURN, Input::C },
|
||||||
|
{ SDL_SCANCODE_ESCAPE, Input::B },
|
||||||
|
{ SDL_SCANCODE_KP_0, Input::B },
|
||||||
|
{ SDL_SCANCODE_LSHIFT, Input::A },
|
||||||
|
{ SDL_SCANCODE_X, Input::B },
|
||||||
|
{ SDL_SCANCODE_D, Input::Z },
|
||||||
|
{ SDL_SCANCODE_Q, Input::L },
|
||||||
|
{ SDL_SCANCODE_W, Input::R },
|
||||||
|
{ SDL_SCANCODE_A, Input::X },
|
||||||
|
{ SDL_SCANCODE_S, Input::Y }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* RGSS1 */
|
||||||
|
static const KbBindingData defaultKbBindings1[] =
|
||||||
|
{
|
||||||
|
{ SDL_SCANCODE_Z, Input::A },
|
||||||
|
{ SDL_SCANCODE_C, Input::C },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* RGSS2 and higher */
|
||||||
|
static const KbBindingData defaultKbBindings2[] =
|
||||||
|
{
|
||||||
|
{ SDL_SCANCODE_Z, Input::C }
|
||||||
|
};
|
||||||
|
|
||||||
|
static elementsN(defaultKbBindings);
|
||||||
|
static elementsN(defaultKbBindings1);
|
||||||
|
static elementsN(defaultKbBindings2);
|
||||||
|
|
||||||
|
static const JsBindingData defaultJsBindings[] =
|
||||||
|
{
|
||||||
|
{ 0, Input::A },
|
||||||
|
{ 1, Input::B },
|
||||||
|
{ 2, Input::C },
|
||||||
|
{ 3, Input::X },
|
||||||
|
{ 4, Input::Y },
|
||||||
|
{ 5, Input::Z },
|
||||||
|
{ 6, Input::L },
|
||||||
|
{ 7, Input::R }
|
||||||
|
};
|
||||||
|
|
||||||
|
static elementsN(defaultJsBindings);
|
||||||
|
|
||||||
|
static void addAxisBinding(BDescVec &d, uint8_t axis, AxisDir dir, Input::ButtonCode target)
|
||||||
|
{
|
||||||
|
SourceDesc src;
|
||||||
|
src.type = JAxis;
|
||||||
|
src.d.ja.axis = axis;
|
||||||
|
src.d.ja.dir = dir;
|
||||||
|
|
||||||
|
BindingDesc desc;
|
||||||
|
desc.src = src;
|
||||||
|
desc.target = target;
|
||||||
|
|
||||||
|
d.push_back(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
BDescVec genDefaultBindings(const Config &conf)
|
||||||
|
{
|
||||||
|
BDescVec d;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < defaultKbBindingsN; ++i)
|
||||||
|
defaultKbBindings[i].add(d);
|
||||||
|
|
||||||
|
if (conf.rgssVersion == 1)
|
||||||
|
for (size_t i = 0; i < defaultKbBindings1N; ++i)
|
||||||
|
defaultKbBindings1[i].add(d);
|
||||||
|
else
|
||||||
|
for (size_t i = 0; i < defaultKbBindings2N; ++i)
|
||||||
|
defaultKbBindings2[i].add(d);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < defaultJsBindingsN; ++i)
|
||||||
|
defaultJsBindings[i].add(d);
|
||||||
|
|
||||||
|
addAxisBinding(d, 0, Negative, Input::Left );
|
||||||
|
addAxisBinding(d, 0, Positive, Input::Right);
|
||||||
|
addAxisBinding(d, 1, Negative, Input::Up );
|
||||||
|
addAxisBinding(d, 1, Positive, Input::Down );
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FORMAT_VER 1
|
||||||
|
|
||||||
|
struct Header
|
||||||
|
{
|
||||||
|
uint32_t formVer;
|
||||||
|
uint32_t rgssVer;
|
||||||
|
uint32_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void buildPath(const std::string &dir, uint32_t rgssVersion,
|
||||||
|
char *out, size_t outSize)
|
||||||
|
{
|
||||||
|
snprintf(out, outSize, "%s/keybindings.mkxp%u", dir.c_str(), rgssVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool writeBindings(const BDescVec &d, const std::string &dir,
|
||||||
|
uint32_t rgssVersion)
|
||||||
|
{
|
||||||
|
if (dir.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char path[1024];
|
||||||
|
buildPath(dir, rgssVersion, path, sizeof(path));
|
||||||
|
|
||||||
|
FILE *f = fopen(path, "w");
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Header hd;
|
||||||
|
hd.formVer = FORMAT_VER;
|
||||||
|
hd.rgssVer = rgssVersion;
|
||||||
|
hd.count = d.size();
|
||||||
|
|
||||||
|
if (fwrite(&hd, sizeof(hd), 1, f) < 1)
|
||||||
|
{
|
||||||
|
fclose(f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fwrite(&d[0], sizeof(d[0]), hd.count, f) < hd.count)
|
||||||
|
{
|
||||||
|
fclose(f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void storeBindings(const BDescVec &d, const Config &conf)
|
||||||
|
{
|
||||||
|
if (writeBindings(d, conf.customDataPath, conf.rgssVersion))
|
||||||
|
return;
|
||||||
|
|
||||||
|
writeBindings(d, conf.commonDataPath, conf.rgssVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define READ(ptr, size, n, f) if (fread(ptr, size, n, f) < n) return false
|
||||||
|
|
||||||
|
static bool verifyDesc(const BindingDesc &desc)
|
||||||
|
{
|
||||||
|
const Input::ButtonCode codes[] =
|
||||||
|
{
|
||||||
|
Input::None,
|
||||||
|
Input::Down, Input::Left, Input::Right, Input::Up,
|
||||||
|
Input::A, Input::B, Input::C,
|
||||||
|
Input::X, Input::Y, Input::Z,
|
||||||
|
Input::L, Input::R,
|
||||||
|
Input::Shift, Input::Ctrl, Input::Alt,
|
||||||
|
Input::F5, Input::F6, Input::F7, Input::F8, Input::F9
|
||||||
|
};
|
||||||
|
|
||||||
|
elementsN(codes);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < codesN; ++i)
|
||||||
|
if (desc.target == codes[i])
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i == codesN)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const SourceDesc &src = desc.src;
|
||||||
|
|
||||||
|
switch (src.type)
|
||||||
|
{
|
||||||
|
case Invalid:
|
||||||
|
return true;
|
||||||
|
case Key:
|
||||||
|
return src.d.scan < SDL_NUM_SCANCODES;
|
||||||
|
case JButton:
|
||||||
|
return true;
|
||||||
|
case JAxis:
|
||||||
|
return src.d.ja.dir == Negative || src.d.ja.dir == Positive;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool readBindings(BDescVec &out, const std::string &dir,
|
||||||
|
uint32_t rgssVersion)
|
||||||
|
{
|
||||||
|
if (dir.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char path[1024];
|
||||||
|
buildPath(dir, rgssVersion, path, sizeof(path));
|
||||||
|
|
||||||
|
FILE *f = fopen(path, "r");
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Header hd;
|
||||||
|
if (fread(&hd, sizeof(hd), 1, f) < 1)
|
||||||
|
{
|
||||||
|
fclose(f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hd.formVer != FORMAT_VER)
|
||||||
|
return false;
|
||||||
|
if (hd.rgssVer != rgssVersion)
|
||||||
|
return false;
|
||||||
|
/* Arbitrary max value */
|
||||||
|
if (hd.count > 1024)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
out.resize(hd.count);
|
||||||
|
if (fread(&out[0], sizeof(out[0]), hd.count, f) < hd.count)
|
||||||
|
{
|
||||||
|
fclose(f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < hd.count; ++i)
|
||||||
|
if (!verifyDesc(out[i]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BDescVec loadBindings(const Config &conf)
|
||||||
|
{
|
||||||
|
BDescVec d;
|
||||||
|
|
||||||
|
if (readBindings(d, conf.customDataPath, conf.rgssVersion))
|
||||||
|
return d;
|
||||||
|
|
||||||
|
if (readBindings(d, conf.commonDataPath, conf.rgssVersion))
|
||||||
|
return d;
|
||||||
|
|
||||||
|
return genDefaultBindings(conf);
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
** keybindings.h
|
||||||
|
**
|
||||||
|
** This file is part of mkxp.
|
||||||
|
**
|
||||||
|
** Copyright (C) 2014 Jonas Kulla <Nyocurio@gmail.com>
|
||||||
|
**
|
||||||
|
** mkxp is free software: you can redistribute it and/or modify
|
||||||
|
** it under the terms of the GNU General Public License as published by
|
||||||
|
** the Free Software Foundation, either version 2 of the License, or
|
||||||
|
** (at your option) any later version.
|
||||||
|
**
|
||||||
|
** mkxp is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEYBINDINGS_H
|
||||||
|
#define KEYBINDINGS_H
|
||||||
|
|
||||||
|
#include "input.h"
|
||||||
|
|
||||||
|
#include <SDL_scancode.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
enum AxisDir
|
||||||
|
{
|
||||||
|
Negative,
|
||||||
|
Positive
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SourceType
|
||||||
|
{
|
||||||
|
Invalid,
|
||||||
|
Key,
|
||||||
|
JButton,
|
||||||
|
JAxis
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SourceDesc
|
||||||
|
{
|
||||||
|
SourceType type;
|
||||||
|
|
||||||
|
union Data
|
||||||
|
{
|
||||||
|
/* Keyboard scancode */
|
||||||
|
SDL_Scancode scan;
|
||||||
|
/* Joystick button index */
|
||||||
|
uint8_t jb;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/* Joystick axis index */
|
||||||
|
uint8_t axis;
|
||||||
|
/* Joystick axis direction */
|
||||||
|
AxisDir dir;
|
||||||
|
} ja;
|
||||||
|
} d;
|
||||||
|
|
||||||
|
bool operator==(const SourceDesc &o) const
|
||||||
|
{
|
||||||
|
if (type != o.type)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Invalid:
|
||||||
|
return true;
|
||||||
|
case Key:
|
||||||
|
return d.scan == o.d.scan;
|
||||||
|
case JButton:
|
||||||
|
return d.jb == o.d.jb;
|
||||||
|
case JAxis:
|
||||||
|
return (d.ja.axis == o.d.ja.axis) && (d.ja.dir == o.d.ja.dir);
|
||||||
|
default:
|
||||||
|
assert(!"unreachable");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const SourceDesc &o) const
|
||||||
|
{
|
||||||
|
return !(*this == o);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define JAXIS_THRESHOLD 0x4000
|
||||||
|
|
||||||
|
struct BindingDesc
|
||||||
|
{
|
||||||
|
SourceDesc src;
|
||||||
|
Input::ButtonCode target;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<BindingDesc> BDescVec;
|
||||||
|
struct Config;
|
||||||
|
|
||||||
|
BDescVec genDefaultBindings(const Config &conf);
|
||||||
|
|
||||||
|
void storeBindings(const BDescVec &d, const Config &conf);
|
||||||
|
BDescVec loadBindings(const Config &conf);
|
||||||
|
|
||||||
|
#endif // KEYBINDINGS_H
|
10
src/main.cpp
10
src/main.cpp
|
@ -238,7 +238,7 @@ int main(int argc, char *argv[])
|
||||||
SDL_SetHint("SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS", "0");
|
SDL_SetHint("SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS", "0");
|
||||||
|
|
||||||
SDL_Window *win;
|
SDL_Window *win;
|
||||||
Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
|
Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_FOCUS;
|
||||||
|
|
||||||
if (conf.winResizable)
|
if (conf.winResizable)
|
||||||
winFlags |= SDL_WINDOW_RESIZABLE;
|
winFlags |= SDL_WINDOW_RESIZABLE;
|
||||||
|
@ -268,6 +268,9 @@ int main(int argc, char *argv[])
|
||||||
EventThread eventThread;
|
EventThread eventThread;
|
||||||
RGSSThreadData rtData(&eventThread, argv[0], win, conf);
|
RGSSThreadData rtData(&eventThread, argv[0], win, conf);
|
||||||
|
|
||||||
|
/* Load and post key bindings */
|
||||||
|
rtData.bindingUpdateMsg.post(loadBindings(conf));
|
||||||
|
|
||||||
/* Start RGSS thread */
|
/* Start RGSS thread */
|
||||||
SDL_Thread *rgssThread =
|
SDL_Thread *rgssThread =
|
||||||
SDL_CreateThread(rgssThreadFun, "rgss", &rtData);
|
SDL_CreateThread(rgssThreadFun, "rgss", &rtData);
|
||||||
|
@ -310,6 +313,11 @@ int main(int argc, char *argv[])
|
||||||
/* Clean up any remainin events */
|
/* Clean up any remainin events */
|
||||||
eventThread.cleanup();
|
eventThread.cleanup();
|
||||||
|
|
||||||
|
/* Store key bindings */
|
||||||
|
BDescVec keyBinds;
|
||||||
|
rtData.bindingUpdateMsg.get(keyBinds);
|
||||||
|
storeBindings(keyBinds, rtData.config);
|
||||||
|
|
||||||
Debug() << "Shutting down.";
|
Debug() << "Shutting down.";
|
||||||
|
|
||||||
SDL_DestroyWindow(win);
|
SDL_DestroyWindow(win);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
** settingsmenu.h
|
||||||
|
**
|
||||||
|
** This file is part of mkxp.
|
||||||
|
**
|
||||||
|
** Copyright (C) 2014 Jonas Kulla <Nyocurio@gmail.com>
|
||||||
|
**
|
||||||
|
** mkxp is free software: you can redistribute it and/or modify
|
||||||
|
** it under the terms of the GNU General Public License as published by
|
||||||
|
** the Free Software Foundation, either version 2 of the License, or
|
||||||
|
** (at your option) any later version.
|
||||||
|
**
|
||||||
|
** mkxp is distributed in the hope that it will be useful,
|
||||||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
** GNU General Public License for more details.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the GNU General Public License
|
||||||
|
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SETTINGSMENU_H
|
||||||
|
#define SETTINGSMENU_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct SettingsMenuPrivate;
|
||||||
|
struct RGSSThreadData;
|
||||||
|
union SDL_Event;
|
||||||
|
|
||||||
|
class SettingsMenu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SettingsMenu(RGSSThreadData &rtData);
|
||||||
|
~SettingsMenu();
|
||||||
|
|
||||||
|
/* Returns true if the event was consumed */
|
||||||
|
bool onEvent(const SDL_Event &event);
|
||||||
|
void raise();
|
||||||
|
bool destroyReq() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SettingsMenuPrivate *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SETTINGSMENU_H
|
|
@ -106,6 +106,7 @@ struct SharedStatePrivate
|
||||||
config(threadData->config),
|
config(threadData->config),
|
||||||
midiState(threadData->config),
|
midiState(threadData->config),
|
||||||
graphics(threadData),
|
graphics(threadData),
|
||||||
|
input(*threadData),
|
||||||
audio(threadData->config),
|
audio(threadData->config),
|
||||||
fontState(threadData->config),
|
fontState(threadData->config),
|
||||||
stampCounter(0)
|
stampCounter(0)
|
||||||
|
|
Loading…
Reference in New Issue