<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <p>
      <meta http-equiv="content-type" content="text/html; charset=utf-8">
    </p>
    <p>
      <title>Proposal on enhancing MouseWheelEvent to include absolute
        scrolling delta</title>
      <meta name="generator" content="LibreOffice 5.1.4.2 (Windows)">
      <style type="text/css">
                @page { margin: 2cm }
                p { margin-bottom: 0.25cm; line-height: 120% }
                a:link { so-language: zxx }
        </style> </p>
    <p style="margin-bottom: 0cm; line-height: 115%">Hi All,</p>
    <p style="margin-bottom: 0cm; line-height: 115%">Next follows a
      proposal on enhancing <tt>MouseWheelEvent</tt> to include
      absolute scrolling delta.</p>
    <p style="margin-bottom: 0cm; line-height: 115%">My name is Pavel
      Fatin, I work at JetBrains (IntelliJ IDEA). Although this is my
      first message here, I have been working with Java / AWT / Swing
      since Java 1.2 and have some in-depth experience (for example, my
      research on <a
        href="https://pavelfatin.com/low-latency-painting-in-awt-and-swing/">low-latency
        painting in AWT and Swing</a>).</p>
    <p style="margin-bottom: 0cm; line-height: 115%">Because we at
      JetBrains receive many <a
        href="https://youtrack.jetbrains.com/issue/IDEA-76396">requests</a>
      to implement smooth-scrolling in IDEA, as an experiment, we <a
href="https://github.com/JetBrains/intellij-community/commit/34b9dfd0585937c3731e06a89554d1dc86f7f235">extended</a>
      our custom scroll pane class to handle <tt>MouseWheelEvent</tt>'s
      <a
