From fa8bda4851fb848635dcf6c403f7c2b0f1386dc1 Mon Sep 17 00:00:00 2001 From: Gene Mecija Date: Mon, 13 Jan 2020 00:03:58 -0800 Subject: [PATCH] Fixed bug caused by simultaneous click/touch events --- src/app-modes/ChallengeMode.js | 46 +++++- src/app-modes/PracticeMode.js | 2 +- src/components/ChallengeBufferDisplay.js | 25 +++- src/hooks/useTelegraph.js | 88 +++++++----- src/hooks/useTelegraph_baseline.js | 173 +++++++++++++++++++++++ 5 files changed, 289 insertions(+), 45 deletions(-) create mode 100644 src/hooks/useTelegraph_baseline.js diff --git a/src/app-modes/ChallengeMode.js b/src/app-modes/ChallengeMode.js index bbac29b..7490f85 100644 --- a/src/app-modes/ChallengeMode.js +++ b/src/app-modes/ChallengeMode.js @@ -1,17 +1,57 @@ import React from 'react'; import '../css/App.css'; +import morseCode from '../data/morse-reverse.json' import useTelegraph from '../hooks/useTelegraph'; // import ChallengeWord from '../components/ChallengeWord' // import MorseBufferDisplay from '../components/MorseBufferDisplay' -import ChallengeDisplay from '../components/ChallengeDisplay'; +// import ChallengeDisplay from '../components/ChallengeDisplay'; +import ChallengeBufferDisplay from '../components/ChallengeBufferDisplay'; function ChallengeMode() { - const {morseCharBuffer, setMorseCharBuffer} = useTelegraph('challenge') + let word = "morse" + const {morseCharBuffer} = useTelegraph('challenge') + // console.log('morseCharBuffer:', morseCharBuffer, '|END'); + let morseLetters = morseCharBuffer.split('_').filter(l => l !== '') + // console.log('morseLetters:', morseLetters, morseLetters.length); + let challengeLetters = word.split('') + let correctIndexes = [] + let incorrectIndex = null + + morseLetters.forEach((morseLetter, index) => { + let morseAlpha = morseCode[morseLetter] + let challengeLetter = challengeLetters[index].toLowerCase() + + if (morseAlpha === challengeLetter) { + correctIndexes.push(index) + // console.log('MATCH', correctIndexes); + } + else { + if (morseCharBuffer.slice(-1) === "_") { + incorrectIndex = index + // console.log('MISMATCH:', incorrectIndex, 'should be', challengeLetter, 'instead of', morseAlpha, '>', morseLetter); + // props.setMorseCharBuffer(morseLetters.slice(0,-1).join('_') + '_') + } + } + }) + + let spannedWord = challengeLetters.map((letter,index) => { + // console.log('correctIndexes',correctIndexes); + // console.log('index',index); + let className = 'cLetter' + className += (correctIndexes.includes(index)) ? ' correct' : '' + className += (incorrectIndex === index) ? ' morseError' : '' + return ( + {letter} + ) + }) + + return ( <> - +
{spannedWord}
+ ); diff --git a/src/app-modes/PracticeMode.js b/src/app-modes/PracticeMode.js index 843dd10..187581f 100644 --- a/src/app-modes/PracticeMode.js +++ b/src/app-modes/PracticeMode.js @@ -7,7 +7,7 @@ import MorseDisplay from '../components/MorseDisplay' function PracticeMode() { const {morseCharBuffer, morseWords, clearHistory} = useTelegraph('practice') - + return ( <>
diff --git a/src/components/ChallengeBufferDisplay.js b/src/components/ChallengeBufferDisplay.js index f423eee..4c53f75 100644 --- a/src/components/ChallengeBufferDisplay.js +++ b/src/components/ChallengeBufferDisplay.js @@ -3,32 +3,45 @@ import DitDahDisplay from "./DitDahDisplay" import morseCode from '../data/morse-reverse.json' function ChallengeBufferDisplay(props) { - + // INCREMENTING COUNTER TO MONITOR COMPONENT RELOADING + // console.log('ChallengeMode') + if (!document.getElementById('counter')) { + let counter = document.createElement('h1') + let holder = document.createElement('h3') + counter.id = 'counter' + holder.id = 'holder' + counter.innerText = "0" + document.querySelector('#main-content').appendChild(counter) + document.querySelector('#main-content').appendChild(holder) + } else { + let num = document.getElementById('counter').innerText + document.getElementById('counter').innerText = Number(num) + 1 + document.getElementById('holder').innerText = props.buffer + + } + // + let ditDahs = [] let incorrectIndex = props.incorrectIndex let morseLetters = props.buffer.split(' ') if (incorrectIndex) { - console.log('incorrectIndex:', incorrectIndex); + for (let i in morseLetters) { let letter = morseLetters[i] if (Number(i) === incorrectIndex) { ditDahs.push(letter.split('').map((ditdah,index) => )) } else { - console.log('i === incorrectIndex', i, incorrectIndex); ditDahs.push(letter.split('').map((ditdah,index) => )) } } } else { ditDahs = props.buffer.split('').map((ditdah,index) => ) - console.log('ditDahs:', typeof ditDahs, ditDahs.length, ditDahs); } let alphanumeric = '' - // if (props.buffer.includes(' ')) { - let letters = props.buffer.split(' ') if (props.buffer === '') {} diff --git a/src/hooks/useTelegraph.js b/src/hooks/useTelegraph.js index 6483439..36625c5 100644 --- a/src/hooks/useTelegraph.js +++ b/src/hooks/useTelegraph.js @@ -29,36 +29,49 @@ function useTelegraph(mode = 'practice') { let o let frequency = 550.0 + + let isRunning = false function clearHistory() { setMorseWords([]) } function handleInputStart(event) { - event.preventDefault() - if ((event.keyCode !== 32 && event.target.id !== "morseButton") || - (event.repeat)) { - return - } - if (context.state === 'interrupted') { - context.resume() - } - - o = context.createOscillator() - o.frequency.value = frequency - o.type = "sine" - - let g = context.createGain() - g.gain.exponentialRampToValueAtTime(0.08, context.currentTime) - o.connect(g) - g.connect(context.destination) - o.start() - - checkGapBetweenInputs() - clearInterval(gapTimer) - startCharTimer() + if (isRunning) { + console.log("isRunning True:", isRunning); + return + } else { + console.log("isRunning False:", isRunning); + isRunning = true + + // TODO: + // Make sure only one touchdown event registered at a time + if ((event.keyCode !== 32 && event.target.id !== "morseButton") || + (event.repeat)) { + return + } + if (context.state === 'interrupted') { + context.resume() + } + + o = context.createOscillator() + o.frequency.value = frequency + o.type = "sine" + + let g = context.createGain() + g.gain.exponentialRampToValueAtTime(0.08, context.currentTime) + o.connect(g) + g.connect(context.destination) + o.start() + + checkGapBetweenInputs() + clearInterval(gapTimer) + + startCharTimer() + } + } function startCharTimer() { // Reset character time @@ -71,20 +84,25 @@ function useTelegraph(mode = 'practice') { function handleInputEnd(event) { event.preventDefault() - if ((event.keyCode !== 32 && event.target.id !== "morseButton") || - (event.repeat)) { - return - } - if (charTime <= ditMaxTime) { - setMorseCharBuffer(prev => prev + '.') - } else { - setMorseCharBuffer(prev => prev + '-') - } - - stopCharTimer() - startGapTimer() - o.stop() + if (isRunning) { + isRunning = false + if ((event.keyCode !== 32 && event.target.id !== "morseButton") || + (event.repeat)) { + return + } + + if (charTime <= ditMaxTime) { + setMorseCharBuffer(prev => prev + '.') + } else { + setMorseCharBuffer(prev => prev + '-') + } + + stopCharTimer() + startGapTimer() + console.log("o.context.state:", o.context.state); + if (o.context.state === 'running') {o.stop()} + } else { return } } function stopCharTimer() { diff --git a/src/hooks/useTelegraph_baseline.js b/src/hooks/useTelegraph_baseline.js new file mode 100644 index 0000000..6483439 --- /dev/null +++ b/src/hooks/useTelegraph_baseline.js @@ -0,0 +1,173 @@ +import {useState, useEffect} from 'react' + +function useTelegraph(mode = 'practice') { + + const [morseCharBuffer, setMorseCharBuffer] = useState('') // e.g. '-..' + const [morseWords, setMorseWords] = useState([]) // e.g. [['-..','.','-,'], ['...','---','...']] + + let charTimer = 0 + let charTime = 0 + let gapTimer = 0 + let gapTime = 0 + + const timingUnit = 15 // default: 25 + + const ditMaxTime = 5 // default: 3 + const letterGapMinTime = ditMaxTime*3 + const wordGapMaxTime = ditMaxTime*7 + const morseHistorySize = 5 + + // 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 + let frequency = 550.0 + + function clearHistory() { + setMorseWords([]) + } + + function handleInputStart(event) { + + event.preventDefault() + if ((event.keyCode !== 32 && event.target.id !== "morseButton") || + (event.repeat)) { + return + } + if (context.state === 'interrupted') { + context.resume() + } + + o = context.createOscillator() + o.frequency.value = frequency + o.type = "sine" + + let g = context.createGain() + g.gain.exponentialRampToValueAtTime(0.08, context.currentTime) + o.connect(g) + g.connect(context.destination) + o.start() + + checkGapBetweenInputs() + clearInterval(gapTimer) + + startCharTimer() + } + function startCharTimer() { + // Reset character time + charTime = 0 + // Start Character Timer + charTimer = setInterval(() => { + charTime += 1 + }, timingUnit); + } + + function handleInputEnd(event) { + event.preventDefault() + if ((event.keyCode !== 32 && event.target.id !== "morseButton") || + (event.repeat)) { + return + } + + if (charTime <= ditMaxTime) { + setMorseCharBuffer(prev => prev + '.') + } else { + setMorseCharBuffer(prev => prev + '-') + } + + stopCharTimer() + startGapTimer() + o.stop() + } + + function stopCharTimer() { + clearInterval(charTimer) + charTimer = 0 + } + + function startGapTimer() { + gapTime = 0 + gapTimer = setInterval(() => { + gapTime += 1 + + // Gap between words + if (mode === 'practice' && gapTime >= wordGapMaxTime) { + setMorseCharBuffer(prev => prev + '/') + clearInterval(gapTimer) + gapTimer = 0 + gapTime = 0 + } + if (mode === '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 (mode === 'practice') { + setMorseCharBuffer(prev => prev + ' ') + } else if (mode === 'challenge') { + setMorseCharBuffer(prev => prev + '_') + } + clearInterval(gapTimer) + gapTimer = 0 + } + } + + useEffect(() => { + document.addEventListener('keydown', handleInputStart) + document.addEventListener('keyup', handleInputEnd) + + const morseButton = document.getElementById('morseButton') + morseButton.addEventListener('mousedown', handleInputStart) + morseButton.addEventListener('touchstart', handleInputStart) + morseButton.addEventListener('mouseup', handleInputEnd) + morseButton.addEventListener('touchend', handleInputEnd) + + return function cleanup() { + document.removeEventListener('keydown', handleInputStart) + document.removeEventListener('keyup', handleInputEnd) + clearHistory() + } + // eslint-disable-next-line + }, []) + + useEffect(() => { + // PRACTICE MODE + if (morseCharBuffer.slice(-1) === '/' && mode === '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('') + } + console.log('morseCharBuffer:', morseCharBuffer, '|'); + // CHALLENGE MODE: leave forward slash there; to be parsed by ChallengeDisplay.js + // else if (morseCharBuffer.slice(-1) === '/' && mode === 'challenge') { + + // } + + // eslint-disable-next-line + }, [morseCharBuffer]) + + return {morseCharBuffer, morseWords, clearHistory, setMorseCharBuffer, setMorseWords} +} + +export default useTelegraph \ No newline at end of file