acpiの設定。

音量調整とかそういうのは、だいたいコマンドで叩くので普段はACPIを使ってなかったのだが、つい隣でid:athlonzがACPIの設定していたので試しに設定してみた。
以下覚書程度に、Gentoo on PrimePC(DosPara)でのACPIの設定方法をば。

まずはACPIがハードウェアのイベントを拾えるかどうかのテスト

acpidが起動していれば

$ acpi_listen

でイベントが見れるはず。


もしくはacpidが動いてなければ

# cat /proc/acpi/event

でもokなはず。


で、acpi_listenなりcatなりで監視しながら、マシンにくっついてるボタンをポチポチ押してみる。
電源ボタンやらスリープボタンも拾えるのだけど、拾った直後にシャットダウンし始めたりする可能性もあるので注意。
少なくともMandrivaだと無設定で電源ボタンは効いた...気がする。


うちの環境での結果はこんな感じ。

hotkey ATKD 00000030 00000028
hotkey ATKD 00000031 0000001a
hotkey ATKD 00000032 00000006

一番目の項目は分類(?)かなにか、電源とかだとbutton/powerとかになる。
二個目がデバイス、とからしい。
三番目がボタンごとのIDみたいなので、これが一番大事。
四番目はなんか押すごとに数字が増えていく。多分押した回数かなにか。
IDはうちのPCだと音量上げが00000030、下げるのが00000031、ミュートが00000032となってるらしい。

