| #!/bin/sh |
| # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # Log all calls, with arguments, to /var/log/messages |
| logger "$0" "$@" |
| |
| XINPUT=/usr/bin/xinput |
| |
| PROG=`basename $0` |
| COMMAND=$1 |
| |
| SCREEN_DPI=125 |
| |
| . $(dirname "$0")/common |
| |
| export DISPLAY=:0 |
| export XAUTHORITY=/home/chronos/.Xauthority |
| |
| # On disk preferences |
| PREF_SENS_FILE=/home/chronos/user/mouse_sensitivity |
| PREF_SENS_VALID="[12345]" |
| PREF_SENS_DEFAULT=3 |
| PREF_SWAP_LR_FILE=/home/chronos/user/mouse_swap_lr_buttons |
| PREF_SWAP_LR_VALID="[01]" |
| PREF_SWAP_LR_DEFAULT=0 |
| |
| # We are supposed to set an xinput setting as screen DPI * a multiplier that |
| # describes how fast the mouse should be (user preference). This function |
| # returns that product. |
| # We use multipliers of: 1, 1.4, 1.8, 2, 2.2. The low three have a slope that |
| # stops rising after speeds of 5 in/sec (hence 500 hundredths of an inch/sec |
| # param). See xorg-server's dix/ptrveloc.c for more info on the acceleration |
| # algorithm. |
| thresh_and_dpi_times_sensitivity_multiplier() { |
| local sens=$1 # 1..5 |
| case $sens in |
| 1) echo 500 $SCREEN_DPI;; |
| 2) echo 500 $(((SCREEN_DPI * 7) / 5));; |
| 3) echo 500 $(((SCREEN_DPI * 9) / 5));; |
| 4) echo 0 $((SCREEN_DPI * 2));; |
| 5) echo 0 $(((SCREEN_DPI * 11) / 5));; |
| esac |
| } |
| |
| # Applies the given sensitivity preference (1..5) to all mice attached to the |
| # system. If this is called when a new device is being connected, that new |
| # device probably won't show up yet, so this won't apply to it. |
| apply_sensitivity() { |
| local sens="$1" |
| local mice="$2" |
| local thresh_and_acc="$(thresh_and_dpi_times_sensitivity_multiplier "$sens")" |
| if [ -z "$thresh_and_acc" ]; then |
| return |
| fi |
| for mouse in $mice ; do |
| if is_multitouch_mouse ${mouse}; then |
| $XINPUT set-prop ${mouse} "Pointer Sensitivity" "${sens}" |
| else |
| $XINPUT set-ptr-feedback $mouse $thresh_and_acc 1 |
| fi |
| done |
| } |
| |
| # Applies the preference for whether or not to swap the left and right mouse |
| # buttons on all existing mice attached to the system. If this is called when a |
| # new device is being connected, that new device probably won't show up yet, so |
| # this won't apply to it. |
| apply_swap_lr() { |
| local value="$1" |
| local mice="$2" |
| local map="1 2 3" |
| if [ "$value" -eq 1 ]; then |
| map="3 2 1" |
| fi |
| for mouse in $mice ; do |
| $XINPUT get-button-map $mouse | sed "s/^[0-9]* [0-9]* [0-9]*/$map/" | \ |
| xargs $XINPUT set-button-map $mouse |
| done |
| } |
| |
| # Remaps buttons for a device |
| apply_button_remap() { |
| local xinput_ids="$1" |
| |
| for xinput_id in $xinput_ids ; do |
| local vp="$(vendor_product_for_xinput_id $xinput_id)" |
| # 0304: USB Mighty Mouse, 030c: BT Mighty Mouse |
| if [ "$vp" = "05ac:0304" -o "$vp" = "05ac:030c" ]; then |
| $XINPUT get-button-map $xinput_id | awk \ |
| '{ for (i=1; i <= NF; i++) { \ |
| if (i == 8) { printf 0 } else { printf $(i) }; printf " " \ |
| } } END{ print "" }' | \ |
| xargs $XINPUT set-button-map $xinput_id |
| fi |
| done |
| } |
| |
| apply_cpi_for_mouse() { |
| local mouse="$1" |
| if is_multitouch_mouse $1; then |
| $XINPUT set-prop $mouse "Mouse CPI" $(get_cpi $mouse) |
| $XINPUT set-prop $mouse "Device Accel Profile" -1 |
| $XINPUT set-prop $mouse "Device Accel Constant Deceleration" 1 |
| $XINPUT set-prop $mouse "Device Accel Velocity Scaling" 1 |
| else |
| $XINPUT set-prop $mouse "Device Accel Constant Deceleration" \ |
| $(get_cpi $mouse) |
| $XINPUT set-prop $mouse "Device Accel Velocity Scaling" 1 |
| fi |
| } |
| |
| # Applies the correct CPI to the given mice |
| apply_cpi() { |
| local mice="$1" |
| for mouse in $mice ; do |
| apply_cpi_for_mouse $mouse |
| done |
| } |
| |
| # Prints out all xinput IDs for all existing attached mice. If this is called |
| # when a new device is being connected, that new device probably won't show up |
| # yet, so this won't apply to it. |
| find_mice() { |
| # Search for an xinput entry that contains the "slave pointer" |
| # Then, find a field that matches "id=". |
| # Lastly, return the part of the field after the '='. |
| local slave_pointers="$($XINPUT list | \ |
| awk '/slave *pointer/ { for (i=1; i<NF; i++) \ |
| if ($i ~/id=/) print substr($i, 4) }')" |
| # Next, return only those slave pointers that are using the Evdev driver |
| for pointer in $slave_pointers ; do |
| local match=$($XINPUT list-props $pointer | grep "Evdev" | wc -l) |
| if [ "$match" != "0" ]; then |
| echo -n " $pointer" |
| elif is_multitouch_mouse ${pointer}; then |
| echo -n " ${pointer}" |
| fi |
| done |
| } |
| |
| # Returns the CPI (counts per inch) of the newly attached mouse. Since mice |
| # generally don't report CPI, we use the following approach: By default, we |
| # assume a CPI of 1000, as this is quite close to most mice on the market today |
| # (2012 time frame). For mice that we know aren't near 1000, we have a database |
| # of CPI values. |
| get_cpi() { |
| local xinput_id="$1" |
| |
| local vp="$(vendor_product_for_xinput_id $xinput_id)" |
| |
| # Database of mice that have CPI (DPI) significantly off from 1000. |
| local cpi=1000; # Default CPI |
| local trackpoint_cpi=400; # Approximate, since CPI doesn't exactly apply |
| case $vp in |
| "0002:000a") cpi=$trackpoint_cpi;; # PS/2 IBM Trackpoint |
| "045e:0024") cpi=400;; # Microsoft Corp. Trackball Explorer* |
| "045e:0040") cpi=416;; # Microsoft Corp. Wheel Mouse Optical |
| "0461:4d22") cpi=474;; # Standard Dell |
| "046d:1028") cpi=600;; # M570 trackball[u] |
| "046d:400e") cpi=400;; # K400 touchpad[u] |
| "046d:4024") cpi=400;; # K400r touchpad[u] |
| "046d:c00f") cpi=385;; # Logitech MouseMan Traveler/Mobile |
| "046d:c00"*) cpi=385;; # Old Logitech Mice (copying 0xc00f setting) |
| "046d:c014") cpi=425;; # HP branded "Logitech Optical USB Mouse" |
| "046d:c016") cpi=377;; # HP branded "Logitech, Inc. Optical Wheel Mouse" |
| "046d:c018") cpi=530;; # "Logitech, Inc. Optical Wheel Mouse" model M-UAE96 |
| "046d:c03d") cpi=434;; # Logitech M-BT96a Pilot Optical Mouse |
| "046d:c03e") cpi=464;; # Logitech Premium Optical Wheel Mouse (M-BT58) |
| "046d:c077") cpi=580;; # HP branded "Logitech USB Optical Mouse" |
| # According to http://www.linux-usb.org/usb.ids , these are 4 trackballs: |
| "046d:c40"*) cpi=300;; # Logitech Trackballs* |
| "046d:c508") cpi=300;; # Cordless Trackball |
| "047d:1002") cpi=300;; # Kensington Turbo Mouse Pro (trackball)* |
| "047d:1003") cpi=300;; # Kensington Orbit TrackBall (trackball)* |
| "047d:1005") cpi=300;; # Kensington TurboBall (trackball)* |
| "047d:1006") cpi=300;; # Kensington TurboRing (trackball)* |
| "047d:1009") cpi=300;; # Kensington Orbit TrackBall for Mac (trackball)* |
| "047d:1020") cpi=300;; # Kensington Expert Mouse (trackball)* |
| "047d:2041") cpi=300;; # Kensington SlimBlade Trackball (trackball)* |
| "04d9:2519") cpi=400;; # FAVI Wireless Keyboard (TouchPad)* |
| "05ac:0304") cpi=400;; # Apple USB Optical Mouse (Mighty Mouse) |
| "05ac:030c") cpi=400;; # Apple BT Optical Mouse (Mighty Mouse) |
| "05ac:030d") cpi=1780;; # Apple magicmouse (BT) |
| "05ac:"*) cpi=373;; # Apple mice (other) |
| "06cb:0009") cpi=$trackpoint_cpi;; # USB IBM Trackpoint |
| "0a5c:8502") cpi=400;; # FAVI Wireless Keyboard (TouchPad), Bluetooth* |
| "0c45:7000") cpi=400;; # FAVI Entertainment Wireless Keyboard (TouchPad)* |
| "1532:0016") cpi=1714;; # Razer USA, Ltd DeathAdder RZ01-0015 |
| "17ef:6009") cpi=$trackpoint_cpi;; # Lenovo ThinkPad Keyboard w/ TrackPoint |
| "17ef:6014") cpi=400;; # Lenovo N5901 multimedia keyboard/trackball* |
| "17ef:602b") cpi=400;; # Lenovo N5902 multimedia keyboard/OFN* |
| "1997:0409") cpi=400;; # Riitek Rii Mote i6 (TouchPad)* |
| "413c:3012") cpi=502;; # Dell Computer Corp. Optical Wheel Mouse |
| esac |
| # * Trackball/touchpad measurements are approximate |
| # [u] This device uses the unifying receiver |
| echo $cpi |
| } |
| |
| # Kernel's Apple magicmouse driver by default will interpret mouse events, and |
| # we would like to turn off this interpretation. |
| fixup_apple_magicmouse_driver_parameters() { |
| if [ "$(vendor_product_for_xinput_id $1)" != "05ac:030d" ]; then |
| return |
| fi |
| echo 0 > /sys/module/hid_magicmouse/parameters/emulate_3button |
| echo 0 > /sys/module/hid_magicmouse/parameters/emulate_scroll_wheel |
| } |
| |
| # Add is a special command that's run possibly before xinput detects the mice. |
| # It's run from udev. We handle this here, rather than below, since a newly |
| # plugged device may not show up in xinput yet. |
| if [ "$COMMAND" = "add" ]; then |
| newid=$(wait_and_get_added_xinput_id) |
| if [ -z "$newid" ]; then |
| return |
| fi |
| apply_cpi_for_mouse $newid |
| |
| sens=$(load_pref SENS) |
| apply_sensitivity $sens "$newid" |
| swap_lr=$(load_pref SWAP_LR) |
| apply_swap_lr $swap_lr "$newid" |
| apply_button_remap "$newid" |
| |
| fixup_apple_magicmouse_driver_parameters "$newid" |
| |
| exit 0 |
| fi |
| |
| usage() { |
| echo "Usage:" \ |
| "$PROG {listdev|add|status|sensitivity [1-5]|swap_left_right" \ |
| "[01]|set property value}" |
| } |
| |
| MICE=$(find_mice) |
| if [ -z "$MICE" ]; then |
| exit 0 |
| fi |
| VALID=0 |
| |
| # If no args passed, print usage |
| if [ $# = 0 ] ; then |
| usage |
| exit 1 |
| fi |
| |
| while true ; do |
| COMMAND=$1 |
| VALID=0 |
| |
| if [ $# = 0 ] ; then |
| # If no commands remain, we're done |
| exit 0 |
| elif [ "$COMMAND" = "listdev" ] ; then |
| for mouse in $MICE ; do |
| echo "${mouse}" |
| done |
| VALID=1 |
| shift |
| elif [ "$COMMAND" = "status" ] ; then |
| for mouse in $MICE ; do |
| echo "Details for mouse ${mouse}:" |
| $XINPUT list-props $mouse |
| $XINPUT get-feedbacks $mouse |
| done |
| VALID=1 |
| shift |
| elif [ "$COMMAND" = "sensitivity" -a -n "$2" ] ; then |
| sens="$2" |
| store_pref SENS "$sens" |
| apply_sensitivity "$sens" "$MICE" |
| VALID=1 |
| shift 2 |
| elif [ "$COMMAND" = "swap_left_right" -a -n "$2" ] ; then |
| value="$2" |
| store_pref SWAP_LR "$value" |
| apply_swap_lr "$value" "$MICE" |
| VALID=1 |
| shift 2 |
| elif [ "$COMMAND" = "refresh" ] ; then |
| apply_cpi "$MICE" |
| apply_button_remap "$MICE" |
| apply_sensitivity $(load_pref SENS) "$MICE" |
| apply_swap_lr $(load_pref SWAP_LR) "$MICE" |
| VALID=1 |
| shift |
| elif [ "$COMMAND" = "set" -a -n "$2" -a -n "$3" ] ; then |
| prop=$2 |
| value=$3 |
| for mouse in $MICE ; do |
| $XINPUT set-prop $mouse "$prop" "$value" |
| done |
| VALID=1 |
| shift 3 |
| fi |
| |
| if [ $VALID = 0 ] ; then |
| usage |
| exit 1 |
| fi |
| done |