質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

1回答

936閲覧

ショートカットキーを覚えてもらうタイピングゲームをJavaScriptで作成したい

jdshngy2

総合スコア1

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2023/05/06 01:49

編集2023/05/06 06:18

実現したいこと

  • ショートカットキーを覚えてもらうタイピングゲームをJavaScriptで作成する

前提

勉強も兼ね、また職場でみんなにショートカットキーを覚えてもらおうと
簡単なゲームを作成したかったのですが、特定のショートカットキーを押すと
ショートカットキー本来の機能が反応してしまい、ゲームが成立しない状態に
なってしまっています。

発生している問題・エラーメッセージ

例えばF1キーなどを押したり、Ctrl+Wなどを押すと画面が切り替わってしまったり、 F11などでも音量が変わる(MACを使用しています)など、キー入力して場所を覚えて もらいたいのですが、ゲームが進行できなくなっています。

該当のソースコード

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Shortcut Typing Game</title> <style> #game-canvas { border: 1px solid #000; } #score-label, #time-label { display: inline-block; width: 70px; text-align: right; } #score, #time-left, #time-limit { display: inline-block; width: 50px; text-align: left; } #game-canvas { background-color: black; } </style> </head> <body> <canvas id="game-canvas" width="800" height="400"></canvas> <div> <span id="score-label">Score:</span> <span id="score">0</span> <span id="time-label">Time Left:</span> <span id="time-left">10</span> <span>/</span> <span id="time-limit">10</span> </div> <button id="start-btn">Start</button> <button id="stop-btn">Stop</button> <button id="restart-btn">Restart</button> <button id="reset-btn">Reset</button> <script> // ゲーム画面のcanvas要素を取得する let canvas = document.getElementById('game-canvas'); let ctx = canvas.getContext('2d'); // ゲーム画面の背景色を指定する ctx.fillStyle = '#000'; ctx.fillRect(0, 0, canvas.width, canvas.height); // ショートカットリスト const shortcuts = [ { keyName: 'Ctrl+C', keyCode: 67, description: 'コピー' }, { keyName: 'Ctrl+X', keyCode: 88, description: '切り取り' }, { keyName: 'Ctrl+V', keyCode: 86, description: '貼り付け' }, { keyName: 'Ctrl+A', keyCode: 65, description: '全て選択' }, { keyName: 'Ctrl+Z', keyCode: 90, description: '元に戻す' }, { keyName: 'Ctrl+Y', keyCode: 89, description: 'やり直し' }, { keyName: 'Ctrl+F', keyCode: 70, description: '検索' }, { keyName: 'Ctrl+S', keyCode: 83, description: '保存' }, { keyName: 'Ctrl+N', keyCode: 78, description: '新規作成' }, { keyName: 'Ctrl+O', keyCode: 79, description: 'ファイルを開く' }, { keyName: 'Ctrl+P', keyCode: 80, description: '印刷' }, { keyName: 'Ctrl+Alt+Delete', keyCode: 46, description: 'タスクマネージャーを開く' }, { keyName: 'Ctrl+Tab', keyCode: 9, description: '次のタブに切り替える' }, { keyName: 'Ctrl+Shift+Tab', keyCode: 9, description: '前のタブに切り替える' }, { keyName: 'Ctrl+T', keyCode: 84, description: '新しいタブを開く' }, { keyName: 'Ctrl+W', keyCode: 87, description: '現在のタブを閉じる' }, { keyName: 'Ctrl+Shift+T', keyCode: 84, description: '最後に閉じたタブを復元する' }, { keyName: 'Ctrl+Shift+N', keyCode: 78, description: 'シークレットモードで新しいウィンドウを開く' }, { keyName: 'Alt+Tab', keyCode: 9, description: '別のアプリケーションに切り替える' }, { keyName: 'Alt+F4', keyCode: 115, description: 'アプリケーションを閉じる' }, { keyName: 'F1', keyCode: 112, description: 'ヘルプを表示する' }, { keyName: 'F2', keyCode: 113, description: 'ファイル名を変更する' }, { keyName: 'F5', keyCode: 116, description: 'リフレッシュ、再読み込み' }, { keyName: 'F11', keyCode: 122, description: 'フルスクリーン表示に切り替える' } ]; // 現在のショートカットを格納する変数 let currentShortcut = ''; // 得点を格納する変数 let score = 0; // 制限時間を格納する変数 let timeLimit = 10; // カウントダウンを行うinterval IDを格納する変数 let countdownInterval; // ゲーム中かどうかを示すフラグ let isPlaying = false; // ショートカットを表示する関数 function showShortcut() { // ショートカットリストからランダムにショートカットを選択する let index = Math.floor(Math.random() * shortcuts.length); currentShortcut = shortcuts[index]; // canvasに現在のショートカットを描画する ctx.clearRect(0,0,canvas.width,canvas.height);//まず消す ctx.fillStyle = '#f00'; ctx.fillRect(150, 150, 300, 100); ctx.font = '24px Arial'; ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.fillText(currentShortcut.keyName, 300, 200); ctx.fillText(currentShortcut.description, 300, 240); } // キー入力を受け取る関数 function handleKeyPress(event) { // ゲーム中でない場合は何もしない if (!isPlaying) { return; } // ここから追加 event.preventDefault(); // ここまで追加 if (event.keyCode === currentShortcut.keyCode) { // 得点を加算する score += 10; // スコアを更新する document.getElementById('score').textContent = score; // 次のショートカットを表示する showShortcut(); } } // ゲームを開始する関数 function startGame() { score = 0; // スタートボタンを無効化する document.getElementById('start-btn').disabled = true; // 制限時間を表示する document.getElementById('time-limit').textContent = timeLimit; timeLimit = 10; // 得点を表示する document.getElementById('score').textContent = score; // ゲーム中フラグを立てる isPlaying = true; // カウントダウンを開始する countdownInterval = setInterval(() => { timeLimit--; document.getElementById('time-limit').textContent = timeLimit; // 制限時間が0になった場合はゲームを終了する if (timeLimit === 0) { endGame(); } }, 1000); //最初のショートカットを表示する showShortcut(); // キー入力を受け取るようにする document.addEventListener('keydown', handleKeyPress); } // ゲームを終了する関数 function endGame() { // カウントダウンを停止する clearInterval(countdownInterval); // ゲーム中フラグを下ろす isPlaying = false; // canvasをクリアする ctx.clearRect(0, 0, canvas.width, canvas.height); // canvasに得点を描画する ctx.font = '48px Arial'; ctx.fillStyle = '#f00'; ctx.textAlign = 'center'; ctx.fillText(`Score: ${score}`, 300, 200); // スタートボタンを有効化する document.getElementById('start-btn').disabled = false; } // ストップボタンをクリックした時の処理 function stopGame() { // ゲーム中でなければ何もしない if (!isPlaying) { return; } // スタートボタンを有効化する document.getElementById('start-btn').disabled = false; // キー入力を受け取るイベントリスナーを削除する document.removeEventListener('keydown', handleKeyPress); // カウントダウンを停止する clearInterval(countdownInterval); // ゲーム中フラグを下ろす isPlaying = false; } // リスタートボタンをクリックした時の処理 function restartGame() { stopGame(); // スタートボタンを有効化する document.getElementById('start-btn').disabled = false; score = 0; document.getElementById('score').textContent = score; timeLimit = 10; document.getElementById('time-limit').textContent = timeLimit; } // リセットボタンをクリックした時の処理 function resetGame() { restartGame(); showShortcut(); } // 各ボタンにイベントリスナーを登録する document.getElementById('start-btn').addEventListener('click', startGame); document.getElementById('stop-btn').addEventListener('click', stopGame); document.getElementById('restart-btn').addEventListener('click', restartGame); document.getElementById('reset-btn').addEventListener('click', resetGame); document.addEventListener('keydown', function(event) { event.preventDefault(); }); </script> </body> </html>

