jetperch / pyjoulescope_ui

Joulescope graphical user interface
https://www.joulescope.com
Apache License 2.0
86 stars 26 forks source link

Add support for high resulution scrolling to move/zoom the trace #289

Closed diggit closed 1 month ago

diggit commented 2 months ago

Joulescope model

JS220

UI version

other

Your idea

Hi, my mouse (Logitech MX Master 3S) has a high resolution scroll wheel with much finer step than regular mouse. It would be nice to support it and zoom/move traces with finer step when possible. I recorded libinput events of my mouse here. On linux you can replay it by libinput replay filename

Version info

UI: 1.1.10 driver: 1.5.5 JLS: 0.10.0 Python: 3.12.5 (main, Aug 9 2024, 08:20:41) [GCC 14.2.1 20240805] Platform: Linux-6.10.6-arch1-1-x86_64-with-glibc2.40

Does your idea concern a specific OS?

No response

mliberty1 commented 1 month ago

Hi @diggit - Thanks for the feature request!

If you use the high resolution scroll wheel today with the Joulescope UI, does anything happen?

Ideally, the "high resolution" scroll wheel events would come through as scroll wheel events, which we already handle [source code]. It looks like this code does presume ticks are 15 degrees, so we may need to modify this code.

If not, do you happen to know if there is a more general way to get this mouse to support high-resolution scrolling with Qt6? Ideally, it would come through Qt6 angleDelta. I know this is Windows-specific, but check out this stackoverflow post.

diggit commented 1 month ago

Thanks for pointing out where events come in. I modified the code a little bit to get the idea about math there...

    def plot_wheelEvent(self, event: QtGui.QWheelEvent):
        print("new event ---------------")
        print(f"_WHEEL_TO_DEGREES {_WHEEL_TO_DEGREES}")
        print(f"_WHEEL_TICK_DEGREES {_WHEEL_TICK_DEGREES}")
        x_name, y_name = self._target_lookup_by_pos(self._mouse_pos)
        delta = np.array([event.angleDelta().x(), event.angleDelta().y()], dtype=np.float64)
        print(f"delta1 {delta}")
        delta *= _WHEEL_TO_DEGREES
        print(f"delta2 {delta}")
        self._wheel_accum_degrees += delta
        incr = np.fix(self._wheel_accum_degrees / _WHEEL_TICK_DEGREES) # this rounding causes the issue
        self._wheel_accum_degrees -= incr * _WHEEL_TICK_DEGREES
        x_delta, y_delta = incr
        delta = y_delta
        print(f"delta3 {delta}")

and with hires scrollwheel

new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 64.]
delta2 [0. 8.]
delta3 0.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 16.]
delta2 [0. 2.]
delta3 0.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 16.]
delta2 [0. 2.]
delta3 0.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 16.]
delta2 [0. 2.]
delta3 0.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 16.]
delta2 [0. 2.]
delta3 1.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 16.]
delta2 [0. 2.]
delta3 0.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 16.]
delta2 [0. 2.]
delta3 0.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 16.]
delta2 [0. 2.]
delta3 0.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 16.]
delta2 [0. 2.]
delta3 0.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 16.]
delta2 [0. 2.]
delta3 0.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 16.]
delta2 [0. 2.]
delta3 0.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [ 0. 16.]
delta2 [0. 2.]
delta3 1.0

regular mouse

new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [  0. 120.]
delta2 [ 0. 15.]
delta3 1.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [  0. 120.]
delta2 [ 0. 15.]
delta3 1.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [  0. 120.]
delta2 [ 0. 15.]
delta3 1.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [  0. 120.]
delta2 [ 0. 15.]
delta3 1.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [  0. 120.]
delta2 [ 0. 15.]
delta3 1.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [  0. 120.]
delta2 [ 0. 15.]
delta3 1.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [  0. 120.]
delta2 [ 0. 15.]
delta3 1.0
new event ---------------
_WHEEL_TO_DEGREES 0.125
_WHEEL_TICK_DEGREES 15.0
delta1 [  0. 120.]
delta2 [ 0. 15.]
delta3 1.0

culprit is this line

        incr = np.fix(self._wheel_accum_degrees / _WHEEL_TICK_DEGREES) # this rounding causes the issue

What is the goal of this rounding?

mliberty1 commented 1 month ago

@diggit - So it sounds like your high resolution scroll wheel is reporting scroll wheel events to Qt and the Joulescope UI, right? If I am interpreting the output above correctly, the high resolution scroll wheel has a minimum step size of 2° rather than 15° for a standard scroll wheel.

Looking at the code, the goal is to convert from degrees to integer delta steps. For example, when you press the +, -, ←, → keys, they each change the view by one step. The corresponding actions x_pan, x_zoom, y_pan, y_zoom all operate on these integer steps. We could modify these to operate on float fractional steps, too.

mliberty1 commented 1 month ago

Turns out my wife has a Logitech MX Master 3. I tried it on Windows, but I cannot figure out how to use the high resolution scroll as you are doing. Here is Logi Options+: image

I have the thumb wheel set for Horizontal scroll, which works, but only in 15 deg increments, even at 1%.

How can I duplicate what you are doing?

diggit commented 1 month ago

I am on Linux, all inputs are handled by libinput. I am on wayland (sway), but that should not matter. Also, I have it connected via Bluetooth. IIRC there is some quirk in libinput which disables hires scrolling with that dongle.

On windows, I had to enable hires scrolling in that app for specific apps (eg firefix), but never tried it with Qt based app and I have very little experience with this mouse on windows.

On my setup MX master 3S reports 15 degrees and more per event. It depends on scrolling speed.

diggit commented 1 month ago

@mliberty1 I just tested 1.1.11 and high resolution scrolling is working. Normal scroll wheel mouse still works well. Thank you!