Edited at

Ubuntu16.04LTSの画面を自動回転させる

More than 1 year has passed since last update.


tl;dr

しばらく前に Dell inspiron 11 3147 を買ったのですが、Windows 10 がちょっと嫌になり、 Ubuntu 16.04 LTS を入れました。

各種ドライバーも使え、タッチパネルも使え、スクリーンキーボードも普通に使えています。

これだけでも充分満足なのですが、Windowsの時に使えていた画面の自動回転はUbuntuの設定にはないようで、どこの設定画面にもそれらしきものがありません。

とは言っても回転しなくてもどうということはないのです。

2-in-1のPCですがそもそもタブレットとしても使わないですし、タッチパネルもスクリーンキーボードも使えなくても全く問題ないのです。

最悪タッチパッドさえ使えれば別に良いってかんじです。

でもどうせなら自動で回転させたいですよね。

WindowsでできていたことをUbuntuでも同じようにしたいというのは至極当然の流れだと思います。

そこで画面の自動回転を検索したところ江添さんのブログがヒットしたので参考にさせてもらうことに。

で、色々ごちゃごちゃやってみてなんとか画面の自動回転が成功したので、記載します。


大まかな流れ


  1. 必要なパッケージをインストール

  2. 1でインストールしたツールをサービス化

  3. rsyslogでログを取得する

  4. ログを監視し、メッセージが出たら画面を回転させる簡単なスクリプトを書く

  5. 4で書いたスクリプトをサービス化

  6. 完了

こんな感じです。


マシンの情報とか

メーカ
シリーズ
OS
バージョン
GUI

Dell
Inspiron 11 3147
Ubuntu
16.04 LTS
Unity


カーネルバージョン

ine@daisy:~$ uname -a

Linux daisy 4.4.0-59-generic #80-Ubuntu SMP Fri Jan 6 17:47:47 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux


1. パッケージインストール

画面を自動で回転させるには、デフォルトでインストールされるであろう各種パッケージやコマンド群だけでは実現できません。

そのために必要なパッケージをインストールします。

また、画面の自動回転を実現するには、画面の傾きを検出する必要があります。

それを検出するためには加速度センサが内蔵されている必要があるみたいです。

今回のマシンはWindowsの時点で画面の自動回転が実現できていたので、センサがあるであろうと考えました。


画面を回転させるコマンド(xrandr)

画面の回転には xrandr というコマンドを使います。

UbuntuをGUIで使う場合は、デフォルトでインストールされているかも知れません、

入っていなければ apt-getxrandr の入っているパッケージをインストールしてください。

ine@daisy:~$ sudo apt-get install x11-xserver-utils

これで xrandr コマンドが使えるようになりました。

試しに画面を回転させてみることにしましょう。

xrandr -o [normal|inverted|right|left]

-o の後に付けるオプションで回転が選択できます。

オプション
回転

normal
デフォルト(0度)に戻す

inverted
画面を180度回転させる

right
画面を右に90度回転させる

left
画面を左に90度回転させる

以下のコマンドを打つと画面が右90度回転し、5秒後元に戻ります。

ine@daisy:~$ xrandr -o right && sleep 5 && xrandr -o normal

xrandr コマンドを使うとこんな感じで回転します。

このコマンドを使ってスクリプトを書き、自動化させてしまおうというわけです。


傾きを検出する(iio-sensor-proxy, monitor-sensor)

次に傾きを検出するツールをインストールします。

apt-getiio-sensor-proxy というパッケージをインストールします。

ine@daisy:~$ sudo apt-get install iio-sensor-proxy

このパッケージにある iio-sensor-proxymonitor-sensor というツールを使います。

インストールするとsystemdのユニットに iio-sensor-proxy というserviceファイルが追加されます。

ine@daisy:~$ systemctl list-unit-files iio-sensor-proxy.service

UNIT FILE STATE
iio-sensor-proxy.service static

1 unit files listed.

このserviceを起動した後、 monitor-sensor コマンドを実行すると、センサから読み取った情報が表示されます。

ine@daisy:~$ systemctl start iio-sensor-proxy

ine@daisy:~$ monitor-sensor
** Message: Light changed: 16.000000 (lux)
** Message: Light changed: 18.000000 (lux)
** Message: Light changed: 16.000000 (lux)
** Message: Light changed: 13.000000 (lux)

出力される数字がセンサから読み取っている情報のようで、少しでも角度が変わると数字が変わります。

出力されるのは数字だけではありません。

画面を回転させると、以下のようなメッセージが出力されます。

** Message: Light changed: 15.000000 (lux)

** Message: Light changed: 17.000000 (lux)
** Message: Accelerometer orientation changed: left-up

この Accelerometer orientation changed: メッセージは、傾きがある値を超えると出力されるようです。

これにより画面がどの程度回転しているのかがわかります。

出力
回転

normal
デフォルト(0度)

bottom-up
画面が180度回転した

right-up
画面が右に90度回転した

left-up
画面が左に90度回転した

これで画面の傾きが検出できるようになりました。


2. monitor-sensor をサービス化

iio-sensor-proxy はserviceファイルもインストールされますが、 monitor-sensor はコマンドなので、適当にserviceファイルを作ります。

私は /lib/systemd/system/monitor-sensor.service といったファイルで以下のような感じで書きました。


/lib/systemd/system/monitor-sensor.service

[Unit]

Description=Monitor Sensor service
Requires=iio-sensor-proxy.service
After=iio-sensor-proxy.service

[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/monitor-sensor

[Install]
WantedBy=multi-user.target


ファイルを作ったら systemctl を再読み込みして、サービスの開始、自動起動を有効化しましょう

ine@daisy:~$ sudo systemctl daemon-reload

ine@daisy:~$ sudo systemctl start monitor-sensor.service
ine@daisy:~$ sudo systemctl enable monitor-sensor.service
Created symlink from /etc/systemd/system/multi-user.target.wants/monitor-sensor.service to /lib/systemd/system/monitor-sensor.service.

ステータスを確認すると起動していることが確認できると思います。

ine@daisy:~$ systemctl status monitor-sensor.service 

● monitor-sensor.service - Monitor Sensor service
Loaded: loaded (/lib/systemd/system/monitor-sensor.service; enabled; vendor p
Active: active (running) since 日 2017-01-29 22:11:40 JST; 1min 18s ago
Main PID: 8276 (monitor-sensor)
Tasks: 3
Memory: 520.0K
CPU: 35ms
CGroup: /system.slice/monitor-sensor.service
└─8276 /usr/bin/monitor-sensor

1月 29 22:12:48 daisy monitor-sensor[8276]: ** Message: Light changed: 21.000000
1月 29 22:12:49 daisy monitor-sensor[8276]: ** Message: Light changed: 20.000000
1月 29 22:12:49 daisy monitor-sensor[8276]: ** Message: Light changed: 18.000000

これで monitor-sensor がOS起動時に自動で起動するようになりました。


3. rsyslogでログを取得する

Ubuntuではrsyslogでimuxsockモジュールをロードしているためか、systemd-journaldのログをrsyslogで取得できます。

これを使って /etc/rsyslog.d の下に以下のような設定ファイルを作ります。


/etc/rsyslog.d/10-monitor-sensor.conf

:msg,contains,"** Message: Accelerometer orientation changed:" -/var/log/monitor-sensor.log

& ~

:syslogtag,startswith,"monitor-sensor[" ~


これでOKです。

内容的には "** Message: Accelerometer orientation changed:" という文字列を含んだメッセージを /var/log/monitor-sensor.log に出力し、それ以外に syslogtag 部分に monitor-sensor[ を含むメッセージがあれば全て除外する、といったものになります。

"** Message: Accelerometer orientation changed:"monitor-sensor を動かした時、画面の傾きがある一定の値を超えると出力されるメッセージですね。

これだけをログに取るようにしました。

というのも、角度が変わるだけで出力されるメッセージも一緒のログに出力しているとログが肥大化してしまいそうだったためです。

結構な頻度で出てきますからね。

また、ファイル名を指定している直前にハイフン(-)が入っていますが、これがあるとメッセージ出力時に該当するファイルがない場合自動で作成してくれます。

とても便利。

最後の行はそれ以外のメッセージは除外するという意味のものです。

設定ファイルを作成したら rsyslog を再起動しましょう。

ine@daisy:~$ sudo systemctl restart rsyslog.service

一度 /var/log を見てみます。

ine@daisy:~$ ls -la /var/log/

drwxrwxr-x 12 root syslog 4096 1月 30 23:19 .
drwxr-xr-x 14 root root 4096 4月 26 2016 ..
-rw-r--r-- 1 root root 27811 1月 30 22:58 Xorg.0.log
.
.
.
drwxr-x--- 2 root adm 4096 1月 21 00:31 unattended-upgrades
drwxr-xr-x 2 root root 4096 3月 1 2016 upstart
-rw-rw-r-- 1 root utmp 154752 1月 30 22:55 wtmp

monitor-sensor.log はまだないみたいです。

では、ログが出力されるようアクションをしてみましょう。

画面を物理的に90度回転させた後元に戻し、もう一度確認してみます。

ine@daisy:~$ ls -la /var/log/

drwxrwxr-x 12 root syslog 4096 1月 30 23:19 .
drwxr-xr-x 14 root root 4096 4月 26 2016 ..
-rw-r--r-- 1 root root 27811 1月 30 22:58 Xorg.0.log
.
.
-rw-r----- 1 syslog adm 392 1月 30 23:19 monitor-sensor.log
.
.
drwxr-x--- 2 root adm 4096 1月 21 00:31 unattended-upgrades
drwxr-xr-x 2 root root 4096 3月 1 2016 upstart
-rw-rw-r-- 1 root utmp 154752 1月 30 22:55 wtmp

作成されていることが確認できます。

umaskやowner、groupもrsyslogで設定されているものです。

内容も以下の通り

ine@daisy:~$ sudo cat /var/log/monitor-sensor.log

** Message: Accelerometer orientation changed: left-up
** Message: Accelerometer orientation changed: normal

これでログ設定はOKです。


4. ログを監視し、メッセージが出たら画面を回転させるスクリプト

最初は自分で一から作ろうと思ったのですが、探したらそれっぽいのがあったので、使わせていただきました。

しかし元のままでは使えなかったため、多少改造したものが以下になります。


monitor-rotate.sh

#!/bin/bash

# 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
# 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

WATCH_LOG="/var/log/monitor-sensor.log"
LAUNCHER_POS="set com.canonical.Unity.Launcher launcher-position"

export XAUTHORITY=${HOME}/.Xauthority
export DISPLAY=$(w -hs | grep ${LOGNAME} | awk '{print $3}')
export DISPLAY=${DISPLAY:-\:0}

while inotifywait -e modify ${WATCH_LOG} > /dev/null 2>&1 ; do
# Read the last line that was added to the file and get the orientation
ORIENTATION=$(tail -n 1 ${WATCH_LOG} | grep -oE '[^ ]+$')

# Set the actions to be taken for each possible orientation
case "${ORIENTATION}" in
normal)
xrandr -o normal && \
gsettings ${LAUNCHER_POS} Left
echo "Orientation Changed normal"
;;

bottom-up)
xrandr -o inverted && \
gsettings ${LAUNCHER_POS} Left
echo "Orientation Changed inverted"
;;

right-up)
xrandr -o right && \
gsettings ${LAUNCHER_POS} Left
echo "Orientation Changed right"
;;

left-up)
xrandr -o left && \
gsettings ${LAUNCHER_POS} Left
echo "Orientation Changed left"
;;

esac

done


while文でログを確認してグルグル回すスクリプトです。

ログに特定の文字列(normal|bottom-up|right-up|left-up)が出た時に xrandr で画面を回転させます。

文字列の検知には inotifywait コマンドを使っています。

オプションには -e modify を使っていますが、これは「指定したファイルの内容に変更があった場合に通知する」という意味のものになります。

これのおかげで /var/log/monitor-sensor.log の内容に変更(書き込みや削除等)があったというイベントが走る度に while が回るようになっています。

更にそのメッセージから文字列を切り出して分岐させている・・・という具合です。

これをserviceファイルにして自動起動させるようにします。


設定されない環境変数

これは自分の環境にあわせた結果ですが、

スクリプトの初っぱなに環境変数を定義している部分があります。

export XAUTHORITY=${HOME}/.Xauthority

export DISPLAY=$(w -hs | grep ${LOGNAME} | awk '{print $3}')

不要っぽいですが、ないとちょっとまずいんです。

というのも、最初これを入れずにservice化させた時、以下のようなエラーが出て自動起動できなかったためです。

 1月 30 21:28:25 daisy monitor-rotate.sh[1446]: Can't open display

調べたところ、どうやら環境変数の DISPLAYXAUTHORITY が設定されていないと上記のエラーが出てしまうようでした。

で、結構調べたんですが、 systemd で各種サービスが読み込まれる時点では、上記の環境変数って未設定っぽいのですね。

どうやらXセッションが開始すると設定される環境変数のようで、/etc/X11/Xsession.d 以下にあるファイルに変数が定義されていました。

自動起動をさせたいのですが、これだと困ります。

そのため、スクリプト内で環境変数を設定してしまおうと考えたわけです。

XAUTHORITY はホームディレクトリにコピーされる.Xauthorityを見ているらしいので、 XAUTHORITY=${HOME}/.Xauthority としました。

DISPLAY はどうすればいいのかわからなかったのですが、どうやら w コマンドで出力されるFROMに書かれているものと同一のようだったので、grepとawkを使って切り出し、 DISPLAY=$(w -hs | grep ${LOGNAME} | awk '{print $3}') といった感じになりました。

ちなみに HOMELOGNAMEmonitor-rotate.sh を起動する以前に設定されているようでした。

あとは export で環境変数とすれば完璧!

と思っていたのですが、この記事を書いた後、何度か起動していたら何故か動かなくなっていました。

原因を調べたところまたも DISPLAY が定義されていなかったので、以下を足しました。

export DISPLAY=${DISPLAY:-\:0}

多分これで上手く動くんじゃないですかね・・・(願望)。

これに結構時間食いました。

でも、何はともあれ完成です。

作ったスクリプトは恐らくパスが通っているであろう /usr/local/bin/ ディレクトリにでもコピーしておきましょう。

ine@daisy:~$ sudo cp -ip monitor-rotate.sh /usr/local/bin/


5. monitor-rotate.sh をサービス化

最後に monitor-rotate.sh をserviceファイルにします。

普通にservice化させるのであれば、全ユーザに適用させたいので monitor-sensor.service を作成した時と同様に /lib/systemd/system/ ディレクトリに作ってしまえば良いのですが、今回はユーザ固有の環境変数(HOME, LOGNAME)を使っていますし、スクリプト内で設定している DISPLAY も毎度 :0 とは限りません。

ではどうするかですが、 systemd はユーザに systemd のインスタンスを実行させてサービスを管理できる機能を提供しています。

ココらへんは Arch Linux の Wiki に詳しく書いてあります。

要は ユーザ固有の権限で停止、起動等ができるserviceファイルを作れる というお話です。

/usr/lib/systemd/uesr/ ディレクトリの下に、以下のserviceファイルを作ります。


/usr/lib/systemd/uesr/monitor-rotate.service

[Unit]

Description=Monitor Rotation Service

[Service]
Type=simple
ExecStart=/usr/local/bin/monitor-rotate.sh

[Install]
WantedBy=default.target


作成したら、systemctl を再読み込みして、サービスの開始、自動起動を有効化しましょう。

気を付ける点としては、 systemctl コマンドの直後に --user を付けなくてはいけないということです。

ine@daisy:~$ sudo systemctl --user daemon-reload

ine@daisy:~$ sudo systemctl --user start monitor-sensor.service
ine@daisy:~$ sudo systemctl --user enable monitor-sensor.service
Created symlink from /home/ine/.config/systemd/user/default.target.wants/monitor-rotate.service to /usr/lib/systemd/user/monitor-sensor.service.

自動起動を有効にするとホームディレクトリの下に .config ディレクトリが作成され、シンボリックリンクが貼られます。

これで自動起動設定まで完了です。

再起動してからPCを傾けてみてください。


デモ的な

こんな感じになるはずです。

描画が遅いのはUnityだからというのと、PC自体のスペックの問題かもしれません。

現状こんな感じです。

回転時にブラックアウトするのがちょっと気になりますが、まぁ及第点かな、と思います。


所感

まぁ及第点ではあるのですが、もうちょっとやりようがあったんじゃないかなと思ったりもします。

なんか色んな所にファイル作り過ぎなんですよね。

手順もしんどいし・・・なんなんですかね・・・。

とりあえずこれが私の限界です。

ちなみに、画面を手動で回転させるのであればGitHubにScreenRotatorというリポジトリがありました。

DLしてファイルを実行させるだけなので用途によってはこっちの方が良いかもしれません。

アイコンも表示されて、ちょっといい感じです。

できればこれを真似して自動回転させるスクリプトとか書ければよかったんですが、python・・・わっかんねえんだよなぁ・・・。

精進します。

以上。