This commit is contained in:
lededev 2021-10-30 18:01:11 -04:00 committed by GitHub
commit 6917c58b49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 350 additions and 36 deletions

View File

@ -26,7 +26,8 @@ const char* Action::m_ActionTypeNames[] =
"keyDown", "keyUp", "keystroke", "keyDown", "keyUp", "keystroke",
"switchToScreen", "toggleScreen", "switchToScreen", "toggleScreen",
"switchInDirection", "lockCursorToScreen", "switchInDirection", "lockCursorToScreen",
"mouseDown", "mouseUp", "mousebutton" "userScript",
"mouseDown", "mouseUp", "mousebutton",
}; };
const char* Action::m_SwitchDirectionNames[] = { "left", "right", "up", "down" }; const char* Action::m_SwitchDirectionNames[] = { "left", "right", "up", "down" };
@ -37,6 +38,7 @@ Action::Action() :
m_Type(keystroke), m_Type(keystroke),
m_TypeScreenNames(), m_TypeScreenNames(),
m_SwitchScreenName(), m_SwitchScreenName(),
m_UserScriptCommand(),
m_SwitchDirection(switchLeft), m_SwitchDirection(switchLeft),
m_LockCursorMode(lockCursorToggle), m_LockCursorMode(lockCursorToggle),
m_ActiveOnRelease(false), m_ActiveOnRelease(false),
@ -105,6 +107,11 @@ QString Action::text() const
text += ")"; text += ")";
break; break;
case userScript:
text += "(";
text += userScriptCommand();
text += ")";
break;
default: default:
Q_ASSERT(0); Q_ASSERT(0);
break; break;
@ -133,6 +140,7 @@ void Action::loadSettings(QSettings& settings)
setLockCursorMode(settings.value("lockCursorToScreen", lockCursorToggle).toInt()); setLockCursorMode(settings.value("lockCursorToScreen", lockCursorToggle).toInt());
setActiveOnRelease(settings.value("activeOnRelease", false).toBool()); setActiveOnRelease(settings.value("activeOnRelease", false).toBool());
setHaveScreens(settings.value("hasScreens", false).toBool()); setHaveScreens(settings.value("hasScreens", false).toBool());
setUserScriptCommand(settings.value("userScriptCommand").toString());
} }
void Action::saveSettings(QSettings& settings) const void Action::saveSettings(QSettings& settings) const
@ -153,6 +161,7 @@ void Action::saveSettings(QSettings& settings) const
settings.setValue("lockCursorToScreen", lockCursorMode()); settings.setValue("lockCursorToScreen", lockCursorMode());
settings.setValue("activeOnRelease", activeOnRelease()); settings.setValue("activeOnRelease", activeOnRelease());
settings.setValue("hasScreens", haveScreens()); settings.setValue("hasScreens", haveScreens());
settings.setValue("userScriptCommand", userScriptCommand());
} }
QTextStream& operator<<(QTextStream& outStream, const Action& action) QTextStream& operator<<(QTextStream& outStream, const Action& action)

View File

@ -35,7 +35,8 @@ class Action
public: public:
enum ActionType { keyDown, keyUp, keystroke, enum ActionType { keyDown, keyUp, keystroke,
switchToScreen, toggleScreen, switchInDirection, switchToScreen, toggleScreen, switchInDirection,
lockCursorToScreen, mouseDown, mouseUp, mousebutton }; lockCursorToScreen, userScript,
mouseDown, mouseUp, mousebutton };
enum SwitchDirection { switchLeft, switchRight, switchUp, switchDown }; enum SwitchDirection { switchLeft, switchRight, switchUp, switchDown };
enum LockCursorMode { lockCursorToggle, lockCursonOn, lockCursorOff }; enum LockCursorMode { lockCursorToggle, lockCursonOn, lockCursorOff };
@ -72,11 +73,15 @@ class Action
bool haveScreens() const { return m_HasScreens; } bool haveScreens() const { return m_HasScreens; }
void setHaveScreens(bool b) { m_HasScreens = b; } void setHaveScreens(bool b) { m_HasScreens = b; }
const QString& userScriptCommand() const { return m_UserScriptCommand; }
void setUserScriptCommand(const QString& n) { m_UserScriptCommand = n; }
private: private:
KeySequence m_KeySequence; KeySequence m_KeySequence;
int m_Type; int m_Type;
QStringList m_TypeScreenNames; QStringList m_TypeScreenNames;
QString m_SwitchScreenName; QString m_SwitchScreenName;
QString m_UserScriptCommand;
int m_SwitchDirection; int m_SwitchDirection;
int m_LockCursorMode; int m_LockCursorMode;
bool m_ActiveOnRelease; bool m_ActiveOnRelease;

