Electronic key functionality progress, context separation

This commit is contained in:
Gene Mecija 2020-01-16 01:18:40 -08:00
parent dd5b0ec4a0
commit 92b5286165
19 changed files with 848 additions and 204 deletions

View file

@ -1,12 +1,19 @@
import React, {useContext, useEffect} from 'react';
import React, {useContext} from 'react';
import './css/App.css';
import MorseButton from './components/MorseButton'
import ModePicker from './components/ModePicker'
import KeyTypePicker from './components/KeyTypePicker'
// import MorseDisplay from './components/MorseDisplay'
// import MorseBufferDisplay from './components/MorseBufferDisplay'
// import GameClock from "./components/GameClock"
// import ChallengeWord from "./components/ChallengeWord"
import {GameModeContext} from "./gameContext"
import {GameModeContext} from "./contexts/gameContext"
import {KeyTypeContext} from "./contexts/keyTypeContext"
import {MorseBufferContextProvider} from "./contexts/morseBufferContext"
import StraightKey from './components/StraightKey'
import ElectronicKey from './components/ElectronicKey'
import PracticeMode from './app-modes/PracticeMode';
import TimedMode from './app-modes/TimedMode'
import ChallengeMode from './app-modes/ChallengeMode'
@ -16,15 +23,23 @@ function App() {
console.log('App.js rendered')
const {gameMode} = useContext(GameModeContext)
const {keyType} = useContext(KeyTypeContext)
return (
<div id='main-content'>
<Legend />
<ModePicker />
<KeyTypePicker />
<MorseBufferContextProvider>
{keyType === "straight" && <StraightKey />}
{keyType === "electronic" && <ElectronicKey />}
{gameMode === 'practice' && <PracticeMode />}
{gameMode === 'timed' && <TimedMode />}
{gameMode === 'challenge' && <ChallengeMode />}
{gameMode === 'practice' && <PracticeMode />}
{gameMode === 'timed' && <TimedMode />}
{gameMode === 'challenge' && <ChallengeMode />}
</MorseBufferContextProvider>
<MorseButton />
</div>

View file

@ -1,7 +1,7 @@
import React from 'react';
import '../css/App.css';
import morseCode from '../data/morse-reverse.json'
import useTelegraph from '../hooks/useTelegraph';
import useStraightKey from '../hooks/useStraightKey';
// import ChallengeWord from '../components/ChallengeWord'
// import MorseBufferDisplay from '../components/MorseBufferDisplay'
// import ChallengeDisplay from '../components/ChallengeDisplay';
@ -11,7 +11,7 @@ function ChallengeMode() { console.log("ChallengeMode loaded");
let word = "morse"
const {morseCharBuffer} = useTelegraph('challenge')
const {morseCharBuffer} = useStraightKey('challenge')
// console.log('morseCharBuffer:', morseCharBuffer, '|END');
let morseLetters = morseCharBuffer.split('_').filter(l => l !== '')
// console.log('morseLetters:', morseLetters, morseLetters.length);

View file

@ -1,23 +1,28 @@
import React from 'react';
import React, {useContext} from 'react';
import '../css/App.css';
// import useTelegraph from '../hooks/useTelegraph';
import usePaddleTelegraph from '../hooks/usePaddleTelegraph';
import useStraightKey from '../hooks/useStraightKey';
import useElectronicKey from '../hooks/useElectronicKey';
import MorseBufferDisplay from '../components/MorseBufferDisplay'
import MorseDisplay from '../components/MorseDisplay'
import {MorseBufferContext} from "../contexts/morseBufferContext"
function PracticeMode() {
console.log("PracticeMode loaded");
// const {morseCharBuffer, morseWords, clearHistory} = useTelegraph('practice')
usePaddleTelegraph()
// const [telegraphType, setTelegraphType] = useState('electronic')
// useElectronicKey()
// const {morseCharBuffer, morseWords, clearHistory} = useStraightKey('practice')
const {morseCharBuffer, morseWords} = useContext(MorseBufferContext)
return (
<>
{/* <MorseBufferDisplay buffer={morseCharBuffer} /><br/>
<MorseDisplay morseWords={morseWords} /><br/> */}
<button onClick={console.log('hi')}>Clear Morse History</button><br/>
<MorseBufferDisplay buffer={morseCharBuffer} /><br/>
<MorseDisplay morseWords={morseWords} /><br/>
</>
);
}
export default React.memo(PracticeMode);

View file

@ -1,13 +1,13 @@
import React from 'react';
import '../css/App.css';
import useTelegraph from '../hooks/useTelegraph';
import useStraightKey from '../hooks/useStraightKey';
import GameClock from '../components/GameClock'
import MorseBufferDisplay from '../components/MorseBufferDisplay'
import MorseDisplay from '../components/MorseDisplay'
function TimedMode() {
const {morseCharBuffer, morseWords} = useTelegraph('timed')
const {morseCharBuffer, morseWords} = useStraightKey('timed')
console.log('TimedMode.js rendered')

View file

@ -0,0 +1,7 @@
import React from 'react'
// import useStraightKey from '../hooks/useStraightKey';
import useElectronicKey from '../hooks/useElectronicKey';
export default React.memo(function StraightKey() {
useElectronicKey()
})

View file

@ -0,0 +1,25 @@
import React, {useContext} from "react"
import {KeyTypeContext} from "../contexts/keyTypeContext"
function KeyTypePicker() {
const {switchKeyType} = useContext(KeyTypeContext)
function handleClick(e) {
switchKeyType(e.target.id)
console.log("Switched to " + e.target.id + " keyType.");
}
return (
<div id="mode-picker">
<button id="straight" onClick={handleClick}>
Straight Key
</button>
<button id="electronic" onClick={handleClick}>
Electronic Key
</button>
</div>
)
}
export default React.memo(KeyTypePicker)

View file

@ -1,5 +1,5 @@
import React, {useContext} from "react"
import {GameModeContext} from "../gameContext"
import {GameModeContext} from "../contexts/gameContext"
function ModePicker() {

View file

@ -3,7 +3,7 @@ import DitDahDisplay from "./DitDahDisplay"
import morseCode from '../data/morse-reverse.json'
function MorseBufferDisplay(props) {
let ditDahs = props.buffer.split('').map((ditdah,index) => <DitDahDisplay key={index} dd={ditdah} />)
let alphanumeric = ''

View file

@ -0,0 +1,9 @@
import React from 'react'
import useStraightKey from '../hooks/useStraightKey';
// import useElectronicKey from '../hooks/useElectronicKey';
export default React.memo(function StraightKey(props) {
useStraightKey(props.gameMode)
})

View file

@ -7,5 +7,6 @@
"slow": 40,
"normal": 24,
"fast": 17
}
},
"historySize": 5
}

View file

@ -0,0 +1,24 @@
import React, {Component} from "react"
const KeyTypeContext = React.createContext()
class KeyTypeContextProvider extends Component {
state = {
keyType: "straight"
}
switchKeyType = (type = "straight") => {
this.setState({keyType: type})
}
render() {
return (
<KeyTypeContext.Provider value={{keyType: this.state.keyType, switchKeyType: this.switchKeyType}}>
{this.props.children}
</KeyTypeContext.Provider>
)
}
}
export {KeyTypeContextProvider, KeyTypeContext}

View file

@ -0,0 +1,42 @@
import React, {useState} from "react"
const MorseBufferContext = React.createContext()
function MorseBufferContextProvider(props) {
// state = {
// morseCharBuffer: '',
// morseWords: []
// //morseCharBuffer, morseWords, clearHistory, setMorseCharBuffer, setMorseWords
// }
const [morseCharBuffer, setMorseCharBuffer] = useState('')
const [morseWords, setMorseWords] = useState([])
// switchKeyType = (type = "straight") => {
// this.setState({keyType: type})
// }
// setMorseCharBuffer = (value) => {
// this.setState({morseCharBuffer: value})
// }
// setMorseWords = (value) => {
// this.setState({morseWords: value})
// }
// render() {
return (
<MorseBufferContext.Provider value={{
morseCharBuffer: morseCharBuffer,
morseWords: morseWords,
setMorseCharBuffer: setMorseCharBuffer,
setMorseWords: setMorseWords
}}>
{props.children}
</MorseBufferContext.Provider>
)
// }
}
export {MorseBufferContextProvider, MorseBufferContext}

View file

@ -0,0 +1,335 @@
import {useEffect, useContext, useState} from 'react'
import config from '../config.json'
import {MorseBufferContext} from '../contexts/morseBufferContext'
// SINGLE/DUAL LEVER TELEGRAPH
function useElectronicKey(mode = 'practice') {
const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext)
const timingUnit = config.timingUnit
const ditMaxTime = 85 // ditMaxTime * 0.365 to get ms, e.g. 85 * 0.365 ~= 31ms
const letterGapMinTime = ditMaxTime*0.36*3 //config.practiceSpeed.normal*3
const wordGapMaxTime = ditMaxTime*0.36*7 // config.practiceSpeed.normal*7
const morseHistorySize = config.historySize
let leftIsPressed = false
let rightIsPressed = false
let queueRunning = false
let queue = []
let pressedFirst = null
let depressSyncTime
let depressSyncTimer
let depressSyncTimerRunning = false
let gapTimer = 0
let gapTime = 0
let paddlesReleasedSimultaneously = false
let currentPromise = Promise.resolve()
// Audio 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 frequency = config.frequency
let toneTimer = 0
let toneTime = 0
let start = 0
let end = 0
// Promisify playing Dits and Dahs
function play(ditDah) {
let playDuration = ((ditDah === '.') ? ditMaxTime : ditMaxTime*3)
return new Promise((resolve, reject) => {
if (context.state === 'interrupted') {
context.resume()
}
let o = context.createOscillator()
o.frequency.value = frequency
o.type = "sine"
o.onended = () => {
// clearInterval(toneTimer)
// end = toneTime
// console.log('duration:', end-start);
resolve()
}
let startTime = context.currentTime;
let g = context.createGain()
g.gain.exponentialRampToValueAtTime(config.mainVolume, startTime)
g.gain.setValueAtTime(config.mainVolume, startTime)
o.connect(g)
g.connect(context.destination)
o.start(startTime)
// // for troubleshooting ditDah length in milliseconds
// toneTimer = setInterval(() => {
// toneTime += 1
// }, 1);
// start = toneTime
// // </>
g.gain.setTargetAtTime(0.0001, startTime + playDuration/1000, 0.001)
o.stop(startTime + playDuration/1000 + 0.05)
})
}
function playWithSpaces(ditDah) {
let delay = (ditDah === '.') ? ditMaxTime + ditMaxTime : ditMaxTime*3 + ditMaxTime
return new Promise(function(resolve) {
if (ditDah === '.' || ditDah === '-') {
play(ditDah)
.then(setTimeout(() => {
setMorseCharBuffer(prev => prev + ditDah)
resolve();
}, delay))
} else {
setTimeout(() => {
// setMorseCharBuffer(prev => prev + ' ')
resolve();
}, delay)
}
});
}
function executeQueue() {
let localQueue = queue
// Set waitTime to completion of queue (including spaces)
let waitTime = 0
for (let i in localQueue) {
if (localQueue[i] === '.') {
waitTime += ditMaxTime*2
} else if (localQueue[i] === '-') {
waitTime += ditMaxTime*4
}
}
queueRunning = true
// Wait till completion of queue to execute
const clear = setTimeout(() => {
queueRunning = false
queue = []
checkPressed()
}, waitTime)
// Execute queue
for (let i = 0; i < localQueue.length; i++) {
currentPromise = currentPromise.then(() => {
return playWithSpaces(localQueue[i])
});
}
}
function checkPressed() {
if (leftIsPressed && rightIsPressed) {
// queue.push(queue.slice(-1) === '.' ? '-' : '.')
if (pressedFirst === 'left') {
queue.push('-')
if (!paddlesReleasedSimultaneously) {
// console.log('one');
queue.push('.')
}
} else {
queue.push('.')
if (!paddlesReleasedSimultaneously) {
// console.log('two');
queue.push('-')
}
}
}
else if (leftIsPressed && !rightIsPressed) {
queue.push('.')
}
else if (rightIsPressed && !leftIsPressed) {
queue.push('-')
}
if (queue.length > 0) {
executeQueue()
}
}
function handleInputStart(event) {
event.preventDefault()
// if (event.keyCode === 188) {
// depressSyncTimeout()
// }
// else if (event.keyCode === 190) {
// testQueue.push('.')
// console.log('testQueue', testQueue);
// }
// else if (event.target.id === 'morseButton') {
// testQueue = []
// }
// while (testQueue.length > 0) {
// currentPromise = currentPromise.then(() => {
// return playWithSpaces(testQueue.shift())
// })
// }
paddlesReleasedSimultaneously = false
if (event.repeat) { return }
// if (!leftIsPressed && !rightIsPressed) {
// clearInterval(gapTimer)
// checkGapBetweenInputs()
// }
if (event.keyCode === 188) {
leftIsPressed = true
if (!rightIsPressed) { pressedFirst = 'left'}
// Prevent further input if queue is executing
if (!queueRunning) {
checkPressed()
}
}
else if (event.keyCode === 190) {
rightIsPressed = true
if (!leftIsPressed) { pressedFirst = 'right'}
// Prevent further input if queue is executing
if (!queueRunning) {
checkPressed()
}
}
}
function startDepressSyncTimer() {
depressSyncTimerRunning = true
// Reset depressSyncTime
depressSyncTime = 0
// Start depressSyncTimer
depressSyncTimer = setInterval(() => {
depressSyncTime += 1
if (depressSyncTime > 20) {
depressSyncTimerRunning = false
clearInterval(depressSyncTimer)
depressSyncTime = 0
}
}, 1);
}
function stopDepressSyncTimer() {
depressSyncTimerRunning = false
clearInterval(depressSyncTimer)
if (depressSyncTime < 10) {
paddlesReleasedSimultaneously = true
queue.pop()
console.log('paddles released', queue);
}
depressSyncTime = 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) {
console.log('letterGapMinTime <= gapTime < wordGapMaxTime:',letterGapMinTime, gapTime, wordGapMaxTime);
if (mode === 'practice') {
setMorseCharBuffer(prev => prev + ' ')
} else if (mode === 'challenge') {
console.log("UNDERSCORE ADDED");
setMorseCharBuffer(prev => prev + '_')
}
clearInterval(gapTimer)
gapTimer = 0
}
}
function handleInputEnd(event) {
event.preventDefault()
if (event.keyCode === 188) {
leftIsPressed = false
if (pressedFirst === 'left') { pressedFirst = null }
if (!depressSyncTimerRunning) { startDepressSyncTimer() }
else { stopDepressSyncTimer() }
}
else if (event.keyCode === 190) {
rightIsPressed = false
if (pressedFirst === 'right') { pressedFirst = null }
if (!depressSyncTimerRunning) { startDepressSyncTimer() }
else { stopDepressSyncTimer() }
}
// if (!leftIsPressed && !rightIsPressed ) { startGapTimer() }
}
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)
}
// 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('')
}
// 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 useElectronicKey

