2014-01-25 08:24:55 +00:00
|
|
|
/*
|
|
|
|
** 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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-09-04 05:53:41 +00:00
|
|
|
struct GcBindingData
|
|
|
|
{
|
|
|
|
int source;
|
|
|
|
Input::ButtonCode target;
|
|
|
|
|
|
|
|
void add(BDescVec &d) const
|
|
|
|
{
|
|
|
|
SourceDesc src;
|
|
|
|
src.type = CButton;
|
|
|
|
src.d.jb = source;
|
|
|
|
|
|
|
|
BindingDesc desc;
|
|
|
|
desc.src = src;
|
|
|
|
desc.target = target;
|
|
|
|
|
|
|
|
d.push_back(desc);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-01-25 08:24:55 +00:00
|
|
|
/* Common */
|
|
|
|
static const KbBindingData defaultKbBindings[] =
|
|
|
|
{
|
2015-09-04 05:53:41 +00:00
|
|
|
{ SDL_SCANCODE_LEFT, Input::Left },
|
2015-09-04 02:47:43 +00:00
|
|
|
{ SDL_SCANCODE_RIGHT, Input::Right },
|
|
|
|
{ SDL_SCANCODE_UP, Input::Up },
|
|
|
|
{ SDL_SCANCODE_DOWN, Input::Down },
|
|
|
|
{ SDL_SCANCODE_Z, Input::Action },
|
2015-09-04 05:53:41 +00:00
|
|
|
{ SDL_SCANCODE_SPACE, Input::Action },
|
2015-09-04 02:47:43 +00:00
|
|
|
{ SDL_SCANCODE_X, Input::Cancel },
|
2015-09-04 05:53:41 +00:00
|
|
|
{ SDL_SCANCODE_ESCAPE, Input::Cancel },
|
2015-09-04 02:47:43 +00:00
|
|
|
{ SDL_SCANCODE_A, Input::Menu },
|
2015-09-04 05:53:41 +00:00
|
|
|
{ SDL_SCANCODE_RETURN, Input::Menu },
|
2015-09-04 02:47:43 +00:00
|
|
|
{ SDL_SCANCODE_S, Input::Items },
|
|
|
|
{ SDL_SCANCODE_LSHIFT, Input::Run },
|
|
|
|
{ SDL_SCANCODE_LCTRL, Input::Deactivate },
|
|
|
|
{ SDL_SCANCODE_Q, Input::L },
|
|
|
|
{ SDL_SCANCODE_W, Input::R },
|
2014-01-25 08:24:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static elementsN(defaultKbBindings);
|
|
|
|
|
2015-09-04 05:53:41 +00:00
|
|
|
static const GcBindingData defaultGcBindings[] =
|
2014-01-25 08:24:55 +00:00
|
|
|
{
|
2015-09-04 05:53:41 +00:00
|
|
|
{ SDL_CONTROLLER_BUTTON_DPAD_LEFT, Input::Left },
|
|
|
|
{ SDL_CONTROLLER_BUTTON_DPAD_RIGHT, Input::Right },
|
|
|
|
{ SDL_CONTROLLER_BUTTON_DPAD_UP, Input::Up },
|
|
|
|
{ SDL_CONTROLLER_BUTTON_DPAD_DOWN, Input::Down },
|
|
|
|
{ SDL_CONTROLLER_BUTTON_A, Input::Action },
|
|
|
|
{ SDL_CONTROLLER_BUTTON_B, Input::Cancel },
|
|
|
|
{ SDL_CONTROLLER_BUTTON_X, Input::Run },
|
|
|
|
{ SDL_CONTROLLER_BUTTON_Y, Input::Items },
|
|
|
|
{ SDL_CONTROLLER_BUTTON_START, Input::Menu },
|
|
|
|
{ SDL_CONTROLLER_BUTTON_BACK, Input::Deactivate },
|
|
|
|
{ SDL_CONTROLLER_BUTTON_LEFTSHOULDER, Input::L },
|
|
|
|
{ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, Input::R },
|
2014-01-25 08:24:55 +00:00
|
|
|
};
|
|
|
|
|
2015-09-04 05:53:41 +00:00
|
|
|
static elementsN(defaultGcBindings);
|
2014-01-25 08:24:55 +00:00
|
|
|
|
2015-09-04 05:53:41 +00:00
|
|
|
static void addGcAxisBinding(BDescVec &d, uint8_t axis, AxisDir dir, Input::ButtonCode target)
|
2014-01-25 08:24:55 +00:00
|
|
|
{
|
|
|
|
SourceDesc src;
|
2015-09-04 05:53:41 +00:00
|
|
|
src.type = CAxis;
|
2014-01-25 08:24:55 +00:00
|
|
|
src.d.ja.axis = axis;
|
|
|
|
src.d.ja.dir = dir;
|
|
|
|
|
|
|
|
BindingDesc desc;
|
|
|
|
desc.src = src;
|
|
|
|
desc.target = target;
|
|
|
|
|
|
|
|
d.push_back(desc);
|
|
|
|
}
|
|
|
|
|
2015-09-03 02:41:25 +00:00
|
|
|
BDescVec genDefaultBindings()
|
2014-01-25 08:24:55 +00:00
|
|
|
{
|
|
|
|
BDescVec d;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < defaultKbBindingsN; ++i)
|
|
|
|
defaultKbBindings[i].add(d);
|
|
|
|
|
2015-09-04 05:53:41 +00:00
|
|
|
for (size_t i = 0; i < defaultGcBindingsN; ++i)
|
|
|
|
defaultGcBindings[i].add(d);
|
2015-09-03 02:41:25 +00:00
|
|
|
|
2015-09-04 05:53:41 +00:00
|
|
|
addGcAxisBinding(d, SDL_CONTROLLER_AXIS_LEFTX, Negative, Input::Left );
|
|
|
|
addGcAxisBinding(d, SDL_CONTROLLER_AXIS_LEFTX, Positive, Input::Right );
|
|
|
|
addGcAxisBinding(d, SDL_CONTROLLER_AXIS_LEFTY, Negative, Input::Up );
|
|
|
|
addGcAxisBinding(d, SDL_CONTROLLER_AXIS_LEFTY, Positive, Input::Down );
|
|
|
|
addGcAxisBinding(d, SDL_CONTROLLER_AXIS_TRIGGERLEFT, Positive, Input::Deactivate);
|
|
|
|
addGcAxisBinding(d, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, Positive, Input::Run );
|
2014-01-25 08:24:55 +00:00
|
|
|
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2015-09-04 05:53:41 +00:00
|
|
|
#define FORMAT_VER 0
|
2014-01-25 08:24:55 +00:00
|
|
|
|
|
|
|
struct Header
|
|
|
|
{
|
|
|
|
uint32_t formVer;
|
|
|
|
uint32_t count;
|
|
|
|
};
|
|
|
|
|
2015-09-03 02:41:25 +00:00
|
|
|
static void buildPath(const std::string &dir, char *out, size_t outSize)
|
2014-01-25 08:24:55 +00:00
|
|
|
{
|
2015-09-03 02:41:25 +00:00
|
|
|
snprintf(out, outSize, "%skeybindings", dir.c_str());
|
2014-01-25 08:24:55 +00:00
|
|
|
}
|
|
|
|
|
2015-09-03 02:41:25 +00:00
|
|
|
static bool writeBindings(const BDescVec &d, const std::string &dir)
|
2014-01-25 08:24:55 +00:00
|
|
|
{
|
|
|
|
if (dir.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
char path[1024];
|
2015-09-03 02:41:25 +00:00
|
|
|
buildPath(dir, path, sizeof(path));
|
2014-01-25 08:24:55 +00:00
|
|
|
|
2014-11-17 06:18:39 +00:00
|
|
|
FILE *f = fopen(path, "wb");
|
2014-01-25 08:24:55 +00:00
|
|
|
|
|
|
|
if (!f)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Header hd;
|
|
|
|
hd.formVer = FORMAT_VER;
|
|
|
|
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)
|
|
|
|
{
|
2015-09-03 02:41:25 +00:00
|
|
|
if (writeBindings(d, conf.customDataPath))
|
2014-01-25 08:24:55 +00:00
|
|
|
return;
|
|
|
|
|
2015-09-03 02:41:25 +00:00
|
|
|
writeBindings(d, conf.commonDataPath);
|
2014-01-25 08:24:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#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,
|
2015-09-04 02:47:43 +00:00
|
|
|
Input::Action,
|
|
|
|
Input::Cancel,
|
|
|
|
Input::Menu,
|
|
|
|
Input::Items,
|
|
|
|
Input::Run,
|
|
|
|
Input::Deactivate,
|
2014-01-25 08:24:55 +00:00
|
|
|
Input::L, Input::R,
|
|
|
|
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;
|
2015-09-04 05:53:41 +00:00
|
|
|
case CButton:
|
2014-01-25 08:24:55 +00:00
|
|
|
case JButton:
|
|
|
|
return true;
|
2014-12-31 15:39:28 +00:00
|
|
|
case JHat:
|
|
|
|
/* Only accept single directional binds */
|
|
|
|
return src.d.jh.pos == SDL_HAT_LEFT || src.d.jh.pos == SDL_HAT_RIGHT ||
|
|
|
|
src.d.jh.pos == SDL_HAT_UP || src.d.jh.pos == SDL_HAT_DOWN;
|
2015-09-04 05:53:41 +00:00
|
|
|
case CAxis:
|
2014-01-25 08:24:55 +00:00
|
|
|
case JAxis:
|
|
|
|
return src.d.ja.dir == Negative || src.d.ja.dir == Positive;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-03 02:41:25 +00:00
|
|
|
static bool readBindings(BDescVec &out, const std::string &dir)
|
2014-01-25 08:24:55 +00:00
|
|
|
{
|
|
|
|
if (dir.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
char path[1024];
|
2015-09-03 02:41:25 +00:00
|
|
|
buildPath(dir, path, sizeof(path));
|
2014-01-25 08:24:55 +00:00
|
|
|
|
2014-11-17 06:18:39 +00:00
|
|
|
FILE *f = fopen(path, "rb");
|
2014-01-25 08:24:55 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
/* 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;
|
|
|
|
|
2015-09-03 02:41:25 +00:00
|
|
|
if (readBindings(d, conf.customDataPath))
|
2014-01-25 08:24:55 +00:00
|
|
|
return d;
|
|
|
|
|
2015-09-03 02:41:25 +00:00
|
|
|
if (readBindings(d, conf.commonDataPath))
|
2014-01-25 08:24:55 +00:00
|
|
|
return d;
|
|
|
|
|
2015-09-03 02:41:25 +00:00
|
|
|
return genDefaultBindings();
|
2014-01-25 08:24:55 +00:00
|
|
|
}
|