SYNERGY-1454 Scroll direction (#7140)

* SYNERGY-1454 Add a new checkbox into the setting dialog

* SYNERGY-1454 Save the new option

* SYNERGY-1454 Pass the new option to client

* SYNERGY-1454 Parse the new param on client side

* SYNERGY-1454 Invert scroll direction for macOS

* SYNERGY-1454 Scroll direction on Windows

* SYNERGY-1454 Remove unused code

* SYNERGY-1454 Scroll direction for Linux

* SYNERGY-1454 Simplify scroll direction for Mac

* SYNERGY-1454 Simplify scroll direction for Linux

* SYNERGY-1454 Simplify scroll direction for Windows

* SYNERGY-1454 ChangeLog

* SYNERGY-1454 Fix code smell

* SYNERGY-1434 Lower case for the first char of the option

* SYNERGY-1454 Fix indentations

Co-authored-by: Serhii Hadzhilov <gadzhilov.sergey@gmail.com>
Co-authored-by: Serhii Hadzhilov <serhii@symless.com>
This commit is contained in:
Serhii Hadzhilov 2022-01-26 14:07:28 +02:00 committed by GitHub
parent dc72af7a7b
commit af4c88e531
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 104 additions and 227 deletions

View file

@ -2,6 +2,7 @@ v1.14.3-snapshot
=========== ===========
Bug fixes: Bug fixes:
- #7135 Fix issue with function keys on macOS - #7135 Fix issue with function keys on macOS
- #7140 Configure scroll direction on a per-computer basis
=========== ===========
v1.14.2-stable v1.14.2-stable

View file

@ -78,7 +78,8 @@ const char* AppConfig::m_SynergySettingsName[] = {
"tlsCertPath", "tlsCertPath",
"tlsKeyLength", "tlsKeyLength",
"preventSleep", "preventSleep",
"languageSync" "languageSync",
"invertScrollDirection"
}; };
static const char* logLevelNames[] = static const char* logLevelNames[] =
@ -243,6 +244,7 @@ void AppConfig::loadSettings()
m_ServerHostname = loadSetting(kServerHostname).toString(); m_ServerHostname = loadSetting(kServerHostname).toString();
m_PreventSleep = loadSetting(kPreventSleep, false).toBool(); m_PreventSleep = loadSetting(kPreventSleep, false).toBool();
m_LanguageSync = loadSetting(kLanguageSync, false).toBool(); m_LanguageSync = loadSetting(kLanguageSync, false).toBool();
m_InvertScrollDirection = loadSetting(kInvertScrollDirection, false).toBool();
//only change the serial key if the settings being loaded contains a key //only change the serial key if the settings being loaded contains a key
bool updateSerial = ConfigWriter::make() bool updateSerial = ConfigWriter::make()
@ -305,6 +307,7 @@ void AppConfig::saveSettings()
setSetting(kServerHostname, m_ServerHostname); setSetting(kServerHostname, m_ServerHostname);
setSetting(kPreventSleep, m_PreventSleep); setSetting(kPreventSleep, m_PreventSleep);
setSetting(kLanguageSync, m_LanguageSync); setSetting(kLanguageSync, m_LanguageSync);
setSetting(kInvertScrollDirection, m_InvertScrollDirection);
} }
m_unsavedChanges = false; m_unsavedChanges = false;
@ -454,8 +457,16 @@ void AppConfig::setMinimizeToTray(bool newValue) {
setSettingModified(m_MinimizeToTray, newValue); setSettingModified(m_MinimizeToTray, newValue);
} }
bool AppConfig::getInvertScrollDirection() const {
return m_InvertScrollDirection;
}
bool AppConfig::getLanguageSync() const { return m_LanguageSync; } bool AppConfig::getLanguageSync() const { return m_LanguageSync; }
void AppConfig::setInvertScrollDirection(bool newValue) {
setSettingModified(m_InvertScrollDirection, newValue);
}
void AppConfig::setLanguageSync(bool newValue) { void AppConfig::setLanguageSync(bool newValue) {
setSettingModified(m_LanguageSync, newValue); setSettingModified(m_LanguageSync, newValue);
} }

