Implemented macro playback
This commit is contained in:
parent
99ce84df6a
commit
4f5755bcf9
4 changed files with 291 additions and 5 deletions
47
examples/helloworld.macro
Normal file
47
examples/helloworld.macro
Normal 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
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue