===== XInput: Scroll-Wheel Emulation on a 4-button Marble Mouse ====
{{ http://ecx.images-amazon.com/images/I/417FCRZRJ9L.jpg?250|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 [[https://help.ubuntu.com/community/Logitech_Marblemouse_USB|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"((I've not determined the purpose of this position, if indeed there is a default)).
=== 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 (Ubuntu 10.04) ====
cf. https://wiki.ubuntu.com/X/Config/Input
To enable for the current session (i.e. temporarily):
meermanr@ryoga:~
$ xinput list
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ SynPS/2 Synaptics TouchPad id=10 [slave pointer (2)]
⎜ ↳ Serial Wacom Tablet id=12 [slave pointer (2)]
⎜ ↳ Serial Wacom Tablet eraser id=11 [slave pointer (2)]
⎜ ↳ Macintosh mouse button emulation id=13 [slave pointer (2)]
⎜ ↳ Logitech USB Trackball id=14 [slave pointer (2)]
⎜ ↳ Microsoft Natural® Ergonomic Keyboard 4000 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)]
↳ Sleep Button id=8 [slave keyboard (3)]
↳ AT Translated Set 2 keyboard id=9 [slave keyboard (3)]
↳ Microsoft Natural® Ergonomic Keyboard 4000 id=15 [slave keyboard (3)]
meermanr@ryoga:~
$ xinput query-state "Logitech USB Trackball"
2 classes :
ButtonClass
button[1]=up
button[2]=up
button[3]=up
button[4]=up
button[5]=up
button[6]=up
button[7]=up
button[8]=up
button[9]=up
ValuatorClass Mode=Relative Proximity=In
valuator[0]=151
valuator[1]=388
meermanr@ryoga:~
$ xinput list-props "Logitech USB Trackball"
Device 'Logitech USB Trackball':
Device Enabled (117): 1
Device Accel Profile (236): 0
Device Accel Constant Deceleration (237): 1.000000
Device Accel Adaptive Deceleration (239): 1.000000
Device Accel Velocity Scaling (240): 10.000000
Evdev Reopen Attempts (235): 10
Evdev Axis Inversion (305): 0, 0
Evdev Axes Swap (307): 0
Axis Labels (308): "Rel X" (125), "Rel Y" (126)
Button Labels (309): "Button Left" (118), "Button Middle" (119), "Button Right" (120), "Button Wheel Up" (121), "Button Wheel Down" (122), "Button Horiz Wheel Left" (123), "Button Horiz Wheel Right" (124), "Button Side" (581), "Button Extra" (582)
Evdev Middle Button Emulation (310): 2
Evdev Middle Button Timeout (311): 50
Evdev Wheel Emulation (312): 1
Evdev Wheel Emulation Axes (313): 0, 0, 4, 5
Evdev Wheel Emulation Inertia (314): 10
Evdev Wheel Emulation Timeout (315): 200
Evdev Wheel Emulation Button (316): 4
Evdev Drag Lock Buttons (317): 0
meermanr@ryoga:~
$ xinput set-int-prop "Logitech USB Trackball" "Evdev Wheel Emulation Button" 8 8
meermanr@ryoga:~
$ xinput set-int-prop "Logitech USB Trackball" "Evdev Wheel Emulation" 8 1
meermanr@ryoga:~
$ xinput list-props "Logitech USB Trackball"Device 'Logitech USB Trackball':
Device Enabled (117): 1
Device Accel Profile (236): 0
Device Accel Constant Deceleration (237): 1.000000
Device Accel Adaptive Deceleration (239): 1.000000
Device Accel Velocity Scaling (240): 10.000000
Evdev Reopen Attempts (235): 10
Evdev Axis Inversion (305): 0, 0
Evdev Axes Swap (307): 0
Axis Labels (308): "Rel X" (125), "Rel Y" (126)
Button Labels (309): "Button Left" (118), "Button Middle" (119), "Button Right" (120), "Button Wheel Up" (121), "Button Wheel Down" (122), "Button Horiz Wheel Left" (123), "Button Horiz Wheel Right" (124), "Button Side" (581), "Button Extra" (582)
Evdev Middle Button Emulation (310): 2
Evdev Middle Button Timeout (311): 50
Evdev Wheel Emulation (312): 1
Evdev Wheel Emulation Axes (313): 0, 0, 4, 5
Evdev Wheel Emulation Inertia (314): 10
Evdev Wheel Emulation Timeout (315): 200
Evdev Wheel Emulation Button (316): 8
Evdev Drag Lock Buttons (317): 0
==== Enabling Emulation (Ubuntu 9.10) ====
''/etc/hal/fdi/policy/10-marblemouse.fdi''
true
200
8
4 5
6 7
true
true
200
8
4 5
6 7
true
Note in particular:
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 following((Note that this was generated _after_ I finished setting up my mouse, so it's "perfect" already)):
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:
true
8
This causes button 8 (the small-left one) to toggle the interpretation of ball movements. The details of how are:
4 5
6 7
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:
200
==== 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.