Introduce F1 menu to reconfigure key bindings at runtime
This commit is contained in:
		
							parent
							
								
									af145c3a01
								
							
						
					
					
						commit
						dd73db2e9d
					
				
					 17 changed files with 1837 additions and 136 deletions
				
			
		| 
						 | 
				
			
			@ -25,6 +25,8 @@
 | 
			
		|||
#include <boost/program_options/parsers.hpp>
 | 
			
		||||
#include <boost/program_options/variables_map.hpp>
 | 
			
		||||
 | 
			
		||||
#include <SDL_filesystem.h>
 | 
			
		||||
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -118,6 +120,15 @@ static bool validUtf8(const char *string)
 | 
			
		|||
	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;
 | 
			
		||||
namespace po = boost::program_options;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -167,6 +178,8 @@ void Config::read(int argc, char *argv[])
 | 
			
		|||
	PO_DESC(anyAltToggleFS, bool) \
 | 
			
		||||
	PO_DESC(enableReset, bool) \
 | 
			
		||||
	PO_DESC(allowSymlinks, bool) \
 | 
			
		||||
	PO_DESC(dataPathOrg, std::string) \
 | 
			
		||||
	PO_DESC(dataPathApp, std::string) \
 | 
			
		||||
	PO_DESC(iconPath, std::string) \
 | 
			
		||||
	PO_DESC(titleLanguage, std::string) \
 | 
			
		||||
	PO_DESC(midi.soundFont, std::string) \
 | 
			
		||||