View File

@ -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 // work around Qt Designer's lack of a QButtonGroup; we need it to get
// at the button id of the checked radio button // 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++) for (unsigned int i = 0; i < sizeof(typeButtons) / sizeof(typeButtons[0]); i++)
m_pButtonGroupType->addButton(typeButtons[i], 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_pButtonGroupType->button(m_Action.type())->setChecked(true);
m_pComboSwitchInDirection->setCurrentIndex(m_Action.switchDirection()); m_pComboSwitchInDirection->setCurrentIndex(m_Action.switchDirection());
m_pComboLockCursorToScreen->setCurrentIndex(m_Action.lockCursorMode()); m_pComboLockCursorToScreen->setCurrentIndex(m_Action.lockCursorMode());
m_pUserScriptCommand->setText(m_Action.userScriptCommand());
if (m_Action.activeOnRelease()) if (m_Action.activeOnRelease())
m_pRadioHotkeyReleased->setChecked(true); m_pRadioHotkeyReleased->setChecked(true);
@ -93,6 +94,7 @@ void ActionDialog::accept()
m_Action.setSwitchDirection(m_pComboSwitchInDirection->currentIndex()); m_Action.setSwitchDirection(m_pComboSwitchInDirection->currentIndex());
m_Action.setLockCursorMode(m_pComboLockCursorToScreen->currentIndex()); m_Action.setLockCursorMode(m_pComboLockCursorToScreen->currentIndex());
m_Action.setActiveOnRelease(m_pRadioHotkeyReleased->isChecked()); m_Action.setActiveOnRelease(m_pRadioHotkeyReleased->isChecked());
m_Action.setUserScriptCommand(m_pUserScriptCommand->text());
QDialog::accept(); QDialog::accept();
} }

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>372</width> <width>372</width>
<height>484</height> <height>508</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -250,6 +250,37 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QRadioButton" name="m_pRadioUserScript">
<property name="text">
<string>User Script</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="m_pUserScriptCommand">
<property name="text">
<string>script1</string>
</property>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -588,5 +619,53 @@
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>m_pRadioUserScript</sender>
<signal>toggled(bool)</signal>
<receiver>m_pUserScriptCommand</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>63</x>
<y>385</y>
</hint>
<hint type="destinationlabel">
<x>291</x>
<y>385</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_pRadioUserScript</sender>
<signal>toggled(bool)</signal>
<receiver>m_pKeySequenceWidgetHotkey</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>63</x>
<y>385</y>
</hint>
<hint type="destinationlabel">
<x>185</x>
<y>118</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_pRadioUserScript</sender>
<signal>toggled(bool)</signal>
<receiver>m_pGroupBoxScreens</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>63</x>
<y>385</y>
</hint>
<hint type="destinationlabel">
<x>185</x>
<y>189</y>
</hint>
</hints>
</connection>
</connections> </connections>
</ui> </ui>

View File

