From 42e4d05b7568ed5706c05a8eeaeed9aa12e423c0 Mon Sep 17 00:00:00 2001 From: Sergey Naumov Date: Sun, 4 Sep 2016 17:46:37 +0300 Subject: [PATCH] resolve #8 Implement support of binding_event --- examples/events.cpp | 13 ++++++++- include/i3ipc++/ipc.hpp | 24 +++++++++++++++++ src/ipc.cpp | 58 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/examples/events.cpp b/examples/events.cpp index efcf81c..549dfeb 100644 --- a/examples/events.cpp +++ b/examples/events.cpp @@ -5,7 +5,7 @@ int main() { i3ipc::connection conn; - conn.subscribe(i3ipc::ET_WORKSPACE | i3ipc::ET_WINDOW); + conn.subscribe(i3ipc::ET_WORKSPACE | i3ipc::ET_WINDOW | i3ipc::ET_BINDING); conn.signal_workspace_event.connect([](const i3ipc::workspace_event_t& ev) { std::cout << "workspace_event: " << (char)ev.type << std::endl; @@ -13,6 +13,17 @@ int main() { conn.signal_window_event.connect([](const i3ipc::window_event_t& ev) { std::cout << "window_event: " << (char)ev.type << std::endl; }); + conn.signal_binding_event.connect([](const i3ipc::binding_t& b) { + std::cout << "binding_event:" << std::endl + << "\tcommand = \"" << b.command << '"' << std::endl + << "\tinput_code = " << b.input_code << std::endl + << "\tsymbol = " << b.symbol << std::endl + << "\tinput_type = " << static_cast(b.input_type) << std::endl + << "\tevent_state_mask =" << std::endl; + for (const std::string& s : b.event_state_mask) { + std::cout << "\t\t\"" << s << '"' << std::endl; + } + }); // Don't forget this: conn.prepare_to_event_handling(); diff --git a/include/i3ipc++/ipc.hpp b/include/i3ipc++/ipc.hpp index 3edc8b5..7d656f8 100644 --- a/include/i3ipc++/ipc.hpp +++ b/include/i3ipc++/ipc.hpp @@ -77,6 +77,7 @@ enum EventType { ET_MODE = (1 << 2), ///< Output mode event ET_WINDOW = (1 << 3), ///< Window event ET_BARCONFIG_UPDATE = (1 << 4), ///< Bar config update event @attention Yet is not implemented as signal in connection + ET_BINDING = (1 << 5), ///< Binding event }; /** @@ -130,6 +131,16 @@ enum class ContainerLayout : char { }; +/** + * A type of the input of bindings + */ +enum class InputType : char { + UNKNOWN = '?', //< If got an unknown input_type in binding_event + KEYBOARD = 'k', + MOUSE = 'm', +}; + + /** * A node of tree of windows */ @@ -174,6 +185,18 @@ struct window_event_t { }; +/** + * A binding + */ +struct binding_t { + std::string command; ///< The i3 command that is configured to run for this binding + std::vector event_state_mask; ///< The group and modifier keys that were configured with this binding + int32_t input_code; ///< If the binding was configured with bindcode, this will be the key code that was given for the binding. If the binding is a mouse binding, it will be the number of the mouse button that was pressed. Otherwise it will be 0 + std::string symbol; ///< If this is a keyboard binding that was configured with bindsym, this field will contain the given symbol. Otherwise it will be null + InputType input_type; +}; + + struct buf_t; /** * Connection to the i3 @@ -258,6 +281,7 @@ public: sigc::signal signal_mode_event; ///< Output mode event signal sigc::signal signal_window_event; ///< Window event signal sigc::signal signal_barconfig_update_event; ///< Barconfig update event signal + sigc::signal signal_binding_event; ///< Binding event signal sigc::signal&> signal_event; ///< i3 event signal @note Default handler routes event to signal according to type private: const int32_t m_main_socket; diff --git a/src/ipc.cpp b/src/ipc.cpp index a94a220..59a4723 100644 --- a/src/ipc.cpp +++ b/src/ipc.cpp @@ -155,6 +155,39 @@ static std::shared_ptr parse_output_from_json(const Json::Value& val return p; } +static std::shared_ptr parse_binding_from_json(const Json::Value& value) { +#define i3IPC_TYPE_STR "PARSE BINDING FROM JSON" + if (value.isNull()) + return std::shared_ptr(); + IPC_JSON_ASSERT_TYPE_OBJECT(value, "binding") + std::shared_ptr b (new binding_t()); + + b->command = value["command"].asString(); + b->symbol = value["symbol"].asString(); + b->input_code = value["input_code"].asInt(); + + Json::Value input_type = value["input_type"].asString(); + if (input_type == "keyboard") { + b->input_type = InputType::KEYBOARD; + } else if (input_type == "mouse") { + b->input_type = InputType::MOUSE; + } else { + b->input_type = InputType::UNKNOWN; + } + + Json::Value esm_arr = value["event_state_mask"]; + IPC_JSON_ASSERT_TYPE_ARRAY(esm_arr, "event_state_mask") + + b->event_state_mask.resize(esm_arr.size()); + + for (Json::ArrayIndex i = 0; i < esm_arr.size(); i++) { + b->event_state_mask[i] = esm_arr[i].asString(); + } + + return b; +#undef i3IPC_TYPE_STR +} + std::string get_socketpath() { std::string str; @@ -259,6 +292,28 @@ connection::connection(const std::string& socket_path) : m_main_socket(i3_conne I3IPC_DEBUG("BARCONFIG_UPDATE") signal_barconfig_update_event.emit(); break; + case ET_BINDING: { + Json::Value root; + IPC_JSON_READ(root); + std::string change = root["change"].asString(); + if (change != "run") { + I3IPC_WARN("Got \"" << change << "\" in field \"change\" of binding_event. Expected \"run\"") + } + + Json::Value binding_json = root["binding"]; + std::shared_ptr bptr; + if (!binding_json.isNull()) { + bptr = parse_binding_from_json(binding_json); + } + + if (!bptr) { + I3IPC_ERR("Failed to parse field \"binding\" from binding_event") + } else { + I3IPC_DEBUG("BINDING " << bptr->symbol); + signal_binding_event.emit(*bptr); + } + break; + } }; }); #undef i3IPC_TYPE_STR @@ -308,6 +363,9 @@ bool connection::subscribe(const int32_t events) { if (events & static_cast(ET_BARCONFIG_UPDATE)) { payload_auss << "\"barconfig_update\","; } + if (events & static_cast(ET_BINDING)) { + payload_auss << "\"binding\","; + } payload = payload_auss; if (payload.empty()) { return true;