diff --git a/MessageClient.cpp b/MessageClient.cpp index 3227bdd9c..4c031a7d7 100644 --- a/MessageClient.cpp +++ b/MessageClient.cpp @@ -152,12 +152,14 @@ void MessageClient::impl::parse_message (QByteArray const& msg) QByteArray mode; QByteArray message; bool low_confidence {false}; - in >> time >> snr >> delta_time >> delta_frequency >> mode >> message >> low_confidence; + quint8 modifiers {0}; + in >> time >> snr >> delta_time >> delta_frequency >> mode >> message + >> low_confidence >> modifiers; if (check_status (in) != Fail) { Q_EMIT self_->reply (time, snr, delta_time, delta_frequency , QString::fromUtf8 (mode), QString::fromUtf8 (message) - , low_confidence); + , low_confidence, modifiers); } } break; diff --git a/MessageClient.hpp b/MessageClient.hpp index 6fe1903af..d641a66d7 100644 --- a/MessageClient.hpp +++ b/MessageClient.hpp @@ -72,7 +72,7 @@ public: // this signal is emitted if the server sends us a reply, the only // reply supported is reply to a prior CQ or QRZ message Q_SIGNAL void reply (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode - , QString const& message_text, bool low_confidence); + , QString const& message_text, bool low_confidence, quint8 modifiers); // this signal is emitted if the server has requested a replay of // all decodes diff --git a/MessageServer.cpp b/MessageServer.cpp index 8825e20a3..39b4b1d5b 100644 --- a/MessageServer.cpp +++ b/MessageServer.cpp @@ -403,7 +403,9 @@ void MessageServer::start (port_type port, QHostAddress const& multicast_group_a } } -void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text, bool low_confidence) +void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delta_time + , quint32 delta_frequency, QString const& mode + , QString const& message_text, bool low_confidence, quint8 modifiers) { auto iter = m_->clients_.find (id); if (iter != std::end (m_->clients_)) @@ -411,7 +413,7 @@ void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delt QByteArray message; NetworkMessage::Builder out {&message, NetworkMessage::Reply, id, (*iter).negotiated_schema_number_}; out << time << snr << delta_time << delta_frequency << mode.toUtf8 () - << message_text.toUtf8 () << low_confidence; + << message_text.toUtf8 () << low_confidence << modifiers; m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); } } diff --git a/MessageServer.hpp b/MessageServer.hpp index 33a0c6b0b..f78d07d16 100644 --- a/MessageServer.hpp +++ b/MessageServer.hpp @@ -46,7 +46,7 @@ public: // note that the client is not obliged to take any action and only // takes any action if the decode is present and is a CQ or QRZ message Q_SLOT void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency - , QString const& mode, QString const& message, bool low_confidence); + , QString const& mode, QString const& message, bool low_confidence, quint8 modifiers); // ask the client with identification 'id' to replay all decodes Q_SLOT void replay (QString const& id); diff --git a/NetworkMessage.hpp b/NetworkMessage.hpp index 67d19f221..e59a9a4ba 100644 --- a/NetworkMessage.hpp +++ b/NetworkMessage.hpp @@ -157,7 +157,7 @@ * Mode utf8 * Message utf8 * Low confidence bool - * Off air bool + * Off air bool * * The decode message is sent when a new decode is completed, in * this case the 'New' field is true. It is also used in response @@ -193,6 +193,7 @@ * Mode utf8 * Message utf8 * Low confidence bool + * Modifiers quint8 * * In order for a server to provide a useful cooperative service * to WSJT-X it is possible for it to initiate a QSO by sending @@ -209,6 +210,19 @@ * initiation the rest of the QSO is carried out manually using * the normal WSJT-X user interface. * + * The Modifiers field allows the equivalent of keyboard + * modifiers to be sent "as if" those modifier keys where pressed + * while double-clicking the specified decoded message. The + * modifier values (hexadecimal) are as follows: + * + * no modifier 0x00 + * SHIFT 0x02 + * CTRL 0x04 CMD on Mac + * ALT 0x08 + * META 0x10 Windows key on MS Windows + * KEYPAD 0x20 Keypad or arrows + * Group switch 0x40 X11 only + * * * QSO Logged Out 5 quint32 * Id (unique key) utf8 diff --git a/UDPExamples/ClientWidget.cpp b/UDPExamples/ClientWidget.cpp index 0e101fdf9..357875327 100644 --- a/UDPExamples/ClientWidget.cpp +++ b/UDPExamples/ClientWidget.cpp @@ -208,7 +208,7 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod // connect up table view signals connect (decodes_table_view_, &QTableView::doubleClicked, this, [this] (QModelIndex const& index) { - Q_EMIT do_reply (decodes_proxy_model_.mapToSource (index)); + Q_EMIT do_reply (decodes_proxy_model_.mapToSource (index), QApplication::keyboardModifiers () >> 24); }); } diff --git a/UDPExamples/ClientWidget.hpp b/UDPExamples/ClientWidget.hpp index 6f43e9a0c..37126520e 100644 --- a/UDPExamples/ClientWidget.hpp +++ b/UDPExamples/ClientWidget.hpp @@ -39,7 +39,7 @@ public: , QString const& callsign, QString const& grid, qint32 power , bool off_air); - Q_SIGNAL void do_reply (QModelIndex const&); + Q_SIGNAL void do_reply (QModelIndex const&, quint8 modifier); Q_SIGNAL void do_halt_tx (QString const& id, bool auto_only); Q_SIGNAL void do_free_text (QString const& id, QString const& text, bool); diff --git a/UDPExamples/DecodesModel.cpp b/UDPExamples/DecodesModel.cpp index f442003d0..bf1acf9b8 100644 --- a/UDPExamples/DecodesModel.cpp +++ b/UDPExamples/DecodesModel.cpp @@ -136,7 +136,7 @@ void DecodesModel::clear_decodes (QString const& client_id) } } -void DecodesModel::do_reply (QModelIndex const& source) +void DecodesModel::do_reply (QModelIndex const& source, quint8 modifiers) { auto row = source.row (); Q_EMIT reply (data (index (row, 0)).toString () @@ -146,7 +146,8 @@ void DecodesModel::do_reply (QModelIndex const& source) , item (row, 4)->data ().toInt () , data (index (row, 5)).toString () , data (index (row, 6)).toString () - , confidence_string (true) == data (index (row, 7)).toString ()); + , confidence_string (true) == data (index (row, 7)).toString () + , modifiers); } #include "moc_DecodesModel.cpp" diff --git a/UDPExamples/DecodesModel.hpp b/UDPExamples/DecodesModel.hpp index b028d60e5..fa51732bf 100644 --- a/UDPExamples/DecodesModel.hpp +++ b/UDPExamples/DecodesModel.hpp @@ -35,10 +35,10 @@ public: , quint32 delta_frequency, QString const& mode, QString const& message , bool low_confidence, bool off_air, bool is_fast); Q_SLOT void clear_decodes (QString const& client_id); - Q_SLOT void do_reply (QModelIndex const& source); + Q_SLOT void do_reply (QModelIndex const& source, quint8 modifiers); Q_SIGNAL void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency - , QString const& mode, QString const& message, bool low_confidence); + , QString const& mode, QString const& message, bool low_confidence, quint8 modifiers); }; #endif diff --git a/mainwindow.cpp b/mainwindow.cpp index 7ba61d3f1..57b11986e 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -6130,7 +6130,9 @@ void MainWindow::on_cbTx6_toggled(bool) } // Takes a decoded CQ line and sets it up for reply -void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text) +void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 delta_frequency + , QString const& mode, QString const& message_text + , bool /*low_confidence*/, quint8 modifiers) { if (!m_config.accept_udp_requests ()) { @@ -6140,14 +6142,14 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de if (message_text.contains (QRegularExpression {R"(^(CQ |CQDX |QRZ ))"})) { // a message we are willing to accept - QString format_string {"%1 %2 %3 %4 %5 %6"}; + QString format_string {"%1 %2 %3 %4 %5 %6"}; auto const& time_string = time.toString ("~" == mode || "&" == mode ? "hhmmss" : "hhmm"); auto cqtext = format_string .arg (time_string) .arg (snr, 3) .arg (delta_time, 4, 'f', 1) .arg (delta_frequency, 4) - .arg (mode) + .arg (mode, 2) .arg (message_text); auto messages = ui->decodedTextBrowser->toPlainText (); auto position = messages.lastIndexOf (cqtext); @@ -6159,7 +6161,7 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de .arg (snr, 3) .arg ('-' + QString::number (delta_time, 'f', 1), 4) .arg (delta_frequency, 4) - .arg (mode) + .arg (mode, 2) .arg (message_text)); } if (position >= 0) @@ -6180,8 +6182,9 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de m_bDoubleClicked = true; auto start = messages.left (position).lastIndexOf (QChar::LineFeed) + 1; DecodedText message {messages.mid (start, position - start), ("MSK144" == m_mode || "FT8" == m_mode) && - ui->cbVHFcontest->isChecked(), m_config.my_grid ()}; - processMessage (message); + ui->cbVHFcontest->isChecked(), m_config.my_grid ()}; + Qt::KeyboardModifiers kbmod {modifiers << 24}; + processMessage (message, kbmod & Qt::ControlModifier,kbmod & Qt::AltModifier); tx_watchdog (false); QApplication::alert (this); } @@ -6239,7 +6242,7 @@ void MainWindow::postDecode (bool is_new, QString const& message) m_messageClient->decode (is_new , QTime::fromString (parts[0], has_seconds ? "hhmmss" : "hhmm") , parts[1].toInt () - , parts[2].toFloat (), parts[3].toUInt (), parts[4][0] + , parts[2].toFloat (), parts[3].toUInt (), parts[4] , decode.mid (has_seconds ? 24 : 22, 21) , QChar {'?'} == decode.mid (has_seconds ? 24 + 21 : 22 + 21, 1) , m_diskData); diff --git a/mainwindow.h b/mainwindow.h index cbfdb9d24..7c8d2028a 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -597,7 +597,7 @@ private: void displayDialFrequency (); void transmitDisplay (bool); void processMessage(DecodedText const&, bool ctrl = false, bool alt = false); - void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text); + void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text, bool low_confidence, quint8 modifiers); void replayDecodes (); void postDecode (bool is_new, QString const& message); void postWSPRDecode (bool is_new, QStringList message_parts);