User Tools

Site Tools


unix:xinput

This is an old revision of the document!


XInput: Scroll-Wheel Emulation on a 4-button Marble Mouse

Logitech 4-button Marble Mouse, note the absence of a scroll-wheel My 4-button Logitech Marble Mouse does not have a scroll-wheel, and by default in Ubuntu 8.10 does not use any of its buttons to emulate one.

Time to dive into xorg.conf, right?

Wrong! To quote the Ubuntu Documentation:

The newest version of Xorg used in Intrepid brings changes as to how input devices are detected and set up for use. Hal now plays a large part in the process, and as such xorg.conf is largely ignored, so any settings you had in xorg.conf will no longer be in use when X starts. You will now need to add files to /etc/hal/fdi/policy with an .fdi extension.

Now the example on that page is pretty good, and I tweaked it like so (both files had to be created):

Remapping Buttons

~/.Xmodmap:

! Logitech USB Marble Mouse Physical buttons available: 
!  Mouse Big:   1 3
!  Mouse Small: 8 9
! Xmodmap positional meanings:
!  Pointer: Left-click, Middle-click, Right-click, Scroll-up, Scroll-down, Scroll-left, Scroll-right, Scroll-click, 9
pointer = 1 9 3 4 5 6 7 8 2

Ordinarily, the first logical button on a mouse (or “pointer” in this case) will be interpreted as a left-click, the second as middle-click, third as right and so on according to the list above.

Note that scrolling manifests as multiple buttons, one for each direction. Even though most mice have a wheel for this, the snapping-action as you move it acts as a button-push as far as the computer is concerned. Four scrolling directions are available plus a click-action (pushing the scroll wheel down).

This marble mouse, however, reports to have 9 buttons, but in fact only has 4. The big buttons are numbered 1 (left) and 3 (right), and the small buttons as 8 (left) and 9 (right).

I prefer to make the small-right button my middle click, and so I swap the numbers appearing in positions “middle-click” and “9”1).

How did you find all this out?

If you open a terminal and run xev a small window should pop up and a lot of text, which at first glance looks like lots of errors. They are not. xev prints out all the X events the window it creates recieves.

First, make sure your pointer doesn't have any strange mappings:

# Note, this affects all attached mice!
xmodmap -e "pointer = 1 2 3 4 5 6 7 8 9 10 11 12 13"

So if you place your mouse cursor over the window and press-and-hold the button you want to be left click, you should see a message like this:

ButtonRelease event, serial 35, synthetic NO, window 0x1a00002,
    root 0x329, subw 0x1a00003, time 8162295, (31,37), root:(1049,1281),
    state 0x110, button 1, same_screen YES

Note the “button 1” text, telling us the button we just pressed is number 1.

I then repeat this for all buttons. This trick will also be useful for testing the scroll wheel emulation later.

Enabling Emulation

/etc/hal/fdi/policy/10-marblemouse.fdi

<deviceinfo version="0.2">
  <device>
    <match key="info.product" string="Logitech USB Trackball">
      <merge key="input.x11_options.EmulateWheel" type="string">true</merge>
      <merge key="input.x11_options.EmulateWheelTimeout" type="string">200</merge>
      <merge key="input.x11_options.EmulateWheelButton" type="string">8</merge>
      <merge key="input.x11_options.YAxisMapping" type="string">4 5</merge>
      <merge key="input.x11_options.XAxisMapping" type="string">6 7</merge>
      <merge key="input.x11_options.Emulate3Buttons" type="string">true</merge>
    </match>
    <match key="info.product" string="Marble Mouse (4-button)">
      <merge key="input.x11_options.EmulateWheel" type="string">true</merge>
      <merge key="input.x11_options.EmulateWheelTimeout" type="string">200</merge>
      <merge key="input.x11_options.EmulateWheelButton" type="string">8</merge>
      <merge key="input.x11_options.YAxisMapping" type="string">4 5</merge>
      <merge key="input.x11_options.XAxisMapping" type="string">6 7</merge>
      <merge key="input.x11_options.Emulate3Buttons" type="string">true</merge>
    </match>
  </device>
</deviceinfo>

Note in particular:

<match key="info.product" string="Logitech USB Trackball">
<match key="info.product" string="Marble Mouse (4-button)">

These strings must exactly match that used by HAL itself. You can list all HAL devices with the command hal-device. My marble mouse looks like one of the following2):

15: udi = '/org/freedesktop/Hal/devices/usb_device_46d_c408_noserial_if0_logicaldev_input'
  info.subsystem = 'input'  (string)
  info.product = 'Logitech USB Trackball'  (string)
  linux.device_file = '/dev/input/event1'  (string)
  input.x11_driver = 'evdev'  (string)
  linux.sysfs_path = '/sys/devices/pci0000:00/0000:00:1d.7/usb7/7-6/7-6.2/7-6.2:1.0/input/input18/event1'  (string)
  info.udi = '/org/freedesktop/Hal/devices/usb_device_46d_c408_noserial_if0_logicaldev_input'  (string)
  input.x11_options.EmulateWheel = 'true'  (string)
  info.parent = '/org/freedesktop/Hal/devices/usb_device_46d_c408_noserial_if0'  (string)
  input.x11_options.EmulateWheelTimeout = '200'  (string)
  input.x11_options.EmulateWheelButton = '8'  (string)
  linux.hotplug_type = 2  (0x2)  (int)
  input.x11_options.YAxisMapping = '4 5'  (string)
  info.category = 'input'  (string)
  linux.subsystem = 'input'  (string)
  input.x11_options.XAxisMapping = '6 7'  (string)
  input.originating_device = '/org/freedesktop/Hal/devices/usb_device_46d_c408_noserial_if0'  (string)
  info.capabilities = { 'input', 'input.mouse' } (string list)
  input.x11_options.Emulate3Buttons = 'true'  (string)
  input.device = '/dev/input/event1'  (string)
  input.product = 'Logitech USB Trackball'  (string)

