diff --git a/src/App.js b/src/App.js
index 0413752..43e0f89 100644
--- a/src/App.js
+++ b/src/App.js
@@ -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 (
+
+
+
+ {keyType === "straight" && }
+ {keyType === "electronic" && }
- {gameMode === 'practice' && }
- {gameMode === 'timed' && }
- {gameMode === 'challenge' && }
+ {gameMode === 'practice' && }
+ {gameMode === 'timed' && }
+ {gameMode === 'challenge' && }
+
diff --git a/src/app-modes/ChallengeMode.js b/src/app-modes/ChallengeMode.js
index 8577d9c..5c941b2 100644
--- a/src/app-modes/ChallengeMode.js
+++ b/src/app-modes/ChallengeMode.js
@@ -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);
diff --git a/src/app-modes/PracticeMode.js b/src/app-modes/PracticeMode.js
index b9451e5..78ca163 100644
--- a/src/app-modes/PracticeMode.js
+++ b/src/app-modes/PracticeMode.js
@@ -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 (
<>
- {/*
-
*/}
-
+
+
>
);
+
}
export default React.memo(PracticeMode);
diff --git a/src/app-modes/TimedMode.js b/src/app-modes/TimedMode.js
index 16d4df4..9ee1ee4 100644
--- a/src/app-modes/TimedMode.js
+++ b/src/app-modes/TimedMode.js
@@ -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')
diff --git a/src/components/ElectronicKey.js b/src/components/ElectronicKey.js
new file mode 100644
index 0000000..3d58490
--- /dev/null
+++ b/src/components/ElectronicKey.js
@@ -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()
+})
\ No newline at end of file
diff --git a/src/components/KeyTypePicker.js b/src/components/KeyTypePicker.js
new file mode 100644
index 0000000..6fb4f21
--- /dev/null
+++ b/src/components/KeyTypePicker.js
@@ -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 (
+
+
+
+
+ )
+}
+
+export default React.memo(KeyTypePicker)
\ No newline at end of file
diff --git a/src/components/ModePicker.js b/src/components/ModePicker.js
index 0d4ee78..3c0453c 100644
--- a/src/components/ModePicker.js
+++ b/src/components/ModePicker.js
@@ -1,5 +1,5 @@
import React, {useContext} from "react"
-import {GameModeContext} from "../gameContext"
+import {GameModeContext} from "../contexts/gameContext"
function ModePicker() {
diff --git a/src/components/MorseBufferDisplay.js b/src/components/MorseBufferDisplay.js
index 09b75cf..92aa736 100644
--- a/src/components/MorseBufferDisplay.js
+++ b/src/components/MorseBufferDisplay.js
@@ -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) => )
let alphanumeric = ''
diff --git a/src/components/StraightKey.js b/src/components/StraightKey.js
new file mode 100644
index 0000000..8f2b825
--- /dev/null
+++ b/src/components/StraightKey.js
@@ -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)
+
+})
\ No newline at end of file
diff --git a/src/config.json b/src/config.json
index bf51225..ea050cd 100644
--- a/src/config.json
+++ b/src/config.json
@@ -7,5 +7,6 @@
"slow": 40,
"normal": 24,
"fast": 17
- }
+ },
+ "historySize": 5
}
\ No newline at end of file
diff --git a/src/gameContext.js b/src/contexts/gameContext.js
similarity index 100%
rename from src/gameContext.js
rename to src/contexts/gameContext.js
diff --git a/src/contexts/keyTypeContext.js b/src/contexts/keyTypeContext.js
new file mode 100644
index 0000000..1013e2f
--- /dev/null
+++ b/src/contexts/keyTypeContext.js
@@ -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 (
+
+ {this.props.children}
+
+ )
+ }
+
+}
+
+export {KeyTypeContextProvider, KeyTypeContext}
diff --git a/src/contexts/morseBufferContext.js b/src/contexts/morseBufferContext.js
new file mode 100644
index 0000000..111e05b
--- /dev/null
+++ b/src/contexts/morseBufferContext.js
@@ -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 (
+
+ {props.children}
+
+ )
+ // }
+
+}
+
+export {MorseBufferContextProvider, MorseBufferContext}
diff --git a/src/hooks/useElectronicKey.js b/src/hooks/useElectronicKey.js
new file mode 100644
index 0000000..e095b9c
--- /dev/null
+++ b/src/hooks/useElectronicKey.js
@@ -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
\ No newline at end of file
diff --git a/src/hooks/useElectronicKey_iambicB.js b/src/hooks/useElectronicKey_iambicB.js
new file mode 100644
index 0000000..2f70fc9
--- /dev/null
+++ b/src/hooks/useElectronicKey_iambicB.js
@@ -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
\ No newline at end of file
diff --git a/src/hooks/useKeySelection.js b/src/hooks/useKeySelection.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/hooks/usePaddleTelegraph.js b/src/hooks/usePaddleTelegraph.js
deleted file mode 100644
index 22bf72e..0000000
--- a/src/hooks/usePaddleTelegraph.js
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/src/hooks/useTelegraph.js b/src/hooks/useStraightKey.js
similarity index 86%
rename from src/hooks/useTelegraph.js
rename to src/hooks/useStraightKey.js
index 77050fc..fa35b91 100644
--- a/src/hooks/useTelegraph.js
+++ b/src/hooks/useStraightKey.js
@@ -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
\ No newline at end of file
+export default useStraightKey
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 959578c..83e7fd2 100644
--- a/src/index.js
+++ b/src/index.js
@@ -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(
-
+
+
+
, document.getElementById('root'));