Blob Blame Raw
#!/bin/bash

set -e

# command to run a screen keyboard
KEYBOARD="coolkbd"
# arguments for the screen keyboard
KEYBOARD_ARGS="/dev/input/event1"
# 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 "    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"
}


# keyboard functions
function is_keyboard_run() {
    [ -n "$KEYBOARD" ]
    pidof "$KEYBOARD" > /dev/null
}
function run_keyboard() {
    if ! is_keyboard_run; then
        nohup $KEYBOARD $KEYBOARD_ARGS &> /dev/null &
    fi
}
function stop_keyboard() {
    [ -z "$KEYBOARD" ] || killall -q "$KEYBOARD" || true
}
function toggle_keyboard() {
    [ -n "$KEYBOARD" ] || return
    if is_keyboard_run; then stop_keyboard; else run_keyboard; 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_keyboard_run; 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
  elif [ "$1" = "kboff" ]; then
    echo "close screen keyboard"
    stop_keyboard
  elif [ "$1" = "kbtoggle" ]; then
    echo "toggle screen keyboard"
    toggle_keyboard
  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