diff --git a/src/config/config.cpp b/src/config/config.cpp index 0bbd0cc..0c4b633 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -16,100 +16,126 @@ along with this program. If not, see . */ - -#include #include "config.h" #include "../util.h" +#include /** * Check if config file exists at current path */ -bool gebaar::config::Config::config_file_exists() -{ - auto true_path = std::filesystem::path(config_file_path); - return std::filesystem::exists(true_path); +bool gebaar::config::Config::config_file_exists() { + auto true_path = std::filesystem::path(config_file_path); + return std::filesystem::exists(true_path); } /** * Load Configuration from TOML file */ -void gebaar::config::Config::load_config() -{ - if (find_config_file()) { - if (config_file_exists()) { - try { - config = cpptoml::parse_file(std::filesystem::path(config_file_path)); - } catch (const cpptoml::parse_exception& e) { - std::cerr << e.what() << std::endl; - exit(EXIT_FAILURE); - } - - /* Swipe Settings */ - swipe_three_commands[1] = *config->get_qualified_as("swipe.commands.three.left_up"); - swipe_three_commands[2] = *config->get_qualified_as("swipe.commands.three.up"); - swipe_three_commands[3] = *config->get_qualified_as("swipe.commands.three.right_up"); - swipe_three_commands[4] = *config->get_qualified_as("swipe.commands.three.left"); - swipe_three_commands[6] = *config->get_qualified_as("swipe.commands.three.right"); - swipe_three_commands[7] = *config->get_qualified_as("swipe.commands.three.left_down"); - swipe_three_commands[8] = *config->get_qualified_as("swipe.commands.three.down"); - swipe_three_commands[9] = *config->get_qualified_as("swipe.commands.three.right_down"); - - swipe_four_commands[1] = *config->get_qualified_as("swipe.commands.four.left_up"); - swipe_four_commands[2] = *config->get_qualified_as("swipe.commands.four.up"); - swipe_four_commands[3] = *config->get_qualified_as("swipe.commands.four.right_up"); - swipe_four_commands[4] = *config->get_qualified_as("swipe.commands.four.left"); - swipe_four_commands[6] = *config->get_qualified_as("swipe.commands.four.right"); - swipe_four_commands[7] = *config->get_qualified_as("swipe.commands.four.left_down"); - swipe_four_commands[8] = *config->get_qualified_as("swipe.commands.four.down"); - swipe_four_commands[9] = *config->get_qualified_as("swipe.commands.four.right_down"); - - settings.swipe_threshold = config->get_qualified_as("swipe.settings.threshold").value_or(0.5); - settings.swipe_one_shot = config->get_qualified_as("swipe.settings.one_shot").value_or(true); - settings.swipe_trigger_on_release = config->get_qualified_as("swipe.settings.trigger_on_release").value_or(true); - - /* Pinch settings */ - pinch_commands[PINCH_IN] = *config->get_qualified_as("pinch.commands.two.out"); - pinch_commands[PINCH_OUT] = *config->get_qualified_as("pinch.commands.two.in"); - - settings.pinch_threshold = config->get_qualified_as("pinch.settings.threshold").value_or(0.25); - settings.pinch_one_shot = config->get_qualified_as("pinch.settings.one_shot").value_or(false); - - - loaded = true; - } +void gebaar::config::Config::load_config() { + if (find_config_file()) { + if (config_file_exists()) { + try { + config = cpptoml::parse_file(std::filesystem::path(config_file_path)); + } catch (const cpptoml::parse_exception &e) { + std::cerr << e.what() << std::endl; + exit(EXIT_FAILURE); + } + + /* Swipe Settings */ + swipe_three_commands[1] = *config->get_qualified_as( + "swipe.commands.three.left_up"); + swipe_three_commands[2] = + *config->get_qualified_as("swipe.commands.three.up"); + swipe_three_commands[3] = *config->get_qualified_as( + "swipe.commands.three.right_up"); + swipe_three_commands[4] = + *config->get_qualified_as("swipe.commands.three.left"); + swipe_three_commands[6] = + *config->get_qualified_as("swipe.commands.three.right"); + swipe_three_commands[7] = *config->get_qualified_as( + "swipe.commands.three.left_down"); + swipe_three_commands[8] = + *config->get_qualified_as("swipe.commands.three.down"); + swipe_three_commands[9] = *config->get_qualified_as( + "swipe.commands.three.right_down"); + + swipe_four_commands[1] = + *config->get_qualified_as("swipe.commands.four.left_up"); + swipe_four_commands[2] = + *config->get_qualified_as("swipe.commands.four.up"); + swipe_four_commands[3] = *config->get_qualified_as( + "swipe.commands.four.right_up"); + swipe_four_commands[4] = + *config->get_qualified_as("swipe.commands.four.left"); + swipe_four_commands[6] = + *config->get_qualified_as("swipe.commands.four.right"); + swipe_four_commands[7] = *config->get_qualified_as( + "swipe.commands.four.left_down"); + swipe_four_commands[8] = + *config->get_qualified_as("swipe.commands.four.down"); + swipe_four_commands[9] = *config->get_qualified_as( + "swipe.commands.four.right_down"); + + settings.swipe_threshold = + config->get_qualified_as("swipe.settings.threshold") + .value_or(0.5); + settings.swipe_one_shot = + config->get_qualified_as("swipe.settings.one_shot") + .value_or(true); + settings.swipe_trigger_on_release = + config->get_qualified_as("swipe.settings.trigger_on_release") + .value_or(true); + + /* Pinch settings */ + pinch_commands[PINCH_IN] = + *config->get_qualified_as("pinch.commands.two.out"); + pinch_commands[PINCH_OUT] = + *config->get_qualified_as("pinch.commands.two.in"); + pinch_commands[ROTATE_RIGHT] = + *config->get_qualified_as("pinch.commands.rotate.right"); + pinch_commands[ROTATE_LEFT] = + *config->get_qualified_as("pinch.commands.rotate.left"); + + settings.pinch_threshold = + config->get_qualified_as("pinch.settings.threshold") + .value_or(0.25); + settings.pinch_one_shot = + config->get_qualified_as("pinch.settings.one_shot") + .value_or(false); + + loaded = true; } - + } } /** * Find the configuration file according to XDG spec * @return bool */ -bool gebaar::config::Config::find_config_file() -{ - std::string temp_path = gebaar::util::stringFromCharArray(getenv("XDG_CONFIG_HOME")); +bool gebaar::config::Config::find_config_file() { + std::string temp_path = + gebaar::util::stringFromCharArray(getenv("XDG_CONFIG_HOME")); + if (temp_path.empty()) { + // first get the path to HOME + temp_path = gebaar::util::stringFromCharArray(getenv("HOME")); if (temp_path.empty()) { - // first get the path to HOME - temp_path = gebaar::util::stringFromCharArray(getenv("HOME")); - if (temp_path.empty()) { - temp_path = getpwuid(getuid())->pw_dir; - } - // then append .config - if (!temp_path.empty()) { - temp_path.append("/.config"); - } + temp_path = getpwuid(getuid())->pw_dir; } + // then append .config if (!temp_path.empty()) { - config_file_path = temp_path; - config_file_path.append("/gebaar/gebaard.toml"); - return true; + temp_path.append("/.config"); } - return false; + } + if (!temp_path.empty()) { + config_file_path = temp_path; + config_file_path.append("/gebaar/gebaard.toml"); + return true; + } + return false; } -gebaar::config::Config::Config() -{ - if (!loaded) { - load_config(); - } +gebaar::config::Config::Config() { + if (!loaded) { + load_config(); + } } diff --git a/src/config/config.h b/src/config/config.h index 34d7a42..6b6166a 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -21,44 +21,40 @@ #include #include -#include #include +#include namespace gebaar::config { - class Config { - public: - Config(); - - bool loaded = false; - - void load_config(); - - - struct settings { - bool pinch_one_shot; - double pinch_threshold; +class Config { +public: + Config(); - bool swipe_one_shot; - double swipe_threshold; - bool swipe_trigger_on_release; - } settings; + bool loaded = false; - enum pinch {PINCH_IN, PINCH_OUT}; - std::string swipe_three_commands[10]; - std::string swipe_four_commands[10]; - std::string pinch_commands[10]; + void load_config(); - private: + struct settings { + bool pinch_one_shot; + double pinch_threshold; - bool config_file_exists(); + bool swipe_one_shot; + double swipe_threshold; + bool swipe_trigger_on_release; + } settings; - bool find_config_file(); + enum pinch { PINCH_IN, PINCH_OUT, ROTATE_RIGHT, ROTATE_LEFT }; + std::string swipe_three_commands[10]; + std::string swipe_four_commands[10]; + std::string pinch_commands[10]; +private: + bool config_file_exists(); - std::string config_file_path; - std::shared_ptr config; + bool find_config_file(); + std::string config_file_path; + std::shared_ptr config; +}; +} // namespace gebaar::config - }; -} -#endif //GEBAAR_CONFIG_H +#endif // GEBAAR_CONFIG_H diff --git a/src/daemonizer.cpp b/src/daemonizer.cpp index 3c0e383..639c818 100644 --- a/src/daemonizer.cpp +++ b/src/daemonizer.cpp @@ -1,22 +1,21 @@ /* gebaar Copyright (C) 2019 coffee2code - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ - #include "daemonizer.h" /** @@ -24,40 +23,45 @@ * * @return bool that denotes fork success */ -bool gebaar::daemonizer::Daemonizer::daemonize() -{ - pid_t pid = 0; - pid = fork(); - if (pid<0) { - exit(EXIT_FAILURE); - } - if (pid>0) { - exit(EXIT_SUCCESS); - } - if (setsid()<0) { - // Boo. - } - signal(SIGCHLD, SIG_IGN); - signal(SIGTRAP, SIG_IGN); - pid = fork(); - if (pid<0) { - exit(EXIT_FAILURE); - } - if (pid>0) { - exit(EXIT_SUCCESS); - } - umask(0); - if ((chdir("/"))<0) { - return false; - } - close(STDOUT_FILENO); - close(STDIN_FILENO); - close(STDERR_FILENO); - if (getpid()!=getsid(getpid())) { - // - } - return true; +bool gebaar::daemonizer::Daemonizer::daemonize() { + pid_t pid = 0; + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + if (setsid() < 0) { + // Boo. + } + + signal(SIGCHLD, SIG_IGN); + signal(SIGTRAP, SIG_IGN); + + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + + if (pid > 0) { + exit(EXIT_SUCCESS); + } + umask(0); + if ((chdir("/")) < 0) { + return false; + } + + close(STDOUT_FILENO); + close(STDIN_FILENO); + close(STDERR_FILENO); + if (getpid() != getsid(getpid())) { + // + } + return true; } gebaar::daemonizer::Daemonizer::Daemonizer() = default; diff --git a/src/daemonizer.h b/src/daemonizer.h index ca60a15..debce01 100644 --- a/src/daemonizer.h +++ b/src/daemonizer.h @@ -1,33 +1,36 @@ /* gebaar Copyright (C) 2019 coffee2code - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ + +#ifndef GEBAAR_DAEMONIZER_H +#define GEBAAR_DAEMONIZER_H + #include -#include #include #include +#include -#ifndef GEBAAR_DAEMONIZER_H -#define GEBAAR_DAEMONIZER_H namespace gebaar::daemonizer { - class Daemonizer { - public: - Daemonizer(); - ~Daemonizer(); - bool daemonize(); - }; -} -#endif //GEBAAR_DAEMONIZER_H +class Daemonizer { +public: + Daemonizer(); + ~Daemonizer(); + bool daemonize(); +}; +} // namespace gebaar::daemonizer + +#endif // GEBAAR_DAEMONIZER_H diff --git a/src/io/input.cpp b/src/io/input.cpp index 415fdab..45a4b8a 100644 --- a/src/io/input.cpp +++ b/src/io/input.cpp @@ -60,6 +60,10 @@ void gebaar::io::Input::reset_pinch_event() { gesture_pinch_event = {}; gesture_pinch_event.scale = DEFAULT_SCALE; gesture_pinch_event.executed = false; + gesture_pinch_event.angle = 0; + gesture_pinch_event.step = 1; + gesture_pinch_event.rotation_step = 1; + rotating = false; } /** @@ -82,6 +86,39 @@ void gebaar::io::Input::handle_one_shot_pinch(double new_scale) { } } +/** + * Check for rotation. If rotation detected execute command and return true + * return false otherwise + * @param new_angle new absolute angle + */ +void gebaar::io::Input::handle_rotation(double new_angle) { + if (new_angle > gesture_pinch_event.angle) { // Rotate right + std::system(config->pinch_commands[config->ROTATE_RIGHT].c_str()); + inc_step(gesture_pinch_event.rotation_step); + } else { // Rotate left + std::system(config->pinch_commands[config->ROTATE_LEFT].c_str()); + dec_step(gesture_pinch_event.rotation_step); + } +} + +/** + * Check for rotation trigger + * @param angle current angle + * @param threshold threshold from config to trigger action + */ +bool gebaar::io::Input::do_rotation_trigger(double angle, double threshold) { + // Threshold for rotation... that's tricky. + // Basically there could be 360 degrees angle but that'd be too long + // Hence let's do the trigger based on 90 degrees. That might be problematic + // In a long run but let's see how it works, maybe reduce to 44? + double nor = abs(angle) / 45.0; + double trigger = abs(threshold * gesture_pinch_event.rotation_step); + if (nor > trigger) { + return true; + } + return false; +} + /** * Pinch continous gesture handle * Calculates the trigger value according to current step @@ -118,18 +155,33 @@ void gebaar::io::Input::handle_pinch_event(libinput_event_gesture *gev, gesture_pinch_event.fingers = libinput_event_gesture_get_finger_count(gev); } else { double new_scale = libinput_event_gesture_get_scale(gev); - if (config->settings.pinch_one_shot && !gesture_pinch_event.executed) - handle_one_shot_pinch(new_scale); - if (!config->settings.pinch_one_shot) - handle_continouos_pinch(new_scale); + double delta = libinput_event_gesture_get_angle_delta(gev); + double new_angle = gesture_pinch_event.angle + delta; + /* + * Since rotation and pinch gestures don't play very well together + * we should return if rotation is handled to prevent pinch jittering + */ + // printf("Delta: %.2f, pinch_threshold: %.2f\n", delta, + // config->settings.pinch_threshold); + if (do_rotation_trigger(new_angle, config->settings.pinch_threshold)) { + handle_rotation(new_angle); + rotating = true; + } else if (!rotating) { + if (config->settings.pinch_one_shot && !gesture_pinch_event.executed) + handle_one_shot_pinch(new_scale); + if (!config->settings.pinch_one_shot) + handle_continouos_pinch(new_scale); + } + gesture_pinch_event.scale = new_scale; + gesture_pinch_event.angle = new_angle; } } /** - * This event has no coordinates, so it's an event that gives us a begin or end - * signal. If it begins, we get the amount of fingers used. If it ends, we check - * what kind of gesture we received. + * This event has no coordinates, so it's an event that gives us a begin or + * end signal. If it begins, we get the amount of fingers used. If it ends, we + * check what kind of gesture we received. * * @param gev Gesture Event * @param begin Boolean to denote begin or end of gesture diff --git a/src/io/input.h b/src/io/input.h index 2f62a29..4c6c85c 100644 --- a/src/io/input.h +++ b/src/io/input.h @@ -19,107 +19,113 @@ #ifndef GEBAAR_INPUT_HPP #define GEBAAR_INPUT_HPP -#include +#include "../config/config.h" #include +#include #include -#include "../config/config.h" -#define DEFAULT_SCALE 1.0 -#define SWIPE_X_THRESHOLD 1000 -#define SWIPE_Y_THRESHOLD 500 +#define DEFAULT_SCALE 1.0 +#define SWIPE_X_THRESHOLD 1000 +#define SWIPE_Y_THRESHOLD 500 namespace gebaar::io { - struct gesture_swipe_event { - int fingers; - double x; - double y; - bool executed; - int step; - }; +struct gesture_swipe_event { + int fingers; + double x; + double y; + + bool executed; + int step; +}; + +struct gesture_pinch_event { + int fingers; + double scale; + double angle; + + bool executed; + bool rotating; + int step; + int rotation_step; +}; + +class Input { +public: + Input(std::shared_ptr const &config_ptr); - struct gesture_pinch_event { - int fingers; - double scale; - double angle; + ~Input(); - bool executed; - int step; - }; + bool initialize(); - class Input { - public: - Input(std::shared_ptr const& config_ptr); + void start_loop(); - ~Input(); +private: + std::shared_ptr config; - bool initialize(); + struct libinput *libinput; + struct libinput_event *libinput_event; + struct udev *udev; - void start_loop(); + struct gesture_swipe_event gesture_swipe_event; + struct gesture_pinch_event gesture_pinch_event; - private: - std::shared_ptr config; + bool rotating; - struct libinput* libinput; - struct libinput_event* libinput_event; - struct udev* udev; + bool initialize_context(); - struct gesture_swipe_event gesture_swipe_event; - struct gesture_pinch_event gesture_pinch_event; + bool gesture_device_exists(); - bool initialize_context(); + static int open_restricted(const char *path, int flags, void *user_data) { + int fd = open(path, flags); + return fd < 0 ? -errno : fd; + } - bool gesture_device_exists(); + static void close_restricted(int fd, void *user_data) { close(fd); } - static int open_restricted(const char* path, int flags, void* user_data) - { - int fd = open(path, flags); - return fd < 0 ? -errno : fd; - } + constexpr static struct libinput_interface libinput_interface = { + .open_restricted = open_restricted, + .close_restricted = close_restricted, + }; - static void close_restricted(int fd, void* user_data) - { - close(fd); - } + /* + * Decrements step of current trigger. Just to skip 0 + * @param cur current step + */ + inline void dec_step(int &cur) { --cur == 0 ? --cur : cur; } - constexpr static struct libinput_interface libinput_interface = { - .open_restricted = open_restricted, - .close_restricted = close_restricted, - }; + /* + * Increase step of current trigger. Just to pass -1 + * @param cur current step + */ + inline void inc_step(int &cur) { ++cur == 0 ? ++cur : cur; } - /* - * Decrements step of current trigger. Just to skip 0 - * @param cur current step - */ - inline void dec_step(int &cur) { --cur == 0 ? --cur : cur; } + bool do_rotation_trigger(double angle, double threshold); - /* - * Increase step of current trigger. Just to pass -1 - * @param cur current step - */ - inline void inc_step(int &cur) { ++cur == 0 ? ++cur : cur; } + void handle_event(); - void handle_event(); + /* Swipe event */ + void reset_swipe_event(); - /* Swipe event */ - void reset_swipe_event(); + void handle_swipe_event_without_coords(libinput_event_gesture *gev, + bool begin); - void handle_swipe_event_without_coords(libinput_event_gesture* gev, bool begin); + void handle_swipe_event_with_coords(libinput_event_gesture *gev); - void handle_swipe_event_with_coords(libinput_event_gesture* gev); + void trigger_swipe_command(); - void trigger_swipe_command(); + /* Pinch event */ + void reset_pinch_event(); - /* Pinch event */ - void reset_pinch_event(); + void handle_one_shot_pinch(double new_scale); - void handle_one_shot_pinch(double new_scale); + void handle_continouos_pinch(double new_scale); - void handle_continouos_pinch(double new_scale); + void handle_rotation(double new_angle); - void handle_pinch_event(libinput_event_gesture* gev, bool begin); + void handle_pinch_event(libinput_event_gesture *gev, bool begin); - }; -} +}; +} // namespace gebaar::io -#endif //GEBAAR_INPUT_HPP +#endif // GEBAAR_INPUT_HPP diff --git a/src/main.cpp b/src/main.cpp index 982ce3d..e43a41d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,42 +16,43 @@ along with this program. If not, see . */ - -#include -#include #include "config/config.h" -#include "io/input.h" #include "daemonizer.h" +#include "io/input.h" +#include +#include + +gebaar::io::Input *input; + +int main(int argc, char *argv[]) { + cxxopts::Options options(argv[0], "Gebaard Gestures Daemon"); -gebaar::io::Input* input; + bool should_daemonize = false; -int main(int argc, char* argv[]) -{ - cxxopts::Options options(argv[0], "Gebaard Gestures Daemon"); + options.add_options() + ("b,background", "Daemonize", cxxopts::value(should_daemonize)) + ("h,help", "Prints this help text"); - bool should_daemonize = false; + auto result = options.parse(argc, argv); - options.add_options() - ("b,background", "Daemonize", cxxopts::value(should_daemonize)) - ("h,help", "Prints this help text"); + if (result.count("help")) { + std::cout << options.help() << std::endl; + exit(EXIT_SUCCESS); + } - auto result = options.parse(argc, argv); + if (should_daemonize) { + auto *daemonizer = new gebaar::daemonizer::Daemonizer(); + daemonizer->daemonize(); + } - if (result.count("help")) { - std::cout << options.help() << std::endl; - exit(EXIT_SUCCESS); - } + std::shared_ptr config = + std::make_shared(); - if (should_daemonize) { - auto *daemonizer = new gebaar::daemonizer::Daemonizer(); - daemonizer->daemonize(); - } - std::shared_ptr config = std::make_shared(); - input = new gebaar::io::Input(config); + input = new gebaar::io::Input(config); - if (input->initialize()) { - input->start_loop(); - } + if (input->initialize()) { + input->start_loop(); + } - return 0; + return 0; } diff --git a/src/util.cpp b/src/util.cpp index a56dfe6..947a4a6 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -23,7 +23,6 @@ * @param charArr The char array to convert * @return charArr or an empty string, if charArr is a nullptr */ -std::string gebaar::util::stringFromCharArray(char* charArr) -{ - return charArr == nullptr ? "" : charArr; +std::string gebaar::util::stringFromCharArray(char *charArr) { + return charArr == nullptr ? "" : charArr; } diff --git a/src/util.h b/src/util.h index eafec82..5c0791e 100644 --- a/src/util.h +++ b/src/util.h @@ -22,7 +22,7 @@ #include namespace gebaar::util { - std::string stringFromCharArray(char* charArr); +std::string stringFromCharArray(char *charArr); } #endif // UTIL_H