🖱️

MacBookのナチュラルスクロール切り替え自動化with Python

2023/08/20に公開

やったこと

MacBookのナチュラルスクロールの設定をPythonコードで変更できるように設定し,実質自動化しました.
多分n番煎じですが…

実施に至った経緯

外付けマウスをつけるとナチュラルスクロールに違和感を覚えたからです.余談ですが使っているマウスはローラーマウスです.

学生時代からMacBookを一応使っていますが,外付けのマウスを接続せずに使っていたため気づかなかった出来事です.

環境

MacBook Air M1 2020
mac OS Ventura
Python 3.9.12

なぜPythonなのか?

普通にシェルで良いですね.結局subprocessでコマンド呼び出しているので…

ただ学生時代はnumpyやTensorflowとか数値計算系に全振りしていて,データ分析系に携わっていない現職では,Pythonの経験がそこまで活かせておらず,もうちょいPythonで出来ること増やしとこうと思ったからです.

実際のコード

とりあえず正常に動いていると思われるコードです.

#!/usr/bin/env python
import subprocess

#接続されているUSB一覧を入手するコマンド
command = "system_profiler SPUSBDataType"
#コマンド実行
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=True)

if result.stderr == "":
    
    #上記コマンドの出力結果
    output = result.stdout
    
    #マウスが接続されている場合に処理開始
    if "Mouse" in output:
        
	#現在のナチュラルスクロールの状態を取得するコマンド
        command2 = "defaults read -g com.apple.swipescrolldirection"
	#コマンド実行
        result2 = subprocess.run(command2,stdout=subprocess.PIPE, stderr=subprocess.PIPE,shell=True,text=True)
	#コマンドの出力結果
        output2 = result2.stdout
        
	#0の時にナチュラルスクロールは無効化,1の時に有効化されている
        if int(output2) != 0:
	    #ナチュラルスクロールの変更コマンド
            command3 = "defaults write -g com.apple.swipescrolldirection -bool false"
            subprocess.run(command3,shell=True)
	    
	    #一旦サインアウト
            command4 = "sudo pkill loginwindow"
            subprocess.run(command4,shell=True)
	    
        #ここのelse要らなかったかもしれないです
	else:
            exit()
    
    else:
        command5 = "defaults read -g com.apple.swipescrolldirection"
        result3 = subprocess.run(command5,stdout=subprocess.PIPE, stderr=subprocess.PIPE,shell=True,text=True)
        output3 = result3.stdout

        if int(output3) != 1:
            command6 = "defaults write -g com.apple.swipescrolldirection -bool true"
            subprocess.run(command6,shell=True)
            command7 = "sudo pkill loginwindow"
            subprocess.run(command7,shell=True) 
        else:
            exit()

#ここの分岐に行くテストしていないので,どうなるかわからないです
else:
    print(result.stderr)




コードの利用方法

以下のような形で,このコードをcronで走らせることにしました.

*/1 * * * * python hoge.py


1分ごとに実行されるため,外付けマウスを使っていて,ナチュラルスクロールがオンになっていると該当時刻になったらサインアウトします.もちろん設定が反映されていない1回だけです.
逆も然りで,外付けマウスを使っていなければ,該当時刻でサインアウトします.

躓いたところ

1時間あれば余裕で終わると思っていたのですが,想像以上に躓きました.

1. defaults write~コマンド打っても変わらなかった点
defaults writeコマンドで設定変更すると,システム設定の画面(GUI)から反映されていても,実際には反映されなかったです.
色々調べてみたところ,一旦該当プロセスを止めるなりしないと設定が反映されないらしいです.
今回はどこのプロセスを止めればいいか不明だったため,サインアウトにしました.再起動するよりは手軽とも判断しました.

2. defaults writeコマンドをsudoでしてもGUIからも反映されない
sudo defaults write~してもGUIからナチュラルスクロールが変更されていることは確認できませんでした.
調べきれてないので確証はないですが,sudo実行したらrootアカウントでのナチュラルスクロールが変更されただけなのではないかと思われます.
そもそもsudo実行しようとしたのは,上記GUIの変更とともに即反映されることを期待していたからですが,この躓きが下記の躓きにも絡んでいきます.

3. pkillのパーミッション
コード内部でpkillを呼び出していますが,自分のアカウントではパーミッションエラーが出てしまいました.
そこでsudoを直でpythonコードに書き込んでみましたが,スルーされてしまいました.パスワード入力できないからかと思われます.おそらく…
そこでsudoを直で書き込んだまま,pythonコード自体をsudo実行すると,pkillは機能しました.
ですが,上記躓きのdefaults writeが自分のアカウントに反映されないという状態になりました.

最終的にどうしたのか

結局sudoersファイルを編集しました.
visudoですね.以下のような感じでパスワードなしで自分のアカウントがpkillを使えるようにルールを追加してしまいました.個人のPCなので…
※以下の記述はうろ覚えのため正確じゃないです

hoge ALL=(root) NOPASSWD:/.../pkill
GitHubで編集を提案

Discussion