diff --git a/examples/helloworld.macro b/examples/helloworld.macro new file mode 100644 index 0000000..0995d0b --- /dev/null +++ b/examples/helloworld.macro @@ -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 diff --git a/src/button_event.cpp b/src/button_event.cpp index 3752af3..b949daf 100644 --- a/src/button_event.cpp +++ b/src/button_event.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #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& filters) +ButtonEvent::add_filters(const std::vector& 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 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 > tokenizer; + tokenizer tokens(str, boost::char_separator(" ")); + 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(*t); + } + } + break; + + case 2: + { + if (event.type == MacroEvent::kSendOp) + { + event.send.value = boost::lexical_cast(*t); + } + else + { + throw std::runtime_error("to many arguments for 'wait'"); + } + } + break; + } + } + + return event; +} + +MacroButtonEventHandler::MacroButtonEventHandler(const std::vector& events) : + m_events(events), + m_send_in_progress(false) +{ +} + +void +MacroButtonEventHandler::init(uInput& uinput) const +{ + for(std::vector::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 */ diff --git a/src/button_event.hpp b/src/button_event.hpp index d918ca0..16030eb 100644 --- a/src/button_event.hpp +++ b/src/button_event.hpp @@ -53,7 +53,8 @@ public: void update(uInput& uinput, int msec_delta); std::string str() const; - void set_filters(const std::vector& filters); + void add_filters(const std::vector& filters); + void add_filter(ButtonFilterPtr filter); private: bool m_last_send_state; @@ -157,6 +158,47 @@ private: std::vector 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& 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 m_events; + bool m_send_in_progress; + int m_countdown; + std::vector::size_type m_event_counter; +}; + #endif /* EOF */ diff --git a/src/button_filter.cpp b/src/button_filter.cpp index 0b65e65..1533f26 100644 --- a/src/button_filter.cpp +++ b/src/button_filter.cpp @@ -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) {