Input

Differences between revisions 4 and 22 (spanning 18 versions)
Revision 4 as of 2008-11-09 06:30:44
Size: 13481
Editor: dcolish
Comment:
Revision 22 as of 2012-12-21 12:38:00
Size: 9890
Editor: tsimpson
Comment: Add instructions for enabling Ctrl+Alt+BkSp killing of the X server for KDE
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
Ubuntu 8.04 and later include a new version of Xorg which support input-hotplug. With this new functionality, it's likely that you won't need to do any configuration at all to make your devices work, assuming they're recognized and set up by the kernel. However, if you do need to do adjust things, read on. #title Configuring Input Devices
||<tablestyle="font-size: 0.9em; background:#F1F1ED;margin: 0 0 1em 1em;" style="padding:2.0em;"><<TableOfContents(2)>>||

Ubuntu supports input-hotplug. With this functionality, it's likely that you won't need to do any configuration at all to make your devices work, assuming they're recognized and set up by the kernel. However, if you do need to do adjust things, read on.
Line 5: Line 8:
The {{{xinput}}} command line tool can be used for some on-the-fly configuration adjustments.  Ubuntu 8.04 users will first need to install {{{xinput}}} from {{{universe}}}. The {{{xinput}}} command line tool can be used for some on-the-fly configuration adjustments.
Line 11: Line 14:
...
"Configured Mouse" id=2 [XExtensionPointer]
 Num_buttons is 9
 Num_axes is 2
 Mode is Relative
 Motion_buffer is 256
 Axis 0 :
  Min_value is -1
  Max_value is -1
  Resolution is 1
 Axis 1 :
  Min_value is -1
  Max_value is -1
  Resolution is 1
"Generic Keyboard" id=3 [XExtensionKeyboard]
 Num_keys is 248
 Min_keycode is 8
 Max_keycode is 255
}}}

Individual devices can be queried for more details:

{{{
$ xinput query-state "Configured Mouse"
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ SynPS/2 Synaptics TouchPad id=8 [slave pointer (2)]
⎜ ↳ Logitech USB Receiver id=9 [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)]
    ↳ Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint id=7 [slave keyboard (3)]
}}}

Individual devices can be queried for more details by using the numerical id or the name:

{{{
$ xinput query-state 9
Line 46: Line 39:
 button[10]=up
 button[11]=up
 button[12]=up
 button[13]=up
 button[14]=up
 button[15]=up
 button[16]=up
 button[17]=up
 button[18]=up
 button[19]=up
 button[20]=up
 button[21]=up
 button[22]=up
 button[23]=up
 button[24]=up
Line 47: Line 55:
 valuator[0]=3182
 valuator[1]=969
}}}

If you have multiple mouse devices installed, you can switch which is considered the core pointer like this:

{{{
$ xinput set-pointer "Configured Mouse"
 valuator[0]=66
 valuator[1]=925
Line 59: Line 61:
In '''Ubuntu 8.10''' and later, different input drivers may also expose arbitrary properties for applications to set. Synaptics touchpads are particularly configurable like this, but other devices have some more general properties.

{{{
$ xinput list-props "SynPS/2 Synaptics TouchPad"
Different input drivers may also expose arbitrary properties for applications to set. Synaptics touchpads are particularly configurable like this, but other devices have some more general properties.

{{{
$ xinput list-props 8
Line 73: Line 75:
$ xinput set-int-prop "SynPS/2 Synaptics TouchPad" "Device Enabled" 8 0
$ xinput list-props "SynPS/2 Synaptics TouchPad"
$ xinput set-int-prop 8 "Device Enabled" 8 0
$ xinput list-props 8
Line 86: Line 88:
<<Anchor(hal)>>
== Input Configuration with HAL ==

Beginning with Ubuntu 8.10, input device configuration is done through HAL rather than in your {{{xorg.conf}}}. The syntax for HAL {{{fdi}}} files is a bit different than {{{xorg.conf}}}, and editing XML is only marginally better than editing {{{xorg.conf}}}... but on the plus side configuration changes don't require an X restart - just replugging of the device.

Essentially, to configure a device, add a new {{{fdi}}} file for it to your {{{/etc/hal/fdi/policy}}} directory. You will then need to replug the device or log out and in again for the changes to take effect.

For example, use this sort of {{{fdi}}} file to set Synaptics touchpad options (see the {{{synaptics}}} manpage for possible options, or [[https://help.ubuntu.com/community/SynapticsTouchpad|the Synaptics documentation]] for other methods):

{{{
<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
 <device>
  <match key="input.x11_driver" string="synaptics">
   <merge key="input.x11_options.VertTwoFingerScroll" type="string">true</merge>
   <merge key="input.x11_options.HorizTwoFingerScroll" type="string">true</merge>
  </match>
 </device>
</deviceinfo>
}}}

The '''match''' elements are used to conditionally match on various attributes related to the device or system. In this case we apply these settings to any device using the {{{synaptics}}} (ie. touchpad) driver.
The '''append''' elements are used to add parameters to various options. Options previously put in {{{xorg.conf}}} can be set using {{{input.x11_options.<option-name> (string)}}}.

Here is an example {{{fdi}}} file for setting up keys on a Dell Precision M20:

{{{
<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
  <device>
    <match key="/org/freedesktop/Hal/devices/computer:system.hardware.product" prefix="Precision">
      <match key="/org/freedesktop/Hal/devices/computer:system.hardware.product" contains="M20">
        <append key="input.keymap.data" type="strlist">e005:brightnessdown</append> <!-- Fn+Down arrow Brightness Down -->
        <append key="input.keymap.data" type="strlist">e006:brightnessup</append> <!-- Fn+Up arrow Brightness Up -->
        <append key="input.keymap.data" type="strlist">e007:battery</append> <!-- Fn+F3 battery icon -->
        <append key="input.keymap.data" type="strlist">e008:wlan</append> <!-- Fn+F2 Turn On/Off Wireless -->
        <append key="input.keymap.data" type="strlist">e009:ejectclosecd</append> <!-- Fn+F10 Eject CD -->
        <append key="input.keymap.data" type="strlist">e00a:suspend</append> <!-- Fn+F1 hibernate -->
        <append key="input.keymap.data" type="strlist">e00b:displaytoggle</append> <!-- Fn+F8 CRT/LCD -->
        <append key="info.capabilities" type="strlist">input.keymap</append>
      </match>
    </match>
  </device>
</deviceinfo>
}}}

These '''match''' elements are used to match on the system's product name, to check that it starts with "Precision" and contains "M20". In this case, we're appending some {{{[key]:[function]}}} pairs to the {{{input.keymap.data}}} option.

As a contrived example, let's say you wanted to specify the dvorak-intl variant and configure the eurosign to the E key:

{{{
<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
  <device>
    <match key="info.capabilities" contains="input.keys">
      <merge key="input.xkb.variant" type="string">dvorak-intl</merge>
      <merge key="input.xkb.options" type="string">eurosign:e</merge>
    </match>
  </device>
</deviceinfo>
}}}

An example of configuring for the Logitech MX1000 USB mouse:

{{{
<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
 <device>
  <match key="info.capabilities" contains="input.mouse">
   <merge key="input.x11_driver" type="string">mouse</merge>

    <!-- Logitech tweaks -->
    <match key="@input.originating_device:usb.vendor_id" int="0x46d">
     <match key="@input.originating_device:usb.product_id" int_outof="0xc50e;0xc518">
      <merge key="input.x11_options.RelHWHEELOptions" type="string">invert</merge>
     </match>
    </match>

   </match>
  </match>
 </device>
</deviceinfo>
}}}

The {{{vendor_id}}} and {{{product_id}}} values can be found via

{{{
$ cat /proc/bus/input/devices
}}}


== More on writing fdi's ==

The fdi file allows you to adjust the HAL layers auto-detection of hardware to make it work better, or work at all. So for instance, I am configuring my mouse. I will need to know what to use to match the input device and how it is identified by hal. Probing the HAL is very easy with
{{{
$ lshal | less
}}}
I can then search that output with /<search term> . In my case, I can able discover the following about my mouse device:

{{{
udi = '/org/freedesktop/Hal/devices/usb_device_2222_3061_noserial_if0_logicaldev_input'
  info.capabilities = {'input', 'input.mouse'} (string list)
  info.category = 'input' (string)
  info.parent = '/org/freedesktop/Hal/devices/usb_device_2222_3061_noserial_if0' (string)
  info.product = 'Evoluent Vertical Mouse 2' (string)
  info.subsystem = 'input' (string)
  info.udi = '/org/freedesktop/Hal/devices/usb_device_2222_3061_noserial_if0_logicaldev_input' (string)
  input.device = '/dev/input/event1' (string)
  input.originating_device = '/org/freedesktop/Hal/devices/usb_device_2222_3061_noserial_if0' (string)
  input.product = 'Evoluent Vertical Mouse 2' (string)
  input.x11_driver = 'evdev' (string)
  linux.device_file = '/dev/input/event1' (string)
  linux.hotplug_type = 2 (0x2) (int)
  linux.subsystem = 'input' (string)
  linux.sysfs_path = '/sys/devices/pci0000:00/0000:00:0b.1/usb2/2-5/2-5.3/2-5.3:1.0/input/input1/event1' (string)
}}}

I used to have this configured in my xorg.conf like this
{{{
Section "InputDevice"
    Identifier "Mouse0"
    Driver "mouse"
    Option "Protocol" "auto"
    Option "Device" "/dev/psaux"
    Option "Emulate3Buttons" "no"
    Option "ZAxisMapping" "4 5"
== Input Configuration with InputClass sections ==

To set e.g. the Coordinate Transformation Matrix in an xorg.conf type file (e.g., `/etc/X11/xorg.conf.d/90-rotate-screen.conf`), set the [[http://www.x.org/archive/current/doc/man/man5/xorg.conf.5.xhtml#heading8|"TransformationMatrix"]] option ('''NOT''' `"CoordinateTransformationMatrix"` or `"Coordinate Transformation Matrix"`!!!!) in an [[http://www.x.org/archive/current/doc/man/man5/xorg.conf.5.xhtml#heading8|InputDevice]] or [[http://www.x.org/archive/current/doc/man/man5/xorg.conf.5.xhtml#heading9|InputClass]] section; for example:

{{{
Section "InputClass"
    Identifier "RotateTouchCW"
    MatchProduct "N-Trig MultiTouch"
    Option "TransformationMatrix" "0 1 0 -1 0 1 0 0 1"
Line 213: Line 98:
}}

I will need to match the mouse device in the hal output and configure it to respond like it did in my xorg. I created the following fdi file to accomplish this.
{{{
<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
  <device>
    <match key="info.capabilities" contains="input.mouse">
        <merge key="input.x11_driver" type="string">mouse</merge>
        <merge key="input.x11_options.Emulate3Buttons" type="string">no</merge>
        <merge key="input.x11_options.ZAxisMapping" type="integer">4 5</merge>
    </match>
  </device>
</deviceinfo>
}}}

As you can see, the translation from xorg configuration to fdi is fairly trivial. A simple script could easy accomplish this task. I then repeated the same method for my keyboard configuration.
{{{
<?xml version="1.0" encoding="ISO-8859-1"?>
<deviceinfo version="0.2">
  <device>
    <match key="info.capabilities" contains="input.keyboard">
      <merge key="input.x11_driver" type="string">kbd</merge>
    </match>
  </device>
</deviceinfo>
}}}

Thats it. Here are a few more links on general fdi configuration
 * [[http://www.redhat.com/magazine/003jan05/features/hal/|Basic HAL Overview]]
 * [[http://ubuntuforums.org/showthread.php?t=948154|Ubuntu Forums Topic on HAL]]
 * [[http://cgit.freedesktop.org/xorg/xserver/tree/config/x11-input.fdi|Keyboard Configuration fdi from freedesktop project]]
 * [[http://webcvs.freedesktop.org/hal/hal/doc/spec/hal-spec.html?view=co#ov_hal_linux26|The complete hal spec]]

== Troubleshooting ==
If you run into a problem where you HAL hardware detection just doesn't work with GDM(once the login screen comes up) you're not alone. It looks like there is an issue with the gdm start priorities. Since a patch is not released yet, you can read about it [[https://bugs.launchpad.net/ubuntu/+source/xorg/+bug/271138 | here]], the best solution is to alter the boot priorities of gdm during start up so it always starts after hal. You do that by running the following:
{{{
$ sudo update-rc.d -f gdm remove #get rid of the old boot symlinks
$ sudo update-rc.d gdm defaults 25 #add the new ones with a higher priority
}}}
That's all there is to it. Hopefully that fixed the issue for you. If not, try converting your old xorg.conf input sections to fdi files using the techniques described above.
}}}

== Example: Disabling middle-mouse button paste on a scrollwheel mouse ==

Scrollwheel mice support a middle-button click event when pressing the scrollwheel. This is a great feature, but you may find it irritating. Fortunately it can be disabled.

First, you need to know the id of the mouse, like this:

{{{
$ xinput list | grep 'id='

"Virtual core pointer" id=0 [XPointer]
"Virtual core keyboard" id=1 [XKeyboard]
"AT Translated Set 2 keyboard" id=2 [XExtensionKeyboard]
"Macintosh mouse button emulation" id=3 [XExtensionPointer]
"Logitech USB-PS/2 Optical Mouse" id=4 [XExtensionPointer]
}}}

My mouse has the Logitech logo printed on it, so I gather I need the last entry.

I can view the current button mapping thusly:

{{{
$ xinput get-button-map 4

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 10
}}}

Really, only the first three numbers have meaning for me. They represent the left, middle, and right mouse buttons.

{{{
$ xinput get-button-map 4
}}}

I can turn the middle mouse button off by setting it to 0:

{{{
$ xinput set-button-map 4 1 0 3
}}}

Or I can turn the middle-mouse button into a left-mouse button by setting it to 1:

{{{
$ xinput set-button-map 4 1 1 3
}}}

To make this set on a per-user basis, I can plug that line into my ~/.xstartup or other init file. It can also be done via configuring a matching InputClass section on xorg.conf.
Line 259: Line 150:
 * [[X/InputCoordinateTransformation|Input Device Coordinate Mapping]] - How to set the mapping of an input device to a display through X
Line 260: Line 153:
 * [[https://help.ubuntu.com/community/MultimediaKeys|General Multimedia keyboard]]
 * [[https://wiki.ubuntu.com/USBKeyboardInstall|USB keyboard]]
 * [[https://help.ubuntu.com/community/AppleKeyboard|Apple Keyboard]]
 * [[https://help.ubuntu.com/community/MultimediaKeys|General Multimedia keyboard]] - Probably out of date as of Intrepid due to input-hotplug
 * [[https://wiki.ubuntu.com/USBKeyboardInstall|USB keyboard]] - Probably out of date as of Intrepid due to input-hotplug
 * [[https://help.ubuntu.com/community/AppleKeyboard|Apple Keyboard]] - Probably out of date as of Intrepid due to input-hotplug
Line 292: Line 185:

== Don't Zap ==
=== Using GNOME ===
 * Get to the System->Preferences->Keyboard menu.
 * Select the "Layouts" tab and click on the "Options" button.
 * Then select "Key sequence to kill the X server" and enable "Control + Alt + Backspace".
If this doesn't work (e.g. the option is unchecked but the key sequence still works), you can edit your /etc/X11/xorg.conf as explained below

=== Using KDE ===
 * Open System Settings and go to {{{Input Devices}}}.
 * In the {{{Keyboard}}} section open the {{{Advanced}}} tab.
 * Check the {{{Configure keyboard options}}} box if it's not already enabled.
 * Expand the {{{Key sequence to kill the X server}}} option and check the box labelled {{{Control + Alt + Backspace}}}.
 * Make sure to click the {{{Apply}}} button to apply the changes.

=== Using the command line ===

You can type the following command to enable Zapping immediately.

{{{
      setxkbmap -option terminate:ctrl_alt_bksp
}}}

If you're happy with the new behaviour you can add that command to your ~/.xinitrc in order to make the change permanent.

== Sticky Keys ==
It may be worth mentioning that the Accessibility shortcuts (for both KDE and Gnome) are enabled by holding the shift-key for 8 seconds. (This is easy to do if, say, selecting multiple items with the mouse). As a result, it's easy to inadvertently enable "Sticky Keys". Now, if you press Ctrl and then release it, and a bit later, you press Alt-Bksp (the shortcut to delete a whole word), then Boom! Bye-bye X-session Sad :-(

Also, unlike Ctrl-Alt-Del, the Ctrl-Alt-Bksp shortcut is not trapped. It's instant death (without confirmation) for the X-server, and too bad about your unsaved files. That's why DontZap is a good default.

For anyone missing the ability to kill the X-server in emergency, may I point out Alt-SysRq-R, followed by Ctrl-Alt-F1 (the first puts the keyboard back into Raw mode, i.e. outside the control of the X-server; the latter switches Virtual Terminal.) Or you can use Alt-SysRq-K to kill the current session.

Ubuntu supports input-hotplug. With this functionality, it's likely that you won't need to do any configuration at all to make your devices work, assuming they're recognized and set up by the kernel. However, if you do need to do adjust things, read on.

Dynamic Input Configuration with xinput

The xinput command line tool can be used for some on-the-fly configuration adjustments.

To view a listing of the input devices X sees, run:

$ xinput list
⎡ Virtual core pointer                          id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad                id=8    [slave  pointer  (2)]
⎜   ↳ Logitech USB Receiver                     id=9    [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)]
    ↳ Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint    id=7    [slave  keyboard (3)]

Individual devices can be queried for more details by using the numerical id or the name:

$ xinput query-state 9
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
        button[10]=up
        button[11]=up
        button[12]=up
        button[13]=up
        button[14]=up
        button[15]=up
        button[16]=up
        button[17]=up
        button[18]=up
        button[19]=up
        button[20]=up
        button[21]=up
        button[22]=up
        button[23]=up
        button[24]=up
ValuatorClass Mode=Relative Proximity=In
        valuator[0]=66
        valuator[1]=925

xinput can also be used to alter the button mappings on mice and adjust the acceleration and feedback settings.

Different input drivers may also expose arbitrary properties for applications to set. Synaptics touchpads are particularly configurable like this, but other devices have some more general properties.

$ xinput list-props 8
Device 'SynPS/2 Synaptics TouchPad':
        Device Enabled:         1
        Synaptics Edges:                1632, 5312, 1575, 4281
        Synaptics Finger:               25, 30, 256
        Synaptics Tap Time:             180
        Synaptics Tap Move:             220
        Synaptics Tap Durations:                180, 180, 100
        Synaptics Tap FastTap:          0
[...]

$ xinput set-int-prop 8 "Device Enabled" 8 0
$ xinput list-props 8
Device 'SynPS/2 Synaptics TouchPad':
        Device Enabled:         0
        Synaptics Edges:                1632, 5312, 1575, 4281
        Synaptics Finger:               25, 30, 256
        Synaptics Tap Time:             180
        Synaptics Tap Move:             220
        Synaptics Tap Durations:                180, 180, 100
        Synaptics Tap FastTap:          0
[...]

Input Configuration with InputClass sections

To set e.g. the Coordinate Transformation Matrix in an xorg.conf type file (e.g., /etc/X11/xorg.conf.d/90-rotate-screen.conf), set the "TransformationMatrix" option (NOT "CoordinateTransformationMatrix" or "Coordinate Transformation Matrix"!!!!) in an InputDevice or InputClass section; for example:

Section "InputClass"
    Identifier    "RotateTouchCW"
    MatchProduct    "N-Trig MultiTouch"
    Option    "TransformationMatrix" "0 1 0 -1 0 1 0 0 1"
EndSection

Example: Disabling middle-mouse button paste on a scrollwheel mouse

Scrollwheel mice support a middle-button click event when pressing the scrollwheel. This is a great feature, but you may find it irritating. Fortunately it can be disabled.

First, you need to know the id of the mouse, like this:

$ xinput list | grep 'id='

"Virtual core pointer"  id=0    [XPointer]
"Virtual core keyboard" id=1    [XKeyboard]
"AT Translated Set 2 keyboard"  id=2    [XExtensionKeyboard]
"Macintosh mouse button emulation"      id=3    [XExtensionPointer]
"Logitech USB-PS/2 Optical Mouse"       id=4    [XExtensionPointer]

My mouse has the Logitech logo printed on it, so I gather I need the last entry.

I can view the current button mapping thusly:

$ xinput get-button-map 4

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 10

Really, only the first three numbers have meaning for me. They represent the left, middle, and right mouse buttons.

$ xinput get-button-map 4

I can turn the middle mouse button off by setting it to 0:

$ xinput set-button-map 4 1 0 3

Or I can turn the middle-mouse button into a left-mouse button by setting it to 1:

$ xinput set-button-map 4 1 1 3

To make this set on a per-user basis, I can plug that line into my ~/.xstartup or other init file. It can also be done via configuring a matching InputClass section on xorg.conf.

Contributed Documentation

The following documentation was provided by various people in the past. Generally, much of it was written for pre-InputHotplug X, so may or may not still work in Intrepid.

Keyboard Config

Mouse Config

Tablet Config

Touchpad Config

Game Controller Config

Don't Zap

Using GNOME

  • Get to the System->Preferences->Keyboard menu.

  • Select the "Layouts" tab and click on the "Options" button.
  • Then select "Key sequence to kill the X server" and enable "Control + Alt + Backspace".

If this doesn't work (e.g. the option is unchecked but the key sequence still works), you can edit your /etc/X11/xorg.conf as explained below

Using KDE

  • Open System Settings and go to Input Devices.

  • In the Keyboard section open the Advanced tab.

  • Check the Configure keyboard options box if it's not already enabled.

  • Expand the Key sequence to kill the X server option and check the box labelled Control + Alt + Backspace.

  • Make sure to click the Apply button to apply the changes.

Using the command line

You can type the following command to enable Zapping immediately.

      setxkbmap -option terminate:ctrl_alt_bksp

If you're happy with the new behaviour you can add that command to your ~/.xinitrc in order to make the change permanent.

Sticky Keys

It may be worth mentioning that the Accessibility shortcuts (for both KDE and Gnome) are enabled by holding the shift-key for 8 seconds. (This is easy to do if, say, selecting multiple items with the mouse). As a result, it's easy to inadvertently enable "Sticky Keys". Now, if you press Ctrl and then release it, and a bit later, you press Alt-Bksp (the shortcut to delete a whole word), then Boom! Bye-bye X-session Sad Sad :-(

Also, unlike Ctrl-Alt-Del, the Ctrl-Alt-Bksp shortcut is not trapped. It's instant death (without confirmation) for the X-server, and too bad about your unsaved files. That's why DontZap is a good default.

For anyone missing the ability to kill the X-server in emergency, may I point out Alt-SysRq-R, followed by Ctrl-Alt-F1 (the first puts the keyboard back into Raw mode, i.e. outside the control of the X-server; the latter switches Virtual Terminal.) Or you can use Alt-SysRq-K to kill the current session.

X/Config/Input (last edited 2012-12-21 12:38:00 by tsimpson)