Implemnted some AxisFilter

This commit is contained in:
Ingo Ruhnke 2010-12-28 17:38:12 +01:00
parent c87dfc201d
commit 19ae8b55d1
8 changed files with 257 additions and 41 deletions

View file

@ -1,6 +1,6 @@
# -*- python -*-
if True:
if False:
env = Environment(CPPFLAGS=['-g', '-O2', '-Wall', '-ansi', '-pedantic'])
else:
env = Environment(CXXFLAGS= [ "-O3", "-g3",
@ -9,7 +9,7 @@ else:
"-Wall",
"-Wextra",
"-Wnon-virtual-dtor",
"-Weffc++",
#"-Weffc++",
#"-Wconversion",
"-Wold-style-cast",
# "-Werror",

31
TODO
View file

@ -27,6 +27,18 @@ $ dput my-ppa xboxdrv_0.6.1_source.changes
Stuff to do before 0.6.1 release:
=================================
* "couldn't convert 'ABS_y' to enum, not a member of EV_ABS"
convert all enum names to uppercase? or does that lead to conflicts in the naming?
* allow giving ini options on command line: xboxdrv '-e' foo=5 (or '-o')
* allow the right side of --ui-buttomap/--ui-axismap to be empty:
xboxdrv --ui-buttonmap X1^deadzone:50
This would just add the filter to the chain, not create a complete new mapping
* remove guide button from default mapping when its an Xbox1 controller
* fixup guitar
@ -37,6 +49,15 @@ Stuff to do before 0.6.1 release:
* add more example scripts
* make evdev grab optional:
--evdev-grab
Takes exclusive ownership of the event device, all events are
directed to xboxdrv and no other application will be able to
receive events.
--evdev-no-grab
Stuff to do before 0.7.0 release:
=================================
@ -51,16 +72,6 @@ Stuff to do before 0.7.0 release:
* make dummy joystick axis creation optional
* make evdev grab optional:
--evdev-grab
Takes exclusive ownership of the event device, all events are
directed to xboxdrv and no other application will be able to
receive events.
--evdev-no-grab
* --ui-axismap LT=KEY_A:KEY_B:1
Here KEY_B is the key you want to send and KEY_A is a random other key

58
Xbox360
View file

@ -23,11 +23,55 @@
| `---. .---' \ \ / / |
| | \/ | \ `----' / |
| `----' `------' |
` DD/DPAD_Y- Y2- '
| _____________ |
. ,-' '-. .
\ ,/ \. /
\. ,/ \. ./
\__ __/ \__ __/
\____________/ \____________/
` DD/DPAD_Y- Y2- '
| ___________ |
. ,-' '-. .
\ ,/ \. /
\. ,/ \. ./
\__ __/ \__ __/
\____________/ \____________/
||
||
==== _______Reload
,---------------- / ______Fire
/ _ | /
/ / \ o O o | O
/ \_/ O O
/ ^ O \__Reload
| <-|-> \____ Jump
| v
|||||||||||||
. .
/
|
.
\_____
____
___ .' `.
4 lines: / \ 5 lines: 6 lines: / \
| | | |
\___/ \ /
.----.
/ \ Guide
| | Back ,--. Start ,-.
\ / ( < ) / \/ \ ( > ) ( Y )
`----' \ /\ / ,-. `-' ,-.
`--' ( X ) ( B )
`-' ,-. `-'
,----. ( A )
| /\ | `-'
,---' `---.
| < > |
`---. .---'
| \/ |
`----'

View file

@ -80,6 +80,8 @@ AxisEvent::from_string(const std::string& str)
}
AxisEvent::AxisEvent(AxisEventHandler* handler) :
m_min(0),
m_max(0),
m_handler(handler),
m_filters()
{
@ -98,14 +100,14 @@ AxisEvent::init(uInput& uinput) const
}
void
AxisEvent::send(uInput& uinput, int old_value, int value) const
AxisEvent::send(uInput& uinput, int value)
{
for(std::vector<AxisFilterPtr>::const_iterator i = m_filters.begin(); i != m_filters.end(); ++i)
{
value = (*i)->filter(old_value, value);
value = (*i)->filter(value, m_min, m_max);
}
m_handler->send(uinput, old_value, value);
m_handler->send(uinput, value);
}
void
@ -117,6 +119,8 @@ AxisEvent::update(uInput& uinput, int msec_delta)
void
AxisEvent::set_axis_range(int min, int max)
{
m_min = min;
m_max = max;
m_handler->set_axis_range(min, max);
}
@ -186,7 +190,7 @@ RelAxisEventHandler::init(uInput& uinput) const
}
void
RelAxisEventHandler::send(uInput& uinput, int old_value, int value) const
RelAxisEventHandler::send(uInput& uinput, int value)
{
// FIXME: Need to know the min/max of value
int v = m_value * value / 32767;
@ -278,7 +282,7 @@ AbsAxisEventHandler::init(uInput& uinput) const
}
void
AbsAxisEventHandler:: send(uInput& uinput, int old_value, int value) const
AbsAxisEventHandler:: send(uInput& uinput, int value)
{
/*FIXME for(std::vector<AxisFilterPtr>::const_iterator i = m_filters.begin(); i != m_filters.end(); ++i)
{
@ -355,7 +359,8 @@ KeyAxisEventHandler::from_string(const std::string& str)
return ev.release();
}
KeyAxisEventHandler::KeyAxisEventHandler()
KeyAxisEventHandler::KeyAxisEventHandler() :
m_old_value(0)
{
std::fill_n(m_up_codes, MAX_MODIFIER+1, UIEvent::invalid());
std::fill_n(m_down_codes, MAX_MODIFIER+1, UIEvent::invalid());
@ -380,10 +385,10 @@ KeyAxisEventHandler::init(uInput& uinput) const
}
void
KeyAxisEventHandler::send(uInput& uinput, int old_value, int value) const
KeyAxisEventHandler::send(uInput& uinput, int value)
{
if (::abs(old_value) < m_threshold &&
::abs(value) >= m_threshold)
if (::abs(m_old_value) < m_threshold &&
::abs(value) >= m_threshold)
{ // entering bigger then threshold zone
if (value < 0)
{
@ -402,8 +407,8 @@ KeyAxisEventHandler::send(uInput& uinput, int old_value, int value) const
uinput.send_key(m_up_codes[i].device_id, m_up_codes[i].code, false);
}
}
else if (::abs(old_value) >= m_threshold &&
::abs(value) < m_threshold)
else if (::abs(m_old_value) >= m_threshold &&
::abs(value) < m_threshold)
{ // entering zero zone
for(int i = 0; m_up_codes[i].is_valid(); ++i)
uinput.send_key(m_down_codes[i].device_id, m_down_codes[i].code, false);
@ -411,6 +416,8 @@ KeyAxisEventHandler::send(uInput& uinput, int old_value, int value) const
for(int i = 0; m_up_codes[i].is_valid(); ++i)
uinput.send_key(m_up_codes[i].device_id, m_up_codes[i].code, false);
}
m_old_value = value;
}
void

View file

@ -51,7 +51,7 @@ public:
void set_filters(const std::vector<AxisFilterPtr>& filters);
void init(uInput& uinput) const;
void send(uInput& uinput, int old_value, int value) const;
void send(uInput& uinput, int value);
void update(uInput& uinput, int msec_delta);
void set_axis_range(int min, int max);
@ -59,6 +59,8 @@ public:
std::string str() const;
private:
int m_min;
int m_max;
boost::scoped_ptr<AxisEventHandler> m_handler;
std::vector<AxisFilterPtr> m_filters;
};
@ -69,7 +71,7 @@ public:
virtual ~AxisEventHandler() {}
virtual void init(uInput& uinput) const =0;
virtual void send(uInput& uinput, int old_value, int value) const =0;
virtual void send(uInput& uinput, int value) =0;
virtual void update(uInput& uinput, int msec_delta) =0;
virtual void set_axis_range(int min, int max) {}
@ -87,7 +89,7 @@ public:
RelAxisEventHandler(int device_id, int code, int repeat = 10, float value = 5);
void init(uInput& uinput) const;
void send(uInput& uinput, int old_value, int value) const;
void send(uInput& uinput, int value);
void update(uInput& uinput, int msec_delta);
std::string str() const;
@ -110,7 +112,7 @@ public:
void set_axis_range(int min, int max);
void init(uInput& uinput) const;
void send(uInput& uinput, int old_value, int value) const;
void send(uInput& uinput, int value);
void update(uInput& uinput, int msec_delta);
std::string str() const;
@ -132,7 +134,7 @@ public:
KeyAxisEventHandler();
void init(uInput& uinput) const;
void send(uInput& uinput, int old_value, int value) const;
void send(uInput& uinput, int value);
void update(uInput& uinput, int msec_delta);
std::string str() const;
@ -140,6 +142,8 @@ public:
private:
static const int MAX_MODIFIER = 4;
int m_old_value;
// Array is terminated by -1
UIEvent m_up_codes[MAX_MODIFIER+1];
UIEvent m_down_codes[MAX_MODIFIER+1];

View file

@ -18,20 +18,50 @@
#include "axis_filter.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <iostream>
#include <math.h>
#include <sstream>
#include <stdexcept>
#include "helper.hpp"
namespace {
/** converts the arbitary range to [-1,1] */
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;
}
/** converts the range [-1,1] to [min,max] */
inline int from_float(float value, int min, int max)
{
return (value + 1.0f) / 2.0f * static_cast<float>(max - min) + min;
}
} // namespace
AxisFilterPtr
AxisFilter::from_string(const std::string& str)
{
std::string::size_type p = str.find(':');
const std::string& filtername = str.substr(0, p);
std::string rest = str.substr(p+1);
if (filtername == "invert")
{
return AxisFilterPtr(new InvertAxisFilter);
}
else if (filtername == "calibration" || filtername == "cal")
{
return AxisFilterPtr(CalibrationAxisFilter::from_string(rest));
}
else if (filtername == "sensitivity" || filtername == "sen")
{
return AxisFilterPtr(SensitivityAxisFilter::from_string(rest));
}
else
{
std::ostringstream out;
@ -41,9 +71,100 @@ AxisFilter::from_string(const std::string& str)
}
int
InvertAxisFilter::filter(int old_value, int value)
InvertAxisFilter::filter(int value, int min, int max)
{
// FIXME: take min/max into account
return -value;
}
SensitivityAxisFilter*
SensitivityAxisFilter::from_string(const std::string& str)
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(str, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
float sensitivity = 0.0f;
int j = 0;
for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i, ++j)
{
switch(j)
{
case 0: sensitivity = boost::lexical_cast<float>(*i); break;
default: throw std::runtime_error("to many arguments");
};
}
return new SensitivityAxisFilter(sensitivity);
}
SensitivityAxisFilter::SensitivityAxisFilter(float sensitivity) :
m_sensitivity(sensitivity)
{
}
int
SensitivityAxisFilter::filter(int value, int min, int max)
{
float pos = to_float(value, min, max);
float t = powf(2, m_sensitivity);
if (pos > 0)
{
pos = powf(1.0f - powf(1.0f - pos, t), 1 / t);
return from_float(pos, min, max);
}
else
{
pos = powf(1.0f - powf(1.0f - -pos, t), 1 / t);
return from_float(-pos, min, max);
}
}
CalibrationAxisFilter*
CalibrationAxisFilter::from_string(const std::string& str)
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(str, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
int min = 0;
int center = 0;
int max = 0;
int j = 0;
for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i, ++j)
{
switch(j)
{
case 0: min = boost::lexical_cast<int>(*i); break;
case 1: center = boost::lexical_cast<int>(*i); break;
case 2: max = boost::lexical_cast<int>(*i); break;
default: throw std::runtime_error("to many arguments");
};
}
return new CalibrationAxisFilter(min, center, max);
}
CalibrationAxisFilter::CalibrationAxisFilter(int min, int center, int max) :
m_min(min),
m_center(center),
m_max(max)
{
}
int
CalibrationAxisFilter::filter(int value, int min, int max)
{
if (value < m_center)
value = -min * (value - m_center) / (m_center - m_min);
else if (value > m_center)
value = max * (value - m_center) / (m_max - m_center);
else
value = 0;
return Math::clamp(min, value, max);
}
/* EOF */

