Bug 99648 - Disappearing events for buttons 4 and 5
Summary: Disappearing events for buttons 4 and 5
Status: RESOLVED MOVED
Alias: None
Product: xorg
Classification: Unclassified
Component: Input/libinput (show other bugs)
Version: unspecified
Hardware: x86-64 (AMD64) Linux (All)
: medium normal
Assignee: Peter Hutterer
QA Contact: Xorg Project Team
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-02-02 13:39 UTC by momboisse.alain
Modified: 2018-08-10 20:56 UTC (History)
1 user (show)

See Also:
i915 platform:
i915 features:


Attachments

Description momboisse.alain 2017-02-02 13:39:26 UTC
Hello

I'm a Slackware-current user ; I've just "migrated" from xf86-input-evdev to xf86-input-libinput 0.23.0 ( + libinput 1.5.4 + xorg-server 1.19.1 ) and X "eats" the first scroll event, each time the scroll direction changes.

One simple example :
 * before (with evdev), when I wanted to change virtual desktops, I moved my mouse pointer over the root window and scrolled. Once. And it worked immediately.
 * now (with libinput), I move the mouse pointer over the root window and scroll. And maybe if I'm lucky it changes virtual desktops, and maybe not.

Any other examples :
 * move the mouse pointer over a window with a scrollbar, scroll repeatedly up/down/up/down and nothing will move

I use a mouse (not a touchpad) and I haven't tested this with a touchpad (yet).
This particular hardware works just fine with xf86-input-evdev (2.10.4 in my case, but it has been working normally for years with previous versions).

xev shows that the event is not even generated (nothing appears when I "scroll" inside its window), meaning it's not hardware-related nor application-related : there's something in libinput or the drivers that ignores a button press when it's pressed for the first time after the press of another button.
Comment 1 Peter Hutterer 2017-02-03 03:41:11 UTC
hmm, not sure what's happening there. I just tested this locally and it works fine. Please try to verify it by doing the following:

Figure out the event node, sudo evemu-record lists them all. Mine is event7, replace below accordingly.

start two terminals, start xev in one.
in the other one, run these commands as a script:

sleep 10
sudo evemu-event /dev/input/event7 --sync --type EV_REL --code REL_WHEEL --value -1
sudo evemu-event /dev/input/event7 --sync --type EV_REL --code REL_WHEEL --value -1
sleep 10
sudo evemu-event /dev/input/event7 --sync --type EV_REL --code REL_WHEEL --value 1
sudo evemu-event /dev/input/event7 --sync --type EV_REL --code REL_WHEEL --value 1


during the first sleep, move to the xev window, hands off your mouse, monitor the xev output. You should get two scroll events, a 10s sleep, two scroll events in the other direction. This is what happens here, do you see any other output?

Please attach an evemu-record of a scroll in both directions (2 clicks each direction please) and the output of udevadm info /sys/class/input/eventX with the device's event node.
Comment 2 momboisse.alain 2017-02-03 10:08:47 UTC
# evemu-record
Available devices:
(blah)
/dev/input/event11:	Logitech M570
Select the device event number [0-11]: 11
# EVEMU 1.3
# Kernel: 4.8.10
(blah)
################################
#      Waiting for events      #
################################
E: 0.000001 0002 0008 -001	# EV_REL / REL_WHEEL            -1
E: 0.000001 0000 0000 0000	# ------------ SYN_REPORT (0) ---------- +0ms
E: 0.296008 0002 0008 -001	# EV_REL / REL_WHEEL            -1
E: 0.296008 0000 0000 0000	# ------------ SYN_REPORT (0) ---------- +296ms
E: 1.304031 0002 0008 0001	# EV_REL / REL_WHEEL            1
E: 1.304031 0000 0000 0000	# ------------ SYN_REPORT (0) ---------- +1008ms
E: 2.038052 0002 0008 -001	# EV_REL / REL_WHEEL            -1
E: 2.038052 0000 0000 0000	# ------------ SYN_REPORT (0) ---------- +734ms
E: 2.656060 0002 0008 0001	# EV_REL / REL_WHEEL            1
E: 2.656060 0000 0000 0000	# ------------ SYN_REPORT (0) ---------- +618ms
E: 3.358089 0002 0008 -001	# EV_REL / REL_WHEEL            -1
E: 3.358089 0000 0000 0000	# ------------ SYN_REPORT (0) ---------- +702ms

