Windows 上で空間ナビゲーションを実現したい
目的:UIAssistant に空間ナビゲーションを実装して、ウィンドウ内の要素間をラクラク移動したい
空間ナビゲーションとは
空間ナビゲーションは、表示された位置関係によって上下左右にフォーカスを移動できる機能です。矢印キーで指定した方向にフォーカスが移動する、と想像してもらえれば分かりやすいかも。コントローラを使用したゲームだと昔からよく見かけるモノです。十字キーでカーソルが移動するアレです。あと、Opera(Presto 時代)、Vivaldi に実装されていることで有名(?)
何が便利?
キーボード派の皆様は体験したことがあると思うのですが、Tab キーでのフォーカス移動で「あれ?フォーカスどこにいった?」と思ったことは無いでしょうか。このフォーカスどこいった現象は、Tab キーでのフォーカス移動だとユーザの予想に反した移動を行なう可能性が高いため発生します。
空間ナビゲーションの場合、ユーザが移動方向を指定できるため以下のメリットがあります。
- フォーカス移動回数の減少
移動方向にある要素のみが移動対象になるため - フォーカスどこいった現象をある程度軽減
移動方向は決まっているので、どこにいったかは予想しやすい
実装の前に先人の知恵を
まず先人の知恵を借りようということで、GitHub 内を spatial navigation
で検索しました。結果は現時点(2016/04/30)で 15 リポジトリあり、ほぼ javascript 系で占められています。だいたいがブラウザ上での使用前提なので納得の結果です。実装の仕方はそれぞれですが、移動先決定のアルゴリズムは似たりよったりで、大きく分けて 2 パターンありました。
- 絨毯爆撃的に要素を探す方法(FromPoint)
- 全要素の中から一番いいのを頼む(selector)
絨毯爆撃的に要素を探す方法(FromPoint)
elementFromPoint を使用して要素を探す方法です。空振りが多いのと、どのくらいの間隔をあけて取得するかが問題となります。AutomationElement.FromPoint メソッドを使用した場合、僕のマシンだと 1 回あたり 3.5-3.6 ms かかります。300 x 300 px の範囲を 5px の間隔で検索すると、180 回で 600 ms くらいかかる計算です。これは遅いので、今回こちらの手法は不向き。
全要素の中から一番いいのを頼む(selector)
一方のこちらは、全要素の中からフォーカスを合わせられる要素を抽出した上で、一番いいのを選択するパターン。"一番いいの" は、現在フォーカスのあたっている要素から最も距離が近いものを単純に選択しているようです。"一番いいの"の選び方を操作できれば楽しそうです。具体的には、リストボックス内の要素にフォーカスがあたっているとして、
- リストボックス内の要素へ移動したい
- リストボックス外の要素へ移動したい
の切り替えができたら便利そうだということです。リストボックスに要素が大量にあったら、いつまでも外に脱出できないですから一発で外に行けたら楽です。UIAssistant では(個人的に)ほしい機能です。
で、これを実現していたのが、ja-spatial-navigation の restrict で、移動対象の優先順位付けをして、ユーザが移動先をある程度選択することができます。
restrict Type: 'self-first', 'self-only' or 'none' Default: 'self-first' 'self-first' implies that elements within the same section will have higher priority to be chosen as the next candidate. 'self-only' implies that elements in the other sections will never be navigated by arrow keys. (However, you can always focus them by calling focus() manually.) 'none' implies no restriction.
GitHub - luke-chang/js-spatial-navigation: A javascript-based implementation of Spatial Navigation.
この辺りを参考に実装してみようと思います。
実装しました
それなりに動きました。(下の GIF 参照) 分かりやすいようにゆっくり操作していますが、もう少し速くフォーカス移動できます。ですが、やはり少し遅い……のと稀に変な移動するのでバイナリの公開はまだあとで。
2016/5/1 追記 続編は↓こちら。