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.