From 268908e5a7fe5b87bffcaa611e79b81498e6bc31 Mon Sep 17 00:00:00 2001 From: PixlOne <8843371+PixlOne@users.noreply.github.com> Date: Thu, 8 Aug 2019 18:22:54 -0400 Subject: [PATCH] Implement additional gesture modes --- src/logid/Actions.cpp | 92 +++++++++++++++++++++++++++++++++++-- src/logid/Actions.h | 34 ++++++++++---- src/logid/Configuration.cpp | 61 ++++++++++++++++++++++-- src/logid/Configuration.h | 2 + src/logid/Device.cpp | 85 +++++++++++++++++++++++----------- src/logid/Device.h | 14 ++++-- src/logid/EvdevDevice.cpp | 6 +++ src/logid/EvdevDevice.h | 1 + src/logid/util.cpp | 4 +- 9 files changed, 249 insertions(+), 50 deletions(-) diff --git a/src/logid/Actions.cpp b/src/logid/Actions.cpp index cb3485a..3ecff7a 100644 --- a/src/logid/Actions.cpp +++ b/src/logid/Actions.cpp @@ -1,17 +1,59 @@ +#include +#include #include #include #include #include #include +#include #include "Actions.h" #include "util.h" #include "EvdevDevice.h" -KeyAction::KeyAction(const KeyAction &a, Device* d) : ButtonAction(Action::Keypress) +NoAction* NoAction::copy(Device *dev) { - device = d; - std::copy(a.keys.begin(), a.keys.end(), std::back_inserter(keys)); + auto action = new NoAction(); + action->device = dev; + return action; +} +KeyAction* KeyAction::copy(Device *dev) +{ + auto action = new KeyAction(keys); + action->device = dev; + return action; +} +GestureAction* GestureAction::copy(Device* dev) +{ + auto action = new GestureAction({}); + action->device = dev; + for(auto it : gestures) + action->gestures.insert({it.first, new Gesture(*it.second, dev)}); + return action; +} +SmartshiftAction* SmartshiftAction::copy(Device* dev) +{ + auto action = new SmartshiftAction(); + action->device = dev; + return action; +} +HiresScrollAction* HiresScrollAction::copy(Device* dev) +{ + auto action = new HiresScrollAction(); + action->device = dev; + return action; +} +CycleDPIAction* CycleDPIAction::copy(Device* dev) +{ + auto action = new CycleDPIAction(dpis); + action->device = dev; + return action; +} +ChangeDPIAction* ChangeDPIAction::copy(Device* dev) +{ + auto action = new ChangeDPIAction(dpi_inc); + action->device = dev; + return action; } void KeyAction::press() @@ -39,12 +81,54 @@ void GestureAction::move(HIDPP20::IReprogControlsV4::Move m) { x += m.x; y += m.y; + if(m.y != 0 && abs(y) > 50) + { + auto g = gestures.find(m.y > 0 ? Direction::Down : Direction::Up); + if(g != gestures.end()) + { + if (g->second->mode == GestureMode::Axis) + global_evdev->move_axis(g->second->axis, abs(m.y) * g->second->axis_multiplier); + if (g->second->mode == GestureMode::OnFewPixels) + { + g->second->per_pixel_mod += abs(m.y); + if(g->second->per_pixel_mod >= g->second->per_pixel) + { + g->second->per_pixel_mod -= g->second->per_pixel; + g->second->action->press(); + g->second->action->release(); + } + } + } + } + if(m.x != 0 && abs(x) > 50) + { + auto g = gestures.find(m.x > 0 ? Direction::Right : Direction::Left); + if(g != gestures.end()) + { + if (g->second->mode == GestureMode::Axis) + global_evdev->move_axis(g->second->axis, abs(m.x) * g->second->axis_multiplier); + if (g->second->mode == GestureMode::OnFewPixels) + { + g->second->per_pixel_mod += abs(m.x); + if (g->second->per_pixel_mod >= g->second->per_pixel) + { + g->second->per_pixel_mod -= g->second->per_pixel; + g->second->action->press(); + g->second->action->release(); + } + } + } + } } void GestureAction::release() { held = false; - auto direction = get_direction(x, y); + Direction direction; + if(abs(x) < 50 && abs(y) < 50) direction = Direction::None; + else direction = get_direction(x, y); + x = 0; + y = 0; auto g = gestures.find(direction); diff --git a/src/logid/Actions.h b/src/logid/Actions.h index 2eee633..fe5b5d7 100644 --- a/src/logid/Actions.h +++ b/src/logid/Actions.h @@ -28,7 +28,8 @@ enum class GestureMode { NoPress, OnRelease, - OnFewPixels + OnFewPixels, + Axis }; class Device; @@ -37,6 +38,7 @@ class ButtonAction { public: Action type; + virtual ButtonAction* copy(Device* dev) = 0; virtual void press() = 0; virtual void release() = 0; // ButtonAction(const ButtonAction &a, Device* d) : type (a.type), device (d) {} @@ -49,6 +51,7 @@ class NoAction : public ButtonAction { public: NoAction() : ButtonAction(Action::None) {} + virtual NoAction* copy(Device* dev); virtual void press() {} virtual void release() {} }; @@ -56,8 +59,7 @@ class KeyAction : public ButtonAction { public: explicit KeyAction(std::vector k) : ButtonAction(Action::Keypress), keys (std::move(k)) {}; - KeyAction(const KeyAction &a, Device* d); - //virtual KeyAction* create_instance(Device* d) { return new KeyAction(*this, d); }; + virtual KeyAction* copy(Device* dev); virtual void press(); virtual void release(); private: @@ -66,31 +68,42 @@ private: class Gesture { public: - Gesture(ButtonAction* ba, GestureMode m, int pp=0) : action (ba), mode (m), per_pixel (pp) {}; - Gesture(const Gesture &g) : action (g.action), mode (g.mode), per_pixel (g.per_pixel) {}; + Gesture(ButtonAction* ba, GestureMode m, int pp=0, uint a=0, float am=1) + : action (ba), mode (m), per_pixel (pp), axis (a), axis_multiplier (am) + { + } + Gesture(const Gesture &g, Device* dev) + : action (g.action->copy(dev)), mode (g.mode), per_pixel (g.per_pixel), axis (g.axis), axis_multiplier (g.axis_multiplier) + { + } ButtonAction* action; - GestureMode mode; int per_pixel; + int per_pixel_mod; + uint axis; + float axis_multiplier; }; + class GestureAction : public ButtonAction { public: GestureAction(std::map g) : ButtonAction(Action::Gestures), gestures (std::move(g)) {}; std::map gestures; + virtual GestureAction* copy(Device* dev); virtual void press(); - void move(HIDPP20::IReprogControlsV4::Move m); virtual void release(); + void move(HIDPP20::IReprogControlsV4::Move m); private: bool held; - int x; - int y; + int x = 0; + int y = 0; }; class SmartshiftAction : public ButtonAction { public: SmartshiftAction() : ButtonAction(Action::ToggleSmartshift) {}; + virtual SmartshiftAction* copy(Device* dev); virtual void press(); virtual void release() {} }; @@ -98,6 +111,7 @@ class HiresScrollAction : public ButtonAction { public: HiresScrollAction() : ButtonAction(Action::ToggleHiresScroll) {}; + virtual HiresScrollAction* copy(Device* dev); virtual void press(); virtual void release() {} }; @@ -105,6 +119,7 @@ class CycleDPIAction : public ButtonAction { public: CycleDPIAction(std::vector d) : ButtonAction(Action::CycleDPI), dpis (d) {}; + virtual CycleDPIAction* copy(Device* dev); virtual void press(); virtual void release() {} private: @@ -114,6 +129,7 @@ class ChangeDPIAction : public ButtonAction { public: ChangeDPIAction(int i) : ButtonAction(Action::ChangeDPI), dpi_inc (i) {}; + virtual ChangeDPIAction* copy(Device* dev); virtual void press(); virtual void release() {} private: diff --git a/src/logid/Configuration.cpp b/src/logid/Configuration.cpp index 1be9463..00ddeda 100644 --- a/src/logid/Configuration.cpp +++ b/src/logid/Configuration.cpp @@ -21,7 +21,7 @@ Configuration::Configuration(const char *config_file) } catch(const FileIOException &e) { - log_printf(ERROR, "%s", "I/O Error while reading configuration file!"); + log_printf(ERROR, "I/O Error while reading configuration file: %s", e.what()); throw e; } catch(const ParseException &e) @@ -69,10 +69,7 @@ DeviceConfig::DeviceConfig(const libconfig::Setting &root) throw SettingTypeException(root["dpi"]); dpi = new int(d); } - catch(const SettingNotFoundException &e) - { - log_printf(INFO, "Missing dpi option, not setting."); - } + catch(const SettingNotFoundException &e) { } catch(const SettingTypeException &e) { log_printf(WARN, "Line %d: DPI must me an integer; not setting.", root["dpi"].getSourceLine()); @@ -325,6 +322,51 @@ ButtonAction* parse_action(Action type, const Setting* action_config, bool is_ge continue; } + if(mode == GestureMode::Axis) + { + uint axis; + try + { + std::string axis_str; + if(!gesture_config.lookupValue("axis", axis_str)) + throw SettingTypeException(gesture_config["axis"]); + axis = libevdev_event_code_from_name(EV_REL, axis_str.c_str()); + } + catch(SettingNotFoundException &e) + { + log_printf(WARN, "Line %d: No axis found, defaulting to no action.", gesture_config.getSourceLine()); + gestures.insert({direction, new Gesture(new NoAction(), GestureMode::NoPress)}); + continue; + } + catch(SettingTypeException &e) + { + log_printf(WARN, "Line %d: Axis must be a string (e.g. 'REL_WHEEL')", gesture_config["axis"].getSourceLine()); + gestures.insert({direction, new Gesture(new NoAction(), GestureMode::NoPress)}); + continue; + } + + float multiplier = 1; + try + { + if(!gesture_config.lookupValue("axis_multiplier", multiplier)) + { + int im = 1; + if(!gesture_config.lookupValue("axis_multiplier", im)) + throw SettingTypeException(gesture_config["axis_multiplier"]); + multiplier = im; + } + } + catch(SettingNotFoundException &e) { } + catch(SettingTypeException &e) + { + log_printf(WARN, "Line %d: axis_multiplier must be a float/integer", gesture_config["axis_multiplier"].getSourceLine()); + continue; + } + + gestures.insert({direction, new Gesture(new NoAction(), GestureMode::Axis, 0, axis, multiplier)}); + continue; + } + Setting* g_action; try { g_action = &gesture_config["action"]; } catch(SettingNotFoundException &e) @@ -414,6 +456,15 @@ ButtonAction* parse_action(Action type, const Setting* action_config, bool is_ge return new NoAction(); } +DeviceConfig::DeviceConfig(DeviceConfig* dc, Device* dev) : baseConfig (false) +{ + dpi = dc->dpi; + smartshift = dc->smartshift; + hiresscroll = dc->hiresscroll; + for(auto it : dc->actions) + actions.insert( { it.first, it.second->copy(dev) } ); +} + DeviceConfig::DeviceConfig() { dpi = nullptr; diff --git a/src/logid/Configuration.h b/src/logid/Configuration.h index ac1eea9..0a45a3a 100644 --- a/src/logid/Configuration.h +++ b/src/logid/Configuration.h @@ -14,11 +14,13 @@ class DeviceConfig { public: DeviceConfig(); + DeviceConfig(DeviceConfig* dc, Device* dev); DeviceConfig(const libconfig::Setting& root); const int* dpi = nullptr; HIDPP20::ISmartShift::SmartshiftStatus* smartshift; const uint8_t* hiresscroll = nullptr; std::map actions; + const bool baseConfig = true; }; class Configuration diff --git a/src/logid/Device.cpp b/src/logid/Device.cpp index 9c10c4f..4fb0a53 100644 --- a/src/logid/Device.cpp +++ b/src/logid/Device.cpp @@ -40,22 +40,41 @@ Device::Device(std::string p, const HIDPP::DeviceIndex i) : path(std::move(p)), else config = global_config->devices.find(name)->second; } -void Device::configure(bool scanning) +void Device::configure() { + if(config->baseConfig) + config = new DeviceConfig(config, this); + + configuring = true; + usleep(50000); + if(disconnected) { + configuring = false; return; } + // Divert buttons divert_buttons(); + if(disconnected) { + configuring = false; return; } + // Set DPI if it is set if(config->dpi != nullptr) - set_dpi(*config->dpi, scanning); + set_dpi(*config->dpi); + if(disconnected) { + configuring = false; return; } + // Set Smartshift if it is set if(config->smartshift != nullptr) - set_smartshift(*config->smartshift, scanning); + set_smartshift(*config->smartshift); + if(disconnected) { + configuring = false; return; } + // Set Hires Scroll if it is set if(config->hiresscroll != nullptr) - set_hiresscroll(*config->hiresscroll, scanning); + set_hiresscroll(*config->hiresscroll); + + configuring = false; } -void Device::divert_buttons(bool scanning) +void Device::divert_buttons() { try { @@ -78,9 +97,13 @@ void Device::divert_buttons(bool scanning) { log_printf(DEBUG, "%s does not support Reprog controls, not diverting!", name.c_str()); } + catch(HIDPP10::Error &e) + { + log_printf(DEBUG, "Could not divert buttons: HID++ 1.0 Error %s!", e.what()); + } } -void Device::set_smartshift(HIDPP20::ISmartShift::SmartshiftStatus ops, bool scanning) +void Device::set_smartshift(HIDPP20::ISmartShift::SmartshiftStatus ops) { try { @@ -97,7 +120,7 @@ void Device::set_smartshift(HIDPP20::ISmartShift::SmartshiftStatus ops, bool sca } } -void Device::set_hiresscroll(uint8_t ops, bool scanning) +void Device::set_hiresscroll(uint8_t ops) { try { @@ -114,17 +137,12 @@ void Device::set_hiresscroll(uint8_t ops, bool scanning) } } -void Device::set_dpi(int dpi, bool scanning) +void Device::set_dpi(int dpi) { HIDPP20::IAdjustableDPI iad(hidpp_dev); - try { for(int i = 0; i < iad.getSensorCount(); i++) iad.setSensorDPI(i, dpi); } - catch (HIDPP20::Error &e) - { - if(scanning) - throw e; - log_printf(ERROR, "Error while setting DPI: %s", e.what()); - } + try { for(unsigned int i = 0; i < iad.getSensorCount(); i++) iad.setSensorDPI(i, dpi); } + catch (HIDPP20::Error &e) { log_printf(ERROR, "Error while setting DPI: %s", e.what()); } } void Device::start() @@ -192,7 +210,7 @@ void ReceiverHandler::handleEvent(const HIDPP::Report &event) { if(it->first->path == dev->path && it->first->index == event.deviceIndex()) { - log_printf(INFO, "%s (Device %d on %s) unpaired.", it->first->name.c_str(), event.deviceIndex(), dev->path); + log_printf(INFO, "%s (Device %d on %s) unpaired.", it->first->name.c_str(), event.deviceIndex(), dev->path.c_str()); it->first->stop(); it->second.join(); finder->devices.erase(it); @@ -202,18 +220,28 @@ void ReceiverHandler::handleEvent(const HIDPP::Report &event) break; } case HIDPP10::IReceiver::DevicePaired: - { break; - } case HIDPP10::IReceiver::ConnectionStatus: { auto status = HIDPP10::IReceiver::connectionStatusEvent(event); if(status == HIDPP10::IReceiver::LinkLoss) - log_printf(INFO, "Link lost to device %d on %s", event.deviceIndex(), dev->path.c_str()); + { + log_printf(INFO, "Link lost to %s", dev->name.c_str()); + dev->disconnected = true; + } else if (status == HIDPP10::IReceiver::ConnectionEstablished) { - dev->configure(); - log_printf(INFO, "Connection established to device %d on %s", event.deviceIndex(), dev->path.c_str()); + log_printf(INFO, "Connection established to %s", dev->name.c_str()); + dev->disconnected = false; + std::thread + { + [dev=this->dev] + { + while (dev->configuring) + if(dev->disconnected) return; + dev->configure(); + } + }.detach(); } break; } @@ -293,11 +321,16 @@ void Device::release_button(uint16_t cid) void Device::move_diverted(uint16_t cid, HIDPP20::IReprogControlsV4::Move m) { - auto action = config->actions.find(cid)->second; - switch(action->type) + auto action = config->actions.find(cid); + if(action == config->actions.end()) + { + log_printf(DEBUG, "0x%x's RawXY was diverted with no action.", cid); + return; + } + switch(action->second->type) { case Action::Gestures: - ((GestureAction*)action)->move(m); + ((GestureAction*)action->second)->move(m); break; default: break; @@ -308,9 +341,9 @@ std::map Device::get_features() { std::map _features; HIDPP20::IFeatureSet ifs (hidpp_dev); - unsigned int feature_count = ifs.getCount(); + uint8_t feature_count = ifs.getCount(); - for(int i = 0; i < feature_count; i++) + for(uint8_t i = 0; i < feature_count; i++) _features.insert( {i, ifs.getFeatureID(i) } ); return _features; diff --git a/src/logid/Device.h b/src/logid/Device.h index 2400f2c..84a13fd 100644 --- a/src/logid/Device.h +++ b/src/logid/Device.h @@ -21,7 +21,7 @@ public: std::string name; - void configure(bool scanning=false); + void configure(); void press_button(uint16_t cid); void release_button(uint16_t cid); @@ -39,15 +39,18 @@ public: HIDPP::Dispatcher* dispatcher; HIDPP20::Device* hidpp_dev; + bool configuring = false; + bool disconnected = false; + protected: DeviceConfig* config; bool DeviceRemoved; EventListener* listener; - void divert_buttons(bool scanning=false); - void set_smartshift(HIDPP20::ISmartShift::SmartshiftStatus ops, bool scanning=false); - void set_hiresscroll(uint8_t flags, bool scanning=false); - void set_dpi(int dpi, bool scanning=false); + void divert_buttons(); + void set_smartshift(HIDPP20::ISmartShift::SmartshiftStatus ops); + void set_hiresscroll(uint8_t flags); + void set_dpi(int dpi); }; class EventHandler @@ -81,6 +84,7 @@ public: ReceiverHandler (Device *d) : dev (d) { } const HIDPP20::FeatureInterface *feature () const { + return nullptr; // This sounds like a horrible idea } virtual const std::vector featureIndices() const { diff --git a/src/logid/EvdevDevice.cpp b/src/logid/EvdevDevice.cpp index 7abeaa9..0ac3545 100644 --- a/src/logid/EvdevDevice.cpp +++ b/src/logid/EvdevDevice.cpp @@ -22,6 +22,12 @@ EvdevDevice::EvdevDevice(const char* name) throw std::system_error(-err, std::generic_category()); } +void EvdevDevice::move_axis(unsigned int axis, int movement) +{ + libevdev_uinput_write_event(ui_device, EV_REL, axis, movement); + libevdev_uinput_write_event(ui_device, EV_SYN, SYN_REPORT, 0); +} + void EvdevDevice::send_event(unsigned int type, unsigned int code, int value) { libevdev_uinput_write_event(ui_device, type, code, value); diff --git a/src/logid/EvdevDevice.h b/src/logid/EvdevDevice.h index 36e3a57..0d7e78c 100644 --- a/src/logid/EvdevDevice.h +++ b/src/logid/EvdevDevice.h @@ -9,6 +9,7 @@ class EvdevDevice public: EvdevDevice(const char* name); ~EvdevDevice(); + void move_axis(unsigned int axis, int movement); void send_event(unsigned int type, unsigned int code, int value); libevdev* device; libevdev_uinput* ui_device; diff --git a/src/logid/util.cpp b/src/logid/util.cpp index e5feab0..80c19d5 100644 --- a/src/logid/util.cpp +++ b/src/logid/util.cpp @@ -34,7 +34,7 @@ const char* level_prefix(LogLevel level) Direction get_direction(int x, int y) { - if(abs(x) < 50 && abs(y) < 50) return Direction::None; + if(x == 0 && y == 0) return Direction::None; double angle; @@ -83,11 +83,13 @@ GestureMode string_to_gesturemode(std::string s) if(s == "nopress") return GestureMode::NoPress; if(s == "onrelease") return GestureMode::OnRelease; if(s == "onfewpixels") return GestureMode::OnFewPixels; + if(s == "axis") return GestureMode::Axis; s = original_str; log_printf(INFO, "%s is an invalid gesture mode. Defaulting to OnRelease", original_str); + return GestureMode::OnRelease; }