View file

@ -0,0 +1,344 @@
import {useEffect, useContext, useState} from 'react'
import config from '../config.json'
import {MorseBufferContext} from '../contexts/morseBufferContext'
// SINGLE/DUAL LEVER TELEGRAPH
function useElectronicKey(mode = 'practice') {
const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext)
const timingUnit = config.timingUnit
const ditMaxTime = 85 // ditMaxTime * 0.365 to get ms, e.g. 85 * 0.365 ~= 31ms
const letterGapMinTime = ditMaxTime*0.36*3 //config.practiceSpeed.normal*3
const wordGapMaxTime = ditMaxTime*0.36*7 // config.practiceSpeed.normal*7
const morseHistorySize = config.historySize
let leftIsPressed = false
let rightIsPressed = false
let queueRunning = false
let queue = []
let pressedFirst = null
let depressSyncTime
let depressSyncTimer
let depressSyncTimerRunning = false
let gapTimer = 0
let gapTime = 0
const [paddlesReleasedSimultaneously, setPaddlesReleasedSimultaneously] = useState(false)
let currentPromise = Promise.resolve()
// Audio 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 frequency = config.frequency
let toneTimer = 0
let toneTime = 0
let start = 0
let end = 0
// Promisify playing Dits and Dahs
function play(ditDah) {
let playDuration = ((ditDah === '.') ? ditMaxTime : ditMaxTime*3)
return new Promise((resolve, reject) => {
if (context.state === 'interrupted') {
context.resume()
}
let o = context.createOscillator()
o.frequency.value = frequency
o.type = "sine"
o.onended = () => {
// clearInterval(toneTimer)
// end = toneTime
// console.log('duration:', end-start);
resolve()
}
let startTime = context.currentTime;
let g = context.createGain()
g.gain.exponentialRampToValueAtTime(config.mainVolume, startTime)
g.gain.setValueAtTime(config.mainVolume, startTime)
o.connect(g)
g.connect(context.destination)
o.start(startTime)
// // for troubleshooting ditDah length in milliseconds
// toneTimer = setInterval(() => {
// toneTime += 1
// }, 1);
// start = toneTime
// // </>
g.gain.setTargetAtTime(0.0001, startTime + playDuration/1000, 0.001)
o.stop(startTime + playDuration/1000 + 0.05)
})
}
function playWithSpaces(ditDah) {
let delay = (ditDah === '.') ? ditMaxTime + ditMaxTime : ditMaxTime*3 + ditMaxTime
return new Promise(function(resolve) {
if (ditDah === '.' || ditDah === '-') {
play(ditDah)
.then(setTimeout(() => {
setMorseCharBuffer(prev => prev + ditDah)
resolve();
}, delay))
} else {
setTimeout(() => {
// setMorseCharBuffer(prev => prev + ' ')
resolve();
}, delay)
}
});
}
function executeQueue() {
let localQueue = queue
// Set waitTime to completion of queue (including spaces)
let waitTime = 0
for (let i in localQueue) {
if (localQueue[i] === '.') {
waitTime += ditMaxTime*2
} else if (localQueue[i] === '-') {
waitTime += ditMaxTime*4
}
}
queueRunning = true
// Wait till completion of queue to execute
const clear = setTimeout(() => {
queueRunning = false
queue = []
checkPressed()
}, waitTime)
// Execute queue
for (let i = 0; i < localQueue.length; i++) {
currentPromise = currentPromise.then(() => {
return playWithSpaces(localQueue[i])
});
}
}
function checkPressed() {
if (leftIsPressed && rightIsPressed) {
if (pressedFirst === 'left') {
queue.push('-')
if (!paddlesReleasedSimultaneously) {
console.log('one');
queue.push('.')
}
} else {
queue.push('.')
if (!paddlesReleasedSimultaneously) {
console.log('two');
queue.push('-')
}
}
}
else if (leftIsPressed && !rightIsPressed) {
queue.push('.')
}
else if (rightIsPressed && !leftIsPressed) {
queue.push('-')
}
if (queue.length > 0) {
executeQueue()
}
}
// function depressSyncTimeout() {
// let depressSyncTimeO = setTimeout(() => {
// if (testQueue.length > 0) {
// let x = testQueue.shift()
// console.log('testQueue', x, testQueue);
// depressSyncTimeout()
// } else {
// clearTimeout(depressSyncTimeO)
// }
// }, 1000)
// }
function handleInputStart(event) {
event.preventDefault()
// if (event.keyCode === 188) {
// depressSyncTimeout()
// }
// else if (event.keyCode === 190) {
// testQueue.push('.')
// console.log('testQueue', testQueue);
// }
// else if (event.target.id === 'morseButton') {
// testQueue = []
// }
// while (testQueue.length > 0) {
// currentPromise = currentPromise.then(() => {
// return playWithSpaces(testQueue.shift())
// })
// }
setPaddlesReleasedSimultaneously(false)
if (event.repeat) { return }
// if (!leftIsPressed && !rightIsPressed) {
// clearInterval(gapTimer)
// checkGapBetweenInputs()
// }
if (event.keyCode === 188) {
leftIsPressed = true
if (!rightIsPressed) { pressedFirst = 'left'}
// Prevent further input if queue is executing
if (!queueRunning) {
checkPressed()
}
}
else if (event.keyCode === 190) {
rightIsPressed = true
if (!leftIsPressed) { pressedFirst = 'right'}
// Prevent further input if queue is executing
if (!queueRunning) {
checkPressed()
}
}
}
function startDepressSyncTimer() {
depressSyncTimerRunning = true
// Reset depressSyncTime
depressSyncTime = 0
// Start depressSyncTimer
depressSyncTimer = setInterval(() => {
depressSyncTime += 1
if (depressSyncTime > 20) {
depressSyncTimerRunning = false
clearInterval(depressSyncTimer)
depressSyncTime = 0
}
}, 1);
}
function stopDepressSyncTimer() {
depressSyncTimerRunning = false
clearInterval(depressSyncTimer)
if (depressSyncTime < 10) {
setPaddlesReleasedSimultaneously(true)
}
depressSyncTime = 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) {
console.log('letterGapMinTime <= gapTime < wordGapMaxTime:',letterGapMinTime, gapTime, wordGapMaxTime);
if (mode === 'practice') {
setMorseCharBuffer(prev => prev + ' ')
} else if (mode === 'challenge') {
console.log("UNDERSCORE ADDED");
setMorseCharBuffer(prev => prev + '_')
}
clearInterval(gapTimer)
gapTimer = 0
}
}
function handleInputEnd(event) {
event.preventDefault()
if (event.keyCode === 188) {
leftIsPressed = false
if (pressedFirst === 'left') { pressedFirst = null }
if (!depressSyncTimerRunning) { startDepressSyncTimer() }
else { stopDepressSyncTimer() }
}
else if (event.keyCode === 190) {
rightIsPressed = false
if (pressedFirst === 'right') { pressedFirst = null }
if (!depressSyncTimerRunning) { startDepressSyncTimer() }
else { stopDepressSyncTimer() }
}
// if (!leftIsPressed && !rightIsPressed ) { startGapTimer() }
}
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)
}
// 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('')
}
// 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 useElectronicKey

