cloudlog/assets/js/winkey.js
Peter Goodhall d7da056ce3 Enable Enter key to send sendText messages
Add Enter key handling for the CW free-text input (sendText) so pressing Enter sends the message. Replaced the old 'message' keypress handler in footer.php with a DOMContentLoaded listener that binds keydown on #sendText and calls sendMyMessage() (preventing default). Also added matching keydown handling in assets/js/winkey.js to call clickSend() when Enter is pressed on the sendText element.
2026-05-14 22:36:19 +01:00

424 lines
12 KiB
JavaScript

// Lets see if CW is selected
const ModeSelected = document.getElementById('mode');
$('#winkey_buttons').hide();
if (location.protocol !== 'https:') {
// Do something if the page is being served over HTTP
$('#winkey').hide(); // Hide the CW buttons
}
function toggleWinkeyVisibility() {
const winkeyElement = document.getElementById('winkey');
if (ModeSelected && winkeyElement) {
if (ModeSelected.value === 'CW') {
$('#winkey').show();
} else {
$('#winkey').hide();
}
}
}
// Check initial mode
toggleWinkeyVisibility();
// Listen for mode changes
if (ModeSelected) {
ModeSelected.addEventListener('change', toggleWinkeyVisibility);
}
let function1Name, function1Macro, function2Name, function2Macro, function3Name, function3Macro, function4Name, function4Macro, function5Name, function5Macro;
getMacros();
document.addEventListener('keydown', function(event) {
if (event.key === 'F1') {
event.preventDefault();
morsekey_func1();
}
if (event.key === 'F2') {
event.preventDefault();
morsekey_func2();
}
if (event.key === 'F3') {
event.preventDefault();
morsekey_func3();
}
if (event.key === 'F4') {
event.preventDefault();
morsekey_func4();
}
if (event.key === 'F5') {
event.preventDefault();
morsekey_func5();
}
});
let sendText = document.getElementById("sendText");
let sendButton = document.getElementById("sendButton");
let receiveText = document.getElementById("receiveText");
let connectButton = document.getElementById("connectButton");
let statusBar = document.getElementById("statusBar");
//Couple the elements to the Events
if (connectButton) {
connectButton.addEventListener("click", clickConnect)
}
if (sendButton) {
sendButton.addEventListener("click", clickSend)
}
if (sendText) {
sendText.addEventListener("keydown", function(event) {
if (event.key === "Enter") {
event.preventDefault();
clickSend();
}
});
}
// statusButton.addEventListener("click", clickStatus)
//When the connectButton is pressed
async function clickConnect() {
if (port) {
//if already connected, disconnect
disconnect();
$('#winkey_buttons').hide();
} else {
//otherwise connect
await connect();
$('#winkey_buttons').show();
}
}
//Define outputstream, inputstream and port so they can be used throughout the sketch
var outputStream, inputStream, port;
// Auto-reconnect functionality
async function autoReconnect() {
try {
// Get previously connected ports
const ports = await navigator.serial.getPorts();
if (ports.length > 0) {
// Try to reconnect to the first available port
port = ports[0];
await port.open({ baudRate: 1200 });
await port.setSignals({ dataTerminalReady: true });
statusBar.innerText = "Auto-reconnected";
connectButton.innerText = "Disconnect";
let decoder = new TextDecoderStream();
inputDone = port.readable.pipeTo(decoder.writable);
inputStream = decoder.readable;
const encoder = new TextEncoderStream();
outputDone = encoder.readable.pipeTo(port.writable);
outputStream = encoder.writable;
writeToByte("0x00, 0x02");
writeToByte("0x02, 0x00");
$('#winkey_buttons').show();
reader = inputStream.getReader();
readLoop();
}
} catch (e) {
console.log("Auto-reconnect failed:", e);
// If auto-reconnect fails, just continue with normal flow
}
}
// Call auto-reconnect when page loads
window.addEventListener('load', autoReconnect);
navigator.serial.addEventListener('connect', e => {
statusBar.innerText = `Connected to ${e.port}`;
connectButton.innerText = "Disconnect"
});
navigator.serial.addEventListener('disconnect', e => {
statusBar.innerText = `Disconnected`;
connectButton.innerText = "Connect"
});
let debug = 0;
let speed = 24;
let minSpeed = 20;
let maxSpeed = 40;
//Connect to the serial
async function connect() {
//Optional filter to only see relevant boards
const filter = {
usbVendorId: 0x2341 // Arduino SA
};
//Try to connect to the Serial port
try {
port = await navigator.serial.requestPort(/*{ filters: [filter] }*/);
// Continue connecting to |port|.
// - Wait for the port to open.
await port.open({ baudRate: 1200 });
await port.setSignals({ dataTerminalReady: true });
statusBar.innerText = "Connected";
connectButton.innerText = "Disconnect"
let decoder = new TextDecoderStream();
inputDone = port.readable.pipeTo(decoder.writable);
inputStream = decoder.readable;
const encoder = new TextEncoderStream();
outputDone = encoder.readable.pipeTo(port.writable);
outputStream = encoder.writable;
writeToByte("0x00, 0x02");
writeToByte("0x02, 0x00");
$('#winkey_buttons').show();
reader = inputStream.getReader();
readLoop();
} catch (e) {
//If the pipeTo error appears; clarify the problem by giving suggestions.
if (e == "TypeError: Cannot read property 'pipeTo' of undefined") {
e += "\n Use Google Chrome and enable-experimental-web-platform-features"
}
connectButton.innerText = "Connect"
statusBar.innerText = e;
}
}
//Write to the Serial port
async function writeToStream(line) {
var enc = new TextEncoder(); // always utf-8
const writer = outputStream.getWriter();
writer.write(line);
writer.releaseLock();
}
async function writeToByte(line) {
const writer = outputStream.getWriter();
const data = new Uint8Array([line]);
writer.write(data);
writer.releaseLock();
}
//Disconnect from the Serial port
async function disconnect() {
if (reader) {
await reader.cancel();
await inputDone.catch(() => { });
reader = null;
inputDone = null;
}
if (outputStream) {
await outputStream.getWriter().close();
await outputDone;
outputStream = null;
outputDone = null;
}
statusBar.innerText = "Disconnected";
connectButton.innerText = "Connect"
//Close the port.
if (port) {
await port.close();
port = null;
}
}
//When the send button is pressed
function clickSend() {
const textToSend = sendText.value;
writeToStream(textToSend);
writeToStream("\r");
if (window.cloudlogCwSidetone) {
window.cloudlogCwSidetone.playText(textToSend, speed);
}
//and clear the input field, so it's clear it has been sent
sendText.value = "";
}
function morsekey_func1() {
const textToSend = UpdateMacros(function1Macro);
console.log("F1: " + textToSend);
writeToStream(textToSend);
if (window.cloudlogCwSidetone) {
window.cloudlogCwSidetone.playText(textToSend, speed);
}
//and clear the input field, so it's clear it has been sent
sendText.value = "";
}
function morsekey_func2() {
const textToSend = UpdateMacros(function2Macro);
console.log("F2: " + textToSend);
writeToStream(textToSend);
if (window.cloudlogCwSidetone) {
window.cloudlogCwSidetone.playText(textToSend, speed);
}
//and clear the input field, so it's clear it has been sent
sendText.value = "";
}
function morsekey_func3() {
const textToSend = UpdateMacros(function3Macro);
console.log("F3: " + textToSend);
writeToStream(textToSend);
if (window.cloudlogCwSidetone) {
window.cloudlogCwSidetone.playText(textToSend, speed);
}
//and clear the input field, so it's clear it has been sent
sendText.value = "";
}
function morsekey_func4() {
const textToSend = UpdateMacros(function4Macro);
console.log("F4: " + textToSend);
writeToStream(textToSend);
if (window.cloudlogCwSidetone) {
window.cloudlogCwSidetone.playText(textToSend, speed);
}
//and clear the input field, so it's clear it has been sent
sendText.value = "";
}
function morsekey_func5() {
const textToSend = UpdateMacros(function5Macro);
console.log("F5: " + textToSend);
writeToStream(textToSend);
if (window.cloudlogCwSidetone) {
window.cloudlogCwSidetone.playText(textToSend, speed);
}
//and clear the input field, so it's clear it has been sent
sendText.value = "";
}
//Read the incoming data
async function readLoop() {
while (true) {
const { value, done } = await reader.read();
if (done === true){
break;
}
console.log(value);
//When recieved something add it to the big textarea
receiveText.value += value;
//Scroll to the bottom of the text field
receiveText.scrollTop = receiveText.scrollHeight;
}
}
function closeModal() {
var container = document.getElementById("modals-here")
var backdrop = document.getElementById("modal-backdrop")
var modal = document.getElementById("modal")
modal.classList.remove("show")
backdrop.classList.remove("show")
getMacros();
setTimeout(function() {
container.removeChild(backdrop)
container.removeChild(modal)
}, 200)
}
function UpdateMacros(macrotext) {
// Get the values from the form set to uppercase
let CALL = document.getElementById("callsign").value.toUpperCase();
let RSTS = document.getElementById("rst_sent").value;
let newString;
newString = macrotext.replace(/\[MYCALL\]/g, my_call);
newString = newString.replace(/\[CALL\]/g, CALL);
newString = newString.replace(/\[RSTS\]/g, RSTS);
console.log(newString);
return newString;
}
// Call url and store the returned json data as variables
function getMacros() {
fetch(base_url + 'index.php/qso/cwmacros_json')
.then(response => {
if (!response.ok) {
throw new Error('HTTP ' + response.status + ': ' + response.statusText);
}
return response.json();
})
.then(data => {
// Handle case where no macros are saved yet
if (data.status === 'not found') {
// Set default values
function1Name = 'CQ';
function1Macro = 'CQ CQ CQ DE [MYCALL] [MYCALL] K';
function2Name = 'REPT';
function2Macro = '[CALL] DE [MYCALL] [RSTS] [RSTS] K';
function3Name = 'TU';
function3Macro = '[CALL] TU 73 DE [MYCALL] K';
function4Name = 'QRZ';
function4Macro = 'QRZ DE [MYCALL] K';
function5Name = 'TEST';
function5Macro = 'TEST DE [MYCALL] K';
} else {
// Use saved values or defaults if empty
function1Name = data.function1_name || 'F1';
function1Macro = data.function1_macro || '';
function2Name = data.function2_name || 'F2';
function2Macro = data.function2_macro || '';
function3Name = data.function3_name || 'F3';
function3Macro = data.function3_macro || '';
function4Name = data.function4_name || 'F4';
function4Macro = data.function4_macro || '';
function5Name = data.function5_name || 'F5';
function5Macro = data.function5_macro || '';
}
// Update button labels
const morsekey_func1_Button = document.getElementById('morsekey_func1');
if (morsekey_func1_Button) {
morsekey_func1_Button.textContent = 'F1 (' + function1Name + ')';
}
const morsekey_func2_Button = document.getElementById('morsekey_func2');
if (morsekey_func2_Button) {
morsekey_func2_Button.textContent = 'F2 (' + function2Name + ')';
}
const morsekey_func3_Button = document.getElementById('morsekey_func3');
if (morsekey_func3_Button) {
morsekey_func3_Button.textContent = 'F3 (' + function3Name + ')';
}
const morsekey_func4_Button = document.getElementById('morsekey_func4');
if (morsekey_func4_Button) {
morsekey_func4_Button.textContent = 'F4 (' + function4Name + ')';
}
const morsekey_func5_Button = document.getElementById('morsekey_func5');
if (morsekey_func5_Button) {
morsekey_func5_Button.textContent = 'F5 (' + function5Name + ')';
}
})
.catch(error => {
console.error('Error loading CW macros:', error);
});
}