diff --git a/src/KeybindManager.cpp b/src/KeybindManager.cpp index 39e90c1..6e5306d 100644 --- a/src/KeybindManager.cpp +++ b/src/KeybindManager.cpp @@ -1,5 +1,7 @@ #include "KeybindManager.hpp" +#include + Keybind* KeybindManager::findKeybindByKey(int mod, xcb_keysym_t keysym) { for(auto& key : KeybindManager::keybinds) { if (keysym == key.getKeysym() && mod == key.getMod()) { @@ -7,4 +9,84 @@ Keybind* KeybindManager::findKeybindByKey(int mod, xcb_keysym_t keysym) { } } return nullptr; +} + +void KeybindManager::reloadAllKeybinds() { + KeybindManager::keybinds.clear(); + + // todo: config + KeybindManager::keybinds.push_back(Keybind(MOD_SUPER, 0x72 /* R */, "krunner", &KeybindManager::call)); + KeybindManager::keybinds.push_back(Keybind(MOD_SUPER, 0x62 /* G */, "google-chrome-stable", &KeybindManager::call)); +} + +unsigned int KeybindManager::modToMask(MODS mod) { + switch(mod) { + case MOD_NONE: + return 0; + case MOD_SUPER: + return XCB_MOD_MASK_4; + case MOD_SHIFT: + return XCB_MOD_MASK_SHIFT; + } + + return 0; +} + +xcb_keysym_t KeybindManager::getKeysymFromKeycode(xcb_keycode_t keycode) { + const auto KEYSYMS = xcb_key_symbols_alloc(WindowManager::DisplayConnection); + const auto KEYSYM = (!(KEYSYMS) ? 0 : xcb_key_symbols_get_keysym(KEYSYMS, keycode, 0)); + xcb_key_symbols_free(KEYSYMS); + return KEYSYM; +} + +xcb_keycode_t KeybindManager::getKeycodeFromKeysym(xcb_keysym_t keysym) { + const auto KEYSYMS = xcb_key_symbols_alloc(WindowManager::DisplayConnection); + const auto KEYCODE = (!(KEYSYMS) ? NULL : xcb_key_symbols_get_keycode(KEYSYMS, keysym)); + xcb_key_symbols_free(KEYSYMS); + return KEYCODE ? *KEYCODE : 0; +} + +// Dispatchers + +void KeybindManager::call(std::string args) { + if (fork() == 0) { + setsid(); + if (fork() != 0) { + _exit(0); + } + + // fix the args + std::string command = args.substr(0, args.find_first_of(" ")); + + int ARGNO = std::count(args.begin(), args.end(), ' '); + if(ARGNO > 0) + ARGNO -= 1; + + if(ARGNO) { + char* argsarr[ARGNO]; + + for (int i = 0; i < ARGNO; ++i) { + args = args.substr(args.find_first_of(' ') + 1); + argsarr[i] = (char*)args.substr(0, args.find_first_of(' ')).c_str(); + } + + Debug::log(LOG, "Executing " + command + " with " + std::to_string(ARGNO) + " args:"); + for (int i = 0; i < ARGNO; ++i) { + Debug::log(NONE, argsarr[i]); + } + + execvp((char*)command.c_str(), (char**)argsarr); + } else { + char* argsarr[1]; + argsarr[0] = ""; + + Debug::log(LOG, "Executing " + command + " with 0 args."); + + execvp((char*)command.c_str(), (char**)argsarr); + } + + + _exit(0); + } + wait(NULL); } \ No newline at end of file diff --git a/src/KeybindManager.hpp b/src/KeybindManager.hpp index 1ee73eb..a4535dd 100644 --- a/src/KeybindManager.hpp +++ b/src/KeybindManager.hpp @@ -1,11 +1,19 @@ +#pragma once + #include "utilities/Keybind.hpp" #include +#include "windowManager.hpp" namespace KeybindManager { - std::vector keybinds; + inline std::vector keybinds; - - // -- Methods -- // + unsigned int modToMask(MODS); Keybind* findKeybindByKey(int mod, xcb_keysym_t keysym); + void reloadAllKeybinds(); + xcb_keysym_t getKeysymFromKeycode(xcb_keycode_t keycode); + xcb_keycode_t getKeycodeFromKeysym(xcb_keysym_t keysym); + + // Dispatchers + void call(std::string args); }; \ No newline at end of file diff --git a/src/events/events.cpp b/src/events/events.cpp index 27f4189..b645101 100644 --- a/src/events/events.cpp +++ b/src/events/events.cpp @@ -59,4 +59,16 @@ void Events::eventMapWindow(xcb_generic_event_t* event) { xcb_change_window_attributes_checked(WindowManager::DisplayConnection, E->window, XCB_CW_EVENT_MASK, WindowManager::Values); WindowManager::setFocusedWindow(E->window); +} + +void Events::eventKeyPress(xcb_generic_event_t* event) { + const auto E = reinterpret_cast(event); + + const auto KEYSYM = KeybindManager::getKeysymFromKeycode(E->detail); + + for (auto& keybind : KeybindManager::keybinds) { + if (keybind.getKeysym() != 0 && keybind.getKeysym() == KEYSYM && KeybindManager::modToMask(keybind.getMod()) == E->state) { + keybind.getDispatcher()(keybind.getCommand()); + } + } } \ No newline at end of file diff --git a/src/events/events.hpp b/src/events/events.hpp index 80ca4b0..d8d1aed 100644 --- a/src/events/events.hpp +++ b/src/events/events.hpp @@ -6,4 +6,5 @@ namespace Events { EVENT(Leave); EVENT(Destroy); EVENT(MapWindow); + EVENT(KeyPress); }; \ No newline at end of file diff --git a/src/utilities/Keybind.cpp b/src/utilities/Keybind.cpp new file mode 100644 index 0000000..a49cbfc --- /dev/null +++ b/src/utilities/Keybind.cpp @@ -0,0 +1,10 @@ +#include "Keybind.hpp" + +Keybind::Keybind(MODS mod, xcb_keysym_t keysym, std::string comm, Dispatcher disp) { + this->m_iMod = mod; + this->m_Keysym = keysym; + this->m_szCommand = comm; + this->m_pDispatcher = disp; +} + +Keybind::~Keybind() { } \ No newline at end of file diff --git a/src/utilities/Keybind.hpp b/src/utilities/Keybind.hpp index d3bcd7b..e8a811c 100644 --- a/src/utilities/Keybind.hpp +++ b/src/utilities/Keybind.hpp @@ -1,9 +1,22 @@ +#pragma once #include "../defines.hpp" -class Keybind { - EXPOSED_MEMBER(Mod, int, i); - EXPOSED_MEMBER(Keysym, xcb_keysym_t,); - EXPOSED_MEMBER(Command, std::string, sz); - EXPOSED_MEMBER(Dispatcher, void*, p); +typedef void (*Dispatcher)(std::string); + +enum MODS { + MOD_NONE = 0, + MOD_SUPER, + MOD_SHIFT +}; + +class Keybind { +public: + Keybind(MODS, xcb_keysym_t, std::string, Dispatcher); + ~Keybind(); + + EXPOSED_MEMBER(Mod, MODS, i); + EXPOSED_MEMBER(Keysym, xcb_keysym_t,); + EXPOSED_MEMBER(Command, std::string, sz); + EXPOSED_MEMBER(Dispatcher, Dispatcher, p); }; diff --git a/src/windowManager.cpp b/src/windowManager.cpp index 5112ea6..b5bab65 100644 --- a/src/windowManager.cpp +++ b/src/windowManager.cpp @@ -2,23 +2,31 @@ #include "./events/events.hpp" void WindowManager::setupManager() { + KeybindManager::reloadAllKeybinds(); + WindowManager::Values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; xcb_change_window_attributes_checked(WindowManager::DisplayConnection, WindowManager::Screen->root, XCB_CW_EVENT_MASK, WindowManager::Values); xcb_ungrab_key(WindowManager::DisplayConnection, XCB_GRAB_ANY, WindowManager::Screen->root, XCB_MOD_MASK_ANY); - /*int key_table_size = sizeof(keys) / sizeof(*keys); - for (int i = 0; i < key_table_size; ++i) { - xcb_keycode_t *keycode = xcb_get_keycodes(keys[i].keysym); - if (keycode != NULL) { - xcb_grab_key(WindowManager::DisplayConnection, 1, WindowManager::Screen->root, keys[i].mod, *keycode, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); - } + + for (auto& keybind : KeybindManager::keybinds) { + xcb_grab_key(WindowManager::DisplayConnection, 1, WindowManager::Screen->root, + KeybindManager::modToMask(keybind.getMod()), KeybindManager::getKeycodeFromKeysym(keybind.getKeysym()), + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); } + xcb_flush(WindowManager::DisplayConnection); - xcb_grab_button(WindowManager::DisplayConnection, 0, WindowManager::Screen->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, WindowManager::Screen->root, XCB_NONE, 1, MOD1); - xcb_grab_button(WindowManager::DisplayConnection, 0, WindowManager::Screen->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, WindowManager::Screen->root, XCB_NONE, 3, MOD1);*/ + + xcb_grab_button(WindowManager::DisplayConnection, 0, + WindowManager::Screen->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, WindowManager::Screen->root, XCB_NONE, + 1, KeybindManager::modToMask(MOD_SUPER)); + + xcb_grab_button(WindowManager::DisplayConnection, 0, + WindowManager::Screen->root, XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, + XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, WindowManager::Screen->root, XCB_NONE, + 3, KeybindManager::modToMask(MOD_SUPER)); + xcb_flush(WindowManager::DisplayConnection); } @@ -26,7 +34,7 @@ bool WindowManager::handleEvent() { if (xcb_connection_has_error(WindowManager::DisplayConnection)) return false; - xcb_generic_event_t* ev = xcb_wait_for_event(WindowManager::DisplayConnection); + const auto ev = xcb_wait_for_event(WindowManager::DisplayConnection); if (ev != NULL) { switch (ev->response_type & ~0x80) { case XCB_ENTER_NOTIFY: @@ -45,6 +53,11 @@ bool WindowManager::handleEvent() { Events::eventMapWindow(ev); Debug::log(LOG, "Event dispatched MAP"); break; + case XCB_KEY_PRESS: + case XCB_BUTTON_PRESS: + Events::eventKeyPress(ev); + Debug::log(LOG, "Event dispatched KEYPRESS"); + break; default: Debug::log(WARN, "Unknown event: " + std::to_string(ev->response_type & ~0x80)); diff --git a/src/windowManager.hpp b/src/windowManager.hpp index 547fabe..9afede3 100644 --- a/src/windowManager.hpp +++ b/src/windowManager.hpp @@ -5,6 +5,8 @@ #include +#include "KeybindManager.hpp" + // temp config values #define BORDERSIZE 1