17: udi = '/org/freedesktop/Hal/devices/usb_device_46d_c408_noserial'
  info.vendor = 'Logitech, Inc.'  (string)
  info.subsystem = 'usb_device'  (string)
  linux.hotplug_type = 2  (0x2)  (int)
  info.product = 'Marble Mouse (4-button)'  (string)
  linux.subsystem = 'usb'  (string)
  info.udi = '/org/freedesktop/Hal/devices/usb_device_46d_c408_noserial'  (string)
  info.linux.driver = 'usb'  (string)
  usb_device.linux.sysfs_path = '/sys/devices/pci0000:00/0000:00:1d.7/usb4/4-6/4-6.2'  (string)
  usb_device.configuration_value = 1  (0x1)  (int)
  usb_device.num_configurations = 1  (0x1)  (int)
  usb_device.num_interfaces = 1  (0x1)  (int)
  usb_device.device_class = 0  (0x0)  (int)
  usb_device.device_subclass = 0  (0x0)  (int)
  usb_device.device_protocol = 0  (0x0)  (int)
  usb_device.vendor_id = 1133  (0x46d)  (int)
  usb_device.product_id = 50184  (0xc408)  (int)
  usb_device.vendor = 'Logitech, Inc.'  (string)
  usb_device.product = 'Marble Mouse (4-button)'  (string)
  usb_device.device_revision_bcd = 5120  (0x1400)  (int)
  usb_device.max_power = 50  (0x32)  (int)
  usb_device.num_ports = 0  (0x0)  (int)
  usb_device.linux.device_number = 124  (0x7c)  (int)
  linux.sysfs_path = '/sys/devices/pci0000:00/0000:00:1d.7/usb4/4-6/4-6.2'  (string)
  usb_device.speed = 1.5  (double)
  info.parent = '/org/freedesktop/Hal/devices/usb_device_424_2512_noserial'  (string)
  usb_device.version = 1.1  (double)
  usb_device.is_self_powered = false  (bool)
  usb_device.can_wake_up = true  (bool)
  input.x11_options.EmulateWheel = 'true'  (string)
  input.x11_options.EmulateWheelTimeout = '200'  (string)
  usb_device.bus_number = 4  (0x4)  (int)
  input.x11_options.EmulateWheelButton = '8'  (string)
  linux.device_file = '/dev/bus/usb/004/124'  (string)
  input.x11_options.YAxisMapping = '4 5'  (string)
  input.x11_options.XAxisMapping = '6 7'  (string)
  input.x11_options.Emulate3Buttons = 'true'  (string)

You will notice that the info.product entries in the two config files match exactly. If you are not using a USB mouse my config won't work for you until you update it's info.product entry.

At some point my mouse's info.product entry changed from “Logitech USB Trackball” to “Marble Mouse (4-button)”. I'm not certain what caused it, but am pretty sure it was one of Ubuntu's updates.

Where can I find a definitive list of input.x11_options?

http://manpages.ubuntu.com/manpages/jaunty/man4/evdev.4.html

==

The following does the magic:

<merge key="input.x11_options.EmulateWheel" type="string">true</merge>
<merge key="input.x11_options.EmulateWheelButton" type="string">8</merge>

This causes button 8 (the small-left one) to toggle the interpretation of ball movements. The details of how are:

<merge key="input.x11_options.YAxisMapping" type="string">4 5</merge>
<merge key="input.x11_options.XAxisMapping" type="string">6 7</merge>

Which says movement in the vertical axis should be mapped to buttons 4 and 5, and horizontal movement to 6 and 7.

The following handily allows you to use button 8 as button 8, so long as you don't press it longer than 200ms:

<merge key="input.x11_options.EmulateWheelTimeout" type="string">200</merge>

Testing it all

You don't have to restart X every time you change your settings - you need only restart the HAL daemon and unplug/replug your mouse:

$ sudo invoke-rc.d hal restart
[sudo] password for meermanr:
 * Restarting Hardware abstraction layer hald
   ...done.     

You can then move your mouse over your xev window (see above) and check what the buttons do. You can also hold down the small-left button and move the ball to see button 4/5/6/7 events firing. Let go of the small-left button and no button event fires, but quickly tap it and you do get one - this is thanks to the 200ms timeout.

1)
I've not determined the purpose of this position, if indeed there is a default
2)
Note that this was generated _after_ I finished setting up my mouse, so it's “perfect” already
unix/xinput.1282245169.txt.gz · Last modified: 2010/08/19 19:12 by robm