Combinging straight/electronic keys

This commit is contained in:
Gene Mecija 2020-01-25 12:23:47 -08:00
parent 1d331a1d21
commit 4b4030a88d
9 changed files with 345 additions and 118 deletions

View file

@ -26,12 +26,13 @@ import MorseHistory from './components/MorseHistory'
import StraightKey from './components/StraightKey';
import ElectronicKey from './components/ElectronicKey';
import Footer from './components/Footer';
import { WPMContextProvider } from './contexts/wpmContext';
import { WPMContext } from './contexts/wpmContext';
export default React.memo(function App() {
console.log('App.js rendered')
const {gameMode} = useContext(GameModeContext)
const {wpm} = useContext(WPMContext)
const {keyType} = useContext(KeyTypeContext)
console.log('gameMode', gameMode);
@ -41,45 +42,43 @@ export default React.memo(function App() {
<>
<Header />
<div id='main-content'>
<WPMContextProvider>
<Legend />
<WordsPerMinute />
<MorseBufferContextProvider>
<ModePicker />
<KeyTypePicker />
{gameMode === 'practice' &&
<>
{keyType === "straight" ?
<StraightKey gameMode='practice' /> : <ElectronicKey gameMode='practice' />}
<PracticeMode /><br/>
<MorseBufferDisplay /><br/>
<MorseHistory /><br/>
</>
}
{gameMode === 'timed' &&
<>
{keyType === "straight" ?
<StraightKey gameMode='training' /> : <ElectronicKey gameMode='training' />}
<TrainingMode /><br/>
<MorseBufferDisplay /><br/>
<MorseHistory /><br/>
</>
}
{gameMode === 'challenge' &&
<>
<WordListPickerContextProvider>
<WordFeederContextProvider>
<WordListPicker />
{keyType === "straight" ?
<StraightKey gameMode='challenge' /> : <ElectronicKey gameMode='challenge' />}
<ChallengeMode />
</WordFeederContextProvider>
</WordListPickerContextProvider>
</>
}
<MorseButtons />
</MorseBufferContextProvider>
</WPMContextProvider>
<Legend />
<WordsPerMinute />
<MorseBufferContextProvider>
<ModePicker />
<KeyTypePicker />
{gameMode === 'practice' &&
<>
{/* {keyType === "straight" ?
<StraightKey gameMode='practice' wpm={wpm} /> : <ElectronicKey gameMode='practice' wpm={wpm} />} */}
<PracticeMode /><br/>
{/* <MorseBufferDisplay /><br/>
<MorseHistory /><br/> */}
</>
}
{/* {gameMode === 'timed' &&
<>
{keyType === "straight" ?
<StraightKey gameMode='training' /> : <ElectronicKey gameMode='training' />}
<TrainingMode /><br/>
<MorseBufferDisplay /><br/>
<MorseHistory /><br/>
</>
}
{gameMode === 'challenge' &&
<>
<WordListPickerContextProvider>
<WordFeederContextProvider>
<WordListPicker />
{keyType === "straight" ?
<StraightKey gameMode='challenge' /> : <ElectronicKey gameMode='challenge' />}
<ChallengeMode />
</WordFeederContextProvider>
</WordListPickerContextProvider>
</>
} */}
<MorseButtons />
</MorseBufferContextProvider>
</div>
<Footer />
</>

View file

@ -5,17 +5,23 @@ import StraightKey from '../components/StraightKey'
import ElectronicKey from '../components/ElectronicKey'
import MorseBufferDisplay from '../components/MorseBufferDisplay'
import MorseHistory from '../components/MorseHistory'
import { WPMContext } from '../contexts/wpmContext';
import { GameModeContext } from '../contexts/gameModeContext';
import useStraightKey from '../hooks/useStraightKey';
export default React.memo(function PracticeMode() {
const {keyType} = useContext(KeyTypeContext)
const {gameMode} = useContext(GameModeContext)
const {wpm} = useContext(WPMContext)
return (
<>
{/* {keyType === "straight" ? <StraightKey /> : <ElectronicKey />}
{keyType === "straight" ? <StraightKey gameMode={gameMode} wpm={wpm} /> : <ElectronicKey gameMode={gameMode} wpm={wpm} />}
<MorseBufferDisplay /><br/>
<MorseHistory /><br/> */}
<MorseHistory /><br/>
</>
);

View file

@ -1,6 +1,9 @@
import React from 'react'
import React, { useContext } from 'react'
import useElectronicKey from '../hooks/useElectronicKey';
export default React.memo(function ElectronicKey(props) {
useElectronicKey(props.gameMode)
})
function ElectronicKey(props) {
return useElectronicKey(props.gameMode, props.wpm)
}
export default ElectronicKey

View file

@ -1,7 +1,13 @@
import React from 'react'
import React, { useContext } from 'react'
import useStraightKey from '../hooks/useStraightKey';
import { GameModeContext } from '../contexts/gameModeContext';
import { WPMContext } from '../contexts/wpmContext';
export default React.memo(function StraightKey(props) {
console.log('props.gameMode',props.gameMode);
useStraightKey(props.gameMode)
// const {gameMode} = useContext(GameModeContext)
// const {wpm} = useContext(WPMContext)
useStraightKey(props.gameMode, props.wpm)
})

View file

@ -11,6 +11,7 @@ export default React.memo(function WordsPerMinute(props) {
}
return (
<input id='wpm-input' type='text' value={wpm} onChange={handleChange} />
// <input id='wpm-input' type='text' value={wpm} onChange={handleChange} />
<input type="number" name="wpm" id='wpm-input' min="5" max="30" value={wpm} onChange={handleChange}></input>
)
})

View file

@ -5,10 +5,11 @@ import { WPMContext } from '../contexts/wpmContext'
// ELECTRONIC KEY TELEGRAPH - Iambic A
function useElectronicKey(gameMode) {
function useElectronicKey(gameMode, wpm) {
const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext)
const {wpm} = useContext(WPMContext)
// const {wpm} = useContext(WPMContext)
// console.log('useStraightKey-WPM:', wpm);
const timingUnit = config.timingUnit
@ -33,7 +34,6 @@ function useElectronicKey(gameMode) {
// let gapTimerRunning = false
let paddlesReleasedSimultaneously = false
let insideBufferDisplay = false
// function consoleLogVars() {
// // Log variables (Debug tool)
@ -235,26 +235,6 @@ function useElectronicKey(gameMode) {
function handleInputStart(event) {
event.preventDefault()
console.log(event.target);
if (event.type === 'mousedown' && event.target.className !== 'paddle') {
if (bufferDisplay.includes(event.target.id)) {
document.addEventListener('keydown', handleInputStart)
document.addEventListener('keyup', handleInputEnd)
insideBufferDisplay = true
console.log('insideBufferDisplay', insideBufferDisplay);
} else {
document.removeEventListener('keydown', handleInputStart)
document.removeEventListener('keyup', handleInputEnd)
insideBufferDisplay = false
console.log('insideBufferDisplay', insideBufferDisplay);
if (event.target.id === 'wpm-input') {
event.target.focus()
} else {
document.activeElement.blur()
}
}
}
paddlesReleasedSimultaneously = false
if (event.repeat) { return }
@ -282,7 +262,7 @@ function useElectronicKey(gameMode) {
function handleInputEnd(event) {
event.preventDefault()
if (!insideBufferDisplay) {return}
// if (!insideBufferDisplay) {return}
if (event.keyCode === 188 || event.target.id === "left") {
leftIsPressed = false
@ -343,7 +323,6 @@ function useElectronicKey(gameMode) {
useEffect(() => {
document.addEventListener('keydown', handleInputStart)
document.addEventListener('keyup', handleInputEnd)
document.addEventListener('mousedown', handleInputStart)
const paddles = document.querySelectorAll('.paddle')
paddles.forEach(paddle => {
@ -357,7 +336,6 @@ function useElectronicKey(gameMode) {
return function cleanup() {
document.removeEventListener('keydown', handleInputStart)
document.removeEventListener('keyup', handleInputEnd)
document.removeEventListener('mousedown', handleInputStart)
const paddles = document.querySelectorAll('.paddle')
paddles.forEach(paddle => {
@ -367,8 +345,8 @@ function useElectronicKey(gameMode) {
paddle.removeEventListener('mouseup', handleInputEnd)
paddle.removeEventListener('touchend', handleInputEnd)
})
clearHistory()
}
clearHistory()
// eslint-disable-next-line
}, [])

View file

@ -1,13 +1,14 @@
import {useEffect, useContext} from 'react'
import {MorseBufferContext} from '../contexts/morseBufferContext'
import config from '../config.json'
import { WPMContext } from '../contexts/wpmContext'
// import { WPMContext } from '../contexts/wpmContext'
// STRAIGHT KEY TELEGRAPH
function useStraightKey(gameMode) {
function useStraightKey(gameMode, wpm) {
const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext)
const {wpm} = useContext(WPMContext)
// const {wpm} = useContext(WPMContext)
// console.log('useStraightKey-WPM:', wpm);
let charTimer = 0
let charTime = 0
@ -21,7 +22,6 @@ function useStraightKey(gameMode) {
const wordGapMaxTime = ditMaxTime*7
const morseHistorySize = config.historySize
let insideBufferDisplay = false
// Tone Setup
let AudioContext = window.AudioContext || window.webkitAudioContext || false
@ -44,35 +44,49 @@ function useStraightKey(gameMode) {
}
const bufferDisplay = ['morseBufferDisplay', 'challengeBufferDisplay', 'ditDahs', 'alphanumeric-container']
function handleInputStart(event) {
event.preventDefault()
console.log('INPUTSTART');
// console.log('event.type', event.type);
// if (event.type === 'mousedown' && event.target.className !== 'paddle') {
// if (event.target.id === 'wpm-input') {
// console.log('REMOVED KEYDOWN/UP');
// document.removeEventListener('keydown', handleInputStart)
// document.removeEventListener('keyup', handleInputEnd)
// event.target.focus()
// } else {
// document.addEventListener('keydown', handleInputStart)
// document.addEventListener('keyup', handleInputEnd)
// document.activeElement.blur()
// }
// }
console.log(event.target);
if (event.type === 'mousedown' && event.target.className !== 'paddle') {
if (bufferDisplay.includes(event.target.id)) {
document.addEventListener('keydown', handleInputStart)
document.addEventListener('keyup', handleInputEnd)
insideBufferDisplay = true
console.log('insideBufferDisplay', insideBufferDisplay);
} else {
document.removeEventListener('keydown', handleInputStart)
document.removeEventListener('keyup', handleInputEnd)
insideBufferDisplay = false
console.log('insideBufferDisplay', insideBufferDisplay);
if (event.target.id === 'wpm-input') {
event.target.focus()
} else {
document.activeElement.blur()
}
}
}
// console.log(event.target);
// if (event.type === 'mousedown' && event.target.className !== 'paddle') {
// if (bufferDisplay.includes(event.target.id)) {
// document.addEventListener('keydown', handleInputStart)
// document.addEventListener('keyup', handleInputEnd)
// insideBufferDisplay = true
// console.log('insideBufferDisplay', insideBufferDisplay);
// } else {
// document.removeEventListener('keydown', handleInputStart)
// document.removeEventListener('keyup', handleInputEnd)
// insideBufferDisplay = false
// console.log('insideBufferDisplay', insideBufferDisplay);
// if (event.target.id === 'wpm-input') {
// event.target.focus()
// } else {
// document.activeElement.blur()
// }
// }
// }
if (isRunning) {
console.log('insideBufferDisplay', insideBufferDisplay);
// console.log('insideBufferDisplay', insideBufferDisplay);
return
} else if (insideBufferDisplay === true) {
} else {
if ((event.keyCode !== 32 &&
event.target.id !== "morseButton" &&
event.target.className !== "paddle") ||
@ -100,8 +114,6 @@ function useStraightKey(gameMode) {
clearInterval(gapTimer)
startCharTimer()
} else {
return
}
}
@ -120,7 +132,7 @@ function useStraightKey(gameMode) {
// insideBufferDisplay = true
// console.log('insideBufferDisplay', insideBufferDisplay);
// }
if (!insideBufferDisplay) {return}
// if (!insideBufferDisplay) {return}
if (isRunning) {
if ((event.keyCode !== 32 &&
@ -191,13 +203,8 @@ function useStraightKey(gameMode) {
useEffect(() => {
// const buffer = document.getElementById('morseBufferDisplay')
// document.addEventListener('mousedown', morseOn)
// document.addEventListener('mousedown', morseOff)
document.addEventListener('keydown', handleInputStart)
document.addEventListener('keyup', handleInputEnd)
document.addEventListener('mousedown', handleInputStart)
const paddles = document.querySelectorAll('.paddle')
paddles.forEach(paddle => {
@ -209,13 +216,8 @@ function useStraightKey(gameMode) {
})
return function cleanup() {
// const buffer = document.getElementById('morseBufferDisplay')
// document.removeEventListener('mousedown', morseOn)
// document.removeEventListener('mousedown', morseOff)
document.removeEventListener('keydown', handleInputStart)
document.removeEventListener('keyup', handleInputEnd)
document.removeEventListener('mouseUp', handleInputStart)
const paddles = document.querySelectorAll('.paddle')
paddles.forEach(paddle => {

View file

@ -0,0 +1,229 @@
import {useEffect, useContext} from 'react'
import {MorseBufferContext} from '../contexts/morseBufferContext'
import config from '../config.json'
import { WPMContext } from '../contexts/wpmContext'
import { KeyTypeContext } from '../contexts/keyTypeContext'
// STRAIGHT KEY TELEGRAPH
function useTelegraphKey(gameMode, wpm) {
const {morseCharBuffer, setMorseCharBuffer, morseWords, setMorseWords} = useContext(MorseBufferContext)
// const {wpm} = useContext(WPMContext)
// console.log('useStraightKey-WPM:', wpm);
// Straight Key Variables
let charTimer = 0
let charTime = 0
// Electronic Key Variables
let ratio = .2
let depressSyncTime
let depressSyncTimer
let depressSyncTimerRunning = false
let paddlesReleasedSimultaneously = false
// Straight && Electronic Key Variables
let gapTimer = 0
let gapTime = 0
const timingUnit = config.timingUnit
const ditMaxTime = 1200/wpm
const letterGapMinTime = ditMaxTime*3
const wordGapMaxTime = ditMaxTime*7
const morseHistorySize = config.historySize
// 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 // Oscillator Node
let g // Gain Node
let frequency = config.frequency
let isRunning = false
function clearHistory() {
setMorseWords([])
}
function handleInputStart(event) {
event.preventDefault()
if (isRunning) {
return
} else {
if ((event.keyCode !== 32 &&
event.target.id !== "morseButton" &&
event.target.className !== "paddle") ||
(event.repeat)) {
return
}
isRunning = true
if (context.state === 'interrupted') {
context.resume()
}
o = context.createOscillator()
o.frequency.value = frequency
o.type = "sine"
g = context.createGain()
g.gain.exponentialRampToValueAtTime(config.mainVolume, context.currentTime)
o.connect(g)
g.connect(context.destination)
o.start()
checkGapBetweenInputs()
clearInterval(gapTimer)
startCharTimer()
}
}
function startCharTimer() {
// Start Character Timer
charTimer = setInterval(() => {
charTime += 1
}, timingUnit);
}
function handleInputEnd(event) {
event.preventDefault()
// if (event.target.id !== 'morseBufferDisplay') {
// insideBufferDisplay = true
// console.log('insideBufferDisplay', insideBufferDisplay);
// }
// if (!insideBufferDisplay) {return}
if (isRunning) {
if ((event.keyCode !== 32 &&
event.target.id !== "morseButton" &&
event.target.className !== "paddle") ||
(event.repeat)) {
return
}
isRunning = false
// console.log('charTime:', charTime);
if (charTime <= ditMaxTime) {
setMorseCharBuffer(prev => prev + '.')
} else {
setMorseCharBuffer(prev => prev + '-')
}
stopCharTimer()
startGapTimer()
if (o.context.state === 'running') {
g.gain.setTargetAtTime(0.0001, context.currentTime, 0.001)
o.stop(context.currentTime + 0.05)
}
} else { return }
}
function stopCharTimer() {
clearInterval(charTimer)
charTimer = 0
charTime = 0
}
function startGapTimer() {
gapTime = 0
gapTimer = setInterval(() => {
gapTime += 1
// Gap between words
if (gameMode === 'practice' && gapTime >= wordGapMaxTime) {
setMorseCharBuffer(prev => prev + '/')
clearInterval(gapTimer)
gapTimer = 0
gapTime = 0
}
else if (gameMode === '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 (gameMode === 'practice') {
setMorseCharBuffer(prev => prev + ' ')
} else if (gameMode === 'challenge') {
setMorseCharBuffer(prev => prev + '_')
}
clearInterval(gapTimer)
gapTimer = 0
}
}
useEffect(() => {
document.addEventListener('keydown', handleInputStart)
document.addEventListener('keyup', handleInputEnd)
const paddles = document.querySelectorAll('.paddle')
paddles.forEach(paddle => {
paddle.addEventListener('mousedown', handleInputStart)
paddle.addEventListener('touchstart', handleInputStart)
paddle.addEventListener('mouseout', handleInputEnd)
paddle.addEventListener('mouseup', handleInputEnd)
paddle.addEventListener('touchend', handleInputEnd)
})
return function cleanup() {
document.removeEventListener('keydown', handleInputStart)
document.removeEventListener('keyup', handleInputEnd)
const paddles = document.querySelectorAll('.paddle')
paddles.forEach(paddle => {
paddle.removeEventListener('mousedown', handleInputStart)
paddle.removeEventListener('touchstart', handleInputStart)
paddle.removeEventListener('mouseout', handleInputEnd)
paddle.removeEventListener('mouseup', handleInputEnd)
paddle.removeEventListener('touchend', handleInputEnd)
})
clearHistory()
}
// eslint-disable-next-line
}, [])
useEffect(() => {
// PRACTICE MODE
if (morseCharBuffer.slice(-1) === '/' && gameMode === '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 useTelegraphKey

View file

@ -5,13 +5,16 @@ import App from './App';
import * as serviceWorker from './serviceWorker';
import {GameModeContextProvider} from "./contexts/gameModeContext"
import { KeyTypeContextProvider } from './contexts/keyTypeContext';
import { WPMContextProvider } from './contexts/wpmContext';
ReactDOM.render(
<KeyTypeContextProvider>
<GameModeContextProvider>
<App />
</GameModeContextProvider>
<WPMContextProvider>
<GameModeContextProvider>
<App />
</GameModeContextProvider>
</WPMContextProvider>
</KeyTypeContextProvider>
, document.getElementById('root'));