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:
@ -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)
|
||||
===========
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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
|
||||
//@{
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user