View file

@ -112,6 +112,8 @@ class AppConfig: public QObject, public GUI::Config::ConfigBase
void setAutoHide(bool b); void setAutoHide(bool b);
bool getAutoHide(); bool getAutoHide();
void setInvertScrollDirection(bool b);
bool getInvertScrollDirection() const;
void setLanguageSync(bool b); void setLanguageSync(bool b);
bool getLanguageSync() const; bool getLanguageSync() const;
void setPreventSleep(bool b); void setPreventSleep(bool b);
@ -205,7 +207,8 @@ protected:
kTLSCertPath, kTLSCertPath,
kTLSKeyLength, kTLSKeyLength,
kPreventSleep, kPreventSleep,
kLanguageSync kLanguageSync,
kInvertScrollDirection
}; };
void setScreenName(const QString& s); void setScreenName(const QString& s);
@ -248,6 +251,7 @@ protected:
int m_LastExpiringWarningTime; int m_LastExpiringWarningTime;
bool m_ActivationHasRun; bool m_ActivationHasRun;
bool m_MinimizeToTray; bool m_MinimizeToTray;
bool m_InvertScrollDirection = false;
bool m_LanguageSync = true; bool m_LanguageSync = true;
bool m_PreventSleep = false; bool m_PreventSleep = false;

View file

@ -811,6 +811,9 @@ bool MainWindow::clientArgs(QStringList& args, QString& app)
args << "--sync-language"; args << "--sync-language";
} }
if (appConfig().getInvertScrollDirection()) {
args <<"--invert-scroll";
}
#if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG) #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG)
// check auto config first, if it is disabled or no server detected, // check auto config first, if it is disabled or no server detected,

View file

