Extend UDP Reply message with keyboard modifiers

This allows UDP servers to  emulate keyboard modified double-clicks on
decoded messages,  E.g. ALT+double-click for  replying to a CQ  or QRZ
call without changing ones Tx frequency offset.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@8103 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Bill Somerville 2017-09-22 15:36:24 +00:00
parent e1da6f6e16
commit 567af321c0
11 changed files with 43 additions and 21 deletions

View File

@ -152,12 +152,14 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
QByteArray mode; QByteArray mode;
QByteArray message; QByteArray message;
bool low_confidence {false}; 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) if (check_status (in) != Fail)
{ {
Q_EMIT self_->reply (time, snr, delta_time, delta_frequency Q_EMIT self_->reply (time, snr, delta_time, delta_frequency
, QString::fromUtf8 (mode), QString::fromUtf8 (message) , QString::fromUtf8 (mode), QString::fromUtf8 (message)
, low_confidence); , low_confidence, modifiers);
} }
} }
break; break;

View File

@ -72,7 +72,7 @@ public:
// this signal is emitted if the server sends us a reply, the only // this signal is emitted if the server sends us a reply, the only
// reply supported is reply to a prior CQ or QRZ message // 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 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 // this signal is emitted if the server has requested a replay of
// all decodes // all decodes

View File

@ -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); auto iter = m_->clients_.find (id);
if (iter != std::end (m_->clients_)) if (iter != std::end (m_->clients_))
@ -411,7 +413,7 @@ void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delt
QByteArray message; QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Reply, id, (*iter).negotiated_schema_number_}; NetworkMessage::Builder out {&message, NetworkMessage::Reply, id, (*iter).negotiated_schema_number_};
out << time << snr << delta_time << delta_frequency << mode.toUtf8 () 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_); m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
} }
} }

View File

@ -46,7 +46,7 @@ public:
// note that the client is not obliged to take any action and only // 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 // 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 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 // ask the client with identification 'id' to replay all decodes
Q_SLOT void replay (QString const& id); Q_SLOT void replay (QString const& id);

View File

@ -157,7 +157,7 @@
* Mode utf8 * Mode utf8
* Message utf8 * Message utf8
* Low confidence bool * Low confidence bool
* Off air bool * Off air bool
* *
* The decode message is sent when a new decode is completed, in * 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 * this case the 'New' field is true. It is also used in response
@ -193,6 +193,7 @@
* Mode utf8 * Mode utf8
* Message utf8 * Message utf8
* Low confidence bool * Low confidence bool
* Modifiers quint8
* *
* In order for a server to provide a useful cooperative service * 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 * 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 * initiation the rest of the QSO is carried out manually using
* the normal WSJT-X user interface. * 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 * QSO Logged Out 5 quint32
* Id (unique key) utf8 * Id (unique key) utf8

View File

@ -208,7 +208,7 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
// connect up table view signals // connect up table view signals
connect (decodes_table_view_, &QTableView::doubleClicked, this, [this] (QModelIndex const& index) { 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);
}); });
} }

View File

@ -39,7 +39,7 @@ public:
, QString const& callsign, QString const& grid, qint32 power , QString const& callsign, QString const& grid, qint32 power
, bool off_air); , 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_halt_tx (QString const& id, bool auto_only);
Q_SIGNAL void do_free_text (QString const& id, QString const& text, bool); Q_SIGNAL void do_free_text (QString const& id, QString const& text, bool);

View File

@ -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 (); auto row = source.row ();
Q_EMIT reply (data (index (row, 0)).toString () Q_EMIT reply (data (index (row, 0)).toString ()
@ -146,7 +146,8 @@ void DecodesModel::do_reply (QModelIndex const& source)
, item (row, 4)->data ().toInt () , item (row, 4)->data ().toInt ()
, data (index (row, 5)).toString () , data (index (row, 5)).toString ()
, data (index (row, 6)).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" #include "moc_DecodesModel.cpp"

View File

@ -35,10 +35,10 @@ public:
, quint32 delta_frequency, QString const& mode, QString const& message , quint32 delta_frequency, QString const& mode, QString const& message
, bool low_confidence, bool off_air, bool is_fast); , bool low_confidence, bool off_air, bool is_fast);
Q_SLOT void clear_decodes (QString const& client_id); 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 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 #endif