View file

View file

@ -1,175 +0,0 @@
import {useEffect} from 'react'
import config from '../config.json'
// SINGLE/DUAL LEVER TELEGRAPH
function usePaddleTelegraph() {
const ditMaxTime = 85
let leftIsPressed = false
let rightIsPressed = false
let queueRunning = false
let queue = []
let currentPromise = Promise.resolve()
// Audio 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 frequency = config.frequency
// Promisify playing Dits and Dahs
function play(ditDah) {
let playDuration = ((ditDah === '.') ? ditMaxTime : ditMaxTime*3)
return new Promise((resolve, reject) => {
if (context.state === 'interrupted') {
context.resume()
}
let o = context.createOscillator()
o.frequency.value = frequency
o.type = "sine"
o.onended = () => {
resolve()
}
let startTime = context.currentTime;
let g = context.createGain()
g.gain.exponentialRampToValueAtTime(config.mainVolume, startTime)
g.gain.setValueAtTime(config.mainVolume, startTime)
o.connect(g)
g.connect(context.destination)
o.start(startTime)
g.gain.setTargetAtTime(0.0001, startTime + playDuration/1000, 0.001)
o.stop(startTime + playDuration/1000 + 0.05)
})
}
function playWithSpaces(ditDah) {
let delay = (ditDah === '.') ? ditMaxTime + ditMaxTime : ditMaxTime*3 + ditMaxTime
return new Promise(function(resolve) {
if (ditDah === '.' || ditDah === '-') {
play(ditDah)
.then(setTimeout(() => {
resolve();
}, delay))
} else {
setTimeout(() => {
resolve();
}, delay)
}
});
}
function executeQueue() {
let localQueue = queue
console.log('localQueue',localQueue);
// Set wait time to completion of queue (including spaces)
let waitTime = 0
for (let i in localQueue) {
if (localQueue[i] === '.') {
waitTime += ditMaxTime*2
} else if (localQueue[i] === '-') {
waitTime += ditMaxTime*4
}
}
queueRunning = true
// Wait till completion of queue to execute
setTimeout(() => {
queueRunning = false
queue = []
checkPressed()
}, waitTime)
// Execute queue
for (let i = 0; i < localQueue.length; i++) {
currentPromise = currentPromise.then(() => {
return playWithSpaces(localQueue[i])
});
}
}
function checkPressed() {
if (leftIsPressed) {
queue.push('.')
}
if (rightIsPressed) {
queue.push('-')
}
if (queue.length > 0) {
executeQueue()
}
}
function handleInputStart(event) {
event.preventDefault()
if (event.repeat) { return }
if (event.keyCode === 188) {
leftIsPressed = true
console.log("LEFT DOWN");
// Prevent further input if queue is executing
if (!queueRunning) {
checkPressed()
}
}
else if (event.keyCode === 190) {
rightIsPressed = true
console.log("RIGHT DOWN");
// Prevent further input if queue is executing
if (!queueRunning) {
checkPressed()
}
}
}
function handleInputEnd(event) {
event.preventDefault()
if (event.keyCode === 188) {
leftIsPressed = false
console.log("LEFT UP");
}
else if (event.keyCode === 190) {
rightIsPressed = false
console.log("RIGHT UP");
}
}
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)
}
// eslint-disable-next-line
}, [])
}
export default usePaddleTelegraph

