| #!/bin/sh |
| # Copyright (c) 2014 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. |
| |
| XINPUT=/usr/bin/xinput |
| |
| export DISPLAY=:0 |
| export XAUTHORITY=/home/chronos/.Xauthority |
| |
| pref_folder="/home/chronos/user/cmt" |
| if ! [ -d $pref_folder ]; then |
| mkdir $pref_folder |
| fi |
| if [ "$(id -u)" -eq 0 ]; then |
| chown chronos:chronos $pref_folder |
| fi; |
| # Functions for storing preferences |
| # A preference requires the following global variables: |
| # pref_${pref}_type: device type this preference is appllied on |
| # pref_${pref}_validator: a batch match to validate the preference value |
| # pref_${pref}_default: default value |
| # apply_${pref}: function to apply the preference to a device |
| # Also a list of all preference names is stored in the variable: preferences |
| |
| apply_preference() { |
| local pref="$1" |
| local type="$(eval echo \"\${pref_${pref}_type}\")" |
| local value="$3" |
| for device in $2; do |
| if device_is_${type} $device; then |
| log "Applying $pref=$value to device $device" |
| apply_${pref} "$device" "$value" |
| fi |
| done |
| } |
| |
| apply_all_preferences() { |
| local devices="$1" |
| for pref in $preferences; do |
| local value="$(load_preference $pref)" |
| for device in $devices; do |
| apply_preference $pref $device "$value" |
| done |
| done |
| } |
| |
| validate_preference() { |
| local pref="$1" |
| local value="$2" |
| local validator="$(eval echo \"\${pref_${pref}_validator}\")" |
| case $value in |
| $validator) true ;; |
| *) |
| echo "invalid value '${value}' for preference ${pref}" >&2 |
| false |
| ;; |
| esac |
| } |
| |
| transition_legacy_pref_file() { |
| local pref=$1 |
| local new_file="$pref_folder/$pref" |
| |
| case $pref in |
| "mouse_sensitivity") filename="mouse_sensitivity" ;; |
| "touchpad_sensitivity") filename="touchpad_sensitivity" ;; |
| "mouse_swap_lr") filename="mouse_swap_lr_buttons" ;; |
| "tapclick") filename="touchpad_tap_enable" ;; |
| "tapdrag") filename="touchpad_tap_drag_enable" ;; |
| "t5r2_three_finger_click") filename="touchpad_t5r2_3f_click_enable" ;; |
| *) return ;; |
| esac |
| |
| legacy_file="/home/chronos/user/$filename" |
| if [ -f $legacy_file ]; then |
| log "mv $legacy_file $new_file" |
| mv $legacy_file $new_file |
| chown chronos:chronos $new_file |
| fi |
| } |
| |
| load_preference() { |
| assert_eq $# 1 |
| local pref="$1" |
| local default="$(eval echo \"\${pref_${pref}_default}\")" |
| local file="$pref_folder/$pref" |
| |
| # The new inputcontrol script uses a different file path to store preferences |
| # Make sure to copy the old setting over when the new file does not yet exist. |
| if [ ! -f $file ]; then |
| transition_legacy_pref_file $pref |
| fi |
| |
| if [ ! -f $file ]; then |
| echo $default |
| return |
| fi |
| |
| local file_size="$(stat -c %s $file)" |
| if [ "$file_size" -gt "1000" ]; then |
| # invalid file size |
| echo $default |
| return |
| fi |
| |
| local value="$(cat ${file})" |
| if validate_preference $pref "$value"; then |
| echo $value |
| else |
| echo $default |
| fi |
| } |
| |
| save_preference() { |
| assert_eq $# 2 |
| local pref="$1" |
| local value="$2" |
| local pref_file="$pref_folder/$pref" |
| |
| if validate_preference "$pref" "$value"; then |
| log "echo $value > $pref_file" |
| echo "$value" > $pref_file |
| fi |
| } |
| |
| # Functions to access information about a device |
| |
| device_get_name() { |
| assert_eq $# 1 |
| xinput --list --name-only $1 |
| } |
| |
| device_get_canonical_name() { |
| assert_eq $# 1 |
| device_get_name $device | sed 's/[^a-zA-Z0-9]/_/g' |
| } |
| |
| device_set_prop() { |
| assert_eq $# 3 |
| log "$XINPUT set-prop \"$1\" \"$2\" $3" |
| $XINPUT set-prop "$1" "$2" $3 |
| } |
| |
| device_get_prop() { |
| assert_eq $# 2 |
| $XINPUT list-props $1 | awk "/$2/ { print \$4 }" |
| } |
| |
| device_get_bool_prop() { |
| assert_eq $# 2 |
| prop=$(device_get_prop $1 "$2") |
| [ "$prop" = "1" ] |
| } |
| |
| device_get_string_prop() { |
| assert_eq $# 2 |
| prop=$(device_get_prop $1 "$2") |
| # get rid of " around value via eval |
| eval echo $prop |
| } |
| |
| device_is_mouse() { |
| assert_eq $# 1 |
| device_get_bool_prop $1 "Device Mouse" |
| } |
| |
| device_is_multitouch() { |
| assert_eq $# 1 |
| device_get_bool_prop $1 "Device Touchpad" |
| } |
| |
| device_is_touchpad() { |
| assert_eq $# 1 |
| ! device_is_mouse $1 && device_is_multitouch $1 |
| } |
| |
| device_is_multitouch_mouse() { |
| assert_eq $# 1 |
| device_is_mouse $1 && device_is_multitouch $1 |
| } |
| |
| device_is_nontouch_mouse() { |
| assert_eq $# 1 |
| device_is_mouse $1 && ! device_is_multitouch $1 |
| } |
| |
| device_is_touchscreen() { |
| assert_eq $# 1 |
| device_get_name $1 | grep -q '[tT]ouch[sS]creen' |
| } |
| |
| device_is_valid() { |
| assert_eq $# 1 |
| device_is_mouse $1 || device_is_multitouch $1 || device_is_touchscreen $1 |
| } |
| |
| device_status() { |
| assert_eq $# 1 |
| if device_is_valid $1; then |
| echo |
| echo "ID $1:" |
| $XINPUT list-props $1 |
| fi; |
| } |
| |
| # Functions to list devices |
| |
| list_devices() { |
| # optional first argument is filter method |
| local filter=device_is_valid |
| if ! [ -z $1 ]; then |
| filter=$1 |
| fi |
| |
| # 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 devices="$($XINPUT list | \ |
| awk '/.*slave.*/ { for (i=1; i<NF; i++) \ |
| if ($i ~/id=/) print substr($i, 4) }')" |
| |
| for device in $devices ; do |
| if $filter $device; then |
| echo -n " ${device}" |
| fi |
| done |
| } |
| |
| list_mice() { |
| list_devices device_is_mouse |
| } |
| |
| list_touchpads() { |
| list_devices device_is_touchpad |
| } |
| |
| list_touchscreens() { |
| list_devices device_is_touchscreen |
| } |
| |
| list_multitouch() { |
| list_devices device_is_multitouch |
| } |
| |
| list_multitouch_mice() { |
| list_devices device_is_multitouch_mouse |
| } |
| |
| # Returns the xinput ID of the newly attached mouse. If X hasn't loaded a driver |
| # for the new mouse, yet, this will not print anything. If found, it prints the |
| # xinput ID. |
| get_device_by_devname() { |
| # Get the list of xinput IDs: |
| local ids="$(list_devices)" |
| if [ -z "$ids" ]; then |
| return |
| fi |
| for id in $ids; do |
| local test_node=$(device_get_prop $id "Device Node") |
| if [ "$test_node" = "\"$1\"" ]; then |
| echo $id |
| return |
| fi |
| done |
| } |
| |
| wait_and_get_added_device() { |
| tries=10 |
| while [ "$tries" -ne "0" ]; do |
| tries=$((tries - 1)) |
| newid=$(get_device_by_devname $1) |
| if [ -n "$newid" ]; then |
| echo $newid |
| return |
| fi |
| sleep 1 |
| done |
| } |
| |
| |
| canonical_ids() { |
| # In case minus number is passed, truncate it to the last 4 hexdigits. |
| # e.g., -16360 -> ffffffffffffc018 -> c018 |
| local id_strings id_str first |
| read id_strings |
| for id_str in $id_strings; do |
| if [ -n "$first" ]; then |
| printf ":" |
| fi |
| printf "%04x" "$id_str" | sed 's/.*\(.\{4\}\)$/\1/' |
| first="not" |
| done |
| } |
| |
| device_get_vendor_product() { |
| local xinput_id="$1" |
| |
| local vp="$(xinput list-props $xinput_id 2>/dev/null \ |
| | fgrep "Device Product ID" | \ |
| cut -d : -f 2 | sed 's/,//' | canonical_ids)" |
| if ! echo "${vp}" | grep -q ':'; then |
| vp="$(xinput list-props $xinput_id 2>/dev/null \ |
| | fgrep "Device Vendor ID" | \ |
| cut -d : -f 2 | canonical_ids)" |
| vp="${vp}:$(xinput list-props $xinput_id 2>/dev/null \ |
| | fgrep "Device Product ID" | \ |
| cut -d : -f 2 | canonical_ids)" |
| fi |
| echo "$vp" |
| } |
| |
| |
| # Helper for debugging in bash |
| |
| log() { |
| if [ ${FLAGS_verbose} -eq ${FLAGS_TRUE} ] ; then |
| echo "$@" >&2 |
| fi |
| } |
| |
| assert_eq() { |
| if [ "$1" -ne "$2" ]; then |
| echo "${FUNCNAME[1]}: Assertion '$1' == '$2' failed" >&2 |
| exit -1 |
| fi |
| } |
| |
| # FUNCNAME is only available in BASH. Disable assert_eq on all other shells. |
| if [ -z "$BASH_VERSION" ]; then |
| assert_eq() { true; } |
| fi |