@ -53,6 +53,7 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
enableControls(appConfig().isWritable()); enableControls(appConfig().isWritable());
m_pCheckBoxLanguageSync->setVisible(m_pMainWindow->synergyType() == MainWindow::synergyClient); m_pCheckBoxLanguageSync->setVisible(m_pMainWindow->synergyType() == MainWindow::synergyClient);
m_pCheckBoxScrollDirection->setVisible(m_pMainWindow->synergyType() == MainWindow::synergyClient);
const auto& serveConfig = m_pMainWindow->serverConfig(); const auto& serveConfig = m_pMainWindow->serverConfig();
m_pLineEditScreenName->setValidator(new validators::ScreenNameValidator(m_pLineEditScreenName, m_pLabelNameError, (&serveConfig.screens()))); m_pLineEditScreenName->setValidator(new validators::ScreenNameValidator(m_pLineEditScreenName, m_pLabelNameError, (&serveConfig.screens())));
@ -69,6 +70,7 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
connect(m_pLineEditScreenName, SIGNAL(textEdited(QString)), this, SLOT(onChange())); connect(m_pLineEditScreenName, SIGNAL(textEdited(QString)), this, SLOT(onChange()));
connect(m_pComboElevate, SIGNAL(currentIndexChanged(int)), this, SLOT(onChange())); connect(m_pComboElevate, SIGNAL(currentIndexChanged(int)), this, SLOT(onChange()));
connect(m_pCheckBoxLanguageSync, SIGNAL(clicked()), this, SLOT(onChange())); connect(m_pCheckBoxLanguageSync, SIGNAL(clicked()), this, SLOT(onChange()));
connect(m_pCheckBoxScrollDirection, SIGNAL(clicked()), this, SLOT(onChange()));
adjustSize(); adjustSize();
} }
@ -92,6 +94,7 @@ void SettingsDialog::accept()
appConfig().setTLSKeyLength(m_pComboBoxKeyLength->currentText()); appConfig().setTLSKeyLength(m_pComboBoxKeyLength->currentText());
appConfig().setCryptoEnabled(m_pCheckBoxEnableCrypto->isChecked()); appConfig().setCryptoEnabled(m_pCheckBoxEnableCrypto->isChecked());
appConfig().setLanguageSync(m_pCheckBoxLanguageSync->isChecked()); appConfig().setLanguageSync(m_pCheckBoxLanguageSync->isChecked());
appConfig().setInvertScrollDirection(m_pCheckBoxScrollDirection->isChecked());
appConfig().saveSettings(); appConfig().saveSettings();
QDialog::accept(); QDialog::accept();
@ -150,6 +153,7 @@ void SettingsDialog::loadFromConfig() {
m_pLineEditCertificatePath->setText(appConfig().getTLSCertPath()); m_pLineEditCertificatePath->setText(appConfig().getTLSCertPath());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled());
m_pCheckBoxLanguageSync->setChecked(m_appConfig.getLanguageSync()); m_pCheckBoxLanguageSync->setChecked(m_appConfig.getLanguageSync());
m_pCheckBoxScrollDirection->setChecked(m_appConfig.getInvertScrollDirection());
//If the tls file exists test its key length //If the tls file exists test its key length
if (QFile(appConfig().getTLSCertPath()).exists()) { if (QFile(appConfig().getTLSCertPath()).exists()) {
@ -341,7 +345,8 @@ bool SettingsDialog::isModified()
|| appConfig().getTLSKeyLength() != m_pComboBoxKeyLength->currentText() || appConfig().getTLSKeyLength() != m_pComboBoxKeyLength->currentText()
|| appConfig().getCryptoEnabled() != m_pCheckBoxEnableCrypto->isChecked() || appConfig().getCryptoEnabled() != m_pCheckBoxEnableCrypto->isChecked()
|| appConfig().isSystemScoped() != m_isSystemAtStart || appConfig().isSystemScoped() != m_isSystemAtStart
|| appConfig().getLanguageSync() != m_pCheckBoxLanguageSync->isChecked()) || appConfig().getLanguageSync() != m_pCheckBoxLanguageSync->isChecked()
|| appConfig().getInvertScrollDirection() != m_pCheckBoxScrollDirection->isChecked())
); );
} }
@ -363,6 +368,7 @@ void SettingsDialog::enableControls(bool enable) {
m_pCheckBoxEnableCrypto->setEnabled(enable); m_pCheckBoxEnableCrypto->setEnabled(enable);
m_labelAdminRightsMessage->setVisible(!enable); m_labelAdminRightsMessage->setVisible(!enable);
m_pCheckBoxLanguageSync->setEnabled(enable); m_pCheckBoxLanguageSync->setEnabled(enable);
m_pCheckBoxScrollDirection->setEnabled(enable);
if (enable) { if (enable) {
m_pLabelLogPath->setEnabled(m_pCheckBoxLogToFile->isChecked()); m_pLabelLogPath->setEnabled(m_pCheckBoxLogToFile->isChecked());

View file

@ -337,10 +337,33 @@ background-color: rgba(192,192,192, 0.1);
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="1"> <item row="4" column="0">
<widget class="QComboBox" name="m_pComboLanguage"/> <widget class="QLabel" name="m_pLabelElevate">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Elevate privileges</string>
</property>
</widget>
</item> </item>
<item row="1" column="0" colspan="3"> <item row="5" column="0">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" colspan="3">
<widget class="QCheckBox" name="m_pCheckBoxLanguageSync"> <widget class="QCheckBox" name="m_pCheckBoxLanguageSync">
<property name="text"> <property name="text">
<string>&amp;Use server's keyboard language on this machine</string> <string>&amp;Use server's keyboard language on this machine</string>
@ -369,20 +392,7 @@ background-color: rgba(192,192,192, 0.1);
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="4" column="1">
<widget class="QLabel" name="m_pLabelElevate">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Elevate privileges</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="m_pComboElevate"> <widget class="QComboBox" name="m_pComboElevate">
<property name="toolTip"> <property name="toolTip">
<string>Specify when the Synergy service should run at an elevated privilege level</string> <string>Specify when the Synergy service should run at an elevated privilege level</string>
@ -407,18 +417,15 @@ background-color: rgba(192,192,192, 0.1);
</item> </item>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="0" column="1">
<spacer name="verticalSpacer_6"> <widget class="QComboBox" name="m_pComboLanguage"/>
<property name="orientation"> </item>
<enum>Qt::Vertical</enum> <item row="1" column="0" colspan="3">
<widget class="QCheckBox" name="m_pCheckBoxScrollDirection">
<property name="text">
<string>Invert scroll direction on this computer</string>
</property> </property>
<property name="sizeHint" stdset="0"> </widget>
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -1008,7 +1015,6 @@ font-weight: bold;</string>
</tabstops> </tabstops>
<resources> <resources>
<include location="../res/Synergy.qrc"/> <include location="../res/Synergy.qrc"/>
<include location="../res/Synergy.qrc"/>
</resources> </resources>
<connections> <connections>
<connection> <connection>

View file

@ -19,10 +19,6 @@
#include "arch/unix/ArchSystemUnix.h" #include "arch/unix/ArchSystemUnix.h"
#include <sys/utsname.h> #include <sys/utsname.h>
#include <stdio.h>
#include <array>
#include <memory>
#include <string>
#ifndef __APPLE__ #ifndef __APPLE__
#include <QtDBus> #include <QtDBus>
#endif #endif
@ -86,24 +82,6 @@ ArchSystemUnix::getLibsUsed(void) const
return "not implemented.\nuse lsof on shell"; return "not implemented.\nuse lsof on shell";
} }
std::string
ArchSystemUnix::runCommand(const std::string& cmd)
{
std::array<char, 128> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), &pclose);
if (!pipe)
{
return "";
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
{
result += buffer.data();
}
return result;
}
#ifndef __APPLE__ #ifndef __APPLE__
bool bool
ArchSystemUnix::DBusInhibitScreenCall(InhibitScreenServices serviceID, bool state, std::string& error) ArchSystemUnix::DBusInhibitScreenCall(InhibitScreenServices serviceID, bool state, std::string& error)

View file

@ -35,8 +35,6 @@ public:
virtual void setting(const std::string&, const std::string&) const; virtual void setting(const std::string&, const std::string&) const;
virtual std::string getLibsUsed(void) const; virtual std::string getLibsUsed(void) const;
static std::string runCommand(const std::string& cmd);
#ifndef __APPLE__ #ifndef __APPLE__
enum class InhibitScreenServices { enum class InhibitScreenServices {
kScreenSaver, kScreenSaver,

View file

@ -46,7 +46,6 @@
#include <Shlobj.h> #include <Shlobj.h>
#include <comutil.h> #include <comutil.h>
#include <algorithm> #include <algorithm>
#include <thread>
// suppress warning about GetVersionEx, which is used indirectly in this compilation unit. // suppress warning about GetVersionEx, which is used indirectly in this compilation unit.
#pragma warning(disable: 4996) #pragma warning(disable: 4996)
@ -341,11 +340,6 @@ MSWindowsScreen::leave()
// tell desk that we're leaving and tell it the keyboard layout // tell desk that we're leaving and tell it the keyboard layout
m_desks->leave(m_keyLayout); m_desks->leave(m_keyLayout);
// Forcefully update scrolling direction
// Will keep server updated when moving cursor
allowScrollDirectionUpdate();
updateScrollDirection();
if (m_isPrimary) { if (m_isPrimary) {
// warp to center // warp to center
@ -831,8 +825,8 @@ MSWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
void void
MSWindowsScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const MSWindowsScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const
{ {
xDelta = mapScrollFromSynergy(xDelta); xDelta *= ClientApp::instance().args().m_clientScrollDirection;
yDelta = mapScrollFromSynergy(yDelta); yDelta *= ClientApp::instance().args().m_clientScrollDirection;
m_desks->fakeMouseWheel(xDelta, yDelta); m_desks->fakeMouseWheel(xDelta, yDelta);
} }
@ -1485,8 +1479,6 @@ MSWindowsScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta)
// ignore message if posted prior to last mark change // ignore message if posted prior to last mark change
if (!ignore()) { if (!ignore()) {
LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta)); LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta));
xDelta = mapScrollToSynergy(xDelta);
yDelta = mapScrollToSynergy(yDelta);
sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(xDelta, yDelta)); sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(xDelta, yDelta));
} }
return true; return true;
@ -2036,56 +2028,3 @@ MSWindowsScreen::isModifierRepeat(KeyModifierMask oldState, KeyModifierMask stat
return result; return result;
} }
SInt32
MSWindowsScreen::mapScrollToSynergy(SInt32 delta) const
{
// for mouse wheel the delta will be a multiple of WHEEL_DELTA
if (delta % WHEEL_DELTA == 0)
{
return delta * m_scrollDirectionMouse;
}
else
{
return delta * m_scrollDirectionTouchpad;
}
}
SInt32
MSWindowsScreen::mapScrollFromSynergy(SInt32 delta) const
{
// use mouse scrolling direction to invert
if (m_scrollDirectionMouse < 0)
return -delta;
return delta;
}
void
MSWindowsScreen::updateScrollDirection()
{
static const TCHAR* const touchpadScrollDirectionNames[] = {
_T("SOFTWARE"),
_T("Microsoft"),
_T("Windows"),
_T("CurrentVersion"),
_T("PrecisionTouchPad"),
NULL
};
if (m_shouldUpdateScrollDirection)
{
m_shouldUpdateScrollDirection = false;
std::thread scrollDirectionUpdateThread([&] {
HKEY key = ArchMiscWindows::openKey(HKEY_CURRENT_USER, touchpadScrollDirectionNames);
if (key)
{
DWORD scroll = ArchMiscWindows::readValueInt(key, _T("ScrollDirection"));
ArchMiscWindows::closeKey(key);
if (scroll == 0) m_scrollDirectionTouchpad = 1;
else m_scrollDirectionTouchpad = -1;
}
});
scrollDirectionUpdateThread.detach();
}
}

View file

@ -141,7 +141,6 @@ public:
virtual const String& virtual const String&
getDropTarget() const; getDropTarget() const;
String getSecureInputApp() const override; String getSecureInputApp() const override;
void updateScrollDirection() override;
protected: protected:
// IPlatformScreen overrides // IPlatformScreen overrides
@ -249,9 +248,6 @@ private: // HACK
// send drag info and data back to server // send drag info and data back to server
void sendDragThread(void*); void sendDragThread(void*);
SInt32 mapScrollToSynergy(SInt32 delta) const;
SInt32 mapScrollFromSynergy(SInt32 delta) const;
private: private:
struct HotKeyItem { struct HotKeyItem {
public: public:
@ -371,9 +367,5 @@ private:
Thread* m_sendDragThread; Thread* m_sendDragThread;
PrimaryKeyDownList m_primaryKeyDownList; PrimaryKeyDownList m_primaryKeyDownList;
MSWindowsPowerManager m_powerManager;
// -1 for natural scrolling direction, 1 otherwise
SInt32 m_scrollDirectionMouse = 1;
SInt32 m_scrollDirectionTouchpad = 1;
MSWindowsPowerManager m_powerManager;
}; };

View file

@ -338,10 +338,6 @@ private:
Thread* m_getDropTargetThread; Thread* m_getDropTargetThread;
String m_dropTarget; String m_dropTarget;
void updateScrollDirection() override;
// -1 for natural scrolling direction, 1 otherwise
SInt32 m_scrollDirection = 1;
#if defined(MAC_OS_X_VERSION_10_7) #if defined(MAC_OS_X_VERSION_10_7)
Mutex* m_carbonLoopMutex; Mutex* m_carbonLoopMutex;
CondVar<bool>* m_carbonLoopReady; CondVar<bool>* m_carbonLoopReady;

View file

@ -1460,7 +1460,7 @@ OSXScreen::mapScrollWheelToSynergy(SInt32 x) const
{ {
// return accelerated scrolling // return accelerated scrolling
double d = (1.0 + getScrollSpeed()) * x; double d = (1.0 + getScrollSpeed()) * x;
return static_cast<SInt32>(m_scrollDirection * 120.0 * d); return static_cast<SInt32>(120.0 * d);
} }
SInt32 SInt32
@ -1468,7 +1468,8 @@ OSXScreen::mapScrollWheelFromSynergy(SInt32 x) const
{ {
// use server's acceleration with a little boost since other platforms // use server's acceleration with a little boost since other platforms
// take one wheel step as a larger step than the mac does. // take one wheel step as a larger step than the mac does.
return static_cast<SInt32>(m_scrollDirection * 3.0 * x / 120.0); auto result = static_cast<SInt32>(3.0 * x / 120.0);
return (result * ClientApp::instance().args().m_clientScrollDirection);
} }
double double
@ -2214,17 +2215,6 @@ getProcessName(int pid)
return buf; return buf;
} }
void
OSXScreen::updateScrollDirection()
{
if(m_shouldUpdateScrollDirection)
{
LOG((CLOG_DEBUG "updated scrolling direction"));
m_scrollDirection = [[[NSUserDefaults standardUserDefaults] objectForKey:@"com.apple.swipescrolldirection"] boolValue] ? -1 : 1;
m_shouldUpdateScrollDirection = false;
}
}
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
void void

View file

@ -25,6 +25,8 @@
#include "platform/XWindowsUtil.h" #include "platform/XWindowsUtil.h"
#include "synergy/Clipboard.h" #include "synergy/Clipboard.h"
#include "synergy/KeyMap.h" #include "synergy/KeyMap.h"
#include "synergy/ClientApp.h"
#include "synergy/ClientArgs.h"
#include "synergy/XScreen.h" #include "synergy/XScreen.h"
#include "synergy/ArgsBase.h" #include "synergy/ArgsBase.h"
#include "synergy/App.h" #include "synergy/App.h"
@ -39,7 +41,6 @@
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <algorithm> #include <algorithm>
#include <thread>
#if X_DISPLAY_MISSING #if X_DISPLAY_MISSING
# error X11 is required to build synergy # error X11 is required to build synergy
#else #else
@ -875,11 +876,7 @@ XWindowsScreen::fakeMouseWheel(SInt32, SInt32 yDelta) const
return; return;
} }
// use mouse scroll direction for inversion yDelta *= ClientApp::instance().args().m_clientScrollDirection;
if( m_scrollDirectionMouse < 0 )
{
yDelta = -yDelta;
}
// choose button depending on rotation direction // choose button depending on rotation direction
const unsigned int xButton = mapButtonToX(static_cast<ButtonID>( const unsigned int xButton = mapButtonToX(static_cast<ButtonID>(
@ -1638,13 +1635,11 @@ XWindowsScreen::onMouseRelease(const XButtonEvent& xbutton)
} }
else if (xbutton.button == 4) { else if (xbutton.button == 4) {
// wheel forward (away from user) // wheel forward (away from user)
// invert for natural scroll setting sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, 120));
sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, 120 * m_scrollDirectionMouse));
} }
else if (xbutton.button == 5) { else if (xbutton.button == 5) {
// wheel backward (toward user) // wheel backward (toward user)
// invert for natural scroll setting sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, -120));
sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, -120 * m_scrollDirectionMouse));
} }
// XXX -- support x-axis scrolling // XXX -- support x-axis scrolling
} }
@ -2169,28 +2164,3 @@ XWindowsScreen::selectXIRawMotion()
free(mask.mask); free(mask.mask);
} }
#endif #endif
void
XWindowsScreen::updateScrollDirection()
{
if (m_shouldUpdateScrollDirection)
{
m_shouldUpdateScrollDirection = false;
std::thread scrollDirectionUpdateThread([this]{
std::string mouseScroll = ArchSystemUnix::runCommand("gsettings get org.gnome.desktop.peripherals.mouse natural-scroll");
if(mouseScroll == "false\n")
m_scrollDirectionMouse = 1;
else if(mouseScroll == "true\n")
m_scrollDirectionMouse = -1;
std::string touchpadScroll = ArchSystemUnix::runCommand("gsettings get org.gnome.desktop.peripherals.touchpad natural-scroll");
if(touchpadScroll == "false\n")
m_scrollDirectionTouchpad = 1;
else if(touchpadScroll == "true\n")
m_scrollDirectionTouchpad = -1;
});
scrollDirectionUpdateThread.detach();
}
}

View file