Every event is correctly recorded. Scrolling Up /Down / Up / Down / ... correctly displays every event (1 for up, -1 for down). 

Now, with xev :

(blah)
FocusIn event, serial 36, synthetic NO, window 0x5e00001,
    mode NotifyNormal, detail NotifyNonlinear

KeymapNotify event, serial 36, synthetic NO, window 0x0,
    keys:  4294967263 0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   
           0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   

ButtonPress event, serial 36, synthetic NO, window 0x5e00001,
    root 0xdf, subw 0x0, time 2096017450, (100,75), root:(860,422),
    state 0x0, button 5, same_screen YES

ButtonRelease event, serial 36, synthetic NO, window 0x5e00001,
    root 0xdf, subw 0x0, time 2096017450, (100,75), root:(860,422),
    state 0x1000, button 5, same_screen YES

PropertyNotify event, serial 36, synthetic NO, window 0x5e00001,
    atom 0x13c (_NET_WM_STATE), time 2096017450, state PropertyNewValue

ButtonPress event, serial 36, synthetic NO, window 0x5e00001,
    root 0xdf, subw 0x0, time 2096020510, (100,75), root:(860,422),
    state 0x0, button 4, same_screen YES

ButtonRelease event, serial 36, synthetic NO, window 0x5e00001,
    root 0xdf, subw 0x0, time 2096020510, (100,75), root:(860,422),
    state 0x800, button 4, same_screen YES

KeyPress event, serial 36, synthetic NO, window 0x5e00001,
    root 0xdf, subw 0x0, time 2096024349, (100,75), root:(860,422),
    state 0x0, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

... and depending on the last scroll "state" (if I last scrolled up or down before executing evemu-event) I get two or four button 5 events (I count two for press + release)

Since evemu-record shows every event, and since xf86-input-evdev behaves correctly, do we rule out a possible problem with the way I compiled the kernel with support for the Logitech Unifying Receiver (HID_LOGITECH_DJ=m etc.) ?

FYIW this is what's inside /etc/X11/xorg.conf.d/50-pointer.conf :

Section "InputClass"
    Identifier "Logitech Wireless Trackball M570"
    MatchIsPointer "on"
#    MatchProduct "Logitech Unifying Device"
    MatchProduct "Logitech M570"
    Driver "libinput"
    # https://www.mankier.com/4/libinput
    Option "ScrollMethod" "button"
    Option "ScrollButton" "8"
#
#    Driver "evdev"
#    Option "EmulateWheel" "true"
#    Option "EmulateWheelButton" "8"
#    Option "YAxisMapping" "4 5"
#    Option "XAxisMapping" "6 7"
#    Option "ZAxisMapping" "4 5 6 7"
EndSection
Comment 3 momboisse.alain 2017-02-03 10:09:15 UTC
FWIW + FYI = ... ah crap !
Comment 4 momboisse.alain 2017-02-03 16:41:33 UTC
# udevadm info /sys/class/input/event11
P: /devices/pci0000:00/0000:00:14.0/usb3/3-5/3-5.1/3-5.1:1.2/0003:046D:C52B.00F0/0003:046D:1028.00F1/input/input85/event11
N: input/event11
S: input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse
S: input/by-path/pci-0000:00:14.0-usb-0:5.1:1.2-event-mouse
E: DEVLINKS=/dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse /dev/input/by-path/pci-0000:00:14.0-usb-0:5.1:1.2-event-mouse
E: DEVNAME=/dev/input/event11
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb3/3-5/3-5.1/3-5.1:1.2/0003:046D:C52B.00F0/0003:046D:1028.00F1/input/input85/event11
E: ID_BUS=usb
E: ID_INPUT=1
E: ID_INPUT_MOUSE=1
E: ID_MODEL=USB_Receiver
E: ID_MODEL_ENC=USB\x20Receiver
E: ID_MODEL_ID=c52b
E: ID_PATH=pci-0000:00:14.0-usb-0:5.1:1.2
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_5_1_1_2
E: ID_REVISION=1203
E: ID_SERIAL=Logitech_USB_Receiver
E: ID_TYPE=hid
E: ID_USB_DRIVER=usbhid
E: ID_USB_INTERFACES=:030101:030102:030000:
E: ID_USB_INTERFACE_NUM=02
E: ID_VENDOR=Logitech
E: ID_VENDOR_ENC=Logitech
E: ID_VENDOR_ID=046d
E: LIBINPUT_DEVICE_GROUP=3/46d/1028/111:usb-0000:00:14.0-5
E: MAJOR=13
E: MINOR=75
E: MOUSE_DPI=540@167
E: SUBSYSTEM=input
E: USEC_INITIALIZED=6389801557583
Comment 5 momboisse.alain 2017-02-03 16:55:12 UTC
The part of Xorg.0.log about /dev/input/event11