@ -61,7 +61,8 @@ AppConfig::AppConfig(QSettings* settings) :
m_CryptoEnabled(false), m_CryptoEnabled(false),
m_AutoHide(false), m_AutoHide(false),
m_AutoStart(false), m_AutoStart(false),
m_MinimizeToTray(false) m_MinimizeToTray(false),
m_HeadlessMode(false)
{ {
Q_ASSERT(m_pSettings); Q_ASSERT(m_pSettings);
@ -161,6 +162,7 @@ void AppConfig::loadSettings()
m_AutoHide = settings().value("autoHide", false).toBool(); m_AutoHide = settings().value("autoHide", false).toBool();
m_AutoStart = settings().value("autoStart", false).toBool(); m_AutoStart = settings().value("autoStart", false).toBool();
m_MinimizeToTray = settings().value("minimizeToTray", false).toBool(); m_MinimizeToTray = settings().value("minimizeToTray", false).toBool();
m_HeadlessMode = settings().value("headlessMode", false).toBool();
} }
void AppConfig::saveSettings() void AppConfig::saveSettings()
@ -184,6 +186,7 @@ void AppConfig::saveSettings()
settings().setValue("autoHide", m_AutoHide); settings().setValue("autoHide", m_AutoHide);
settings().setValue("autoStart", m_AutoStart); settings().setValue("autoStart", m_AutoStart);
settings().setValue("minimizeToTray", m_MinimizeToTray); settings().setValue("minimizeToTray", m_MinimizeToTray);
settings().setValue("headlessMode", m_HeadlessMode);
settings().sync(); settings().sync();
} }
@ -236,3 +239,7 @@ bool AppConfig::getAutoStart() { return m_AutoStart; }
void AppConfig::setMinimizeToTray(bool b) { m_MinimizeToTray = b; } void AppConfig::setMinimizeToTray(bool b) { m_MinimizeToTray = b; }
bool AppConfig::getMinimizeToTray() { return m_MinimizeToTray; } bool AppConfig::getMinimizeToTray() { return m_MinimizeToTray; }
void AppConfig::setHeadlessMode(bool b) { m_HeadlessMode = b; }
bool AppConfig::getHeadlessMode() { return m_HeadlessMode; }

View File

@ -100,6 +100,9 @@ class AppConfig: public QObject
void setMinimizeToTray(bool b); void setMinimizeToTray(bool b);
bool getMinimizeToTray(); bool getMinimizeToTray();
void setHeadlessMode(bool b);
bool getHeadlessMode();
void saveSettings(); void saveSettings();
protected: protected:
@ -135,6 +138,7 @@ protected:
bool m_AutoHide; bool m_AutoHide;
bool m_AutoStart; bool m_AutoStart;
bool m_MinimizeToTray; bool m_MinimizeToTray;
bool m_HeadlessMode;
static const char m_BarriersName[]; static const char m_BarriersName[];
static const char m_BarriercName[]; static const char m_BarriercName[];

View File

@ -520,6 +520,9 @@ void MainWindow::startBarrier()
args << "--enable-crypto"; args << "--enable-crypto";
} }
if (m_AppConfig->getHeadlessMode()) {
args << "--headless-mode";
}
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
// on windows, the profile directory changes depending on the user that // on windows, the profile directory changes depending on the user that
// launched the process (e.g. when launched with elevation). setting the // launched the process (e.g. when launched with elevation). setting the

View File

