Fixed bug caused by simultaneous click/touch events

This commit is contained in:
Gene Mecija 2020-01-13 00:03:58 -08:00
parent 20cf1aa3df
commit fa8bda4851
5 changed files with 289 additions and 45 deletions

View file

@ -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 (
<span key={index} className={className} id={"chal"+index}>{letter}</span>
)
})
return (
<>
<ChallengeDisplay buffer={morseCharBuffer} word="Morse" setMorseCharBuffer={setMorseCharBuffer}/>
<div id="challengeWord">{spannedWord}</div>
<ChallengeBufferDisplay buffer={morseCharBuffer.slice(0,-1).replace(/_/g, ' ')} incorrectIndex={incorrectIndex} />
<button onClick={() => console.log(morseCharBuffer)}>morseCharBuffer</button>
</>
);

View file

@ -7,7 +7,7 @@ import MorseDisplay from '../components/MorseDisplay'
function PracticeMode() {
const {morseCharBuffer, morseWords, clearHistory} = useTelegraph('practice')
return (
<>
<MorseBufferDisplay buffer={morseCharBuffer} /><br/>

View file

@ -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) => <DitDahDisplay key={index} dd={ditdah} className={"morseError"}/>))
} else {
console.log('i === incorrectIndex', i, incorrectIndex);
ditDahs.push(letter.split('').map((ditdah,index) => <DitDahDisplay key={index} dd={ditdah} className={""}/>))
}
}
} else {
ditDahs = props.buffer.split('').map((ditdah,index) => <DitDahDisplay key={index} dd={ditdah} />)
console.log('ditDahs:', typeof ditDahs, ditDahs.length, ditDahs);
}
let alphanumeric = ''
// if (props.buffer.includes(' ')) {
let letters = props.buffer.split(' ')
if (props.buffer === '') {}

View file

@ -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() {

View file

@ -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