1
0
forked from BRT/arc
arc/VideoWindow.cpp
2025-05-24 15:19:27 +07:00

147 lines
5.0 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "VideoWindow.h"
#include <QVBoxLayout>
enum : uint8_t {
CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT = 2,
ACTION_DOWN = 0,
ACTION_UP = 1,
ACTION_MOVE = 2,
};
// Вспомогательная запись BE-целых
static void write32BE(QByteArray &buf, uint32_t v) {
buf.append(char((v >> 24) & 0xFF));
buf.append(char((v >> 16) & 0xFF));
buf.append(char((v >> 8) & 0xFF));
buf.append(char((v) & 0xFF));
}
static void write16BE(QByteArray &buf, uint16_t v) {
buf.append(char((v >> 8) & 0xFF));
buf.append(char((v) & 0xFF));
}
static constexpr uint8_t SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT = 2;
static constexpr uint32_t AMOTION_EVENT_BUTTON_PRIMARY = 1;
void VideoWindow::sendTouch(uint8_t action, const QPoint &pos) {
if (m_controlSocket->state() != QAbstractSocket::ConnectedState) {
return;
}
// 1) Подготовка буфера нужного размера
QByteArray ba;
ba.reserve(32);
// 2) Хелперы для записи
auto write8 = [&](uint8_t v) { ba.append(char(v)); };
auto write16 = [&](uint16_t v) {
ba.append(char((v >> 8) & 0xFF));
ba.append(char(v & 0xFF));
};
auto write32 = [&](uint32_t v) {
ba.append(char((v >> 24) & 0xFF));
ba.append(char((v >> 16) & 0xFF));
ba.append(char((v >> 8) & 0xFF));
ba.append(char(v & 0xFF));
};
auto write64 = [&](quint64 v) {
for (int shift = 56; shift >= 0; shift -= 8) {
ba.append(char((v >> shift) & 0xFF));
}
};
// 3) Нормализация координат от QLabel → реальные
QSize lbl = m_videoLabel->size();
quint32 x = quint32(double(pos.x()) * m_originalWidth / lbl.width());
quint32 y = quint32(double(pos.y()) * m_originalHeight / lbl.height());
// 4) Сборка пакета по спецификации (32 байта):
write8(SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT); // 1 байт: тип сообщения
write8(action); // 1 байт: action (DOWN=0, UP=1, MOVE=2)
write64(0); // 8 байт: pointerId = 0
write32(x); // 4 байта: position.x
write32(y); // 4 байта: position.y
write16(uint16_t(m_originalWidth)); // 2 байта: screenWidth
write16(uint16_t(m_originalHeight)); // 2 байта: screenHeight
// pressure: float [0;1] → int16 [0;0x7FFF]
{
int16_t p16 = int16_t(1.0f * 0x7FFF);
write16(uint16_t(p16)); // 2 байта: pressure
}
write32(AMOTION_EVENT_BUTTON_PRIMARY); // 4 байта: action_button
write32(AMOTION_EVENT_BUTTON_PRIMARY); // 4 байта: buttons
// 5) Проверка длины и отправка
const int len = ba.size();
qDebug() << "Packed touch event size =" << len;
Q_ASSERT(len == 32);
if (len != 32) {
qWarning() << "Wrong packet length, aborting send.";
return;
}
m_controlSocket->write(ba);
m_controlSocket->flush();
}
void VideoWindow::mousePressEvent(QMouseEvent *ev) {
sendTouch(ACTION_DOWN, ev->pos());
}
void VideoWindow::mouseMoveEvent(QMouseEvent *ev) {
sendTouch(ACTION_MOVE, ev->pos());
}
void VideoWindow::mouseReleaseEvent(QMouseEvent *ev) {
sendTouch(ACTION_UP, ev->pos());
}
VideoWindow::VideoWindow(QWidget *parent): QMainWindow(parent) {
setFixedSize(360, 800);
QWidget *central = new QWidget(this);
setCentralWidget(central);
QVBoxLayout *layout = new QVBoxLayout(central);
m_videoLabel = new QLabel(this);
m_videoLabel->setAlignment(Qt::AlignCenter);
m_videoLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_videoLabel->setScaledContents(true);
layout->addWidget(m_videoLabel);
layout->setContentsMargins(0, 0, 0, 0);
m_receiver = new VideoReceiver(this);
connect(m_receiver, &VideoReceiver::frameReady, this, [&](const QImage &img) {
if (m_originalWidth == 0) {
m_originalWidth = img.width();
m_originalHeight = img.height();
}
QPixmap scaled = QPixmap::fromImage(img).scaled(m_videoLabel->size(), Qt::KeepAspectRatio,
Qt::SmoothTransformation);
m_videoLabel->setPixmap(scaled);
});
m_receiver->start();
// В конструкторе VideoWindow:
m_controlSocket = new QTcpSocket(this);
m_controlSocket->connectToHost("127.0.0.1", 27184);
if (!m_controlSocket->waitForConnected(3000)) {
qWarning() << "Cannot connect to control socket";
} else {
qDebug() << "Connected to control socket";
}
connect(m_controlSocket, &QTcpSocket::readyRead, this, [this]() {
m_controlSocket->readAll(); // важно «чистить» буфер
});
}
VideoWindow::~VideoWindow() {
m_receiver->wait();
}