CTRL (日本語)
CTRL - Control & Trigger Relays Library (制御&トリガー中継ライブラリ) - LÖVE 入力
基本的な使用方法に関しては簡単であり同時に強靭かつ広範囲の用途で先進的です。このライブラリではユーザ入力を処理するために必要な全ての機能が使えます。さらに、ネイティブのフレームワークでは対応していない入力デバイスを処理するにも十分な能力と拡張があります。
Contents
基本的な使用方法
使用を開始するには CTRL クラスのインスタンスを作成する必要があり(何らかの理由があり多数の CTRL のインスタンスが必要な場合は、それを作成することはできます)、イベントハンドラのコールバック関数を定義する必要があります。 CTRL により取り除かれた関連性のない入力イベントにおけるすべての情報、および残りの最も有用なステート(状態)の改善を除き、大部分は通常の LÖVE の入力コールバックと同様の方法で動作します。その後に一部の入力バインディングを作成する必要があります。そして最後に、 LÖVE 入力イベントを接続するための CTRL のインスタンスが必要となります。
コードの一例
local ctrl = require ( 'ctrl' ) ( )
function ctrl:inputpressed ( name, value ) print ( "pressed", name, value ) end
function ctrl:inputreleased ( name, value ) print ( "released", name, value ) end
function ctrl:inputmoved ( name, value ) print ( "moved", name, value ) end
ctrl:bind ( "fire", { "keyboard", "space" } )
ctrl:bind ( "fire", { "joystick", "default", "button", 1 } )
ctrl:bind ( "fire", { "mouse", "left" } )
ctrl:hookup ( )
有効な入力値の一覧
"keyboard"
- すべて LÖVE の標準キーボード定数
"mouse"
"x", "y", "wheelx", "wheely", "left", "right", "middle"
- 4, 5, 6, など。
"gamepad"
"default"
またはジョイスティック用の任意の既存マッピングです"axis"
"leftx", "rightx", "lefty", "righty", "triggerleft", "triggerright"
"button"
"a", "b", "x", "y", "back", "guide", "start", "leftstick", "rightstick", "leftshoulder", "rightshoulder"
"hat"
"up", "down", "left", "right"
"joystick"
"default"
またはジョイスティック用の任意の既存デバイスマッピングです"axis"
- 1, 2, 3, など。
"button"
- 1, 2, 3, など。
"hat"
- 1, 2, 3, など。
"up", "down", "left", "right"
- 1, 2, 3, など。
デフォルトではジョイスティックおよびゲームパッドのマップは "default"
であり、これで大抵の場合は事足ります。
詳細
CTRL は基本的な機能性の上にたくさんの組み合わせることのできる機能を有しています。
入力の自動取得
入力設定画面で最も有用です。
grab
関数を使用することで利用者が Select (選択) の動作をするボタン押しても CTRL は自動的にバインド (接続、結線) 設定を行うことができ、そして全入力信号から望む入力だけを残して、それ以外をフィルタリング (除外、篩い分け) する設定を行うことができます。三種類の引数は全てオプション (必要に応じて選択) ですが、いずれかのコールバックまたは自動バインディング名称が存在するべきです (そうでなければ有効な動作は行われません)。
local bindname = "foo"
callback = function ( input )
-- 利用者が "escape" を押した場合は入力を取り消すか、またはバインドを行います。
if input[ 1 ] == "keyboard" and input[ 2 ] == "escape" then ctrl:grab ( )
else ctrl:bind ( bindname, input ) end
end
ctrl:grab ( callback )
-- 自動バインドに対しては次回の全入力を "foo" の動作として CTRL へ設定を行い、キーボードとゲームパッドからの入力のみできるようにします。
ctrl:grab ( "foo", { { "keyboard" }, { "gamepad", nil, "button" } } )
取得した入力バインディングを保存することは意味のあることです。それを CTRL で行うための機能として saveData
および loadData
関数があります。ファイル名を渡してデータの読み込み・保存ができます。saveData
に何も渡さない場合は、保存されたデータの文字列を返します。loadData
の代わりに前述したデータの文字列を渡すことができます。
カスタムバインディング
最も重要な機能の一つはバインディングのカスタマイズ機能です。これは bind
関数の第三引数である bind のオプション引数 options へテーブルを渡すことで得られます。mapper
テーブルが有するのはバインディングと結びついた生の値による再マッピング関数に関しての情報を有することができ、 filter
テーブル は生の値からの最終実時間によるマッピング値に関して類似情報を有することができ、さらに events
テーブルは、このバインディングで生成を行うイベントの一覧を有することができます。
Mapper (マッパー) テーブルは二種類の名称の値を有しています:
func
: マッピングを行う関数args
(オプション): 関数へ渡すための追加の引数テーブル
マッパー関数 (後述) は登録された文字列による名前の mapper 関数または関数値のいずれかです。呼び出し時に、 raw, last mapped, args, ...
を渡します。第一引数は入力デバイスからの生の値です。第二引数は最後に呼び出されたときに出力された値です。第三引数は args
であり、なにかのデータを有しているか、まったく存在しないオプションのテーブルです。最後の引数で vararg
が渡されます。そられは全て有していますが、追加の生のイベント引数は一般的なイベントハンドラ関数へ渡されます。マウスイベントを除き標準的な LÖVE イベントは空となるため、 dx dy
および isTouch
はマウスのコールバックとなります。これを用いると、多種多様な生の入力情報を渡すことでカスタムの生の入力イベントを定義することができます。
local fooMapper = function ( raw, last, args, ... )
return raw * args.foo
end
ctrl:bind ( "foo", { "keyboard", "f" }, { mapper = { func = fooMapper, args = { foo = 1 } } } )
Filter (フィルタ) テーブルは二種類の名称の値を有しています:
func
: マッピングを行う関数args
(オプション): 関数へ渡すための追加の引数テーブル
マッパーと同様、フィルタ関数 (後述) は登録された文字列による名前の filter 関数または関数値のいずれかです。呼び出し時に、 dt, mapped または raw, last filtered, args
を渡します。第一引数は update 関数からの dt
です。第二引数は現在のマップ値 (マッパー未設定時は生の値) です。第三引数は最後に呼び出されたときに出力された値です。第四引数は args
であり、なにかのデータを有しているか、まったく存在しないオプションのテーブルです。
local fooFilter = function ( dt, raw, last, args )
return last + raw * dt
end
ctrl:bind ( "foo", { "keyboard", "f" }, { filter = { func = fooFilter } } )
イベントテーブルはイベントテーブルの一覧を有しています。 Filter (フィルタ) テーブルは各三種類の名称の値を有しています:
trigger
: 入力されたイベントを切り替えるかどうかを決定するための関数handler
: 入力されたイベントを処理するために呼び出されるコールバック関数args
(オプション): トリガー関数へ渡される追加の引数テーブル
トリガー関数 (後述) は登録された文字列による名前の trigger 関数または関数値のいずれかです。呼び出し時に、 current, previous, args
を渡します。第一引数は現在の値です。第二引数は以前の値です。第三引数は args
であり、なにかのデータを有しているか、まったく存在しないオプションのテーブルです。
ハンドラ関数は文字列による名前の既存イベントハンドラ関数 (単に正常であると定義されている) または関数値のいずれかです。呼び出し時に、 ctrl, name, value
を渡します。第一引数はこのイベントを作動させた CTRL のインスタンスです。第二引数はこのイベントを作動させたバインド済みの動作名称です。第三引数は現在の値です。
local fooTrigger = function ( curr, last, args )
return curr > last
end
local inputFooBar = function ( ctrl, name, value )
print ( "foobar", name, value )
end
ctrl:bind ( "foo", { "keyboard", "f" }, { events = { foobar = { trigger = fooTrigger, handler = inputFooBar } } } )
マッパー、フィルタおよびトリガー関数は "登録済み" およびバインディングのコードから文字列名称により参照することができます。すぐに使用しないのであれば、ビットデータを一切消失することなく、データセーバーへ正確なバインディングを記憶することができます: 付加された関数のコードはファイルへ保存することはできませんが、文字列の名称は保存可能です。イベントハンドラのコールバックは明示的登録する必要はなく、 LÖVE の入力コールバックの定義と同様の方法で CTRL のインスタンスを定義します。バインディングのオプションを関数へ渡す代わりに、その方法 (訳注: インスタンスのことだと思います) を使う理由はマッパー、フィルタおよびトリガーと同じです。
ctrl:addMapperFunction ( "fooMapper", fooMapper )
ctrl:addFilterFunction ( "fooFilter", fooFilter )
ctrl:addTriggerFunction ( "fooTrigger", fooTrigger )
function ctrl:inputFooBar ( name, value )
print ( "foobar", name, value )
end
CTRL はデフォルトで豊富なマッパー、フィルタ、トリガーを標準装備しています:
deadzone
: アナログ入力範囲を 0 より小さい領域で固定します (args = { deadzone = 0.1 }
)remap
: 全部のアナログ入力範囲を異なる出力範囲へマッピングします (args = { rawmin = 0, rawmax = 1, mapmin = 0, mapmax = 1, min = 0, max = 1 }
)
smooth
: 出力値を生の値に向かってスムーズに移動します (args = { speed = 1 }
)ramp
: 生の値により上下に出力値を動かします (args = { speed = 1, min = 0, max = 1 }
)
pressed
: 値が 0.25 以下に下降するときに作動しますreleased
: 値が 0.75 以上に上昇するときに作動しますmoved
: どのような量であっても値の変化が発生したときに作動します
ゲームパッドのマッピング
CTRL 流の入力テーブルを受け入れる点を除き、LÖVE の gamepadMapping
と同じ方法で機能しますので、 grab
関数を使用してゲームパッドのマッピングを設定することができます。
local joystick = love.joystick.getJoysticks[ 1 ]
local inputtype = "start"
local callback = function ( input )
ctrl:setGamepadMapping ( joystick, inputtype, input )
end
-- ジョイスティックのボタンのみ対象として取得、フィルタ処理を開始します
ctrl:grab ( callback, { "joystick", nil, "button" } )
カスタム入力メソッド
これは仮想キーボードおよびモバイル機器で見かける仮想ジョイスティックといった純粋な仮想デバイスと同様にカスタム入力デバイスを使用できるようにします。これを行うには二種類の方法があります。一つ目の方法はカスタム入力デバイスのイベントを標準的なイベントへ流すことです。カスタムデバイスは表に出てこないため標準的なデバイスからは識別できません。二つ目の方法は新しい入力の種類を定義して手動で一般的な入力ハンドラ関数を呼び出すことです。
ctrl:addInputs ( { "virtualkeyboard", "A" }, { "w", "s", "a", "d" } )
ctrl:addInputs ( { "virtualkeyboard", "B" }, { "u", "j", "h", "k" } )
ctrl:bind ( "foo", { "virtualkeyboard", "A", "w" } )
ctrl:bind ( "bar", { "virtualkeyboard", "B", "u" } )
. . .
function virtualkeyboard:pressed ( section, key )
ctrl:handleUpdate ( { "virtualkeyboard", section, key }, 1 )
end
function virtualkeyboard:released ( section, key )
ctrl:handleUpdate ( { "virtualkeyboard", section, key }, 0 )
end
デバイスマッピング
入力の種類が (キーボードやマウスのように) ユニークで繰り返し識別できないならば、その ID は実行時に生成する必要があります。それを行うための様々な方法はありますが、そのすべては一つたりとも全てを終わらせる銀の銃弾ではありません。これはデバイスの自動識別に関して CTRL が完全に止まってしまう理由であるため、代わりにデフォルトとして "default"
のマッピングの行うために、自作の ID 生成関数を実装する必要があります。大抵の場合はデフォルトを使うだけで事足りますが、一部のシナリオとして、ローカル型のマルチプレイヤーゲームのように、同一デバイスであってもデバイスが類似していることがあるため識別を必要とします。よくある方法の人ととしてゲームパッドごとにインデックス番号を割り当て、番号によりゲームパッドを参照することです。もう一つの方法として必然的に GUID またはゲームパッドのリテラル名を取得して、それがユニークなものでなければ、区別をするために数字を付け加えることが必要です。一度 ID 生成を完了すると、 mapDevice
関数を使用して、この ID をジョイスティックに割り当てることができます:
local id = produceId ( joystick )
ctrl:mapDevice ( joystick, id )
リファレンスマニュアル
ctrl ( ), ctrl.new ( ) 入力ハンドラのインスタンスを新規作成して返します ctrl:hookup ( ) デフォルトの LÖVE 入力コールバックに関して寄生対象の入力ハンドラを接続します ctrl:bind ( name, input, [options] ) 入力の名称で指定された入力をバインドします * name - バインドを行う入力名称 * input - バインドを行う CTRL の入力アドレス * options (オプション) - オプションのテーブルであり、以下のフィールドを有することができます: * mapper (オプション) - 生の値からなるマッパーのテーブルを記述します * func - マッパーのコールバック関数であり、マップ処理済みの値を返します * args (オプション) - コールバック関数の引数テーブル * filter (オプション) - フィルタの値を記述します * func - フィルタのコールバック関数であり、フィルタ処理済みの値を返します * args (オプション) - コールバック関数の引数テーブル * events (オプション) - イベントの一覧を記述したテーブルを有するテーブルです。各テーブルが有しているものは: * trigger - コールバックのトリガー関数であり、トリガーが発生した場合は true を返します * handler - コールバックのハンドラ関数であり、イベントが発生した場合は true を返します * args (オプション) - コールバックのトリガーに対する引数テーブル ctrl:unbind ( [name], [input] ) 指定された入力のバインドを解除します * name (オプション) - 入力名称のバインドを解除します * input (オプション) - CTRL での入力アドレスのバインドを解除します 引数なしで呼び出された場合は、すべての接続を解除 (アンバインド) します。 入力アドレスなしで呼び出された場合は、個別名称によりバインドされたすべてものの接続を解除します。 名称なしで呼び出された場合は、絶対アドレスによりバインドされたすべてものの接続を解除します。 入力アドレスは部分的なアドレスを指定すると、それはフィルタのように機能して、一致するすべてのものの接続を解除します ctrl:grab ( [callback], [autobind], [filters] ) 入力デバイスにおける全動作状態の記録を開始してから、最初の変更を取得します * callback (オプション) - 動作状態の検出時に呼び出される関数 現在の入力を破棄して次の入力を記録した場合は true を返します 以下の引数を伴って呼び出されます: * input - CTRL の入力アドレステーブル * name - 引数により変更されなかった自動バインド * autobind (オプション) - 自動的に何かを検出して対象のバインドを行うために使用する文字列による入力名称 * filters (オプション) - 記録時に不一致とする CTRL の入力アドレス一覧 ctrl:getBindings ( [name], [input] ) 指定された入力名称によりバインドされた全入力アドレスの一覧を検出して返します * name (オプション) - バインディングのために検索する名称 * input (オプション) - 検索を行う CTRL の入力パス ファイル名称が渡されなかった場合は、すべてのバインディングを検索します 入力 (input) は部分的なパスにすることができ、それはフィルタのように機能します リスト項目は以下の形式からなります: * name - 入力の文字列名 * input - CTRL の入力アドレステーブル * options - 入力オプションのテーブル (マッパー、フィルタ、イベント) ctrl:isUp ( name ) ctrl:wasUp ( name ) 入力値が 0.25 以下ならば true を返します * name - 検索を行う入力の名称 ctrl:isDown ( name ) ctrl:wasDown ( name ) 入力値が 0.75 以上ならば true を返します * name - 検索を行う入力の名称 ctrl:getValue ( name ) ctrl:getLastValue ( name ) 入力の値を返します * name - 検索を行う入力の名称 ctrl:resetValues ( ) 全ての値を 0 へリセットします。 一部の方法においてウィンドウの組み合わせでフォーカスアウトを行うと入力処理で入力の異常が発生しますが、 この問題を解決するにはすべての値をリセットします ctrl:mapDevice ( device, value ) ユーザデータまたはデバイスの文字列、番号またはブーリアンのテーブルにマップを割り当てます * device - 入力デバイスにより参照されるユーザデータ、テーブルまたは任意の他の値 * value - 入力アドレスにより割り当てられる文字列、番号またはブール値 持続的な ID を除きジョイスティックとゲームパッドは他のデバイスで使用してください ctrl:getMapping ( device ) 以前、このデバイスにマップとして割り当てられた値を返します。デフォルトは "default" です * device - 検索対象の入力デバイス ctrl:setGamepadMapping ( joy, control, input ) love.joystick.setGamepadMapping の複製ですが、ライブラリとの円滑な統合を提供しています * joy - マッピング対象となる löve の Joystick オブジェクト * control - löve の Gamepad コントロール (ボタン、ハット、軸) * input - CTRL のジョイスティック入力パスのテーブル ctrl:getGamepadMapping ( joy, control ) love.joystick.getGamepadMapping の複製ですが、ライブラリとの円滑な統合を提供しています * joy - マッピング取得先となる löve の Joystick オブジェクト * control - löve の Gamepad コントロール (ボタン、ハット、軸) 選択された Gamepad コントロールに対して CTRL のジョイスティック入力におけるアドレステーブルを返します ctrl:addInputs ( input, new ) 有効な入力一覧へ新しい値を追加します * input - 追加する CTRL の入力パス * new - 追加の有効な入力一覧であり、メタテーブルを有することができます ctrl:handleUpdate ( input, raw, ... ) 入力イベント処理およびコールバックの切り替え * input - CTRL の入力アドレステーブル * raw - 生の値 * vararg - 生のマッパー関数へ渡される任意の追加値 ctrl:addTriggerFunction ( name, func ) 一覧へ追加する新規トリガー関数 * name - 新規イベントトリガー関数の文字列名称 * func - コールバック関数であり、イベントが発生した場合は true を返します 以下の引数を伴って呼び出されます: * 現在の値 * 以前の値 * 関数の引数テーブル ctrl:addFilterFunction ( name, func ) 新規フィルタ関数を一覧に追加します * name - 新しい生値のフィルタ関数における文字列の名称 * func - コールバック関数であり、フィルタ処理された生の値を返します 以下の引数を伴って呼び出されます: * 最終呼び出しからの経過時間 * 生の入力値 * 以前にフィルタ処理された値 * 関数の引数テーブル ctrl:addMapperFunction ( name, func ) マッパー関数の新規生値を一覧に追加します * name - 新しい生値のマッパー関数における文字列の名称 * func - コールバック関数であり、マップが割り当てられた生の値を返します 以下の引数を伴って呼び出されます: * 生の値 * 以前にマップ処理された値 * 関数の引数テーブル * vararg は入力イベントのハンドラ関数へ渡されます ctrl:saveData ( [filename] ) ファイルへ全内部データを保存しますが、ファイル未指定時はデータ文字列を返します * filename (オプション) - データの保存先となるファイルの名称 ctrl:loadData ( filename ) ファイルまたは文字列からデータを読み込みます * filename - データの読み込み先となるファイルの名称、またはデータ文字列 ctrl:handleUpdate ( dt ) ctrl:handleKeypressed ( key, code, repeated ) ctrl:handleKeyreleased ( key, code, repeated ) ctrl:handleMousepressed ( x, y, button, touch ) ctrl:handleMousereleased ( x, y, button, touch ) ctrl:handleMousemoved ( x, y, dx, dy, touch ) ctrl:handleWheelmoved ( x, y ) ctrl:handleGamepadaxis ( joy, axis, value ) ctrl:handleGamepadpressed ( joy, button ) ctrl:handleGamepadreleased ( joy, button ) ctrl:handleJoystickaxis ( joy, axis, value ) ctrl:handleJoystickhat ( joy, hat, dir ) ctrl:handleJoystickpressed ( joy, button ) ctrl:handleJoystickreleased ( joy, button ) ctrl:handleJoystickadded ( joy ) ctrl:handleJoystickremoved ( joy ) LÖVE の入力イベントハンドラです。CTRL のインスタンスが "接続" されていない場合は適切な方法をもって手動で呼び出してください。
リンク
- フォーラムのスレッド: https://love2d.org/forums/viewtopic.php?f=5&t=84093
- BitBucket レポジトリ: https://bitbucket.org/rcoaxil/ctrl
- デモ・コード/アプリケーション: https://bitbucket.org/rcoaxil/ctrl/downloads/example.love