View file

@ -35,7 +35,7 @@ public:
AxisFilter() {}
virtual ~AxisFilter() {}
virtual int filter(int old_value, int value) =0;
virtual int filter(int value, int min, int max) =0;
};
class InvertAxisFilter : public AxisFilter
@ -44,7 +44,37 @@ public:
InvertAxisFilter() {}
~InvertAxisFilter() {}
int filter(int old_value, int value);
int filter(int value, int min, int max);
};
class SensitivityAxisFilter : public AxisFilter
{
public:
static SensitivityAxisFilter* from_string(const std::string& str);
public:
SensitivityAxisFilter(float sensitivity);
int filter(int value, int min, int max);
private:
float m_sensitivity;
};
class CalibrationAxisFilter : public AxisFilter
{
public:
static CalibrationAxisFilter* from_string(const std::string& str);
public:
CalibrationAxisFilter(int min, int center, int max);
int filter(int value, int min, int max);
private:
int m_min;
int m_center;
int m_max;
};
#endif

View file

@ -490,7 +490,6 @@ uInput::send_axis(XboxAxis code, int32_t value)
// not just when the axis changed
if (axis_state[code] != value)
{
int old_value = axis_state[code];
axis_state[code] = value;
bool event_send = false;
@ -503,7 +502,7 @@ uInput::send_axis(XboxAxis code, int32_t value)
const AxisEventPtr& event = cfg.get_axis_map().lookup(static_cast<XboxButton>(shift), code);
if (event)
{
event->send(*this, old_value, value);
event->send(*this, value);
event_send = true;
}
}
@ -515,7 +514,7 @@ uInput::send_axis(XboxAxis code, int32_t value)
const AxisEventPtr& event = cfg.get_axis_map().lookup(code);
if (event)
{
event->send(*this, old_value, value);
event->send(*this, value);
}
}
}