#!/bin/bash
set -e
# directory to store pids of background processes
PIDS=/dev/shm/cool-rotate
# command to run a screen keyboard
KEYBOARD="coolkbd"
# arguments for the screen keyboard
KEYBOARD_ARGS="/dev/input/event1"
# command to run sensors monitor (which do the screen auto-rotation)
MONITOR="$(dirname "$0")/monitor.sh"
# arguments for the sensors monitor
MONITOR_ARGS=
# screen notify command, just comment out if it is not need
NOTIFY="notify-send"
# name of an input device to configure (from xinput)
INPUTDEV="Elan Touchscreen"
# name of a transformation matrix property of the device
MATRIX_PROP="Coordinate Transformation Matrix"
# name of a dead edges sizes property of the device
# by this property you can disable keyboard area from taps
# use it if the screen keyboard handle touches by it self directly from a device
# just comment out this if you don't need this feature
EDGE_PROP="Trackpad Edge Sizes"
# height of a dead zone area at the bottom of the screen
# integer value - count of percents of the screen height
KEYAREA=20
function usage() {
echo ""
echo "Usage ./rotate.sh [command] ..."
echo " available commands:"
echo " kbon - open screen keyboard"
echo " kboff - close screen keyboard"
echo " kbtoggle - toggle screen keyboard"
echo " aron - enable auto-rotation"
echo " aroff - disable auto-rotation"
echo " artoggle - toggle auto-rotation"
echo " quiet - disable screen notify"
echo " normal,left,inverted,right"
echo " - comma separated looped sequence of orientations"
echo " screen will be turned to the next state relative to current"
echo " if only one item is in sequence"
echo " then screen will be turned into it"
echo " if current state is not present in the sequence"
echo " then the first sequence item will be chosen"
echo " without args script will just configure the input device for the current orientation"
echo ""
}
# function gets a next item from the looped sequence
# example: next normal,left,inverted,right left
# will be echoed: inverted
function next() {
local res="$(echo "$1" | tr -s , '\n' | grep -i -x -A 1 "$2" | tail +2)"
if [ -z "$res" ]; then
res="$(echo "$1" | tr -s , '\n' | head -1)"
fi
echo "$res"
}
# always returns a valid name of the rotation (bad values will replaced with 'normal')
function fix_rotation_name() {
case "$1" in
right | inverted | left) echo "$1";;
*) echo "normal";;
esac
}
# check if the first arg is a comma separated sequence of valid rotation names
function is_rotation_sequence() {
local s="$(echo "$1" | tr -s , ' ')"
local x=
for x in $s; do
[ "$x" == "$(fix_rotation_name "$x")" ]
done
}
# show the current screen rotation
function current_rotation() {
fix_rotation_name "$(xrandr --screen 0 --current --query | head -2 | tail -1 | cut -d' ' -f5)"
}
# turn screen to chosen rotation
# possible values: normal, left, inverted and right
function rotate_screen() {
xrandr -o "$1"
}
# check if our serivice is running
function is_run() {
[ -f "$PIDS/$1.pid" ]
}
# run our service if it is not running
# args: service-name command command-args...
function run() {
local svc="$1"
shift
( ! is_run "$svc" ) || return 0
[ -n "$1" ] || return 0
nohup "$@" &> /dev/null &
local p="$!"
mkdir -p "$PIDS"
echo "$p" > "$PIDS/$svc.pid"
[ "$svc" != "monitor" ] || [ -z "$NOTIFY" ] || "$NOTIFY" "rotation ON"
}
# stop our service
function stop() {
is_run "$1" || return 0
kill "$(cat "$PIDS/$1.pid")" || true
rm "$PIDS/$1.pid"
[ "$1" != "monitor" ] || [ -z "$NOTIFY" ] || "$NOTIFY" "rotation OFF"
}
# stop our service if it is running or run it in other case
# args: service-name command command-args...
function toggle() {
[ -n "$1" ] || return 0
if is_run "$1"; then stop "$1"; else run "$@"; fi
}
# configure the input device for a specified rotation
function configure_input() {
local rot="$(current_rotation)"
local matrix=
local edges=
local area=0
if is_run keyboard; then area="$KEYAREA"; fi
echo "configure the input device for orientation: $rot"
case "$rot" in
left)
matrix="0 -1 1 1 0 0 0 0 1"
edges="0 0 0 $area"
;;
right)
matrix="0 1 0 -1 0 1 0 0 1"
edges="0 0 $area 0"
;;
inverted)
matrix="-1 0 1 0 -1 1 0 0 1"
edges="$area 0 0 0"
;;
*)
matrix="1 0 0 0 1 0 0 0 1"
edges="0 $area 0 0"
;;
esac
[ -z "$INPUTDEV" ] || [ -z "$MATRIX_PROP" ] || \
xinput --set-prop "$INPUTDEV" "$MATRIX_PROP" $matrix
[ -z "$INPUTDEV" ] || [ -z "$EDGE_PROP" ] || [ -z "$KEYAREA" ] || \
xinput --set-prop "$INPUTDEV" "$EDGE_PROP" $edges
}
# parse arguments
SHOW_USAGE=
CHANGED=
while [ "$#" != "0" ]; do
IS_CMD=1
if [ "$1" = "kbon" ]; then
echo "open screen keyboard"
run keyboard "$KEYBOARD" $KEYBOARD_ARGS
elif [ "$1" = "kboff" ]; then
echo "close screen keyboard"
stop keyboard
elif [ "$1" = "kbtoggle" ]; then
echo "toggle screen keyboard"
toggle keyboard "$KEYBOARD" $KEYBOARD_ARGS
elif [ "$1" = "aron" ]; then
echo "run auto-rotation sensor monitor"
run monitor "$MONITOR" $MONITOR_ARGS
elif [ "$1" = "aroff" ]; then
echo "stop auto-rotation sensor monitor"
stop monitor
elif [ "$1" = "artoggle" ]; then
echo "toggle auto-rotation sensor monitor"
toggle monitor "$MONITOR" $MONITOR_ARGS
elif [ "$1" = "quiet" ]; then
NOTIFY=
elif is_rotation_sequence "$1"; then
ROT="$(current_rotation)"
ROT="$(next "$1" "$ROT")"
echo "turn screen to: $ROT"
rotate_screen "$ROT"
else
echo "unknown command: $1"
IS_CMD=
fi
if [ -n "$IS_CMD" ]; then CHANGED=1; else SHOW_USAGE=1; fi
shift
done
[ -z "$SHOW_USAGE" ] || usage
( [ -n "$SHOW_USAGE" ] && [ -z "$CHANGED" ] ) || configure_input
[ -z "$SHOW_USAGE" ]
echo success