Supercharging Your Mouse Ergonomics in Linux, Part 1: Scrolling with Mouse Movements

Sometimes I use a touchpad, and at other times an optical mouse, but my main workstation pointer device is a trackball, in particular, the Logitech M570. This model comes with two little index finger buttons, labeled “Forward Button” and “Back Button”, in the image below:

which by default send you forward and backward through your web page visit chain in your browser. I find this mapping a phenomenal waste of two very useful buttons.

In addition, I find the default scroll speed of the wheel really slow. It is easy enough to amplify the number of steps up and down taken by each click of the scroll wheel, but it is difficult to find an amplification factor that works well in all cases, and, typically once you get the factor high enough for comfortable “big picture” scanning of large pages/documents, the resulting jumps become jarringly unuseable for finer-grained scrolling.

Here I show how you can setup the mouse so that upon pressing one of those little index finger buttons and holding it down, you can then use the trackball to smoothly scroll up and down or left and right on any window. The effect is identical to moving the cursor to the scroll bar, clicking and holding down the left mouse button and spinning the trackball. The (huge) advantage of what I describe here is that you do not need to move the cursor over to the scroll bar of the window — as long as your cursor is on a window, just clicking the assigned index finger button and holding it down works. If you are working with big monitors, the ergonomics saving is really significant!

  1. First, we have to get the device ID of the mouse on our system. Run the following command:

    $ xinput list

    and you should see output like the following:

    ⎡ Virtual core pointer                          id=2    [master pointer  (3)]
    ⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
    ⎜   ↳ bcm5974                                   id=15   [slave  pointer  (2)]
    ⎜   ↳ Logitech M570                             id=13   [slave  pointer  (2)]
    ⎜   ↳ Razer Razer BlackWidow Ultimate 2016      id=10   [slave  pointer  (2)]
    ⎜   ↳ Razer Razer BlackWidow Ultimate 2016      id=16   [slave  pointer  (2)]
    ⎣ Virtual core keyboard                         id=3    [master keyboard (2)]
        ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
        ↳ Power Button                              id=6    [slave  keyboard (3)]
        ↳ Video Bus                                 id=7    [slave  keyboard (3)]
        ↳ Power Button                              id=8    [slave  keyboard (3)]
        ↳ Sleep Button                              id=9    [slave  keyboard (3)]
        ↳ Apple Inc. Apple Internal Keyboard / Trackpad id=14   [slave  keyboard (3)]
        ↳ C-Media Electronics Inc.       Microsoft LifeChat LX-3000 id=17   [slave  keyboard (3)]
        ↳ Razer Razer BlackWidow Ultimate 2016      id=11   [slave  keyboard (3)]
        ↳ Razer Razer BlackWidow Ultimate 2016      id=12   [slave  keyboard (3)]

    As can be seen, the “Logitech M570” mouse has an id of 13.

  2. Before going any further, we should probably save our settings for this device. The settings can be viewed by (of course, replaceing “13” with the correct device id from the previous step) :

    $ xinput list-props 13

    which yields:

    Device 'Logitech M570':
        Device Enabled (146):   1
        Coordinate Transformation Matrix (148): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000
        libinput Natural Scrolling Enabled (281):   0
        libinput Natural Scrolling Enabled Default (282):   0
        libinput Scroll Methods Available (285):    0, 0, 1
        libinput Scroll Method Enabled (286):   0, 0, 0
        libinput Scroll Method Enabled Default (287):   0, 0, 0
        libinput Button Scrolling Button (288): 2
        libinput Button Scrolling Button Default (289): 2
        libinput Middle Emulation Enabled (290):    0
        libinput Middle Emulation Enabled Default (291):    0
        libinput Rotation Angle (299):  0.000000
        libinput Rotation Angle Default (300):  0.000000
        libinput Accel Speed (292): 0.000000
        libinput Accel Speed Default (293): 0.000000
        libinput Accel Profiles Available (294):    1, 1
        libinput Accel Profile Enabled (295):   1, 0
        libinput Accel Profile Enabled Default (296):   1, 0
        libinput Left Handed Enabled (297): 0
        libinput Left Handed Enabled Default (298): 0
        libinput Send Events Modes Available (266): 1, 0
        libinput Send Events Mode Enabled (267):    0, 0
        libinput Send Events Mode Enabled Default (268):    0, 0
        Device Node (269):  "/dev/input/event10"
        Device Product ID (270):    1133, 4136
        libinput Drag Lock Buttons (283):   <no items>
        libinput Horizontal Scroll Enabled (284):   1

    We can save these settings for future reference but copying and pasting the text to a file, or otherwise do something like “xinput list-props 13 > ~/saved-m570-props.txt

  3. Next, we enable the smooth scrolling by running:

    $ xinput set-prop 13 "libinput Scroll Method Enabled" 0, 0, 1
  4. Now we just have to assign the scrolling mode button. In my case, this was already assigned by default to button 2 (as can be seen from the line, “libinput Button Scrolling Button Default (289): 2”), which corresponds to the middle button (i.e., pressing down on the scroll wheel). Sure enough, pressing down and holding the middle button / scroll wheel and then spinning the trackball gives me super slick scrolling in both axes in any application.


  5. If you are happy with this button assignment, then you can stop right here. However, in my case, I actually wanted to preserve the traditional Linux middle-button-pastes idiom, and thought I would just appropriate one of the useless index finger buttons to do the job. To assign the job to the rearmost index finger button, we specify that the scrolling button is button 8:

    $ xinput set-prop 13 "libinput Button Scrolling Button" 8

    This is simple enough, but how do I know the id of the button? To discover the button numbers, you can run the following command:

    $ xev | grep -i button

    which will open a window. Move the cursor to the window and click the mouse buttons of interest. You will see two messages for each key stroke: one for the press and the other for the release. The messages will include the button numbers.

  6. OK, now we have things the way we want them. But these changes are not going to persist across boots or even logins. To bake the changes into the system, we just need to add the two commands (one to enabling the button-triggered mouse scrolling and the other to assign the button) to our startup commands. In Ubuntu, this can be done by going to “Startup Applications” (search for “Startup Applications” in the applications overview, called up by “Super+a”), clicking on “Add Command”, and adding the following multi-command (or you can add them as two separate startup commands if you prefer):

    xinput set-prop 13 "libinput Scroll Method Enabled" 0, 0, 1 && xinput set-prop 13 "libinput Button Scrolling Button" 8

    like so:

And now you have some seamless, smooth, fast and precise scrolling in your desktop!

Also, you will note that if you click and release the index finger button assigned above (instead of clicking and holding it down and then moving the trackball), then the default “backward” (or “forward”) behavior is invoked. That is, we have not actually overridden the existing mapping, but just supplemented it. And we also have the forward (or other) index finger button to deal with. So that are two highly-ergonomic buttons on our mouse doing something unimpressive, useless, or redundant (even if one of them has been appropriated into truly wonderful service when held down as opposed to clicking-and-releasing). In a subsequent post, I describe how we can fix all of these by mapping them to some really nice functionality.

Stay tuned …