Rainmeterを使ってみようの巻 〜Lua Scripting〜

覚えたら何かすごく便利な気がするので勉強を始めてみた。取り敢えず5chのスレを覗いてみると話が高度過ぎてついていけない。考えてみればLuaは元々C/C++の組み込みなのでそっち方面の人間ばっかりが集まってるのか。まあいいや、何か難しい事がしたい訳でもなくRainmeterをより楽にしたいだけだし。

概要

Luaの最新は5.3だがRainmeterで使用可能なLuaのVerは5.1。ちょっと触ってみた感想はLua単体だと出来る事は少ない。元々がCの組み込みなのでLua単体だと低機能。ややこしい事はCの方でやれという発想なんだろう。それはまあ別にいいが正規表現の実装が独特。いわゆるPerl準拠とはかなり違う。ここらはリファレンスを熟読しないと間違いの元。
さて、Python辺りのScript言語を使うのと何が違うのかというと一つはパッケージとして配布する事が出来るという点だがまあこれは殆どの人には関係ない事だろう。もう一つはRainmeterのBangを使えるという事。つまり実行結果をMeterに面倒なく反映できる。Pythonだと一旦txtに書き出してそれをWebParserで読み取る等の作業がいる。RainmeterにおけるLuaの存在意義はほぼこれのみだと個人的には思う。

Script Measure

[MeasureName]
Measure=Script
ScriptFile=MyScript.lua

これはLua scriptをロードするだけで実行は!CommandMeasureで行う。詳細は下記。

Options

これでLua scriptに引数を与える事が出来る。

[MeasureName]
Measure=Script
ScriptFile=MyScript.lua
MyOption=Hello, world!

Lua script内でSELFオブジェクトを通じてMyOptionを得る事が出来る。

!CommandMeasure

!CommandMeasureを使ってLuaコードを実行できる。

!CommandMeasure "MyScriptMeasure" "MyFunction()"
!CommandMeasure "MyScriptMeasure" "a = b; print(SKIN:ParseFormula('(2 + 2)'))"

Rainmeterは「"」しか認識しないので引数内で使うなら「'」を使う事。

Initialize

Initialize関数が定義されている時skinがloadまたはrefreshされた時1回だけ実行される。これはscript Measure自体が無効になっていても実行される。!SetOptionで実行scriptを変更した時も実行される。ちなみにdofileを使えばimportと同様の事が出来る。

function Initialize()
	dofile(SKIN:GetVariable('@').."MyDoFiles\\toolkit.lua")
	dofile(SKIN:MakePathAbsolute("toolkit.lua"))
end

Update

Update関数が定義されている場合Script Measureが更新されるたびに実行される。

function Update()
	MyVariable = "Hello, world!"
	return MyVariable
end

Update関数の返り値はScript Measureの返り値となる。

Log

printを使用する事

print("The current value of MyVariable is: " .. MyVariable)

Functions

SKIN object

SKINオブジェクトは自動的に生成される。

Method名 引数 概要
GetMeasure MeasureName 指定された名前のMeasure objectを生成する。ない場合はnilを返す。
MyMeasure = SKIN:GetMeasure("MeasureName")
GetMeter MeterName 指定された名前のMeter objectを生成する。ない場合はnilを返す。
MyMeter = SKIN:GetMeter("MeterName")
GetVariable VariableName
Default
ここでDefaultは任意。ユーザー定義変数の値を返す。ない場合はDefaultで与えられた値を返しDefaultが与えられてない場合はnilを返す。
MyVariable = SKIN:GetVariable("VariableName", "n/a")
Bang BangName
BangArg1
BangArg2
...
BangArgN
Bangを実行する。BangArg1以降はBangの引数。
someVar = 12
SKIN:Bang("!SetOption", "MeterName", "Text", "Hello, world!")
SKIN:Bang("!SetOption", "MeterName", "FontSize", someVar)
SKIN:Bang("!UpdateMeter", "MeterName")
SKIN:Bang("!Redraw")
MakePathAbsolute File/Folder 相対Pathをskinフォルダからの絶対Pathに変換する。
MyPath = SKIN:MakePathAbsolute("MyImage.png")
ReplaceVariables String 変数を含む文字列を処理する。Section変数も有効。
MyString = SKIN:ReplaceVariables("The value of MyVariable is #MyVariable#.")
ParseFormula FormulaString 数式の結果を返す。数式でない場合はnilを返す。Rainmeterの組み込み関数は括弧で括る必要がある事に注意する事。
numToRound = 239.78
roundedNum = SKIN:ParseFormula("(Round("..numToRound.."))")
Measure object

Measure objectはGetMeasureを使用して生成する。