/etc/acpi/events/*の編集

で、acpidが「どのイベントが起きたときにどのファイルを実行するか」を記述するのが/etc/acpi/events/*のファイル。
さいしょからdefaultというのがあるので、こいつを参考に...とかいうほどでもないか。
イベントがevent=の部分にマッチするとaction=で指定されたファイルを実行する、という至極単純なフォーマット。


で、最初ハマったのだがこれ、1ファイルに1イベントのみらしい。
複数のイベントを拾いたいならファイルを複数書かないといけないらしい。
例えばうちの環境でミュートを拾う場合には

event=hotkey\ ATKD\ 00000032\ .*
action=/etc/acpi/actions/mute.sh %e

みたくなる。
eventの半角スペースは\でエスケープしますじゃ。
四番目の要素はガンガン変わるので正規表現の.*でなんでもマッチするようにする。
で、actionはなんかactionsディレクトリを作る流儀があるらしいの作ってみた。
まぁ、多分これはどうでもいいと思う。
%eはeventに置き換えられるらしい。
なんで、actionの方のスクリプトでこれを元にアクションを変えることもできる。

actionの編集

actionはとりあえず/etc/acpi/actions/に置いてみた。
音量調整ということで、amixerを使うことに。
あと、音量の上げ下げもミュートもほとんど同じようなコマンドで済むので複数のeventから一つのactionを呼ぶことに。
というわけで、/etc/acpi/events/muteも合わせて変更

# /etc/acpi/events/mute
event=hotkey\ ATKD\ 00000032\ .*
action=/etc/acpi/actions/vol.sh "toggle"

%eを使うと色々面倒なんで直接toggleを指定。
で、一方/etc/acpi/actions/vol.shを作成

#!/bin/bash
amixer set Master $*

...わざわざスクリプト書かずに直接actionに書いた方が早いかも。
まぁいいや。
chmodで実行権限を立てるのを忘れずに。

# chmod u+x vol.sh


で、あと音量も上げ下げも同様に

# /etc/acpi/events/volup
event=hotkey\ ATKD\ 00000030\ .*
action=/etc/acpi/actions/vol.sh 1+
# /etc/acpi/events/voldown
event=hotkey\ ATKD\ 00000031\ .*
action=/etc/acpi/actions/vol.sh 1-

こんな感じかな?

テストしてみる

とりあえず何はともあれacpidを動かそう。
インストールして

# emerge acpid


デーモンさんを起動。

# /etc/init.d/acpid start


で、あと、起動時に自動で立ち上げるにはrc-updateをば。

# rc-update add acpid default


で、ボタンをポチポチ。
音量は見た目では分かりづらいんでalsamixerなりGUIなミキサーを見ながらポチポチ。

で、ハマりやすいことですをいくつか。


まず、/etc/acpi/events/*はacpidを再起動しないと有効にならないっぽいです。
actionの方は書き換えたそばから有効になるっぽいのですが、念のためacpidも再起動しておくといいかも。


あと、デバックが非常にやりづらい...気がしないでもないです。
dmesgに流れたり流れなかったりなんですが、一番簡単なのはttyを使う方法かな?とか思ってます。
というか、それでデバックしてました。
とりあえずps fあたりで作業しているコンソールのpts番号を取得。
具体的にはpts/4とかね。
で、actionのほうで"echo debug message > /dev/pts/4"とか書いておくと作業してるコンソールに出るので便利かな、と。
まぁ、適当にちょいちょいやってくださいな。

ついでにモニタの輝度も変えてみる。

とりあえず、手動で明るさを変える方法について調べてみる。
過程をすっ飛ばして結果だけ書くと、proc以下に「ある」らしい。


環境によって変わるだろうから一概に言えないけど

$ cat /proc/acpi/video/VGA/LCDD/brightness
levels:  15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
current: 15

で、明るさの段階と、現在の明るさを取得可能。
うちの場合は1刻み、0から15の16段階らしい。
環境によっては15刻みとかあるらしい。


で、設定するときは

# echo 13 > /proc/acpi/video/VGA/LCDD/brightness

と数字を叩き込めばいいらしい。
リダイレクト(">")はシェルにログインしているユーザの権限で動くので、sudoだとうまくいかないです。
sudo suするなりしてからechoしてくださいな。


brightnessがどこにあるか分からないばあいはfindとかで探すとよいかも。

$ find /proc/ -name "brightness"
とりあえずスクリプトを書いてみる。

とりあえず輝度を上げてみる。

#!/bin/bash
current=$(cat /proc/acpi/video/VGA/LCDD/brightness | sed "s/^current=\s*\([0-9]*\)/\1/p;d")
expr ${current} + 1 > /proc/acpi/video/VGA/LCDD/brightness

まぁ、単純にはこうなるわけですが...ちょいとエレガントじゃない。
あ、bash方言まるだしなんで他shellの方はちょいちょい変えてやってください。


あと、ついでに言えばうちの環境だと輝度調整はacpiが拾ってくれない。
拾ってくれないので別のボタンを輝度調整に割り当てることに。
なので、あまり多くのボタンを割けないのです。
つまり、何が言いたいかというと、1ボタンで調整したいのです。
すると上げる用のボタン、下げる用のボタン、というようにできない。
つまり輝度をループさせたい。0->1->2->...->15->0->1の様に。


ということで、

輝度をループさせる

acpiイベントの吐く四番目の数字は押す度にインクリメントしていく。
で、輝度の段階が16段階で、四番目の数字も16進数。
おぉ、都合が良さそうだ。と、思って書いてみた。

# /etc/acpi/events/brightness
event=hotkey\ ATKD\ 00000061\ .*
action=/etc/acpi/actions/brightness %e
#!/bin/bash
echo $(($(echo $4 | sed "s/^......./0x/"))) > /proc/acpi/video/VGA/LCDD/brightness

ちょいと黒魔術。
第四引数をsedで先頭7文字を消して"0x"変えてbashの機能を使って10進数に変更。


で、使ってみて気がついたのだが、上がっていって、最大から最小にループするのは使うづらい。
少しずつ明るくなっていくのでどこが最大か分からない。
最小輝度までもどってやっと、「あぁ、さっきのが最大輝度か」とわかる。
ので、ちょいと都合が悪い。


ということで、やや改造

#!/bin/bash
echo $((15 - $(echo $4 | sed "s/^......./0x/"))) > /proc/acpi/video/VGA/LCDD/brightness

まぁ、単純に引き算しているだけですとさ。


で、

全然エレガントじゃない!!!

ので書き直し。

#!/bin/bash

brightness="/proc/acpi/video/VGA/LCDD/brightness"

item="\([0-9]\+\)"

current=$(cat ${brightness} | sed "s/^current:\s*${item}$/\1/p;d")
max=$(cat ${brightness} | sed "s/^levels:\s*${item}\b.*$/\1/p;d")
min=$(cat ${brightness} | sed "s/^levels:\s*.*\b${item}$/\1/p;d")
pos=$(cat ${brightness} | sed "s/^levels:.*\b${item}\s*${current}\b.*$/\1/p;d")
neg=$(cat ${brightness} | sed "s/^levels:.*\b${current}\s*${item}\b.*$/\1/p;d")

case $1 in
	"+")
		if [ -n "${pos}" ]; then
			echo ${pos} > ${brightness}
		else
			echo ${min} > ${brightness}
		fi
	;;
	"-")
		if [ -n "${neg}" ]; then
			echo ${neg} > ${brightness}
		else
			echo ${max} > ${brightness}
		fi
	;;
	"max")
		echo ${max} > ${brightness}
	;;
	"min")
		echo ${min} > ${brightness}
	;;
	*)
		echo $1 > ${brightness}
	;;
esac

levelsを使ってみた。
sedまわりは黒魔術なんで、説明不可(苦笑)まぁ、なんとなくわかるっしょ?
多分輝度の値が飛び飛びだったり、等差じゃなくても動くはず。
currentが現在の値、posが一つ次の値、negが一つ手前。
minは最小、maxが最大。
...って書かんでもわかるか。
で、スクリプトの引数で場合分け。
で、eventの方で"-"とか引数渡しておけばok。
現状だとループさせてるけど、適当にmin,maxを切り替えればループしなくなります。


...で、今さっき気がついたのだけど、Xが動いていると今の輝度が画面に表示されるね。うん。
コンソールで作業してたから気がつかんかった。


ということで、どうでもいいお話でした。