[2038427.694] (II) config/udev: Adding input device Logitech M570 (/dev/input/event11)
[2038427.694] (**) Logitech M570: Applying InputClass "libinput pointer catchall"
[2038427.694] (**) Logitech M570: Applying InputClass "Logitech Wireless Trackball M570"
[2038427.694] (II) Using input driver 'libinput' for 'Logitech M570'
[2038427.694] (**) Logitech M570: always reports core events
[2038427.694] (**) Option "Device" "/dev/input/event11"
[2038427.694] (**) Option "_source" "server/udev"
[2038427.694] (II) input device 'Logitech M570', /dev/input/event11 is tagged by udev as: Mouse
[2038427.694] (II) Device 'Logitech M570' set to 540 DPI
[2038427.694] (II) input device 'Logitech M570', /dev/input/event11 is a pointer caps
[2038427.709] (**) Option "ScrollMethod" "button"
[2038427.709] (**) Option "ScrollButton" "8"
[2038427.709] (**) Option "config_info" "udev:/sys/devices/pci0000:00/0000:00:14.0/usb3/3-5/3-5.1/3-5.1:1.2/0003:046D:C52B.00E9/0003:046D:1028.00EA/input/input82/event11"
[2038427.709] (II) XINPUT: Adding extended input device "Logitech M570" (type: MOUSE, id 9)
[2038427.709] (**) Option "AccelerationScheme" "none"
[2038427.709] (**) Logitech M570: (accel) selected scheme none/0
[2038427.709] (**) Logitech M570: (accel) acceleration factor: 2.000
[2038427.709] (**) Logitech M570: (accel) acceleration threshold: 4
[2038427.709] (II) input device 'Logitech M570', /dev/input/event11 is tagged by udev as: Mouse
[2038427.709] (II) Device 'Logitech M570' set to 540 DPI
[2038427.709] (II) input device 'Logitech M570', /dev/input/event11 is a pointer caps
[2038427.709] (II) config/udev: Adding input device Logitech M570 (/dev/input/mouse0)
[2038427.709] (**) Logitech M570: Applying InputClass "Logitech Wireless Trackball M570"
[2038427.709] (II) Using input driver 'libinput' for 'Logitech M570'
[2038427.709] (**) Logitech M570: always reports core events
[2038427.709] (**) Option "Device" "/dev/input/mouse0"
[2038427.709] (**) Option "_source" "server/udev"
[2038427.718] (II) failed to create input device '/dev/input/mouse0'.
[2038427.718] (EE) libinput: Logitech M570: Failed to create a device for /dev/input/mouse0
[2038427.718] (EE) PreInit returned 2 for "Logitech M570"
[2038427.718] (II) UnloadModule: "libinput"


The part of /usr/share/X11/xorg.conf.d/40-libinput.conf about "libinput pointer catchall" :

Section "InputClass"
        Identifier "libinput pointer catchall"
        MatchIsPointer "on"
        MatchDevicePath "/dev/input/event*"
        Driver "libinput"
EndSection
Comment 6 momboisse.alain 2017-02-04 01:02:04 UTC
Weird thing : I've just restarted X, and buttons 4 / 5 work correctly... until I press button 8 to scroll ! Only after that do I get the strange behaviour reported here.

