キーボード操作がマウスによるパズルスライドを破綻させないようにする方法
テーブルトークRPGの補助ツールとしてブラウザベースのスライドパズルを作成する場合、キーボードショートカットの適用範囲をパズル内に限定しつつ、マウスのドラッグとキーボードの移動が同じパズル状態に対して動作するようにします。重要なチェックポイントは、フォーカス、イベント処理、そしてドラッグの完了です。テキストフィールドでキーを押してもピースが動かないようにし、ポインタがピースの境界を越えてもドラッグが中断されたり失われたりしないようにする必要があります。
まずは予期せずパズルを動かしている原因を特定する
マウス操作中にパズルが矢印キーに反応してしまう場合、原因の多くはキーボードリスナーの対象範囲が広すぎることです。document や window に設定されたハンドラーは、プレイヤーが手がかりの入力フィールドに入力しているときや、メニューを使用しているとき、あるいは別のコントロールを操作しているときでも矢印キーを受け取ってしまいます。また、パズルを動かすと同時に、スクロールなどのブラウザのデフォルトの挙動を引き起こすこともあります。
簡単なチェックリストを使って問題を再現してみましょう。ピースをクリックしてドラッグする、パズルの枠外までドラッグする、パズルにフォーカスがある状態で矢印キーを押す、そして手がかりの入力欄、ボタン、メニューにフォーカスがある状態で矢印キーを押す。盤面が変わるか、ページがスクロールするか、フォーカスが移動するか、あるいはドラッグが停止するかを記録します。これらの観察により、パズルのハンドラーの問題なのか、ポインタのトラッキングの問題なのか、あるいはブラウザのデフォルトの挙動なのかを区別できます。
パズルに明示的なフォーカス境界を設ける
盤面は、明確なキーボード入力のエントリーポイントを持つコントロールとして扱います。フォーカス可能な盤面コンテナを使用し、その盤面がアクティブな場合、またはフォーカスが盤面内のピースにある場合にのみパズルのキーを処理します。ヒントボタンやテキストフィールドなど、無関係なコントロールはそのキー処理の境界外に配置します。プレイヤーが「いつ盤面が反応するか」を判別できるように、フォーカスの位置を視覚的に示しましょう。
キー入力を解釈する前に、イベントターゲットを確認します。フォーカスが入力欄、テキストエリア、編集可能な要素、または別のボタンにある場合は、キー入力を処理しないでください。協力型のアドベンチャーツールでは、他のプレイヤーがパズルを操作している間に、プレイヤーがルーン、名前、または手がかりを入力することがあるため、この点が重要になります。文字入力によって誤ってピースが動いてしまってはなりません。
それでもキーボード操作自体は機能させる必要があります。W3Cのガイドラインでは、可能な限りキーボードインターフェースを通じて機能を利用できるようにすべきであると説明されており、オブジェクトを特定の位置に移動するアクションもキーボードで操作可能なものとして挙げられています。キー操作を完全に削除するのではなく、その適用範囲を慎重に限定してください。W3C: 達成基準 2.1.1: キーボードを理解する
パズルのコマンドとブラウザのデフォルト動作を分離する
盤面にフォーカスがあるときの矢印キーなど、盤面用にあらかじめ文書化した少数のキーセットを選定します。ハンドラー内では、まずそのキーがパズルで使用されるものであること、そして盤面がアクティブなターゲットであることを確認します。その上で移動を適用し、必要に応じてそのキーのブラウザのデフォルトアクションをキャンセルします。あらゆるキーを一括でグローバルに無効化することは避けてください。プレイヤーはパズル外で通常のタイピング、ブラウザナビゲーション、コントロールの操作を行う必要がある場合があります。
preventDefault() は、イベントがキャンセル可能な場合にブラウザのデフォルトアクションをキャンセルしますが、他のハンドラーへのイベント伝播を停止させるわけではありません。つまり、ページのスクロールを防ぐことはできても、ピースを動かす別のリスナーの実行まで止めることはできません。ゲーム状態を変更するハンドラーを特定してその対象を絞り込みましょう。イベントの明確な所有権を定義する代わりに、無差別にキャンセルを適用して済ませようとしてはなりません。MDN: Event: preventDefault() メソッド
盤面全体でポインタのドラッグを途切れさせない
ドラッグ操作では、ドラッグを開始する押下から離脱またはキャンセルまで、単一のアクティブなポインタを追跡します。ポインターイベントには pointerdown、pointermove、pointerup、pointercancel が用意されています。ポインターキャプチャ(pointer capture)を使用すると、ポインタが本来の当たり判定エリアの外に出た場合でも、その後のポインターイベントを盤面に向け続けることができます。中断されたジェスチャーによってパズルがドラッグ状態のままスタックしないよう、pointerup と pointercancel の両方でアクティブなドラッグを解除してください。MDN: ポインターイベント
ドラッグ中のピースを再構築または置き換えることでポインタの追跡が失われてしまう事態は避けてください。ドラッグ中にインターフェースがDOM内の要素を移動させる場合、MDNではその移動の後にポインターキャプチャを設定すべきであると記載されています。無効な位置でポインタが離されたときに何が起きるかも決めておきましょう。スライドパズルの場合、無関係なピースを勝手に動かすよりも、ピースを元の位置に戻すか、有効な位置にスナップさせる方がわかりやすい仕様となります。
ドラッグなしでも同じ移動を行えるようにする
パズルは、マウス、キーボード、シンプルなポインタ入力をすべて併用できるようにサポートできます。たとえば、空きスペースに隣接するピースをクリックまたはタップして移動できるようにし、そのピースのドラッグ操作はオプションの直接操作ジェスチャーとして残し、盤面にフォーカスがあるときの矢印キーでキーボード操作を提供する、といった形です。これらの入力はすべて同じ移動検証ロジックを呼び出す必要があるため、どのように要求されたかに関係なく、移動の可否が一貫して判定されます。
これは設計上の有用な確認項目にもなります。「プレイヤーはドラッグ操作を行わず、クリックやタップだけでパズルを完成できるか?」という点です。W3CのWCAG 2.2ガイドラインでは、キーボードアクセスとドラッグに対するシングルポインタの代替手段を別々の懸念事項として扱っています。その例には、ドラッグの代わりに方向コントロールのクリックを利用することが挙げられています。キーボードのみの代替手段は、それ自体ではシングルポインタの代替手段を提供したことにはなりません。W3C: 達成基準 2.5.7: ドラッグ動作を理解する
スライドパズルでは、パズルの「隣接移動」ルールをそのまま維持できるため、隣接するピースを1つずつクリックしていくのが自然な代替手段となるケースが多いです。その操作がわかりにくい場合は、利用可能な方向を視覚的な移動ボタンで示すこともできます。W3Cの達成方法G219には、ドラッグを行わずに同じ基本操作を実行するシングルポインタコントロールの例が記載されています。W3C: G219: コンテンツを操作するドラッグ動作に対して代替手段が利用可能であることを確認する
簡易な入力マトリクスでテストする
セッションでパズルを使用する前に、同じ盤面レイアウトと初期状態を用いて、各入力経路を一通りテストします。有効な移動によって盤面が1回だけ更新されること、無効な移動では盤面が変化しないこと、そして無関係なコントロールが正常な動作を維持していることを確認します。
マウス: 有効なピースをドラッグし、盤面外で離したあと、無効な移動を試みます。盤面がドラッグを見失わず、予期せぬ変化が起きないことを確認します。
キーボード: 盤面にフォーカスを当て、サポートされている各方向を試したあと、フォーカスをテキストフィールドに移して入力します。盤面にフォーカスがあるキーのみがピースを動かすこと、そして文字入力によってスクロールしたり盤面が変わったりしないことを確認します。
ドラッグなしのポインタ: 有効な隣接ピースをクリックまたはタップします。他の入力方法と同じ移動が行われることを確認します。
中断: ドラッグをキャンセルまたは破棄し、その後に別のドラッグを開始します。古い選択状態が残っていないことを確認します。
テストが失敗した場合は、最も直接的に関係する層から順に調査します。キーボードの挙動についてはイベントターゲットとフォーカス状態、中断されたドラッグについてはポインターキャプチャとクリーンアップ処理、ルールの不整合については共通の移動バリデータを点検します。この手順を踏むことで、制作者はアドベンチャー用の小道具を汎用コントロールのチュートリアルに作り直すことなく、問題を具体的に特定できます。
