fine grained scrolling via uinput [SOLVED - mostly]

Peter Hutterer peter.hutterer at who-t.net
Sun Aug 13 08:30:42 UTC 2017


On Mon, Aug 07, 2017 at 06:25:05PM +0700, Antoine Martin wrote:
> Hi,
> 
> We've got a solution to the "smooth scrolling" query from last year:
> https://lists.freedesktop.org/archives/xorg/2016-June/058138.html
> 
> I believe that this solution is actually easier than implementing a
> trackstick-like device: we adjust MOUSE_WHEEL_CLICK_COUNT on a uinput
> device to give us 1 degree resolution, then multiply at runtime if we
> need the "regular" 15 degree events.
> 
> There are quite a few places that need configuring to make this work:
> 
> 1) ensure that those devices won't be picked up by real Xorg servers:
> cat > /etc/X11/xorg.conf.d/90-xpra-virtual.conf << EOF
> # Ignore all xpra virtual devices by default,
> # these will be enabled explicitly when needed.
> Section "InputClass"
>         Identifier "xpra-virtual-device"
>         MatchProduct "Xpra"
>         Option "Ignore" "true"
> EndSection
> EOF
> 
> 2) Tell udev to add our click count setting:
> cat > /lib/udev/rules.d/71-xpra-mouse.rules << EOF
> ACTION=="add|change", ATTRS{name}=="Xpra Virtual Pointer", \
> ENV{MOUSE_WHEEL_CLICK_ANGLE}="1", ENV{MOUSE_WHEEL_CLICK_COUNT}="360"
> EOF
> udevadm control --reload-rules && udevadm trigger
> 
> 3) to be able to use uinput devices, xpra's xorg.conf has to enable
> "AutoEnableDevices" and "AutoAddDevices", and so we also have to tell it
> to ignore all the devices except the ones we will assign to it:
> Section "InputClass"
>   Identifier "ignore-non-xpra-devices"
>   NoMatchProduct "Xpra"
>   Option "Ignore" "true"
> EndSection
> 
> 4) When starting a dummy Xorg server, we create a uinput device with
> REL_WHEEL and BTN_* (as root so we can access /dev/uinput), then figure
> out what path it's available under using UI_GET_SYSNAME and add this
> section:
> Section "InputClass"
>     Identifier "xpra-virtual-pointer"
>     MatchProduct "Xpra Virtual Pointer"
>     MatchDevicePath "/dev/input/eventNNN"
>     Option "Ignore" "False"
>     MatchIsPointer "True"

i generally recommend having the various Match* first, then the options. Not
that it really matters but it's better to read that way. 

>     Driver "libinput"
>     Option "AccelProfile" "flat"
> EndSection
> (the Xorg server doesn't run as root, we can drop privileges after
> dealing with uinput and chowning the new device)
> 
> 5) To send scroll events, we send these events to the uinput device:
> REL_WHEEL, 30
> or
> REL_WHEEL, -30
> 
> ----------------------
> 
> And it all seems to work pretty well so far. Applications like Firefox
> can now scroll a few pixels at a time.
> 
> Questions:
> 1) Anything wrong with this approach?

well. on the face of it, it's fine. but remember, you're not triggering a
behaviour directly, you're emulating a physical device with specific
hardware properties that libinput currently treats in a specific way. Keep
that in mind, as libinput's behaviour may change over time.

amongst other things, you're emulating a wheel which is handled differently
in libinput than e.g. two-finger scrolling.
 
> 2) what is the valid range for MOUSE_WHEEL_CLICK_COUNT?
> If I set MOUSE_WHEEL_CLICK_COUNT too high, I get:
> (EE) event19 - (EE) Xpra Virtual Pointer: (EE) mouse wheel click count
> is present but invalid, using 15 degrees for angle instead instead
> (and this error is logged twice)

see evdev_read_wheel_click_count_prop() in libinput/src/evdev.c.
libinput assumes anything with <1 degre per click as invalid because no such
devices currently exist (to my knowledge)
 
> 3) Despite setting a flat AccelProfile above, "libinput list-devices" shows:
> Accel profiles:   flat *adaptive
> What am I doing wrong here?

from libinput-list-devices(1)
       An xorg.conf(5) configuration entry or Wayland compositor setting
       may  have  changed  configurations  on  a device.  The  libinput
       list-devices tool only shows the device's default configuration, not
       the current configuration.

> 4) the first scroll event is always ignored - what can I do to fix that?

you can't. it's a long-standing XI2.1 protocol design flaw:
http://who-t.blogspot.co.at/2012/06/xi-21-protocol-design-issues.html

> 5) I tried using a udev hwdb.d rule for setting the click count, but
> that didn't seem to have any effect:
> cat > /lib/udev/hwdb.d/71-mouse-xpra.hwdb <<EOF
> # allow xpra to use smooth scrolling
> mouse:*:name:Xpra Virtual Pointer:
>  MOUSE_WHEEL_CLICK_ANGLE=1
>  MOUSE_WHEEL_CLICK_COUNT=360
> EOF
> udevadm hwdb --update

you did reboot or re-trigger the rules after that?

> Does it matter? Any reason to use this rather than the udev rule?

the effect of using udev rules and hwdb entries is the same. hwdb entries
are easier to manage when you end up having a lot of them. I don't know
specifically what's wrong here though, nothing immediately sticks out.

> 6) to get the same motion as with an XTest wheel click, I'm having to
> send REL_WHEEL=+-30, I would have thought it should be 15 instead.
> Where did I get my maths wrong?

is that the first scroll event getting swallowed as above?

> 7) when the uinput device is created, udev will chown it to root:input,
> is there any way we can tell udev to just leave it alone?
> We know the uid and gid we want to chown to, and currently we have to
> wait for udev to do its thing then do what we really want, which is both
> ugly and racy.

add a udev rule that sorts high enough and changes the mode. telling udev to
leave it alone is generally harder than just overriding what it does with a
higher-sorted rule. this can be part of your exisiting udev rule with
MODE=...  and GROUP=...

Cheers,
   Peter


More information about the xorg-devel mailing list