@ -88,8 +88,6 @@ public:
virtual bool isPrimary() const; virtual bool isPrimary() const;
String getSecureInputApp() const override; String getSecureInputApp() const override;
void updateScrollDirection() override;
protected: protected:
// IPlatformScreen overrides // IPlatformScreen overrides
virtual void handleSystemEvent(const Event&, void*); virtual void handleSystemEvent(const Event&, void*);
@ -255,9 +253,5 @@ private:
// pointer to (singleton) screen. this is only needed by // pointer to (singleton) screen. this is only needed by
// ioErrorHandler(). // ioErrorHandler().
static XWindowsScreen* s_screen; static XWindowsScreen* s_screen;
// -1 for natural scrolling direction, 1 otherwise
SInt32 m_scrollDirectionMouse = 1;
SInt32 m_scrollDirectionTouchpad = 1;
XWindowsPowerManager m_powerManager; XWindowsPowerManager m_powerManager;
}; };

View file

@ -114,6 +114,9 @@ ArgParser::parseClientArgs(lib::synergy::ClientArgs& args, int argc, const char*
else if (isArg(i, argc, argv, nullptr, "--sync-language")) { else if (isArg(i, argc, argv, nullptr, "--sync-language")) {
args.m_enableLangSync = true; args.m_enableLangSync = true;
} }
else if (isArg(i, argc, argv, nullptr, "--invert-scroll")) {
args.m_clientScrollDirection = lib::synergy::ClientScrollDirection::INVERT_SERVER;
}
else { else {
if (i + 1 == argc) { if (i + 1 == argc) {
args.m_synergyAddress = argv[i]; args.m_synergyAddress = argv[i];

View file

@ -127,6 +127,7 @@ ClientApp::help()
"Usage: %s" "Usage: %s"
" [--yscroll <delta>]" " [--yscroll <delta>]"
" [--sync-language]" " [--sync-language]"
" [--invert-scroll]"
WINAPI_ARG WINAPI_ARG
HELP_SYS_ARGS HELP_SYS_ARGS
HELP_COMMON_ARGS HELP_COMMON_ARGS
@ -140,6 +141,7 @@ ClientApp::help()
" --yscroll <delta> defines the vertical scrolling delta, which is\n" " --yscroll <delta> defines the vertical scrolling delta, which is\n"
" 120 by default.\n" " 120 by default.\n"
" --sync-language set this parameter to enable language synchronization.\n" " --sync-language set this parameter to enable language synchronization.\n"
" --invert-scroll invert scroll direction on this computer.\n"
HELP_COMMON_INFO_2 HELP_COMMON_INFO_2
"\n" "\n"
"* marks defaults.\n" "* marks defaults.\n"

View file

@ -23,6 +23,11 @@
namespace lib { namespace lib {
namespace synergy { namespace synergy {
enum ClientScrollDirection {
SERVER = 1,
INVERT_SERVER = -1
};
class ClientArgs : public ArgsBase { class ClientArgs : public ArgsBase {
/// Public functions /// Public functions
@ -32,10 +37,14 @@ namespace lib {
~ClientArgs() override; ~ClientArgs() override;
public: public:
int m_yscroll = 0; int m_yscroll = 0;
bool m_enableLangSync = false; /// @brief Should keyboard input be in same language as on server bool m_enableLangSync = false; /// @brief Should keyboard input be in same language as on server
private: /**
* @brief m_clientScrollDirection
* This option is responcible for scroll direction on client side.
*/
ClientScrollDirection m_clientScrollDirection = ClientScrollDirection::SERVER;
}; };
} }

View file

@ -139,20 +139,6 @@ public:
*/ */
virtual String getSecureInputApp() const = 0; virtual String getSecureInputApp() const = 0;
//! Allow updating wheel scrolling direction
/*!
Sets a flag to allow updating the scrolling direction automatically
when scrolling
*/
virtual void allowScrollDirectionUpdate() = 0;
//! Update the scrolling direction if allowed
/*!
If relevant flag is set should read a system settings to apply a
correct scrolling direction
*/
virtual void updateScrollDirection() = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{

View file

@ -102,9 +102,6 @@ public:
virtual const String& virtual const String&
getDropTarget() const { throw std::runtime_error("getDropTarget not implemented"); } getDropTarget() const { throw std::runtime_error("getDropTarget not implemented"); }
void allowScrollDirectionUpdate() override { m_shouldUpdateScrollDirection = true; }
void updateScrollDirection() override = 0;
protected: protected:
//! Update mouse buttons //! Update mouse buttons
/*! /*!
@ -127,5 +124,4 @@ protected:
String m_draggingFilename; String m_draggingFilename;
bool m_draggingStarted; bool m_draggingStarted;
bool m_fakeDraggingStarted; bool m_fakeDraggingStarted;
bool m_shouldUpdateScrollDirection = false;
}; };

View file

@ -114,11 +114,6 @@ Screen::enter(KeyModifierMask toggleMask)
// now on screen // now on screen
m_entered = true; m_entered = true;
// Forcefully update scrolling direction
// Will keep clients updated when moving cursor
m_screen->allowScrollDirectionUpdate();
m_screen->updateScrollDirection();
m_screen->enter(); m_screen->enter();
if (m_isPrimary) { if (m_isPrimary) {
enterPrimary(); enterPrimary();
@ -134,11 +129,6 @@ Screen::leave()
assert(m_entered == true); assert(m_entered == true);
LOG((CLOG_INFO "leaving screen")); LOG((CLOG_INFO "leaving screen"));
// Forcefully update scrolling direction
// Will keep server updated when moving cursor
m_screen->allowScrollDirectionUpdate();
m_screen->updateScrollDirection();
if (!m_screen->leave()) { if (!m_screen->leave()) {
return false; return false;
} }
@ -222,11 +212,6 @@ Screen::keyUp(KeyID, KeyModifierMask, KeyButton button)
void void
Screen::mouseDown(ButtonID button) Screen::mouseDown(ButtonID button)
{ {
// No other convinient way to check if scroll direction was changed
// If mouse button is pressed is good enough indication to allow checking
// for scroll direction
m_screen->allowScrollDirectionUpdate();
m_screen->fakeMouseButton(button, true); m_screen->fakeMouseButton(button, true);
} }
@ -251,12 +236,9 @@ Screen::mouseRelativeMove(SInt32 dx, SInt32 dy)
} }
void void
Screen::mouseWheel(SInt32 xDelta, SInt32 yDelta) Screen::mouseWheel(SInt32 xDelta, SInt32 yDelta) const
{ {
assert(!m_isPrimary); assert(!m_isPrimary);
// update scroll direction if necessary
m_screen->updateScrollDirection();
m_screen->fakeMouseWheel(xDelta, yDelta); m_screen->fakeMouseWheel(xDelta, yDelta);
} }

View file

@ -177,7 +177,7 @@ public:
to the right and negative for motion towards the user or to the left. to the right and negative for motion towards the user or to the left.
Each wheel click should generate a delta of +/-120. Each wheel click should generate a delta of +/-120.
*/ */
void mouseWheel(SInt32 xDelta, SInt32 yDelta); void mouseWheel(SInt32 xDelta, SInt32 yDelta) const;
//! Notify of options changes //! Notify of options changes
/*! /*!

View file

@ -68,6 +68,17 @@ TEST(ClientArgsParsingTests, parseClientArgs_setLangSync)
EXPECT_TRUE(clientArgs.m_enableLangSync); EXPECT_TRUE(clientArgs.m_enableLangSync);
} }
TEST(ClientArgsParsingTests, parseClientArgs_setInvertScroll)
{
NiceMock<MockArgParser> argParser;
lib::synergy::ClientArgs clientArgs;
const int argc = 2;
std::array<const char*, argc> kLangCmd = { "stub", "--invert-scroll" };
argParser.parseClientArgs(clientArgs, argc, kLangCmd.data());
EXPECT_EQ(clientArgs.m_clientScrollDirection, lib::synergy::ClientScrollDirection::INVERT_SERVER);
}
TEST(ClientArgsParsingTests, parseClientArgs_setCommonArgs) TEST(ClientArgsParsingTests, parseClientArgs_setCommonArgs)
{ {
NiceMock<MockArgParser> argParser; NiceMock<MockArgParser> argParser;