Implemnted some AxisFilter
This commit is contained in:
parent
c87dfc201d
commit
19ae8b55d1
8 changed files with 257 additions and 41 deletions
|
@ -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
31
TODO
|
@ -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
58
Xbox360
|
@ -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 )
|
||||
| /\ | `-'
|
||||
,---' `---.
|
||||
| < > |
|
||||
`---. .---'
|
||||
| \/ |
|
||||
`----'
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue