#!/usr/bin/env bash # tivasyk # License: GPU GPL v3 # Settings # -------- # It's probably a good idea to verify these prior to first use of the script and # modify if necessary. # IIO devices path (Linux industrial I/O subsystem) # One probably does not need to change this # iio_devices_path - path to the iio devices buffer tree # iio_devices_name - the file containing device name iio_devices_path="/sys/bus/iio/devices/iio:device" iio_devices_name="name" # Accelerometer device path and sensor files # accel_device_name - what we expect to find in the ../iio:deviceX/name file # accel_device_path - will be populated by identify_device(), may be set to override # accel_sensor_x - the channel file of the axis to check for screen rotation (x,y,z) accel_device_name="accel_3d" accel_device_path="" accel_sensor_x="in_accel_x_raw" accel_sensor_y="in_accel_y_raw" accel_sensor_z="in_accel_z_raw" # Current display that will be rotated. This will be populated automatically # with the name of connected output (xrandr) by the script if left empty. # Otherwise one can fill this in manually to omit automatical detection xdisplay="" # Input devices (touchpad and touchscreen) # One probably needs to run xinput --list to verify the names of the input devices # actually present and modify these variables accordingly. Leaving one of them blank # will omit rotation for that device. touchpad='' touchscreen='SYNAPTICS Synaptics Touch Digitizer V04' # Error codes error_arguments=1 # Incorrect argument(s) either to the script or a function error_device=2 # Accelerometer device path or folder structure not found? error_sensor=3 # Accelerometer sensor channel file $accel_sensor not found? # Functions # --------- show_help() { local NAME NAME=$(basename "$0") cat <]] [--help] -h, --help Print this help and quit -c, --cont Run continuously at specified interval (default 1s) Example: $NAME --cont 2 & # Run the script in the background at 2s intervals NOTE: The script has only been tested on Acer Aspire R13 (R7-371T) transformer laptop. EOF } identify_device() { # Will look for the device whose name is given as the only argument, # by comparing the devices names in /sys/bus/iio/devices/iio:deviceX/name # file and return the path to the device folder. # Relies on the devices_path variable set in the Setting section. # Process arguments: if [[ $# -eq 0 ]]; then # Incorrect arguments exit ${error_arguments} else local device_name="${1}" fi # Loop through all devices and check names: local device for device in "${iio_devices_path}"* ; do if [[ $(cat "${device}/${iio_devices_name}") == "${device_name}" ]]; then echo "${device}" fi done } read_accelerometer() { # The first argument is obligatory and should specify one axis # of the accelerometer device: -x, -y or -z # Also --raw will not try to decode the reading. # Process arguments: if [[ $# -eq 0 ]]; then # Incorrect arguments exit ${error_arguments} else while [[ "$*" != "" ]]; do local accel_sensor=${accel_sensor_x} case "$1" in # Check for --raw option "-r"|"--raw" ) local option_raw=1 ; shift ;; # Select accelerometer axis (-x is default) "-x" ) shift ;; "-y" ) accel_sensor=${accel_sensor_y} ; shift ;; "-z" ) accel_sensor=${accel_sensor_z} ; shift ;; # Ignore any other options * ) shift ;; esac done fi # Read the sensor: if [[ -f "${accel_device_path}/${accel_sensor}" ]]; then local reading ; reading=$(cat "${accel_device_path}/${accel_sensor}") else # No sensor file found? exit ${error_sensor} fi # Decode the reading # It's a 16-bit signed integer, but reads as a string # 1..1000 : positive angle (0-90°) # 65575..54576 : negative angle (0-90°) local max_reading=1000 local max_positive=32767 local max_integer=65535 # Decode reading into degrees (unless option_raw in set) if [[ -z ${option_raw} ]]; then if [[ ${reading} -gt ${max_positive} ]]; then echo "$(((reading - max_integer) / (max_reading / 90)))" else echo "$((reading / (max_reading / 90)))" fi else echo "${reading}" fi } rotate_screen() { # Will try to rotate the display and input devices, using: # xrandr to rotate the display picture; # xinput to rotate the touchpad and touchscreen (via Coordinate Transformation Matrix). # Relies on touchpad and touchscreen variables set in the Settings section. # Rotate the display: xrandr --output $1 --rotate $2 # Rotate the input devices transform='Coordinate Transformation Matrix' case "$2" in normal) [ ! -z "$touchpad" ] && xinput set-prop "$touchpad" "$transform" 1 0 0 0 1 0 0 0 1 [ ! -z "$touchscreen" ] && xinput set-prop "$touchscreen" "$transform" 1 0 0 0 1 0 0 0 1 ;; inverted) [ ! -z "$touchpad" ] && xinput set-prop "$touchpad" "$transform" -1 0 1 0 -1 1 0 0 1 [ ! -z "$touchscreen" ] && xinput set-prop "$touchscreen" "$transform" -1 0 1 0 -1 1 0 0 1 ;; left) [ ! -z "$touchpad" ] && xinput set-prop "$touchpad" "$transform" 0 -1 1 1 0 0 0 0 1 [ ! -z "$touchscreen" ] && xinput set-prop "$touchscreen" "$transform" 0 -1 1 1 0 0 0 0 1 ;; right) [ ! -z "$touchpad" ] && xinput set-prop "$touchpad" "$transform" 0 1 0 -1 0 1 0 0 1 [ ! -z "$touchscreen" ] && xinput set-prop "$touchscreen" "$transform" 0 1 0 -1 0 1 0 0 1 ;; esac } main() { # Process arguments while [[ "$*" != "" ]]; do case "$1" in "-h"|"--help" ) show_help exit 0 ;; "-c"|"--cont" ) # Check next argument for repeat interval option_cont=1 shift if [[ ! -z "$1" && -z "${1//[0-9.]/}" ]]; then option_cont="$1" shift fi ;; * ) ;; esac done # Identify the current display to be rotated if [[ "${xdisplay}" == "" ]]; then xdisplay=`xrandr --current | grep " connected" | sed -e 's/ .*//g'` fi # Identify the accelerometer device, unless the accel_device_path has been set manually if [[ "${accel_device_path}" == "" ]]; then accel_device_path=$(identify_device ${accel_device_name}) fi # Run the test while true ; do # Get the screen rotation angle from the accelerometer sensor angle_x=$(read_accelerometer -x) angle_y=$(read_accelerometer -y) angle_z=$(read_accelerometer -z) # Check orientation if [[ ${angle_z//-/} -lt 80 && ${angle_x} -gt 20 ]]; then echo "Screen orientation: left (x=${angle_x}, y=${angle_y}, z=${angle_z})" rotate_screen ${xdisplay} left elif [[ ${angle_z//-/} -lt 80 && ${angle_x} -lt -20 ]]; then echo "Screen orientation: right (x=${angle_x}, y=${angle_y}, z=${angle_z})" rotate_screen ${xdisplay} right elif [[ ${angle_y//-/} -gt 20 && ${angle_x//-/} -lt 20 ]]; then echo "Screen orientation: normal (x=${angle_x}, y=${angle_y}, z=${angle_z})" rotate_screen ${xdisplay} normal else echo "Screen orientation: keep (x=${angle_x}, y=${angle_y}, z=${angle_z})" fi # Run continuously (option_cont)? if [[ "${option_cont}" == "" ]]; then exit 0 else sleep ${option_cont} fi done } main "$@"