2016年9月21日水曜日

UWP App の Xbox One 対応でやったこと

今回、F10 Image bbs browser をXbox One に対応させる機会がありました。
やった事を忘れないうちにメモしておこう、という記事です。

この記事で触れない所


  • UWP 「ゲーム」アプリのXbox One対応 … ご承知とは思いますが、UWPゲームだけは別扱い、ID@XBOX でゲームのコンセプト確認プロセスがあるので全く別ルートです。今回は扱いません。
  • Xbox One 実機を使ったテスト・デバッグ … 私はXbox One 実機を持っていないのでこのあたりの経験が全くありません。PC+ゲームパッドでなるべく頑張り、後は持っている人に助けを仰ぐスタイルです。


参考になるドキュメント


今回、UWP App をXbox One 対応するにあたって、こなれたかなり良い文書(英語・日本語共に)が出ています。
これらを読みながら作業すればほぼ間違いないはずです。

Xbox およびテレビ向け設計 / Designing for Xbox and TV
日本語 https://msdn.microsoft.com/ja-jp/windows/uwp/input-and-devices/designing-for-tv
英語 https://msdn.microsoft.com/en-us/windows/uwp/input-and-devices/designing-for-tv

Xbox の ベストプラクティス / Xbox best practices
日本語 https://msdn.microsoft.com/ja-jp/windows/uwp/xbox-apps/tailoring-for-xbox
英語 https://msdn.microsoft.com/en-us/windows/uwp/xbox-apps/tailoring-for-xbox

※日本語情報は二か月ほど古く、いくつか間違いもあるようなので適宜英語版も参照するのがお勧めです。

この記事では、(基本的過ぎて)上の文書にあまり出てこない所を中心に、作業順に書いてみます。

xInput 対応ゲームパッドを入手する


PC上で作業するには、何は無くともまずこのxInput 対応ゲームパッドを用意するのがお勧めです。

UWP App とそのUI Controlは、既定でxInput ゲームパッドである程度操作可能になっています。
そして、ゲームパッドでの操作・フォーカス移動等重要な部分はPC+ゲームパッド と、Xbox One+ゲームパッドでほぼ同じです(※1)。
Xbox One 実機をお持ちであっても、まずPC上でゲームパッドでの操作を詰めてからXbox One 実機に転送・デバッグを行うことで、かなりの手間を省くことが可能です。

(Xbox One 実機をお持ちの場合、そのゲームパッドがそのままPCで使えます)


Amazonで「Xbox ゲームパッド」で検索した結果
どれでもOKです
私が使ってるのはエレコムの安いの


※1 完全に互換、では無いです。今回F10 のXbox One 対応では1件、Xbox Oneで発生するがPC上で再現しない、という問題がありました。この件は後でもう一度触れます。

※2 xInput ... UWP App が対応しているのはこの形式です。今お店で買えるXbox 360 以降用のパッドは全て xInput に対応しています。「大昔の」Windows用ゲームパッド…Microsoft Sidewinder 等、Win9xの頃のものはDirect Input 形式で、UWP Appでは使えません。


UWP App のターゲットバージョンを Anniversary Update (14393) に変更する


そもそも UWP App が Xbox One に対応できるのは AU SDK 以降なので、必須の作業です。

ここではTarget/Min両方を14393に設定しています。


マウスモードを無効にする


マウスモードを無効にする / How to disable mouse mode
日本語 https://msdn.microsoft.com/ja-jp/windows/uwp/xbox-apps/how-to-disable-mouse-mode
英語 https://msdn.microsoft.com/en-us/windows/uwp/xbox-apps/how-to-disable-mouse-mode


最低限これはやらないとXbox One 対応とは言いづらいと思います。
Xbox Best Practice でもいの一番に「マウスモードを切れ」と載っています(既定にすればいいのに)。

これを切らない(既定)場合、UWP App のコントロールは画面上に表示される「ポインタ」を方向キーで自由な位置に(マウスのように)移動させ、押したいところでAを押すというシステムになります。
マウスモードを無効にすることで、方向パッドでフォーカスを素早く移動する一般的なXbox のスタイルになります。

※ただしこの設定、PCでは入れても切っても全く変わらず、方向パッドで操作可能です。
これが微妙に罠なので、まず最初にばっすり切っておくのがお勧めです


◇◇◇


このあたりで下準備は大体終わりです。
ここからは、上で紹介した「Xbox および テレビ向け設計」を足掛かりに、

  • ゲームパッドで無理なく操作できるUI

を作り込んでいく作業になります。

