Implemented macro playback

This commit is contained in:
Ingo Ruhnke 2010-12-30 18:37:50 +01:00
parent 99ce84df6a
commit 4f5755bcf9
4 changed files with 291 additions and 5 deletions

47
examples/helloworld.macro Normal file
View file

@ -0,0 +1,47 @@
send KEY_LEFTSHIFT 1
send KEY_H 1
wait 100
send KEY_H 0
send KEY_LEFTSHIFT 0
send KEY_E 1
wait 100
send KEY_E 0
send KEY_L 1
wait 100
send KEY_L 0
send KEY_L 1
wait 100
send KEY_L 0
send KEY_O 1
wait 100
send KEY_O 0
send KEY_SPACE 1
wait 100
send KEY_SPACE 0
send KEY_LEFTSHIFT 1
send KEY_W 1
wait 100
send KEY_W 0
send KEY_LEFTSHIFT 0
send KEY_O 1
wait 100
send KEY_O 0
send KEY_R 1
wait 100
send KEY_R 0
send KEY_L 1
wait 100
send KEY_L 0
send KEY_D 1
wait 100
send KEY_D 0

View file

@ -26,6 +26,7 @@
#include <stdexcept>
#include <string.h>
#include <unistd.h>
#include <fstream>
#include "helper.hpp"
#include "button_event.hpp"
@ -95,6 +96,10 @@ ButtonEvent::from_string(const std::string& str)
{
return ButtonEvent::create(ExecButtonEventHandler::from_string(rest));
}
else if (token == "macro")
{
return ButtonEvent::create(MacroButtonEventHandler::from_string(rest));
}
else
{
// try to guess the type of event on the type of the first event code
@ -103,7 +108,7 @@ ButtonEvent::from_string(const std::string& str)
case EV_KEY: return ButtonEvent::create(KeyButtonEventHandler::from_string(str));
case EV_REL: return ButtonEvent::create(RelButtonEventHandler::from_string(str));
case EV_ABS: return ButtonEvent::create(AbsButtonEventHandler::from_string(str));
case -1: return ButtonEvent::invalid();
case -1: return ButtonEvent::invalid(); // void
default: assert(!"unknown type");
}
}
@ -118,9 +123,15 @@ ButtonEvent::ButtonEvent(ButtonEventHandler* handler) :
}
void
ButtonEvent::set_filters(const std::vector<ButtonFilterPtr>& filters)
ButtonEvent::add_filters(const std::vector<ButtonFilterPtr>& filters)
{
m_filters = filters;
std::copy(filters.begin(), filters.end(), std::back_inserter(m_filters));
}
void
ButtonEvent::add_filter(ButtonFilterPtr filter)
{
m_filters.push_back(filter);
}
void
@ -531,4 +542,188 @@ ExecButtonEventHandler::str() const
return "exec";
}
/* EOF */
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)
{
}
void
MacroButtonEventHandler::init(uInput& uinput) const
{
for(std::vector<MacroEvent>::const_iterator i = m_events.begin(); i != m_events.end(); ++i)
{
switch(i->type)
{
case MacroEvent::kSendOp:
uinput.create_uinput_device(i->send.event.device_id);
switch(i->send.event.type)
{
case EV_REL:
uinput.add_rel(i->send.event.device_id, i->send.event.code);
break;
case EV_KEY:
uinput.add_key(i->send.event.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.get_uinput(m_events[m_event_counter].send.event.device_id)
->send(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

@ -53,7 +53,8 @@ public:
void update(uInput& uinput, int msec_delta);
std::string str() const;
void set_filters(const std::vector<ButtonFilterPtr>& filters);
void add_filters(const std::vector<ButtonFilterPtr>& filters);
void add_filter(ButtonFilterPtr filter);
private:
bool m_last_send_state;
@ -157,6 +158,47 @@ 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) const;
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

@ -127,6 +127,8 @@ AutofireButtonFilter::filter(bool value)
}
else
{
// FIXME: should fire event at 0 not m_frequency
// auto fire
if (m_counter > m_frequency)
{