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
@sphh
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

sphh commented May 20, 2021

while true; do
    rotate-screen
    sleep 1
done

!

@javiercviegas
Copy link

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
Copy link

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
while 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
Copy link

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

@dionnismo
Copy link

dionnismo commented Nov 26, 2021

thanks a lot, everything worked, I just substituted my devices

@marcomarinho
Copy link

marcomarinho commented Nov 28, 2021

Check this script. Basically automatically rotates the screen based on the orientation
https://github.com/marcomarinho/auto-rotate-tablets-linux/tree/main

@sphh
Copy link

sphh commented Nov 30, 2021

@marcomarinho: It looks, like your script uses

monitor-sensor >> sensor.log 2>&1 &

while inotifywait -e modify sensor.log; do
    [...]
done

If I understand that correctly, monitor-sensor writes the output to a file on the (hard-)disk and acts, whenever this file changes. When I start monitor-sensor, it writes a line roughly ever 0.5s. If you do not restart your script, the sensor.log file gets longer and longer using up more and more hard-disk space. That would trouble me, if you only send the laptop to sleep and do not restart it.

I can see another problem: SSDs do not like these regular writing and could wear out quickly.

Wouldn't it be better to write a script, which monitors the DBus (as I believe monitor-sensor does) and act on changes of the orientation? Actually I shortly thought about adding this approach to my script, but did not do it in the end, because I personally do not like automatic screen orientation (it always flips the screen when you do not want it to do). What do you think?

@mildmojo
Copy link
Author

mildmojo commented Jan 10, 2022

As an aside, the other day my 8-year-old Yoga 11s started auto-rotating the screen when I physically change the laptop's orientation. Maybe I updated a system package somewhere and it suddenly gained support for my hardware? Wild.

Now that it's finally supported, I'd kind of like to turn it off. 😝 I now prefer setting the rotation manually with global hotkeys set to call the script in this gist. I can see how it would be useful in tablet mode, though.

@mw-cyrano
Copy link

mw-cyrano commented Jan 28, 2022

Thank you so much! This works flawlessly on my XPS 13 2-in-1, even if external monitor connected, which remains unaffected. Touch events on the screen, external mouse and digitizer work on spot. Finally video conferences with a digital and streamable paper at hand.

@clavisound
Copy link

clavisound commented Apr 4, 2022

Thank you for the script.

On yoga 11s with my custom kernel-5.15.31 on Slackware-15 I changed only one line

TOUCHSCREEN='Atmel Atmel maXTouch Digitizer'
vs
TOUCHSCREEN='Atmel Atmel maXTouch Digitizer Touchscreen'

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