#include #include #include #include #include #include #include #include namespace fs = std::filesystem; static fs::path const hooksConfigDir = fs::path(getenv("XDG_CONFIG_DIR") ? getenv("XDG_CONFIG_DIR") : (fs::path(getenv("HOME")) / ".config")) / "fcitx5-hooks"; void runCommand(std::string_view hookName) { auto full_path = hooksConfigDir / hookName; pid_t pid = fork(); if (pid < 0) { FCITX_ERROR() << "Couldn't fork to run command"; return; } else if (pid == 0) { char* argv[] = {strdup(full_path.c_str()), 0}; execve(full_path.c_str(), argv, environ); exit(-1); } return; } static void eventHandler(fcitx::Event& event) { using ET = fcitx::EventType; switch (event.type()) { case ET::InputContextFocusIn: runCommand("input-context-focus-in-hook"); case ET::InputContextFocusOut: runCommand("input-context-focus-out-hook"); default: } } class Hooks : public fcitx::AddonInstance { public: Hooks(fcitx::Instance* instance) { #define WATCH_EVENT(event_name) \ instance->watchEvent(fcitx::EventType::event_name, \ fcitx::EventWatcherPhase::InputMethod, \ eventHandler) focusEvent_ = WATCH_EVENT(InputContextFocusIn); unfocusEvent_ = WATCH_EVENT(InputContextFocusOut); } private: std::unique_ptr> focusEvent_; std::unique_ptr> unfocusEvent_; }; class HooksFactory : public fcitx::AddonFactory { fcitx::AddonInstance* create(fcitx::AddonManager* manager) override { FCITX_UNUSED(manager); return new Hooks(manager->instance()); } }; FCITX_ADDON_FACTORY(HooksFactory);