diff --git a/src/gui/src/Action.cpp b/src/gui/src/Action.cpp index 2882afb1..4ca9b684 100644 --- a/src/gui/src/Action.cpp +++ b/src/gui/src/Action.cpp @@ -26,7 +26,8 @@ const char* Action::m_ActionTypeNames[] = "keyDown", "keyUp", "keystroke", "switchToScreen", "toggleScreen", "switchInDirection", "lockCursorToScreen", - "mouseDown", "mouseUp", "mousebutton" + "userScript", + "mouseDown", "mouseUp", "mousebutton", }; const char* Action::m_SwitchDirectionNames[] = { "left", "right", "up", "down" }; @@ -37,6 +38,7 @@ Action::Action() : m_Type(keystroke), m_TypeScreenNames(), m_SwitchScreenName(), + m_UserScriptCommand(), m_SwitchDirection(switchLeft), m_LockCursorMode(lockCursorToggle), m_ActiveOnRelease(false), @@ -105,6 +107,11 @@ QString Action::text() const text += ")"; break; + case userScript: + text += "("; + text += userScriptCommand(); + text += ")"; + break; default: Q_ASSERT(0); break; @@ -133,6 +140,7 @@ void Action::loadSettings(QSettings& settings) setLockCursorMode(settings.value("lockCursorToScreen", lockCursorToggle).toInt()); setActiveOnRelease(settings.value("activeOnRelease", false).toBool()); setHaveScreens(settings.value("hasScreens", false).toBool()); + setUserScriptCommand(settings.value("userScriptCommand").toString()); } void Action::saveSettings(QSettings& settings) const @@ -153,6 +161,7 @@ void Action::saveSettings(QSettings& settings) const settings.setValue("lockCursorToScreen", lockCursorMode()); settings.setValue("activeOnRelease", activeOnRelease()); settings.setValue("hasScreens", haveScreens()); + settings.setValue("userScriptCommand", userScriptCommand()); } QTextStream& operator<<(QTextStream& outStream, const Action& action) diff --git a/src/gui/src/Action.h b/src/gui/src/Action.h index c260badc..64a85206 100644 --- a/src/gui/src/Action.h +++ b/src/gui/src/Action.h @@ -35,7 +35,8 @@ class Action public: enum ActionType { keyDown, keyUp, keystroke, switchToScreen, toggleScreen, switchInDirection, - lockCursorToScreen, mouseDown, mouseUp, mousebutton }; + lockCursorToScreen, userScript, + mouseDown, mouseUp, mousebutton }; enum SwitchDirection { switchLeft, switchRight, switchUp, switchDown }; enum LockCursorMode { lockCursorToggle, lockCursonOn, lockCursorOff }; @@ -72,11 +73,15 @@ class Action bool haveScreens() const { return m_HasScreens; } void setHaveScreens(bool b) { m_HasScreens = b; } + const QString& userScriptCommand() const { return m_UserScriptCommand; } + void setUserScriptCommand(const QString& n) { m_UserScriptCommand = n; } + private: KeySequence m_KeySequence; int m_Type; QStringList m_TypeScreenNames; QString m_SwitchScreenName; + QString m_UserScriptCommand; int m_SwitchDirection; int m_LockCursorMode; bool m_ActiveOnRelease; diff --git a/src/gui/src/ActionDialog.cpp b/src/gui/src/ActionDialog.cpp index 89a037e3..493a5aba 100644 --- a/src/gui/src/ActionDialog.cpp +++ b/src/gui/src/ActionDialog.cpp @@ -39,7 +39,7 @@ ActionDialog::ActionDialog(QWidget* parent, ServerConfig& config, Hotkey& hotkey // work around Qt Designer's lack of a QButtonGroup; we need it to get // at the button id of the checked radio button - QRadioButton* const typeButtons[] = { m_pRadioPress, m_pRadioRelease, m_pRadioPressAndRelease, m_pRadioSwitchToScreen, m_pRadioToggleScreen, m_pRadioSwitchInDirection, m_pRadioLockCursorToScreen }; + QRadioButton* const typeButtons[] = { m_pRadioPress, m_pRadioRelease, m_pRadioPressAndRelease, m_pRadioSwitchToScreen, m_pRadioToggleScreen, m_pRadioSwitchInDirection, m_pRadioLockCursorToScreen, m_pRadioUserScript }; for (unsigned int i = 0; i < sizeof(typeButtons) / sizeof(typeButtons[0]); i++) m_pButtonGroupType->addButton(typeButtons[i], i); @@ -49,6 +49,7 @@ ActionDialog::ActionDialog(QWidget* parent, ServerConfig& config, Hotkey& hotkey m_pButtonGroupType->button(m_Action.type())->setChecked(true); m_pComboSwitchInDirection->setCurrentIndex(m_Action.switchDirection()); m_pComboLockCursorToScreen->setCurrentIndex(m_Action.lockCursorMode()); + m_pUserScriptCommand->setText(m_Action.userScriptCommand()); if (m_Action.activeOnRelease()) m_pRadioHotkeyReleased->setChecked(true); @@ -93,6 +94,7 @@ void ActionDialog::accept() m_Action.setSwitchDirection(m_pComboSwitchInDirection->currentIndex()); m_Action.setLockCursorMode(m_pComboLockCursorToScreen->currentIndex()); m_Action.setActiveOnRelease(m_pRadioHotkeyReleased->isChecked()); + m_Action.setUserScriptCommand(m_pUserScriptCommand->text()); QDialog::accept(); } diff --git a/src/gui/src/ActionDialogBase.ui b/src/gui/src/ActionDialogBase.ui index 9c6ad0a0..1113b2bf 100644 --- a/src/gui/src/ActionDialogBase.ui +++ b/src/gui/src/ActionDialogBase.ui @@ -7,7 +7,7 @@ 0 0 372 - 484 + 508 @@ -250,6 +250,37 @@ + + + + + + User Script + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + script1 + + + + + @@ -588,5 +619,53 @@ + + m_pRadioUserScript + toggled(bool) + m_pUserScriptCommand + setEnabled(bool) + + + 63 + 385 + + + 291 + 385 + + + + + m_pRadioUserScript + toggled(bool) + m_pKeySequenceWidgetHotkey + setDisabled(bool) + + + 63 + 385 + + + 185 + 118 + + + + + m_pRadioUserScript + toggled(bool) + m_pGroupBoxScreens + setDisabled(bool) + + + 63 + 385 + + + 185 + 189 + + + diff --git a/src/lib/server/Config.cpp b/src/lib/server/Config.cpp index bcdb88cd..0c30bed8 100644 --- a/src/lib/server/Config.cpp +++ b/src/lib/server/Config.cpp @@ -1244,6 +1244,20 @@ void Config::parseAction(ConfigReadContext& s, const std::string& name, action = new InputFilter::KeyboardBroadcastAction(m_events, mode, screens); } + else if (name == "userScript") { + if (args.size() != 1) { + throw XConfigRead(s, "syntax for action: userScript(scriptCommand)"); + } + + std::string scriptCommand = args[0]; + + if (scriptCommand.empty()) { + throw XConfigRead(s, "bad script command in userScript"); + } + + action = new InputFilter::UserScriptAction(m_events, scriptCommand); + } + else { throw XConfigRead(s, "unknown action argument \"%{1}\"", name); } diff --git a/src/lib/server/InputFilter.cpp b/src/lib/server/InputFilter.cpp index a0dce17c..872bb0b7 100644 --- a/src/lib/server/InputFilter.cpp +++ b/src/lib/server/InputFilter.cpp @@ -660,6 +660,53 @@ InputFilter::MouseButtonAction::formatName() const return (m_press ? "mouseDown" : "mouseUp"); } + +InputFilter::UserScriptAction::UserScriptAction(IEventQueue* events, + const std::string& scriptCommand) : + m_scriptCommand(scriptCommand), + m_events(events) +{ + // do nothing +} + +std::string InputFilter::UserScriptAction::getScriptCommand() const +{ + return m_scriptCommand; +} + +InputFilter::Action* +InputFilter::UserScriptAction::clone() const +{ + return new UserScriptAction(*this); +} + +std::string InputFilter::UserScriptAction::format() const +{ + return barrier::string::sprintf("userScript(%s)", m_scriptCommand.c_str()); +} + +void +InputFilter::UserScriptAction::perform(const Event& event) +{ + // pick screen name. if m_screen is empty then use the screen from + // event if it has one. + std::string scriptCommand = m_scriptCommand; + if (scriptCommand.empty()) { + LOG((CLOG_ERR "script ID empty")); + return; + } + + // exec script +#if !defined(_WIN32) + std::string s = barrier::string::sprintf(R"(sh -c '%s')", scriptCommand.c_str()); +#else + std::string s = barrier::string::sprintf(R"(cmd.exe /C "%s")", scriptCommand.c_str()); + +#endif + LOG((CLOG_DEBUG "%s",s.c_str())); + system(s.c_str()); +} + // // InputFilter::Rule // diff --git a/src/lib/server/InputFilter.h b/src/lib/server/InputFilter.h index 5e6ef9cf..5a730004 100644 --- a/src/lib/server/InputFilter.h +++ b/src/lib/server/InputFilter.h @@ -270,6 +270,23 @@ public: IEventQueue* m_events; }; + // UserScriptAction + class UserScriptAction : public Action { + public: + UserScriptAction(IEventQueue* events, const std::string& scriptCommand); + + std::string getScriptCommand() const; + + // Action overrides + virtual Action* clone() const; + virtual String format() const; + virtual void perform(const Event&); + + private: + std::string m_scriptCommand; + IEventQueue* m_events; + }; + class Rule { public: Rule();