View file

@ -1,12 +1,15 @@
import {useState, useEffect} from 'react'
import {useEffect, useContext} from 'react'
import {MorseBufferContext} from '../contexts/morseBufferContext'
import config from '../config.json'
// STRAIGHT KEY TELEGRAPH
function useTelegraph(mode = 'practice') {
function useStraightKey(mode = 'practice') {
const [morseCharBuffer, setMorseCharBuffer] = useState('') // e.g. '-..'
const [morseWords, setMorseWords] = useState([]) // e.g. [['-..','.','-,'], ['...','---','...']]
const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext)
// const [morseCharBuffer, setMorseCharBuffer] = useState('') // e.g. '-..'
// const [morseWords, setMorseWords] = useState([]) // e.g. [['-..','.','-,'], ['...','---','...']]
let charTimer = 0
let charTime = 0
@ -18,7 +21,7 @@ function useTelegraph(mode = 'practice') {
const ditMaxTime = config.practiceSpeed.normal
const letterGapMinTime = ditMaxTime*3
const wordGapMaxTime = ditMaxTime*7
const morseHistorySize = 5
const morseHistorySize = config.historySize
// Tone Setup
let AudioContext = window.AudioContext || window.webkitAudioContext || false
@ -169,6 +172,11 @@ function useTelegraph(mode = 'practice') {
return function cleanup() {
document.removeEventListener('keydown', handleInputStart)
document.removeEventListener('keyup', handleInputEnd)
const morseButton = document.getElementById('morseButton')
morseButton.removeEventListener('mousedown', handleInputStart)
morseButton.removeEventListener('touchstart', handleInputStart)
morseButton.removeEventListener('mouseup', handleInputEnd)
morseButton.removeEventListener('touchend', handleInputEnd)
clearHistory()
}
// eslint-disable-next-line
@ -199,4 +207,4 @@ function useTelegraph(mode = 'practice') {
return {morseCharBuffer, morseWords, clearHistory, setMorseCharBuffer, setMorseWords}
}
export default useTelegraph
export default useStraightKey

View file

@ -3,11 +3,15 @@ import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {GameModeContextProvider} from "./gameContext"
import {GameModeContextProvider} from "./contexts/gameContext"
import {KeyTypeContextProvider} from "./contexts/keyTypeContext"
ReactDOM.render(
<GameModeContextProvider>
<App />
<KeyTypeContextProvider>
<App />
</KeyTypeContextProvider>
</GameModeContextProvider>
, document.getElementById('root'));