From f6384b30ef4d254c56e1b12917852a5c63dcd61d Mon Sep 17 00:00:00 2001 From: Gene Mecija Date: Mon, 27 Jan 2020 03:21:41 -0800 Subject: [PATCH] Resolved WPM change/telegraph timing bug --- src/App.js | 49 ++++--- src/app-modes/PracticeMode.js | 16 +-- src/components/ElectronicKey.js | 10 +- src/components/KeyTypePicker.js | 2 +- src/components/StraightKey.js | 12 +- src/components/WordsPerMinute.js | 2 +- src/contexts/wpmContext.js | 6 +- src/hooks/useElectronicKey.js | 16 ++- src/hooks/useMorsePlayer copy.js | 75 ++++++++-- src/hooks/useStraightKey.js | 20 +-- src/hooks/useTelegraphKey.js | 229 ------------------------------- 11 files changed, 120 insertions(+), 317 deletions(-) delete mode 100644 src/hooks/useTelegraphKey.js diff --git a/src/App.js b/src/App.js index c22859d..27dbfe7 100644 --- a/src/App.js +++ b/src/App.js @@ -20,23 +20,19 @@ import Legend from './components/Legend'; // import GameClock from "./components/GameClock" import WordsPerMinute from "./components/WordsPerMinute" import MorseButtons from './components/MorseButtons' -import MorseBufferDisplay from './components/MorseBufferDisplay' -import MorseHistory from './components/MorseHistory' - -import StraightKey from './components/StraightKey'; -import ElectronicKey from './components/ElectronicKey'; import Footer from './components/Footer'; import { WPMContext } from './contexts/wpmContext'; +import StraightKey from './components/StraightKey'; +import ElectronicKey from './components/ElectronicKey'; export default React.memo(function App() { console.log('App.js rendered') - const {gameMode} = useContext(GameModeContext) - const {wpm} = useContext(WPMContext) - + const {keyType} = useContext(KeyTypeContext) - console.log('gameMode', gameMode); - console.log('keyType', keyType); + const {gameMode} = useContext(GameModeContext) + const wpm = useContext(WPMContext) + return ( <> @@ -45,17 +41,18 @@ export default React.memo(function App() { + - {gameMode === 'practice' && - <> - {/* {keyType === "straight" ? - : } */} -
- {/*
-
*/} - + + {keyType === "straight" ? + : } + + {gameMode === 'practice' && + + } + {/* {gameMode === 'timed' && <> {keyType === "straight" ? @@ -64,19 +61,19 @@ export default React.memo(function App() {

- } + } */} + {gameMode === 'challenge' && <> - - - {keyType === "straight" ? - : } - - + + + + - } */} + } +
diff --git a/src/app-modes/PracticeMode.js b/src/app-modes/PracticeMode.js index 1cda927..ca7b645 100644 --- a/src/app-modes/PracticeMode.js +++ b/src/app-modes/PracticeMode.js @@ -1,25 +1,13 @@ -import React, {useContext} from 'react'; +import React from 'react'; import '../css/App.css'; -import {KeyTypeContext} from "../contexts/keyTypeContext" -import StraightKey from '../components/StraightKey' -import ElectronicKey from '../components/ElectronicKey' import MorseBufferDisplay from '../components/MorseBufferDisplay' import MorseHistory from '../components/MorseHistory' -import { WPMContext } from '../contexts/wpmContext'; -import { GameModeContext } from '../contexts/gameModeContext'; -import useStraightKey from '../hooks/useStraightKey'; -export default React.memo(function PracticeMode() { - - const {keyType} = useContext(KeyTypeContext) - const {gameMode} = useContext(GameModeContext) - const {wpm} = useContext(WPMContext) - +export default (function PracticeMode(props) { return ( <> - {keyType === "straight" ? : }

diff --git a/src/components/ElectronicKey.js b/src/components/ElectronicKey.js index bd23ee7..ebf5b58 100644 --- a/src/components/ElectronicKey.js +++ b/src/components/ElectronicKey.js @@ -1,9 +1,7 @@ -import React, { useContext } from 'react' +import React from 'react' import useElectronicKey from '../hooks/useElectronicKey'; -function ElectronicKey(props) { +export default React.memo(function ElectronicKey(props) { - return useElectronicKey(props.gameMode, props.wpm) -} - -export default ElectronicKey \ No newline at end of file + useElectronicKey() +}) \ No newline at end of file diff --git a/src/components/KeyTypePicker.js b/src/components/KeyTypePicker.js index f5cddc9..6f3f452 100644 --- a/src/components/KeyTypePicker.js +++ b/src/components/KeyTypePicker.js @@ -7,10 +7,10 @@ export default React.memo(function KeyTypePicker() { function handleClick(e) { setKeyType(e.target.id) + console.log("KEYTYPE PICKED:", e.target.id); let buttons = document.querySelector(".mode-picker#keyType").childNodes buttons.forEach(button => { - console.log('buttonID', button.id); if (button.id === e.target.id) { button.classList.add('selected') } else { button.classList.remove('selected')} diff --git a/src/components/StraightKey.js b/src/components/StraightKey.js index 870ae3f..57195ea 100644 --- a/src/components/StraightKey.js +++ b/src/components/StraightKey.js @@ -1,13 +1,7 @@ -import React, { useContext } from 'react' +import React from 'react' import useStraightKey from '../hooks/useStraightKey'; -import { GameModeContext } from '../contexts/gameModeContext'; -import { WPMContext } from '../contexts/wpmContext'; export default React.memo(function StraightKey(props) { - console.log('props.gameMode',props.gameMode); - - // const {gameMode} = useContext(GameModeContext) - // const {wpm} = useContext(WPMContext) - - useStraightKey(props.gameMode, props.wpm) + + useStraightKey() }) \ No newline at end of file diff --git a/src/components/WordsPerMinute.js b/src/components/WordsPerMinute.js index 37a394a..57c93d1 100644 --- a/src/components/WordsPerMinute.js +++ b/src/components/WordsPerMinute.js @@ -7,7 +7,7 @@ export default React.memo(function WordsPerMinute(props) { const {wpm, setWPM} = useContext(WPMContext) function handleChange(e) { - setWPM(e.target.value) + setWPM(Number(e.target.value)) } return ( diff --git a/src/contexts/wpmContext.js b/src/contexts/wpmContext.js index 536b727..81ecbb2 100644 --- a/src/contexts/wpmContext.js +++ b/src/contexts/wpmContext.js @@ -1,11 +1,15 @@ import React, {useState} from "react" + const WPMContext = React.createContext() function WPMContextProvider(props) { + const [wpm, setWPM] = useState(15) return ( - + {props.children} ) diff --git a/src/hooks/useElectronicKey.js b/src/hooks/useElectronicKey.js index b91b24b..b6a393c 100644 --- a/src/hooks/useElectronicKey.js +++ b/src/hooks/useElectronicKey.js @@ -2,23 +2,26 @@ import {useEffect, useContext} from 'react' import {MorseBufferContext} from '../contexts/morseBufferContext' import config from '../config.json' import { WPMContext } from '../contexts/wpmContext' +import { GameModeContext } from '../contexts/gameModeContext' // ELECTRONIC KEY TELEGRAPH - Iambic A -function useElectronicKey(gameMode, wpm) { +function useElectronicKey() { const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext) - // const {wpm} = useContext(WPMContext) - // console.log('useStraightKey-WPM:', wpm); + const {wpm} = useContext(WPMContext) + const {gameMode} = useContext(GameModeContext) + + let ditMaxTime = 1200/wpm + const timingUnit = config.timingUnit let ratio = .2 - const ditMaxTime = 1200/wpm // ditMaxTime * 0.365 to get ms, e.g. 85 * 0.365 ~= 31ms - const letterGapMinTime = ditMaxTime*ratio*3 //config.practiceSpeed.normal*3 const wordGapMaxTime = ditMaxTime*ratio*7 // config.practiceSpeed.normal*7 const morseHistorySize = config.historySize + let leftIsPressed = false let rightIsPressed = false @@ -230,7 +233,6 @@ function useElectronicKey(gameMode, wpm) { } } - const bufferDisplay = ['morseBufferDisplay', 'challengeBufferDisplay', 'ditDahs', 'alphanumeric-container'] function handleInputStart(event) { event.preventDefault() @@ -348,7 +350,7 @@ function useElectronicKey(gameMode, wpm) { clearHistory() } // eslint-disable-next-line - }, []) + }, [wpm]) useEffect(() => { // PRACTICE MODE diff --git a/src/hooks/useMorsePlayer copy.js b/src/hooks/useMorsePlayer copy.js index b43e350..7cb4276 100644 --- a/src/hooks/useMorsePlayer copy.js +++ b/src/hooks/useMorsePlayer copy.js @@ -1,8 +1,12 @@ import config from '../config.json' +import { WPMContext } from '../contexts/wpmContext.js'; +import { useContext } from 'react'; -function useMorsePlayer() { +function useMorsePlayerCopy() { - const ditMaxTime = 85 //config.ditMaxTime + const {wpm} = useContext(WPMContext) + // const ditMaxTime = 85 //config.ditMaxTime + const ditMaxTime = 1200/wpm // Tone Setup let AudioContext = window.AudioContext || window.webkitAudioContext @@ -20,7 +24,7 @@ function useMorsePlayer() { let length = ((ditDah === '.') ? ditMaxTime : ditMaxTime*3) // length = 1 - return new Promise((resolve, reject) => { + // return new Promise((resolve, reject) => { if (context.state === 'interrupted') { context.resume() } @@ -28,12 +32,12 @@ function useMorsePlayer() { o = context.createOscillator() o.frequency.value = frequency o.type = "sine" - o.onended = () => { - resolve() - } + // o.onended = () => { + // resolve() + // } let startTime = context.currentTime; - + let g = context.createGain() g.gain.exponentialRampToValueAtTime(config.mainVolume, startTime) g.gain.setValueAtTime(config.mainVolume, startTime) @@ -47,17 +51,60 @@ function useMorsePlayer() { g.gain.setTargetAtTime(0.0001, context.currentTime, 0.009) o.stop(context.currentTime + 0.05) }, length) - }) + // }) } function playMorseWord(morse) { let chars = Array.from(morse) - let currentPromise = Promise.resolve(); + // let currentPromise = Promise.resolve(); + let soundQueue = [] + + let delay = 0 + let firstWord = true for (let i = 0; i < chars.length; i++) { - currentPromise = currentPromise.then(() => { - return playChar(chars[i]); - }); + // currentPromise = currentPromise.then(() => { + // return playChar(chars[i]); + // }); + let char = chars[i] + if (char === '.') { + if (firstWord) { + firstWord = false + // soundQueue.push( + setTimeout(() => { + play(char) + }, 0) + // ) + } else { + // soundQueue.push( + setTimeout(() => { + play(char) + }, delay) + // ) + } + delay += ditMaxTime*2 + } else if (char === '-') { + if (firstWord) { + firstWord = false + // soundQueue.push( + setTimeout(() => { + play(char) + }, 0) + // ) + } else { + // soundQueue.push( + setTimeout(() => { + play(char) + }, delay) + // ) + } + delay += ditMaxTime*4 + } else if (char === ' ') { + setTimeout(() => { + + }, delay) + delay += ditMaxTime*3 + } } function playChar(char) { @@ -78,7 +125,7 @@ function useMorsePlayer() { } } - return { playMorseWord } + return { play } } -export default useMorsePlayer \ No newline at end of file +export default useMorsePlayerCopy \ No newline at end of file diff --git a/src/hooks/useStraightKey.js b/src/hooks/useStraightKey.js index dce0bdd..bfba50c 100644 --- a/src/hooks/useStraightKey.js +++ b/src/hooks/useStraightKey.js @@ -1,14 +1,15 @@ import {useEffect, useContext} from 'react' import {MorseBufferContext} from '../contexts/morseBufferContext' import config from '../config.json' -// import { WPMContext } from '../contexts/wpmContext' +import { WPMContext } from '../contexts/wpmContext' +import { GameModeContext } from '../contexts/gameModeContext' // STRAIGHT KEY TELEGRAPH -function useStraightKey(gameMode, wpm) { +function useStraightKey() { const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext) - // const {wpm} = useContext(WPMContext) - // console.log('useStraightKey-WPM:', wpm); + const {wpm} = useContext(WPMContext) + const {gameMode} = useContext(GameModeContext) let charTimer = 0 let charTime = 0 @@ -17,7 +18,8 @@ function useStraightKey(gameMode, wpm) { const timingUnit = config.timingUnit - const ditMaxTime = 1200/wpm + const ditMaxTime = 1200/wpm * 0.3 + const letterGapMinTime = ditMaxTime*3 const wordGapMaxTime = ditMaxTime*7 const morseHistorySize = config.historySize @@ -43,11 +45,11 @@ function useStraightKey(gameMode, wpm) { setMorseWords([]) } - const bufferDisplay = ['morseBufferDisplay', 'challengeBufferDisplay', 'ditDahs', 'alphanumeric-container'] - function handleInputStart(event) { event.preventDefault() - console.log('INPUTSTART'); + console.log('ditMaxTime',ditMaxTime); + console.log('letterGapMinTime',letterGapMinTime); + console.log('wordGapMaxTime',wordGapMaxTime); // console.log('event.type', event.type); // if (event.type === 'mousedown' && event.target.className !== 'paddle') { // if (event.target.id === 'wpm-input') { @@ -230,7 +232,7 @@ function useStraightKey(gameMode, wpm) { clearHistory() } // eslint-disable-next-line - }, []) + }, [wpm]) useEffect(() => { // PRACTICE MODE diff --git a/src/hooks/useTelegraphKey.js b/src/hooks/useTelegraphKey.js deleted file mode 100644 index a65092e..0000000 --- a/src/hooks/useTelegraphKey.js +++ /dev/null @@ -1,229 +0,0 @@ -import {useEffect, useContext} from 'react' -import {MorseBufferContext} from '../contexts/morseBufferContext' -import config from '../config.json' -import { WPMContext } from '../contexts/wpmContext' -import { KeyTypeContext } from '../contexts/keyTypeContext' - - -// STRAIGHT KEY TELEGRAPH -function useTelegraphKey(gameMode, wpm) { - - const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext) - // const {wpm} = useContext(WPMContext) - // console.log('useStraightKey-WPM:', wpm); - - // Straight Key Variables - let charTimer = 0 - let charTime = 0 - - // Electronic Key Variables - let ratio = .2 - let depressSyncTime - let depressSyncTimer - let depressSyncTimerRunning = false - let paddlesReleasedSimultaneously = false - - // Straight && Electronic Key Variables - let gapTimer = 0 - let gapTime = 0 - const timingUnit = config.timingUnit - const ditMaxTime = 1200/wpm - const letterGapMinTime = ditMaxTime*3 - const wordGapMaxTime = ditMaxTime*7 - const morseHistorySize = config.historySize - - // Tone Setup - let AudioContext = window.AudioContext || window.webkitAudioContext || false - let context - window.AudioContext = window.AudioContext || window.webkitAudioContext; - if (AudioContext) { - context = new AudioContext() - } else { - context = null - } - - let o // Oscillator Node - let g // Gain Node - let frequency = config.frequency - - let isRunning = false - - function clearHistory() { - setMorseWords([]) - } - - function handleInputStart(event) { - event.preventDefault() - - if (isRunning) { - return - } else { - if ((event.keyCode !== 32 && - event.target.id !== "morseButton" && - event.target.className !== "paddle") || - (event.repeat)) { - return - } - - isRunning = true - - if (context.state === 'interrupted') { - context.resume() - } - - o = context.createOscillator() - o.frequency.value = frequency - o.type = "sine" - - g = context.createGain() - g.gain.exponentialRampToValueAtTime(config.mainVolume, context.currentTime) - o.connect(g) - g.connect(context.destination) - o.start() - - checkGapBetweenInputs() - clearInterval(gapTimer) - - startCharTimer() - } - - } - - function startCharTimer() { - // Start Character Timer - charTimer = setInterval(() => { - charTime += 1 - }, timingUnit); - } - - function handleInputEnd(event) { - event.preventDefault() - - // if (event.target.id !== 'morseBufferDisplay') { - // insideBufferDisplay = true - // console.log('insideBufferDisplay', insideBufferDisplay); - // } - // if (!insideBufferDisplay) {return} - - if (isRunning) { - if ((event.keyCode !== 32 && - event.target.id !== "morseButton" && - event.target.className !== "paddle") || - (event.repeat)) { - return - } - isRunning = false - - - // console.log('charTime:', charTime); - if (charTime <= ditMaxTime) { - setMorseCharBuffer(prev => prev + '.') - } else { - setMorseCharBuffer(prev => prev + '-') - } - - stopCharTimer() - startGapTimer() - - if (o.context.state === 'running') { - g.gain.setTargetAtTime(0.0001, context.currentTime, 0.001) - o.stop(context.currentTime + 0.05) - } - } else { return } - } - - function stopCharTimer() { - clearInterval(charTimer) - charTimer = 0 - charTime = 0 - } - - function startGapTimer() { - gapTime = 0 - gapTimer = setInterval(() => { - gapTime += 1 - - // Gap between words - if (gameMode === 'practice' && gapTime >= wordGapMaxTime) { - setMorseCharBuffer(prev => prev + '/') - clearInterval(gapTimer) - gapTimer = 0 - gapTime = 0 - } - else if (gameMode === 'challenge' && gapTime >= letterGapMinTime) { - setMorseCharBuffer(prev => prev + '_') - clearInterval(gapTimer) - gapTimer = 0 - gapTime = 0 - } - }, timingUnit); - } - - function checkGapBetweenInputs() { - // Check Gap between letters - if (gapTime >= letterGapMinTime && gapTime < wordGapMaxTime) { - if (gameMode === 'practice') { - setMorseCharBuffer(prev => prev + ' ') - } else if (gameMode === 'challenge') { - setMorseCharBuffer(prev => prev + '_') - } - clearInterval(gapTimer) - gapTimer = 0 - } - } - - - useEffect(() => { - document.addEventListener('keydown', handleInputStart) - document.addEventListener('keyup', handleInputEnd) - - const paddles = document.querySelectorAll('.paddle') - paddles.forEach(paddle => { - paddle.addEventListener('mousedown', handleInputStart) - paddle.addEventListener('touchstart', handleInputStart) - paddle.addEventListener('mouseout', handleInputEnd) - paddle.addEventListener('mouseup', handleInputEnd) - paddle.addEventListener('touchend', handleInputEnd) - }) - - return function cleanup() { - document.removeEventListener('keydown', handleInputStart) - document.removeEventListener('keyup', handleInputEnd) - - const paddles = document.querySelectorAll('.paddle') - paddles.forEach(paddle => { - paddle.removeEventListener('mousedown', handleInputStart) - paddle.removeEventListener('touchstart', handleInputStart) - paddle.removeEventListener('mouseout', handleInputEnd) - paddle.removeEventListener('mouseup', handleInputEnd) - paddle.removeEventListener('touchend', handleInputEnd) - }) - clearHistory() - } - // eslint-disable-next-line - }, []) - - useEffect(() => { - // PRACTICE MODE - if (morseCharBuffer.slice(-1) === '/' && gameMode === 'practice') { - // Remove forward slash - let val = morseCharBuffer.slice(0,morseCharBuffer.length-1) - - setMorseWords(prev => [val, ...prev]) - - if (morseWords.length >= morseHistorySize) { - setMorseWords(prev => prev.slice(0,prev.length-1)) - } - setMorseCharBuffer('') - } - // CHALLENGE MODE: leave forward slash there; to be parsed by ChallengeDisplay.js - // else if (morseCharBuffer.slice(-1) === '/' && mode === 'challenge') { - - // } - - // eslint-disable-next-line - }, [morseCharBuffer]) - -} - -export default useTelegraphKey \ No newline at end of file