Menu

#2449 Horizontal scrolling with mouse is backwards

Bug
closed-fixed
nobody
5
2024-10-19
2024-10-01
Dustin Luck
No

When using a touchpad or mouse that supports horizontal scrolling, the Scintilla editor window scrolls the opposite way of what is expected. In this case, expected refers to the behavior of the vast majority of Windows applications that support horizontal scrolling (web browsers, text editors, etc.). The behavior is as expected when using Shift + Scroll Up/Down.

I have seen this behavior in SciTE as well as other applications that use the Scintilla library.

Platform: Win11

I have coded a fix for this issue but haven't figured out how to submit a pull request in SourceForge. I have instead attached the code change to \win32\ScintillaWin.cxx as a patch file.

1 Attachments

Discussion

  • Zufu Liu

    Zufu Liu - 2024-10-02

    The document for WM_MOUSEHWHEEL says:
    https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-mousehwheel

    The high-order word indicates the distance the wheel is rotated, expressed in multiples or factors of WHEEL_DELTA, which is set to 120. A positive value indicates that the wheel was rotated to the right; a negative value indicates that the wheel was rotated to the left.

    See https://github.com/zufuliu/notepad4/issues/609, here needs a way to read scroll direction.

     
    • Dustin Luck

      Dustin Luck - 2024-10-08

      Not sure if this reply was meant to contradict what was reported, support it, or spur further discussion.

      Here is a full explanation of how scrolling is currently implemented and why reversing the sign of charsToScroll when the mouse event is triggered by WM_MOUSEHWHEEL (the change in the patch file) corrects the issue.

      Vertical scrolling: WM_MOUSEWHEEL produces a positive value when scrolled up (away from the user) and negative when scrolled down (toward the user). The Accumulate method of MouseWheelData (line 59 in PlatWin.h (sourceforge.net)) reverses that value. Therefore, when the vertical mouse wheel is scrolled down, the scrollbar moves down (the negative value has turned to positive and the scrollbar position moves away from the 0 position, which is the top, to the maximum value position which is the bottom). The reverse happens when the vertical mouse wheel is scrolled up. This is correct and expected behavior.

      Horizontal scrolling: WM_MOUSEHWHEEL produces a positive value when scrolled right and negative when scrolled left. The Accumulate method of MouseWheelData (line 59 in PlatWin.h (sourceforge.net)) reverses that value. Therefore, when the horizontal mouse wheel is scrolled left, the scrollbar moves right (the negative value has turned to positive and the scrollbar position moves away from the 0 position, which is the left, to the maximum value position which is the right). The reverse happens when the horizontal mouse wheel is scrolled right. This is incorrect and unexpected behavior.

       
  • Zufu Liu

    Zufu Liu - 2024-10-09

    WM_MOUSEHWHEEL produces a positive value when scrolled right and negative when scrolled left.

    Is this still true when scroll direction is reversed? see https://github.com/zufuliu/notepad4/issues/609#issuecomment-1417413299

     
    • Dustin Luck

      Dustin Luck - 2024-10-09

      I can't find any documentation that definitively states how the system handles the scroll direction. However, I can provide what I see on my system.

      When the scroll direction is reversed, the Windows OS reverses the scroll wheel messages. This changes all of the logic in my previous post for both horizontal and vertical scrolling as expected. There is no special handling that applications need to do when the scroll direction is reversed.

      EDIT: I have a touchpad and a mouse with a vertical scroll wheel (but no horizontal) connected to the same laptop. I can confirm that the scroll direction only applies to my touchpad and not to the mouse.

       

      Last edit: Dustin Luck 2024-10-09
  • Zufu Liu

    Zufu Liu - 2024-10-10

    Maybe be better patch, needs comments/references for reverse direction.

    - const int charsToScroll = charsPerScroll * wheelDelta.Actions();
    + int charsToScroll = charsPerScroll * wheelDelta.Actions();
    + if (iMessage == WM_MOUSEHWHEEL) {
    +   // horizontal wheelDelta has opposite sign/direction
    +   charsToScroll = -charsToScroll;
    + }
    
     

    Last edit: Zufu Liu 2024-10-11
    • Dustin Luck

      Dustin Luck - 2024-10-10

      Looks good.

       
  • Neil Hodgson

    Neil Hodgson - 2024-10-11

    With a Logitech MX Master 3S mouse, the horizontal scroll wheel mostly does not produce WM_MOUSEHWHEEL messages. It commonly produces one WM_MOUSEHWHEEL but after that WM_HSCROLL messages with SB_LINELEFT or SB_LINERIGHT are seen. This means that the scroll direction is not affected by the WM_MOUSEHWHEEL code in ScintillaWin::MouseMessage in this scenario. It is likely that some component, possibly the Logi Options+ software, is intercepting and interpreting the horizontal scroll wheel. For SciTE, there is different behaviour for the main Scintilla windows and the one in the about box.

    Searching the web produced several mentions that a non-zero value should be returned from the message handler instead of the 0 documented.

     
  • Neil Hodgson

    Neil Hodgson - 2024-10-13
    • status: open --> open-fixed
     
  • Neil Hodgson

    Neil Hodgson - 2024-10-13

    Committed with [e9007d]. Also changed return value with [451b3c] to make this work for me and possibly other users of Logitech mice.

     

    Related

    Commit: [451b3c]
    Commit: [e9007d]

    • Zufu Liu

      Zufu Liu - 2024-10-14

      Also changed return value

      It seems better to limit it to Logi mouse (mouse returns 1 and touchpad returns 0 are the tested combinations):

      @@ -171,6 +171,14 @@
          }
       }
      
      +inline bool IsMouseEvent() noexcept {
      
      +   // Distinguishing Pen Input from Mouse and Touch
      +   // https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages
      +   constexpr DWORD MI_WP_SIGNATURE = 0xFF515700;
      +   constexpr DWORD SIGNATURE_MASK = 0xFFFFFF00;
      +   return (::GetMessageExtraInfo() & SIGNATURE_MASK) != MI_WP_SIGNATURE;
      +}
      +
       /**
        */
       class FormatEnumerator final : public IEnumFORMATETC {
      @@ -1653,7 +1661,8 @@
                      const int widthToScroll = static_cast<int>(std::lround(charsToScroll * vs.aveCharWidth));
                      HorizontalScrollToClamped(xOffset + widthToScroll);
                  }
      -           return 1;
      +           // return 1 for Logitech mouse, https://www.pretentiousname.com/setpoint_hwheel/index.html
      +           return ((iMessage == WM_MOUSEHWHEEL) && IsMouseEvent()) ? 1 : 0;
              }
      
              // Either SCROLL vertically or ZOOM. We handle the wheel steppings calculation
      
       
  • Neil Hodgson

    Neil Hodgson - 2024-10-15

    Tried the touchpad on a Logitech K400R keyboard with a tracepoint on the result of GetMessageExtraInfo and with 2-finger horizontal scrolling it is always 0, just like the horizontal scroll wheel on the MX Master 3S mouse. It is possible that laptop touchpads return something else but that should be checked.

    Notepad++ has some mouse wheel handling code in PowerEditor\src\ScintillaComponent\ScintillaEditView.cpp that looks for a Synaptics touchpad driver.

     
  • Zufu Liu

    Zufu Liu - 2024-10-16

    As tested at https://github.com/zufuliu/notepad4/issues/609, returns 1 for WM_MOUSEHWHEEL also works for Touchpad, safe change to avoid potential break for WM_MOUSEWHEEL:

    - return 1;
    + // return 1 for Logitech mouse, https://www.pretentiousname.com/setpoint_hwheel/index.html
    + return (iMessage == WM_MOUSEHWHEEL) ? 1 : 0;
    
     
    • Neil Hodgson

      Neil Hodgson - 2024-10-16
       

      Related

      Commit: [94aff7]

  • Neil Hodgson

    Neil Hodgson - 2024-10-19
    • status: open-fixed --> closed-fixed
     

Log in to post a comment.

MongoDB Logo MongoDB