Added support mapping multiple events to the same key, toggled by the time the button is held

This commit is contained in:
Ingo Ruhnke 2010-12-25 21:52:07 +01:00
parent d5628cc1b5
commit 8f9f0516e7
7 changed files with 191 additions and 23 deletions

9
NEWS
View file

@ -1,3 +1,12 @@
xboxdrv 0.6.2 - (??/???/????)
==============================
* added ability to do toggle buttons
* added ability to invert buttons
* added ability to send different events depending on how long a
button was pressed
xboxdrv 0.6.1 - (21/Dec/2010)
==============================

View file

@ -121,20 +121,53 @@ KeyButtonEvent::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 j = 0;
for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i, ++j)
int idx = 0;
for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i, ++idx)
{
if (j == 0)
{
ev.reset(new KeyButtonEvent());
boost::char_separator<char> plus_sep("+", "", boost::keep_empty_tokens);
tokenizer ev_tokens(*i, plus_sep);
int k = 0;
for(tokenizer::iterator m = ev_tokens.begin(); m != ev_tokens.end(); ++m, ++k)
{
ev->m_codes[k] = str2key_event(*m);
}
switch(idx)
{
case 0:
{
ev.reset(new KeyButtonEvent());
boost::char_separator<char> plus_sep("+", "", boost::keep_empty_tokens);
tokenizer ev_tokens(*i, plus_sep);
int k = 0;
for(tokenizer::iterator m = ev_tokens.begin(); m != ev_tokens.end() && k < MAX_MODIFIER; ++m, ++k)
{
ev->m_codes[k] = str2key_event(*m);
}
}
break;
case 1:
{
boost::char_separator<char> plus_sep("+", "", boost::keep_empty_tokens);
tokenizer ev_tokens(*i, plus_sep);
int k = 0;
for(tokenizer::iterator m = ev_tokens.begin(); m != ev_tokens.end() && k < MAX_MODIFIER; ++m, ++k)
{
ev->m_secondary_codes[k] = str2key_event(*m);
}
ev->m_hold_threshold = 250;
}
break;
case 2:
{
ev->m_hold_threshold = boost::lexical_cast<int>(*i);
}
break;
default:
{
std::ostringstream out;
out << "to many arguments in '" << str << "'";
throw std::runtime_error(out.str());
}
break;
}
}
@ -142,15 +175,21 @@ KeyButtonEvent::from_string(const std::string& str)
}
KeyButtonEvent::KeyButtonEvent() :
m_codes()
m_state(false),
m_codes(),
m_secondary_codes(),
m_hold_threshold(0),
m_hold_counter(0)
{
std::fill_n(m_codes, MAX_MODIFIER + 1, UIEvent::invalid());
std::fill_n(m_secondary_codes, MAX_MODIFIER + 1, UIEvent::invalid());
}
KeyButtonEvent::KeyButtonEvent(int code) :
m_codes()
{
std::fill_n(m_codes, MAX_MODIFIER + 1, UIEvent::invalid());
std::fill_n(m_secondary_codes, MAX_MODIFIER + 1, UIEvent::invalid());
m_codes[0] = UIEvent::create(DEVICEID_AUTO, EV_KEY, code);
}
@ -162,17 +201,100 @@ KeyButtonEvent::init(uInput& uinput) const
uinput.create_uinput_device(m_codes[i].device_id);
uinput.add_key(m_codes[i].device_id, m_codes[i].code);
}
if (m_hold_threshold)
{
for(int i = 0; m_secondary_codes[i].is_valid(); ++i)
{
uinput.add_key(m_secondary_codes[i].device_id, m_secondary_codes[i].code);
}
}
}
void
KeyButtonEvent::send(uInput& uinput, bool value) const
KeyButtonEvent::send(uInput& uinput, bool value)
{
value = apply_filter(value);
// FIXME: should key releases in return
for(int i = 0; m_codes[i].is_valid(); ++i)
if (m_state != value)
{
uinput.send_key(m_codes[i].device_id, m_codes[i].code, value);
m_state = value;
if (m_hold_threshold == 0)
{
// FIXME: should handle key releases in reverse order
for(int i = 0; m_codes[i].is_valid(); ++i)
{
uinput.send_key(m_codes[i].device_id, m_codes[i].code, m_state);
}
}
else
{
if (m_hold_counter < m_hold_threshold)
{
if (m_state)
{
// we are only sending events after release or when
// hold_threshold is passed
}
else
{
// send both a press and release event after another, aka a "click"
for(int i = 0; m_codes[i].is_valid(); ++i)
{
uinput.send_key(m_codes[i].device_id, m_codes[i].code, true);
}
// FIXME: should do this in reverse order
for(int i = 0; m_codes[i].is_valid(); ++i)
{
uinput.send_key(m_codes[i].device_id, m_codes[i].code, false);
}
}
}
else
{
if (m_state)
{
// should never happen
}
else
{
// FIXME: should do in reverse
for(int i = 0; m_secondary_codes[i].is_valid(); ++i)
{
uinput.send_key(m_secondary_codes[i].device_id, m_secondary_codes[i].code, false);
}
}
}
if (!m_state)
{
m_hold_counter = 0;
}
}
}
}
void
KeyButtonEvent::update(uInput& uinput, int msec_delta)
{
if (m_state && m_hold_threshold)
{
if (m_hold_counter < m_hold_threshold &&
m_hold_counter + msec_delta >= m_hold_threshold)
{
// start sending the secondary events
for(int i = 0; m_secondary_codes[i].is_valid(); ++i)
{
uinput.send_key(m_secondary_codes[i].device_id, m_secondary_codes[i].code, true);
}
uinput.sync();
}
if (m_hold_counter < m_hold_threshold)
{
m_hold_counter += msec_delta;
}
}
}
@ -213,7 +335,7 @@ AbsButtonEvent::init(uInput& uinput) const
}
void
AbsButtonEvent::send(uInput& uinput, bool value) const
AbsButtonEvent::send(uInput& uinput, bool value)
{
value = apply_filter(value);
@ -276,7 +398,7 @@ RelButtonEvent::init(uInput& uinput) const
}
void
RelButtonEvent::send(uInput& uinput, bool value) const
RelButtonEvent::send(uInput& uinput, bool value)
{
value = apply_filter(value);

View file

@ -49,7 +49,8 @@ protected:
public:
virtual void init(uInput& uinput) const =0;
virtual void send(uInput& uinput, bool value) const =0;
virtual void send(uInput& uinput, bool value) =0;
virtual void update(uInput& uinput, int msec_delta) =0;
void set_filters(const std::vector<ButtonFilterPtr>& filters);
@ -69,15 +70,20 @@ public:
KeyButtonEvent(int code);
void init(uInput& uinput) const;
void send(uInput& uinput, bool value) const;
void send(uInput& uinput, bool value);
void update(uInput& uinput, int msec_delta);
std::string str() const;
private:
static const int MAX_MODIFIER = 4;
bool m_state;
// Array is terminated by !is_valid()
UIEvent m_codes[MAX_MODIFIER+1];
UIEvent m_secondary_codes[MAX_MODIFIER+1];
int m_hold_threshold;
int m_hold_counter;
};
class AbsButtonEvent : public ButtonEvent
@ -89,7 +95,8 @@ public:
AbsButtonEvent(int code);
void init(uInput& uinput) const;
void send(uInput& uinput, bool value) const;
void send(uInput& uinput, bool value);
void update(uInput& uinput, int msec_delta) {}
std::string str() const;
@ -107,12 +114,14 @@ public:
RelButtonEvent(const UIEvent& code);
void init(uInput& uinput) const;
void send(uInput& uinput, bool value) const;
void send(uInput& uinput, bool value);
void update(uInput& uinput, int msec_delta) {}
std::string str() const;
private:
UIEvent m_code;
int m_value;
int m_repeat;
};

