diff --git a/include/components/controller.hpp b/include/components/controller.hpp index 6b07f527..2067a4ec 100644 --- a/include/components/controller.hpp +++ b/include/components/controller.hpp @@ -117,9 +117,12 @@ class controller modulemap_t m_blocks; /** - * \brief Module input handlers + * \brief Input handlers modules + * + * Maps the name of the input handler (module name) to the corresponding input + * handler */ - vector m_inputhandlers; + std::map> m_inputhandlers; /** * \brief Maximum number of subsequent events to swallow diff --git a/include/modules/meta/base.hpp b/include/modules/meta/base.hpp index aed26f6f..558f5b90 100644 --- a/include/modules/meta/base.hpp +++ b/include/modules/meta/base.hpp @@ -101,6 +101,10 @@ namespace modules { public: virtual ~module_interface() {} + /** + * Module name w/o 'module/' prefix + */ + virtual string name_raw() const = 0; virtual string name() const = 0; virtual bool running() const = 0; @@ -119,6 +123,7 @@ namespace modules { module(const bar_settings bar, string name); ~module() noexcept; + string name_raw() const; string name() const; bool running() const; void stop(); @@ -148,6 +153,7 @@ namespace modules { std::condition_variable m_sleephandler; string m_name; + string m_name_raw; unique_ptr m_builder; unique_ptr m_formatter; vector m_threads; diff --git a/include/modules/meta/base.inl b/include/modules/meta/base.inl index 73255347..f201c9cf 100644 --- a/include/modules/meta/base.inl +++ b/include/modules/meta/base.inl @@ -17,6 +17,7 @@ namespace modules { , m_log(logger::make()) , m_conf(config::make()) , m_name("module/" + name) + , m_name_raw(name) , m_builder(make_unique(bar)) , m_formatter(make_unique(m_conf, m_name)) , m_handle_events(m_conf.get(m_name, "handle-events", true)) {} @@ -40,6 +41,11 @@ namespace modules { return m_name; } + template + string module::name_raw() const { + return m_name_raw; + } + template bool module::running() const { return static_cast(m_enabled); diff --git a/include/modules/meta/input_handler.hpp b/include/modules/meta/input_handler.hpp index 3ce847f3..b3362cc3 100644 --- a/include/modules/meta/input_handler.hpp +++ b/include/modules/meta/input_handler.hpp @@ -8,6 +8,11 @@ namespace modules { class input_handler { public: virtual ~input_handler() {} + /** + * Handle command + * + * \returns true if the command is supported and false otherwise + */ virtual bool input(string&& cmd) = 0; }; } diff --git a/src/components/controller.cpp b/src/components/controller.cpp index 8560d00c..2929a4f3 100644 --- a/src/components/controller.cpp +++ b/src/components/controller.cpp @@ -143,11 +143,12 @@ bool controller::run(bool writeback, string snapshot_dst) { size_t started_modules{0}; for (const auto& module : m_modules) { - auto inp_handler = dynamic_cast(&*module); + auto inp_handler = std::dynamic_pointer_cast(module); auto evt_handler = dynamic_cast(&*module); - if (inp_handler != nullptr) { - m_inputhandlers.emplace_back(inp_handler); + if (inp_handler) { + m_log.trace("Registering module %s as input handler", module->name_raw()); + m_inputhandlers.emplace(module->name_raw(), inp_handler); } if (evt_handler != nullptr) { @@ -390,32 +391,62 @@ void controller::process_eventqueue() { * Process stored input data */ void controller::process_inputdata() { - if (!m_inputdata.empty()) { - string cmd = m_inputdata; - m_inputdata.clear(); + if (m_inputdata.empty()) { + return; + } - for (auto&& handler : m_inputhandlers) { - if (handler->input(string{cmd})) { - return; - } + const string cmd = m_inputdata; + m_inputdata.clear(); + + /* + * Module inputs have the following form (w/o the quotes): "#NAME#INPUT" + * where 'NAME' is the name of the module (for which '#' is a forbidden + * character) and 'INPUT' is the input that is sent to the module + */ + if (cmd.front() == '#') { + // Find the second delimiter '#' + auto end_pos = cmd.find('#', 1); + + if (end_pos == string::npos) { + m_log.err("Invalid action string (input: %s)", cmd); + return; } - try { - m_log.info("Uncaught input event, forwarding to shell... (input: %s)", cmd); + auto handler_name = cmd.substr(1, end_pos - 1); + auto action = cmd.substr(end_pos + 1); - if (m_command) { - m_log.warn("Terminating previous shell command"); - m_command->terminate(); - } + m_log.info("Forwarding data to input handler (name: %s, action: %s) ", handler_name, action); - m_log.info("Executing shell command: %s", cmd); - m_command = command_util::make_command(move(cmd)); - m_command->exec(); - m_command.reset(); - process_update(true); - } catch (const application_error& err) { - m_log.err("controller: Error while forwarding input to shell -> %s", err.what()); + auto handler = m_inputhandlers.find(handler_name); + + if (handler == m_inputhandlers.end()) { + m_log.err("The input handler with name '%s' doesn't exist (input: %s)", handler_name, cmd); + return; } + + if(!handler->second->input(string{action})) { + m_log.warn("The '%s' module does not support the '%s' action.", handler_name, action); + } + + return; + } + + try { + // Run input as command if it's not an input for a module + m_log.info("Forwarding command to shell... (input: %s)", cmd); + + if (m_command) { + m_log.warn("Terminating previous shell command"); + m_command->terminate(); + } + + m_log.info("Executing shell command: %s", cmd); + m_command = command_util::make_command(move(cmd)); + m_command->exec(); + m_command.reset(); + process_update(true); + } catch (const application_error& err) { + m_log.err("controller: Error while forwarding input to shell -> %s", err.what()); } }