diff --git a/VERSION b/VERSION index f13f1bb..758fc0b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.0.4 +v1.1.0 diff --git a/lib/comfortable_swipe b/lib/comfortable_swipe index 3ee260a..7c917ca 100644 --- a/lib/comfortable_swipe +++ b/lib/comfortable_swipe @@ -28,6 +28,7 @@ along with this program. If not, see . #include "gesture/xdo_gesture.cpp" #include "gesture/swipe_gesture.cpp" #include "gesture/swipe_gesture.regex.cpp" +#include "gesture/keyboard_swipe_gesture.cpp" #include "service/autostart.cpp" #include "service/buffer.cpp" #include "service/config.cpp" diff --git a/lib/gesture/keyboard_swipe_gesture.cpp b/lib/gesture/keyboard_swipe_gesture.cpp new file mode 100644 index 0000000..9d4489a --- /dev/null +++ b/lib/gesture/keyboard_swipe_gesture.cpp @@ -0,0 +1,197 @@ +#ifndef __COMFORTABLE_SWIPE__gesture_keyboard_swipe_gesture__ +#define __COMFORTABLE_SWIPE__gesture_keyboard_swipe_gesture__ + +/* +Comfortable Swipe +by Rico Tiongson + +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 // std::cout, std::endl +#include // std::stoi, std::stof +#include // std::regex, std::regex_match, std::cmatch +#include "keyboard_swipe_gesture.h" + +extern "C" +{ + #include // xdo, xdo_new, xdo_free, + // xdo_get_mouse_location + // CURRENT_WINDOW +} + +namespace comfortable_swipe::gesture +{ + + /* STATICS DEFINITIONS */ + const int keyboard_swipe_gesture::MSK_THREE_FINGERS = 0; + const int keyboard_swipe_gesture::MSK_FOUR_FINGERS = 1; + const int keyboard_swipe_gesture::MSK_NEGATIVE = 0; + const int keyboard_swipe_gesture::MSK_POSITIVE = 2; + const int keyboard_swipe_gesture::MSK_HORIZONTAL = 0; + const int keyboard_swipe_gesture::MSK_VERTICAL = 4; + const int keyboard_swipe_gesture::FRESH = -1; + const char * const keyboard_swipe_gesture::command_map[8] = { + "left3", + "left4", + "right3", + "right4", + "up3", + "up4", + "down3", + "down4" + }; + + /** + * Constructs a new keyboard-based swipe gesture, given configurations + * for certain swipe events. Here, we construct our definition based on + * the four directions (left, up, right, down) for 3-finger and 4-finger + * swipes. Note that the direction is based on the Australian natural + * scrolling direction (ie. left3 is natural movement of 3 fingers left). + */ + keyboard_swipe_gesture::keyboard_swipe_gesture + ( + const float threshold, + const char* left3 /* 000 */, + const char* left4 /* 001 */, + const char* right3 /* 010 */, + const char* right4 /* 011 */, + const char* up3 /* 100 */, + const char* up4 /* 101 */, + const char* down3 /* 110 */, + const char* down4 /* 111 */ + ): + // construct superclass + comfortable_swipe::gesture::swipe_gesture(), + // compute square of threshold because we will use squared distances + threshold_squared(threshold*threshold), + // register our commands + commands(new const char*[8]{ + left3, left4, right3, right4, up3, up4, down3, down4 + }) + { } + + /** + * Destructs this keyboard swipe gesture. + */ + keyboard_swipe_gesture::~keyboard_swipe_gesture() + { + delete[] commands; + } + + /** + * Hook on begin of swipe gesture. + */ + void keyboard_swipe_gesture::begin() + { + // call superclass method + swipe_gesture::begin(); + + // assign previous gesture to FRESH + this->previous_gesture = keyboard_swipe_gesture::FRESH; + } + + /** + * Hook on update of swipe gesture. + */ + void keyboard_swipe_gesture::update() + { + // call superclass method + swipe_gesture::update(); + + // scale threshold to 1/10 when gesture is not fresh + float scale = + this->previous_gesture == keyboard_swipe_gesture::FRESH + ? 1.00f + : 0.01f; // square root of 1/10 + + // we are working with floating points which are not exact + // make sure we compare with a very small value (epsilon) + static const float EPSILON = 1e-6f; + const float distance_squared = this->x * this->x + this->y * this->y; + const float beyond_threshold = this->threshold_squared * scale; + + // apply if strictly beyond threshold + if (distance_squared > beyond_threshold + EPSILON) + { + // we parse our mask based on the values obtained from the regex + int mask = 0; + + if (this->fingers == 3) + mask |= keyboard_swipe_gesture::MSK_THREE_FINGERS; + + else if (this->fingers == 4) + mask |= keyboard_swipe_gesture::MSK_FOUR_FINGERS; + + const float absx = x >= 0 ? x : -x; + const float absy = y >= 0 ? y : -y; + + if (absx > absy) + { + // gesture is horizontal + mask |= keyboard_swipe_gesture::MSK_HORIZONTAL; + if (x < 0) + mask |= keyboard_swipe_gesture::MSK_NEGATIVE; + else + mask |= keyboard_swipe_gesture::MSK_POSITIVE; + } + else /* std::abs(x) <= std::abs(y) */ + { + // gesture is vertical + mask |= keyboard_swipe_gesture::MSK_VERTICAL; + if (y < 0) + mask |= keyboard_swipe_gesture::MSK_NEGATIVE; + else + mask |= keyboard_swipe_gesture::MSK_POSITIVE; + } + + // send command on fresh OR opposite gesture + if (this->previous_gesture == keyboard_swipe_gesture::FRESH + || this->previous_gesture == (mask ^ keyboard_swipe_gesture::MSK_POSITIVE)) + { + this->do_keyboard_gesture(mask); + } + } + } + + /** + * Apply the update given a mask. + */ + void keyboard_swipe_gesture::do_keyboard_gesture(int mask) + { + // perform our keyboard command with xdo_send_keysequence + const char * command = keyboard_swipe_gesture::commands[mask]; + xdo_send_keysequence_window(this->xdo, CURRENTWINDOW, command, 0); + + // reset our location variables + this->x = this->y = 0; + this->previous_gesture = mask; + + // log our command name in stdout + const char * command_name = keyboard_swipe_gesture::command_map[mask]; + std::cout << "SWIPE " << command_name << std::endl; + } + + /** + * Hook on end of swipe gesture. + */ + void keyboard_swipe_gesture::end() + { + // call superclass method + swipe_gesture::end(); + } + +} + +#endif /* __COMFORTABLE_SWIPE__gesture_keyboard_swipe_gesture__ */ diff --git a/lib/gesture/keyboard_swipe_gesture.h b/lib/gesture/keyboard_swipe_gesture.h new file mode 100644 index 0000000..f9e9b77 --- /dev/null +++ b/lib/gesture/keyboard_swipe_gesture.h @@ -0,0 +1,84 @@ +#ifndef __COMFORTABLE_SWIPE__gesture_keyboard_swipe_gesture_h__ +#define __COMFORTABLE_SWIPE__gesture_keyboard_swipe_gesture_h__ + +/* +Comfortable Swipe +by Rico Tiongson + +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 "swipe_gesture.h" + +#ifdef __cplusplus +extern "C" { +#endif + +namespace comfortable_swipe::gesture +{ + class keyboard_swipe_gesture : public swipe_gesture + { + public: + // constructor + keyboard_swipe_gesture( + const float threshold, + const char* left3 /* 000 */, + const char* left4 /* 001 */, + const char* right3 /* 010 */, + const char* right4 /* 011 */, + const char* up3 /* 100 */, + const char* up4 /* 101 */, + const char* down3 /* 110 */, + const char* down4 /* 111 */ + ); + + // destructor + ~keyboard_swipe_gesture(); + + // hooks that we override + virtual void begin() override; + virtual void update() override; + virtual void end() override; + + // override this when keyboard gesture is to be performed + virtual void do_keyboard_gesture(int mask); + + protected: + // stores square of threshold so we can compute faster + float threshold_squared; + + // stores previous gesture so we don't repeat action + int previous_gesture; + + // stores all command strings for xdo to execute + const char ** commands; + + public: + // static enums we will use for gesture matching + static const int FRESH; + static const int MSK_THREE_FINGERS; + static const int MSK_FOUR_FINGERS; + static const int MSK_NEGATIVE; + static const int MSK_POSITIVE; + static const int MSK_HORIZONTAL; + static const int MSK_VERTICAL; + static const char * const command_map[8]; + }; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __COMFORTABLE_SWIPE__gesture_keyboard_swipe_gesture_h__ */ diff --git a/lib/gesture/swipe_gesture.cpp b/lib/gesture/swipe_gesture.cpp index 973df0f..e91d440 100644 --- a/lib/gesture/swipe_gesture.cpp +++ b/lib/gesture/swipe_gesture.cpp @@ -34,100 +34,47 @@ extern "C" namespace comfortable_swipe::gesture { /** - * Constructs a new swipe gesture, given configurations for certain swipe events. + * Constructs a new fresh swipe gesture container. */ swipe_gesture::swipe_gesture - ( - const float threshold, - const char* left3 /* 000 */, - const char* left4 /* 001 */, - const char* right3 /* 010 */, - const char* right4 /* 011 */, - const char* up3 /* 100 */, - const char* up4 /* 101 */, - const char* down3 /* 110 */, - const char* down4 /* 111 */ - ): + (): + // construct our superclass comfortable_swipe::gesture::xdo_gesture(), - threshold_squared(threshold*threshold), - commands(new const char*[8]{left3, left4, right3, right4, up3, up4, down3, down4}), flag_swiping(false) { - // improve responsiveness of first gesture by pre-empting xdotool runtime - xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, &this->screen_num); + // improve responsiveness of first gesture by pre-empting xdotool + xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, + &this->screen_num); } /** * Destructs this swipe gesture. */ swipe_gesture::~swipe_gesture() - { - delete[] commands; - } + { } /** - * Hook on begin of swipe gesture. + * Hook on begin of swipe gesture (you can override this). */ void swipe_gesture::begin() { - xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, &this->screen_num); - this->previous_gesture = swipe_gesture::FRESH; + xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, + &this->screen_num); this->x = 0; this->y = 0; } /** - * Hook on update of swipe gesture. + * Hook on update of swipe gesture (you can override this). */ void swipe_gesture::update() { this->x += this->dx; this->y += this->dy; - // scale threshold to 1/10 when gesture is not fresh - float scale = this->previous_gesture == swipe_gesture::FRESH - ? 1.00f - : 0.01f; // square root of 1/10 - static const float EPSILON = 1e-6f; - if (this->x * this->x + this->y * this->y - > this->threshold_squared * scale + EPSILON) - { - int mask = 0; - if (this->fingers == 3) mask |= swipe_gesture::MSK_THREE_FINGERS; - else if (this->fingers == 4) mask |= swipe_gesture::MSK_FOUR_FINGERS; - - const float absx = x >= 0 ? x : -x; - const float absy = y >= 0 ? y : -y; - if (absx > absy) - { // horizontal - mask |= swipe_gesture::MSK_HORIZONTAL; - if (x < 0) - mask |= swipe_gesture::MSK_NEGATIVE; - else - mask |= swipe_gesture::MSK_POSITIVE; - } - else /* std::abs(x) <= std::abs(y) */ - { // vertical - mask |= swipe_gesture::MSK_VERTICAL; - if (y < 0) - mask |= swipe_gesture::MSK_NEGATIVE; - else - mask |= swipe_gesture::MSK_POSITIVE; - } - - // send command on fresh OR opposite gesture - if (this->previous_gesture == swipe_gesture::FRESH - || this->previous_gesture == (mask ^ swipe_gesture::MSK_POSITIVE)) - { - xdo_send_keysequence_window(this->xdo, CURRENTWINDOW, swipe_gesture::commands[mask], 0); - this->x = this->y = 0; - this->previous_gesture = mask; - std::cout << "SWIPE " << swipe_gesture::command_map[mask] << std::endl; - } - } } /** - * Hook on end of swipe gesture. + * Hook on end of swipe gesture (you can override this). */ void swipe_gesture::end() { } @@ -141,10 +88,11 @@ namespace comfortable_swipe::gesture bool swipe_gesture::parse_line(const char * line) { - // prepare regex matchers (will only load at most once) - static const std::regex gesture_swipe_begin(swipe_gesture::GESTURE_BEGIN_REGEX_PATTERN); - static const std::regex gesture_swipe_update(swipe_gesture::GESTURE_UPDATE_REGEX_PATTERN); - static const std::regex gesture_swipe_end(swipe_gesture::GESTURE_END_REGEX_PATTERN); + // prepare regex matchers statically (will only load at most once) + static const std::regex + gesture_swipe_begin(swipe_gesture::GESTURE_BEGIN_REGEX_PATTERN), + gesture_swipe_update(swipe_gesture::GESTURE_UPDATE_REGEX_PATTERN), + gesture_swipe_end(swipe_gesture::GESTURE_END_REGEX_PATTERN); // prepare holder for regex matches static std::cmatch matches; @@ -191,25 +139,6 @@ namespace comfortable_swipe::gesture return false; } - - /* STATICS DEFINITIONS */ - const int swipe_gesture::MSK_THREE_FINGERS = 0; - const int swipe_gesture::MSK_FOUR_FINGERS = 1; - const int swipe_gesture::MSK_NEGATIVE = 0; - const int swipe_gesture::MSK_POSITIVE = 2; - const int swipe_gesture::MSK_HORIZONTAL = 0; - const int swipe_gesture::MSK_VERTICAL = 4; - const int swipe_gesture::FRESH = -1; - const char * const swipe_gesture::command_map[8] = { - "left3", - "left4", - "right3", - "right4", - "up3", - "up4", - "down3", - "down4" - }; } #endif /* __COMFORTABLE_SWIPE__gesture_swipe_gesture__ */ diff --git a/lib/gesture/swipe_gesture.h b/lib/gesture/swipe_gesture.h index 86ec3bd..adeffd9 100644 --- a/lib/gesture/swipe_gesture.h +++ b/lib/gesture/swipe_gesture.h @@ -27,55 +27,33 @@ extern "C" { namespace comfortable_swipe::gesture { - class swipe_gesture : protected xdo_gesture + class swipe_gesture : public xdo_gesture { public: // constructor - swipe_gesture( - const float threshold, - const char* left3 /* 000 */, - const char* left4 /* 001 */, - const char* right3 /* 010 */, - const char* right4 /* 011 */, - const char* up3 /* 100 */, - const char* up4 /* 101 */, - const char* down3 /* 110 */, - const char* down4 /* 111 */ - ); + swipe_gesture(); + // destructor ~swipe_gesture(); // fields for xdo int fingers; - float dx, dy, udx, udy; + float x, y, dx, dy, udx, udy; - void begin() override; - void update() override; - void end() override; - bool parse_line(const char *) override; + // hooks that we can override (mark as virtual) + virtual void begin(); + virtual void update(); + virtual void end(); + virtual bool parse_line(const char *); protected: // location of mouse int screen_num, ix, iy; - // current location - float x, y, threshold_squared; - int previous_gesture; - const char ** commands; - // optimization flag for checking if GESTURE_SWIPE_BEGIN was dispatched bool flag_swiping; public: - // static constants - static const int MSK_THREE_FINGERS; - static const int MSK_FOUR_FINGERS; - static const int MSK_NEGATIVE; - static const int MSK_POSITIVE; - static const int MSK_HORIZONTAL; - static const int MSK_VERTICAL; - static const int FRESH; - static const char * const command_map[8]; // regex patterns static const char* GESTURE_BEGIN_REGEX_PATTERN; static const char* GESTURE_UPDATE_REGEX_PATTERN; diff --git a/lib/gesture/xdo_gesture.h b/lib/gesture/xdo_gesture.h index 37eb157..0dd6834 100644 --- a/lib/gesture/xdo_gesture.h +++ b/lib/gesture/xdo_gesture.h @@ -40,12 +40,6 @@ namespace comfortable_swipe public: xdo_gesture(); ~xdo_gesture(); - - // hooks - virtual void begin() = 0; - virtual void update() = 0; - virtual void end() = 0; - virtual bool parse_line(const char *) = 0; }; } } diff --git a/lib/service/buffer.cpp b/lib/service/buffer.cpp index 7edd7b6..69dbbb4 100644 --- a/lib/service/buffer.cpp +++ b/lib/service/buffer.cpp @@ -36,10 +36,12 @@ namespace comfortable_swipe::service std::cout.flush(); // read config file - auto config = comfortable_swipe::util::read_config_file(comfortable_swipe::util::conf_filename()); + auto config = comfortable_swipe::util::read_config_file( + comfortable_swipe::util::conf_filename() + ); // initialize swipe gesture handler - comfortable_swipe::gesture::swipe_gesture swipe_gesture_handler + comfortable_swipe::gesture::keyboard_swipe_gesture keyboard_swipe ( config.count("threshold") ? std::stof(config["threshold"]) : 0.0, config["left3"].c_str(), @@ -59,7 +61,7 @@ namespace comfortable_swipe::service while (fgets_unlocked(line.data(), line.size(), stdin) != NULL) { // attempt to parse swipe gestures - swipe_gesture_handler.parse_line(line.data()); + keyboard_swipe.parse_line(line.data()); } } } diff --git a/lib/service/status.cpp b/lib/service/status.cpp index b20cfd3..be25ae7 100644 --- a/lib/service/status.cpp +++ b/lib/service/status.cpp @@ -73,7 +73,7 @@ namespace comfortable_swipe::service std::printf(" %9s is OFF\n", "threshold"); // print swipe commands - for (auto &command : comfortable_swipe::gesture::swipe_gesture::command_map) + for (auto &command : comfortable_swipe::gesture::keyboard_swipe_gesture::command_map) { if (config.count(command) > 0) std::printf(" %9s is OK (%s)\n", command, config[command].data());