Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Script to rotate the screen and touch devices on modern Linux desktops. Great for convertible laptops.
#!/bin/bash
#
# rotate_desktop.sh
#
# Rotates modern Linux desktop screen and input devices to match. Handy for
# convertible notebooks. Call this script from panel launchers, keyboard
# shortcuts, or touch gesture bindings (xSwipe, touchegg, etc.).
#
# Using transformation matrix bits taken from:
# https://wiki.ubuntu.com/X/InputCoordinateTransformation
#
# Configure these to match your hardware (names taken from `xinput` output).
TOUCHPAD='SynPS/2 Synaptics TouchPad'
TOUCHSCREEN='Atmel Atmel maXTouch Digitizer'
if [ -z "$1" ]; then
echo "Missing orientation."
echo "Usage: $0 [normal|inverted|left|right] [revert_seconds]"
echo
exit 1
fi
function do_rotate
{
xrandr --output $1 --rotate $2
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
}
XDISPLAY=`xrandr --current | grep primary | sed -e 's/ .*//g'`
XROT=`xrandr --current --verbose | grep primary | egrep -o ' (normal|left|inverted|right) '`
do_rotate $XDISPLAY $1
if [ ! -z "$2" ]; then
sleep $2
do_rotate $XDISPLAY $XROT
exit 0
fi
@mildmojo

This comment has been minimized.

Copy link
Owner Author

@mildmojo mildmojo commented Jun 18, 2014

Tested with the following versions:

$ xinput --version
xinput version 1.6.1
XI version on server: 2.3
$ xrandr --version
xrandr program version       1.4.1
Server reports RandR version 1.4
@JosephLeedy

This comment has been minimized.

Copy link

@JosephLeedy JosephLeedy commented Sep 6, 2014

Thanks! This worked great with my HP Envy x360! I had to calibrate it first by running the command xinput_calibrator --output-type xorg.conf.d and following its instructions to get the pointer orientation correct.

@mnpale

This comment has been minimized.

Copy link

@mnpale mnpale commented May 19, 2015

Thanks, this helped me flip the screen on my XPS 12 in Linux Mint. I tied this to keyboard shortcuts.

@maferv

This comment has been minimized.

Copy link

@maferv maferv commented Dec 12, 2015

Beautiful script. God bless you.

@KoljaWindeler

This comment has been minimized.

Copy link

@KoljaWindeler KoljaWindeler commented Dec 26, 2015

Great script! Thanks. I've extended it to toggle between left and normal by reading the current orientation.

@yzpaul

This comment has been minimized.

Copy link

@yzpaul yzpaul commented Jan 10, 2016

This is phenomenal, thank you so much!

@Apollia

This comment has been minimized.

Copy link

@Apollia Apollia commented Jun 10, 2016

Thank you so much!!! Works great on my Toughbook CF-C1 in Lighthouse 64 Puppy Linux 6.02 Beta 2!

My forked and slightly modified version:

https://github.com/Apollia/Rotate-Toughbook-CF-C1-Screen-in-Lighthouse-64-Puppy-Linux-6.02-Beta-2/tree/master

@infinitekh

This comment has been minimized.

Copy link

@infinitekh infinitekh commented Sep 24, 2016

Thanks!! This is so good!!
I use this script for watching youtube personal cam video that looks on stars.

Hmmm. But two touch or three touch events are yet normal mode.
Is this are impossible using xinput?

@mildmojo

This comment has been minimized.

Copy link
Owner Author

@mildmojo mildmojo commented Feb 15, 2017

I'm not sure about multitouch gestures; I think I use touchegg to manage them, and I use them so infrequently that I never noticed if they were correct after rotation. I've been pretty disappointed with multitouch gestures and touchscreen support in Linux, TBH.

@leabdd

This comment has been minimized.

Copy link

@leabdd leabdd commented Feb 18, 2017

I'm new to Linux/Ubuntu and have only tried it on my Yoga 2 11 per USB-Stick. So my question is if it somehow it possible to get the code in a GUI where you can just press 4 buttons and it will change the rotation of the Screen.

@aiya000

This comment has been minimized.

Copy link

@aiya000 aiya000 commented Jul 23, 2017

Great !!
Thank you !

@debdeepbh

This comment has been minimized.

Copy link

@debdeepbh debdeepbh commented Sep 23, 2017

Works perfectly except for the scrolling part. Both edge scrolling and two finger scrolling remain unchanged after the coordinate transform. Any idea how to fix this?
EDIT: If the stylus, touchscreen and eraser is a Wacom device, the following works instead of the coordinate transform:
xsetwacom set "$TOUCHSCREEN" Rotate ccw

The options for Rotate can be one of ccw/cw/half/none from this link.

@mildmojo

This comment has been minimized.

Copy link
Owner Author

@mildmojo mildmojo commented Sep 28, 2017

@rbnbdd A GUI is farther than I want to go with this, but a GUI could easily call this script.

You could add quick launcher icons to your panel or desktop that call this script with the proper arguments for the rotations. Just add a new shortcut the way you regularly would, and tell it to run this script like e.g. /Users/<username>/rotate_desktop.sh inverted.

@tuxflo

This comment has been minimized.

Copy link

@tuxflo tuxflo commented Dec 19, 2017

@rbnbdd It should be not too hard if you're using Zenity or something like that.

@mildmojo do you know an approach to remove the second parameter and do just a "toggle" through the different modes?

@yuletide

This comment has been minimized.

Copy link

@yuletide yuletide commented Jan 5, 2018

Haven't tried this exact script yet but another with similar approach here breaks the keyboard cover and touchpad (only when rotated!) on a Surface 2017 with running Ubuntu 16.04. Any ideas how to fix?

@mildmojo

This comment has been minimized.

Copy link
Owner Author

@mildmojo mildmojo commented Feb 2, 2018

@tuxflo The XROT line shows how to get the current mode; you'd want to get that and then look through a list of the modes to find the next one to switch to.

@yuletide Sorry, I haven't tried this on a Surface. My test box was a Lenovo Yoga.

@mmhobi7

This comment has been minimized.

Copy link

@mmhobi7 mmhobi7 commented Mar 2, 2018

@rbnbdd
if your own ubuntu or debian, search for shortcuts in keyboard settings

@zx6802

This comment has been minimized.

Copy link

@zx6802 zx6802 commented May 1, 2018

@ rbnbdd 18 Feb 2017
On Lubuntu LXHotkey provides a graphical interface for binding programs to keys.

@TroyFletcher

This comment has been minimized.

Copy link

@TroyFletcher TroyFletcher commented Jul 21, 2018

Extensible, flexible, and commented. Thank you!

@mbinnun

This comment has been minimized.

Copy link

@mbinnun mbinnun commented Aug 31, 2018

I have been using your script for a while but changed it a bit:

  • Added an option to transform all pointing devices (not from a hardcoded device name)
  • Added an option to transform only the devices from a specific type (see comments)
  • Removed the unnecessery option to transform back automatically after a while

Here's my code:

#!/bin/bash

if [ -z "$1" ] ; then
  echo "Usage: $0 [normal|inverted|left|right]"
  echo " "
  exit 1
fi

function do_rotate
{
  xrandr --output $1 --rotate $2

  TRANSFORM='Coordinate Transformation Matrix'

  POINTERS=`xinput | grep 'slave  pointer'`
  POINTERS=`echo $POINTERS | sed s/↳\ /\$/g`
  POINTERS=`echo $POINTERS | sed s/\ id=/\@/g`
  POINTERS=`echo $POINTERS | sed s/\ \\\[slave\ pointer/\#/g`
  iIndex=2
  POINTER=`echo $POINTERS | cut -d "@" -f $iIndex | cut -d "#" -f 1`
  while [ "$POINTER" != "" ] ; do
    POINTER=`echo $POINTERS | cut -d "@" -f $iIndex | cut -d "#" -f 1`
    POINTERNAME=`echo $POINTERS | cut -d "$" -f $iIndex | cut -d "@" -f 1`
    #if [ "$POINTER" != "" ] && [[ $POINTERNAME = *"TouchPad"* ]]; then    # ==> uncomment to transform only touchpads
    #if [ "$POINTER" != "" ] && [[ $POINTERNAME = *"TrackPoint"* ]]; then  # ==> uncomment to transform only trackpoints
    #if [ "$POINTER" != "" ] && [[ $POINTERNAME = *"Digitizer"* ]]; then   # ==> uncomment to transform only digitizers (touch)
    #if [ "$POINTER" != "" ] && [[ $POINTERNAME = *"MOUSE"* ]]; then       # ==> uncomment to transform only optical mice
    if [ "$POINTER" != "" ] ; then                                         # ==> uncomment to transform all pointer devices
        case "$2" in
            normal)
              [ ! -z "$POINTER" ]    && xinput set-prop "$POINTER" "$TRANSFORM" 1 0 0 0 1 0 0 0 1
              ;;
            inverted)
              [ ! -z "$POINTER" ]    && xinput set-prop "$POINTER" "$TRANSFORM" -1 0 1 0 -1 1 0 0 1
              ;;
            left)
              [ ! -z "$POINTER" ]    && xinput set-prop "$POINTER" "$TRANSFORM" 0 -1 1 1 0 0 0 0 1
              ;;
            right)
              [ ! -z "$POINTER" ]    && xinput set-prop "$POINTER" "$TRANSFORM" 0 1 0 -1 0 1 0 0 1
              ;;
        esac      
    fi
    iIndex=$[$iIndex+1]
  done
}

XDISPLAY=`xrandr --current | grep primary | sed -e 's/ .*//g'`
if [ "$XDISPLAY" == "" ] || [ "$XDISPLAY" == " " ] ; then
  XDISPLAY=`xrandr --current | grep connected | sed -e 's/ .*//g' | head -1`
fi

do_rotate $XDISPLAY $1

@DaringDreams

This comment has been minimized.

Copy link

@DaringDreams DaringDreams commented Oct 6, 2018

Was able to fix the touch screen on Linux Cinnamon by using the following:

  1. Type the following in the terminal:
    xrandr -o orientation
    Replace orientation with the orientation you want.

  2. Get the touch screen device name using the following command:
    xinput list

  3. xinput set-prop '' 'Coordinate Transformation Matrix' matrix-elements-rowwise
    Replace matrix-elements-rowwise with 0 1 0 -1 0 1 0 0 1 or one of the other three orientation number sets mentioned above.

@i-am-neet

This comment has been minimized.

Copy link

@i-am-neet i-am-neet commented Oct 11, 2018

Great Script!!! Thanks a lot!!!
I test it on NUC with gechic on-lap 1102i touch screen,
And it works perfectly, thanks!

@doublehp

This comment has been minimized.

Copy link

@doublehp doublehp commented Dec 3, 2018

On my Raspberry pi, with screen Quimat SPI, here is what I needed:

Landscape with ethernet on the left:
/boot/config.txt
dtoverlay=tft35a:rotate=270,swapxy=1
but Y axis is inverted, and no combination of xmin=200,xmax=3900,ymin=200,ymax=3900 could fix it for me.

I don't need console, so, I fixed inversion only for Xorg with this command:
xinput set-prop "$TOUCHPAD" "$TRANSFORM" 1 0 0 0 -1 1 0 0 1

@cunidev

This comment has been minimized.

Copy link

@cunidev cunidev commented Feb 6, 2019

A must-have. Thank you

@ebrensi

This comment has been minimized.

Copy link

@ebrensi ebrensi commented May 2, 2019

Hi all. I had a similar problem on my HP Spectre x360 Convertible using Linux Mint 19 with Cinnamon. The Cinnamon desktop manager has
System Settings >> General >> Enable/Disable automatic screen rotation

Automatic screen rotation correctly rotates the orientation of the touchscreen device, but not the pen (stylus) functionality.
I adapted an existing script to do that, and you might find my script useful to automate pointing device orientation.
Check it out here: https://gist.github.com/ebrensi/6d270bd84f04fbe0366fbbc3e5cf7054

@marian556

This comment has been minimized.

Copy link

@marian556 marian556 commented May 24, 2019

if the code posted by mbinnun is called rotate.sh
then call this rotateloop.sh:
while read line do ./rotate.sh "$line" done < /dev/stdin

and call this one liner autorotate.sh

/usr/bin/monitor-sensor | unbuffer -p grep -o "right|normal|bottom|left" | unbuffer -p sed 's/bottom/inverted/g' | unbuffer -p ./rotateloop.sh

This will detect orientation of laptop and adjusts the screen.
You need to install :
apt install iio-sensor-proxy expect

@mikelduke

This comment has been minimized.

Copy link

@mikelduke mikelduke commented Jun 8, 2019

Thanks for sharing this! I had the same issue on Ubuntu and combined the solutions here in a repo https://github.com/mikelduke/rotate-touchscreen to make it easier to run

@maxigit

This comment has been minimized.

Copy link

@maxigit maxigit commented Mar 11, 2020

Exactly what I was looking for, Thanks !
(I add to change "primary" to " connected" and set the TOUCHSCREEN to actual touchscreen Id but It works like a cham)

@mildmojo

This comment has been minimized.

Copy link
Owner Author

@mildmojo mildmojo commented Apr 13, 2020

I'm happy people are still getting some mileage out of this script! I'm actually still using that laptop and I've had this script bound to ctrl + super + alt + <arrows> to pick a screen orientation for years. It's especially handy when I want to fold the screen flat or bend it backwards in tent mode to show something to a person across the table from me.

Back when I originally checked, my model was a weird orphan in the Yoga line that compared accelerometer angles in the base and the screen to calculate orientation in Windows, and since no other laptop does it that way, there wasn't Linux support for an automatic solution.

@Bloodchiefy

This comment has been minimized.

Copy link

@Bloodchiefy Bloodchiefy commented Dec 29, 2020

Thank you guys very much!

@denics

This comment has been minimized.

Copy link

@denics denics commented Feb 20, 2021

well, this is mine :) I run it on Debian Mate on a XPS13
the script is called /usr/local/bin/rotate.sh and it starts via mate startup programs. Thanks for all your inspiring comments!

#!/bin/sh
# Auto rotate screen based on device orientation

# Receives input from monitor-sensor (part of iio-sensor-proxy package)
# Screen orientation and launcher location is set based upon accelerometer position
# Launcher will be on the left in a landscape orientation and on the bottom in a portrait orientation
# This script should be added to startup applications for the user

# Clear sensor.log so it doesn't get too long over time
> /var/log/sensor.log

# Launch monitor-sensor and store the output in a variable that can be parsed by the rest of the script
monitor-sensor >> /var/log/sensor.log 2>&1 &

# Parse output or monitor sensor to get the new orientation whenever the log file is updated
# Possibles are: normal, bottom-up, right-up, left-up
# Light data will be ignored
TRANSFORM='Coordinate Transformation Matrix'
POINTER='DLL077A:01 06CB:76AF Touchpad'
TOUCH='Wacom HID 482F Finger touch'

while inotifywait -e modify /var/log/sensor.log; do
# Read the last line that was added to the file and get the orientation
	ORIENTATION=$(tail -n 1 /var/log/sensor.log | grep 'orientation' | grep -oE '[^ ]+$')

# Set the actions to be taken for each possible orientation
	case "$ORIENTATION" in
	normal)
		xrandr --output eDP-1 --rotate normal 
		xinput set-prop "$POINTER" "$TRANSFORM" 1 0 0 0 1 0 0 0 1
		xinput set-prop "$TOUCH" "$TRANSFORM" 1 0 0 0 1 0 0 0 1
		;;
	bottom-up)
		xrandr --output eDP-1 --rotate inverted 
		xinput set-prop "$POINTER" "$TRANSFORM" -1 0 1 0 -1 1 0 0 1
		xinput set-prop "$TOUCH" "$TRANSFORM" -1 0 1 0 -1 1 0 0 1
		;;
	right-up)
		xrandr --output eDP-1 --rotate right 
		xinput set-prop "$POINTER" "$TRANSFORM" 0 1 0 -1 0 1 0 0 1
		xinput set-prop "$TOUCH" "$TRANSFORM" 0 1 0 -1 0 1 0 0 1
		;;
	left-up)
		xrandr --output eDP-1 --rotate left 
		xinput set-prop "$POINTER" "$TRANSFORM" 0 -1 1 1 0 0 0 0 1
		xinput set-prop "$TOUCH" "$TRANSFORM" 0 -1 1 1 0 0 0 0 1
		;;
esac
done
@mihanich

This comment has been minimized.

Copy link

@mihanich mihanich commented Feb 27, 2021

got Y axis inverted and none of options fit to resolve it.
For those who get same pain as me - https://codepen.io/GottZ/full/pWpNgK
This tool helps to transform all rotation right.

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented Apr 17, 2021

Here is my take on it …

I wanted an automatic one-shot utility script, which figures out automatically the orientation of the device and adjusts screen and input devices accordingly. No automatic permanent rotations of the screen, if you hold the tablet at an angle, no deciding, if this orientation is left or right, just move the tablet into the position you want and call this script.

EDIT2: The script now has command line parameters and can be used in more situations:

  1. rotate-screen: Get the current orientation from the hardware accelerometer and rotate screen and pointers accordingly.
  2. rotate-screen screen: Get the current orientation from the screen and a rotate the points accordingly.
  3. rotate-screen next: Get the current orientation from the screen and switch screen and pointers to the next orientation (normal→left→inverted→right→normal). rotate-screen previous cycles the other direction.
  4. rotate-screen normal|left|inverted|right: Switch screen and pointers to the given orientation.
  5. rotate-screen --help: Shows extensive help. (Also have a look at the comment section at the start of the script.)

I use it in Linux Mint 20.1 with the Comand Launcher applet and the rotation-allowed-symbolic icon, because whenever my device is rotated, the attached keyboard is disabled by its firmware:

#!/bin/sh
#
# One-shot automatic screen rotation
#
# If the attached keyboard is switched off, whenever the tablet is
# rotated, it is best to put this command into the panel, because
# hotkeys do not work.
#
# On Cinnamon, the 'Command Launcher' add-on can be used with the
# following settings:
#   Panel Icon:                         rotation-allowed-symbolic
#   Tooltip:                            Set screen rotation
#   Keyboard shortcut:                  unassigned | unassigned
#   Show notification on completion:    NO
#   Command:                            rotate-screen
#   Run as root:                        NO
#   Run in alternate directory:         NO
#
# A possible .desktop file can look like this:
#   [Desktop Entry]
#   Encoding=UTF-8
#   Version=1.0
#   Name=Rotate
#   Comment=Rotate Screen
#   Type=Application
#   Exec=rotate-screen
#   Icon=rotation-allowed-symbolic
#   Terminal=false
#   Categories=Settings
#   StartupNotify=true
# and could be saved in ~/.local/share/applications/rotate-screen.desktop
#
# Anchestors and ideas:
#   mildmojo
#   https://gist.github.com/mildmojo/48e9025070a2ba40795c
#   mbinnun:
#   https://gist.github.com/mildmojo/48e9025070a2ba40795c#gistcomment-2694429
#   frgomes:
#   https://github.com/frgomes/bash-scripts/blob/develop/bin/rotate

GDBUS=gdbus
XINPUT=xinput
XRANDR=xrandr


usage () {
    # Display the usage
    #
    # No options

    cat <<EOF
$(basename $0) [-h|--help] [screen|next|previous|normal|left|inverted|right]

Rotate the screen and all pointing devices (touchscreens, pens, touchpads, ...)

The script can handle the following typical use cases:
1. One-shot rotation (automatic detection):
   You hold the device in the new orientation desired and invoke this script.
   The screen and all pointing devices rotate.
   Usage:
      - Disable automatic screen rotation in the settings for your desktop
        environment.
      - Hold the device in the new orientation and call this script with "$0".
   Pre-requisites:
      Programs: $GDBUS, $XINPUT, $XRANDR
      Hardware: Accelerometer
      Package: iio-sensor-proxy
2. Automatic screen rotation, but pointing devices do not rotate:
   The orientation of the screen is set by the desktop environment, but the
   pointing devices are not.
   Usage:
      - Enable automatic screen rotation in the settings for your desktop
        environment.
      - Hold the device in the new orientation and call this script with
        "$0 screen".
   Pre-requisites:
      Programs: $XINPUT, $XRANDR
      Hardware: --
      Package: --
3. Cycle through screen rotations:
   The orientation of the screen is cycled through normal -> left -> inverted
   -> right -> normal (option "next") or in reversed order (option "previous")
   with each call of this script.
   Usage:
      - Disable automatic screen rotation in the settings for your desktop
        environment.
      - Call this script with "$0 next|previous".
   Pre-requisites:
      Programs: $XINPUT, $XRANDR
      Hardware: --
      Package: --
4. One-shot rotation (manual):
   Independent of the actual orientation of the device, the orientation is
   set to the given orientation.
   Usage:
      - Disable automatic screen rotation in the settings for your desktop
        environment.
      - Call this script with "$0 normal|inverted|left|right".
   Pre-requisites:
      Programs: $XINPUT, $XRANDR
      Hardware: --
      Package: --

Note:
   Sometimes not all pointing devices are rotated. The reason is, that the
   pointing device was not active at the time of rotation, as can happen with
   e.g. bluetooth pens. In that case simply call the script again with the
   same parameter.


Parameters:
   -h, --help     Display this help and exit.
   screen, next, normal, left, inverted, right
                  The new orientation (optional). The default behaviour (no
                  option) is to use the orientation from the built-in
                  accelerometer. If 'screen' is given, use the screen's
                  current orientation. 'next' will switch to the next
                  orientation and any other option switches to the specified
                  orientation, regardless of the device's or the screen's
                  actual orientation.
EOF

}


check_commands () {
    # Check for commands needed
    #
    # $1: The required orientation

    if test $1 = auto; then
        GDBUS=$(which $GDBUS)
        if test -z $GDBUS; then
            echo "Command 'gdbus' not found."
            exit 10
        fi
    fi

    XINPUT=$(which $XINPUT)
    if test -z $XINPUT; then
        echo "Command 'xinput' not found."
        exit 11
    fi

    XRANDR=$(which $XRANDR)
    if test -z $XRANDR; then
        echo "Command 'xrandr' not found."
        exit 12
    fi
}


get_dbus_orientation () {
    # Get the orientation from the DBus
    #
    # No options.

    # DBus to query to get the current orientation
    DBUS="--system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy"

    # Check, if DBus is available
    ORIENTATION=$($GDBUS call $DBUS \
                        --method org.freedesktop.DBus.Properties.Get \
                                 net.hadess.SensorProxy HasAccelerometer)
    if test $? != 0; then
        echo $ORIENTATION
        echo " (Is the 'iio-sensor-proxy' package installed and enabled?)"
        exit 20
    elif test "$ORIENTATION" != "(<true>,)"; then
        echo "No sensor available!"
        echo " (Does the computer has a hardware accelerometer?)"
        exit 21
    fi

    # Get the orientation from the DBus
    ORIENTATION=$($GDBUS call $DBUS \
                        --method org.freedesktop.DBus.Properties.Get \
                        net.hadess.SensorProxy AccelerometerOrientation)

    # Release the DBus
    $GDBUS call --system $DBUS --method net.hadess.SensorProxy.ReleaseAccelerometer > /dev/null

    # Normalize the orientation
    case $ORIENTATION in
        "(<'normal'>,)")
            ORIENTATION=normal
            ;;
        "(<'bottom-up'>,)")
            ORIENTATION=inverted
            ;;
        "(<'left-up'>,)")
            ORIENTATION=left
            ;;
        "(<'right-up'>,)")
            ORIENTATION=right
            ;;
        *)
            echo "Orientation $ORIENTATION unknown!"
            echo " (Known orientations are: normal, bottom-up, left-up and right-up.)"
            exit 22
    esac

    # Return the orientation found
    echo $ORIENTATION
}


get_screen_orientation () {
    # Get the orientation from the current screen orientation
    #
    # $1: The screen

    ORIENTATION=$($XRANDR --current --verbose | grep $1 | cut --delimiter=" " -f6)

    case $ORIENTATION in
        normal|inverted|left|right)
            ;;
        *)
            echo "Current screen orientation $ORIENTATION unknown!"
            exit 23
            ;;
    esac

    # Return the orientation found
    echo $ORIENTATION
}


do_rotate () {
    # Rotate screen and pointers
    #
    # $1: The requested mode (only "screen" gets a special treatment)
    # $2: The new orientation
    # $3: The screen to rotate
    # $4-: The pointers to rotate

    TRANSFORM='Coordinate Transformation Matrix'

    MODE=$1
    shift

    ORIENTATION=$1
    shift

    # Rotate the screen
    if test $MODE != screen; then
        # Only rotate it, if we have not got the orientation from the screen
        $XRANDR --output $1 --rotate $ORIENTATION
    fi
    shift

    # Rotate all pointers
    while test $# -gt 0; do
        case $ORIENTATION in
            normal)
                $XINPUT set-prop $1 "$TRANSFORM" 1 0 0 0 1 0 0 0 1
                ;;
            inverted)
                $XINPUT set-prop $1 "$TRANSFORM" -1 0 1 0 -1 1 0 0 1
                ;;
            left)
                $XINPUT set-prop $1 "$TRANSFORM" 0 -1 1 1 0 0 0 0 1
                ;;
            right)
                $XINPUT set-prop $1 "$TRANSFORM" 0 1 0 -1 0 1 0 0 1
                ;;
        esac
        shift
    done
}


# Process the command line options
MODE=auto
while true; do
    case $1 in
        -h|--help)
            usage
            exit
            ;;
        *)
            if test $# -eq 0; then
                break
            fi
            MODE=$1
            shift
            ;;
    esac
done

# Check, if all commands, which are needed, are available
check_commands $MODE

# Get the display
XDISPLAY=$($XRANDR --current --verbose | grep primary | cut --delimiter=" " -f1)

# Get the tablet's orientation
case $MODE in
    auto)
        ORIENTATION=$(get_dbus_orientation)
        ret=$?
        if test $ret != 0; then
            echo $ORIENTATION
            echo "(To use this script, supply the orientation normal, inverted, left or right on the command line.)"
            exit $ret
        fi
        ;;
    screen)
        ORIENTATION=$(get_screen_orientation $XDISPLAY)
        ret=$?
        if test $ret != 0; then
            echo $ORIENTATION
            exit $ret
        fi
        ;;
    next)
        ORIENTATION=$(get_screen_orientation $XDISPLAY)
        ret=$?
        if test $ret != 0; then
            echo $ORIENTATION
            exit $ret
        fi
        case $ORIENTATION in
            normal)
                ORIENTATION=left
                ;;
            left)
                ORIENTATION=inverted
                ;;
            inverted)
                ORIENTATION=right
                ;;
            right)
                ORIENTATION=normal
                ;;
            *)
                ORIENTATION=normal
                ;;
        esac
        ;;
    previous)
        ORIENTATION=$(get_screen_orientation $XDISPLAY)
        ret=$?
        if test $ret != 0; then
            echo $ORIENTATION
            exit $ret
        fi
        case $ORIENTATION in
            normal)
                ORIENTATION=right
                ;;
            left)
                ORIENTATION=normal
                ;;
            inverted)
                ORIENTATION=left
                ;;
            right)
                ORIENTATION=inverted
                ;;
            *)
                ORIENTATION=normal
                ;;
        esac
        ;;
    normal|inverted|left|right)
        ORIENTATION=$MODE
        ;;
    *)
        echo "Unknown command line parameter orientation $MODE"
        exit 1
esac

# Get all pointers
POINTERS=$($XINPUT | grep slave | grep pointer | sed -e 's/^.*id=\([[:digit:]]\+\).*$/\1/')

# Rotate the screen and pointers
echo "Rotate display $XDISPLAY to $ORIENTATION orientation (Pointers: $(echo $POINTERS | sed 's/\n/ /g'))"
do_rotate $MODE $ORIENTATION $XDISPLAY $POINTERS

