How do I make xinput mouse settings persistent for a USB mouse?

You could cron the command or add it to your startup but neither are particularly elegant. If I were you, I'd add this to my udev rules and let the system detect events and fire off the command when it needs to.

First we need the mouse vendor and product strings. You can find these through lsusb. Look for your mouse. Here's my mouse shows up:

Bus 004 Device 012: ID 1532:000f Razer USA, Ltd 

The In the part 1532:000f, 1532 is the vendor and 000f is the product.

So then we add a rule to udev. udev rules are found in /lib/udev/rules.d/. You can write your own or be cheeky and edit another one. There is a helpful little README in there too that I suggest you peruse (cat /lib/udev/rules.d/README).

Whichever you do you want to add a rule like this. Notice I use the IDs from earlier to make this work.

BUS=="usb", SYSFS{idVendor}=="1532", SYSFS{idProduct}=="000f", ACTION=="add",
RUN+="/usr/bin/xinput set-ptr-feedback 'USB Optical Mouse' 4 1 1"

udev should pick that up immediately.

Note udev can do pretty clever things on its own when it comes to configuring devices. You might not need xinput at all. Here's an example of a custom configuration for a mouse.


I can think of no other solution than starting a little daemon that periodically polls xinput --list and runs a command when a device is plugged in or removed.

Sample code:

#! /bin/sh -x
#
# xievd [INTERVAL]
#
# Poll `xinput` device list every INTERVAL seconds (default: 10)
# and run script in ~/.xievd/${device_name}.sh when a device is
# plugged-in (or pulled out).
#
# The device name is the same as given by `xinput --list`, with
# the following transformations applied:
#   * any non-alphanumeric character is deleted (except: space, `_` and `-`)
#   * leading and trailing spaces are removed
#   * any sequence of 1 or more space chars is converted to a single `_`
#

interval=${1:-10}

scripts_dir="$HOME/.xievd"
if [ ! -d "$scripts_dir" ]; then
  echo 1>&2 "xievd: No scripts directory -- exiting."
  exit 1
fi

state_dir="$(mktemp -t -d xievd.XXXXXX)" \
  || { echo 1>&2 "xievd: Cannot create state directory -- exiting."; exit 1; }
trap "rm -rf $state_dir; exit;" TERM QUIT INT ABRT

process_xinput_device_list() {
  touch "${state_dir}/.timestamp"

  # find new devices and run "start" script
  xinput --list --short \
    | fgrep slave \
    | sed -r -e 's/id=[0-9]+.+//;s/[^a-z0-9 _-]//ig;s/^ +//;s/ *$//;s/ +/_/g;' \
    | (while read device; do 
        if [ ! -e "${state_dir}/${device}" ]; then
          # new device, run plug-in script
          [ -x "${scripts_dir}/${device}" ] && "${scripts_dir}/${device}" start
        fi
        touch "${state_dir}/${device}"
      done)

  # find removed devices and run "stop" script
  for d in "$state_dir"/*; do
    if [ "${state_dir}/.timestamp" -nt "$d" ]; then
      # device removed, run "stop" script
      device="$(basename $d)"
      [ -x "${scripts_dir}/${device}" ] && "${scripts_dir}/${device}" stop
      rm -f "$d"
    fi
  done
}

# main loop
while true; do
      process_xinput_device_list
      sleep $interval
      sleep 1
done

# cleanup
rm -rf "$state_dir"

Save the code above in a xievd executable file somewhere in your PATH, add it to your startup applications, and then create a ~/.xievd/USB_Optical_Mouse shell script:

#! /bin/sh
if [ "$1" = "start" ]; then
  xinput set-ptr-feedback 'USB Optical Mouse' 4 1 1
fi