So, the procedure to reproduce the bug seems to be :
 1. Open a new session on a freshly started X
 2. Start xev
 3. Scroll (with the wheel) up (once) / down (once) / up / down / etc.
 4. Every event is reported by xev
 5. Scroll (with the ScrollButton)
 6. Scroll (with the wheel) up (once) / down (once) / up / down / etc.
 7. No event is reported by xev
Comment 7 momboisse.alain 2017-02-04 01:12:19 UTC
Even weirder : the same mouse, connected to a portable computer, restores its "correct" scrolling behaviour when an event occurs through another device (AlpsPS/2 ALPS DualPoint Stick or AlpsPS/2 ALPS DualPoint TouchPad)

1. Scroll with the ScrollButton
2. Notice how xev displays nothing when scrolling (buttons 4 / 5 repeatedly) with the Logitech mouse
3. Press a button on the touchpad (or move the pointer with the stick, or whatever)
4. Notice how xev suddenly displays button event for buttons 4 / 5 on the Logitech mouse

What does the ScrollButton do, that any event on another device undoes ?
Comment 8 Peter Hutterer 2017-02-08 05:47:35 UTC
ok, this has to do with the smooth scroll vs button emulation in the server, in particular with mixing smooth scrolling and button emulation. And it only affects the legacy button emulation. 

For the button emulation on smooth scroll devices, we have an "increment" that defines what movement is 'one unit of scroll'. This defaults to 15 on a wheel in libinput and a wheel sends 15 units by default. So for each wheel we get a movement value of 15 and thus an emulated button event.

For smooth scrolling, scrolling is just an axis. Each movement translates into the axis motion. Say the axis is at 100, if you move 9 pixels down the axis is now at 109. And the XI2 valuators reflect that. But for backwards compat with core X apps, we emulate button events, with the same increment. So whenever you move down by 15 pixels, we send one button scroll event (in addition to the XI2 smooth scroll events). For this to work, we remember the last value we sent a button event for and continually add up the events until (last + new delta) > increment. Then we can send another scroll button event.

Independently, this works because:
* in pure wheel scrolling, the axis always increments by 15, triggering a button event on each movement
* in pure smooth scrolling, the axis smoothly increases, sending regular button events

You'll find that in smooth-scrolling, if you only slightly move up/down no button events are emulated because you're moving for less than 'one unit of scrolling'.

Ok, now to the problem at hand:
when you button-scroll first, you increase the axis value by pixels. Let's say you stop at 162. The last button event for this would've been sent at 150.

Now you scroll by the mouse wheel in the other direction - subtract 15. Your axis value is now 147, but that value is within 15 of the last event sent at 150. If you scroll down now you go back to 162 - also within 165 of the last event sent. That's why you get the button events discarded, it's the equivalent of moving slightly up/down without ever reaching the threshold.

this stops when you touch any other device because doing so resets the 'last scroll event sent at' value.

The only fix possible here would be to detect that the scroll method changed and thus reset the offset for incremental scrolling. This is something libinput allows us to do, we have the information. But we don't have an API in the server to allow for this.

Given my workload, your best chance of fixing this is to dive in yourself. Happy to help, but it's unlikely to make my todo list anytime soon.
Comment 9 momboisse.alain 2017-02-08 11:37:08 UTC
Wow. Perfect explanation. Thanks !

> The only fix possible here would be to detect that the scroll method changed
> and thus reset the offset for incremental scrolling.

In my case resetting it when the ScrollButton is released should be enough. Which other scroll method(s) could possibly leave the 'last scroll event sent at' value at something other than a multiple of 15 ?
Wait... If I get this right this value is absolute and not relative to the "starting point" of the movement initiated when the ScrollButton gets pressed ? Could a relative value fix all possible ScrollMethods ?
Do we agree that this issue is common between all ScrollMethods (button, edge and i-don't-remember-maybe-twofingers) ?

> This is something libinput allows us to do, we have the information.

OK. Good news, then.

> But we don't have an API in the server to allow for this.

Sorry, I don't understand (I most probably need a course on the interactions between libinput, xf86-input-libinput and xorg-server ... and you certainly have better thing to do. Eventually put me in the right direction and I'll do my own research) Where do you store the 'last scroll event sent at' value ?

