SYNERGY-988 - Normalize scrolling direction (#7044)

* SYNERGY-988 - Normalize scrolling direction on Mac

* SYNERGY-988 - Scroll direction check on Windows

* SYNERGY-988 - Add check for registry key presence

* SYNERGY-988 - Normalize scrolling directino on Linux

* SYNERGY-988 - Detach scroll direction check on Windows

* SYNERGY-988 - Update changelog

* SYNERGY-988 - Resolve code smells

* SYNERGY-988 - Normalize scroll direction for Linux servers

* SYNERGY-988 - Removed unnecessary INFO level logs

Co-authored-by: SerhiiGadzhilov <71632867+SerhiiGadzhilov@users.noreply.github.com>
This commit is contained in:
Igor Sikachyna
2021-06-30 15:25:11 +03:00
committed by GitHub
parent 16d9a3dce0
commit 89363240eb
12 changed files with 185 additions and 5 deletions

View File

@ -16,6 +16,7 @@ Enhancements:
- #7035 Add Fedora 34 build
- #7037 Add Ubuntu 21.04 build
- #7030 | #7041 | #7043 Add user notification for secure input on Mac
- #7044 Apply natural scroll setting independently on each client
- #7040 Support "Kana" and "Eisu" keys on Japanese Apple Pro Keyboard (JIS)
===========

View File

@ -19,6 +19,10 @@
#include "arch/unix/ArchSystemUnix.h"
#include <sys/utsname.h>
#include <stdio.h>
#include <array>
#include <memory>
#include <string>
//
// ArchSystemUnix
@ -78,3 +82,21 @@ ArchSystemUnix::getLibsUsed(void) const
{
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;
}

View File

@ -35,4 +35,5 @@ public:
virtual void setting(const std::string&, const std::string&) const;
virtual std::string getLibsUsed(void) const;
static std::string runCommand(const std::string& cmd);
};

View File

@ -46,6 +46,7 @@
#include <Shlobj.h>
#include <comutil.h>
#include <algorithm>
#include <thread>
// suppress warning about GetVersionEx, which is used indirectly in this compilation unit.
#pragma warning(disable: 4996)
@ -344,6 +345,11 @@ MSWindowsScreen::leave()
// tell desk that we're leaving and tell it the keyboard layout
m_desks->leave(m_keyLayout);
// Forcefully update scrolling direction
// Will keep server updated when moving cursor
allowScrollDirectionUpdate();
updateScrollDirection();
if (m_isPrimary) {
// warp to center
@ -829,6 +835,8 @@ MSWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
void
MSWindowsScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const
{
xDelta = mapScrollFromSynergy(xDelta);
yDelta = mapScrollFromSynergy(yDelta);
m_desks->fakeMouseWheel(xDelta, yDelta);
}
@ -1473,6 +1481,8 @@ MSWindowsScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta)
// ignore message if posted prior to last mark change
if (!ignore()) {
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));
}
return true;
@ -2022,3 +2032,56 @@ MSWindowsScreen::isModifierRepeat(KeyModifierMask oldState, KeyModifierMask stat
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

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

View File

@ -341,6 +341,7 @@ private:
Thread* m_getDropTargetThread;
String m_dropTarget;
void updateScrollDirection() override;
// -1 for natural scrolling direction, 1 otherwise
SInt32 m_scrollDirection = 1;

View File

@ -859,8 +859,6 @@ OSXScreen::enter()
setZeroSuppressionInterval();
}
else {
m_scrollDirection = [[[NSUserDefaults standardUserDefaults] objectForKey:@"com.apple.swipescrolldirection"] boolValue] ? -1 : 1;
// reset buttons
m_buttonState.reset();
@ -1465,7 +1463,7 @@ OSXScreen::mapScrollWheelToSynergy(SInt32 x) const
// return accelerated scrolling but not exponentially scaled as it is
// on the mac.
double d = (1.0 + getScrollSpeed()) * x / getScrollSpeedFactor();
return static_cast<SInt32>(120.0 * d);
return static_cast<SInt32>(m_scrollDirection * 120.0 * d);
}
SInt32
@ -2242,6 +2240,17 @@ getProcessName(int pid)
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"
void

View File

@ -37,6 +37,7 @@
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <thread>
#if X_DISPLAY_MISSING
# error X11 is required to build synergy
#else
@ -867,6 +868,12 @@ XWindowsScreen::fakeMouseWheel(SInt32, SInt32 yDelta) const
return;
}
// use mouse scroll direction for inversion
if( m_scrollDirectionMouse < 0 )
{
yDelta = -yDelta;
}
// choose button depending on rotation direction
const unsigned int xButton = mapButtonToX(static_cast<ButtonID>(
(yDelta >= 0) ? -1 : -2));
@ -1624,11 +1631,13 @@ XWindowsScreen::onMouseRelease(const XButtonEvent& xbutton)
}
else if (xbutton.button == 4) {
// wheel forward (away from user)
sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, 120));
// invert for natural scroll setting
sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, 120 * m_scrollDirectionMouse));
}
else if (xbutton.button == 5) {
// wheel backward (toward user)
sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, -120));
// invert for natural scroll setting
sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, -120 * m_scrollDirectionMouse));
}
// XXX -- support x-axis scrolling
}
@ -2153,3 +2162,27 @@ XWindowsScreen::selectXIRawMotion()
free(mask.mask);
}
#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

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

View File

@ -139,6 +139,20 @@ public:
*/
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
//@{

View File

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

View File

@ -114,6 +114,11 @@ Screen::enter(KeyModifierMask toggleMask)
// now on screen
m_entered = true;
// Forcefully update scrolling direction
// Will keep clients updated when moving cursor
m_screen->allowScrollDirectionUpdate();
m_screen->updateScrollDirection();
m_screen->enter();
if (m_isPrimary) {
enterPrimary();
@ -129,6 +134,11 @@ Screen::leave()
assert(m_entered == true);
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()) {
return false;
}
@ -212,6 +222,11 @@ Screen::keyUp(KeyID, KeyModifierMask, KeyButton button)
void
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);
}
@ -239,6 +254,9 @@ void
Screen::mouseWheel(SInt32 xDelta, SInt32 yDelta)
{
assert(!m_isPrimary);
// update scroll direction if necessary
m_screen->updateScrollDirection();
m_screen->fakeMouseWheel(xDelta, yDelta);
}