View file

@ -95,4 +95,19 @@ ButtonMap::init(uInput& uinput) const
}
}
void
ButtonMap::update(uInput& uinput, int msec_delta)
{
for(int shift_code = 0; shift_code < XBOX_BTN_MAX; ++shift_code)
{
for(int code = 0; code < XBOX_BTN_MAX; ++code)
{
if (btn_map[shift_code][code])
{
btn_map[shift_code][code]->update(uinput, msec_delta);
}
}
}
}
/* EOF */

View file

@ -42,6 +42,7 @@ public:
bool send(uInput& uinput, XboxButton code, bool value) const;
bool send(uInput& uinput, XboxButton shift_code, XboxButton code, bool value) const;
void update(uInput& uinput, int msec_delta);
void clear();
};

View file

@ -320,6 +320,8 @@ uInput::send(Xbox360GuitarMsg& msg)
void
uInput::update(int msec_delta)
{
cfg.get_btn_map().update(*this, msec_delta);
for(std::map<UIEvent, RelRepeat>::iterator i = rel_repeat_lst.begin(); i != rel_repeat_lst.end(); ++i)
{
i->second.time_count += msec_delta;
@ -438,6 +440,15 @@ uInput::send_key(int device_id, int ev_code, bool value)
}
}
void
uInput::sync()
{
for(uInputDevs::iterator i = uinput_devs.begin(); i != uinput_devs.end(); ++i)
{
i->second->sync();
}
}
void
uInput::send_rel_repetitive(const UIEvent& code, int value, int repeat_interval)
{

View file

@ -78,6 +78,7 @@ public:
void send_key(int device_id, int ev_code, bool value);
void send_rel_repetitive(const UIEvent& code, int value, int repeat_interval);
void sync();
LinuxUinput* get_uinput(int device_id) const;
LinuxUinput* get_force_feedback_uinput() const;