| 
						 | 
				
			
			@ -243,6 +256,11 @@ void Config::read(int argc, char *argv[])
 | 
			
		|||
	rgssVersion = clamp(rgssVersion, 0, 3);
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,6 +51,9 @@ struct Config
 | 
			
		|||
	bool allowSymlinks;
 | 
			
		||||
	bool pathCache;
 | 
			
		||||
 | 
			
		||||
	std::string dataPathOrg;
 | 
			
		||||
	std::string dataPathApp;
 | 
			
		||||
 | 
			
		||||
	std::string iconPath;
 | 
			
		||||
	std::string titleLanguage;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -82,6 +85,10 @@ struct Config
 | 
			
		|||
		std::string title;
 | 
			
		||||
	} game;
 | 
			
		||||
 | 
			
		||||
	/* Internal */
 | 
			
		||||
	std::string customDataPath;
 | 
			
		||||
	std::string commonDataPath;
 | 
			
		||||
 | 
			
		||||
	Config();
 | 
			
		||||
 | 
			
		||||
	void read(int argc, char *argv[]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,7 @@
 | 
			
		|||
 | 
			
		||||
#include "sharedstate.h"
 | 
			
		||||
#include "graphics.h"
 | 
			
		||||
#include "settingsmenu.h"
 | 
			
		||||
#include "debugwriter.h"
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +38,7 @@ bool EventThread::keyStates[] = { false };
 | 
			
		|||
 | 
			
		||||
EventThread::JoyState EventThread::joyState =
 | 
			
		||||
{
 | 
			
		||||
	0, 0, { false }
 | 
			
		||||
	{ 0 }, { false }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
EventThread::MouseState EventThread::mouseState =
 | 
			
		||||
| 
						 | 
				
			
			@ -108,6 +109,8 @@ void EventThread::process(RGSSThreadData &rtData)
 | 
			
		|||
 | 
			
		||||
	bool resetting = false;
 | 
			
		||||
 | 
			
		||||
	SettingsMenu *sMenu = 0;
 | 
			
		||||
 | 
			
		||||
	while (true)
 | 
			
		||||
	{
 | 
			
		||||
		if (!SDL_WaitEvent(&event))
 | 
			
		||||
| 
						 | 
				
			
			@ -116,6 +119,19 @@ void EventThread::process(RGSSThreadData &rtData)
 | 
			
		|||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (sMenu && sMenu->onEvent(event))
 | 
			
		||||
		{
 | 
			
		||||
			if (sMenu->destroyReq())
 | 
			
		||||
			{
 | 
			
		||||
				delete sMenu;
 | 
			
		||||
				sMenu = 0;
 | 
			
		||||
 | 
			
		||||
				updateCursorState(cursorInWindow && windowFocused);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch (event.type)
 | 
			
		||||
		{
 | 
			
		||||
		case SDL_WINDOWEVENT :
 | 
			
		||||
| 
						 | 
				
			
			@ -129,14 +145,14 @@ void EventThread::process(RGSSThreadData &rtData)
 | 
			
		|||
			case SDL_WINDOWEVENT_ENTER :
 | 
			
		||||
				cursorInWindow = true;
 | 
			
		||||
				mouseState.inWindow = true;
 | 
			
		||||
				updateCursorState(cursorInWindow && windowFocused);
 | 
			
		||||
				updateCursorState(cursorInWindow && windowFocused && !sMenu);
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case SDL_WINDOWEVENT_LEAVE :
 | 
			
		||||
				cursorInWindow = false;
 | 
			
		||||
				mouseState.inWindow = false;
 | 
			
		||||
				updateCursorState(cursorInWindow && windowFocused);
 | 
			
		||||
				updateCursorState(cursorInWindow && windowFocused && !sMenu);
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -147,13 +163,13 @@ void EventThread::process(RGSSThreadData &rtData)
 | 
			
		|||
 | 
			
		||||
			case SDL_WINDOWEVENT_FOCUS_GAINED :
 | 
			
		||||
				windowFocused = true;
 | 
			
		||||
				updateCursorState(cursorInWindow && windowFocused);
 | 
			
		||||
				updateCursorState(cursorInWindow && windowFocused && !sMenu);
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case SDL_WINDOWEVENT_FOCUS_LOST :
 | 
			
		||||
				windowFocused = false;
 | 
			
		||||
				updateCursorState(cursorInWindow && windowFocused);
 | 
			
		||||
				updateCursorState(cursorInWindow && windowFocused && !sMenu);
 | 
			
		||||
				resetInputStates();
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
| 
						 | 
				
			
			@ -181,6 +197,17 @@ void EventThread::process(RGSSThreadData &rtData)
 | 
			
		|||
				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 (!fps.displaying)
 | 
			
		||||
| 
						 | 
				
			
			@ -248,11 +275,7 @@ void EventThread::process(RGSSThreadData &rtData)
 | 
			
		|||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_JOYAXISMOTION :
 | 
			
		||||
			if (event.jaxis.axis == 0)
 | 
			
		||||
				joyState.xAxis = event.jaxis.value;
 | 
			
		||||
			else
 | 
			
		||||
				joyState.yAxis = event.jaxis.value;
 | 
			
		||||
 | 
			
		||||
			joyState.axis[event.jaxis.axis] = event.jaxis.value;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_JOYDEVICEADDED :
 | 
			
		||||
| 
						 | 
				
			
			@ -333,6 +356,8 @@ void EventThread::process(RGSSThreadData &rtData)
 | 
			
		|||
 | 
			
		||||
	if (SDL_JoystickGetAttached(js))
 | 
			
		||||
		SDL_JoystickClose(js);
 | 
			
		||||
 | 
			
		||||
	delete sMenu;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventThread::cleanup()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,7 @@
 | 
			
		|||
#include "config.h"
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
#include "sdl-util.h"
 | 
			
		||||
#include "keybindings.h"
 | 
			
		||||
 | 
			
		||||
#include <SDL_scancode.h>
 | 
			
		||||
#include <SDL_joystick.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -45,10 +46,8 @@ public:
 | 
			
		|||
 | 
			
		||||
	struct JoyState
 | 
			
		||||
	{
 | 
			
		||||
		int xAxis;
 | 
			
		||||
		int yAxis;
 | 
			
		||||
 | 
			
		||||
		bool buttons[16];
 | 
			
		||||
		int axis[256];
 | 
			
		||||
		bool buttons[256];
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
{
 | 
			
		||||
	/* Main thread sets this to request RGSS thread to terminate */
 | 
			
		||||
| 
						 | 
				
			
			@ -171,6 +219,7 @@ struct RGSSThreadData
 | 
			
		|||
 | 
			
		||||
	EventThread *ethread;
 | 
			
		||||
	WindowSizeNotify windowSizeMsg;
 | 
			
		||||
	BindingNotify bindingUpdateMsg;
 | 
			
		||||
 | 
			
		||||
	const char *argv0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -195,6 +195,13 @@ bool SharedFontState::fontPresent(std::string family)
 | 
			
		|||
	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
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,6 +49,8 @@ public:
 | 
			
		|||
 | 
			
		||||
	bool fontPresent(std::string family);
 | 
			
		||||
 | 
			
		||||
	static _TTF_Font *openBundled(int size);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	SharedFontStatePrivate *p;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										225
									
								
								src/input.cpp
									
										
									
									
									
								
							
							
						
						
									
										225
									
								
								src/input.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -22,6 +22,7 @@
 | 
			
		|||
#include "input.h"
 | 
			
		||||
#include "sharedstate.h"
 | 
			
		||||
#include "eventthread.h"
 | 
			
		||||
#include "keybindings.h"
 | 
			
		||||
#include "exception.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +31,7 @@
 | 
			
		|||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#define BUTTON_CODE_COUNT 24
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -52,12 +54,6 @@ struct KbBindingData
 | 
			
		|||
	Input::ButtonCode target;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct JsBindingData
 | 
			
		||||
{
 | 
			
		||||
	int source;
 | 
			
		||||
	Input::ButtonCode target;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Binding
 | 
			
		||||
{
 | 
			
		||||
	Binding(Input::ButtonCode target = Input::None)
 | 
			
		||||
| 
						 | 
				
			
			@ -82,6 +78,15 @@ struct KbBinding : public Binding
 | 
			
		|||
 | 
			
		||||
	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];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -100,11 +105,6 @@ struct JsButtonBinding : public Binding
 | 
			
		|||
{
 | 
			
		||||
	JsButtonBinding() {}
 | 
			
		||||
 | 
			
		||||
	JsButtonBinding(const JsBindingData &data)
 | 
			
		||||
		: Binding(data.target),
 | 
			
		||||
		  source(data.source)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool sourceActive() const
 | 
			
		||||
	{
 | 
			
		||||
		return EventThread::joyState.buttons[source];
 | 
			
		||||
| 
						 | 
				
			
			@ -115,7 +115,7 @@ struct JsButtonBinding : public Binding
 | 
			
		|||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int source;
 | 
			
		||||
	uint8_t source;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Joystick axis binding */
 | 
			
		||||
| 
						 | 
				
			
			@ -123,17 +123,22 @@ struct JsAxisBinding : public Binding
 | 
			
		|||
{
 | 
			
		||||
	JsAxisBinding() {}
 | 
			
		||||
 | 
			
		||||
	JsAxisBinding(int *source,
 | 
			
		||||
	              int compareValue,
 | 
			
		||||
	JsAxisBinding(uint8_t source,
 | 
			
		||||
	              AxisDir dir,
 | 
			
		||||
	              Input::ButtonCode target)
 | 
			
		||||
	    : Binding(target),
 | 
			
		||||
	      source(source),
 | 
			
		||||
	      compareValue(compareValue)
 | 
			
		||||
	      dir(dir)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
| 
						 | 
				
			
			@ -141,8 +146,8 @@ struct JsAxisBinding : public Binding
 | 
			
		|||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int *source;
 | 
			
		||||
	int compareValue;
 | 
			
		||||
	uint8_t source;
 | 
			
		||||
	AxisDir dir;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Mouse button binding */
 | 
			
		||||
| 
						 | 
				
			
			@ -172,10 +177,6 @@ struct MsBinding : public Binding
 | 
			
		|||
/* Not rebindable */
 | 
			
		||||
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_RSHIFT, Input::Shift },
 | 
			
		||||
	{ SDL_SCANCODE_LCTRL,  Input::Ctrl  },
 | 
			
		||||
| 
						 | 
				
			
			@ -191,61 +192,6 @@ static const KbBindingData 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
 | 
			
		||||
 * in the button state array */
 | 
			
		||||
static const int mapToIndex[] =
 | 
			
		||||
| 
						 | 
				
			
			@ -292,6 +238,7 @@ static const Input::ButtonCode otherDirs[4][3] =
 | 
			
		|||
 | 
			
		||||
struct InputPrivate
 | 
			
		||||
{
 | 
			
		||||
	std::vector<KbBinding> kbStatBindings;
 | 
			
		||||
	std::vector<KbBinding> kbBindings;
 | 
			
		||||
	std::vector<JsAxisBinding> jsABindings;
 | 
			
		||||
	std::vector<JsButtonBinding> jsBBindings;
 | 
			
		||||
| 
						 | 
				
			
			@ -320,12 +267,14 @@ struct InputPrivate
 | 
			
		|||
	} dir8Data;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	InputPrivate()
 | 
			
		||||
	InputPrivate(const RGSSThreadData &rtData)
 | 
			
		||||
	{
 | 
			
		||||
		initKbBindings();
 | 
			
		||||
		initJsBindings();
 | 
			
		||||
		initStaticKbBindings();
 | 
			
		||||
		initMsBindings();
 | 
			
		||||
 | 
			
		||||
		/* Main thread should have these posted by now */
 | 
			
		||||
		checkBindingChange(rtData);
 | 
			
		||||
 | 
			
		||||
		states    = stateArray;
 | 
			
		||||
		statesOld = stateArray + BUTTON_CODE_COUNT;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -378,51 +327,90 @@ struct InputPrivate
 | 
			
		|||
		memset(states, 0, size);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void initKbBindings()
 | 
			
		||||
	void checkBindingChange(const RGSSThreadData &rtData)
 | 
			
		||||
	{
 | 
			
		||||
		kbBindings.clear();
 | 
			
		||||
		BDescVec d;
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < staticKbBindingsN; ++i)
 | 
			
		||||
			kbBindings.push_back(KbBinding(staticKbBindings[i]));
 | 
			
		||||
		if (!rtData.bindingUpdateMsg.poll(d))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < defaultKbBindingsN; ++i)
 | 
			
		||||
			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]);
 | 
			
		||||
		applyBindingDesc(d);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void initJsBindings()
 | 
			
		||||
	template<class B>
 | 
			
		||||
	void appendBindings(std::vector<B> &bind)
 | 
			
		||||
	{
 | 
			
		||||
		/* Create axis bindings */
 | 
			
		||||
		jsABindings.resize(4);
 | 
			
		||||
		for (size_t i = 0; i < bind.size(); ++i)
 | 
			
		||||
			bindings.push_back(&bind[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		size_t i = 0;
 | 
			
		||||
		jsABindings[i++] = JsAxisBinding(&EventThread::joyState.xAxis,  0x7FFF, Input::Right);
 | 
			
		||||
		jsABindings[i++] = JsAxisBinding(&EventThread::joyState.xAxis, -0x8000, Input::Left);
 | 
			
		||||
		jsABindings[i++] = JsAxisBinding(&EventThread::joyState.yAxis,  0x7FFF, Input::Down);
 | 
			
		||||
		jsABindings[i++] = JsAxisBinding(&EventThread::joyState.yAxis, -0x8000, Input::Up);
 | 
			
		||||
	void applyBindingDesc(const BDescVec &d)
 | 
			
		||||
	{
 | 
			
		||||
		kbBindings.clear();
 | 
			
		||||
		jsABindings.clear();
 | 
			
		||||
		jsBBindings.clear();
 | 
			
		||||
 | 
			
		||||
		/* Create button bindings */
 | 
			
		||||
		jsBBindings.resize(defaultJsBindingsN);
 | 
			
		||||
		for (size_t i = 0; i < d.size(); ++i)
 | 
			
		||||
		{
 | 
			
		||||
			const BindingDesc &desc = d[i];
 | 
			
		||||
			const SourceDesc &src = desc.src;
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < defaultJsBindingsN; ++i)
 | 
			
		||||
			jsBBindings[i] = JsButtonBinding(defaultJsBindings[i]);
 | 
			
		||||
			if (desc.target == Input::None)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
		/* Add to binging array */
 | 
			
		||||
		for (size_t i = 0; i < jsABindings.size(); ++i)
 | 
			
		||||
			bindings.push_back(&jsABindings[i]);
 | 
			
		||||
			switch (desc.src.type)
 | 
			
		||||
			{
 | 
			
		||||
			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)
 | 
			
		||||
			bindings.push_back(&jsBBindings[i]);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			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()
 | 
			
		||||
| 
						 | 
				
			
			@ -433,10 +421,6 @@ struct InputPrivate
 | 
			
		|||
		msBindings[i++] = MsBinding(SDL_BUTTON_LEFT,   Input::MouseLeft);
 | 
			
		||||
		msBindings[i++] = MsBinding(SDL_BUTTON_MIDDLE, Input::MouseMiddle);
 | 
			
		||||
		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)
 | 
			
		||||
| 
						 | 
				
			
			@ -564,14 +548,15 @@ struct InputPrivate
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Input::Input()
 | 
			
		||||
Input::Input(const RGSSThreadData &rtData)
 | 
			
		||||
{
 | 
			
		||||
	p = new InputPrivate;
 | 
			
		||||
	p = new InputPrivate(rtData);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Input::update()
 | 
			
		||||
{
 | 
			
		||||
	shState->checkShutdown();
 | 
			
		||||
	p->checkBindingChange(shState->rtData());
 | 
			
		||||
 | 
			
		||||
	p->swapBuffers();
 | 
			
		||||
	p->clearBuffer();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@
 | 
			
		|||
#define INPUT_H
 | 
			
		||||
 | 
			
		||||
struct InputPrivate;
 | 
			
		||||
struct RGSSThreadData;
 | 
			
		||||
 | 
			
		||||
class Input
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +60,7 @@ public:
 | 
			
		|||
	int mouseY();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	Input();
 | 
			
		||||
	Input(const RGSSThreadData &rtData);
 | 
			
		||||
	~Input();
 | 
			
		||||
 | 
			
		||||
	friend struct SharedStatePrivate;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										311
									
								
								src/keybindings.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								src/keybindings.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										108
									
								
								src/keybindings.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								src/keybindings.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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_Window *win;
 | 
			
		||||
	Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
 | 
			
		||||
	Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_FOCUS;
 | 
			
		||||
 | 
			
		||||
	if (conf.winResizable)
 | 
			
		||||
		winFlags |= SDL_WINDOW_RESIZABLE;
 | 
			
		||||
| 
						 | 
				
			
			@ -268,6 +268,9 @@ int main(int argc, char *argv[])
 | 
			
		|||
	EventThread eventThread;
 | 
			
		||||
	RGSSThreadData rtData(&eventThread, argv[0], win, conf);
 | 
			
		||||
 | 
			
		||||
	/* Load and post key bindings */
 | 
			
		||||
	rtData.bindingUpdateMsg.post(loadBindings(conf));
 | 
			
		||||
 | 
			
		||||
	/* Start RGSS thread */
 | 
			
		||||
	SDL_Thread *rgssThread =
 | 
			
		||||
	        SDL_CreateThread(rgssThreadFun, "rgss", &rtData);
 | 
			
		||||
| 
						 | 
				
			
			@ -310,6 +313,11 @@ int main(int argc, char *argv[])
 | 
			
		|||
	/* Clean up any remainin events */
 | 
			
		||||
	eventThread.cleanup();
 | 
			
		||||
 | 
			
		||||
	/* Store key bindings */
 | 
			
		||||
	BDescVec keyBinds;
 | 
			
		||||
	rtData.bindingUpdateMsg.get(keyBinds);
 | 
			
		||||
	storeBindings(keyBinds, rtData.config);
 | 
			
		||||
 | 
			
		||||
	Debug() << "Shutting down.";
 | 
			
		||||
 | 
			
		||||
	SDL_DestroyWindow(win);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1112
									
								
								src/settingsmenu.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1112
									
								
								src/settingsmenu.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										46
									
								
								src/settingsmenu.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/settingsmenu.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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),
 | 
			
		||||
	      midiState(threadData->config),
 | 
			
		||||
	      graphics(threadData),
 | 
			
		||||
	      input(*threadData),
 | 
			
		||||
	      audio(threadData->config),
 | 
			
		||||
	      fontState(threadData->config),
 | 
			
		||||
	      stampCounter(0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue