tl;dr
しばらく前に Dell inspiron 11 3147 を買ったのですが、Windows 10 がちょっと嫌になり、 Ubuntu 16.04 LTS を入れました。
各種ドライバーも使え、タッチパネルも使え、スクリーンキーボードも普通に使えています。
これだけでも充分満足なのですが、Windowsの時に使えていた画面の自動回転はUbuntuの設定にはないようで、どこの設定画面にもそれらしきものがありません。
とは言っても回転しなくてもどうということはないのです。
2-in-1のPCですがそもそもタブレットとしても使わないですし、タッチパネルもスクリーンキーボードも使えなくても全く問題ないのです。
最悪タッチパッドさえ使えれば別に良いってかんじです。
でもどうせなら自動で回転させたいですよね。
WindowsでできていたことをUbuntuでも同じようにしたいというのは至極当然の流れだと思います。
そこで画面の自動回転を検索したところ江添さんのブログがヒットしたので参考にさせてもらうことに。
で、色々ごちゃごちゃやってみてなんとか画面の自動回転が成功したので、記載します。
大まかな流れ
- 必要なパッケージをインストール
- 1でインストールしたツールをサービス化
- rsyslogでログを取得する
- ログを監視し、メッセージが出たら画面を回転させる簡単なスクリプトを書く
- 4で書いたスクリプトをサービス化
- 完了
こんな感じです。
マシンの情報とか
メーカ | シリーズ | 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-get
で xrandr
の入っているパッケージをインストールしてください。
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-get
で iio-sensor-proxy
というパッケージをインストールします。
ine@daisy:~$ sudo apt-get install iio-sensor-proxy
このパッケージにある iio-sensor-proxy
と monitor-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
といったファイルで以下のような感じで書きました。
[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
の下に以下のような設定ファイルを作ります。
: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. ログを監視し、メッセージが出たら画面を回転させるスクリプト
最初は自分で一から作ろうと思ったのですが、探したらそれっぽいのがあったので、使わせていただきました。
しかし元のままでは使えなかったため、多少改造したものが以下になります。
#!/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
調べたところ、どうやら環境変数の DISPLAY
と XAUTHORITY
が設定されていないと上記のエラーが出てしまうようでした。
で、結構調べたんですが、 systemd で各種サービスが読み込まれる時点では、上記の環境変数って未設定っぽいのですね。
どうやらXセッションが開始すると設定される環境変数のようで、/etc/X11/Xsession.d
以下にあるファイルに変数が定義されていました。
自動起動をさせたいのですが、これだと困ります。
そのため、スクリプト内で環境変数を設定してしまおうと考えたわけです。
XAUTHORITY
はホームディレクトリにコピーされる.Xauthorityを見ているらしいので、 XAUTHORITY=${HOME}/.Xauthority
としました。
DISPLAY
はどうすればいいのかわからなかったのですが、どうやら w
コマンドで出力されるFROMに書かれているものと同一のようだったので、grepとawkを使って切り出し、 DISPLAY=$(w -hs | grep ${LOGNAME} | awk '{print $3}')
といった感じになりました。
ちなみに HOME
と LOGNAME
は monitor-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ファイルを作ります。
[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を傾けてみてください。
デモ的な
傾きで自動回転してくれるようになったぞい pic.twitter.com/RJPwKkPZJd
— イネ (@i_luv_kneesox) 2017年1月31日
こんな感じになるはずです。
描画が遅いのはUnityだからというのと、PC自体のスペックの問題かもしれません。
現状こんな感じです。
回転時にブラックアウトするのがちょっと気になりますが、まぁ及第点かな、と思います。
所感
まぁ及第点ではあるのですが、もうちょっとやりようがあったんじゃないかなと思ったりもします。
なんか色んな所にファイル作り過ぎなんですよね。
手順もしんどいし・・・なんなんですかね・・・。
とりあえずこれが私の限界です。
ちなみに、画面を手動で回転させるのであればGitHubにScreenRotatorというリポジトリがありました。
DLしてファイルを実行させるだけなので用途によってはこっちの方が良いかもしれません。
アイコンも表示されて、ちょっといい感じです。
できればこれを真似して自動回転させるスクリプトとか書ければよかったんですが、python・・・わっかんねえんだよなぁ・・・。
精進します。
以上。