|
#1 | mid-kid 10:50 May 04, 2019 |
| A lot of programs, including GIMP, Firefox, and others, allow the user to scroll a view horizontally with the mouse wheel while pressing shift. This essentially also inverts the behavior of the horizontal scroll action on input devices that support that.
I'm requesting this here because I think it'd be a good thing for the library to handle this in a generic manner through the Fl_Scrollbar class. | |
|
#2 | AlbrechtS 00:40 May 05, 2019 |
| Thanks for the proposal. I can confirm this behavior in firefox (nothing else tested by me yet).
However, I'm not sure what "This essentially also inverts the behavior of the horizontal scroll action on input devices that support that" means. Can you please elaborate? | |
|
#3 | AlbrechtS 01:40 May 05, 2019 |
| Some thoughts about possible implementations:
A very simple implementation of this feature would be that a vertical scrollbar would use the scroll event only if the shift key is currently NOT pressed and a horizontal scrollbar would use the event only if the shift key IS pressed.
However, this could break existing programs - for instance if there is only one (horizontal) scrollbar which would usually react on all scroll events, no matter if the shift key is actually pressed or not.
We could instead restrict only horizontal scrollbars to use the SHIFT state, but the order of event delivery is significant: order of children in a group, or from nested groups to parent groups if one group ignores the event. The latter is typical behavior so scrollbars can catch events that are delivered to inner groups and propagated to parent (outer) groups. In this case the vertical scrollbar could also consume the event even if the shift key is pressed because it is the first scrollbar child of a group.
Possible solutions:
(1) make sure that vertical scrollbars are always first in a group. This is not always true in FLTK's Fl_Scroll widget and would IMHO be too hard a restriction for user programs.
(2) add a flag to the Fl_Scrollbar widget that must be set if the particular scrollbar uses the shift key to determine whether it shall use or ignore the scroll event.
Solution (2) needs code changes but would be 100% backwards compatible.
That said, I believe that (2) would be an acceptable solution, but all comments and proposals for better implementations would be appreciated. | |
|
#4 | mid-kid 02:09 May 05, 2019 |
| >I'm not sure what "This essentially also inverts the behavior of the horizontal scroll action on input devices that support that" means. Right, I should've worded this better. I meant, that applications like GIMP (I haven't tested firefox for this) simply invert the scrollbar used for a certain scroll action when Shift is being pressed. When Shift is pressed, a vertical scroll event moves the horizontal scrollbar, and a horizontal scroll event (for example with a touchpad) moves the vertical scrollbar.
I have no clue why this behavior exists, since I don't know of any input devices that only allow scrolling horizontally, but maybe it was easier to implement that way? | |
|
#5 | manolo 09:37 May 07, 2019 |
| Running test/scroll program under macOS or X11, one sees that the horizontal scrollbar moves when shift is pressed and the mouse wheel is activated. Isn't that enough? | |
|
#6 | AlbrechtS 05:37 May 08, 2019 |
| @mid-kid: thanks for your clarification.
@Manolo: Using shift + mouse/scrollwheel under Linux (Ubuntu 18.04) in test/scroll does not move the horizontal scrollbar for me. It always moves the vertical scrollbar, no matter if I press the shift key or not. I see the same effect under Windows as well. | |
|
#7 | manolo 11:00 May 08, 2019 |
| I get here 2 situations under X11 :
1) with Ubuntu in VirtualBox (on MacOS host) shift+mouse wheel is ignored by both scrollers
2) with XQuartz (an X11 srver running on macOS) shift+mouse wheel moves the horizontal scroller | |
|
#8 | AlbrechtS 13:07 May 08, 2019 |
| I guess we need to debug events... | |
|
#9 | AlbrechtS 05:37 May 17, 2019 |
| Please see attached file '0001-Switch-hor.-vert.-scrolling-with-SHIFT-STR-3521.patch' for a proof of concept. Please apply with `git am' (hint: after creating a feature branch) or `patch -p1' for testing.
This patch does *unconditionally* change scrollbar behavior by exchanging horizontal and vertical mousewheel movement values (Fl::event_dx and Fl::event_dy) if the Shift key is pressed during mousewheel movement.
As said above this *may* break existing programs that don't care about shift key state when interpreting mousewheel events.
I don't know if these concerns are critical though. If yes, I suggest to use a global flag for the entire program that can /disable/ the new feature as opposed to a per-scrollbar flag.
Note that the patch is local in Fl_Scrollbar mousewheel event handling since this had already the distinction of horizontal and vertical scrollbars. | |
|
#10 | AlbrechtS 05:42 May 17, 2019 |
| Request to test: can anybody with a device with a "scroll ball" or something that allows horizontal and vertical "mousewheel" movement together please test what happens if you press SHIFT while moving the scroll ball (or other device)?
My tests with test/scroll under Linux worked as expected. I'm going to test Windows as well and I'll report if anything is different.
Manolo, can you please test the patch with your different macOS platforms (including X11) as you did before? TIA. | |
|
#11 | AlbrechtS 05:43 May 17, 2019 |
| @mid-kid: does this patch work as you expected? | |
|
#12 | mid-kid 06:44 May 17, 2019 |
| Yeah, this works exactly like I'd expect it to, with both a regular scrollwheel, a multitouch touchpad and a pointing stick. The latter two devices support doing the horizontal and vertical movement together, and they work as expected, as well.
This was tested on Linux X11, with the touchpad using the synaptics driver, and the pointing stick using libinput. | |
|
#13 | AlbrechtS 07:31 May 17, 2019 |
| Thanks for your quick feedback! | |
|
#14 | manolo 09:49 May 18, 2019 |
| The patch on macOS and under XQuartz (X server on macOS) has the consequence that both wheel and shift-wheel have the same effect: the vertical scrollbar is activated, and no effect on the horizontal scrollbar.
That is expected because without the patch, shift-wheel was treated by the OS as a horizontal move. | |
|
#15 | AlbrechtS 12:10 May 18, 2019 |
| Well, this seems to be more complicated than anticipated. Basically I think that my simple approach doesn't work - we need a platform specific patch instead.
As I understand it now macOS does the horizontal/vertical swap for us even before the event reaches FLTK. Hence I conclude that we need to do the same (swap horizontal/vertical) for scrollwheel events on Windows and Linux in FLTK. Note that (according to the FLTK code I investigated) both Windows and Linux have builtin "horiontal mousewheel" support, but this doesn't help users with a simple mouse with only one wheel. Only for the latter we'll do "horizontal mousewheel emulation with Shift key".
I don't think we can resolve the issue for the XQuartz and/or VirtualBox under macOS case though. If we handle these cases in our X11 event handling *and* macOS does its own swapping *before* XQuartz or VirtualBox "see" the event then we'll always get a double swap, i.e. we can't handle the "horizontal mousewheel emulation" - unless we also have a user/system option to disable "horizontal mousewheel emulation" at runtime for users on these platforms.
I'll work on a better (platform specific) patch later. | |
|
#16 | manolo 00:14 May 19, 2019 |
| I tried to process wheel+shift events as equivalent to horizontal movements by doing this starting at line #1973 of file src/Fl_x.cxx :
case ButtonPress: Fl::e_keysym = FL_Button + xevent.xbutton.button; set_event_xy(window); Fl::e_dx = Fl::e_dy = 0; if (xevent.xbutton.button == Button4) { Fl::e_dy = -1; // Up event = FL_MOUSEWHEEL; } else if (xevent.xbutton.button == Button5) { Fl::e_dy = +1; // Down event = FL_MOUSEWHEEL; } else if (xevent.xbutton.button == 6 || (xevent.xbutton.button == Button4 && xevent.xbutton.state & ShiftMask)) { Fl::e_dx = -1; // Left event = FL_MOUSEWHEEL; } else if (xevent.xbutton.button == 7 || (xevent.xbutton.button == Button5 && xevent.xbutton.state & ShiftMask)) { Fl::e_dx = +1; // Right event = FL_MOUSEWHEEL; } else { Fl::e_state |= (FL_BUTTON1 << (xevent.xbutton.button-1)); event = FL_PUSH; checkdouble(); }
But, on my setup which is Ubuntu within Virtualbox on macOS, something swallows altogether events when the mouse wheel is moved AND shift is pressed: function fl_handle(const XEvent& ) doesn't even run. That is possibly caused by VirtualBox on macOS since you report that shift+wheel with the patched Fl_Scrollbar.cxx does activate the horizontal scroll with VirtualBox on windows. | |
|
#17 | manolo 08:55 May 27, 2019 |
| Here is the outcome of 3 further tests.
1) with Ubuntu in VirtualBox under MacOS I used xev to see what X events occur. - moving the mouse wheel up and down produces ButtonPress/ButtonRelease pairs for buttons 4 and 5, respectively. - pressing shift and moving the mouse wheel: xev sees no X event whatsoever (besides KeyPress when shift is pressed)
2) remote logging to a Debian system with X display to a local macOS using XQuartz, an X server. I used xev to see what X events occur. - moving the mouse wheel up and down produces ButtonPress/ButtonRelease pairs for buttons 4 and 5, respectively. - pressing shift and moving the mouse wheel produces ButtonPress/ButtonRelease pairs for buttons 6 and 7, respectively.
3) same remote logging to a Debian system with local X display and running the **unmodified** test/scroll FLTK program: - moving the mouse wheel scrolls vertically - pressing shift and moving the mouse wheel scrolls horizontally
I conclude that the change in function fl_handle() of src/Fl_x.cxx proposed in comment #16 above may be the solution for the X11 FLTK platform. But testing it on a genuine Linux system without VirtualBox in between is necessary. | |
|
#18 | manolo 12:44 May 28, 2019 |
| Attached file #2 (scroll.patch) is a proposed solution for the X11 and Windows platforms.
It's been tested OK under Ubuntu (and also under macOS + XQuartz). It still needs testing under Windows. | |
|
#19 | manolo 14:14 May 28, 2019 |
| scroll patch is also OK for the Windows platform. | |
|
#20 | AlbrechtS 08:22 May 29, 2019 |
| Thanks for the patch and sorry for the delay on my side, I'm pretty busy with other projects.
I tested the patch on Ubuntu 18.04 (as before in my VirtualBox VM, although on another Windows 10 box) and it works as expected.
The Windows patch however inverts the scroll direction of Shift+Mousewheel events.
Linux: mousewheel down -> right, mouswheel up -> left as expected. Windows: mousewheel down -> left, mouswheel up -> right *unexpected*.
We need to make this consistent across platforms. I believe this is due to the "simple" patch approach that doesn't honor the /inverted/ wParam value WRT WM_MOUSEWHEEL vx. WM_MOUSEHWHEEL events.
WM_MOUSEWHEEL: "A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user." [1]
i.e. positive -> up, negative -> down.
WM_MOUSEHWHEEL: "A positive value indicates that the wheel was rotated to the right; a negative value indicates that the wheel was rotated to the left." [2]
i.e. positive -> right, negative -> left.
So AFAICT the WM_MOUSEHWHEEL event implementation is correct but the "simplified FALLTHROUGH patch" doesn't work correctly.
@Manolo: how does the (unpatched) macOS implementation of Shift+Mousewheel work? Is it like the description of Linux above, or is it like the (inverted) Windows description above?
------ [1] https://docs.microsoft.com/en-us/windows/desktop/inputdev/wm-mousewheel [2] https://docs.microsoft.com/en-us/windows/desktop/inputdev/wm-mousehwheel | |
|
#21 | AlbrechtS 08:38 May 29, 2019 |
| FWIW, here's my take on this issue. According to MS docs the MK_SHIFT bit is set if Shift is pressed during the event. I'm using this to invert the wParam value of the WM_MOUSEHWHEEL event which is also executed in the FALLTHROUGH case (WM_MOUSEWHEEL with Shift):
// FALLTHROUGH case WM_MOUSEHWHEEL: { static int delta = 0; // running total of all motion // ** new code starts below int wparam = (SHORT)(HIWORD(wParam)); if (LOWORD(wParam) & MK_SHIFT) wparam = -wparam; delta += wparam; // ** new code ends above Fl::e_dy = 0; Fl::e_dx = delta / WHEEL_DELTA; delta -= Fl::e_dx * WHEEL_DELTA; if (Fl::e_dx) Fl::handle(FL_MOUSEWHEEL, window); return 0; }
This patch, however, has the side effect that it would also invert the scroll /direction/ of real horizontal mousewhee levents (WM_MOUSEHWHEEL).
It works, but I'm not entirely satisfied with this approach. Maybe we need a longer but more explicit patch. Ideas? | |
|
#22 | manolo 06:03 May 30, 2019 |
| The scroll direction of Shift+Mousewheel events is the same on Linux and macOS (and also with XQuartz on macOS where the FLTK X11 platform runs on macOS).
More about X11 under macOS: the patch has no effect because the OS somehow transforms button4+shift into button6 and button5+shift into button7. Thus, both the unpatched and the patched code process mouse-wheel events identically, that is, as Linux does. | |
|
#23 | manolo 06:16 May 30, 2019 |
| That slightly modified code could avoid to invert the scroll /direction/ of real horizontal mousewheel events:
// FALLTHROUGH case WM_MOUSEHWHEEL: { static int delta = 0; // running total of all motion int wparam = (SHORT)(HIWORD(wParam)); if ( (LOWORD(wParam) & MK_SHIFT) && uMsg == WM_MOUSEWHEEL) wparam = -wparam; delta += wparam; Fl::e_dy = 0; Fl::e_dx = delta / WHEEL_DELTA; delta -= Fl::e_dx * WHEEL_DELTA; if (Fl::e_dx) Fl::handle(FL_MOUSEWHEEL, window); return 0; }
Untested though. | |
|
#24 | AlbrechtS 08:55 Aug 13, 2023 |
| I committed two changes, one for Linux (X11) and one for Windows:
- commit 8c5c7aa7f43ac3ccbcee3c56629022a9643e2ab9 Handle shift + mousewheel event on Linux (STR 3521)
- commit 847901623a55d69fc8c0c4b7770ec33698402e3a Handle shift + mousewheel event on Windows (STR 3521)
There is no need to change anything on macOS because the OS handles the shift key and sends the correct events.
I hope that these commits do everything correctly, including the correct motion direction. If this should not be the case, please open a GitHub Issue.
I'm closing this STR now as completed because these commits fix the issue as reported and discussed although the solution for the new Wayland platform is not yet available. | |
|
#25 | AlbrechtS 08:03 Aug 14, 2023 |
| Fixed in Git repository.
Final update: commit 3c7610ec2336a2ab2b264d73feca89afbcfc61d2 implements the new behavior on the Wayland platform.
Summary of commits:
commit 8c5c7aa7f43ac3ccbcee3c56629022a9643e2ab9 Unix/Linux (X11 only) commit 847901623a55d69fc8c0c4b7770ec33698402e3a Windows commit 3c7610ec2336a2ab2b264d73feca89afbcfc61d2 Wayland | |