9#include <QLoggingCategory>
13#elif ! (defined(Q_OS_ANDROID) || defined(Q_OS_WIN) || defined(Q_OS_APPLE) || defined(Q_OS_MACOS))
15 #include <X11/XKBlib.h>
17 #include <X11/keysymdef.h>
22static Q_LOGGING_CATEGORY(log,
"Client.FrmViewer")
23static Q_LOGGING_CATEGORY(logKey, "Client.FrmViewer.Key")
24static Q_LOGGING_CATEGORY(logMouse, "Client.FrmViewer.Mouse")
25static Q_LOGGING_CATEGORY(logInputMethod, "Client.FrmViewer.InputMethod")
29 , m_bRecordVideo(false)
31 qDebug(log) << Q_FUNC_INFO;
32 setAttribute(Qt::WA_DeleteOnClose);
39 slotSetAdaptWindows(ADAPT_WINDOWS::ZoomToWindow);
42 setMouseTracking(
true);
43 setFocusPolicy(Qt::WheelFocus);
51 bool check = connect(&m_TimerRecordVideo, SIGNAL(timeout()),
52 this, SLOT(slotRecordVideo()));
56CFrmViewer::~CFrmViewer()
58 qDebug(log) << Q_FUNC_INFO;
61QRectF CFrmViewer::GetAspectRationRect()
63 QRectF dstRect = rect();
64 qreal newW = dstRect.width();
65 qreal newH = dstRect.height();
69 qreal rateW =
static_cast<qreal
>(rect().width())
70 /
static_cast<qreal
>(m_DesktopSize.width());
71 qreal rateH =
static_cast<qreal
>(rect().height())
72 /
static_cast<qreal
>(m_DesktopSize.height());
75 newW = m_DesktopSize.width() * rateW;
76 newH = m_DesktopSize.height() * rateW;
77 newT = (
static_cast<qreal
>(rect().height()) - newH)
78 /
static_cast<qreal
>(2);
79 }
else if(rateW > rateH) {
80 newW = m_DesktopSize.width() * rateH;
81 newH = m_DesktopSize.height() * rateH;
82 newL = (
static_cast<qreal
>(rect().width()) - newW)
83 /
static_cast<qreal
>(2);
85 dstRect = QRectF(newL, newT, newW, newH);
89void CFrmViewer::paintDesktop()
91 QRectF dstRect = rect();
93 switch (m_AdaptWindows) {
95 case ADAPT_WINDOWS::Auto:
100 dstRect.setLeft((rect().width() - m_DesktopSize.width()) >> 1);
101 dstRect.setTop((rect().height() - m_DesktopSize.height()) >> 1);
102 dstRect.setWidth(m_DesktopSize.width());
103 dstRect.setHeight(m_DesktopSize.height());
107 dstRect = GetAspectRationRect();
114 if(m_Desktop.isNull())
return;
116 QPainter painter(
this);
120#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
121 painter.fillRect(rect(), QBrush(palette().color(QPalette::Window)));
123 painter.fillRect(rect(), QBrush(palette().color(QPalette::Background)));
128 painter.setRenderHint(QPainter::SmoothPixmapTransform);
129 painter.drawImage(dstRect, m_Desktop);
133void CFrmViewer::paintEvent(QPaintEvent *event)
141int CFrmViewer::TranslationMousePoint(QPointF inPos, QPointF &outPos)
143 qDebug(logMouse) <<
"TranslationPoint x:" << inPos.x() <<
";y:" << inPos.y();
145 switch (m_AdaptWindows) {
146 case ADAPT_WINDOWS::Auto:
156 outPos.setX(m_DesktopSize.width() * inPos.x() / width());
157 outPos.setY(m_DesktopSize.height() * inPos.y() / height());
161 QRectF r = GetAspectRationRect();
162 if(inPos.x() < r.left()
163 || inPos.x() > r.right()
164 || inPos.y() < r.top()
165 || inPos.y() > r.bottom())
167 outPos.setX(m_DesktopSize.width() * (inPos.x() - r.left()) / r.width());
168 outPos.setY(m_DesktopSize.height() * (inPos.y() - r.top()) / r.height());
178void CFrmViewer::mousePressEvent(QMouseEvent *event)
181#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
187 if(TranslationMousePoint(pos, pos))
return;
190 qDebug(logMouse) <<
"CFrmViewer::mousePressEvent"
191 <<
event <<
event->button() <<
event->buttons() << pos;
192 emit sigMousePressEvent(event, QPoint(pos.x(), pos.y()));
195 if(testAttribute(Qt::WA_InputMethodEnabled)
196 && event->button() == Qt::LeftButton) {
197 qDebug(logInputMethod) << Q_FUNC_INFO <<
"Update micro focus";
202void CFrmViewer::mouseReleaseEvent(QMouseEvent *event)
205#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
210 if(TranslationMousePoint(pos, pos))
return;
213 qDebug(logMouse) <<
"CFrmViewer::mouseReleaseEvent"
214 <<
event <<
event->button() <<
event->buttons() << pos;
215 emit sigMouseReleaseEvent(event, QPoint(pos.x(), pos.y()));
219void CFrmViewer::mouseMoveEvent(QMouseEvent *event)
222#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
227 if(TranslationMousePoint(pos, pos))
return;
230 qDebug(logMouse) <<
"CFrmViewer::mouseMoveEvent"
231 <<
event->button() <<
event->buttons() << pos;
232 emit sigMouseMoveEvent(event, QPoint(pos.x(), pos.y()));
233 emit sigMouseMoveEvent(event);
237void CFrmViewer::wheelEvent(QWheelEvent *event)
240#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
245 if(TranslationMousePoint(pos, pos))
return;
246 qDebug(logMouse) <<
"CFrmViewer::wheelEvent"
247 <<
event->buttons() <<
event->angleDelta() << pos;
248 emit sigWheelEvent(event, QPoint(pos.x(), pos.y()));
252void CFrmViewer::keyPressEvent(QKeyEvent *event)
254 qDebug(logKey) <<
"CFrmViewer::keyPressEvent" << event;
255 emit sigKeyPressEvent(event);
259void CFrmViewer::keyReleaseEvent(QKeyEvent *event)
261 qDebug(logKey) <<
"CFrmViewer::keyReleaseEvent" << event;
262 emit sigKeyReleaseEvent(event);
266void CFrmViewer::inputMethodEvent(QInputMethodEvent *event)
268 qDebug(logInputMethod) << Q_FUNC_INFO << event;
269 emit sigInputMethodEvent(event);
278QVariant CFrmViewer::inputMethodQuery(Qt::InputMethodQuery query)
const
280 qDebug(logInputMethod) << Q_FUNC_INFO << query;
283 case Qt::ImCursorRectangle: {
284 QPoint p = mapFromGlobal(cursor().pos());
285 QRect r(p.x(), p.y() , 1, fontMetrics().height());
291 QVariant r = QWidget::inputMethodQuery(query);
292 qDebug(logKey) << Q_FUNC_INFO << query << r;
296QSize CFrmViewer::GetDesktopSize()
298 return m_DesktopSize;
303 return m_dbZoomFactor;
306int CFrmViewer::slotSetZoomFactor(
double newZoomFactor)
308 if(newZoomFactor < 0)
return -1;
309 if (qFuzzyCompare(m_dbZoomFactor, newZoomFactor))
311 m_dbZoomFactor = newZoomFactor;
315int CFrmViewer::ReSize(
int width,
int height)
323void CFrmViewer::slotSetAdaptWindows(ADAPT_WINDOWS aw)
326 if(!m_Desktop.isNull())
328 switch (m_AdaptWindows) {
331 slotSetZoomFactor(1);
333 ReSize(m_DesktopSize.width(), m_DesktopSize.height());
345 return m_AdaptWindows;
350 m_DesktopSize = QSize(width, height);
351 m_Desktop = QImage(width, height, QImage::Format_RGB32);
356 ReSize(width, height);
368 qDebug(logInputMethod) << Q_FUNC_INFO << bEnable;
369 setAttribute(Qt::WA_InputMethodEnabled, bEnable);
374 this->setWindowTitle(szName);
375 emit sigServerName(szName);
384 emit sigRecordVideo(m_Desktop);
393 if(r.width() != image.rect().width() || r.height() != image.rect().height())
395 qWarning(log) <<
"Image is error";
399 if(m_Desktop.isNull() || m_Desktop.rect() == r)
404 QPainter painter(&m_Desktop);
405 painter.drawImage(r, image);
410 emit sigRecordVideo(m_Desktop);
419 if(testAttribute(Qt::WA_InputMethodEnabled)) {
420 qDebug(logInputMethod) << Q_FUNC_INFO <<
"Update micro focus";
428 cursor().setPos(pos);
429 if(testAttribute(Qt::WA_InputMethodEnabled)) {
430 qDebug(logInputMethod) << Q_FUNC_INFO <<
"Update micro focus";
435#if ! (defined(Q_OS_WIN) || defined(Q_OS_APPLE) || defined(Q_OS_ANDROID) || defined(Q_OS_APPLE) || defined(Q_OS_MACOS))
436unsigned int getModifierMask(
unsigned int keysym)
439 unsigned int mask, keycode;
443 Display *dpy = XOpenDisplay(0);
444 xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
448 for (keycode = xkb->min_key_code; keycode <= xkb->max_key_code; keycode++) {
449 unsigned int state_out;
452 XkbTranslateKeyCode(xkb, keycode, 0, &state_out, &ks);
461 if (keycode > xkb->max_key_code)
464 act = XkbKeyAction(xkb, keycode, 0);
467 if (act->type != XkbSA_LockMods)
470 if (act->mods.flags & XkbSA_UseModMapMods)
471 mask = xkb->map->modmap[keycode];
473 mask = act->mods.mask;
476 XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
482void CFrmViewer::slotUpdateLedState(
unsigned int state)
484 qDebug(log,
"Got server LED state: 0x%08x", state);
496 memset(input, 0,
sizeof(input));
499 if (!!(state & CapsLock) != !!(GetKeyState(VK_CAPITAL) & 0x1)) {
500 input[count].type = input[count+1].type = INPUT_KEYBOARD;
501 input[count].ki.wVk = input[count+1].ki.wVk = VK_CAPITAL;
503 input[count].ki.dwFlags = 0;
504 input[count+1].ki.dwFlags = KEYEVENTF_KEYUP;
508 if (!!(state & NumLock) != !!(GetKeyState(VK_NUMLOCK) & 0x1)) {
509 input[count].type = input[count+1].type = INPUT_KEYBOARD;
510 input[count].ki.wVk = input[count+1].ki.wVk = VK_NUMLOCK;
512 input[count].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
513 input[count+1].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;
517 if (!!(state & ScrollLock) != !!(GetKeyState(VK_SCROLL) & 0x1)) {
518 input[count].type = input[count+1].type = INPUT_KEYBOARD;
519 input[count].ki.wVk = input[count+1].ki.wVk = VK_SCROLL;
521 input[count].ki.dwFlags = 0;
522 input[count+1].ki.dwFlags = KEYEVENTF_KEYUP;
529 ret = SendInput(count, input,
sizeof(*input));
531 qCritical(log) <<
"Failed to update keyboard LED state:" << GetLastError();
532#elif defined(Q_OS_APPLE)
537#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_APPLE)
538 unsigned int affect, values;
546 if (state & CapsLock)
549 mask = getModifierMask(XK_Num_Lock);
554 mask = getModifierMask(XK_Scroll_Lock);
556 if (state & ScrollLock)
558 Display *dpy = XOpenDisplay(0);
559 ret = XkbLockModifiers(dpy, XkbUseCoreKbd, affect, values);
561 qCritical(log) << tr(
"Failed to update keyboard LED state");
567QImage CFrmViewer::GrabImage(
int x,
int y,
int w,
int h)
569 int width = w, height = h;
571 width = m_DesktopSize.width();
573 height = m_DesktopSize.height();
574 return m_Desktop.copy(x, y, width, height);
577void CFrmViewer::slotRecordVideo(
bool bRecord, qreal nRate)
579 m_bRecordVideo = bRecord;
581 qWarning(log) <<
"The video frame rate is 0. it is not record static remote desktop."
582 <<
"If need record static remote desktop,"
583 <<
"please 'Record->Video->Encoding mode' don't select 'Constant quality' in settings dialog,"
584 <<
"then set 'Record->Video->Video frame'";
588 m_bRecordVideo =
false;
590 qreal ms = 1000 / nRate;
592 m_TimerRecordVideo.start(ms);
595 m_TimerRecordVideo.stop();
598void CFrmViewer::slotRecordVideo()
600 emit sigRecordVideo(m_Desktop);
603void CFrmViewer::focusInEvent(QFocusEvent *event)
605 qDebug(log) << Q_FUNC_INFO <<
event <<
this;
609void CFrmViewer::focusOutEvent(QFocusEvent *event)
611 qDebug(log) << Q_FUNC_INFO <<
event <<
this;
A widget which displays output image from a CConnectDesktop and sends input keypresses and mouse acti...
void slotSetDesktopSize(int width, int height)
Update desktop size.
ADAPT_WINDOWS
The ADAPT_WINDOWS enum.
@ Original
Original desktop size, the left-top of the desktop is aligned with the left-top of the window.
@ Zoom
zoom windows = desktop size * factor
@ KeepAspectRationToWindow
Keep desktop aspectration adapt to windows.
@ OriginalCenter
Original desktop size, the center of the desktop is aligned with the center of the window.
@ ZoomToWindow
Desktop adapt to windows.
@ Disable
Disable adapt windows.
void sigViewerFocusIn(QWidget *pView)
The view is focus.
void slotUpdateCursor(const QCursor &cursor)
Update cursor.
void slotUpdateRect(const QRect &r, const QImage &image)
Update image.
void slotRunning()
Enable mouse and keyboard.
void slotSetName(const QString &szName)
Update desktop name.
void slotUpdateCursorPosition(const QPoint &pos)
Update cursor position.
void slotEnableInputMethod(bool bEnable)
Enable input method.
double GetZoomFactor() const
Adjust the zoom factor.