Split ButtonEvent classes into separate files

This commit is contained in:
Ingo Ruhnke 2011-04-11 17:16:06 +02:00
parent 1de36a5664
commit 0fe69b98a9
13 changed files with 956 additions and 682 deletions

View file

@ -149,6 +149,7 @@ libxboxdrv = env.StaticLibrary('xboxdrv',
Glob('src/*.cpp') +
Glob('src/axisfilter/*.cpp') +
Glob('src/buttonfilter/*.cpp') +
Glob('src/buttonevent/*.cpp') +
Glob('src/modifier/*.cpp'))
env.Append(LIBS = libxboxdrv)

View file

@ -25,6 +25,12 @@
#include "evdev_helper.hpp"
#include "log.hpp"
#include "uinput.hpp"
#include "buttonevent/abs_button_event_handler.hpp"
#include "buttonevent/exec_button_event_handler.hpp"
#include "buttonevent/key_button_event_handler.hpp"
#include "buttonevent/macro_button_event_handler.hpp"
#include "buttonevent/rel_button_event_handler.hpp"
ButtonEventPtr
ButtonEvent::invalid()
@ -180,560 +186,4 @@ ButtonEvent::str() const
return m_handler->str();
}
KeyButtonEventHandler*
KeyButtonEventHandler::from_string(const std::string& str)
{
//std::cout << " KeyButtonEventHandler::from_string: " << str << std::endl;
std::auto_ptr<KeyButtonEventHandler> ev;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(str, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
int idx = 0;
for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i, ++idx)
{
switch(idx)
{
case 0:
{
ev.reset(new KeyButtonEventHandler());
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;
}
}
return ev.release();
}
KeyButtonEventHandler::KeyButtonEventHandler() :
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());
}
KeyButtonEventHandler::KeyButtonEventHandler(int device_id, int code) :
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());
m_codes[0] = UIEvent::create(device_id, EV_KEY, code);
}
void
KeyButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
for(int i = 0; m_codes[i].is_valid(); ++i)
{
m_codes[i].resolve_device_id(slot, extra_devices);
uinput.add_key(m_codes[i].get_device_id(), m_codes[i].code);
}
if (m_hold_threshold)
{
for(int i = 0; m_secondary_codes[i].is_valid(); ++i)
{
m_secondary_codes[i].resolve_device_id(slot, extra_devices);
uinput.add_key(m_secondary_codes[i].get_device_id(), m_secondary_codes[i].code);
}
}
}
void
KeyButtonEventHandler::send(UInput& uinput, bool value)
{
if (m_state != 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].get_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].get_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].get_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].get_device_id(), m_secondary_codes[i].code, false);
}
}
}
if (!m_state)
{
m_hold_counter = 0;
}
}
}
}
void
KeyButtonEventHandler::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].get_device_id(), m_secondary_codes[i].code, true);
}
uinput.sync();
}
if (m_hold_counter < m_hold_threshold)
{
m_hold_counter += msec_delta;
}
}
}
std::string
KeyButtonEventHandler::str() const
{
std::ostringstream out;
for(int i = 0; m_codes[i].is_valid();)
{
out << m_codes[i].get_device_id() << "-" << m_codes[i].code;
++i;
if (m_codes[i].is_valid())
out << "+";
}
return out.str();
}
AbsButtonEventHandler*
AbsButtonEventHandler::from_string(const std::string& str)
{
// FIXME: Need magic to detect min/max of the axis
assert(!"not implemented");
}
AbsButtonEventHandler::AbsButtonEventHandler(int code) :
m_code(UIEvent::invalid()),
m_value()
{
assert(!"Not implemented");
// FIXME: Need magic to detect min/max of the axis
}
void
AbsButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
}
void
AbsButtonEventHandler::send(UInput& uinput, bool value)
{
if (value)
{
uinput.send_abs(m_code.get_device_id(), m_code.code, m_value);
}
}
std::string
AbsButtonEventHandler::str() const
{
std::ostringstream out;
out << "abs: " << m_code.get_device_id() << "-" << m_code.code << ":" << m_value;
return out.str();
}
RelButtonEventHandler*
RelButtonEventHandler::from_string(const std::string& str)
{
std::auto_ptr<RelButtonEventHandler> ev;
int idx = 0;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(str, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i, ++idx)
{
switch(idx)
{
case 0:
ev.reset(new RelButtonEventHandler(str2rel_event(*i)));
break;
case 1:
ev->m_value = boost::lexical_cast<int>(*i);
break;
case 2:
ev->m_repeat = boost::lexical_cast<int>(*i);
break;
}
}
return ev.release();
}
RelButtonEventHandler::RelButtonEventHandler(const UIEvent& code) :
m_code(code),
m_value(3),
m_repeat(100)
{
}
void
RelButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
m_code.resolve_device_id(slot, extra_devices);
uinput.add_rel(m_code.get_device_id(), m_code.code);
}
void
RelButtonEventHandler::send(UInput& uinput, bool value)
{
if (m_repeat == -1)
{
if (value)
{
uinput.send_rel(m_code.get_device_id(), m_code.code, m_value);
}
}
else
{
if (value)
{
uinput.send_rel_repetitive(m_code, m_value, m_repeat);
}
else
{
uinput.send_rel_repetitive(m_code, m_value, -1);
}
}
}
std::string
RelButtonEventHandler::str() const
{
std::ostringstream out;
out << "rel:" << m_code.get_device_id() << "-" << m_code.code << ":" << m_value << ":" << m_repeat;
return out.str();
}
ExecButtonEventHandler*
ExecButtonEventHandler::from_string(const std::string& str)
{
std::vector<std::string> args;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(str, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
std::copy(tokens.begin(), tokens.end(), std::back_inserter(args));
return new ExecButtonEventHandler(args);
}
ExecButtonEventHandler::ExecButtonEventHandler(const std::vector<std::string>& args) :
m_args(args)
{
}
void
ExecButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
// nothing to do
}
void
ExecButtonEventHandler::send(UInput& uinput, bool value)
{
if (value)
{
pid_t pid = fork();
if (pid == 0)
{
char** argv = static_cast<char**>(malloc(sizeof(char*) * (m_args.size() + 1)));
for(size_t i = 0; i < m_args.size(); ++i)
{
argv[i] = strdup(m_args[i].c_str());
}
argv[m_args.size()] = NULL;
if (execvp(m_args[0].c_str(), argv) == -1)
{
log_error("exec failed: " << strerror(errno));
_exit(EXIT_FAILURE);
}
}
}
}
std::string
ExecButtonEventHandler::str() const
{
return "exec";
}
MacroButtonEventHandler*
MacroButtonEventHandler::from_string(const std::string& str)
{
std::vector<MacroEvent> events;
std::ifstream in(str.c_str());
std::string line;
while(std::getline(in, line))
{
MacroEvent ev = macro_event_from_string(line);
if (ev.type != MacroEvent::kNull)
{
events.push_back(ev);
}
}
return new MacroButtonEventHandler(events);
}
MacroButtonEventHandler::MacroEvent
MacroButtonEventHandler::macro_event_from_string(const std::string& str)
{
MacroEvent event;
event.type = MacroEvent::kNull;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(str, boost::char_separator<char>(" "));
int idx = 0;
for(tokenizer::iterator t = tokens.begin(); t != tokens.end(); ++t, ++idx)
{
switch(idx)
{
case 0:
if (*t == "send")
{
event.type = MacroEvent::kSendOp;
event.send.event = UIEvent::invalid();
event.send.value = 0;
}
else if (*t == "wait")
{
event.type = MacroEvent::kWaitOp;
event.wait.msec = 0;
}
break;
case 1:
{
if (event.type == MacroEvent::kSendOp)
{
switch(get_event_type(*t))
{
case EV_REL: event.send.event = str2rel_event(*t); break;
case EV_ABS: event.send.event = str2abs_event(*t); break;
case EV_KEY: event.send.event = str2key_event(*t); break;
default: throw std::runtime_error("unknown event type");
}
}
else if (event.type == MacroEvent::kWaitOp)
{
event.wait.msec = boost::lexical_cast<int>(*t);
}
}
break;
case 2:
{
if (event.type == MacroEvent::kSendOp)
{
event.send.value = boost::lexical_cast<int>(*t);
}
else
{
throw std::runtime_error("to many arguments for 'wait'");
}
}
break;
}
}
return event;
}
MacroButtonEventHandler::MacroButtonEventHandler(const std::vector<MacroEvent>& events) :
m_events(events),
m_send_in_progress(false),
m_countdown(0),
m_event_counter()
{
}
void
MacroButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
for(std::vector<MacroEvent>::iterator i = m_events.begin(); i != m_events.end(); ++i)
{
switch(i->type)
{
case MacroEvent::kSendOp:
switch(i->send.event.type)
{
case EV_REL:
i->send.event.resolve_device_id(slot, extra_devices),
uinput.add_rel(i->send.event.get_device_id(), i->send.event.code);
break;
case EV_KEY:
i->send.event.resolve_device_id(slot, extra_devices),
uinput.add_key(i->send.event.get_device_id(), i->send.event.code);
break;
default:
assert(!"not implemented");
break;
}
break;
default:
// nothing to do
break;
}
}
}
void
MacroButtonEventHandler::send(UInput& uinput, bool value)
{
if (value && !m_send_in_progress)
{
m_send_in_progress = true;
m_event_counter = 0;
m_countdown = 0;
}
}
void
MacroButtonEventHandler::update(UInput& uinput, int msec_delta)
{
if (m_send_in_progress)
{
m_countdown -= msec_delta;
if (m_countdown <= 0)
{
while(true)
{
switch(m_events[m_event_counter].type)
{
case MacroEvent::kSendOp:
uinput.send(m_events[m_event_counter].send.event.get_device_id(),
m_events[m_event_counter].send.event.type,
m_events[m_event_counter].send.event.code,
m_events[m_event_counter].send.value);
break;
case MacroEvent::kWaitOp:
m_countdown = m_events[m_event_counter].wait.msec;
if (m_countdown > 0)
{
m_event_counter += 1;
return;
}
break;
default:
assert(!"never reached");
break;
}
m_event_counter += 1;
if (m_event_counter == m_events.size())
{
m_send_in_progress = false;
m_event_counter = 0;
m_countdown = 0;
return;
}
}
}
}
}
std::string
MacroButtonEventHandler::str() const
{
return "macro";
}
/* EOF */
/* EOF */

View file

@ -73,131 +73,6 @@ public:
virtual std::string str() const =0;
};
class KeyButtonEventHandler : public ButtonEventHandler
{
public:
static KeyButtonEventHandler* from_string(const std::string& str);
public:
KeyButtonEventHandler();
KeyButtonEventHandler(int deviceid, int code);
void init(UInput& uinput, int slot, bool extra_devices);
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 AbsButtonEventHandler : public ButtonEventHandler
{
public:
static AbsButtonEventHandler* from_string(const std::string& str);
public:
AbsButtonEventHandler(int code);
void init(UInput& uinput, int slot, bool extra_devices);
void send(UInput& uinput, bool value);
void update(UInput& uinput, int msec_delta) {}
std::string str() const;
private:
UIEvent m_code;
int m_value;
};
class RelButtonEventHandler : public ButtonEventHandler
{
public:
static RelButtonEventHandler* from_string(const std::string& str);
public:
RelButtonEventHandler(const UIEvent& code);
void init(UInput& uinput, int slot, bool extra_devices);
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;
};
class ExecButtonEventHandler : public ButtonEventHandler
{
public:
static ExecButtonEventHandler* from_string(const std::string& str);
public:
ExecButtonEventHandler(const std::vector<std::string>& args);
void init(UInput& uinput, int slot, bool extra_devices);
void send(UInput& uinput, bool value);
void update(UInput& uinput, int msec_delta) {}
std::string str() const;
private:
std::vector<std::string> m_args;
};
class MacroButtonEventHandler : public ButtonEventHandler
{
public:
private:
struct MacroEvent {
enum { kSendOp, kWaitOp, kNull } type;
union {
struct {
UIEvent event;
int value;
} send;
struct {
int msec;
} wait;
};
};
public:
static MacroButtonEventHandler* from_string(const std::string& str);
public:
MacroButtonEventHandler(const std::vector<MacroEvent>& events);
void init(UInput& uinput, int slot, bool extra_devices);
void send(UInput& uinput, bool value);
void update(UInput& uinput, int msec_delta);
std::string str() const;
private:
static MacroEvent macro_event_from_string(const std::string& str);
private:
std::vector<MacroEvent> m_events;
bool m_send_in_progress;
int m_countdown;
std::vector<MacroEvent>::size_type m_event_counter;
};
#endif
/* EOF */

View file

@ -0,0 +1,60 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program 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 3 of the License, or
** (at your option) any later version.
**
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "abs_button_event_handler.hpp"
#include "uinput.hpp"
AbsButtonEventHandler*
AbsButtonEventHandler::from_string(const std::string& str)
{
// FIXME: Need magic to detect min/max of the axis
assert(!"not implemented");
}
AbsButtonEventHandler::AbsButtonEventHandler(int code) :
m_code(UIEvent::invalid()),
m_value()
{
assert(!"Not implemented");
// FIXME: Need magic to detect min/max of the axis
}
void
AbsButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
}
void
AbsButtonEventHandler::send(UInput& uinput, bool value)
{
if (value)
{
uinput.send_abs(m_code.get_device_id(), m_code.code, m_value);
}
}
std::string
AbsButtonEventHandler::str() const
{
std::ostringstream out;
out << "abs: " << m_code.get_device_id() << "-" << m_code.code << ":" << m_value;
return out.str();
}
/* EOF */

