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();