diff --git a/README.md b/README.md index 8f2975d..3c4d095 100644 --- a/README.md +++ b/README.md @@ -29,3 +29,13 @@ Type in the translator below the legend and see/listen to the Morse translation. This web app was built using HTML, CSS, and ReactJS. It utilizes React hooks to manage state and component lifecycle. See it live here: https://genemecija.github.io/learn-morse-code/ + +## Build Instructions + +To build and run the project: + +```bash +cd src/ +npm install +npm start +``` \ No newline at end of file diff --git a/src/components/Info.js b/src/components/Info.js index 12d3679..0a77cc9 100644 --- a/src/components/Info.js +++ b/src/components/Info.js @@ -39,7 +39,7 @@ export default React.memo(function Info() {
Straight Key

Straight Keys use a single button and generate tones when pressed down. Straight keys require greater accuracy as the length of dits, dahs, and spacing is completely under manual control.

Electronic Key
-

Electronic Keys use paddles that automatically generate dits and dahs when pressed. The Electronic Keyer used here is an Iambic keyer that uses two paddles–left paddle for dits, right paddle for dahs. Pressing both paddles simultaneously automatically alternates between dit and dah. Switch between the two paddles at the appropriate times to build letters in Morse code.

+

Electronic Keys use paddles that automatically generate dits and dahs when pressed. The Electronic Keyer used here is an Iambic keyer that uses two paddles–left paddle for dits, right paddle for dahs. Pressing both paddles simultaneously automatically alternates between dit and dah. Mode B automatically adds an extra alternate dit or dah. Switch between the two paddles at the appropriate times to build letters in Morse code.

Check out this video for a demonstration of the difference between Straight and Electronic keys.

diff --git a/src/components/KeyTypePicker.js b/src/components/KeyTypePicker.js index 4f92133..26737bf 100644 --- a/src/components/KeyTypePicker.js +++ b/src/components/KeyTypePicker.js @@ -8,26 +8,36 @@ export default React.memo(function KeyTypePicker() { function handleClick(e) { setKeyType(e.target.id) - - let buttons = document.querySelector(".mode-picker#keyType #buttons").childNodes - buttons.forEach(button => { - if (button.id === e.target.id) { - button.classList.add('selected') - } else { button.classList.remove('selected')} - }) - - if (e.target.id === 'electronic') { - document.querySelector('#morseButton').classList.add('showPaddles') - document.querySelector('.paddle').classList.add('showPaddles') - document.querySelector('.paddle#left').classList.add('showPaddles') - document.querySelector('.paddle#right').classList.add('showPaddles') - document.getElementById('morseButtonText').innerHTML = 'TAP/HOLD BUTTONS OR PRESS COMMA / PERIOD' - } else { - document.querySelector('#morseButton').classList.remove('showPaddles') - document.querySelector('.paddle').classList.remove('showPaddles') - document.querySelector('.paddle#left').classList.remove('showPaddles') - document.querySelector('.paddle#right').classList.remove('showPaddles') - document.getElementById('morseButtonText').innerHTML = 'TAP BUTTON OR PRESS SPACEBAR' + switch (e.target.id) + { + case 'straight': + e.target.classList.add('selected'); + document.getElementById('electronic').classList.remove('selected') + document.querySelector('#morseButton').classList.remove('showPaddles') + document.querySelector('.paddle').classList.remove('showPaddles') + document.querySelector('.paddle#left').classList.remove('showPaddles') + document.querySelector('.paddle#right').classList.remove('showPaddles') + document.getElementById('paddle-mode-buttons').style.visibility = 'hidden' + document.getElementById('morseButtonText').innerHTML = 'TAP BUTTON OR PRESS SPACEBAR' + break; + case 'electronic': + e.target.classList.add('selected'); + document.getElementById('straight').classList.remove('selected') + document.querySelector('#morseButton').classList.add('showPaddles') + document.querySelector('.paddle').classList.add('showPaddles') + document.querySelector('.paddle#left').classList.add('showPaddles') + document.querySelector('.paddle#right').classList.add('showPaddles') + document.getElementById('paddle-mode-buttons').style.visibility = 'visible' + document.getElementById('morseButtonText').innerHTML = 'TAP/HOLD BUTTONS OR PRESS COMMA / PERIOD' + break + case 'modeA': + e.target.classList.add('selected') + document.getElementById('modeB').classList.remove('selected') + break; + case 'modeB': + e.target.classList.add('selected') + document.getElementById('modeA').classList.remove('selected') + break; } } @@ -41,7 +51,7 @@ export default React.memo(function KeyTypePicker() {
Key Type
-
+
@@ -49,6 +59,18 @@ export default React.memo(function KeyTypePicker() { Electronic Key
+
+
+ Paddle Mode + + +
+
+
) }) \ No newline at end of file diff --git a/src/css/App.css b/src/css/App.css index 2aeed31..32c73d5 100644 --- a/src/css/App.css +++ b/src/css/App.css @@ -13,6 +13,23 @@ button { font-family: "Roboto", sans-serif; } +legend { + font-family: "Roboto", sans-serif; + font-size: x-small; + font-weight: bold; + margin: 0.3em; +} + +fieldset { + border: 1px solid darkgray; + padding-bottom: 0.3em; + margin-top: -0.5em; +} + +#paddle-mode-buttons { + visibility: hidden; +} + html, body { height: 100%; width: 100vw; diff --git a/src/hooks/useElectronicKey.js b/src/hooks/useElectronicKey.js index 7652b51..bdf8ac3 100644 --- a/src/hooks/useElectronicKey.js +++ b/src/hooks/useElectronicKey.js @@ -27,6 +27,7 @@ export default (function useElectronicKey() { let queueRunning = false let queue = [] let pressedFirst = null + let lastPlayed = '' // Timers setup let depressSyncTime @@ -51,6 +52,7 @@ export default (function useElectronicKey() { // Promisify playing Dits and Dahs function play(ditDah) { + lastPlayed = ditDah let playDuration = ((ditDah === '.') ? ditMaxTime : ditMaxTime*3) return new Promise((resolve, reject) => { @@ -159,7 +161,11 @@ export default (function useElectronicKey() { cleanup() } currentPromise = currentPromise.then(() => { - return playWithSpaces(localQueue[i]) + var ditDah = localQueue[i] + if (ditDah) + { + return playWithSpaces(ditDah) + } }); } } @@ -237,7 +243,6 @@ export default (function useElectronicKey() { document.querySelector('.paddle#left').classList.remove('active') leftIsPressed = false - if (pressedFirst === 'left') { pressedFirst = null } if (!depressSyncTimerRunning) { startDepressSyncTimer() } @@ -252,6 +257,13 @@ export default (function useElectronicKey() { if (!depressSyncTimerRunning) { startDepressSyncTimer() } else { stopDepressSyncTimer() } } + + if (paddlesReleasedSimultaneously && document.getElementById('modeB').classList.contains('selected')) + { + currentPromise = currentPromise.then(() => { + return playWithSpaces(lastPlayed == '.' ? '-' : '.') + }); + } } // Timer used to determine if both paddles are released within 10ms