> Given my workload (...) it's unlikely to make my todo list anytime soon

I know exactly what it's like. No problem.
For the time being, since I doubt I can disable X's smooth scrolling, I'll be back to xf86-input-evdev.
Comment 10 Peter Hutterer 2017-02-08 21:23:18 UTC
(In reply to momboisse.alain from comment #9)
> In my case resetting it when the ScrollButton is released should be
> enough.

fwiw, that's information that libinput provides, but does not *guarantee*.
So far the implementation provides it though. Specifically, it sends a 0/0
scroll event to terminate the current scroll sequence and there's some plan
to make this more explicit through start/stop scroll events (see bug 99415)

> Which other scroll method(s) could possibly leave the 'last scroll event
> sent at' value at something other than a multiple of 15 ?

in libinput terms, we have 'finger', 'continuous' and wheel/wheel tilt. The
'finger' ones are edge/two-finger scrolling, the 'continuous' one is button
scrolling (atm, may be something else too in the future) and wheel and wheel
tilt are discrete.

> Wait... If I get this right this value is absolute and not relative to the
> "starting point" of the movement initiated when the ScrollButton gets
> pressed ? Could a relative value fix all possible ScrollMethods ?

libinput gives you a relative value in pixels (and discrete steps for
wheels, but that's a separate challenge, see bug 92772). For wheels, that
value is always 15 (hand-waving), finger/continuous it's anything. That
*relative* value is passed on to the server as axis delta, but because we
don't have relative axes in XI2, it needs to be converted to an absolute
value. That's where the server adds the delta to the last known value.

fwiw, all this lives in xserver/dix/getevents.c, function
GetPointerEvents(), the scroll emulation is emulate_scroll_button_events().
The value in question is pDev->last.scroll, that's the one that needs to be
reset on scroll sequence end/scroll method change.

the API used by the driver is xf86PostMotionEventM(). Have a look at the
xorg-libinput driver first and it'll make sense quickly.

Our problem is right now that we don't have a xf86PostFooEvent to notify the
server that a scroll sequence finished and it needs to reset the valuators.

> Do we agree that this issue is common between all ScrollMethods (button,
> edge and i-don't-remember-maybe-twofingers) ?

the issue occurs when switching between non-discrete to discrete, so
finger/continuous to wheel/tilt. the issue doesn't occur when you by chance 
leave the valuator at a multiple of 15. switching back to non-discrete can
have a similar effect because if you're close to a 15-multiple a small
motion can suddenly trigger a button event too soon.
Comment 11 momboisse.alain 2017-02-09 09:08:41 UTC
Interesting. It's still hard for me to wrap my head around it all (what helps is that I studied X11R5 a long time ago) but it's very interesting.

> Our problem is right now that we don't have a xf86PostFooEvent to notify the
> server that a scroll sequence finished and it needs to reset the valuators.

The easiest solution I see right now would be to add an ugly hack to "scroll back" to the last crossed 'multiple of 15' boundary when the scroll sequence finishes (i.e. send faked info to X). Correct me if I'm wrong, but : since this would not trigger any event I think it would be invisible to the user while still putting X back into a state where +15 / -15 scroll movements would have the expected result.
Comment 12 momboisse.alain 2017-02-09 09:12:51 UTC
> the issue doesn't occur when you by chance leave the valuator at a
> multiple of 15.

I say "let's fake our chance" but I ignore what your policy is on these kinds of solutions (AFAIK ugly hacks are hard to maintain, and whenever the empirical 15px value changes, you're toast)
Comment 13 Peter Hutterer 2017-02-09 10:52:35 UTC
I don't think this would work. Due to the way how device switching works I think you can still end up with the scroll valuator getting different values whenever you switch between devices. The driver isn't notified of this, so your calculation of what the server should be up to (and thus what the 15 multiple is) may be wrong. I don't have the sources in front of me atm to verify this, but this is bound to break.
Comment 14 GitLab Migration User 2018-08-10 20:56:39 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/xorg/driver/xf86-input-libinput/issues/5.


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.