diff --git a/.gitignore b/.gitignore index 18998d5..6726e71 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ wayland-protos/*.c wayland-protos/*.h wayland-protos/*.xml *~ -convertablet \ No newline at end of file +convertablet + +fcitx5-hooks/libhooks.so \ No newline at end of file diff --git a/fcitx5-hooks/README.md b/fcitx5-hooks/README.md new file mode 100644 index 0000000..9c698e4 --- /dev/null +++ b/fcitx5-hooks/README.md @@ -0,0 +1,26 @@ +# fcitx5-hooks + +This is a fcitx5 module that allows the user to run scripts on various fcitx events! + +## Build + +```bash +./build.sh +``` + +## Install + +```bash +./install.sh +``` + +Now, restart fcitx, and you should get the hooks module! + +## Hooks available + +All hooks are stored in `~/.config/fcitx5-hooks/` + +| Name | File | +|----------------------|------------------------------| +| InputContextFocusIn | input-context-focus-in-hook | +| InputContextFocusOut | input-context-focus-out-hook | diff --git a/fcitx5-hooks/build.sh b/fcitx5-hooks/build.sh new file mode 100755 index 0000000..9bed764 --- /dev/null +++ b/fcitx5-hooks/build.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +set -ex + +clang++ -fPIC -std=c++20 -Wall -Wextra -pedantic -shared -o libhooks.so hooks.cpp -I/usr/include/Fcitx5/Core/ -I/usr/include/Fcitx5/Config -I/usr/include/Fcitx5/Utils -lFcitx5Core -lFcitx5Config -lFcitx5Utils diff --git a/fcitx5-hooks/hooks.conf b/fcitx5-hooks/hooks.conf new file mode 100644 index 0000000..219fb2c --- /dev/null +++ b/fcitx5-hooks/hooks.conf @@ -0,0 +1,7 @@ +[Addon] +Name=Hooks +Category=Module +Library=libhooks +Type=SharedLibrary +OnDemand=False +Configurable=False \ No newline at end of file diff --git a/fcitx5-hooks/hooks.cpp b/fcitx5-hooks/hooks.cpp new file mode 100644 index 0000000..5f8ed3e --- /dev/null +++ b/fcitx5-hooks/hooks.cpp @@ -0,0 +1,76 @@ +#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); diff --git a/fcitx5-hooks/install.sh b/fcitx5-hooks/install.sh new file mode 100755 index 0000000..d497e7a --- /dev/null +++ b/fcitx5-hooks/install.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +[ ! "$UID" = 0 ] && echo "You must run this script as root" && exit 1 + +echo "Installing..." + +set -ex + +cp libhooks.so /usr/lib64/fcitx5/ +cp hooks.conf /usr/share/fcitx5/addon/