Ubuntu – Run a shell command AFTER a bluetooth input device is detected

bluetoothcommand linemouseudevxinput

I'm trying to slow down my Magic Mouse sensibility using a xinput command automatically when my mouse is connected to my computer.

I managed to create a file under rules.d, that calls a shell script. The problem is that it works well for all scripts except the xinput command because the rule launches the script before that the mouse is listed between other input devices and so xinput command fails to find it.
So, my question is if there is a way to run the command I need only after that mouse is detected as input device or if there are other solutions to my problem.

From terminal, before the mouse connects by BT:

$ hcitool inq
Inquiring ...
00:1E:52:EE:0C:1B   clock offset: 0x33fb    class: 0x3a0104
84:38:35:31:CC:6B   clock offset: 0x1353    class: 0x002580
$ hcitool scan
Scanning ...
84:38:35:31:CC:6B   Mouse of Elios
00:1E:52:EE:0C:1B   Elios

After the mouse connects by BT I get:

$ hcitool info 84:38:35:31:CC:6B
Requesting information ...
BD Address:  84:38:35:31:CC:6B
Device Name: Mouse of Elios
LMP Version: 2.0 (0x3) LMP Subversion: 0x31c
Manufacturer: Apple, Inc. (76)
Features: 0xbd 0x02 0x04 0x38 0x08 0x00 0x00 0x00
    <3-slot packets> <encryption> <slot offset> <timing accuracy> 
    <role switch> <sniff mode> <RSSI> <power control> 
    <enhanced iscan> <interlaced iscan> <interlaced pscan> 
    <AFH cap. slave>

This is my udev rule placed in /etc/udev/rules.d:

SUBSYSTEMS=="input", ATTRS{name}=="Mouse of Elios", RUN+="/home/elios/Documents/FixMouse.sh"

This is my shell script /home/elios/Documents/FixMouse.sh (edited thanks to Cbhihe answer):

#!/bin/sh
while [ ! "$(/usr/bin/hcitool info 84:38:35:31:CC:6B 2>&1 > /dev/null; echo $?)" ]; do
 sleep 0.1
done
xinput --set-prop "Mouse of Elios" "Device Accel Constant Deceleration" 2.5

Other informations:

$ uname -a
Linux dalek 3.19.0-30-generic #34-Ubuntu SMP Fri Oct 2 22:08:41 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
$ xinput --list
⎡ Virtual core pointer                      id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ Mouse of Elios                    id=13   [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 Keyboard                 id=10   [slave  keyboard (3)]
    ↳ Apple, Inc Apple Keyboard                 id=11   [slave  keyboard (3)]
    ↳ FaceTime HD Camera (Built-in)             id=12   [slave  keyboard (3)]
$ xinput --list-props "Mouse of Elios"
Device 'Mouse of Elios':
Device Enabled (133):   1
Coordinate Transformation Matrix (135): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000
Device Accel Profile (527): 0
Device Accel Constant Deceleration (528):   2.500000
Device Accel Adaptive Deceleration (529):   1.000000
Device Accel Velocity Scaling (530):    10.000000
Device Product ID (253):    1452, 781
Device Node (254):  "/dev/input/event5"
Evdev Axis Inversion (531): 0, 0
Evdev Axes Swap (533):  0
Axis Labels (534):  "Rel X" (143), "Rel Y" (144), "Rel Horiz Wheel" (517), "Rel Vert Wheel" (518)
Button Labels (535):    "Button Left" (136), "Button Middle" (137), "Button Right" (138), "Button Wheel Up" (139), "Button Wheel Down" (140), "Button Horiz Wheel Left" (141), "Button Horiz Wheel Right" (142)
Evdev Scrolling Distance (536): 1, 1, 1
Evdev Middle Button Emulation (537):    0
Evdev Middle Button Timeout (538):  50
Evdev Third Button Emulation (539): 0
Evdev Third Button Emulation Timeout (540): 1000
Evdev Third Button Emulation Button (541):  3
Evdev Third Button Emulation Threshold (542):   20
Evdev Wheel Emulation (543):    0
Evdev Wheel Emulation Axes (544):   0, 0, 4, 5
Evdev Wheel Emulation Inertia (545):    10
Evdev Wheel Emulation Timeout (546):    200
Evdev Wheel Emulation Button (547): 4
Evdev Drag Lock Buttons (548):  0

Best Answer

In the script called by your udev rule, place the while, do, done snippet below, before your xinput parameter tweaks.

#!/bin/sh 
while [ ! "$(/usr/bin/hcitool info 84:38:35:31:CC:6B >& /dev/null; echo $?)" ]; do
     sleep 0.1
done
xinput --set-prop "Mouse of Elios" "Device Accel Constant Deceleration" 5.0
xinput --set-prop "Mouse of Elios" "Device Accel Adaptive Deceleration" 1.0
xinput --set-prop "Mouse of Elios" "Device Accel Velocity Scaling" 3.3

It allows yr script to wait for successive time intervals of 0.1 second, until the mouse is appropriately tethered by Bluetooth and before the xinput --set-prop cmds kick in.

Note that you have three ways to tweak yr mouse's response to a hand movement.

  • Device Accel Constant Deceleration (528): 2.500000
  • Device Accel Adaptive Deceleration (529): 1.000000
  • Device Accel Velocity Scaling (530): 10.000000

Check this and this out to figure out exactly what those parameter values stand for. In order to satisfactorily modify the "velocity scaling", you'll need to know what your mouse refresh rate is (in Hz). You should find that value on the technical data sheet of your mouse. The Velocity Scaling value is estimated as 1000/refresh_rate_in_Hz. Thus 3.3 assume a refresh rate of 300Hz, 10 a refresh rate of 100Hz.

Your script seems to bring no change to the default values of:

  • Device Accel Constant Deceleration (528): 2.500000
  • Device Accel Adaptive Decelaration (529): 1.000000

as revealed by your xinput --list-props cmd... Try modifying the value of 2.5 for prop_id 528 and realize that setting prop_id 529 to 1 (default) means "no adaptive acceleration or deceleration".

The udev rule you adapted from Gilles' answer on AU / U&L does not apply strictly to your case. What you need is a rule that kicks in upon "adding" your device, i.e. as soon as its presence first triggers a kernel event. So your udev rule should simply read:

ACTION=="add", SUBSYSTEMS=="input", ATTRS{idVendor}=="____", ATTRS{idProduct}=="____", RUN+="/usr/local/sbin/fixmouse"

where you should replace ____ with your real device's idVendor and idProduct. To find that info:

$ udevadm monitor

Connect your BT mouse. Read on the line where "KERNEL" appears, something similar to:

  KERNEL[22576.118379] add   /devices/pci0000:00/0000:00:1d.7/hci2/2-3/2-3.4/2-3.4:1.0/0003:192F:0916.0004/input/input23/mouse1 (input)

To end monitoring, just type in CTRL+C, then:

$ udevadm info -a -p '/devices/pci0000:00/0000:00:1d.7/hci2/2-3/2-3.4/2-3.4' | grep -e "idVendor" -e "idProduct" 

You should obtain 2 or 3 pairs of (idVendor, idProduct) values, depending on how your hardware is put together. My use-case yields:

ATTRS{idVendor}=="192f"
ATTRS{idProduct}=="0916"
ATTRS{idVendor}=="1a40"
ATTRS{idProduct}=="0101"
ATTRS{idVendor}=="1d6b"
ATTRS{idProduct}=="0002"

Try them in your udev rule in the order they appear. Normally the top most one should be the good one.

To finish, do:

$ sudo mv /home/elios/Documents/FixMouse.sh /usr/local/sbin/fixmouse
$ sudo chown root:root /usr/local/sbin/fixmouse
$ sudo chmod 755 /usr/local/sbin/fixmouse

Hope I got this right. Either way let us know.

Related Question