マイコン工作実験日記

Microcontroller を用いての工作、実験記録

LVGLにおけるゲームパッドの扱い (その2)-- 入力フォーカスについて

2024-11-17 17:06:44 | DoomPlayer

前記事に書いたように、LVGLではゲームパッドをキーボードの代わりとして扱うことでGUI操作に用いることができます。画面上のオブジェクトをキーボード操作可能にするためには、予めそれらのオブジェクトを lv_group_add_obj()を使って同一のgroupに加えておきます。すると、ナビゲーションキーを使うことで、グループに登録された順番で辿って、選択/操作することが可能となります。この際に画面上に現れるのが入力操作対象となるオブジェクトを示すための入力フォーカス(Input focus)です。ディフォルトでは、対象オブジェクトの周りにoutlineスタイルで指定される外枠を描画することで対象オブジェクトが示されます。この入力フォーカスは、オブジェクトのグループが入力デバイスと対応付けられていれば(lv_indev_set_group())、何も余分な設定やコーディングをすることなく、キーパッド操作をするだけで自動的に表示されるのですが、実際にゲームパッドを使って操作をしていると少なからぬ違和感を感じるところがあります。元々、キーボード操作をするときでも生じることなので致し方ないところではありますが、Bluetooth接続のゲームパッドを使っていると結構気になります。

以下、その具体例を見ていきましょう。まず、最初の起動画面ですが、ここでは3つのアプリケーションを示すボタンが並んでいます。この状態では、ゲームパットは接続されていないので、ゲームパッドからのGUI操作はできませんが、LCDタッチパネルによるボタン押下はできます。

次に、DualSenseコントローラのPSボタンを押して、ゲームパッドを接続しました。HIDでの接続が完了すると、画面上にBluetoothのアイコンと電池残量表示が現れてゲームパッドからの操作が可能なことがわかります。この状態でゲームパッドの⬜︎ボタンを押すと実際にはDoom Playerが選択されるのですが、画面表示からはこのボタンが選択されていることは判別できません。

次にゲームパッドの→ボタンを押してみると、下図の様にBluetooth Playerボタンに外枠が表示されて、このボタンが選択されている、つまり入力フォーカスがこのボタンにあることが明示的に表現されます。

続いて←ボタンを押せば、入力フォーカスはひとつ前のDoom Playerボタンに戻り、この部分に外枠が表示されます。このように、ゲームパッドを接続した直後は、入力フォーカスがどのボタンにあるのかは画面表示からは判別できず、試しにLEFT/RIGHTボタン操作をしてみるとフォーカス表示が現れるのです。

さて、この状態で、今度はDualSenseのPSボタンを20秒長押しすることで、接続を切断します。画面左上部のアイコン表示は消えますが、ボタン周囲の入力フォーカス表示は残ったままになってしまします。

このようにBluetooth接続のゲームパッドを、動的に接続/切断しているとユーザとしては、それに応じて入力フォーカスが表示されたり、消えたりすることを期待してしまうのですが、LVGL側ではBluetoothの接続状態を意識しているわけではないので、期待するような表示変化が現れるわけもありません。したがって、この部分の変化はGUI処理部分のソフトウェアで自分で補ってやる必要があります。

具体的には、ゲームパッドが接続/切断された時点で、入力フォーカスの当たっているオブジェクトをlv_group_get_focused()を使って調べて()、そのオブジェクトの状態をlv_obj_set_state()でLV_SET_FOCUS_KEY状態に設定追加(lv_obj_add_state)したりクリア(lv_obj_clear_state)してやることで、外枠表示の追加/消去が行えます。

さて、これで問題が解決したかと思いや、まだうまくいかない場合があることがわかりました。それは、次の例のようにgridnavを使った場合です。

この例では、複数のボタンを並べたものがgridnavによってひとつのコンテナオブジェクトの中にまとまれており、そのコンテナがグループのメンバーになっています。そのため、グループの中でフォーカスが当たっているのはコンテナオブジェクトであり、その中に入っている個々のボタンまでは区別されていないのです。その結果、コンテナのステータスを変更してもボタン周囲の外枠表示は変化してくれないのです。

この問題を解決するためにgridnavのコードを調べたところ、コンテナオブジェクトのステータスを変更するのではなく、コンテナオブジェクトに対してlv_obj_send_event()を使ってLV_EVENT_FOCUSED/LV_EVENT_DEFOCUSED を送ってやれば良いことがわかりました。

 


最新の画像もっと見る

コメントを投稿

ブログ作成者から承認されるまでコメントは反映されません。