diff --git a/src/gui/src/Action.cpp b/src/gui/src/Action.cpp
index f34d1e8f..5184099c 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/gui/src/AppConfig.cpp b/src/gui/src/AppConfig.cpp
index 63943267..e320ce5f 100644
--- a/src/gui/src/AppConfig.cpp
+++ b/src/gui/src/AppConfig.cpp
@@ -61,7 +61,8 @@ AppConfig::AppConfig(QSettings* settings) :
m_CryptoEnabled(false),
m_AutoHide(false),
m_AutoStart(false),
- m_MinimizeToTray(false)
+ m_MinimizeToTray(false),
+ m_HeadlessMode(false)
{
Q_ASSERT(m_pSettings);
@@ -161,6 +162,7 @@ void AppConfig::loadSettings()
m_AutoHide = settings().value("autoHide", false).toBool();
m_AutoStart = settings().value("autoStart", false).toBool();
m_MinimizeToTray = settings().value("minimizeToTray", false).toBool();
+ m_HeadlessMode = settings().value("headlessMode", false).toBool();
}
void AppConfig::saveSettings()
@@ -184,6 +186,7 @@ void AppConfig::saveSettings()
settings().setValue("autoHide", m_AutoHide);
settings().setValue("autoStart", m_AutoStart);
settings().setValue("minimizeToTray", m_MinimizeToTray);
+ settings().setValue("headlessMode", m_HeadlessMode);
settings().sync();
}
@@ -236,3 +239,7 @@ bool AppConfig::getAutoStart() { return m_AutoStart; }
void AppConfig::setMinimizeToTray(bool b) { m_MinimizeToTray = b; }
bool AppConfig::getMinimizeToTray() { return m_MinimizeToTray; }
+
+void AppConfig::setHeadlessMode(bool b) { m_HeadlessMode = b; }
+
+bool AppConfig::getHeadlessMode() { return m_HeadlessMode; }
diff --git a/src/gui/src/AppConfig.h b/src/gui/src/AppConfig.h
index 124ee85f..4561153e 100644
--- a/src/gui/src/AppConfig.h
+++ b/src/gui/src/AppConfig.h
@@ -100,6 +100,9 @@ class AppConfig: public QObject
void setMinimizeToTray(bool b);
bool getMinimizeToTray();
+ void setHeadlessMode(bool b);
+ bool getHeadlessMode();
+
void saveSettings();
protected:
@@ -135,6 +138,7 @@ protected:
bool m_AutoHide;
bool m_AutoStart;
bool m_MinimizeToTray;
+ bool m_HeadlessMode;
static const char m_BarriersName[];
static const char m_BarriercName[];
diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp
index 40050782..b353d54c 100644
--- a/src/gui/src/MainWindow.cpp
+++ b/src/gui/src/MainWindow.cpp
@@ -520,6 +520,9 @@ void MainWindow::startBarrier()
args << "--enable-crypto";
}
+ if (m_AppConfig->getHeadlessMode()) {
+ args << "--headless-mode";
+ }
#if defined(Q_OS_WIN)
// on windows, the profile directory changes depending on the user that
// launched the process (e.g. when launched with elevation). setting the
diff --git a/src/gui/src/SettingsDialog.cpp b/src/gui/src/SettingsDialog.cpp
index 1caeae5d..0e37afbc 100644
--- a/src/gui/src/SettingsDialog.cpp
+++ b/src/gui/src/SettingsDialog.cpp
@@ -51,6 +51,7 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
m_pCheckBoxAutoStart->setChecked(appConfig().getAutoStart());
m_pCheckBoxMinimizeToTray->setChecked(appConfig().getMinimizeToTray());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled());
+ m_pCheckBoxHeadlessMode->setChecked(m_appConfig.getHeadlessMode());
#if defined(Q_OS_WIN)
m_pComboElevate->setCurrentIndex(static_cast(appConfig().elevateMode()));
@@ -75,6 +76,7 @@ void SettingsDialog::accept()
m_appConfig.setAutoHide(m_pCheckBoxAutoHide->isChecked());
m_appConfig.setAutoStart(m_pCheckBoxAutoStart->isChecked());
m_appConfig.setMinimizeToTray(m_pCheckBoxMinimizeToTray->isChecked());
+ m_appConfig.setHeadlessMode(m_pCheckBoxHeadlessMode->isChecked());
m_appConfig.saveSettings();
QDialog::accept();
}
diff --git a/src/gui/src/SettingsDialogBase.ui b/src/gui/src/SettingsDialogBase.ui
index 719a84bc..d250d3cc 100644
--- a/src/gui/src/SettingsDialogBase.ui
+++ b/src/gui/src/SettingsDialogBase.ui
@@ -7,7 +7,7 @@
0
0
368
- 428
+ 454
@@ -133,6 +133,13 @@
+ -
+
+
+ Headless &mode
+
+
+
diff --git a/src/lib/barrier/App.cpp b/src/lib/barrier/App.cpp
index f0aea6a5..97a20b9f 100644
--- a/src/lib/barrier/App.cpp
+++ b/src/lib/barrier/App.cpp
@@ -114,6 +114,9 @@ App::run(int argc, char** argv)
// using the exit(int) function!
result = e.getCode();
}
+ catch (std::runtime_error& re) {
+ LOG((CLOG_CRIT "A runtime error occurred: %s\n", re.what()));
+ }
catch (std::exception& e) {
LOG((CLOG_CRIT "An error occurred: %s\n", e.what()));
}
diff --git a/src/lib/barrier/App.h b/src/lib/barrier/App.h
index 749ca85d..a4146189 100644
--- a/src/lib/barrier/App.h
+++ b/src/lib/barrier/App.h
@@ -168,7 +168,10 @@ private:
" --enable-drag-drop enable file drag & drop.\n" \
" --enable-crypto enable the crypto (ssl) plugin.\n" \
" --profile-dir use named profile directory instead.\n" \
- " --drop-dir use named drop target directory instead.\n"
+ " --drop-dir use named drop target directory instead.\n" \
+ " --headless-mode when any client connected, if server screen is\n" \
+ " holding the input focus, server will actively\n" \
+ " switch input focus to the client.\n"
#define HELP_COMMON_INFO_2 \
" -h, --help display this help and exit.\n" \
diff --git a/src/lib/barrier/ArgParser.cpp b/src/lib/barrier/ArgParser.cpp
index 1ac4baff..28d6c04d 100644
--- a/src/lib/barrier/ArgParser.cpp
+++ b/src/lib/barrier/ArgParser.cpp
@@ -290,6 +290,9 @@ ArgParser::parseGenericArgs(int argc, const char* const* argv, int& i)
else if (isArg(i, argc, argv, NULL, "--plugin-dir", 1)) {
argsBase().m_pluginDirectory = argv[++i];
}
+ else if (isArg(i, argc, argv, NULL, "--headless-mode")) {
+ argsBase().m_headlessMode = true;
+ }
else {
// option not supported here
return false;
diff --git a/src/lib/barrier/ArgsBase.cpp b/src/lib/barrier/ArgsBase.cpp
index dd983c6f..ee9c9356 100644
--- a/src/lib/barrier/ArgsBase.cpp
+++ b/src/lib/barrier/ArgsBase.cpp
@@ -44,7 +44,8 @@ m_shouldExit(false),
m_barrierAddress(),
m_enableCrypto(false),
m_profileDirectory(""),
-m_pluginDirectory("")
+m_pluginDirectory(""),
+m_headlessMode(false)
{
}
diff --git a/src/lib/barrier/ArgsBase.h b/src/lib/barrier/ArgsBase.h
index ad442dc9..4e32f481 100644
--- a/src/lib/barrier/ArgsBase.h
+++ b/src/lib/barrier/ArgsBase.h
@@ -52,4 +52,5 @@ public:
bool m_enableCrypto;
String m_profileDirectory;
String m_pluginDirectory;
+ bool m_headlessMode;
};
diff --git a/src/lib/barrier/ClientApp.cpp b/src/lib/barrier/ClientApp.cpp
index ec687e1e..190f3312 100644
--- a/src/lib/barrier/ClientApp.cpp
+++ b/src/lib/barrier/ClientApp.cpp
@@ -164,7 +164,7 @@ ClientApp::createScreen()
{
#if WINAPI_MSWINDOWS
return new barrier::Screen(new MSWindowsScreen(
- false, args().m_noHooks, args().m_stopOnDeskSwitch, m_events), m_events);
+ false, args().m_noHooks, args().m_stopOnDeskSwitch, args().m_headlessMode, m_events), m_events);
#elif WINAPI_XWINDOWS
return new barrier::Screen(new XWindowsScreen(
new XWindowsImpl(),
diff --git a/src/lib/barrier/IKeyState.cpp b/src/lib/barrier/IKeyState.cpp
index e89c0e9d..cd2aa44c 100644
--- a/src/lib/barrier/IKeyState.cpp
+++ b/src/lib/barrier/IKeyState.cpp
@@ -62,21 +62,21 @@ IKeyState::KeyInfo::alloc(KeyID id,
info->m_button = button;
info->m_count = count;
info->m_screens = info->m_screensBuffer;
- strcpy(info->m_screensBuffer, screens.c_str());
+ strcpy(info->m_screensBuffer, screens.c_str()); // Compliant: String type is safe
return info;
}
IKeyState::KeyInfo*
IKeyState::KeyInfo::alloc(const KeyInfo& x)
{
- KeyInfo* info = (KeyInfo*)malloc(sizeof(KeyInfo) +
- strlen(x.m_screensBuffer));
+ auto bufferLen = strnlen(x.m_screensBuffer, SIZE_MAX);
+ auto info = (KeyInfo*)malloc(sizeof(KeyInfo) + bufferLen);
info->m_key = x.m_key;
info->m_mask = x.m_mask;
info->m_button = x.m_button;
info->m_count = x.m_count;
info->m_screens = x.m_screens ? info->m_screensBuffer : NULL;
- strcpy(info->m_screensBuffer, x.m_screensBuffer);
+ memcpy(info->m_screensBuffer, x.m_screensBuffer, bufferLen + 1);
return info;
}
diff --git a/src/lib/barrier/ProtocolUtil.cpp b/src/lib/barrier/ProtocolUtil.cpp
index 6e67b1b6..4b43d604 100644
--- a/src/lib/barrier/ProtocolUtil.cpp
+++ b/src/lib/barrier/ProtocolUtil.cpp
@@ -62,6 +62,9 @@ ProtocolUtil::readf(barrier::IStream* stream, const char* fmt, ...)
catch (XIO&) {
result = false;
}
+ catch (const std::bad_alloc&) {
+ result = false;
+ }
va_end(args);
return result;
}
@@ -79,18 +82,17 @@ ProtocolUtil::vwritef(barrier::IStream* stream,
}
// fill buffer
- UInt8* buffer = new UInt8[size];
- writef_void(buffer, fmt, args);
+ std::vector buffer;
+ buffer.reserve(size);
+ writef_void(buffer.data(), fmt, args);
try {
// write buffer
- stream->write(buffer, size);
+ stream->write(buffer.data(), size);
LOG((CLOG_DEBUG2 "wrote %d bytes", size));
-
- delete[] buffer;
}
- catch (XBase&) {
- delete[] buffer;
+ catch (const XBase& exception) {
+ LOG((CLOG_DEBUG2 "Exception <%s> during wrote %d bytes into stream", exception.what(), size));
throw;
}
}
diff --git a/src/lib/barrier/ServerApp.cpp b/src/lib/barrier/ServerApp.cpp
index 599bde70..b3d43887 100644
--- a/src/lib/barrier/ServerApp.cpp
+++ b/src/lib/barrier/ServerApp.cpp
@@ -267,6 +267,18 @@ ServerApp::handleClientConnected(const Event&, void* vlistener)
if (client != NULL) {
m_server->adoptClient(client);
updateStatus();
+ if( args().m_headlessMode && m_server->isServerHoldFocus() ) {
+ std::string screen = args().m_config->getCanonicalName(client->getName());
+ if (screen.empty()) {
+ screen = client->getName();
+ }
+ if(screen.empty()) return;
+ // send event
+ Server::SwitchToScreenInfo* info =
+ Server::SwitchToScreenInfo::alloc(screen);
+ m_events->addEvent(Event(m_events->forServer().switchToScreen(),
+ args().m_config->getInputFilter(), info));
+ }
}
}
@@ -604,7 +616,7 @@ ServerApp::createScreen()
{
#if WINAPI_MSWINDOWS
return new barrier::Screen(new MSWindowsScreen(
- true, args().m_noHooks, args().m_stopOnDeskSwitch, m_events), m_events);
+ true, args().m_noHooks, args().m_stopOnDeskSwitch, args().m_headlessMode, m_events), m_events);
#elif WINAPI_XWINDOWS
return new barrier::Screen(new XWindowsScreen(
new XWindowsImpl(),
diff --git a/src/lib/client/Client.cpp b/src/lib/client/Client.cpp
index b0dbbc37..18bd1a82 100644
--- a/src/lib/client/Client.cpp
+++ b/src/lib/client/Client.cpp
@@ -240,7 +240,8 @@ void
Client::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool)
{
m_active = true;
- m_screen->mouseMove(xAbs, yAbs);
+ if (!m_args.m_headlessMode)
+ m_screen->mouseMove(xAbs, yAbs);
m_screen->enter(mask);
if (m_sendFileThread != NULL) {
@@ -515,7 +516,7 @@ Client::setupTimer()
{
assert(m_timer == NULL);
- m_timer = m_events->newOneShotTimer(15.0, NULL);
+ m_timer = m_events->newOneShotTimer(2.0, NULL);
m_events->adoptHandler(Event::kTimer, m_timer,
new TMethodEventJob(this,
&Client::handleConnectTimeout));
diff --git a/src/lib/platform/MSWindowsDesks.cpp b/src/lib/platform/MSWindowsDesks.cpp
index 848ded78..81308cce 100644
--- a/src/lib/platform/MSWindowsDesks.cpp
+++ b/src/lib/platform/MSWindowsDesks.cpp
@@ -100,7 +100,7 @@
MSWindowsDesks::MSWindowsDesks(
bool isPrimary, bool noHooks,
const IScreenSaver* screensaver, IEventQueue* events,
- IJob* updateKeys, bool stopOnDeskSwitch) :
+ IJob* updateKeys, bool stopOnDeskSwitch, bool headlessMode) :
m_isPrimary(isPrimary),
m_noHooks(noHooks),
m_isOnScreen(m_isPrimary),
@@ -117,7 +117,8 @@ MSWindowsDesks::MSWindowsDesks(
m_deskReady(&m_mutex, false),
m_updateKeys(updateKeys),
m_events(events),
- m_stopOnDeskSwitch(stopOnDeskSwitch)
+ m_stopOnDeskSwitch(stopOnDeskSwitch),
+ m_headlessMode(headlessMode)
{
m_cursor = createBlankCursor();
m_deskClass = createDeskWindowClass(m_isPrimary);
@@ -596,9 +597,11 @@ MSWindowsDesks::deskLeave(Desk* desk, HKL keyLayout)
// we aren't notified when the mouse leaves our window.
SetCapture(desk->m_window);
- // warp the mouse to the cursor center
- LOG((CLOG_DEBUG2 "warping cursor to center: %+d,%+d", m_xCenter, m_yCenter));
- deskMouseMove(m_xCenter, m_yCenter);
+ if (!m_headlessMode) {
+ // warp the mouse to the cursor center
+ LOG((CLOG_DEBUG2 "warping cursor to center: %+d,%+d", m_xCenter, m_yCenter));
+ deskMouseMove(m_xCenter, m_yCenter);
+ }
}
}
diff --git a/src/lib/platform/MSWindowsDesks.h b/src/lib/platform/MSWindowsDesks.h
index 65d93ef5..3c988048 100644
--- a/src/lib/platform/MSWindowsDesks.h
+++ b/src/lib/platform/MSWindowsDesks.h
@@ -68,7 +68,7 @@ public:
MSWindowsDesks(
bool isPrimary, bool noHooks,
const IScreenSaver* screensaver, IEventQueue* events,
- IJob* updateKeys, bool stopOnDeskSwitch);
+ IJob* updateKeys, bool stopOnDeskSwitch, bool headlessMode);
~MSWindowsDesks();
//! @name manipulators
@@ -294,4 +294,6 @@ private:
// true if program should stop on desk switch.
bool m_stopOnDeskSwitch;
+
+ bool m_headlessMode;
};
diff --git a/src/lib/platform/MSWindowsScreen.cpp b/src/lib/platform/MSWindowsScreen.cpp
index 2449ba7c..d09e03e5 100644
--- a/src/lib/platform/MSWindowsScreen.cpp
+++ b/src/lib/platform/MSWindowsScreen.cpp
@@ -93,6 +93,7 @@ MSWindowsScreen::MSWindowsScreen(
bool isPrimary,
bool noHooks,
bool stopOnDeskSwitch,
+ bool headlessMode,
IEventQueue* events) :
PlatformScreen(events),
m_isPrimary(isPrimary),
@@ -136,7 +137,8 @@ MSWindowsScreen::MSWindowsScreen(
m_events,
new TMethodJob(
this, &MSWindowsScreen::updateKeysCB),
- stopOnDeskSwitch);
+ stopOnDeskSwitch,
+ headlessMode);
m_keyState = new MSWindowsKeyState(m_desks, getEventTarget(), m_events);
updateScreenShape();
@@ -311,6 +313,13 @@ MSWindowsScreen::enter()
bool
MSWindowsScreen::leave()
{
+ POINT pos;
+ if (!getThisCursorPos(&pos))
+ {
+ LOG((CLOG_DEBUG "Unable to leave screen as Windows security has disabled critical functions required to let barrier work"));
+ //unable to get position this means barrier will break if the cursor leaves the screen
+ return false;
+ }
// get keyboard layout of foreground window. we'll use this
// keyboard layout for translating keys sent to clients.
HWND window = GetForegroundWindow();
@@ -521,6 +530,60 @@ MSWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const
m_desks->getCursorPos(x, y);
}
+/*
+ * getThisCursorPos and setThisCursorPos will attempt to negotiate with the system
+ * to try get the and set the mouse position, however on the logon screen due to
+ * hooks this process has it may unable to work around the problem. Although these
+ * functions did not fix the issue at hand (#5294) its worth keeping them here anyway.
+ */
+bool MSWindowsScreen::getThisCursorPos(LPPOINT pos)
+{
+ auto result = GetCursorPos(pos);
+ auto error = GetLastError();
+ LOG((CLOG_DEBUG3 "%s Attempt: 1 , status %d, code: %d Pos {%d, %d}", __func__, result, error, pos->x, pos->y));
+ if (!result)
+ {
+ result = GetCursorPos(pos);
+ error = GetLastError();
+ LOG((CLOG_DEBUG3 "%s Attempt: 2, status %d, code: %d Pos {%d, %d}", __func__, result, error, pos->x, pos->y));
+ updateDesktopThread();
+ }
+ return result;
+}
+
+bool MSWindowsScreen::setThisCursorPos(int x, int y)
+{
+ auto result = SetCursorPos(x, y);
+ auto error = GetLastError();
+ LOG((CLOG_DEBUG3 "%s Attempt: 1, status %d, code: %d", __func__, result, error));
+ if (!result)
+ {
+ result = SetCursorPos(x, y);
+ error = GetLastError();
+ LOG((CLOG_DEBUG3 "%s Attempt: 2, status %d, code: %d", __func__, result, error));
+ updateDesktopThread();
+ }
+
+ return result;
+}
+
+void MSWindowsScreen::updateDesktopThread()
+{
+
+ LOG((CLOG_DEBUG3 "Failed to set cursor Attempting to switch desktop"));
+ SetLastError(0);
+ HDESK cur_hdesk = OpenInputDesktop(0, true, GENERIC_ALL);
+
+ auto error = GetLastError();
+ LOG((CLOG_DEBUG3 "\tGetting desktop Handle: %p Status code: %d", cur_hdesk, error));
+
+ error = GetLastError();
+ LOG((CLOG_DEBUG3 "\tSetting desktop return: %d Status code: %d", SetThreadDesktop(cur_hdesk), GetLastError()));
+
+ CloseDesktop(cur_hdesk);
+
+}
+
void
MSWindowsScreen::reconfigure(UInt32 activeSides)
{
@@ -1505,11 +1568,11 @@ MSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y)
// warp mouse. hopefully this inserts a mouse motion event
// between the previous message and the following message.
- SetCursorPos(x, y);
+ setThisCursorPos(x, y);
// check to see if the mouse pos was set correctly
POINT cursorPos;
- GetCursorPos(&cursorPos);
+ getThisCursorPos(&cursorPos);
// there is a bug or round error in SetCursorPos and GetCursorPos on
// a high DPI setting. The check here is for Vista/7 login screen.
diff --git a/src/lib/platform/MSWindowsScreen.h b/src/lib/platform/MSWindowsScreen.h
index ae53f1ad..ad134182 100644
--- a/src/lib/platform/MSWindowsScreen.h
+++ b/src/lib/platform/MSWindowsScreen.h
@@ -44,6 +44,7 @@ public:
bool isPrimary,
bool noHooks,
bool stopOnDeskSwitch,
+ bool headlessMode,
IEventQueue* events);
virtual ~MSWindowsScreen();
@@ -76,6 +77,25 @@ public:
SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
+ /**
+ * \brief Get the position of the cursor on the current machine
+ * \param pos the object that the function will use to store the position of the cursor
+ * \return true if the function was successful
+ */
+ virtual bool getThisCursorPos(LPPOINT pos);
+ /**
+ * \brief Sets the cursor position on the current machine
+ * \param x The x coordinate of the cursor
+ * \param y The Y coordinate of the cursor
+ * \return True is successful
+ */
+ virtual bool setThisCursorPos(int x, int y);
+
+ /**
+ * \brief This function will attempt to switch to the current desktop the mouse is located on
+ */
+ virtual void updateDesktopThread();
+
// IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y);
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..c8dd8d9d 100644
--- a/src/lib/server/InputFilter.cpp
+++ b/src/lib/server/InputFilter.cpp
@@ -558,7 +558,7 @@ std::string InputFilter::KeystrokeAction::format() const
return barrier::string::sprintf("%s(%s,%.*s)", type,
barrier::KeyMap::formatKey(m_keyInfo->m_key,
m_keyInfo->m_mask).c_str(),
- strlen(m_keyInfo->m_screens + 1) - 1,
+ strnlen(m_keyInfo->m_screens + 1, SIZE_MAX) - 1,
m_keyInfo->m_screens + 1);
}
}
@@ -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();
diff --git a/src/lib/server/Server.cpp b/src/lib/server/Server.cpp
index 2eff0029..c4ad92dc 100644
--- a/src/lib/server/Server.cpp
+++ b/src/lib/server/Server.cpp
@@ -2338,7 +2338,7 @@ Server::SwitchToScreenInfo::alloc(const std::string& screen)
SwitchToScreenInfo* info =
(SwitchToScreenInfo*)malloc(sizeof(SwitchToScreenInfo) +
screen.size());
- strcpy(info->m_screen, screen.c_str());
+ strcpy(info->m_screen, screen.c_str()); // Compliant: we made sure the buffer is large enough
return info;
}
@@ -2377,7 +2377,7 @@ Server::KeyboardBroadcastInfo::alloc(State state, const std::string& screens)
(KeyboardBroadcastInfo*)malloc(sizeof(KeyboardBroadcastInfo) +
screens.size());
info->m_state = state;
- strcpy(info->m_screens, screens.c_str());
+ strcpy(info->m_screens, screens.c_str()); // Compliant: we made sure that screens variable ended with null
return info;
}
diff --git a/src/lib/server/Server.h b/src/lib/server/Server.h
index cb71ec3d..bf5087f8 100644
--- a/src/lib/server/Server.h
+++ b/src/lib/server/Server.h
@@ -179,6 +179,10 @@ public:
//! Return fake drag file list
DragFileList getFakeDragFileList() { return m_fakeDragFileList; }
+ //! Return true if fucus in primary clinet
+ bool isServerHoldFocus() { return (m_active ==
+ (BaseClientProxy*) m_primaryClient); }
+
//@}
private:
diff --git a/src/test/integtests/platform/MSWindowsKeyStateTests.cpp b/src/test/integtests/platform/MSWindowsKeyStateTests.cpp
index 79935d89..404bbb1c 100644
--- a/src/test/integtests/platform/MSWindowsKeyStateTests.cpp
+++ b/src/test/integtests/platform/MSWindowsKeyStateTests.cpp
@@ -53,7 +53,7 @@ protected:
return new MSWindowsDesks(
true, false, m_screensaver, eventQueue,
new TMethodJob(
- this, &MSWindowsKeyStateTests::updateKeysCB), false);
+ this, &MSWindowsKeyStateTests::updateKeysCB), false, false);
}
void* getEventTarget() const