Linux Mintで画面の自動回転を行う。

以前メルカリで1万円しないで購入したLenovo YOGA900がメモリ4GB固定でWindows厳しいのでLinux Mint(Cinamon)をインストールしスワップ12GB突っ込んだら意外と使い勝手のいいモバイルPCになりました。
とはいえせっかくヒンジが360度回転するのにモニタが自動で回転しないのがもったいないので色々試してみて上手くいった方法を備忘録として書き残しておきます。合わせてタッチパネルも回転時にずれないように調整する必要があるのでその辺りをまとめて対応しました。


## PC情報
| メーカー | 機種名 | CPU | メモリ | OS | バージョン | GUI |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| Lenovo | YOGA 900 | Core(TM) i5-6200U | 4GB |  Linux Mint | 20.2 |Cinamon|

## 参考にしたサイト
[Ubuntu16.04LTSの画面を自動回転させる](https://qiita.com/ine1127/items/38346ef517706cbc5a1d)
[Linuxで画面&タッチスクリーンを90度回転 (Debian10 KDE)](http://bluearth.cocolog-nifty.com/blog/2019/12/post-e5f4f1.html)

ちゃんと実装する人は上の記事は絶対読みましょう。

## やること

1. `xinput list`で回転させるモニター(タッチパネル)デバイス名を探す。
2. `monitor-sensor`コマンドでモニターの傾きを検出
3. モニターの傾きに合わせて`xrander`コマンドでモニターを回転
4. 1で取得したタッチパネル情報から回転後の座標を調整
5. 2-4を行うスクリプトをGUIの自動起動設定に追加

2-4はPythonで書きました。
といってもPythonで各コマンド叩かせるだけなんですがねｗ

## 作業の流れ

### 1. `xinput list`でタッチパネルのデバイス名を調べる

```bash
$ xinput list
⎡ Virtual core pointer                    	id=2	[master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer              	id=4	[slave  pointer  (2)]
⎜   ↳ Synaptics TM3066-002                    	id=10	[slave  pointer  (2)]
⎜   ↳ ELAN21EF:00 04F3:227C                   	id=11	[slave  pointer  (2)]
⎣ Virtual core keyboard                   	id=3	[master keyboard (2)]
    ↳ Virtual core XTEST keyboard             	id=5	[slave  keyboard (3)]
    ↳ Power Button                            	id=6	[slave  keyboard (3)]
    ↳ Video Bus                               	id=7	[slave  keyboard (3)]
    ↳ Power Button                            	id=8	[slave  keyboard (3)]
    ↳ Lenovo EasyCamera: Lenovo EasyC         	id=9	[slave  keyboard (3)]
    ↳ Ideapad extra buttons                   	id=12	[slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard            	id=13	[slave  keyboard (3)]
```

この中で`ELAN21EF:00 04F3:227C`が私の環境でのタッチパネルデバイス名です。
座標の調整にこの`id`が必要になるんですが、再起動だったりマウスも使ったりするとよく変わるので次のPythonのスクリプト内で拾います。

### 2. モニタの回転、タッチパネルの座標調整
以下のPythonスクリプトを用意します。

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import subprocess
from subprocess import PIPE, STDOUT

# get input id
def get_input_id(monitor_name):
    cmd = "xinput list | grep '{}' | awk -F'[\t=]' '{{print $3}}'".format(monitor_name)
    proc = subprocess.Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT,text=True)
    outs,err = proc.communicate()
    id = outs.rstrip()
    return id

# check monitor-sensor and monitor rotate
def monitor_rotate(monitor_name):

    # check word of monitor-sensor
    check_word = "Accelerometer orientation changed:"
  
    # monitor_rotate
    cmd = "/usr/bin/monitor-sensor"
    proc = subprocess.Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT,text=True)
    
    while True:
        monitor_status = proc.stdout.readline()
        
        if "normal" in monitor_status:
            id = get_input_id(monitor_name)
            monitor_rotate_cmd = \
            "/usr/bin/xrandr -o normal " \
            "&& " \
            "xinput set-prop {} 'Coordinate Transformation Matrix' 1 0 0 0 1 0 0 0 1".format(id)
            subprocess.Popen(monitor_rotate_cmd, shell=True, stdout=PIPE, stderr=STDOUT,text=True)
        elif "right-up" in monitor_status:
            id = get_input_id(monitor_name)
            monitor_rotate_cmd = \
            "/usr/bin/xrandr -o right " \
            "&& " \
            "xinput set-prop {} 'Coordinate Transformation Matrix' 0 1 0 -1 0 1 0 0 1".format(id)
            subprocess.Popen(monitor_rotate_cmd, shell=True, stdout=PIPE, stderr=STDOUT,text=True)
        elif "bottom-up" in monitor_status:
            id = get_input_id(monitor_name)
            monitor_rotate_cmd = \
            "/usr/bin/xrandr -o inverted " \
            "&& " \
            "xinput set-prop {} 'Coordinate Transformation Matrix' -1 0 1 0 -1 1 0 0 1".format(id)
            subprocess.Popen(monitor_rotate_cmd, shell=True, stdout=PIPE, stderr=STDOUT,text=True)
            
if __name__ == '__main__':
    monitor_name = "<タッチパネルデバイス名>"
    monitor_rotate(monitor_name)

```

`<タッチパネルデバイス名>`の部分に先程のデバイス名を突っ込んで上げればOKです。
やってることは完全にLinuxのコマンドをPythonに叩かせているだけですえ(笑)シェルスクリプトでもいいんですが`subprocess.Popen`で叩いたコマンドの標準出力結果って変数に格納して継続監視できるので`monitor-sensor`の傾き情報をログファイル等に用意すること無く傾きの検出することができるので必要なものはこのPythonスクリプト一つだけでOK！と少しは作業の楽が出来るかなと！

ちなみにモニターの`left-up`の状態が無いのは、YOGA900の右側にいろいろ電源ボタンとかがあるので右側が下になると勝手に電源落としたりスリープになったりと誤作動をよく起こしたことがあり個人的な理由で抜きました。

ではこのスクリプトを適当な名前で保存して実行権限を付けます。

```bash
# 私は/opt配下にmonitor-rotate.pyで保存していますので作成して保存したスクリプト名に読み替えてください。
$ sudo chmod 755 /opt/monitor-rotate.py
または
$ sudo chmod +x /opt/monitor-rotate.py
```

### 3. Linux MintのGUI設定で自動起動させるようにする。
最後に"設定" > "自動開始させるアプリケーション"から先程作成したPythonスクリプトを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169143/c9ba8f5b-9e2b-d499-49f4-34578f4cac3b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169143/71134ee5-9dc8-cf49-ad04-054589fc0181.png)

なんとなくで起動遅延時間を1秒入れています。

Linux Mintでの内容で書いてますが、デストリビューション側のGUIでアプリの自動起動機能があればいけるのではないかと思います。


## 所感
結局どうしてsystemctlでデーモン化して上手く動かなかったのか不明という残念な結果ですいません。トラブルシューティングを行う場合としては非常にまずいですね。
実際にサービスとしては起動してくれて`monitor-sensor`も動いていることは確認できてたんですけど、自動回転せずorz
まぁサーバーではなく一般的なクライアントOSとしてのLinux利用なのでGUI側で実装できることはそれでOKとすべきかなとこんな形になりました。
試行錯誤しまくってたので最初Pythonで書いたら楽じゃないか！！って思って作り出してから2日もかかるというね。

そしてこれ書いている間になんか使ってた無線マウス行方不明orz