View file

@ -0,0 +1,45 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program 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 3 of the License, or
** (at your option) any later version.
**
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADER_XBOXDRV_BUTTONEVENT_ABS_BUTTON_EVENT_HANDLER_HPP
#define HEADER_XBOXDRV_BUTTONEVENT_ABS_BUTTON_EVENT_HANDLER_HPP
#include "button_event.hpp"
class AbsButtonEventHandler : public ButtonEventHandler
{
public:
static AbsButtonEventHandler* from_string(const std::string& str);
public:
AbsButtonEventHandler(int code);
void init(UInput& uinput, int slot, bool extra_devices);
void send(UInput& uinput, bool value);
void update(UInput& uinput, int msec_delta) {}
std::string str() const;
private:
UIEvent m_code;
int m_value;
};
#endif
/* EOF */

View file

@ -0,0 +1,81 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program 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 3 of the License, or
** (at your option) any later version.
**
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exec_button_event_handler.hpp"
#include <boost/tokenizer.hpp>
#include <errno.h>
#include <string.h>
#include "log.hpp"
ExecButtonEventHandler*
ExecButtonEventHandler::from_string(const std::string& str)
{
std::vector<std::string> args;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(str, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
std::copy(tokens.begin(), tokens.end(), std::back_inserter(args));
return new ExecButtonEventHandler(args);
}
ExecButtonEventHandler::ExecButtonEventHandler(const std::vector<std::string>& args) :
m_args(args)
{
}
void
ExecButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
// nothing to do
}
void
ExecButtonEventHandler::send(UInput& uinput, bool value)
{
if (value)
{
pid_t pid = fork();
if (pid == 0)
{
char** argv = static_cast<char**>(malloc(sizeof(char*) * (m_args.size() + 1)));
for(size_t i = 0; i < m_args.size(); ++i)
{
argv[i] = strdup(m_args[i].c_str());
}
argv[m_args.size()] = NULL;
if (execvp(m_args[0].c_str(), argv) == -1)
{
log_error("exec failed: " << strerror(errno));
_exit(EXIT_FAILURE);
}
}
}
}
std::string
ExecButtonEventHandler::str() const
{
return "exec";
}
/* EOF */

View file

@ -0,0 +1,44 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program 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 3 of the License, or
** (at your option) any later version.
**
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADER_XBOXDRV_BUTTONEVENT_EXEC_BUTTON_EVENT_HANDLER_HPP
#define HEADER_XBOXDRV_BUTTONEVENT_EXEC_BUTTON_EVENT_HANDLER_HPP
#include "button_event.hpp"
class ExecButtonEventHandler : public ButtonEventHandler
{
public:
static ExecButtonEventHandler* from_string(const std::string& str);
public:
ExecButtonEventHandler(const std::vector<std::string>& args);
void init(UInput& uinput, int slot, bool extra_devices);
void send(UInput& uinput, bool value);
void update(UInput& uinput, int msec_delta) {}
std::string str() const;
private:
std::vector<std::string> m_args;
};
#endif
/* EOF */

View file

@ -0,0 +1,230 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program 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 3 of the License, or
** (at your option) any later version.
**
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "buttonevent/key_button_event_handler.hpp"
#include <boost/tokenizer.hpp>
#include <linux/input.h>
#include "evdev_helper.hpp"
#include "uinput.hpp"
KeyButtonEventHandler*
KeyButtonEventHandler::from_string(const std::string& str)
{
//std::cout << " KeyButtonEventHandler::from_string: " << str << std::endl;
std::auto_ptr<KeyButtonEventHandler> ev;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(str, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
int idx = 0;
for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i, ++idx)
{
switch(idx)
{
case 0:
{
ev.reset(new KeyButtonEventHandler());
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;
}
}
return ev.release();
}
KeyButtonEventHandler::KeyButtonEventHandler() :
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());
}
KeyButtonEventHandler::KeyButtonEventHandler(int device_id, int code) :
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());
m_codes[0] = UIEvent::create(device_id, EV_KEY, code);
}
void
KeyButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
for(int i = 0; m_codes[i].is_valid(); ++i)
{
m_codes[i].resolve_device_id(slot, extra_devices);
uinput.add_key(m_codes[i].get_device_id(), m_codes[i].code);
}
if (m_hold_threshold)
{
for(int i = 0; m_secondary_codes[i].is_valid(); ++i)
{
m_secondary_codes[i].resolve_device_id(slot, extra_devices);
uinput.add_key(m_secondary_codes[i].get_device_id(), m_secondary_codes[i].code);
}
}
}
void
KeyButtonEventHandler::send(UInput& uinput, bool value)
{
if (m_state != 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].get_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].get_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].get_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].get_device_id(), m_secondary_codes[i].code, false);
}
}
}
if (!m_state)
{
m_hold_counter = 0;
}
}
}
}
void
KeyButtonEventHandler::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].get_device_id(), m_secondary_codes[i].code, true);
}
uinput.sync();
}
if (m_hold_counter < m_hold_threshold)
{
m_hold_counter += msec_delta;
}
}
}
std::string
KeyButtonEventHandler::str() const
{
std::ostringstream out;
for(int i = 0; m_codes[i].is_valid();)
{
out << m_codes[i].get_device_id() << "-" << m_codes[i].code;
++i;
if (m_codes[i].is_valid())
out << "+";
}
return out.str();
}
/* EOF */

View file

@ -0,0 +1,52 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program 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 3 of the License, or
** (at your option) any later version.
**
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADER_XBOXDRV_BUTTONEVENT_KEY_BUTTON_EVENT_HANDLER_HPP
#define HEADER_XBOXDRV_BUTTONEVENT_KEY_BUTTON_EVENT_HANDLER_HPP
#include "button_event.hpp"
class KeyButtonEventHandler : public ButtonEventHandler
{
public:
static KeyButtonEventHandler* from_string(const std::string& str);
public:
KeyButtonEventHandler();
KeyButtonEventHandler(int deviceid, int code);
void init(UInput& uinput, int slot, bool extra_devices);
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;
};
#endif
/* EOF */

View file

@ -0,0 +1,221 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program 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 3 of the License, or
** (at your option) any later version.
**
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "buttonevent/macro_button_event_handler.hpp"
#include <boost/tokenizer.hpp>
#include <fstream>
#include <linux/input.h>
#include <vector>
#include "evdev_helper.hpp"
#include "uinput.hpp"
MacroButtonEventHandler*
MacroButtonEventHandler::from_string(const std::string& str)
{
std::vector<MacroEvent> events;
std::ifstream in(str.c_str());
std::string line;
while(std::getline(in, line))
{
MacroEvent ev = macro_event_from_string(line);
if (ev.type != MacroEvent::kNull)
{
events.push_back(ev);
}
}
return new MacroButtonEventHandler(events);
}
MacroButtonEventHandler::MacroEvent
MacroButtonEventHandler::macro_event_from_string(const std::string& str)
{
MacroEvent event;
event.type = MacroEvent::kNull;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(str, boost::char_separator<char>(" "));
int idx = 0;
for(tokenizer::iterator t = tokens.begin(); t != tokens.end(); ++t, ++idx)
{
switch(idx)
{
case 0:
if (*t == "send")
{
event.type = MacroEvent::kSendOp;
event.send.event = UIEvent::invalid();
event.send.value = 0;
}
else if (*t == "wait")
{
event.type = MacroEvent::kWaitOp;
event.wait.msec = 0;
}
break;
case 1:
{
if (event.type == MacroEvent::kSendOp)
{
switch(get_event_type(*t))
{
case EV_REL: event.send.event = str2rel_event(*t); break;
case EV_ABS: event.send.event = str2abs_event(*t); break;
case EV_KEY: event.send.event = str2key_event(*t); break;
default: throw std::runtime_error("unknown event type");
}
}
else if (event.type == MacroEvent::kWaitOp)
{
event.wait.msec = boost::lexical_cast<int>(*t);
}
}
break;
case 2:
{
if (event.type == MacroEvent::kSendOp)
{
event.send.value = boost::lexical_cast<int>(*t);
}
else
{
throw std::runtime_error("to many arguments for 'wait'");
}
}
break;
}
}
return event;
}
MacroButtonEventHandler::MacroButtonEventHandler(const std::vector<MacroEvent>& events) :
m_events(events),
m_send_in_progress(false),
m_countdown(0),
m_event_counter()
{
}
void
MacroButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
for(std::vector<MacroEvent>::iterator i = m_events.begin(); i != m_events.end(); ++i)
{
switch(i->type)
{
case MacroEvent::kSendOp:
switch(i->send.event.type)
{
case EV_REL:
i->send.event.resolve_device_id(slot, extra_devices),
uinput.add_rel(i->send.event.get_device_id(), i->send.event.code);
break;
case EV_KEY:
i->send.event.resolve_device_id(slot, extra_devices),
uinput.add_key(i->send.event.get_device_id(), i->send.event.code);
break;
case EV_ABS:
//i->send.event.resolve_device_id(slot, extra_devices);
// uinput.add_abs(i->send.event.get_device_id(), i->send.event.code);
break;
default:
assert(!"not implemented");
break;
}
break;
default:
// nothing to do
break;
}
}
}
void
MacroButtonEventHandler::send(UInput& uinput, bool value)
{
if (value && !m_send_in_progress)
{
m_send_in_progress = true;
m_event_counter = 0;
m_countdown = 0;
}
}
void
MacroButtonEventHandler::update(UInput& uinput, int msec_delta)
{
if (m_send_in_progress)
{
m_countdown -= msec_delta;
if (m_countdown <= 0)
{
while(true)
{
switch(m_events[m_event_counter].type)
{
case MacroEvent::kSendOp:
uinput.send(m_events[m_event_counter].send.event.get_device_id(),
m_events[m_event_counter].send.event.type,
m_events[m_event_counter].send.event.code,
m_events[m_event_counter].send.value);
break;
case MacroEvent::kWaitOp:
m_countdown = m_events[m_event_counter].wait.msec;
if (m_countdown > 0)
{
m_event_counter += 1;
return;
}
break;
default:
assert(!"never reached");
break;
}
m_event_counter += 1;
if (m_event_counter == m_events.size())
{
m_send_in_progress = false;
m_event_counter = 0;
m_countdown = 0;
return;
}
}
}
}
}
std::string
MacroButtonEventHandler::str() const
{
return "macro";
}
/* EOF */

