10#include <QGestureRecognizer>
11#include <QGestureEvent>
13#include <QPinchGesture>
15#include <QLoggingCategory>
19#elif ! (defined(Q_OS_ANDROID) || defined(Q_OS_WIN) || defined(Q_OS_APPLE) || defined(Q_OS_MACOS))
21 #include <X11/XKBlib.h>
23 #include <X11/keysymdef.h>
28static Q_LOGGING_CATEGORY(log,
"Client.FrmViewer")
29static Q_LOGGING_CATEGORY(logKey,
"Client.FrmViewer.Key")
30static Q_LOGGING_CATEGORY(logMouse,
"Client.FrmViewer.Mouse")
31static Q_LOGGING_CATEGORY(logInputMethod,
"Client.FrmViewer.InputMethod")
32static Q_LOGGING_CATEGORY(logTouch,
"Client.FrmViewer.Touch")
36 , m_bRecordVideo(false)
38 qDebug(log) << Q_FUNC_INFO;
39 setAttribute(Qt::WA_DeleteOnClose);
40 setAttribute(Qt::WA_AcceptTouchEvents);
47 slotSetAdaptWindows(ADAPT_WINDOWS::ZoomToWindow);
50 setMouseTracking(
true);
51 setFocusPolicy(Qt::WheelFocus);
59 bool check = connect(&m_TimerRecordVideo, SIGNAL(timeout()),
60 this, SLOT(slotRecordVideo()));
64CFrmViewer::~CFrmViewer()
66 qDebug(log) << Q_FUNC_INFO;
69QRectF CFrmViewer::GetAspectRationRect()
71 QRectF dstRect = rect();
72 qreal newW = dstRect.width();
73 qreal newH = dstRect.height();
77 qreal rateW =
static_cast<qreal
>(rect().width())
78 /
static_cast<qreal
>(m_DesktopSize.width());
79 qreal rateH =
static_cast<qreal
>(rect().height())
80 /
static_cast<qreal
>(m_DesktopSize.height());
83 newW = m_DesktopSize.width() * rateW;
84 newH = m_DesktopSize.height() * rateW;
85 newT = (
static_cast<qreal
>(rect().height()) - newH)
86 /
static_cast<qreal
>(2);
87 }
else if(rateW > rateH) {
88 newW = m_DesktopSize.width() * rateH;
89 newH = m_DesktopSize.height() * rateH;
90 newL = (
static_cast<qreal
>(rect().width()) - newW)
91 /
static_cast<qreal
>(2);
93 dstRect = QRectF(newL, newT, newW, newH);
97void CFrmViewer::paintDesktop()
99 QRectF dstRect = rect();
101 switch (m_AdaptWindows) {
103 case ADAPT_WINDOWS::Auto:
108 dstRect.setLeft((rect().width() - m_DesktopSize.width()) >> 1);
109 dstRect.setTop((rect().height() - m_DesktopSize.height()) >> 1);
110 dstRect.setWidth(m_DesktopSize.width());
111 dstRect.setHeight(m_DesktopSize.height());
115 dstRect = GetAspectRationRect();
122 if(m_Desktop.isNull())
return;
124 QPainter painter(
this);
128#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
129 painter.fillRect(rect(), QBrush(palette().color(QPalette::Window)));
131 painter.fillRect(rect(), QBrush(palette().color(QPalette::Background)));
136 painter.setRenderHint(QPainter::SmoothPixmapTransform);
137 painter.drawImage(dstRect, m_Desktop);
141void CFrmViewer::paintEvent(QPaintEvent *event)
149int CFrmViewer::PointToRemote(
const QPointF &inPos, QPointF &outPos)
153 switch (m_AdaptWindows) {
154 case ADAPT_WINDOWS::Auto:
164 outPos.setX(m_DesktopSize.width() * inPos.x() / width());
165 outPos.setY(m_DesktopSize.height() * inPos.y() / height());
169 QRectF r = GetAspectRationRect();
170 if(inPos.x() < r.left()
171 || inPos.x() > r.right()
172 || inPos.y() < r.top()
173 || inPos.y() > r.bottom())
175 outPos.setX(m_DesktopSize.width() * (inPos.x() - r.left()) / r.width());
176 outPos.setY(m_DesktopSize.height() * (inPos.y() - r.top()) / r.height());
180 qWarning(log) <<
"Unsupported:" << m_AdaptWindows;
187int CFrmViewer::PointFromRemote(
const QPointF &inPos, QPointF &outPos)
191 switch (m_AdaptWindows) {
192 case ADAPT_WINDOWS::Auto:
201 outPos.setX(width() * inPos.x() / m_DesktopSize.width());
202 outPos.setY(height() * inPos.y() / m_DesktopSize.height());
206 QRectF r = GetAspectRationRect();
207 outPos.setX(r.width() * inPos.x() / m_DesktopSize.width() + r.left());
208 outPos.setY(r.height() * inPos.y() / m_DesktopSize.height() + r.top());
212 qWarning(log) <<
"Unsupported:" << m_AdaptWindows;
218void CFrmViewer::mousePressEvent(QMouseEvent *event)
221#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
227 if(PointToRemote(pos, pos))
return;
233 emit sigMousePressEvent(
event, QPoint(pos.x(), pos.y()));
235 if(testAttribute(Qt::WA_InputMethodEnabled)
236 &&
event->button() == Qt::LeftButton) {
237 qDebug(logInputMethod) << Q_FUNC_INFO <<
"Update micro focus";
242void CFrmViewer::mouseReleaseEvent(QMouseEvent *event)
245#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
250 if(PointToRemote(pos, pos))
return;
256 emit sigMouseReleaseEvent(
event, QPoint(pos.x(), pos.y()));
260void CFrmViewer::mouseMoveEvent(QMouseEvent *event)
263#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
268 QPointF outPos = pos;
269 if(PointToRemote(pos, outPos))
return;
277 emit sigMouseMoveEvent(
event, QPoint(outPos.x(), outPos.y()));
278 emit sigMouseMoveEvent(
event);
282void CFrmViewer::wheelEvent(QWheelEvent *event)
285#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
290 if(PointToRemote(pos, pos))
return;
294 emit sigWheelEvent(
event, QPoint(pos.x(), pos.y()));
298void CFrmViewer::keyPressEvent(QKeyEvent *event)
301 emit sigKeyPressEvent(
event);
305void CFrmViewer::keyReleaseEvent(QKeyEvent *event)
308 emit sigKeyReleaseEvent(
event);
312void CFrmViewer::inputMethodEvent(QInputMethodEvent *event)
319 emit sigInputMethodEvent(
event);
328QVariant CFrmViewer::inputMethodQuery(Qt::InputMethodQuery query)
const
333 case Qt::ImCursorRectangle: {
334 QPoint p = mapFromGlobal(cursor().pos());
335 QRect r(p.x(), p.y() , 1, fontMetrics().height());
347 QVariant r = QWidget::inputMethodQuery(query);
355 setAttribute(Qt::WA_InputMethodEnabled, bEnable);
358QSize CFrmViewer::GetDesktopSize()
360 return m_DesktopSize;
365 return m_dbZoomFactor;
368int CFrmViewer::slotSetZoomFactor(
double newZoomFactor)
370 if(newZoomFactor < 0)
return -1;
371 if (qFuzzyCompare(m_dbZoomFactor, newZoomFactor))
373 m_dbZoomFactor = newZoomFactor;
377int CFrmViewer::ReSize(
int width,
int height)
385void CFrmViewer::slotSetAdaptWindows(ADAPT_WINDOWS aw)
388 if(!m_Desktop.isNull())
390 switch (m_AdaptWindows) {
393 slotSetZoomFactor(1);
395 ReSize(m_DesktopSize.width(), m_DesktopSize.height());
407 return m_AdaptWindows;
412 m_DesktopSize = QSize(width, height);
413 m_Desktop = QImage(width, height, QImage::Format_RGB32);
418 ReSize(width, height);
430 this->setWindowTitle(szName);
431 emit sigServerName(szName);
440 emit sigRecordVideo(m_Desktop);
449 if(r.width() != image.rect().width() || r.height() != image.rect().height())
451 qWarning(log) <<
"Image is error";
455 if(m_Desktop.isNull() || m_Desktop.rect() == r)
460 QPainter painter(&m_Desktop);
461 painter.drawImage(r, image);
466 emit sigRecordVideo(m_Desktop);
475 if(testAttribute(Qt::WA_InputMethodEnabled)) {
476 qDebug(logInputMethod) << Q_FUNC_INFO <<
"Update micro focus";
486 if(PointFromRemote(pos, outPos))
return;
487 cursor().setPos(mapToGlobal(outPos.toPoint()));
491 if(testAttribute(Qt::WA_InputMethodEnabled)) {
492 qDebug(logInputMethod) << Q_FUNC_INFO <<
"Update micro focus";
497#if ! (defined(Q_OS_WIN) || defined(Q_OS_APPLE) || defined(Q_OS_ANDROID) || defined(Q_OS_APPLE) || defined(Q_OS_MACOS))
498unsigned int getModifierMask(
unsigned int keysym)
501 unsigned int mask, keycode;
505 Display *dpy = XOpenDisplay(0);
506 xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
510 for (keycode = xkb->min_key_code; keycode <= xkb->max_key_code; keycode++) {
511 unsigned int state_out;
514 XkbTranslateKeyCode(xkb, keycode, 0, &state_out, &ks);
523 if (keycode > xkb->max_key_code)
526 act = XkbKeyAction(xkb, keycode, 0);
529 if (act->type != XkbSA_LockMods)
532 if (act->mods.flags & XkbSA_UseModMapMods)
533 mask = xkb->map->modmap[keycode];
535 mask = act->mods.mask;
538 XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
544void CFrmViewer::slotUpdateLedState(
unsigned int state)
546 qDebug(log,
"Got server LED state: 0x%08x", state);
558 memset(input, 0,
sizeof(input));
561 if (!!(state & CapsLock) != !!(GetKeyState(VK_CAPITAL) & 0x1)) {
562 input[count].type = input[count+1].type = INPUT_KEYBOARD;
563 input[count].ki.wVk = input[count+1].ki.wVk = VK_CAPITAL;
565 input[count].ki.dwFlags = 0;
566 input[count+1].ki.dwFlags = KEYEVENTF_KEYUP;
570 if (!!(state & NumLock) != !!(GetKeyState(VK_NUMLOCK) & 0x1)) {
571 input[count].type = input[count+1].type = INPUT_KEYBOARD;
572 input[count].ki.wVk = input[count+1].ki.wVk = VK_NUMLOCK;
574 input[count].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
575 input[count+1].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;
579 if (!!(state & ScrollLock) != !!(GetKeyState(VK_SCROLL) & 0x1)) {
580 input[count].type = input[count+1].type = INPUT_KEYBOARD;
581 input[count].ki.wVk = input[count+1].ki.wVk = VK_SCROLL;
583 input[count].ki.dwFlags = 0;
584 input[count+1].ki.dwFlags = KEYEVENTF_KEYUP;
591 ret = SendInput(count, input,
sizeof(*input));
593 qCritical(log) <<
"Failed to update keyboard LED state:" << GetLastError();
594#elif defined(Q_OS_APPLE)
599#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_APPLE)
600 unsigned int affect, values;
608 if (state & CapsLock)
611 mask = getModifierMask(XK_Num_Lock);
616 mask = getModifierMask(XK_Scroll_Lock);
618 if (state & ScrollLock)
620 Display *dpy = XOpenDisplay(0);
621 ret = XkbLockModifiers(dpy, XkbUseCoreKbd, affect, values);
623 qCritical(log) << tr(
"Failed to update keyboard LED state");
629QImage CFrmViewer::GrabImage(
int x,
int y,
int w,
int h)
631 int width = w, height = h;
633 width = m_DesktopSize.width();
635 height = m_DesktopSize.height();
636 return m_Desktop.copy(x, y, width, height);
639void CFrmViewer::slotRecordVideo(
bool bRecord, qreal nRate)
641 m_bRecordVideo = bRecord;
643 qWarning(log) <<
"The video frame rate is 0. it is not record static remote desktop."
644 <<
"If need record static remote desktop,"
645 <<
"please 'Record->Video->Encoding mode' don't select 'Constant quality' in settings dialog,"
646 <<
"then set 'Record->Video->Video frame'";
650 m_bRecordVideo =
false;
652 qreal ms = 1000 / nRate;
654 m_TimerRecordVideo.start(ms);
657 m_TimerRecordVideo.stop();
660void CFrmViewer::slotRecordVideo()
662 emit sigRecordVideo(m_Desktop);
665void CFrmViewer::focusInEvent(QFocusEvent *event)
667 qDebug(log) << Q_FUNC_INFO <<
event <<
this;
671void CFrmViewer::focusOutEvent(QFocusEvent *event)
673 qDebug(log) << Q_FUNC_INFO <<
event <<
this;
687 switch (
event->type())
689 case QEvent::TouchBegin:
690 case QEvent::TouchUpdate:
691 case QEvent::TouchEnd:
693 QTouchEvent* e = (QTouchEvent*)
event;
694 qDebug(logTouch) <<
"QEvent::TouchBegin";
698 case QEvent::Gesture:
700 gestureEvent(
static_cast<QGestureEvent*
>(
event));
706 return QWidget::event(
event);
709bool CFrmViewer::touchEvent(QTouchEvent* event)
711 const QList<QTouchEvent::TouchPoint> touchPoints =
event->touchPoints();
713 for (
const QTouchEvent::TouchPoint &touchPoint : touchPoints) {
714 qDebug(logTouch) <<
"Touch Point ID:" << touchPoint.id()
715 <<
"State:" << touchPoint.state()
716 <<
"Position:" << touchPoint.pos();
717 switch (touchPoint.state()) {
718 case Qt::TouchPointPressed: {
719 qDebug(logTouch) <<
"手指按下!ID:" << touchPoint.id() <<
"Pos:" << touchPoint.pos();
723 case Qt::TouchPointMoved:
724 qDebug(logTouch) <<
"手指移动... ID:" << touchPoint.id() <<
"Current Pos:" << touchPoint.pos();
727 case Qt::TouchPointReleased:
728 qDebug(logTouch) <<
"手指抬起。 ID:" << touchPoint.id() <<
"Final Pos:" << touchPoint.pos();
741bool CFrmViewer::gestureEvent(QGestureEvent* event)
743 if (QGesture *pinch =
event->gesture(Qt::PinchGesture)) {
744 QPinchGesture *pinchGesture =
static_cast<QPinchGesture *
>(pinch);
747 if (pinchGesture->state() == Qt::GestureUpdated) {
749 qreal scale = pinchGesture->scaleFactor();
750 qDebug() <<
"正在缩放! 缩放因子:" << scale;
755 if (QGesture *pan =
event->gesture(Qt::PanGesture)) {
756 QPanGesture *panGesture =
static_cast<QPanGesture *
>(pan);
758 if (panGesture->state() == Qt::GestureUpdated) {
759 QPointF delta = panGesture->delta();
760 qDebug() <<
"正在平移! 偏移量:" << delta;
A widget which displays output image from a CConnectDesktop and sends input keypresses and mouse acti...
virtual bool event(QEvent *event) override
[Full Screen]
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.
Q_INVOKABLE int OnFullScreen(bool bFull)
Full Screen.
double GetZoomFactor() const
Adjust the zoom factor.