href="https://docs.oracle.com/javase/8/docs/api/java/awt/event/MouseWheelEvent.html#getPreciseWheelRotation--">getPreciseWheelRotation()</a>
      data (that method was introduced in Java 7, but it’s not yet used
      by AWT / Swing directly). As a result, the scrolling "smoothness"
      and precision improved substantially, however on OS X it was still
      a far cry from the native scrolling experience, particularly:</p>
    <ul>
      <li>
        <p style="margin-bottom: 0cm; line-height: 115%">Scrolling speed
          was unit-dependent (while in OS X it's not). The concept of
          "wheel rotation" is inherently tied to the idea of "scrolling
          unit" (usually 1 or 3 lines). This makes sense for a real
          mouse scrolling wheel, but doesn't make much sense for a
          touchpad – one expects a uniform mapping between physical
          touch gesture and a screen update, consistent across different
          applications. The same goes for touchscreen interfaces.
          Introduction of the fractional wheel rotations increases
          precision but still retains the "rotation-unit" bound.</p>
      </li>
      <li>
        <p style="margin-bottom: 0cm; line-height: 115%">Spatial
          precision was lacking. Typical scrolling deltas were in range
          0.5..>10, and this was only a slight improvement over
          1..>10 deltas.</p>
      </li>
      <li>
        <p style="margin-bottom: 0cm; line-height: 115%">Temporal
          resolution was lacking, so the scrolling was rather
          coarse-grained and there was a substantial lag between
          starting a gesture and a reaction on the screen. This mostly
          stems from the insufficient spatial resolution. Added
          interpolation helped to artificially increase spatial- and
          temporal resolutions, but couldn't solve the input lag and the
          lack of positioning precision.</p>
      </li>
    </ul>
    <p style="margin-bottom: 0cm; line-height: 115%">Wondering how the
      native OS X applications can perform much better we started to
      investigate the Cocoa API. It turns out, that since Mac OS X 10.7
      (Lion) <a
        href="https://developer.apple.com/reference/appkit/nsevent">NSEvent</a>,
      in addition to the <a
href="https://developer.apple.com/reference/appkit/nsevent/1534871-deltax">deltaX</a>
      and <a
href="https://developer.apple.com/reference/appkit/nsevent/1534158-deltay">deltaY</a>
      introduced <a
href="https://developer.apple.com/reference/appkit/nsevent/1524505-scrollingdeltax">scrollingDeltaX</a>
      and <a
href="https://developer.apple.com/reference/appkit/nsevent/1535387-scrollingdeltay">scrollingDeltaY</a>
      properties that supply high-resolution scrolling information (with
      <a
href="https://developer.apple.com/reference/appkit/nsevent/1525758-hasprecisescrollingdeltas">hasPrecisionScrollingDeltas</a>
      property that specifies how to interpret the data). So far so
      good, but those properties are quite a different beast – they
      contain <i>absolute</i> scrolling deltas rather than relative
      deltas, supplied by the previous values.</p>
    <p style="margin-bottom: 0cm; line-height: 115%">How can we
      integrate such values in the existing Java API?</p>
    <p style="margin-bottom: 0cm; line-height: 115%">One way is to try
      to somehow translate the absolute deltas to relative "wheel
      rotations", but the wheel event per se represents input data and
      doesn't deal with possible scrolling units as such. Another
      problem with this approach is that OS might provide so-called
      "pixel-perfect" scrolling, where smallest delta is guaranteed to
      be 1 pixel (yet still preserving large-distance scrolling via
      OS-level acceleration), as OS knows real physical resolution of
      particular input / output devices and the acceleration curve, and
      such a translation cannot reliably handle this. And one more
      problem with the masking is compatibility – because the new data
      have much more temporal resolution, existing applications that
      process precise wheel events synchronously might be overwhelmed,
      hog CPU and lag unnecessarily. All in all, "partial wheel
      rotation" is an imperfect and "leaky" abstraction for the absolute
      scrolling delta.</p>
    <p style="margin-bottom: 0cm; line-height: 115%">A possible "hack"
      is to put the absolute values directly into the relative delta
      property and then to hardcode unit size to be 1 on Mac OS (that is
      what GTK+ 3 <a
href="https://github.com/GNOME/gtk/blob/master/gtk/gtkscrolledwindow.c#L1245">does</a>),
      but that is what it is – a hack, not compatible with the existing
      codebase.</p>
    <p style="margin-bottom: 0cm; line-height: 115%">It seems, that the
      most reasonable solution is to introduce a new, "absolute" kind of
      scrolling deltas, in addition to the relative one. That is, for
      example, what <a href="https://goo.gl/kZqxVc">QWheelEvent</a>
      does with its <a href="https://goo.gl/zwxBt9">angleDelta</a> and
      <a href="https://goo.gl/F5A37V">pixelDelta</a> properties. We
      tried that approach in our JetBrains Runtime by <a
href="https://github.com/JetBrains/jdk8u_jdk/commit/568f2dae82b0fe27b79ce6943071d89463758610">extending</a>
      <tt>MouseWheelEvent</tt> with <tt>getScrollingDelta()</tt> method
      and <a
href="https://github.com/JetBrains/jdk8u_jdk/commit/a3cb8807b148879e9c70a74a8a16c30a28991581">implementing</a>
      it in Mac OS – the result is a genuine, OSX-like scrolling
      experience in Java.</p>
    <p style="margin-bottom: 0cm; line-height: 115%">We chose the method
      name “getScrollingDelta” (a la Apple) instead of “getPixelDelta”
      (a la Qt) because the input event by itself doesn't necessarily
      results in display scrolling, and because the concept of "pixel"
      is not that precise. Likewise, we chose <tt>double</tt> type for
      further extensibility, considering the case with <tt>getWheelDelta()</tt>
      (<tt>NSEvent</tt> also uses a floating point value).</p>
    <p style="margin-bottom: 0cm; line-height: 115%">It should be noted,
      that the absolute delta <i>complements</i> rather than replaces
      the relative value. Those two values are not interchangeable and
      OS generates the values separately (for legacy devices only the
      relative delta is generated and, in such cases, we can use 0 as an
      absolute one). Addition of the absolute scrolling delta fully
      preserves the functioning of Java's existing event processing
      mechanisms.</p>
    <p style="margin-bottom: 0cm; line-height: 115%">Although currently
      only Mac OS supplies that kind of data, Windows Precision Touchpad
      and XInput2 / libinput might follow, as smooth scrolling becomes a
      thing nowadays. Additionally, touchscreen-based scrolling needs
      precisely this kind of scrolling deltas.</p>
    <p style="margin-bottom: 0cm; line-height: 115%">While we may
      implement this functionality privately in our JetBrains Runtime,
      we believe that more people can benefit from it. Moreover, the
      enhancement of <tt>MouseWheelEvent</tt> to support pixel-perfect
      scrolling can pave a road for smooth scrolling in AWT and Swing
      (which is a good thing to improve usability, both GTK+ 3 and Qt 5
      already support that).</p>
    <pre class="moz-signature" cols="72">-- 
Sincerely, Pavel</pre>
  </body>
</html>