MyMeasure = SKIN:GetMeasure("MeasureName")
Method名 引数 概要
GetValue Measureの値を数値で返す。
MyMeasureValue = MyMeasure:GetValue()
GetStringValue Measureの値を文字列で返す。
MyMeasureValue = MyMeasure:GetStringValue()
GetOption OptionName
Default
ここでDefaultは任意。Optionの値を文字列で返す。Optionが存在しない場合はDefaultを返し未指定の場合は空白を返す。
MyGroup = MyMeasure:GetOption("Group", "None")
GetNumberOption OptionName
Default
ここでDefaultは任意。GetOptionと同じだがこちらは数値で返す。
MyUpdateDivider = MyMeasure:GetNumberOption("UpdateDivider", 1)
GetName Measure名を文字列で返す。
MyMeasureName = MyMeasure:GetName()
GetMinValue Measureの最小値を返す。
MyMeasureMin = MyMeasure:GetMinValue()
GetMaxValue Measureの最大値を返す。
MyMeasureMax = MyMeasure:GetMaxValue()
GetRelativeValue Measureの値を0.0-1.0間の%値として返す。当然MinValueとMaxValueに依存する。
MyMeasureValue = MyMeasure:GetRelativeValue()
GetValueRange Measureの値の範囲つまりMinValueとMaxValueの差を返す。
MyMeasureRange = MyMeasure:GetValueRange()
Disable Measureを無効にする。
MyMeasure:Disable()
Enable Measureを有効にする。
MyMeasure:Enable()
SELF object

SELFオブジェクトは自動的に生成される。全てのMeasure objectはSELF objectでも有効。

MyScriptMeasureName = SELF:GetName()
Meter object

Measure objectはGetMeterを使用して生成する。

MyMeter = SKIN:GetMeter("MeterName")
Method名 引数 概要
GetOption OptionName
Default
ここでDefaultは任意。Optionの値を文字列で返す。Optionが存在しない場合はDefaultを返し未指定の場合は空白を返す。
MySolidColor = MyMeter:GetOption("SolidColor", "000000")
GetName Meter名を文字列で返す。
MyMeterName = MyMeter:GetName()
GetX Absolute ここでAbsoluteは任意。X座標を返すのだがAbsoluteがtrueの場合絶対値を返す。
MyX = MyMeter:GetX()
GetY Absolute ここでAbsoluteは任意。Y座標を返すのだがAbsoluteがtrueの場合絶対値を返す。
MyY = MyMeter:GetY()
GetW Meterの幅を返す。
MyW = MyMeter:GetW()
GetH Meterの高さを返す。
MyH = MyMeter:GetH()
SetX X MeterのX座標を与える。Referenceには書いてないが当然引数を指定する必要がある。
MyMeter:SetX(100)
SetY Y MeterのY座標を与える。
MyMeter:SetY(100)
SetW W Meterの幅を与える。
MyMeter:SetW(100)
SetH H Meterの高さを与える。
MyMeter:SetH(100)
Hide Meterを非表示にする。
MyMeter:Hide()
Show Meterを表示する。
MyMeter:Show()

Restrictions

次のLua Libraryは現在はRainmeterでは使用不可。

  • LuaCURLの様なコンパイルされたライブラリ
  • require, os.exit, os.setlocale, io.popen, collectgarbage

Inline Lua

Script MeasureのSectionVariable経由でLua内関数を実行またはLua内の変数を取得できる。関数を実行した場合SectionVariableの値は当然関数の返り値となる。今のところ実行できるのは関数のみでLua Statementを単独で実行は出来ない。

[&ScriptMeasureName:LuaFunctionName(numberParameter, 'stringParameter', ...)]
[&MeasureMyScript:myVariable]

以下はいくつかの注意点

  • SectionVariableなんだから当然DynamicVariables=1が必要。
  • 関数の引数は引用符で括らないと変数扱いされる。
  • 関数の引数にtableを指定する事は出来ない。
  • nilを引数で指定する事は可能だが返り値とする事は出来ない。
  • tableをindex付きで引数に指定する事は出来ない。
  • skinの初回更新前はMeasureおよびMeterの初期値は0もしくは""が設定されるので注意する事とあるが関数の引数にMeasureの値をSectionVariableで引っ張ってくる場合の事。
[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1

[MeasureGetUserName]
Measure=Plugin
Plugin=SysInfo
SysInfoType=USER_NAME
UpdateDivider=-1

[MeasureScript]
Measure=Script
ScriptFile=SimpleLua.lua
Disabled=1

[MeterWelcome]
Meter=String
FontSize=20
FontWeight=400
FontColor=255,255,255,255
SolidColor=47,47,47,255
Padding=5,5,5,5
AntiAlias=1
Text=[&MeasureScript:GetWelcome('[&MeasureGetUserName]')]
DynamicVariables=1
function GetWelcome(inArg)
	hourOfDay = tonumber(os.date('%H'))
	if hourOfDay < 12 then
		greetingText = 'Good Morning'
	elseif hourOfDay < 17 then
		greetingText = 'Good Afternoon'
	else
		greetingText = 'Good Evening'
	end
	welcomeText = greetingText..', '..inArg
	return welcomeText
end

この例は特に解説なんか必要ないがScript MeasureがDisabledとなっているのはUpdate関数もないし返り値も使われてない為Measure自身は動いている必要はないので。