feat: support horizontal scrolling
fixes: #7220
based on 9f15b1bcf2
Co-authored-by: Evan Maddock <maddock.evan@vivaldi.net>
This commit is contained in:
parent
82588a7fc9
commit
a532f655c1
8 changed files with 69 additions and 38 deletions
|
|
@ -30,6 +30,8 @@ static const ButtonID kMacButtonMiddle = 3;
|
||||||
// Only used for X11 Scroll Wheel
|
// Only used for X11 Scroll Wheel
|
||||||
static const ButtonID kX11ScrollWheelUp = 255;
|
static const ButtonID kX11ScrollWheelUp = 255;
|
||||||
static const ButtonID kX11ScrollWheelDown = 254;
|
static const ButtonID kX11ScrollWheelDown = 254;
|
||||||
|
static const ButtonID kX11ScrollWheelLeft = 6;
|
||||||
|
static const ButtonID kX11ScrollWheelRight = 7;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
static const uint8_t NumButtonIDs = 6;
|
static const uint8_t NumButtonIDs = 6;
|
||||||
|
|
|
||||||
|
|
@ -100,4 +100,7 @@ protected:
|
||||||
Converts a sides mask (e.g. LeftMask | RightMask) to a string representation (e.g. "LR").
|
Converts a sides mask (e.g. LeftMask | RightMask) to a string representation (e.g. "LR").
|
||||||
*/
|
*/
|
||||||
static std::string sidesMaskToString(uint32_t sides);
|
static std::string sidesMaskToString(uint32_t sides);
|
||||||
|
|
||||||
|
// Delta for a "click"
|
||||||
|
static const auto s_scrollDelta = 120;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -672,7 +672,7 @@ void EiScreen::onPointerScrollEvent(ei_event *event)
|
||||||
// convert between the two and keep the remainders because
|
// convert between the two and keep the remainders because
|
||||||
// we will very likely get subpixel scroll events.
|
// we will very likely get subpixel scroll events.
|
||||||
// This means a single pixel is 120/s_pixelToWheelRation in wheel values.
|
// This means a single pixel is 120/s_pixelToWheelRation in wheel values.
|
||||||
const int s_pixelToWheelRatio = 120 / s_pixelsPerWheelClick;
|
const int s_pixelToWheelRatio = s_scrollDelta / s_pixelsPerWheelClick;
|
||||||
|
|
||||||
assert(m_isPrimary);
|
assert(m_isPrimary);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,10 @@
|
||||||
#define SPI_GETSCREENSAVERRUNNING 114
|
#define SPI_GETSCREENSAVERRUNNING 114
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MOUSEEVENTF_HWHEEL)
|
||||||
|
#define MOUSEEVENTF_HWHEEL 0x1000
|
||||||
|
#endif
|
||||||
|
|
||||||
// X button stuff
|
// X button stuff
|
||||||
#if !defined(WM_XBUTTONDOWN)
|
#if !defined(WM_XBUTTONDOWN)
|
||||||
#define WM_XBUTTONDOWN 0x020B
|
#define WM_XBUTTONDOWN 0x020B
|
||||||
|
|
@ -697,6 +701,9 @@ void MSWindowsDesks::deskThread(const void *vdesk)
|
||||||
if (msg.lParam != 0) {
|
if (msg.lParam != 0) {
|
||||||
send_mouse_input(MOUSEEVENTF_WHEEL, 0, 0, (DWORD)msg.lParam);
|
send_mouse_input(MOUSEEVENTF_WHEEL, 0, 0, (DWORD)msg.lParam);
|
||||||
}
|
}
|
||||||
|
if (msg.wParam != 0) {
|
||||||
|
send_mouse_input(MOUSEEVENTF_HWHEEL, 0, 0, (DWORD)msg.wParam);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DESKFLOW_MSG_CURSOR_POS: {
|
case DESKFLOW_MSG_CURSOR_POS: {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "deskflow/ScreenException.h"
|
#include "deskflow/ScreenException.h"
|
||||||
|
|
||||||
|
#ifndef WM_MOUSEHWHEEL
|
||||||
|
#define WM_MOUSEHWHEEL 0x020E
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char *g_name = "dfwhook";
|
static const char *g_name = "dfwhook";
|
||||||
|
|
||||||
static DWORD g_processID = 0;
|
static DWORD g_processID = 0;
|
||||||
|
|
@ -505,6 +509,13 @@ static bool mouseHookHandler(WPARAM wParam, int32_t x, int32_t y, int32_t data)
|
||||||
}
|
}
|
||||||
return (g_mode == kHOOK_RELAY_EVENTS);
|
return (g_mode == kHOOK_RELAY_EVENTS);
|
||||||
|
|
||||||
|
case WM_MOUSEHWHEEL:
|
||||||
|
if (g_mode == kHOOK_RELAY_EVENTS) {
|
||||||
|
// relay event
|
||||||
|
PostThreadMessage(g_threadID, DESKFLOW_MSG_MOUSE_WHEEL, 0, data);
|
||||||
|
}
|
||||||
|
return (g_mode == kHOOK_RELAY_EVENTS);
|
||||||
|
|
||||||
case WM_NCMOUSEMOVE:
|
case WM_NCMOUSEMOVE:
|
||||||
case WM_MOUSEMOVE:
|
case WM_MOUSEMOVE:
|
||||||
if (g_mode == kHOOK_RELAY_EVENTS) {
|
if (g_mode == kHOOK_RELAY_EVENTS) {
|
||||||
|
|
@ -620,9 +631,10 @@ EHookResult MSWindowsHook::install()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// clang-format off
|
||||||
// check that we got all the hooks we wanted
|
// check that we got all the hooks we wanted
|
||||||
if ((g_mouseLL == nullptr) ||
|
if (
|
||||||
|
(g_mouseLL == nullptr) ||
|
||||||
#if !NO_GRAB_KEYBOARD
|
#if !NO_GRAB_KEYBOARD
|
||||||
(g_keyboardLL == nullptr)
|
(g_keyboardLL == nullptr)
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -630,7 +642,7 @@ EHookResult MSWindowsHook::install()
|
||||||
uninstall();
|
uninstall();
|
||||||
return kHOOK_FAILED;
|
return kHOOK_FAILED;
|
||||||
}
|
}
|
||||||
|
// clang-format on
|
||||||
if (g_keyboardLL != nullptr || g_mouseLL != nullptr) {
|
if (g_keyboardLL != nullptr || g_mouseLL != nullptr) {
|
||||||
g_hookThread = GetCurrentThreadId();
|
g_hookThread = GetCurrentThreadId();
|
||||||
return kHOOK_OKAY_LL;
|
return kHOOK_OKAY_LL;
|
||||||
|
|
|
||||||
|
|
@ -897,8 +897,7 @@ bool MSWindowsScreen::onPreDispatchPrimary(HWND, UINT message, WPARAM wParam, LP
|
||||||
return onMouseMove(static_cast<int32_t>(wParam), static_cast<int32_t>(lParam));
|
return onMouseMove(static_cast<int32_t>(wParam), static_cast<int32_t>(lParam));
|
||||||
|
|
||||||
case DESKFLOW_MSG_MOUSE_WHEEL:
|
case DESKFLOW_MSG_MOUSE_WHEEL:
|
||||||
// XXX -- support x-axis scrolling
|
return onMouseWheel(static_cast<int32_t>(lParam), static_cast<int32_t>(wParam));
|
||||||
return onMouseWheel(0, static_cast<int32_t>(wParam));
|
|
||||||
|
|
||||||
case DESKFLOW_MSG_PRE_WARP: {
|
case DESKFLOW_MSG_PRE_WARP: {
|
||||||
// save position to compute delta of next motion
|
// save position to compute delta of next motion
|
||||||
|
|
|
||||||
|
|
@ -400,6 +400,7 @@ void OSXScreen::constructMouseButtonEventMap()
|
||||||
{kCGEventRightMouseUp, kCGEventRightMouseDragged, kCGEventRightMouseDown},
|
{kCGEventRightMouseUp, kCGEventRightMouseDragged, kCGEventRightMouseDown},
|
||||||
{kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown},
|
{kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown},
|
||||||
{kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown},
|
{kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown},
|
||||||
|
{kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown},
|
||||||
{kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}
|
{kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -589,8 +590,9 @@ void OSXScreen::fakeMouseWheel(ScrollDelta delta) const
|
||||||
if (delta.x != 0 || delta.y != 0) {
|
if (delta.x != 0 || delta.y != 0) {
|
||||||
// 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.
|
||||||
delta =
|
delta = applyScrollModifier(
|
||||||
applyScrollModifier({static_cast<int32_t>(3.0 * delta.x / 120.0), static_cast<int32_t>(3.0 * delta.y / 120.0)});
|
{static_cast<int32_t>(3.0 * delta.x / s_scrollDelta), static_cast<int32_t>(3.0 * delta.y / s_scrollDelta)}
|
||||||
|
);
|
||||||
// create a scroll event, post it and release it. not sure if kCGScrollEventUnitLine
|
// create a scroll event, post it and release it. not sure if kCGScrollEventUnitLine
|
||||||
// is the right choice here over kCGScrollEventUnitPixel
|
// is the right choice here over kCGScrollEventUnitPixel
|
||||||
CGEventRef scrollEvent = CGEventCreateScrollWheelEvent(nullptr, kCGScrollEventUnitLine, 2, delta.y, delta.x);
|
CGEventRef scrollEvent = CGEventCreateScrollWheelEvent(nullptr, kCGScrollEventUnitLine, 2, delta.y, delta.x);
|
||||||
|
|
|
||||||
|
|
@ -786,44 +786,39 @@ void XWindowsScreen::fakeMouseRelativeMove(int32_t dx, int32_t dy) const
|
||||||
|
|
||||||
void XWindowsScreen::fakeMouseWheel(ScrollDelta delta) const
|
void XWindowsScreen::fakeMouseWheel(ScrollDelta delta) const
|
||||||
{
|
{
|
||||||
// XXX -- support x-axis scrolling
|
if (delta.y == 0 && delta.x == 0) {
|
||||||
if (delta.y == 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
delta = applyScrollModifier(delta);
|
delta = applyScrollModifier(delta);
|
||||||
|
bool isYScroll = delta.y != 0;
|
||||||
|
int32_t axisDelta = delta.y == 0 ? delta.x : delta.y;
|
||||||
|
|
||||||
// choose button depending on rotation direction
|
ButtonID btn = kButtonNone;
|
||||||
const unsigned int xButton = mapButtonToX(delta.y >= 0 ? kX11ScrollWheelUp : kX11ScrollWheelDown);
|
if (isYScroll) {
|
||||||
if (xButton == 0) {
|
btn = axisDelta >= 0 ? kX11ScrollWheelUp : kX11ScrollWheelDown;
|
||||||
// If we get here, then the XServer does not support the scroll
|
} else {
|
||||||
// wheel buttons, so send PageUp/PageDown keystrokes instead.
|
btn = axisDelta >= 0 ? kX11ScrollWheelLeft : kX11ScrollWheelRight;
|
||||||
// Patch by Tom Chadwick.
|
}
|
||||||
KeyCode keycode = 0;
|
const unsigned int button = mapButtonToX(btn);
|
||||||
if (delta.y >= 0) {
|
|
||||||
keycode = XKeysymToKeycode(m_display, XK_Page_Up);
|
// If the XServer does not support the Y scroll send PageUp/PageDown keystrokes instead.
|
||||||
} else {
|
if (const KeyCode keycode = XKeysymToKeycode(m_display, delta.y >= 0 ? XK_Page_Up : XK_Page_Down);
|
||||||
keycode = XKeysymToKeycode(m_display, XK_Page_Down);
|
button == 0 && isYScroll && keycode != 0) {
|
||||||
}
|
XTestFakeKeyEvent(m_display, keycode, True, CurrentTime);
|
||||||
if (keycode != 0) {
|
XTestFakeKeyEvent(m_display, keycode, False, CurrentTime);
|
||||||
XTestFakeKeyEvent(m_display, keycode, True, CurrentTime);
|
|
||||||
XTestFakeKeyEvent(m_display, keycode, False, CurrentTime);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now use absolute value of delta
|
// now use absolute value of delta
|
||||||
if (delta.y < 0) {
|
if (axisDelta < 0) {
|
||||||
delta.y = -delta.y;
|
axisDelta = -axisDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delta for a "click"
|
|
||||||
static const auto s_mouseDelta = 120;
|
|
||||||
|
|
||||||
// send as many clicks as necessary
|
// send as many clicks as necessary
|
||||||
for (; delta.y >= 0; delta.y -= s_mouseDelta) {
|
while (axisDelta >= 0) {
|
||||||
XTestFakeButtonEvent(m_display, xButton, True, CurrentTime);
|
XTestFakeButtonEvent(m_display, button, True, CurrentTime);
|
||||||
XTestFakeButtonEvent(m_display, xButton, False, CurrentTime);
|
XTestFakeButtonEvent(m_display, button, False, CurrentTime);
|
||||||
|
axisDelta -= s_scrollDelta;
|
||||||
}
|
}
|
||||||
XFlush(m_display);
|
XFlush(m_display);
|
||||||
}
|
}
|
||||||
|
|
@ -1461,12 +1456,17 @@ void XWindowsScreen::onMouseRelease(const XButtonEvent &xbutton)
|
||||||
sendEvent(PrimaryScreenButtonUp, ButtonInfo::alloc(button, mask));
|
sendEvent(PrimaryScreenButtonUp, ButtonInfo::alloc(button, mask));
|
||||||
} else if (xbutton.button == 4) {
|
} else if (xbutton.button == 4) {
|
||||||
// wheel forward (away from user)
|
// wheel forward (away from user)
|
||||||
sendEvent(PrimaryScreenWheel, WheelInfo::alloc(0, 120));
|
sendEvent(PrimaryScreenWheel, WheelInfo::alloc(0, s_scrollDelta));
|
||||||
} else if (xbutton.button == 5) {
|
} else if (xbutton.button == 5) {
|
||||||
// wheel backward (toward user)
|
// wheel backward (toward user)
|
||||||
sendEvent(PrimaryScreenWheel, WheelInfo::alloc(0, -120));
|
sendEvent(PrimaryScreenWheel, WheelInfo::alloc(0, -s_scrollDelta));
|
||||||
|
} else if (xbutton.button == 6) {
|
||||||
|
// wheel tilt left
|
||||||
|
sendEvent(PrimaryScreenWheel, WheelInfo::alloc(-s_scrollDelta, 0));
|
||||||
|
} else if (xbutton.button == 7) {
|
||||||
|
// wheel tilt right
|
||||||
|
sendEvent(PrimaryScreenWheel, WheelInfo::alloc(s_scrollDelta, 0));
|
||||||
}
|
}
|
||||||
// XXX -- support x-axis scrolling
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XWindowsScreen::onMouseMove(const XMotionEvent &xmotion)
|
void XWindowsScreen::onMouseMove(const XMotionEvent &xmotion)
|
||||||
|
|
@ -1740,6 +1740,8 @@ ButtonID XWindowsScreen::mapButtonFromX(const XButtonEvent *event) const
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
return static_cast<ButtonID>(button); // Handle Left, Middle and Right buttons
|
return static_cast<ButtonID>(button); // Handle Left, Middle and Right buttons
|
||||||
case 8:
|
case 8:
|
||||||
return kButtonExtra0; // Mouse 4
|
return kButtonExtra0; // Mouse 4
|
||||||
|
|
@ -1761,6 +1763,10 @@ unsigned int XWindowsScreen::mapButtonToX(ButtonID id) const
|
||||||
return 4;
|
return 4;
|
||||||
case kX11ScrollWheelDown:
|
case kX11ScrollWheelDown:
|
||||||
return 5;
|
return 5;
|
||||||
|
case kX11ScrollWheelLeft:
|
||||||
|
return 6;
|
||||||
|
case kX11ScrollWheelRight:
|
||||||
|
return 7;
|
||||||
case kButtonExtra0:
|
case kButtonExtra0:
|
||||||
return 8;
|
return 8;
|
||||||
case kButtonExtra1:
|
case kButtonExtra1:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue