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::PointToRemote(
const QPointF &inPos, QPointF &outPos)
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());
172 qWarning(logMouse) <<
"Unsupport:" << m_AdaptWindows;
179int CFrmViewer::PointFromRemote(
const QPointF &inPos, QPointF &outPos)
183 switch (m_AdaptWindows) {
184 case ADAPT_WINDOWS::Auto:
193 outPos.setX(width() * inPos.x() / m_DesktopSize.width());
194 outPos.setY(height() * inPos.y() / m_DesktopSize.height());
198 QRectF r = GetAspectRationRect();
199 outPos.setX(r.width() * inPos.x() / m_DesktopSize.width() + r.left());
200 outPos.setY(r.height() * inPos.y() / m_DesktopSize.height() + r.top());
204 qWarning(logMouse) <<
"Unsupport:" << m_AdaptWindows;
210void CFrmViewer::mousePressEvent(QMouseEvent *event)
213#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
219 if(PointToRemote(pos, pos))
return;
222 qDebug(logMouse) <<
"CFrmViewer::mousePressEvent"
223 <<
event <<
event->button() <<
event->buttons() << pos;
224 emit sigMousePressEvent(event, QPoint(pos.x(), pos.y()));
226 if(testAttribute(Qt::WA_InputMethodEnabled)
227 && event->button() == Qt::LeftButton) {
228 qDebug(logInputMethod) << Q_FUNC_INFO <<
"Update micro focus";
233void CFrmViewer::mouseReleaseEvent(QMouseEvent *event)
236#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
241 if(PointToRemote(pos, pos))
return;
244 qDebug(logMouse) <<
"CFrmViewer::mouseReleaseEvent"
245 <<
event <<
event->button() <<
event->buttons() << pos;
246 emit sigMouseReleaseEvent(event, QPoint(pos.x(), pos.y()));
250void CFrmViewer::mouseMoveEvent(QMouseEvent *event)
253#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
258 QPointF outPos = pos;
259 if(PointToRemote(pos, outPos))
return;
262 qDebug(logMouse) <<
"CFrmViewer::mouseMoveEvent"
263 <<
event->button() <<
event->buttons()
264 << pos <<
"outPos:" << outPos
265 <<
"mapToGlobal(pos):" << mapToGlobal(pos.toPoint());
266 emit sigMouseMoveEvent(event, QPoint(outPos.x(), outPos.y()));
267 emit sigMouseMoveEvent(event);
271void CFrmViewer::wheelEvent(QWheelEvent *event)
274#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
279 if(PointToRemote(pos, pos))
return;
280 qDebug(logMouse) <<
"CFrmViewer::wheelEvent"
281 <<
event->buttons() <<
event->angleDelta() << pos;
282 emit sigWheelEvent(event, QPoint(pos.x(), pos.y()));
286void CFrmViewer::keyPressEvent(QKeyEvent *event)
288 qDebug(logKey) <<
"CFrmViewer::keyPressEvent" << event;
289 emit sigKeyPressEvent(event);
293void CFrmViewer::keyReleaseEvent(QKeyEvent *event)
295 qDebug(logKey) <<
"CFrmViewer::keyReleaseEvent" << event;
296 emit sigKeyReleaseEvent(event);
300void CFrmViewer::inputMethodEvent(QInputMethodEvent *event)
302 qDebug(logInputMethod) << Q_FUNC_INFO <<
event
303 <<
event->preeditString() <<
event->commitString()
304 <<
event->replacementStart() <<
event->replacementLength();
305 emit sigInputMethodEvent(event);
314QVariant CFrmViewer::inputMethodQuery(Qt::InputMethodQuery query)
const
317 qDebug(logInputMethod) << Q_FUNC_INFO << query;
320 case Qt::ImCursorRectangle: {
321 QPoint p = mapFromGlobal(cursor().pos());
322 QRect r(p.x(), p.y() , 1, fontMetrics().height());
323 qDebug(logInputMethod) <<
"Qt::ImCursorRectangle:" << r;
334 QVariant r = QWidget::inputMethodQuery(query);
335 qDebug(logInputMethod) << Q_FUNC_INFO << query << r;
341 qDebug(logInputMethod) << Q_FUNC_INFO << bEnable;
342 setAttribute(Qt::WA_InputMethodEnabled, bEnable);
345QSize CFrmViewer::GetDesktopSize()
347 return m_DesktopSize;
352 return m_dbZoomFactor;
355int CFrmViewer::slotSetZoomFactor(
double newZoomFactor)
357 if(newZoomFactor < 0)
return -1;
358 if (qFuzzyCompare(m_dbZoomFactor, newZoomFactor))
360 m_dbZoomFactor = newZoomFactor;
364int CFrmViewer::ReSize(
int width,
int height)
372void CFrmViewer::slotSetAdaptWindows(ADAPT_WINDOWS aw)
375 if(!m_Desktop.isNull())
377 switch (m_AdaptWindows) {
380 slotSetZoomFactor(1);
382 ReSize(m_DesktopSize.width(), m_DesktopSize.height());
394 return m_AdaptWindows;
399 m_DesktopSize = QSize(width, height);
400 m_Desktop = QImage(width, height, QImage::Format_RGB32);
405 ReSize(width, height);
417 this->setWindowTitle(szName);
418 emit sigServerName(szName);
427 emit sigRecordVideo(m_Desktop);
436 if(r.width() != image.rect().width() || r.height() != image.rect().height())
438 qWarning(log) <<
"Image is error";
442 if(m_Desktop.isNull() || m_Desktop.rect() == r)
447 QPainter painter(&m_Desktop);
448 painter.drawImage(r, image);
453 emit sigRecordVideo(m_Desktop);
460 qDebug(logMouse) << Q_FUNC_INFO << cursor << cursor.pos();
462 if(testAttribute(Qt::WA_InputMethodEnabled)) {
463 qDebug(logInputMethod) << Q_FUNC_INFO <<
"Update micro focus";
471 qDebug(logMouse) << Q_FUNC_INFO << pos;
473 if(PointFromRemote(pos, outPos))
return;
474 cursor().setPos(mapToGlobal(outPos.toPoint()));
475 qDebug(logMouse) <<
"Cursor Point:" << pos <<
"Out:" << outPos
476 <<
"cursor().pos():" << cursor().pos();
477 if(testAttribute(Qt::WA_InputMethodEnabled)) {
478 qDebug(logInputMethod) << Q_FUNC_INFO <<
"Update micro focus";
483#if ! (defined(Q_OS_WIN) || defined(Q_OS_APPLE) || defined(Q_OS_ANDROID) || defined(Q_OS_APPLE) || defined(Q_OS_MACOS))
484unsigned int getModifierMask(
unsigned int keysym)
487 unsigned int mask, keycode;
491 Display *dpy = XOpenDisplay(0);
492 xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
496 for (keycode = xkb->min_key_code; keycode <= xkb->max_key_code; keycode++) {
497 unsigned int state_out;
500 XkbTranslateKeyCode(xkb, keycode, 0, &state_out, &ks);
509 if (keycode > xkb->max_key_code)
512 act = XkbKeyAction(xkb, keycode, 0);
515 if (act->type != XkbSA_LockMods)
518 if (act->mods.flags & XkbSA_UseModMapMods)
519 mask = xkb->map->modmap[keycode];
521 mask = act->mods.mask;
524 XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
530void CFrmViewer::slotUpdateLedState(
unsigned int state)
532 qDebug(log,
"Got server LED state: 0x%08x", state);
544 memset(input, 0,
sizeof(input));
547 if (!!(state & CapsLock) != !!(GetKeyState(VK_CAPITAL) & 0x1)) {
548 input[count].type = input[count+1].type = INPUT_KEYBOARD;
549 input[count].ki.wVk = input[count+1].ki.wVk = VK_CAPITAL;
551 input[count].ki.dwFlags = 0;
552 input[count+1].ki.dwFlags = KEYEVENTF_KEYUP;
556 if (!!(state & NumLock) != !!(GetKeyState(VK_NUMLOCK) & 0x1)) {
557 input[count].type = input[count+1].type = INPUT_KEYBOARD;
558 input[count].ki.wVk = input[count+1].ki.wVk = VK_NUMLOCK;
560 input[count].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
561 input[count+1].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;
565 if (!!(state & ScrollLock) != !!(GetKeyState(VK_SCROLL) & 0x1)) {
566 input[count].type = input[count+1].type = INPUT_KEYBOARD;
567 input[count].ki.wVk = input[count+1].ki.wVk = VK_SCROLL;
569 input[count].ki.dwFlags = 0;
570 input[count+1].ki.dwFlags = KEYEVENTF_KEYUP;
577 ret = SendInput(count, input,
sizeof(*input));
579 qCritical(log) <<
"Failed to update keyboard LED state:" << GetLastError();
580#elif defined(Q_OS_APPLE)
585#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_APPLE)
586 unsigned int affect, values;
594 if (state & CapsLock)
597 mask = getModifierMask(XK_Num_Lock);
602 mask = getModifierMask(XK_Scroll_Lock);
604 if (state & ScrollLock)
606 Display *dpy = XOpenDisplay(0);
607 ret = XkbLockModifiers(dpy, XkbUseCoreKbd, affect, values);
609 qCritical(log) << tr(
"Failed to update keyboard LED state");
615QImage CFrmViewer::GrabImage(
int x,
int y,
int w,
int h)
617 int width = w, height = h;
619 width = m_DesktopSize.width();
621 height = m_DesktopSize.height();
622 return m_Desktop.copy(x, y, width, height);
625void CFrmViewer::slotRecordVideo(
bool bRecord, qreal nRate)
627 m_bRecordVideo = bRecord;
629 qWarning(log) <<
"The video frame rate is 0. it is not record static remote desktop."
630 <<
"If need record static remote desktop,"
631 <<
"please 'Record->Video->Encoding mode' don't select 'Constant quality' in settings dialog,"
632 <<
"then set 'Record->Video->Video frame'";
636 m_bRecordVideo =
false;
638 qreal ms = 1000 / nRate;
640 m_TimerRecordVideo.start(ms);
643 m_TimerRecordVideo.stop();
646void CFrmViewer::slotRecordVideo()
648 emit sigRecordVideo(m_Desktop);
651void CFrmViewer::focusInEvent(QFocusEvent *event)
653 qDebug(log) << Q_FUNC_INFO <<
event <<
this;
657void CFrmViewer::focusOutEvent(QFocusEvent *event)
659 qDebug(log) << Q_FUNC_INFO <<
event <<
this;
用于显示从 CConnectDesktop 输出的图像,和向 CConnectDesktop 发送键盘、鼠标事件。
void slotSetDesktopSize(int width, int height)
Update desktop size
@ Original
原始桌面大小,桌面的左上点与窗口的左上点对齐
@ KeepAspectRationToWindow
保持长宽比缩放到窗口大小,窗口是固定的
@ OriginalCenter
原始桌面大小,桌面中心点与窗口中心点对齐
@ ZoomToWindow
桌面缩放到窗口大小,窗口是固定的
void sigViewerFocusIn(QWidget *pView)
视图获得焦点
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
调整缩放系数。 调整完成后需要调用 SetAdaptWindows(FrmViewer::Zoom) 缩放窗口大小。