From b2a0ab2f58038a7b20f6e792711f33a778053350 Mon Sep 17 00:00:00 2001 From: yupi2 Date: Wed, 16 Aug 2017 20:37:51 +0000 Subject: [PATCH] support horizontal scrolling, mouse4, and mouse5 --- src/lib/platform/MSWindowsDesks.cpp | 20 ++++- src/lib/platform/MSWindowsScreen.cpp | 12 +-- src/lib/platform/MSWindowsScreen.h | 2 +- src/lib/platform/OSXScreen.mm | 1 + src/lib/platform/XWindowsScreen.cpp | 130 +++++++++++++++------------ src/lib/platform/XWindowsScreen.h | 10 ++- src/lib/synergy/mouse_types.h | 6 +- src/lib/synwinhk/synwinhk.cpp | 12 ++- 8 files changed, 118 insertions(+), 75 deletions(-) diff --git a/src/lib/platform/MSWindowsDesks.cpp b/src/lib/platform/MSWindowsDesks.cpp index c7bad451315..11f9ea7b982 100644 --- a/src/lib/platform/MSWindowsDesks.cpp +++ b/src/lib/platform/MSWindowsDesks.cpp @@ -45,6 +45,10 @@ #define SPI_GETSCREENSAVERRUNNING 114 #endif +#if !defined(MOUSEEVENTF_HWHEEL) +#define MOUSEEVENTF_HWHEEL 0x1000 +#endif + // X button stuff #if !defined(WM_XBUTTONDOWN) #define WM_XBUTTONDOWN 0x020B @@ -330,12 +334,12 @@ MSWindowsDesks::fakeMouseButton(ButtonID button, bool press) flags = press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; break; - case kButtonExtra0 + 0: + case kButtonExtra0: data = XBUTTON1; flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; break; - case kButtonExtra0 + 1: + case kButtonExtra1: data = XBUTTON2; flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; break; @@ -688,6 +692,15 @@ void MSWindowsDesks::deskThread(void* vdesk) { MSG msg; + BOOL vistaOrGreater = FALSE; + + { + OSVERSIONINFOW osvi; + osvi.dwOSVersionInfoSize = sizeof(osvi); + if (GetVersionExW(&osvi)) { + vistaOrGreater = osvi.dwMajorVersion >= 6; + } + } // use given desktop for this thread Desk* desk = static_cast(vdesk); @@ -790,10 +803,11 @@ MSWindowsDesks::deskThread(void* vdesk) break; case SYNERGY_MSG_FAKE_WHEEL: - // XXX -- add support for x-axis scrolling if (msg.lParam != 0) { send_mouse_input(MOUSEEVENTF_WHEEL, 0, 0, (DWORD)msg.lParam); //mouse_event(MOUSEEVENTF_WHEEL, 0, 0, (DWORD)msg.lParam, 0); + } else if (vistaOrGreater && msg.wParam != 0) { + send_mouse_input(MOUSEEVENTF_HWHEEL, 0, 0, (DWORD)msg.wParam); } break; diff --git a/src/lib/platform/MSWindowsScreen.cpp b/src/lib/platform/MSWindowsScreen.cpp index 2333eeb9acd..2286d80b30f 100644 --- a/src/lib/platform/MSWindowsScreen.cpp +++ b/src/lib/platform/MSWindowsScreen.cpp @@ -958,9 +958,9 @@ MSWindowsScreen::updateButtons() m_buttons[kButtonLeft] = (GetKeyState(VK_LBUTTON) < 0); m_buttons[kButtonRight] = (GetKeyState(VK_RBUTTON) < 0); m_buttons[kButtonMiddle] = (GetKeyState(VK_MBUTTON) < 0); - m_buttons[kButtonExtra0 + 0] = (numButtons >= 4) && + m_buttons[kButtonExtra0] = (numButtons >= 4) && (GetKeyState(VK_XBUTTON1) < 0); - m_buttons[kButtonExtra0 + 1] = (numButtons >= 5) && + m_buttons[kButtonExtra1] = (numButtons >= 5) && (GetKeyState(VK_XBUTTON2) < 0); } @@ -1013,8 +1013,8 @@ MSWindowsScreen::onPreDispatchPrimary(HWND, static_cast(lParam)); case SYNERGY_MSG_MOUSE_WHEEL: - // XXX -- support x-axis scrolling - return onMouseWheel(0, static_cast(wParam)); + return onMouseWheel(static_cast(lParam), + static_cast(wParam)); case SYNERGY_MSG_PRE_WARP: { @@ -1676,13 +1676,13 @@ MSWindowsScreen::mapButtonFromEvent(WPARAM msg, LPARAM button) const switch (button) { case XBUTTON1: if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 4) { - return kButtonExtra0 + 0; + return kButtonExtra0; } break; case XBUTTON2: if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 5) { - return kButtonExtra0 + 1; + return kButtonExtra1; } break; } diff --git a/src/lib/platform/MSWindowsScreen.h b/src/lib/platform/MSWindowsScreen.h index ebe27cb464d..78aec4543fb 100644 --- a/src/lib/platform/MSWindowsScreen.h +++ b/src/lib/platform/MSWindowsScreen.h @@ -305,7 +305,7 @@ class MSWindowsScreen : public PlatformScreen { HotKeyToIDMap m_hotKeyToIDMap; // map of button state - bool m_buttons[1 + kButtonExtra0 + 1]; + bool m_buttons[NumButtonIDs]; // the system shows the mouse cursor when an internal display count // is >= 0. this count is maintained per application but there's diff --git a/src/lib/platform/OSXScreen.mm b/src/lib/platform/OSXScreen.mm index 6e96068c750..66b9f9d5cc4 100644 --- a/src/lib/platform/OSXScreen.mm +++ b/src/lib/platform/OSXScreen.mm @@ -422,6 +422,7 @@ {kCGEventRightMouseUp, kCGEventRightMouseDragged, kCGEventRightMouseDown}, {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, + {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown} }; diff --git a/src/lib/platform/XWindowsScreen.cpp b/src/lib/platform/XWindowsScreen.cpp index 635427b2dc8..5f4839207b6 100644 --- a/src/lib/platform/XWindowsScreen.cpp +++ b/src/lib/platform/XWindowsScreen.cpp @@ -99,7 +99,8 @@ XWindowsScreen::XWindowsScreen( IEventQueue* events) : m_isPrimary(isPrimary), m_mouseScrollDelta(mouseScrollDelta), - m_accumulatedScroll(0), + m_x_accumulatedScroll(0), + m_y_accumulatedScroll(0), m_display(NULL), m_root(None), m_window(None), @@ -859,34 +860,33 @@ XWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const } void -XWindowsScreen::fakeMouseWheel(SInt32, SInt32 yDelta) const +XWindowsScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const { - // XXX -- support x-axis scrolling - if (yDelta == 0) { + int numEvents; + + if ((!xDelta && !yDelta) || (xDelta && yDelta)) { + // umm not good i guess return; } - int numEvents = accumulateMouseScroll(yDelta); + // 4, 5, 6, 7 + // up, down, left, right + unsigned int xButton; - // choose button depending on rotation direction - const unsigned int xButton = mapButtonToX(static_cast( - (numEvents >= 0) ? -1 : -2)); - if (xButton == 0) { - // If we get here, then the XServer does not support the scroll - // wheel buttons, so send PageUp/PageDown keystrokes instead. - // Patch by Tom Chadwick. - KeyCode keycode = 0; - if (yDelta >= 0) { - keycode = XKeysymToKeycode(m_display, XK_Page_Up); - } - else { - keycode = XKeysymToKeycode(m_display, XK_Page_Down); + if (yDelta) { // up/down + numEvents = y_accumulateMouseScroll(yDelta); + if (numEvents >= 0) { + xButton = 4; // up + } else { + xButton = 5; // down } - if (keycode != 0) { - XTestFakeKeyEvent(m_display, keycode, True, CurrentTime); - XTestFakeKeyEvent(m_display, keycode, False, CurrentTime); + } else { // left/right + numEvents = x_accumulateMouseScroll(xDelta); + if (numEvents >= 0) { + xButton = 7; // RIGHT -- hopefully good + } else { + xButton = 6; // LEFT -- hopefully good } - return; } numEvents = std::abs(numEvents); @@ -1568,7 +1568,14 @@ XWindowsScreen::onMouseRelease(const XButtonEvent& xbutton) // wheel backward (toward user) sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, -120)); } - // XXX -- support x-axis scrolling + else if (xbutton.button == 6) { + // wheel left + sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(-120, 0)); + } + else if (xbutton.button == 7) { + // wheel right + sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(120, 0)); + } } void @@ -1640,11 +1647,20 @@ XWindowsScreen::onMouseMove(const XMotionEvent& xmotion) } int -XWindowsScreen::accumulateMouseScroll(SInt32 yDelta) const +XWindowsScreen::x_accumulateMouseScroll(SInt32 xDelta) const { - m_accumulatedScroll += yDelta; - int numEvents = m_accumulatedScroll / m_mouseScrollDelta; - m_accumulatedScroll -= numEvents * m_mouseScrollDelta; + m_x_accumulatedScroll += xDelta; + int numEvents = m_x_accumulatedScroll / m_mouseScrollDelta; + m_x_accumulatedScroll -= numEvents * m_mouseScrollDelta; + return numEvents; +} + +int +XWindowsScreen::y_accumulateMouseScroll(SInt32 yDelta) const +{ + m_y_accumulatedScroll += yDelta; + int numEvents = m_y_accumulatedScroll / m_mouseScrollDelta; + m_y_accumulatedScroll -= numEvents * m_mouseScrollDelta; return numEvents; } @@ -1867,50 +1883,46 @@ XWindowsScreen::mapButtonFromX(const XButtonEvent* event) const { unsigned int button = event->button; - // first three buttons map to 1, 2, 3 (kButtonLeft, Middle, Right) - if (button >= 1 && button <= 3) { - return static_cast(button); - } + // http://xahlee.info/linux/linux_x11_mouse_button_number.html + // and the program `xev` - // buttons 4 and 5 are ignored here. they're used for the wheel. - // buttons 6, 7, etc and up map to 4, 5, etc. - else if (button >= 6) { - return static_cast(button - 2); - } + switch (button) { + case 1: case 2: case 3: // kButtonLeft, Middle, Right + return static_cast(button); - // unknown button - else { - return kButtonNone; + case 4: case 5: case 6: case 7: // scroll up, down, left, right -- ignored here + return kButtonNone; + + case 8: // browser backwards - mouse4 + return kButtonExtra0; + + case 9: // browser forwards - mouse5 + return kButtonExtra1; + + default: // yeah, just unknown + return kButtonNone; } } unsigned int XWindowsScreen::mapButtonToX(ButtonID id) const { - // map button -1 to button 4 (+wheel) - if (id == static_cast(-1)) { - id = 4; - } - - // map button -2 to button 5 (-wheel) - else if (id == static_cast(-2)) { - id = 5; - } + switch (id) { + // regular buttons + case kButtonLeft: case kButtonMiddle: case kButtonRight: + return id; - // map buttons 4, 5, etc. to 6, 7, etc. to make room for buttons - // 4 and 5 used to simulate the mouse wheel. - else if (id >= 4) { - id += 2; - } + // mouse4 + case kButtonExtra0: + return 8; + // mouse5 + case kButtonExtra1: + return 9; - // check button is in legal range - if (id < 1 || id > m_buttons.size()) { // out of range - return 0; + default: + return 0; } - - // map button - return static_cast(id); } void diff --git a/src/lib/platform/XWindowsScreen.h b/src/lib/platform/XWindowsScreen.h index 8bd741959d0..6d76e2976fe 100644 --- a/src/lib/platform/XWindowsScreen.h +++ b/src/lib/platform/XWindowsScreen.h @@ -138,7 +138,8 @@ class XWindowsScreen : public PlatformScreen { // Returns the number of scroll events needed after the current delta has // been taken into account - int accumulateMouseScroll(SInt32 yDelta) const; + int x_accumulateMouseScroll(SInt32 xDelta) const; + int y_accumulateMouseScroll(SInt32 yDelta) const; bool detectXI2(); #ifdef HAVE_XI2 @@ -180,10 +181,11 @@ class XWindowsScreen : public PlatformScreen { // The size of a smallest supported scroll event, in points int m_mouseScrollDelta; - // Accumulates scrolls of less than m_mouseScrollDelta across multiple + // Accumulates scrolls of less than m_?_mouseScrollDelta across multiple // scroll events. We dispatch a scroll event whenever the accumulated scroll - // becomes larger than m_mouseScrollDelta - mutable int m_accumulatedScroll; + // becomes larger than m_?_mouseScrollDelta + mutable int m_y_accumulatedScroll; + mutable int m_x_accumulatedScroll; Display* m_display; Window m_root; diff --git a/src/lib/synergy/mouse_types.h b/src/lib/synergy/mouse_types.h index be9f1920d9c..b4a862aa32b 100644 --- a/src/lib/synergy/mouse_types.h +++ b/src/lib/synergy/mouse_types.h @@ -32,10 +32,14 @@ static const ButtonID kButtonNone = 0; static const ButtonID kButtonLeft = 1; static const ButtonID kButtonMiddle = 2; static const ButtonID kButtonRight = 3; +// browser backwards - mouse4 static const ButtonID kButtonExtra0 = 4; +// browser forwards - mouse5 +static const ButtonID kButtonExtra1 = 5; static const ButtonID kMacButtonRight = 2; static const ButtonID kMacButtonMiddle = 3; //@} -static const UInt8 NumButtonIDs = 5; +// XXX -- some osx stuff uses this and might expect it to be 5 +static const UInt8 NumButtonIDs = 6; diff --git a/src/lib/synwinhk/synwinhk.cpp b/src/lib/synwinhk/synwinhk.cpp index 449085197d1..02164de8e01 100644 --- a/src/lib/synwinhk/synwinhk.cpp +++ b/src/lib/synwinhk/synwinhk.cpp @@ -23,6 +23,10 @@ #include #include +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x020E +#endif + #if _MSC_VER >= 1400 // VS2005 hack - we don't use assert here because we don't want to link with the CRT. #undef assert @@ -492,6 +496,12 @@ doMouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data) PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, data, 0); } return (g_mode == kHOOK_RELAY_EVENTS); + case WM_MOUSEHWHEEL: + if (g_mode == kHOOK_RELAY_EVENTS) { + // relay event + PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, 0, data); + } + return (g_mode == kHOOK_RELAY_EVENTS); case WM_NCMOUSEMOVE: case WM_MOUSEMOVE: @@ -588,7 +598,7 @@ mouseHook(int code, WPARAM wParam, LPARAM lParam) SInt32 x = (SInt32)info->pt.x; SInt32 y = (SInt32)info->pt.y; SInt32 w = 0; - if (wParam == WM_MOUSEWHEEL) { + if (wParam == WM_MOUSEWHEEL || wParam == WM_MOUSEHWHEEL) { // win2k and other systems supporting WM_MOUSEWHEEL in // the mouse hook are gratuitously different (and poorly // documented). if a low-level mouse hook is in place