Rabbit Remote Control 0.0.30
Loading...
Searching...
No Matches
ConnectDesktop.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QApplication>
4#include <QClipboard>
5#include <QTimer>
6#include <QLoggingCategory>
7#include <QWheelEvent>
8#include <QVideoFrame>
9#include <QDesktopServices>
10
11#include "ConnectDesktop.h"
12#include "ConnecterThread.h"
13
14static Q_LOGGING_CATEGORY(log, "Client.Connect.Desktop")
15static Q_LOGGING_CATEGORY(logMouse, "Client.Connect.Desktop.Mouse")
16
17#define TypeRecordVideo (QEvent::User + 1)
18class QRecordVideoEvent : public QEvent
19{
20public:
21 QRecordVideoEvent(const QImage& img): QEvent((QEvent::Type)TypeRecordVideo)
22 {
23 m_Image = img;
24 }
25 QImage GetImage()
26 {
27 return m_Image;
28 }
29private:
30 QImage m_Image;
31};
32
33int g_QtKeyboardModifiers = qRegisterMetaType<Qt::KeyboardModifiers>("KeyboardModifiers");
34int g_QtMouseButtons = qRegisterMetaType<Qt::MouseButtons>("MouseButtons");
35int g_QtMouseButton = qRegisterMetaType<Qt::MouseButton>("MouseButton");
36int g_QMessageBox_Icon = qRegisterMetaType<Qt::MouseButton>("QMessageBox::Icon");
37
38CConnectDesktop::CConnectDesktop(CConnecter *pConnecter, bool bDirectConnection)
39 : CConnect(pConnecter)
40#if HAVE_QT6_RECORD
41 , m_pParameterRecord(nullptr)
42 , m_VideoFrameInput(this)
43 , m_AudioBufferInput(this)
44 , m_AudioBufferOutput(this)
45#endif
46{
47 if(pConnecter) {
48 CFrmScroll* pScroll = qobject_cast<CFrmScroll*>(pConnecter->GetViewer());
49 if(pScroll) {
50 CFrmViewer* pView = pScroll->GetViewer();
51 if(pView)
52 SetViewer(pView, bDirectConnection);
53 } else {
54 QString szErr = pConnecter->metaObject()->className();
55 szErr += "::GetViewer() is not CFrmView";
56 qDebug(log) << szErr.toStdString().c_str();
57 }
58 SetConnecter(pConnecter);
59 }
60
61#if HAVE_QT6_RECORD
62 bool check = connect(
63 &m_Recorder, &QMediaRecorder::errorOccurred,
64 this, [&](QMediaRecorder::Error error, const QString &errorString) {
65 qDebug(log) << "Recorder error occurred:" << error << errorString;
66 slotRecord(false);
67 emit sigError(error, errorString);
68 });
69 Q_ASSERT(check);
70 check = connect(
71 &m_Recorder, &QMediaRecorder::recorderStateChanged,
72 this, [&](QMediaRecorder::RecorderState state){
73 qDebug(log) << "Recorder state changed:" << state;
74 if(QMediaRecorder::StoppedState == state)
75 {
76 slotRecord(false);
77 if(m_pParameterRecord) {
78 qDebug(log) << "End action:"
79 << m_pParameterRecord->GetEndAction()
80 << m_Recorder.actualLocation();
81 switch(m_pParameterRecord->GetEndAction())
82 {
83 case CParameterRecord::ENDACTION::OpenFile:
84 QDesktopServices::openUrl(m_Recorder.actualLocation());
85 break;
86 case CParameterRecord::ENDACTION::OpenFolder: {
87 QFileInfo fi(m_Recorder.actualLocation().toLocalFile());
88 QDesktopServices::openUrl(
89 QUrl::fromLocalFile(fi.absolutePath()));
90 break;
91 }
92 default:
93 break;
94 }
95 }
96 }
97 });
98 Q_ASSERT(check);
99 check = connect(&m_Recorder, &QMediaRecorder::actualLocationChanged,
100 this, [&](const QUrl &location){
101 qInfo(log) << "Recorder actual location changed:" << location;
102 });
103 Q_ASSERT(check);
104#endif
105}
106
107CConnectDesktop::~CConnectDesktop()
108{
109 qDebug(log) << "CConnectDesktop::~CConnectDesktop()";
110}
111
112int CConnectDesktop::SetConnecter(CConnecter* pConnecter)
113{
114 qDebug(log) << "CConnectDesktop::SetConnecter" << pConnecter;
115 Q_ASSERT(pConnecter);
116 if(!pConnecter) return -1;
117
118 bool check = false;
119 check = connect(this, SIGNAL(sigServerName(const QString&)),
120 pConnecter, SLOT(slotSetServerName(const QString&)));
121 Q_ASSERT(check);
122 check = connect(pConnecter, SIGNAL(sigClipBoardChanged()),
123 this, SLOT(slotClipBoardChanged()));
124 Q_ASSERT(check);
125 check = connect(this, SIGNAL(sigSetClipboard(QMimeData*)),
126 pConnecter, SLOT(slotSetClipboard(QMimeData*)));
127 Q_ASSERT(check);
128#if HAVE_QT6_RECORD
129 CConnecterThread* p = qobject_cast<CConnecterThread*>(pConnecter);
130 if(p) {
131 m_pParameterRecord = &p->GetParameter()->m_Record;
132 check = connect(p, SIGNAL(sigRecord(bool)),
133 this, SLOT(slotRecord(bool)));
134 Q_ASSERT(check);
135
136 check = connect(p, SIGNAL(sigRecordPause(bool)),
137 this, SLOT(slotRecordPause(bool)));
138 Q_ASSERT(check);
139 check = connect(
140 &m_Recorder,
141 SIGNAL(recorderStateChanged(QMediaRecorder::RecorderState)),
142 p, SLOT(slotRecorderStateChanged(QMediaRecorder::RecorderState)));
143 Q_ASSERT(check);
144 }
145#endif
146 return 0;
147}
148
149int CConnectDesktop::SetViewer(CFrmViewer *pView, bool bDirectConnection)
150{
151 Q_ASSERT(pView);
152 if(!pView) return -1;
153
154 bool check = false;
155 check = connect(this, SIGNAL(sigConnected()), pView, SLOT(slotConnected()));
156 Q_ASSERT(check);
157 check = connect(this, SIGNAL(sigSetDesktopSize(int, int)),
158 pView, SLOT(slotSetDesktopSize(int, int)));
159 Q_ASSERT(check);
160 check = connect(this, SIGNAL(sigServerName(const QString&)),
161 pView, SLOT(slotSetName(const QString&)));
162 Q_ASSERT(check);
163
164 check = connect(this, SIGNAL(sigUpdateRect(const QRect&, const QImage&)),
165 pView, SLOT(slotUpdateRect(const QRect&, const QImage&)));
166 Q_ASSERT(check);
167 check = connect(this, SIGNAL(sigUpdateRect(const QImage&)),
168 pView, SLOT(slotUpdateRect(const QImage&)));
169 Q_ASSERT(check);
170 check = connect(this, SIGNAL(sigUpdateCursor(const QCursor&)),
171 pView, SLOT(slotUpdateCursor(const QCursor&)));
172 Q_ASSERT(check);
173 check = connect(this, SIGNAL(sigUpdateCursorPosition(const QPoint&)),
174 pView, SLOT(slotUpdateCursorPosition(const QPoint&)));
175 Q_ASSERT(check);
176 check = connect(this, SIGNAL(sigUpdateLedState(unsigned int)),
177 pView, SLOT(slotUpdateLedState(unsigned int)));
178 Q_ASSERT(check);
179#if HAVE_QT6_RECORD
180 check = connect(this, SIGNAL(sigRecordVideo(bool)),
181 pView, SLOT(slotRecordVideo(bool)));
182 Q_ASSERT(check);
183 check = connect(pView, SIGNAL(sigRecordVideo(QImage)),
184 this, SLOT(slotRecordVideo(QImage)),
185 Qt::DirectConnection);
186 Q_ASSERT(check);
187#endif
188 if(bDirectConnection)
189 {
190 /* \~chinese 因为连接可能是在另一个线程中的非Qt事件处理,
191 * 它可能会阻塞线程,那会导致键盘、鼠标事件延迟,
192 * 所以这里用 Qt::DirectConnection
193 * \~english Because the connection may be a non-Qt event processing in another thread,
194 * it may block the thread, which will cause the keyboard and mouse events to be delayed.
195 * So here use Qt::DirectConnection
196 */
197 check = connect(pView, SIGNAL(sigMousePressEvent(QMouseEvent*, QPoint)),
198 this, SLOT(slotMousePressEvent(QMouseEvent*, QPoint)),
199 Qt::DirectConnection);
200 Q_ASSERT(check);
201 check = connect(pView, SIGNAL(sigMouseReleaseEvent(QMouseEvent*, QPoint)),
202 this, SLOT(slotMouseReleaseEvent(QMouseEvent*, QPoint)),
203 Qt::DirectConnection);
204 Q_ASSERT(check);
205 check = connect(pView, SIGNAL(sigMouseMoveEvent(QMouseEvent*, QPoint)),
206 this, SLOT(slotMouseMoveEvent(QMouseEvent*, QPoint)),
207 Qt::DirectConnection);
208 Q_ASSERT(check);
209 check = connect(pView, SIGNAL(sigWheelEvent(QWheelEvent*, QPoint)),
210 this, SLOT(slotWheelEvent(QWheelEvent*, QPoint)),
211 Qt::DirectConnection);
212 Q_ASSERT(check);
213 check = connect(pView, SIGNAL(sigKeyPressEvent(QKeyEvent*)),
214 this, SLOT(slotKeyPressEvent(QKeyEvent*)),
215 Qt::DirectConnection);
216 Q_ASSERT(check);
217 check = connect(pView, SIGNAL(sigKeyReleaseEvent(QKeyEvent*)),
218 this, SLOT(slotKeyReleaseEvent(QKeyEvent*)),
219 Qt::DirectConnection);
220 Q_ASSERT(check);
221 } else {
222 check = connect(pView, SIGNAL(sigMousePressEvent(QMouseEvent*, QPoint)),
223 this, SLOT(slotMousePressEvent(QMouseEvent*, QPoint)));
224 Q_ASSERT(check);
225 check = connect(pView, SIGNAL(sigMouseReleaseEvent(QMouseEvent*, QPoint)),
226 this, SLOT(slotMouseReleaseEvent(QMouseEvent*, QPoint)));
227 Q_ASSERT(check);
228 check = connect(pView, SIGNAL(sigMouseMoveEvent(QMouseEvent*, QPoint)),
229 this, SLOT(slotMouseMoveEvent(QMouseEvent*, QPoint)));
230 Q_ASSERT(check);
231 check = connect(pView, SIGNAL(sigWheelEvent(QWheelEvent*, QPoint)),
232 this, SLOT(slotWheelEvent(QWheelEvent*, QPoint)));
233 Q_ASSERT(check);
234 check = connect(pView, SIGNAL(sigKeyPressEvent(QKeyEvent*)),
235 this, SLOT(slotKeyPressEvent(QKeyEvent*)));
236 Q_ASSERT(check);
237 check = connect(pView, SIGNAL(sigKeyReleaseEvent(QKeyEvent*)),
238 this, SLOT(slotKeyReleaseEvent(QKeyEvent*)));
239 Q_ASSERT(check);
240 }
241
242 return 0;
243}
244
245void CConnectDesktop::slotWheelEvent(QWheelEvent *event, QPoint pos)
246{
247 QWheelEvent* e = new QWheelEvent(
248 pos,
249#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
250 event->globalPosition(),
251#else
252 event->globalPos(),
253#endif
254 event->pixelDelta(), event->angleDelta(), event->buttons(),
255 event->modifiers(), event->phase(), event->inverted(), event->source());
256 QCoreApplication::postEvent(this, e);
257 WakeUp();
258}
259
260void CConnectDesktop::slotMouseMoveEvent(QMouseEvent *event, QPoint pos)
261{
262 QMouseEvent* e = new QMouseEvent(event->type(), pos, event->button(),
263 event->buttons(), event->modifiers());
264 QCoreApplication::postEvent(this, e);
265 WakeUp();
266}
267
268void CConnectDesktop::slotMousePressEvent(QMouseEvent *event, QPoint pos)
269{
270 QMouseEvent* e = new QMouseEvent(event->type(), pos, event->button(),
271 event->buttons(), event->modifiers());
272 QCoreApplication::postEvent(this, e);
273 WakeUp();
274}
275
276void CConnectDesktop::slotMouseReleaseEvent(QMouseEvent *event, QPoint pos)
277{
278 QMouseEvent* e = new QMouseEvent(event->type(), pos, event->button(),
279 event->buttons(), event->modifiers());
280 QCoreApplication::postEvent(this, e);
281 WakeUp();
282}
283
284void CConnectDesktop::slotKeyPressEvent(QKeyEvent *event)
285{
286 QKeyEvent* e = new QKeyEvent(event->type(), event->key(),
287 event->modifiers(), event->text());
288 QCoreApplication::postEvent(this, e);
289 WakeUp();
290}
291
292void CConnectDesktop::slotKeyReleaseEvent(QKeyEvent *event)
293{
294 QKeyEvent* e = new QKeyEvent(event->type(), event->key(),
295 event->modifiers(), event->text());
296 QCoreApplication::postEvent(this, e);
297 WakeUp();
298}
299
300void CConnectDesktop::mouseMoveEvent(QMouseEvent *event)
301{
302 qDebug(logMouse) << "Need to implement CConnectDesktop::mouseMoveEvent";
303}
304
305void CConnectDesktop::mousePressEvent(QMouseEvent *event)
306{
307 qDebug(logMouse) << "Need to implement CConnectDesktop::mousePressEvent";
308}
309
310void CConnectDesktop::mouseReleaseEvent(QMouseEvent *event)
311{
312 qDebug(logMouse) << "Need to implement CConnectDesktop::mouseReleaseEvent";
313}
314
315void CConnectDesktop::wheelEvent(QWheelEvent *event)
316{
317 qDebug(logMouse) << "Need to implement CConnectDesktop::wheelEvent";
318}
319
320void CConnectDesktop::keyPressEvent(QKeyEvent *event)
321{
322 qDebug(logMouse) << "Need to implement CConnectDesktop::keyPressEvent";
323}
324
325void CConnectDesktop::keyReleaseEvent(QKeyEvent *event)
326{
327 qDebug(logMouse) << "Need to implement CConnectDesktop::keyReleaseEvent";
328}
329
331{
332 return 0;
333}
334
335bool CConnectDesktop::event(QEvent *event)
336{
337 //qDebug(log) << "CConnectDesktop::event" << event;
338 switch (event->type()) {
339 case QEvent::MouseButtonPress:
340 case QEvent::MouseButtonDblClick:
341 mousePressEvent((QMouseEvent*)event);
342 break;
343 case QEvent::MouseButtonRelease:
344 mouseReleaseEvent((QMouseEvent*)event);
345 break;
346 case QEvent::MouseMove:
347 mouseMoveEvent((QMouseEvent*)event);
348 break;
349 case QEvent::Wheel:
350 wheelEvent((QWheelEvent*)event);
351 break;
352 case QEvent::KeyPress:
353 keyPressEvent((QKeyEvent*)event);
354 break;
355 case QEvent::KeyRelease:
356 keyReleaseEvent((QKeyEvent*)event);
357 break;
358#if HAVE_QT6_RECORD
359 case TypeRecordVideo:
360 RecordVideo((QRecordVideoEvent*)event);
361 break;
362#endif
363 default:
364 return QObject::event(event);
365 }
366
367 event->accept();
368 return true;
369}
370
371#if HAVE_QT6_RECORD
372void CConnectDesktop::slotRecord(bool bRecord)
373{
374 qDebug(log) << Q_FUNC_INFO << bRecord;
375 if(bRecord) {
376 if(QMediaRecorder::RecordingState == m_Recorder.recorderState())
377 return;
378 (*m_pParameterRecord) >> m_Recorder;
379 m_CaptureSession.setVideoFrameInput(&m_VideoFrameInput);
380 m_CaptureSession.setRecorder(&m_Recorder);
381 m_Recorder.record();
382 } else {
383 m_Recorder.stop();
384 m_CaptureSession.setVideoFrameInput(nullptr);
385 m_CaptureSession.setAudioBufferInput(nullptr);
386 m_CaptureSession.setRecorder(nullptr);
387 }
388 emit sigRecordVideo(bRecord);
389}
390
391void CConnectDesktop::slotRecordPause(bool bPause)
392{
393 qDebug(log) << Q_FUNC_INFO << bPause;
394 if(bPause) {
395 if(m_Recorder.recorderState() == QMediaRecorder::RecordingState)
396 m_Recorder.pause();
397 } else {
398 if(m_Recorder.recorderState() == QMediaRecorder::PausedState)
399 m_Recorder.record();
400 }
401}
402
403void CConnectDesktop::slotRecordVideo(const QImage &img)
404{
406 if(!e) return;
407 QCoreApplication::postEvent(this, e);
408 WakeUp();
409}
410
411void CConnectDesktop::RecordVideo(QRecordVideoEvent *e)
412{
413 qDebug(log) << "Update image";
414 if(!e) return;
415 if(QMediaRecorder::RecordingState != m_Recorder.recorderState()) {
416 qCritical(log) << "Recorder is inavailable";
417 return;
418 }
419 QVideoFrame frame(e->GetImage());
420 bool bRet = m_VideoFrameInput.sendVideoFrame(frame);
421 if(!bRet) {
422 //TODO: 放入未成功发送队列,
423 // 当 QVideoFrameInput::readyToSendVideoFrame() 时,再发送
424 qDebug(log) << "m_VideoFrameInput.sendVideoFrame fail";
425 }
426}
427
429{
430 slotRecord(false);
431 return CConnect::Disconnect();
432}
433#endif
CConnectDesktop(CConnecter *pConnecter, bool bDirectConnection=true)
void sigUpdateRect(const QRect &r, const QImage &image)
Notify the CFrmView update image.
virtual int WakeUp()
Wake up Connect thread(background thread)
virtual void slotClipBoardChanged()=0
Be called when the clip board change.
Connect interface.
Definition Connect.h:45
void sigError(const int nError, const QString &szError=QString())
Triggered when an error is generated.
void sigConnected()
Emitted when the plugin is successfully connected.
virtual int Disconnect()
Disconnect.
Definition Connect.cpp:89
virtual CParameterBase * GetParameter()
Get parameter.
It starts a background thread by default.
Connecter interface.
Definition Connecter.h:62
virtual QWidget * GetViewer()=0
Get Viewer.
The scroll form class.
Definition FrmScroll.h:17
A widget which displays output image from a CConnectDesktop and sends input keypresses and mouse acti...
Definition FrmViewer.h:49