STR #3521

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 Home  |  Articles & FAQs  |  Bugs & Features  |  Documentation  |  Download  |  Screenshots  ]

Return to Bugs & Features ]

STR #3521

Application:FLTK Library
Status:1 - Closed w/Resolution
Priority:1 - Request for Enhancement, e.g. asking for a feature
Scope:3 - Applies to all machines and operating systems
Subsystem:Core Library
Summary:Allow shift+scroll for horizontal scrolling
Created By:mid-kid
Assigned To:AlbrechtS
Fix Version:1.4.0
Fix Commit:3c7610ec2336a2ab2b264d73feca89afbcfc61d2
Update Notification:

Receive EMails Don't Receive EMails

Trouble Report Files:

Name/Time/Date Filename/Size top right image
#1 AlbrechtS
05:37 May 17, 2019
#2 manolo
12:42 May 28, 2019
bottom left image   bottom right image

Trouble Report Comments:

Name/Time/Date Text top right image
#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
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;
    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;

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?

#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:

      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
bottom left image   bottom right image

Return to Bugs & Features ]


Comments are owned by the poster. All other content is copyright 1998-2023 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to ''.