@ -51,6 +51,7 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
m_pCheckBoxAutoStart->setChecked(appConfig().getAutoStart()); m_pCheckBoxAutoStart->setChecked(appConfig().getAutoStart());
m_pCheckBoxMinimizeToTray->setChecked(appConfig().getMinimizeToTray()); m_pCheckBoxMinimizeToTray->setChecked(appConfig().getMinimizeToTray());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled());
m_pCheckBoxHeadlessMode->setChecked(m_appConfig.getHeadlessMode());
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
m_pComboElevate->setCurrentIndex(static_cast<int>(appConfig().elevateMode())); m_pComboElevate->setCurrentIndex(static_cast<int>(appConfig().elevateMode()));
@ -75,6 +76,7 @@ void SettingsDialog::accept()
m_appConfig.setAutoHide(m_pCheckBoxAutoHide->isChecked()); m_appConfig.setAutoHide(m_pCheckBoxAutoHide->isChecked());
m_appConfig.setAutoStart(m_pCheckBoxAutoStart->isChecked()); m_appConfig.setAutoStart(m_pCheckBoxAutoStart->isChecked());
m_appConfig.setMinimizeToTray(m_pCheckBoxMinimizeToTray->isChecked()); m_appConfig.setMinimizeToTray(m_pCheckBoxMinimizeToTray->isChecked());
m_appConfig.setHeadlessMode(m_pCheckBoxHeadlessMode->isChecked());
m_appConfig.saveSettings(); m_appConfig.saveSettings();
QDialog::accept(); QDialog::accept();
} }

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>368</width> <width>368</width>
<height>428</height> <height>454</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -133,6 +133,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1">
<widget class="QCheckBox" name="m_pCheckBoxHeadlessMode">
<property name="text">
<string>Headless &amp;mode</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -114,6 +114,9 @@ App::run(int argc, char** argv)
// using the exit(int) function! // using the exit(int) function!
result = e.getCode(); result = e.getCode();
} }
catch (std::runtime_error& re) {
LOG((CLOG_CRIT "A runtime error occurred: %s\n", re.what()));
}
catch (std::exception& e) { catch (std::exception& e) {
LOG((CLOG_CRIT "An error occurred: %s\n", e.what())); LOG((CLOG_CRIT "An error occurred: %s\n", e.what()));
} }

View File

@ -168,7 +168,10 @@ private:
" --enable-drag-drop enable file drag & drop.\n" \ " --enable-drag-drop enable file drag & drop.\n" \
" --enable-crypto enable the crypto (ssl) plugin.\n" \ " --enable-crypto enable the crypto (ssl) plugin.\n" \
" --profile-dir <path> use named profile directory instead.\n" \ " --profile-dir <path> use named profile directory instead.\n" \
" --drop-dir <path> use named drop target directory instead.\n" " --drop-dir <path> 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 \ #define HELP_COMMON_INFO_2 \
" -h, --help display this help and exit.\n" \ " -h, --help display this help and exit.\n" \

View File

@ -290,6 +290,9 @@ ArgParser::parseGenericArgs(int argc, const char* const* argv, int& i)
else if (isArg(i, argc, argv, NULL, "--plugin-dir", 1)) { else if (isArg(i, argc, argv, NULL, "--plugin-dir", 1)) {
argsBase().m_pluginDirectory = argv[++i]; argsBase().m_pluginDirectory = argv[++i];
} }
else if (isArg(i, argc, argv, NULL, "--headless-mode")) {
argsBase().m_headlessMode = true;
}
else { else {
// option not supported here // option not supported here
return false; return false;

View File

@ -44,7 +44,8 @@ m_shouldExit(false),
m_barrierAddress(), m_barrierAddress(),
m_enableCrypto(false), m_enableCrypto(false),
m_profileDirectory(""), m_profileDirectory(""),
m_pluginDirectory("") m_pluginDirectory(""),
m_headlessMode(false)
{ {
} }

View File

@ -52,4 +52,5 @@ public:
bool m_enableCrypto; bool m_enableCrypto;
String m_profileDirectory; String m_profileDirectory;
String m_pluginDirectory; String m_pluginDirectory;
bool m_headlessMode;
}; };

View File