This script can now be found at https://github.com/linux-surface/linux-surface/tree/master/contrib/rotate-screen, where it will also receive future updates.

EDIT: Script updated, so that the error message is displayed, if no accelerometer can be found.
EDIT2: Script update: Command line options, new functionality. Many thanks to https://gist.github.com/mildmojo/48e9025070a2ba40795c#gistcomment-3747448

@frgomes

This comment has been minimized.

Copy link

@frgomes frgomes commented May 3, 2021

Hi,

I've spent a lot of time fighting this very subject and I've tried so many different things.
No: I'm not going to describe all tentatives and failures here.

In the end, I've stumbled with a solution which is at the same time short, simple and powerful.
In a nutshell, all you need to do is something similar to these lines below:

#!/bin/bash -eu

    monitor=eDP # you should select your primary display here
    mode=left      # you should read the mode from the command line, perhaps?
    
    # you need to obtain the device(s) associated to your preferred tablet/stylus
    devices=$( xinput --list | fgrep Pen | sed -E 's/^.*id=([0-9]+).*$/\1/' )
    
    xrandr --output ${monitor} --rotate ${mode}
    for device in ${devices} ;do
        xinput --map-to-output ${device} ${monitor}
    done

More details here: https://github.com/frgomes/bash-scripts/blob/develop/bin/rotate

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 18, 2021

Hi guys how can i install this script and how can i do on Deepin 20.2 to check my actual hardware so i can customize it? Thanks

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 18, 2021

aja xinput result is:

`
Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ SYNA3602:00 0911:5288 Mouse id=10 [slave pointer (2)]
⎜ ↳ SYNA3602:00 0911:5288 Touchpad id=11 [slave pointer (2)]
⎜ ↳ GXTP7385:01 27C6:0114 id=12 [slave pointer (2)]

`

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 18, 2021

@javiercviegas: You copy the script of your choice to a location in your path. This is one way how it can be done:

  1. Open the text editor of your choice.
  2. Make a new document (if it is not already open).
  3. Copy and paste the script you want to have.
  4. Save the document, let's say for the moment to /home/javiercviegas/rotate.
  5. Make it executable:
    1. Open a terminal.
    2. Enter the command chmod +x /home/javiercviegas/rotate.

If you want to rotate the screen, open a terminal and call /home/javiercviegas/rotate.

If you save it in a directory which is in your path, you can call the script just with rotate. (You can show the directories of your path with echo $PATH in your terminal.)

You can always put it somewhere where the desktop can find it, e.g. your desktop's start menu.

If you use the script from https://gist.github.com/mildmojo/48e9025070a2ba40795c#gistcomment-3709782, you do not need to configure it, because it will automatically find the screen and all devices and rotate them. If your screen is rotated by your desktop environment, either switch the automatic screen rotation off or comment out the line $XRANDR --output $1 --rotate $ORIENTATION in the script by inserting a # at the start of that line.

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 18, 2021

@javiercviegas: You copy the script of your choice to a location in your path. This is one way how it can be done:

  1. Open the text editor of your choice.

  2. Make a new document (if it is not already open).

  3. Copy and paste the script you want to have.

  4. Save the document, let's say for the moment to /home/javiercviegas/rotate.

  5. Make it executable:

    1. Open a terminal.
    2. Enter the command chmod +x /home/javiercviegas/rotate.

If you want to rotate the screen, open a terminal and call /home/javiercviegas/rotate.

If you save it in a directory which is in your path, you can call the script just with rotate. (You can show the directories of your path with echo $PATH in your terminal.)

You can always put it somewhere where the desktop can find it, e.g. your desktop's start menu.

If you use the script from https://gist.github.com/mildmojo/48e9025070a2ba40795c#gistcomment-3709782, you do not need to configure it, because it will automatically find the screen and all devices and rotate them. If your screen is rotated by your desktop environment, either switch the automatic screen rotation off or comment out the line $XRANDR --output $1 --rotate $ORIENTATION in the script by inserting a # at the start of that line.

Awesome, thanks for the really detailed answer. I am trying it now.

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 18, 2021

You are welcome. Happy learning!

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 18, 2021

@sphh I have this response:
`
Rotate display eDP-1 to Orientation (<'undefined'>,) unknown! orientation (Pointers: 4 10 11 12)
/usr/bin/xrandr: --rotate: invalid argument 'Orientation'
Try '/usr/bin/xrandr --help' for more information.

`

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 18, 2021

What is this response? Where does it come from? Is this an error message? What should I do with it?

Please give some context and explain what you have done, so that you can be helped.

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 18, 2021

What is this response? Where does it come from? Is this an error message? What should I do with it?

Please give some context and explain what you have done, so that you can be helped.

Sorry. i copied the script to my /usr/local/bin then make it executable and call it from the terminal and that's the output i have from it and nothing happens.

@frgomes

This comment has been minimized.

Copy link

@frgomes frgomes commented May 18, 2021

@javierviegas: Have you tried my script?
https://github.com/frgomes/bash-scripts/blob/develop/bin/rotate

Please let me know in case you find issues.
Thanks

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 18, 2021

And which script are you using? There are so many here …

If you use this script https://gist.github.com/mildmojo/48e9025070a2ba40795c#gistcomment-3709782, please update it to the current version (there was a typo in there) and post the output of these commands called in the terminal:

xrandr --current --verbose | grep primary
xrandr --current --verbose | grep primary | cut --delimiter=" " -f1
@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 18, 2021

@javierviegas: Have you tried my script?
https://github.com/frgomes/bash-scripts/blob/develop/bin/rotate

Please let me know in case you find issues.
Thanks

Hi Frgomes it works but i suppose i need to recalibrate cos if i touch the screen its not working as expected. How can i recalibrate it?

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 18, 2021

@frgomes: Interesting script. Is the --listmonitors parameter for xrandr documented somewhere (man xrandr does not show it)? Does it always return the primary monitor in the first line?

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 18, 2021

And which script are you using? There are so many here …

If you use this script https://gist.github.com/mildmojo/48e9025070a2ba40795c#gistcomment-3709782, please update it to the current version (there was a typo in there) and post the output of these commands called in the terminal:

xrandr --current --verbose | grep primary
xrandr --current --verbose | grep primary | cut --delimiter=" " -f1

Thats the one i am using and the last release.

~$ xrandr --current --verbose | grep primary eDP-1 connected primary 1920x1080+0+0 (0x45) normal (normal left inverted right x axis y axis) 294mm x 165mm

and

xrandr --current --verbose | grep primary | cut --delimiter=" " -f1 eDP-1

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 18, 2021

Thanks @javiercviegas! That shows us, that the script finds the primary monitor (it's eDP-1, by the way @frgomes uses a very similar approach).

Are you happy to debug it further? Then please issue the following three (rather lengthy) commands and post the results:

dbus call --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy --method org.freedesktop.DBus.Properties.Get net.hadess.SensorProxy HasAccelerometer

gdbus call --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy --method org.freedesktop.DBus.Properties.Get net.hadess.SensorProxy AccelerometerOrientation

gdbus call --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy --method net.hadess.SensorProxy.ReleaseAccelerometer

That's also where there is a major difference to @frgomes's script: Mine gets the orientation from the orientation from the built-in accelerometer and @frgomes's script from the current orientation of the primary screen. For @frgomes to work, you have to enable the automatic screen rotation in your desktop's settings (and then the following can happen: The screen switches automatically to a different orientation, but the input device does not). For my script to work, you should disable automatic screen rotation and then hold the device in the orientation you like and call my script. It's your choice, what you prefer.

I just noticed another difference: My script rotates all active input devices (so you need to use your pen just before rotation, if it is a bluetooth pen), @frgomes's script only rotates the pen, but not the touchpad (if I understand his script correctly.

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 18, 2021

Thanks @javiercviegas! That shows us, that the script finds the primary monitor (it's eDP-1, by the way @frgomes uses a very similar approach).

Are you happy to debug it further? Then please issue the following three (rather lengthy) commands and post the results:

dbus call --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy --method org.freedesktop.DBus.Properties.Get net.hadess.SensorProxy HasAccelerometer

gdbus call --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy --method org.freedesktop.DBus.Properties.Get net.hadess.SensorProxy AccelerometerOrientation

gdbus call --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy --method net.hadess.SensorProxy.ReleaseAccelerometer

That's also where there is a major difference to @frgomes's script: Mine gets the orientation from the orientation from the built-in accelerometer and @frgomes's script from the current orientation of the primary screen. For @frgomes to work, you have to enable the automatic screen rotation in your desktop's settings (and then the following can happen: The screen switches automatically to a different orientation, but the input device does not). For my script to work, you should disable automatic screen rotation and then hold the device in the orientation you like and call my script. It's your choice, what you prefer.

I just noticed another difference: My script rotates all active input devices (so you need to use your pen just before rotation, if it is a bluetooth pen), @frgomes's script only rotates the pen, but not the touchpad (if I understand his script correctly.

@sphh Sure i am glad to help for other's to use this scripts.
1.- dbus call --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy --method org.freedesktop.DBus.Properties.Get net.hadess.SensorProxy HasAccelerometer
(,)

2.- gdbus call --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy --method org.freedesktop.DBus.Properties.Get net.hadess.SensorProxy AccelerometerOrientation
(<'undefined'>,)

3.- gdbus call --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy --method net.hadess.SensorProxy.ReleaseAccelerometer

()

My distro (Deepin 20.2) does not have an auto rotate function you can only do it manually.

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 18, 2021

Aha, that explains a bit. It cannot find the accelerometer. I was hoping, that this is caught by my script, but apparently is not.

On my system I had to install the iio-sensor-proxy. It looks either that this is not installed, not started or that your computer does not have an accelerometer.

Please check, that iio-sensor-proxy is installed. Then check with this command, if it is started (assuming that your system is using systemd, which is very likely):

systemctl status iio-sensor-proxy.service 
@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 18, 2021

Aha, that explains a bit. It cannot find the accelerometer. I was hoping, that this is caught by my script, but apparently is not.

On my system I had to install the iio-sensor-proxy. It looks either that this is not installed, not started or that your computer does not have an accelerometer.

Please check, that iio-sensor-proxy is installed. Then check with this command, if it is started (assuming that your system is using systemd, which is very likely):

systemctl status iio-sensor-proxy.service 

`
● iio-sensor-proxy.service - IIO Sensor Proxy service
Loaded: loaded (/lib/systemd/system/iio-sensor-proxy.service; static; vendor preset: enabled)
Active: active (running) since Tue 2021-05-18 16:01:16 EDT; 2h 48min left
Main PID: 664 (iio-sensor-prox)
Tasks: 3 (limit: 4915)
Memory: 1.1M
CGroup: /system.slice/iio-sensor-proxy.service
└─664 /usr/sbin/iio-sensor-proxy

Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.
`

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 18, 2021

@javiercviegas: You are living in the future! 16 o'clock EDT is actually 3 hours away.

Anyway, if you are certain, that iio-sensor-proxy was started before you issued those three long commands, than you computer does not have an accelerometer which is recognized by iio-sensor-proxy

(Still there is a bug in the script: It does not display the proper error message and exit, if it cannot find the accelerometer. Because of this, it calls the commands to set the rotation and you see the error message related to this.)

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 18, 2021

@javiercviegas: You are living in the future! 16 o'clock EDT is actually 3 hours away.

Anyway, if you are certain, that iio-sensor-proxy was started before you issued those three long commands, than you computer does not have an accelerometer which is recognized by iio-sensor-proxy

(Still there is a bug in the script: It does not display the proper error message and exit, if it cannot find the accelerometer. Because of this, it calls the commands to set the rotation and you see the error message related to this.)

@javiercviegas: You are living in the future! 16 o'clock EDT is actually 3 hours away.

Anyway, if you are certain, that iio-sensor-proxy was started before you issued those three long commands, than you computer does not have an accelerometer which is recognized by iio-sensor-proxy

(Still there is a bug in the script: It does not display the proper error message and exit, if it cannot find the accelerometer. Because of this, it calls the commands to set the rotation and you see the error message related to this.)

Lol i am Marty Mcfly! Hmmm i am not sure that the iio-sensor-proxy was started before. This laptop is new and i wouldn't dare to affirm that is was already up before issuing that command.

If this laptop does not have an acelerometer (quite probably not because it's a chinese low budget BMAX Y13 Power) does this mean i cannot use the script?

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 18, 2021

Check, that iio-sensor-proxy is up and running and try to run the first of those lenghty commands again. If you get an output of (true,), your computer does have a accelerometer. You could also try to run monitor-sensor from the command line and investigate its output. If you don't have an accelerometer, you will not have any luck with autodetecting its orientation. Then neither my script nor @frgomes's script will work.

Without an accelerometer, your best bet is this script: https://gist.github.com/mildmojo/48e9025070a2ba40795c#gistcomment-2694429. You have to start it with one of these command line options: normal, inverted, left or right, e.g. rotate-screen left.

@marian556

This comment has been minimized.

Copy link

@marian556 marian556 commented May 18, 2021

No more hacking guys.
Let's do it properly. I asked KDE to add a new feature. We just need to wait about 2 years.
https://bugs.kde.org/show_bug.cgi?id=437326

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 18, 2021

This is the bug for Linux Mint (from 2017): linuxmint/cinnamon-settings-daemon#188

@marian556: Wouldn't it be better to use the d-bus net.hadess.SensorProxy instead of running another command (which btw returns a lot of data related to the brightness)?

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 19, 2021

@javiercviegas: Have a look at the updated script https://gist.github.com/mildmojo/48e9025070a2ba40795c#gistcomment-3709782. It can now be used without an accelerometer. Start by calling it with rotate-script --help to familiarize yourself with the possibilities.

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 20, 2021

@javiercviegas: Have a look at the updated script https://gist.github.com/mildmojo/48e9025070a2ba40795c#gistcomment-3709782. It can now be used without an accelerometer. Start by calling it with rotate-script --help to familiarize yourself with the possibilities.

Confirmed it does have an accelerometer.

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 20, 2021

… so everything should work!

But if

dbus call --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy --method org.freedesktop.DBus.Properties.Get net.hadess.SensorProxy HasAccelerometer

does not return (<true>,), there are only five reasons I can think of:

  1. There is no accelerometer available.
  2. The iio-sensor-proxy is not installed.
  3. The iio-sensor-proxy is installed but its service not activated.
  4. The accelerometer is not supported by iio-sensor-proxy.
  5. The D-Bus is not working.

You can also test, if everything was installed correctly, by running monitor-sensor (and move your device). If that does not show === Has accelerometer, you have to sort it first or use the script in "manual" mode (rotate-screen next|previous or rotate-screen normal|left|inverted|right). If the screen rotates automatically, you could also use rotate-screen screen.

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 20, 2021

… so everything should work!

But if

dbus call --system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy --method org.freedesktop.DBus.Properties.Get net.hadess.SensorProxy HasAccelerometer

does not return (<true>,), there are only five reasons I can think of:

  1. There is no accelerometer available.
  2. The iio-sensor-proxy is not installed.
  3. The iio-sensor-proxy is installed but its service not activated.
  4. The accelerometer is not supported by iio-sensor-proxy.
  5. The D-Bus is not working.

You can also test, if everything was installed correctly, by running monitor-sensor (and move your device). If that does not show === Has accelerometer, you have to sort it first or use the script in "manual" mode (rotate-screen next|previous or rotate-screen normal|left|inverted|right). If the screen rotates automatically, you could also use rotate-screen screen.

It works. But now i am thinking how can i use the accelerometer to trigger the script and at the same time use the accelerometer to determine if the mode should be left right inverted or normal

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 20, 2021

while true; do
    rotate-screen
    sleep 1
done

!

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 25, 2021

while true; do
    rotate-screen
    sleep 1
done

!

Bare with me i am just starting to study scripts. Where exactly should i add this snippet on the original code?

@sphh

This comment has been minimized.

Copy link

@sphh sphh commented May 25, 2021

You could start with a terminal and enter these commands. You can also use the following one-liner:

while true; do rotate-screen; sleep 1; done

If that is what you want, write a tiny script with this contents

#!/bin/sh
true; do
    rotate-screen
    sleep 1
done

make it executable (chmod +x rotate-automatically) and call this script.

See also: https://www.shellscript.sh/ (or any other tutorial on shell scripts).

@javiercviegas

This comment has been minimized.

Copy link

@javiercviegas javiercviegas commented May 25, 2021

You could start with a terminal and enter these commands. You can also use the following one-liner:

while true; do rotate-screen; sleep 1; done

If that is what you want, write a tiny script with this contents

#!/bin/sh
true; do
    rotate-screen
    sleep 1
done

make it executable (chmod +x rotate-automatically) and call this script.

See also: https://www.shellscript.sh/ (or any other tutorial on shell scripts).

Great awesome! Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment