Reimplemented all obsolete modifier via AxisFilter and ButtonFilter

This commit is contained in:
Ingo Ruhnke 2011-01-17 15:40:25 +01:00
parent 7d9b61d9c6
commit 66776ed81a
9 changed files with 210 additions and 113 deletions

View file

@ -1315,7 +1315,7 @@ pos = (1.0f - (1.0f - pos) ** t) ** (1 / t);]]></programlisting>
</varlistentry>
<varlistentry>
<term><option>--autofire BUTTON=FREQUENCY</option></term>
<term><option>--autofire BUTTON=FREQUENCY,...</option></term>
<listitem>
<para>Autofire mapping allows you to let a button automatically fire with a
given frequency in miliseconds:</para>

View file

@ -26,6 +26,7 @@
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <boost/format.hpp>
#include <boost/tokenizer.hpp>
#include "arg_parser.hpp"
#include "button_filter.hpp"
@ -776,7 +777,8 @@ CommandLineParser::print_version() const
<< "Copyright © 2008-2010 Ingo Ruhnke <grumbel@gmx.de>\n"
<< "Licensed under GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
<< "This program comes with ABSOLUTELY NO WARRANTY.\n"
<< "This is free software, and you are welcome to redistribute it under certain conditions; see the file COPYING for details.\n";
<< "This is free software, and you are welcome to redistribute it under certain\n"
<< "conditions; see the file COPYING for details.\n";
}
void
@ -788,13 +790,13 @@ CommandLineParser::set_modifier(const std::string& name, const std::string& valu
void
CommandLineParser::set_axismap(const std::string& name, const std::string& value)
{
m_options->controller.modifier.push_back(ModifierPtr(AxismapModifier::from_string(name, value)));
m_options->controller.axismap->add(AxisMapping::from_string(name, value));
}
void
CommandLineParser::set_buttonmap(const std::string& name, const std::string& value)
{
m_options->controller.modifier.push_back(ModifierPtr(ButtonmapModifier::from_string(name, value)));
m_options->controller.buttonmap->add(ButtonMapping::from_string(name, value));
}
void
@ -826,37 +828,77 @@ CommandLineParser::set_evdev_keymap(const std::string& name, const std::string&
void
CommandLineParser::set_relative_axis(const std::string& name, const std::string& value)
{
//FIXME:m_options->controller.modifier.push_back(ModifierPtr(RelativeAxisModifier::from_string(name, value)));
m_options->controller.axismap->add_filter(string2axis(name),
AxisFilterPtr(new RelativeAxisFilter(boost::lexical_cast<int>(value))));
}
void
CommandLineParser::set_autofire(const std::string& name, const std::string& value)
{
//FIXME: m_options->controller.modifier.push_back(ModifierPtr(AutofireModifier::from_string(name, value)));
m_options->controller.buttonmap->add_filter(string2btn(name),
ButtonFilterPtr(new AutofireButtonFilter(boost::lexical_cast<int>(value), 0)));
}
void
CommandLineParser::set_calibration(const std::string& name, const std::string& value)
{
//FIXME: m_options->controller.modifier.push_back(ModifierPtr(CalibrationModifier::from_string(name, value)));
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(value, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
std::vector<std::string> args(tokens.begin(), tokens.end());
if (args.size() != 3)
{
throw std::runtime_error("calibration requires MIN:CENTER:MAX as argument");
}
else
{
m_options->controller.axismap->add_filter(string2axis(name),
AxisFilterPtr(new CalibrationAxisFilter(boost::lexical_cast<int>(args[0]),
boost::lexical_cast<int>(args[1]),
boost::lexical_cast<int>(args[2]))));
}
}
void
CommandLineParser::set_axis_sensitivity(const std::string& name, const std::string& value)
{
//FIXME: m_options->controller.modifier.push_back(ModifierPtr(AxisSensitivityModifier::from_string(name, value)));
m_options->controller.axismap->add_filter(string2axis(name),
AxisFilterPtr(new SensitivityAxisFilter(boost::lexical_cast<float>(value))));
}
void
CommandLineParser::set_deadzone(const std::string& value)
{
//FIXME: m_options->controller.modifier.push_back(ModifierPtr(new DeadzoneModifier(to_number(32767, value), 0)));
int deadzone = boost::lexical_cast<int>(value);
XboxAxis axes[] = { XBOX_AXIS_X1,
XBOX_AXIS_Y1,
XBOX_AXIS_X2,
XBOX_AXIS_Y2 };
for(size_t i = 0; i < sizeof(axes)/sizeof(XboxAxis); ++i)
{
m_options->controller.axismap->add_filter(axes[i],
AxisFilterPtr(new DeadzoneAxisFilter(-deadzone,
deadzone,
true)));
}
}
void
CommandLineParser::set_deadzone_trigger(const std::string& value)
{
//FIXME: m_options->controller.modifier.push_back(ModifierPtr(new DeadzoneModifier(0, to_number(255, value))));
int deadzone_trigger = boost::lexical_cast<int>(value);
XboxAxis axes[] = { XBOX_AXIS_LT,
XBOX_AXIS_RT };
for(size_t i = 0; i < sizeof(axes)/sizeof(XboxAxis); ++i)
{
m_options->controller.axismap->add_filter(axes[i],
AxisFilterPtr(new DeadzoneAxisFilter(-deadzone_trigger,
deadzone_trigger,
true)));
}
}
void
@ -881,25 +923,6 @@ CommandLineParser::set_dpad_rotation(const std::string& value)
m_options->controller.modifier.push_back(ModifierPtr(DpadRotationModifier::from_string(args)));
}
/*
void set_deadzone(int value);
void set_deadzone_trigger(int value);
void set_square_axis();
void set_four_way_restrictor();
if (opts.controller.deadzone != 0 || opts.controller.deadzone_trigger != 0)
modifier.push_back(ModifierPtr(new DeadzoneModifier(opts.controller.deadzone, opts.controller.deadzone_trigger)));
if (opts.controller.square_axis)
modifier.push_back(ModifierPtr(new SquareAxisModifier()));
if (opts.controller.four_way_restrictor)
modifier.push_back(ModifierPtr(new FourWayRestrictorModifier()));
if (opts.controller.dpad_rotation)
modifier.push_back(ModifierPtr(new DpadRotationModifier(opts.controller.dpad_rotation)));
*/
void
CommandLineParser::read_config_file(Options* opts, const std::string& filename)
{

View file

@ -27,19 +27,19 @@ inline float to_float(int value, int min, int max)
return static_cast<float>(value - min) / static_cast<float>(max - min) * 2.0f - 1.0f;
}
AxismapModifier*
AxismapModifier::from_string(const std::string& lhs_, const std::string& rhs)
AxisMapping
AxisMapping::from_string(const std::string& lhs_, const std::string& rhs)
{
std::string lhs = lhs_;
std::auto_ptr<AxismapModifier> mapping(new AxismapModifier);
AxisMapping mapping;
mapping->m_invert = false;
mapping->m_lhs = XBOX_AXIS_UNKNOWN;
mapping->m_rhs = XBOX_AXIS_UNKNOWN;
mapping.invert = false;
mapping.lhs = XBOX_AXIS_UNKNOWN;
mapping.rhs = XBOX_AXIS_UNKNOWN;
if (lhs[0] == '-')
{
mapping->m_invert = true;
mapping.invert = true;
lhs = lhs.substr(1);
}
@ -50,71 +50,95 @@ AxismapModifier::from_string(const std::string& lhs_, const std::string& rhs)
{
switch(idx)
{
case 0: mapping->m_lhs = string2axis(*t); break;
default: mapping->m_filters.push_back(AxisFilter::from_string(*t));
case 0: mapping.lhs = string2axis(*t); break;
default: mapping.filters.push_back(AxisFilter::from_string(*t));
}
}
if (rhs.empty())
{
mapping->m_rhs = mapping->m_lhs;
mapping.rhs = mapping.lhs;
}
else
{
mapping->m_rhs = string2axis(rhs);
mapping.rhs = string2axis(rhs);
}
if (mapping->m_lhs == XBOX_AXIS_UNKNOWN ||
mapping->m_rhs == XBOX_AXIS_UNKNOWN)
if (mapping.lhs == XBOX_AXIS_UNKNOWN ||
mapping.rhs == XBOX_AXIS_UNKNOWN)
{
throw std::runtime_error("Couldn't convert string \"" + lhs + "=" + rhs + "\" to axis mapping");
}
return mapping.release();
return mapping;
}
AxismapModifier::AxismapModifier() :
m_lhs(XBOX_AXIS_UNKNOWN),
m_rhs(XBOX_AXIS_UNKNOWN),
m_invert(false),
m_filters()
m_axismap()
{
}
void
AxismapModifier::update(int msec_delta, XboxGenericMsg& msg)
{
// update all filters in all mappings
for(std::vector<AxisFilterPtr>::iterator j = m_filters.begin(); j != m_filters.end(); ++j)
{
(*j)->update(msec_delta);
}
XboxGenericMsg newmsg = msg;
// update all filters in all mappings
for(std::vector<AxisMapping>::iterator i = m_axismap.begin(); i != m_axismap.end(); ++i)
{
for(std::vector<AxisFilterPtr>::iterator j = i->filters.begin(); j != i->filters.end(); ++j)
{
(*j)->update(msec_delta);
}
}
// clear all values in the new msg
set_axis_float(newmsg, m_lhs, 0);
int min = get_axis_min(m_lhs);
int max = get_axis_max(m_lhs);
int value = get_axis(msg, m_lhs);
for(std::vector<AxisFilterPtr>::iterator j = m_filters.begin(); j != m_filters.end(); ++j)
for(std::vector<AxisMapping>::iterator i = m_axismap.begin(); i != m_axismap.end(); ++i)
{
value = (*j)->filter(value, min, max);
set_axis_float(newmsg, i->lhs, 0);
}
float lhs = to_float(value, min, max);
float nrhs = get_axis_float(newmsg, m_rhs);
if (m_invert)
for(std::vector<AxisMapping>::iterator i = m_axismap.begin(); i != m_axismap.end(); ++i)
{
lhs = -lhs;
int min = get_axis_min(i->lhs);
int max = get_axis_max(i->lhs);
int value = get_axis(msg, i->lhs);
for(std::vector<AxisFilterPtr>::iterator j = i->filters.begin(); j != i->filters.end(); ++j)
{
value = (*j)->filter(value, min, max);
}
float lhs = to_float(value, min, max);
float nrhs = get_axis_float(newmsg, i->rhs);
if (i->invert)
{
lhs = -lhs;
}
set_axis_float(newmsg, i->rhs, std::max(std::min(nrhs + lhs, 1.0f), -1.0f));
}
msg = newmsg;
}
set_axis_float(newmsg, m_rhs, std::max(std::min(nrhs + lhs, 1.0f), -1.0f));
void
AxismapModifier::add(const AxisMapping& mapping)
{
m_axismap.push_back(mapping);
}
msg = newmsg;
void
AxismapModifier::add_filter(XboxAxis axis, AxisFilterPtr filter)
{
for(std::vector<AxisMapping>::iterator i = m_axismap.begin(); i != m_axismap.end(); ++i)
{
if (i->lhs == axis)
{
i->filters.push_back(filter);
break;
}
}
}
/* EOF */

View file

@ -23,11 +23,17 @@
#include "modifier.hpp"
struct AxisMapping {
static AxisMapping from_string(const std::string& lhs, const std::string& rhs);
XboxAxis lhs;
XboxAxis rhs;
bool invert;
std::vector<AxisFilterPtr> filters;
};
class AxismapModifier : public Modifier
{
public:
static AxismapModifier* from_string(const std::string& lhs, const std::string& rhs);
public:
AxismapModifier();
@ -35,11 +41,11 @@ public:
Modifier::Priority get_priority() const { return Modifier::kAxismapPriority; };
void add(const AxisMapping& mapping);
void add_filter(XboxAxis axis, AxisFilterPtr filter);
public:
XboxAxis m_lhs;
XboxAxis m_rhs;
bool m_invert;
std::vector<AxisFilterPtr> m_filters;
std::vector<AxisMapping> m_axismap;
};
#endif

View file

@ -20,10 +20,13 @@
#include <boost/tokenizer.hpp>
ButtonmapModifier*
ButtonmapModifier::from_string(const std::string& lhs, const std::string& rhs)
ButtonMapping
ButtonMapping::from_string(const std::string& lhs, const std::string& rhs)
{
std::auto_ptr<ButtonmapModifier> mapping(new ButtonmapModifier(XBOX_BTN_UNKNOWN, XBOX_BTN_UNKNOWN));
ButtonMapping mapping;
mapping.lhs = XBOX_BTN_UNKNOWN;
mapping.rhs = XBOX_BTN_UNKNOWN;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(lhs, boost::char_separator<char>("^", "", boost::keep_empty_tokens));
@ -32,57 +35,83 @@ ButtonmapModifier::from_string(const std::string& lhs, const std::string& rhs)
{
switch(idx)
{
case 0: mapping->m_lhs = string2btn(*t); break;
default: mapping->m_filters.push_back(ButtonFilter::from_string(*t));
case 0: mapping.lhs = string2btn(*t); break;
default: mapping.filters.push_back(ButtonFilter::from_string(*t));
}
}
if (rhs.empty())
{
mapping->m_rhs = mapping->m_lhs;
mapping.rhs = mapping.lhs;
}
else
{
mapping->m_rhs = string2btn(rhs);
mapping.rhs = string2btn(rhs);
}
return mapping.release();
return mapping;
}
ButtonmapModifier::ButtonmapModifier(XboxButton lhs,
XboxButton rhs) :
m_lhs(lhs),
m_rhs(rhs)
ButtonmapModifier::ButtonmapModifier() :
m_buttonmap()
{
}
void
ButtonmapModifier::update(int msec_delta, XboxGenericMsg& msg)
{
// update all filters in all mappings
for(std::vector<ButtonFilterPtr>::iterator i = m_filters.begin(); i != m_filters.end(); ++i)
{
(*i)->update(msec_delta);
}
XboxGenericMsg newmsg = msg;
// set all buttons to 0
set_button(newmsg, m_lhs, 0);
bool value = get_button(msg, m_lhs);
// apply the button filter
for(std::vector<ButtonFilterPtr>::iterator j = m_filters.begin(); j != m_filters.end(); ++j)
// update all filters in all mappings
for(std::vector<ButtonMapping>::iterator i = m_buttonmap.begin(); i != m_buttonmap.end(); ++i)
{
value = (*j)->filter(value);
for(std::vector<ButtonFilterPtr>::iterator j = i->filters.begin(); j != i->filters.end(); ++j)
{
(*j)->update(msec_delta);
}
}
// Take both lhs and rhs into account to allow multiple buttons
// mapping to the same button
set_button(newmsg, m_rhs, value || get_button(newmsg, m_rhs));
// set all buttons to 0
for(std::vector<ButtonMapping>::iterator i = m_buttonmap.begin(); i != m_buttonmap.end(); ++i)
{
set_button(newmsg, i->lhs, 0);
}
msg = newmsg;
for(std::vector<ButtonMapping>::iterator i = m_buttonmap.begin(); i != m_buttonmap.end(); ++i)
{
// Take both lhs and rhs into account to allow multiple buttons
// mapping to the same button
bool value = get_button(msg, i->lhs);
// apply the button filter
for(std::vector<ButtonFilterPtr>::iterator j = i->filters.begin(); j != i->filters.end(); ++j)
{
value = (*j)->filter(value);
}
set_button(newmsg, i->rhs, value || get_button(newmsg, i->rhs));
}
msg = newmsg;
}
void
ButtonmapModifier::add(const ButtonMapping& mapping)
{
m_buttonmap.push_back(mapping);
}
void
ButtonmapModifier::add_filter(XboxButton btn, ButtonFilterPtr filter)
{
for(std::vector<ButtonMapping>::iterator i = m_buttonmap.begin(); i != m_buttonmap.end(); ++i)
{
if (i->lhs == btn)
{
i->filters.push_back(filter);
break;
}
}
}
/* EOF */

View file

@ -21,23 +21,28 @@
#include "modifier.hpp"
struct ButtonMapping {
static ButtonMapping from_string(const std::string& lhs, const std::string& rhs);
XboxButton lhs;
XboxButton rhs;
std::vector<ButtonFilterPtr> filters;
};
class ButtonmapModifier : public Modifier
{
public:
static ButtonmapModifier* from_string(const std::string& lhs, const std::string& rhs);
public:
ButtonmapModifier(XboxButton lhs,
XboxButton rhs);
ButtonmapModifier();
void update(int msec_delta, XboxGenericMsg& msg);
Modifier::Priority get_priority() const { return Modifier::kButtonMapPriority; };
void add(const ButtonMapping& mapping);
void add_filter(XboxButton btn, ButtonFilterPtr filter);
public:
XboxButton m_lhs;
XboxButton m_rhs;
std::vector<ButtonFilterPtr> m_filters;
std::vector<ButtonMapping> m_buttonmap;
};
#endif

View file

@ -22,6 +22,8 @@ Options* g_options;
ControllerOptions::ControllerOptions() :
uinput(),
buttonmap(new ButtonmapModifier),
axismap(new AxismapModifier),
modifier()
{
}

View file

@ -37,6 +37,10 @@ public:
ControllerOptions();
uInputCfg uinput;
boost::shared_ptr<ButtonmapModifier> buttonmap;
boost::shared_ptr<AxismapModifier> axismap;
std::vector<ModifierPtr> modifier;
};

View file

@ -97,6 +97,10 @@ XboxdrvThread::controller_loop(GamepadType type, uInput* uinput, const Options&
modifier.insert(modifier.end(), opts.controller.modifier.begin(), opts.controller.modifier.end());
std::stable_sort(modifier.begin(), modifier.end(), SortModifierByPriority());
// axismap, buttonmap comes last, as otherwise they would mess up the button and axis names
modifier.push_back(opts.controller.buttonmap);
modifier.push_back(opts.controller.axismap);
// how long to wait for a controller event before taking care of autofire etc.
timeout = 25; // FIXME: add an option for that