以前に Joystick Mapper という、ゲームパッドのボタンをキーに対応させる有料ツールを使ってJoy-Conをプレゼンリモコンにする方法が紹介されていました1が、ブラウザ上であればJavaScriptのワンライナーでJoy-Conをプレゼンリモコンにすることができます!
動作環境
- macOS Catalina
- Chrome 84
- Joy-Con (L)
準備
Joy-Con (L) を macOS の標準の機能で接続しておきます。
矢印の部分にあるボタンを長押しすると、ペアリングモードに入ります。
Joy-Conをプレゼンリモコンにするワンライナー
以下のスクリプトをデベロッパーツール(Macであればcommand+option+I)の Console に貼り付け Enter で実行します
((a,b,c)=>{const d=(b,c)=>{const d=a.activeElement,e="IFRAME"===d.tagName?d.contentDocument:a;["keydown","keyup"].forEach(a=>{e.body.dispatchEvent(new KeyboardEvent(a,{key:b,keyCode:c,bubbles:!0}))})},e=({vibrationActuator:a},b,c)=>a?a.playEffect(a.type,{startDelay:b,duration:c,strongMagnitude:.8}):Promise.resolve();let f,g;if(c("gamepadconnected",({gamepad:a})=>{if(null!=f||!a.id.includes("57e")||!a.id.includes("2006"))return;f=a.index;let c=!1;g=setInterval(()=>{c=(a=>{const b=a.buttons;return b[0].pressed?(c||d("ArrowLeft",37),!0):b[3].pressed?(c||d("ArrowRight",39),!0):!!b[16].pressed&&(c||e(a,0,10),!0)})(b.getGamepads()[f])},1e3/60);const h=()=>e(a,300,5);h().then(h).then(h)}),c("gamepaddisconnected",a=>{f===a.gamepad.index&&(clearInterval(g),f=g=null)}),b.wakeLock){const c=d=>{"visible"!==a.visibilityState||b.wakeLock.request("screen").then(()=>{d&&(a.addEventListener("visibilitychange",c),a.addEventListener("fullscreenchange",c))}).catch(()=>{})};c(!0)}})(document,navigator,addEventListener);
(minify前のコードはこちらにあります: https://github.com/mascii/presentation-joy-con/blob/master/src/presentation-joy-con.js )
ページが再読み込みされた場合には、再度上記のスクリプトを実行する必要があります。
利用するボタン
画像で図示したボタンでスライドを進めたり、戻したりすることができます。
スクリーンショットのキャプチャーボタンを押すと、コントローラーが少し振動します(疎通テスト用、Chrome などの対応ブラウザのみ)。
対応サイト
以下の対応サイトで利用できることを確認しました
- Google スライド(プレゼンモードのとき)
- SlideShare
- Speaker Deck
- Qiita
- Scrapbox(プレゼンモードのとき)
- Figma(プレゼンモードのとき)
解説
Gamepad APIを利用してJoy-Con (L)で押されたボタンを検知し、dispatchEvent
で左矢印キー・右矢印キーのイベント(keyup
と keydown
)を発火しています。
Joy-Conのボタンイベントの取得はWeb Bluetooth APIで頑張らないとできないのかな思っていましたが、調べていくうちにGamepad APIが使えること2がわかりました。
一方、矢印キーを押すイベントについてはGoogle スライドのようにiframeの中で発生させないといけないものもあることがわかり、複数サイトで対応させる方が大変でした。
コード
minify前のコードはこちらです:
https://github.com/mascii/presentation-joy-con
git clone
, npm ci
, npm run minify
でminifyしたワンライナーを出力可能です。改善点ありましたら、ぜひPull Requestしてください!
(2020/07/24追記)
- Chrome 84 から Screen Wake Lock API が利用可能となったので、対応ブラウザではディスプレイがオフにならないようにリクエストするようにしました(Pull Request)
- Speaker Deck でスライド以外の要素が active のときにスライドを動かそうとするとエラーが発生する問題を修正しました(Pull Request)
(2021/02/07追記)
- Chrome などの一部ブラウザで対応している Gamepad API の vibrationActuator を用いて、以下の対応をしました(Pull Request):
- コントローラー接続時(
gamepadconnected
イベント発生時)に、コントローラーが小刻みに3回振動する - スクリーンショットのキャプチャーボタンを押すと、コントローラーが少し振動する
- コントローラー接続時(