You are not logged in.
Hi,
I intend to remap the middle mouse button whenever an external mouse is plugged into my laptop using udev. I have adapted instructions from the links below to accomplish this
http://ubuntuforums.org/showthread.php?t=1865740, and
http://granjow.net/udev-rules.html
The general idea is that udev triggers the wrapper script, which in turn, invokes another script which uses xinput to remap the buttons. The wrapper script is necessary since udev is paused while the script executes and xinput does not list the mouse right as soon as it is plugged in. Atleast that is how it is supposed to work.
This is my udev rules file 41-mouse.rules
# Logitech B110 Optical Mouse
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c05b", ENV{DISPLAY}=":0", ENV{XAUTHORITY}="/home/imdn/.Xauthority", RUN+="/opt/myscripts/mouse_starter.sh", MODE="0666", OWNER="imdn", SYMLINK+="logitech-b110"
/opt/myscripts/mouse_starter.sh - an executable wrapper script to invoke the actual script
#!/bin/bash
export DISPLAY=$DISPLAY
export LOG=/tmp/mouse_middle.log
export XAUTHORITY=$XAUTHORITY
date > $LOG
echo "DISPLAY-'$DISPLAY'" >> $LOG
echo "Now invoking script from starter script ..." >> $LOG
/opt/myscripts/logitech_b110.sh &
/opt/myscripts/logitech_b110.sh - the actual executable script which remaps the button
#!/bin/bash
sleep 5
xinput >> $LOG
# Get xinput device id
logitech_mouse_id=$(xinput | grep "Logitech USB Optical Mouse" | awk {'print substr($7,4,2)'})
if [ $logitech_mouse_id != '' ]; then
echo "Logitech B110 Optical mouse detected (xinput id - '$logitech_mouse_id') ! Remapping middle button" >> $LOG
# Map button 6 (scroll wheel tilt-left button) and 7 (scroll wheel tilt-right button) to button 2 (middle button)
xinput set-button-map $logitech_mouse_id 1 2 3 4 5 2 2 8 9 10 11 12 13 14 15 16
else
echo "Xinput did not find Logitech mouse" >> $LOG
fi
The problem is that despite calling the second script from inside the wrapper script, the mouse is still not listed by xinput. The mouse is listed by xinput only after both scripts have finished. Increasing the sleep duration does not help.
Running the script standalone works fine. I am also using the latest stable version of udev (systemd) and xinput.
Any ideas what the problem occurs and how to fix this ? Has anything changed in udev regarding the way external programs are run (considering both the sources I cited are quite old) ? Is there any other way I can accomplish remapping of the buttons when it is plugged in?
Last edited by imdn (2016-05-09 17:44:45)
Offline
What items are being written to your log file? Have you evidence that mouse_starter.sh is writing to /mnt/mouse_middle.log?
Who owns that file? What are the write permissions for non-owners?
You might consider using the logger command to write messages to the journal rather than rolling your own logging mechanism. It might yield better information.
Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way
Offline
What items are being written to your log file? Have you evidence that mouse_starter.sh is writing to /mnt/mouse_middle.log?
Who owns that file? What are the write permissions for non-owners?
You might consider using the logger command to write messages to the journal rather than rolling your own logging mechanism. It might yield better information.
The expected statements are being written to the logfile just fine. Infact that is how I diagnosed that the mouse was not showing up in the xinput list. Thanks for the 'logger' suggestion, but in this case logging and file permissions are not where the issue lies. Below are the contents of the logfile should anyone be interested
Mon May 9 17:18:44 CEST 2016
DISPLAY-':0'
Now invoking script from starter script ...
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ AlpsPS/2 ALPS DualPoint TouchPad id=15 [slave pointer (2)]
⎜ ↳ AlpsPS/2 ALPS DualPoint Stick id=16 [slave pointer (2)]
⎜ ↳ Microsoft Natural® Ergonomic Keyboard 4000 id=11 [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)]
↳ Laptop_Integrated_Webcam_FHD id=13 [slave keyboard (3)]
↳ AT Translated Set 2 keyboard id=14 [slave keyboard (3)]
↳ Dell WMI hotkeys id=17 [slave keyboard (3)]
↳ Microsoft Natural® Ergonomic Keyboard 4000 id=10 [slave keyboard (3)]
Xinput did not find Logitech mouse
It would seems xinput is not aware of the mouse despite the second script workaround as suggested in the original sources. Running xinput after the scripts have finished running shows the following missing line.
↳ Logitech USB Optical Mouse id=12 [slave pointer (2)]
Last edited by imdn (2016-05-09 15:27:05)
Offline
Ah....
Take a look at my /etc/acpi/handler script. It turns off the touchpad when the lid is closed, and enables it when the lid is opened. I think the magic may be in how you are defining Xauthority. I don;t think the script is finding your variables because it is not you:
ewaller@turing/home/ewaller % cat /etc/acpi/handler.sh
#!/bin/bash
# Default acpi script that takes an entry for all actions
case "$1" in
button/power)
case "$2" in
PBTN|PWRF)
logger 'PowerButton pressed'
;;
*)
logger "ACPI action undefined: $2"
;;
esac
;;
button/sleep)
case "$2" in
SLPB|SBTN)
logger 'SleepButton pressed'
;;
*)
logger "ACPI action undefined: $2"
;;
esac
;;
ac_adapter)
case "$2" in
AC|ACAD|ADP0)
case "$4" in
00000000)
logger 'AC unpluged'
;;
00000001)
logger 'AC pluged'
;;
esac
;;
*)
logger "ACPI action undefined: $2"
;;
esac
;;
battery)
case "$2" in
BAT0)
case "$4" in
00000000)
logger 'Battery online'
;;
00000001)
logger 'Battery offline'
;;
esac
;;
CPU0)
;;
*) logger "ACPI action undefined: $2" ;;
esac
;;
button/lid)
case "$3" in
close)
export XAUTHORITY=`ls -1 /home/*/.Xauthority | head -n 1`
export DISPLAY=":`ls -1 /tmp/.X11-unix/ | sed -e s/^X//g | head -n 1`"
#xinput set-prop "SynPS/2 Synaptics TouchPad" 307 1
synclient TouchpadOff=1
logger 'LID closed, touchpad off'
;;
open)
logger 'LID opened, touchpad on'
export XAUTHORITY=`ls -1 /home/*/.Xauthority | head -n 1`
export DISPLAY=":`ls -1 /tmp/.X11-unix/ | sed -e s/^X//g | head -n 1`"
#xinput set-prop "SynPS/2 Synaptics TouchPad" 307 0
synclient TouchpadOff=0
;;
*)
logger "ACPI action undefined: $3"
;;
esac
;;
*)
logger "ACPI group/action undefined: $1 / $2"
esac
;;
# vim:set ts=4 sw=4 ft=sh et:
ewaller@turing/home/ewaller %
This script looks through everyone's stuff and uses the first one it finds. Hackish? Yeah.
Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way
Offline
Ah....
Take a look at my /etc/acpi/handler script. It turns off the touchpad when the lid is closed, and enables it when the lid is opened. I think the magic may be in how you are defining Xauthority. I don;t think the script is finding your variables because it is not you:
....
This script looks through everyone's stuff and uses the first one it finds. Hackish? Yeah.
Thanks, tried it , but I am the only user and verified that Xauthority points to the same file (/home/imdn/.Xauthority) - so it didn't work in my case. Besides there are other examples of defining the XAUTHORITY environment variable in udev rules (e.g. https://bbs.archlinux.org/viewtopic.php?id=146725 and https://bugs.launchpad.net/ubuntu/+sour … comments/3)
Offline
Solution
Ok, I managed to put together a solution. According to https://bbs.archlinux.org/viewtopic.php?id=180079, Xorg supposedly resets settings after udev runs. This would explain why the mouse does not show up in the list. So the solution is as follows:
Write udev rule to trigger a shell script (lets call this primary)
Primary shell script writes to a temporary lock file
Set an inotifywatch on the lock file. If it changes trigger the secondary shell script which remaps the mouse buttons (optionally do this in .xinitrc)
Relevant code below (adapted from the above thread)
/etc/udev/rules.d/41-mouse.rules
# Logitech B110 Optical Mouse
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c05b", ENV{DISPLAY}=":0", ENV{XAUTHORITY}="/home/imdn/.Xauthority", RUN+="/opt/myscripts/mouse_udev.sh", MODE="0666", OWNER="imdn", SYMLINK+="logitech-b110"
/opt/myscripts/mouse_udev.sh (make sure it's executable)
#!/bin/bash
# Path to lock file
lock="/tmp/mouse-middle.lock"
# Lock the file (other atomic alternatives would be "ln" or "mkdir")
exec 9>"$lock"
if ! flock -n 9; then
exit 1
fi
# Just putting in a timestamp
echo "Modified - $(date)" > $lock &
/opt/myscripts/logitech_b110.sh (make sure it's executable)
#!/bin/bash
sleep 2
LOG="/tmp/mouse-middle.log"
xinput > $LOG # In case of errors check to see if mouse is in the list of devices
# Get mouse id
logitech_mouse_id=$(xinput | grep "Logitech USB Optical Mouse" | awk {'print substr($7,4,2)'})
if [ $logitech_mouse_id != '' ]; then
echo "Logitech B110 Optical mouse detected (xinput id - '$logitech_mouse_id') ! " >> $LOG
# Map button 6 (scroll wheel tilt-left button) and 7 (scroll wheel tilt-right button) to button 2 (middle button)
xinput set-button-map $logitech_mouse_id 1 2 3 4 5 2 2 8 9 10 11 12 13 14 15 16
notify-send -t 3000 "Remapped Middle-button functionality"
else
echo "Xinput did not find Logitech mouse" >> $LOG
notify-send -t 3000 "Could not find logitech mouse"
fi
~/bin/file-inotify
#!/bin/bash
# Usage: file-inotify <file> <command>
# Command is run when file is written.
path=$(realpath "$1")
job="$2"
#basename=$(basename "$1")
dirname=$(dirname "$1")
inotifywait -m -e close_write --format '%w%f' "$dirname" \
| while read file
do
if [[ $(realpath "$file") == "$path" ]]; then
sh -c "$job"
fi
done
Call file-notify manually by invoking
~/bin/file-inotify /tmp/mouse-middle.lock /opt/myscripts/logitech_b110.sh &
or add it to ~/.xinitrc
/opt/myscripts/logitech_b110.sh &
~/bin/file-inotify /tmp/mouse-middle.lock /opt/myscripts/logitech_b110.sh & # Triggered by udev rule
Last edited by imdn (2016-05-09 17:48:12)
Offline
Thanks, finally found a working solution for configuring my extra USB mouse button at system start and plug in.
Two little details
* better use ~/.xprofile than ~/.xinitrc, when you use a display manager: https://wiki.archlinux.org/index.php/xprofile
* you will need to install community/inotify-tools to have needed inotifywait
The trick with file lock and inotify rocks. I tried some timeouts and background processes but X refreshed it's xinput list always after my udev rule. Thanks again.
Last edited by kokesssss (2016-09-27 08:04:27)
Offline