前回に引き続き簡易プレイヤーネタ。
ブラウザはメディアプレイヤーを備えている。ページにvideo要素があるときは、サイト側でプレイヤーを作らなくても、ブラウザのネイティブプレイヤーを表示してくれる。
このプレイヤーは解像度や字幕の設定がないぐらいで、基本的には動画サイトと同じ。速度変更できるしホットキーも使える。ただブラウザによって微妙に違うところがあったりする。そのひとつがシーク幅。アローキーでシークしたときFirefoxは10秒ずつだが、Chromium系は20秒。
個人的に20秒は多い。そこでホットキーを上書きすることにしたのだが、これがけっこうなハマりポイントだった。あとで書くけど、セオリー通りにやろうとするとめちゃめちゃ大事になる。なので今から書くのは妥協案。
まず、普通にkeydownイベントを登録したときどうなるか。
keydownイベントがトリガーされる前に、ネイティブのホットキーが発火する。例えば10秒シークする処理を仕込んだ場合、20+10で30秒シークしてしまう。必ず先回りして20秒シークするのを逆手にとり、10秒戻して差し引き10秒にするというのもやってみたけど、なんかちょっとズレる。
Eventには、規定の処理や同じタイプのイベントハンドラーを抑止するためのメソッドがあるが、使ってみても効果がなかった。どうやらネイティブのホットキーは、キーボードイベントとは違うっぽい。
唯一の隙は、video要素にフォーカスがあるときだけホットキーが有効になるところ。video要素の機能だから当たり前ではあるんだけど。
というわけで結論としては、video要素のフォーカスを外しまくるしかなかった。video要素のフォーカスイベントをトリガーして、即座にフォーカスを外す。
こんなことすると一切操作を受け付けないんじゃないかと心配したのだが、思ったより副作用は少ない。シークバーは使えるし、再生ボタン、オーディオボタンとかもちゃんと機能する。ただなぜかスリードットボタンだけは反応しなくなった。
スリードットボタンを押すと、通常は再生速度とピクチャーインピクチャーのメニューが表示される。正確には、表示されたあとメニューにフォーカスが移ったような挙動になる。このときフォーカスが外れるとメニューが閉じられるため、結果的にスリードットボタンが機能しなくなっているようだ。でもこれは簡単に対応可能。
Chromium系のブラウザでは、Event.sourceCapabilitiesというプロパティがあり、イベントがユーザーの操作によってトリガーされたとき、ここに入力デバイスのデータが入る。ユーザーの操作ではないとき(スクリプトなど)はnullが入る。
今回のケースでは、スリードットボタンを押したときのフォーカスはユーザーの操作によるが、メニューにフォーカスする処理はネイティブで実行されている。ユーザーの操作ではないので、sourceCapabilitiesの値はnull。
要するに、sourceCapabilitiesがtrueのときだけフォーカスを外すようにすればメニューは閉じない。
これでおおよそは機能するが、まだ完璧じゃない。開いたメニューを閉じるとき、そこら辺をぽちっとクリックすると、ネイティブのホットキーが有効になってしまう。
スリードットボタンを押すと、「メニューにフォーカスが移ったような挙動になる」と書いたが、メニューはvideo要素という扱いになっているため、activeElementはvideo要素のままなのだ。そのためメニューを閉じるとき、動画画面とかvideo要素のどこかをクリックしてしまうとフォーカスが移動しないので、フォーカスイベントもトリガーされない。このときだけはvideo要素にフォーカスされたままになる。
スリードットボタンを押す→video要素がフォーカスされる→メニューが開く→メニューがフォーカスされる→ような挙動をするがフォーカスはvideo要素にある→video要素のどこかをクリック→メニューが閉じる→同じ要素をクリックしたのでフォーカスイベントはトリガーされない。
これを回避するには、video要素のクリックイベントにも、フォーカスを外す処理を仕込まないといけない。ここまでやって、やっとネイティブのホットキーを無効にできる。
でも動画サイトでは独自のホットキーを実装していたりもするし、何かちゃんとしたやり方があるんじゃないの? そう思いますよね。うん、あるんですよ。
ここで前述のセオリー通りにって話に戻るのだが、video要素のコントロールバーを無効にすれば、ネイティブのホットキーは無効になる。ただしスペースキーだけは例外っぽいけど。コントロールバーを無効にするには、video要素のcontrol属性を削除すればいい。
これは、正攻法でいくならコントロールバーから作らなくてはいけない、ということだ。再生ボタン、シークバー、ボリュームバー、全部。……すげえ面倒くさそう。でもバー類は<input type='range'>で簡易的なのは作れるから、意外とすんなりできちゃったりするのかも?
軽い気持ちでホットキーを上書きしようとしたら、知らない世界が広がっててたまげたよ。ちなみに今回制作したものはここに置いてあります。
0 件のコメント:
コメントを投稿