View File

@ -6130,7 +6130,9 @@ void MainWindow::on_cbTx6_toggled(bool)
} }
// Takes a decoded CQ line and sets it up for reply // 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 ()) 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 ))"})) if (message_text.contains (QRegularExpression {R"(^(CQ |CQDX |QRZ ))"}))
{ {
// a message we are willing to accept // 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 const& time_string = time.toString ("~" == mode || "&" == mode ? "hhmmss" : "hhmm");
auto cqtext = format_string auto cqtext = format_string
.arg (time_string) .arg (time_string)
.arg (snr, 3) .arg (snr, 3)
.arg (delta_time, 4, 'f', 1) .arg (delta_time, 4, 'f', 1)
.arg (delta_frequency, 4) .arg (delta_frequency, 4)
.arg (mode) .arg (mode, 2)
.arg (message_text); .arg (message_text);
auto messages = ui->decodedTextBrowser->toPlainText (); auto messages = ui->decodedTextBrowser->toPlainText ();
auto position = messages.lastIndexOf (cqtext); 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 (snr, 3)
.arg ('-' + QString::number (delta_time, 'f', 1), 4) .arg ('-' + QString::number (delta_time, 'f', 1), 4)
.arg (delta_frequency, 4) .arg (delta_frequency, 4)
.arg (mode) .arg (mode, 2)
.arg (message_text)); .arg (message_text));
} }
if (position >= 0) if (position >= 0)
@ -6180,8 +6182,9 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de
m_bDoubleClicked = true; m_bDoubleClicked = true;
auto start = messages.left (position).lastIndexOf (QChar::LineFeed) + 1; auto start = messages.left (position).lastIndexOf (QChar::LineFeed) + 1;
DecodedText message {messages.mid (start, position - start), ("MSK144" == m_mode || "FT8" == m_mode) && DecodedText message {messages.mid (start, position - start), ("MSK144" == m_mode || "FT8" == m_mode) &&
ui->cbVHFcontest->isChecked(), m_config.my_grid ()}; ui->cbVHFcontest->isChecked(), m_config.my_grid ()};
processMessage (message); Qt::KeyboardModifiers kbmod {modifiers << 24};
processMessage (message, kbmod & Qt::ControlModifier,kbmod & Qt::AltModifier);
tx_watchdog (false); tx_watchdog (false);
QApplication::alert (this); QApplication::alert (this);
} }
@ -6239,7 +6242,7 @@ void MainWindow::postDecode (bool is_new, QString const& message)
m_messageClient->decode (is_new m_messageClient->decode (is_new
, QTime::fromString (parts[0], has_seconds ? "hhmmss" : "hhmm") , QTime::fromString (parts[0], has_seconds ? "hhmmss" : "hhmm")
, parts[1].toInt () , 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) , decode.mid (has_seconds ? 24 : 22, 21)
, QChar {'?'} == decode.mid (has_seconds ? 24 + 21 : 22 + 21, 1) , QChar {'?'} == decode.mid (has_seconds ? 24 + 21 : 22 + 21, 1)
, m_diskData); , m_diskData);

View File

@ -597,7 +597,7 @@ private:
void displayDialFrequency (); void displayDialFrequency ();
void transmitDisplay (bool); void transmitDisplay (bool);
void processMessage(DecodedText const&, bool ctrl = false, bool alt = false); 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 replayDecodes ();
void postDecode (bool is_new, QString const& message); void postDecode (bool is_new, QString const& message);
void postWSPRDecode (bool is_new, QStringList message_parts); void postWSPRDecode (bool is_new, QStringList message_parts);