mirror of
https://github.com/genemecija/learn-morse-code.git
synced 2025-12-06 07:02:00 +01:00
Fixed bug caused by simultaneous click/touch events
This commit is contained in:
parent
20cf1aa3df
commit
fa8bda4851
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import MorseDisplay from '../components/MorseDisplay'
|
|||
function PracticeMode() {
|
||||
|
||||
const {morseCharBuffer, morseWords, clearHistory} = useTelegraph('practice')
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<MorseBufferDisplay buffer={morseCharBuffer} /><br/>
|
||||
|
|
|
|||
|
|
@ -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 === '') {}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
173
src/hooks/useTelegraph_baseline.js
Normal file
173
src/hooks/useTelegraph_baseline.js
Normal 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
|
||||
Loading…
Reference in a new issue