今回のF10 の作業では、UI をXbox One に合わせて大きく変更するのは避け、基本的にはゲームパッド対応のみで済ませています。
(ゲームパッド対応は PC + ゲームパッドのみでも可能ですが、他の作業… TV セーフサイズへの対応や TV セーフカラー対応等は細かい作業が必要で、実機が無いと厳しいというのもあります。)

以下は、ゲームパッド対応を入れていて気が付いた点です。

フォーカストラップ・アクセスできないUI を地道に潰す


ガイドに従って XYFocus* や CodeBehind 等でフォーカスを調整し、ゲームパッドで無理のない操作ができるようにする作業が続きます。
その中で、以下の現象が何度も何度も現れました。これを潰すのがメインの作業と言ってもいいくらいでした。

  • フォーカストラップ ... フォーカスがあるコントロールにはまり込んでしまい抜けられない!!
  • アクセスできないUI … あるコントロールにフォーカスを合わせられない!!

どちらもPC 上ではマウスやキーボードで簡単に回避できるのですが、ゲームパッド「だけ」のXbox One の場合…ほぼ脱出手段が無く、一旦アプリを終了するしかなくなります。これはまずいです。

潰しきるためにはゲームパッドでひたすら色々操作を行い、見失う事が無いかを確認する必要があるでしょう。
今回の作業では、以下のような所に引っ掛かりました。

  • AutoSuggestBox から候補リストを開いて→閉じて戻って来る所は大体見失うので、CodeBehindやXYFocus*で明示的に設定する必要がありました。
  • Microsoft Store Services SDK に同梱のMS AdControl、フォーカスをゲームパッドで移動すると抜けられなくなります。isTabStop等も無いため困ります。私は汚い方法…AdControlのChildrenからWebViewを探し、そこにGotFocused でフォーカスが飛んで来たら別のコントロールに飛ばす、で対処しました。
  • ContentDialog 内に置かれたコントロール間でのフォーカス移動は注意したほうが良いようです。上で挙げた「Xbox Oneで発生するがPCのゲームパッドでは再現しなかった」問題がこれで、明示的にXYFocus*で指定する必要がありました。

このあたりのケーススタディは、MSさんガイド文書にも詳しく書いてありますので参考にして下さい。

また、MSさん文書にある「現在のフォーカス位置をDebugMessageに出力するCode Snippet」、あれはフォーカストラップ・アクセスできないUIの原因を探すには最強の武器です。是非使いましょう。

Focus Debug用Snippet



ContextFlyout をマウス・タッチ・ゲームパッド全対応にする


作業を始めてみるとわかる所ですが、操作の多くをContextFlyoutに頼る事になると思います。

このContextFlyout、
  • マウスの右クリック
  • タッチのタッチ&ホールド(いわゆる長押し)
  • ゲームパッドのメニューボタン
それぞれの操作に既定でマップされるので、今までRightTapped等で作っていた右クリックメニューを全部これに統一して、綺麗な実装にできそうです。

ただ同時に判るのが、GridView/ListView等、ListViewBase系での使い勝手が微妙な所です。

今迄のRightTappedでは、argument の RightTappedRoutedEventArgs の OriginalSource が RightTap されたアイテムのViewItemになっており、そのDataContext が Mapされている自前のDataItem、であるため、RightTap されたアイテムに対する操作を簡単に記述することができました。

ところがContextFlyoutでは…Opening・Opened 共、「Tapされたアイテム」の情報が入っていません。えー。困る。

仕方ないので、今回は小汚い手を使っています。
Eventの発生順は、
ContextFlyout の Opening
ContextFlyout の Opened
ListViewBase の RightTapped
です。
…なので、RightTapped が発生した時点で、Menuが開いていたらそのMenuを弄って目的のアイテムに対する操作にすりかえる、という。汚い。


ContextFlyout にアイコンを出す


この件Xbox One 特有では無く MenuFlyout一般にあてはまる話なのですが、MenuFlyout は既定だとアイコンが出なくて寂しいです。
私は以下の記事のテンプレートを丸々使っています。AppBarButton のように名前でSegoe MDL2 Assets を指定できて便利です。

[UWP]How to add an icon to a MenuFlyout in UWP?
https://social.msdn.microsoft.com/Forums/en-US/ef37ee55-0c73-4ca7-9946-f4c70bf095f5/



リリース


普通のUWP App と特に変わるところは無いです。対象とするDeviceFamily でXbox Oneにチェックを入れるくらいです。

ただ、一応Xbox One用のCompliance Testは回しているようです。F10 では一件、Xbox One特有のTestで引っ掛かったところがありました。


謝辞


今回の移植では、Xbox One 実機をお持ちのOssan50 さん、Parupo1467 さんに動作確認・テストの御協力を頂きました。有難うございました。




0 件のコメント:

コメントを投稿