@ -164,7 +164,7 @@ ClientApp::createScreen()
{ {
#if WINAPI_MSWINDOWS #if WINAPI_MSWINDOWS
return new barrier::Screen(new MSWindowsScreen( 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 #elif WINAPI_XWINDOWS
return new barrier::Screen(new XWindowsScreen( return new barrier::Screen(new XWindowsScreen(
new XWindowsImpl(), new XWindowsImpl(),

View File

@ -62,21 +62,21 @@ IKeyState::KeyInfo::alloc(KeyID id,
info->m_button = button; info->m_button = button;
info->m_count = count; info->m_count = count;
info->m_screens = info->m_screensBuffer; 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; return info;
} }
IKeyState::KeyInfo* IKeyState::KeyInfo*
IKeyState::KeyInfo::alloc(const KeyInfo& x) IKeyState::KeyInfo::alloc(const KeyInfo& x)
{ {
KeyInfo* info = (KeyInfo*)malloc(sizeof(KeyInfo) + auto bufferLen = strnlen(x.m_screensBuffer, SIZE_MAX);
strlen(x.m_screensBuffer)); auto info = (KeyInfo*)malloc(sizeof(KeyInfo) + bufferLen);
info->m_key = x.m_key; info->m_key = x.m_key;
info->m_mask = x.m_mask; info->m_mask = x.m_mask;
info->m_button = x.m_button; info->m_button = x.m_button;
info->m_count = x.m_count; info->m_count = x.m_count;
info->m_screens = x.m_screens ? info->m_screensBuffer : NULL; 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; return info;
} }

View File

@ -62,6 +62,9 @@ ProtocolUtil::readf(barrier::IStream* stream, const char* fmt, ...)
catch (XIO&) { catch (XIO&) {
result = false; result = false;
} }
catch (const std::bad_alloc&) {
result = false;
}
va_end(args); va_end(args);
return result; return result;
} }
@ -79,18 +82,17 @@ ProtocolUtil::vwritef(barrier::IStream* stream,
} }
// fill buffer // fill buffer
UInt8* buffer = new UInt8[size]; std::vector<UInt8> buffer;
writef_void(buffer, fmt, args); buffer.reserve(size);
writef_void(buffer.data(), fmt, args);
try { try {
// write buffer // write buffer
stream->write(buffer, size); stream->write(buffer.data(), size);
LOG((CLOG_DEBUG2 "wrote %d bytes", size)); LOG((CLOG_DEBUG2 "wrote %d bytes", size));
delete[] buffer;
} }
catch (XBase&) { catch (const XBase& exception) {
delete[] buffer; LOG((CLOG_DEBUG2 "Exception <%s> during wrote %d bytes into stream", exception.what(), size));
throw; throw;
} }
} }

View File

@ -267,6 +267,18 @@ ServerApp::handleClientConnected(const Event&, void* vlistener)
if (client != NULL) { if (client != NULL) {
m_server->adoptClient(client); m_server->adoptClient(client);
updateStatus(); 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 #if WINAPI_MSWINDOWS
return new barrier::Screen(new MSWindowsScreen( 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 #elif WINAPI_XWINDOWS
return new barrier::Screen(new XWindowsScreen( return new barrier::Screen(new XWindowsScreen(
new XWindowsImpl(), new XWindowsImpl(),

View File

@ -240,7 +240,8 @@ void
Client::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool) Client::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool)
{ {
m_active = true; m_active = true;
m_screen->mouseMove(xAbs, yAbs); if (!m_args.m_headlessMode)
m_screen->mouseMove(xAbs, yAbs);
m_screen->enter(mask); m_screen->enter(mask);
if (m_sendFileThread != NULL) { if (m_sendFileThread != NULL) {
@ -515,7 +516,7 @@ Client::setupTimer()
{ {
assert(m_timer == NULL); 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, m_events->adoptHandler(Event::kTimer, m_timer,
new TMethodEventJob<Client>(this, new TMethodEventJob<Client>(this,
&Client::handleConnectTimeout)); &Client::handleConnectTimeout));

View File

@ -100,7 +100,7 @@
MSWindowsDesks::MSWindowsDesks( MSWindowsDesks::MSWindowsDesks(
bool isPrimary, bool noHooks, bool isPrimary, bool noHooks,
const IScreenSaver* screensaver, IEventQueue* events, const IScreenSaver* screensaver, IEventQueue* events,
IJob* updateKeys, bool stopOnDeskSwitch) : IJob* updateKeys, bool stopOnDeskSwitch, bool headlessMode) :
m_isPrimary(isPrimary), m_isPrimary(isPrimary),
m_noHooks(noHooks), m_noHooks(noHooks),
m_isOnScreen(m_isPrimary), m_isOnScreen(m_isPrimary),
@ -117,7 +117,8 @@ MSWindowsDesks::MSWindowsDesks(
m_deskReady(&m_mutex, false), m_deskReady(&m_mutex, false),
m_updateKeys(updateKeys), m_updateKeys(updateKeys),
m_events(events), m_events(events),
m_stopOnDeskSwitch(stopOnDeskSwitch) m_stopOnDeskSwitch(stopOnDeskSwitch),
m_headlessMode(headlessMode)
{ {
m_cursor = createBlankCursor(); m_cursor = createBlankCursor();
m_deskClass = createDeskWindowClass(m_isPrimary); 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. // we aren't notified when the mouse leaves our window.
SetCapture(desk->m_window); SetCapture(desk->m_window);
// warp the mouse to the cursor center if (!m_headlessMode) {
LOG((CLOG_DEBUG2 "warping cursor to center: %+d,%+d", m_xCenter, m_yCenter)); // warp the mouse to the cursor center
deskMouseMove(m_xCenter, m_yCenter); LOG((CLOG_DEBUG2 "warping cursor to center: %+d,%+d", m_xCenter, m_yCenter));
deskMouseMove(m_xCenter, m_yCenter);
}
} }
} }

View File

@ -68,7 +68,7 @@ public:
MSWindowsDesks( MSWindowsDesks(
bool isPrimary, bool noHooks, bool isPrimary, bool noHooks,
const IScreenSaver* screensaver, IEventQueue* events, const IScreenSaver* screensaver, IEventQueue* events,
IJob* updateKeys, bool stopOnDeskSwitch); IJob* updateKeys, bool stopOnDeskSwitch, bool headlessMode);
~MSWindowsDesks(); ~MSWindowsDesks();
//! @name manipulators //! @name manipulators
@ -294,4 +294,6 @@ private:
// true if program should stop on desk switch. // true if program should stop on desk switch.
bool m_stopOnDeskSwitch; bool m_stopOnDeskSwitch;
bool m_headlessMode;
}; };

View File

@ -93,6 +93,7 @@ MSWindowsScreen::MSWindowsScreen(
bool isPrimary, bool isPrimary,
bool noHooks, bool noHooks,
bool stopOnDeskSwitch, bool stopOnDeskSwitch,
bool headlessMode,
IEventQueue* events) : IEventQueue* events) :
PlatformScreen(events), PlatformScreen(events),
m_isPrimary(isPrimary), m_isPrimary(isPrimary),
@ -136,7 +137,8 @@ MSWindowsScreen::MSWindowsScreen(
m_events, m_events,
new TMethodJob<MSWindowsScreen>( new TMethodJob<MSWindowsScreen>(
this, &MSWindowsScreen::updateKeysCB), this, &MSWindowsScreen::updateKeysCB),
stopOnDeskSwitch); stopOnDeskSwitch,
headlessMode);
m_keyState = new MSWindowsKeyState(m_desks, getEventTarget(), m_events); m_keyState = new MSWindowsKeyState(m_desks, getEventTarget(), m_events);
updateScreenShape(); updateScreenShape();
@ -311,6 +313,13 @@ MSWindowsScreen::enter()
bool bool
MSWindowsScreen::leave() 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 // get keyboard layout of foreground window. we'll use this
// keyboard layout for translating keys sent to clients. // keyboard layout for translating keys sent to clients.
HWND window = GetForegroundWindow(); HWND window = GetForegroundWindow();
@ -521,6 +530,60 @@ MSWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const
m_desks->getCursorPos(x, y); 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 void
MSWindowsScreen::reconfigure(UInt32 activeSides) MSWindowsScreen::reconfigure(UInt32 activeSides)
{ {
@ -1505,11 +1568,11 @@ MSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y)
// warp mouse. hopefully this inserts a mouse motion event // warp mouse. hopefully this inserts a mouse motion event
// between the previous message and the following message. // between the previous message and the following message.
SetCursorPos(x, y); setThisCursorPos(x, y);
// check to see if the mouse pos was set correctly // check to see if the mouse pos was set correctly
POINT cursorPos; POINT cursorPos;
GetCursorPos(&cursorPos); getThisCursorPos(&cursorPos);
// there is a bug or round error in SetCursorPos and GetCursorPos on // 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. // a high DPI setting. The check here is for Vista/7 login screen.

View File

@ -44,6 +44,7 @@ public:
bool isPrimary, bool isPrimary,
bool noHooks, bool noHooks,
bool stopOnDeskSwitch, bool stopOnDeskSwitch,
bool headlessMode,
IEventQueue* events); IEventQueue* events);
virtual ~MSWindowsScreen(); virtual ~MSWindowsScreen();
@ -76,6 +77,25 @@ public:
SInt32& width, SInt32& height) const; SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) 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 // IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides); virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y); virtual void warpCursor(SInt32 x, SInt32 y);

View File

@ -1244,6 +1244,20 @@ void Config::parseAction(ConfigReadContext& s, const std::string& name,
action = new InputFilter::KeyboardBroadcastAction(m_events, mode, screens); 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 { else {
throw XConfigRead(s, "unknown action argument \"%{1}\"", name); throw XConfigRead(s, "unknown action argument \"%{1}\"", name);
} }

View File

@ -558,7 +558,7 @@ std::string InputFilter::KeystrokeAction::format() const
return barrier::string::sprintf("%s(%s,%.*s)", type, return barrier::string::sprintf("%s(%s,%.*s)", type,
barrier::KeyMap::formatKey(m_keyInfo->m_key, barrier::KeyMap::formatKey(m_keyInfo->m_key,
m_keyInfo->m_mask).c_str(), 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); m_keyInfo->m_screens + 1);
} }
} }
@ -660,6 +660,53 @@ InputFilter::MouseButtonAction::formatName() const
return (m_press ? "mouseDown" : "mouseUp"); 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 // InputFilter::Rule
// //

View File

@ -270,6 +270,23 @@ public:
IEventQueue* m_events; 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 { class Rule {
public: public:
Rule(); Rule();

View File

@ -2338,7 +2338,7 @@ Server::SwitchToScreenInfo::alloc(const std::string& screen)
SwitchToScreenInfo* info = SwitchToScreenInfo* info =
(SwitchToScreenInfo*)malloc(sizeof(SwitchToScreenInfo) + (SwitchToScreenInfo*)malloc(sizeof(SwitchToScreenInfo) +
screen.size()); 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; return info;
} }
@ -2377,7 +2377,7 @@ Server::KeyboardBroadcastInfo::alloc(State state, const std::string& screens)
(KeyboardBroadcastInfo*)malloc(sizeof(KeyboardBroadcastInfo) + (KeyboardBroadcastInfo*)malloc(sizeof(KeyboardBroadcastInfo) +
screens.size()); screens.size());
info->m_state = state; 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; return info;
} }

View File

@ -179,6 +179,10 @@ public:
//! Return fake drag file list //! Return fake drag file list
DragFileList getFakeDragFileList() { return m_fakeDragFileList; } DragFileList getFakeDragFileList() { return m_fakeDragFileList; }
//! Return true if fucus in primary clinet
bool isServerHoldFocus() { return (m_active ==
(BaseClientProxy*) m_primaryClient); }
//@} //@}
private: private:

View File

@ -53,7 +53,7 @@ protected:
return new MSWindowsDesks( return new MSWindowsDesks(
true, false, m_screensaver, eventQueue, true, false, m_screensaver, eventQueue,
new TMethodJob<MSWindowsKeyStateTests>( new TMethodJob<MSWindowsKeyStateTests>(
this, &MSWindowsKeyStateTests::updateKeysCB), false); this, &MSWindowsKeyStateTests::updateKeysCB), false, false);
} }
void* getEventTarget() const void* getEventTarget() const