試したこと

event.preventDefault(); で制限をかけることができるのではと思い
追加してみましたが、どうも限界があるようです。

補足情報(FW/ツールのバージョンなど)

JavaScriptでは限界があるようなら一旦諦めて、別の機会に作るか、
選択クイズ(正しいキーはどれでしょう:4択)のようなクイズゲームに
切り替えも検討していますが、もしショートカットキーのキー入力が行われたかどうかを
ゲーム内だけで反映させ、実際の動作はしないようにする方法があればご教示いただきたいです。
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

logres_Fan

2023/05/06 06:59

チートシートを印刷して置いておくのはどうですか?how-to本を買ってきて職場で読んでもらうとか。
Zuishin

2023/05/06 07:43

キーフックできるかどうかはブラウザ依存じゃないですかね。 ローカルアプリならできます。
think49

2023/05/08 13:02

> 特定のショートカットキーを押すとショートカットキー本来の機能が反応してしまい、ゲームが成立しない状態になってしまっています。 回答のコードでは問題なく、ショートカットキーが無効化されています。 解決しない理由を回答にコメントしてください。 https://teratail.com/questions/6na8t3vimxgva2#reply-muhkvpgjy6wks2
guest

回答1

0

ロジック

入力キー検出のロジックがおかしいので、イベントの動きを見直してください。

[Ctrl] + [C] キーを例にとると、[Ctrl] キーと [C] キーは同時に keydown されるわけではありません
第一のキーが keydown されて keyup するまでの間に第二のキーが keydown される挙動を「UI Events」の範疇で実装する必要があります。

コード

HTML

1<script> 2 'use strcit'; 3 { 4 const listener = { 5 preventKeys: [['Control', 'c'], ['Control', 'v']], 6 keys: new Set, 7 handleEvent: function handleKey (event) { 8 const keys = this.keys; 9 switch (event.type) { 10 case 'keydown': 11 keys.add(event.key); 12 break; 13 case 'keyup': 14 keys.delete(event.key); 15 break; 16 } 17 18 console.log(Array.from(keys).sort()); 19 for (let preventKey of this.preventKeys) { 20 if (preventKey.every(pKey => keys.has(pKey))) { 21 event.preventDefault(); 22 break; 23 } 24 } 25 } 26 }; 27 document.addEventListener('keydown', listener, false); 28 document.addEventListener('keyup', listener, false); 29 } 30</script> 31 32<textarea>This is a test.</textarea>

Re: jdshngy2 さん

投稿2023/05/06 15:34

think49

総合スコア18164

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問