View file

@ -0,0 +1,67 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program 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 3 of the License, or
** (at your option) any later version.
**
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADER_XBOXDRV_BUTTONEVENT_MACRO_BUTTON_EVENT_HANDLER_HPP
#define HEADER_XBOXDRV_BUTTONEVENT_MACRO_BUTTON_EVENT_HANDLER_HPP
#include "button_event.hpp"
class MacroButtonEventHandler : public ButtonEventHandler
{
public:
private:
struct MacroEvent {
enum { kSendOp, kWaitOp, kNull } type;
union {
struct {
UIEvent event;
int value;
} send;
struct {
int msec;
} wait;
};
};
public:
static MacroButtonEventHandler* from_string(const std::string& str);
public:
MacroButtonEventHandler(const std::vector<MacroEvent>& events);
void init(UInput& uinput, int slot, bool extra_devices);
void send(UInput& uinput, bool value);
void update(UInput& uinput, int msec_delta);
std::string str() const;
private:
static MacroEvent macro_event_from_string(const std::string& str);
private:
std::vector<MacroEvent> m_events;
bool m_send_in_progress;
int m_countdown;
std::vector<MacroEvent>::size_type m_event_counter;
};
#endif
/* EOF */

View file

@ -0,0 +1,101 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program 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 3 of the License, or
** (at your option) any later version.
**
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "buttonevent/rel_button_event_handler.hpp"
#include <boost/tokenizer.hpp>
#include "evdev_helper.hpp"
#include "uinput.hpp"
RelButtonEventHandler*
RelButtonEventHandler::from_string(const std::string& str)
{
std::auto_ptr<RelButtonEventHandler> ev;
int idx = 0;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tokens(str, boost::char_separator<char>(":", "", boost::keep_empty_tokens));
for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i, ++idx)
{
switch(idx)
{
case 0:
ev.reset(new RelButtonEventHandler(str2rel_event(*i)));
break;
case 1:
ev->m_value = boost::lexical_cast<int>(*i);
break;
case 2:
ev->m_repeat = boost::lexical_cast<int>(*i);
break;
}
}
return ev.release();
}
RelButtonEventHandler::RelButtonEventHandler(const UIEvent& code) :
m_code(code),
m_value(3),
m_repeat(100)
{
}
void
RelButtonEventHandler::init(UInput& uinput, int slot, bool extra_devices)
{
m_code.resolve_device_id(slot, extra_devices);
uinput.add_rel(m_code.get_device_id(), m_code.code);
}
void
RelButtonEventHandler::send(UInput& uinput, bool value)
{
if (m_repeat == -1)
{
if (value)
{
uinput.send_rel(m_code.get_device_id(), m_code.code, m_value);
}
}
else
{
if (value)
{
uinput.send_rel_repetitive(m_code, m_value, m_repeat);
}
else
{
uinput.send_rel_repetitive(m_code, m_value, -1);
}
}
}
std::string
RelButtonEventHandler::str() const
{
std::ostringstream out;
out << "rel:" << m_code.get_device_id() << "-" << m_code.code << ":" << m_value << ":" << m_repeat;
return out.str();
}
/* EOF */

View file

@ -0,0 +1,47 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program 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 3 of the License, or
** (at your option) any later version.
**
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADER_XBOXDRV_BUTTONEVENT_REL_BUTTON_EVENT_HANDLER_HPP
#define HEADER_XBOXDRV_BUTTONEVENT_REL_BUTTON_EVENT_HANDLER_HPP
#include "button_event.hpp"
class RelButtonEventHandler : public ButtonEventHandler
{
public:
static RelButtonEventHandler* from_string(const std::string& str);
public:
RelButtonEventHandler(const UIEvent& code);
void init(UInput& uinput, int slot, bool extra_devices);
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;
};
#endif
/* EOF */