当前位置:主页 > 多云管理 >
QT实现远程桌面共享与控制 文章转发
  • 时间:2022-07-09
  • 浏览:

一)功能概述

总体分为Windows端和Linux端,绝大部分功能可跨操作系统(除了Linux作为控制端未实现),只能连接到局域网内的主机:

Windows端:屏幕共享(连接查看他人屏幕、被他人连接查看屏幕),远程控制(被控端、控制端均可),文件传输。

Linux端:屏幕共享(连接查看他人屏幕、被他人连接查看屏幕),远程控制(只能作为被控制端),文件传输。

(二)运行截图

1.初始界面

2.连接屏幕,(这里没有输入连接的ip,所以界面为空)

3.发送文件

4.这里用虚拟机试一下:

可以看到显示界面没问题:

控制也没问题;

(三)基本框架

1.将控制端与被控制端放在了一个程序中

2.使用了三个线程,分别完成“发送屏幕截图”、“发送文件数据”、“发送控制数据”三个功能,三个线程分别占据一个ip上的一个单独的端口,共使用三个端口。

(四)关键代码

这里从核心功能的三个线程入手简单介绍一下相关代码,这里只介绍关键代码,源码自行查看。

1.屏幕共享的线程

发送端关键代码:其实所谓的屏幕传输,就是不停的发送截屏,接收端接收到截屏后更新到界面上,然后就在视觉上感觉像是屏幕在共享。

//被控端 发送截屏
void MainWindow::startTransfer()
{
    QDataStream sendOut(&outBlock, QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_5_6);
    //获取屏幕截图
    pixbuf=screen->grabWindow(QApplication::desktop()->winId());
    //转为base64数据
    QImage image =pixbuf.toImage();
    QString imageData = getImageData(image);
    // 保留总大小信息空间、图像大小信息空间,然后输入图像信息
    sendOut << qint64(0) << qint64(0) << imageData;
    // 这里的总大小是总大小信息、图像大小信息和实际图像信息的总和
    totalBytes_send += outBlock.size();
    sendOut.device()->seek(0);
    // 返回outBolock的开始,用实际的大小信息代替两个qint64(0)空间
    sendOut << totalBytes_send << qint64((outBlock.size() - sizeof(qint64)*2));
    //发出readyRead()信号
    tcpServerConnection->write(outBlock);
    outBlock.resize(0);
    totalBytes_send = 0;
}

 

接收端关键代码:

//控制端更新屏幕
void showWin::updateShowLb()
{
    //用数据流的方式读取
    QDataStream in(tcpClient);
    in.setVersion(QDataStream::Qt_5_6);
    // 如果已接收到的数据小于16个字节,保存到来的文件头结构
    if (bytesReceived <= sizeof(qint64)*2)
    {
        if((tcpClient->bytesAvailable() >= sizeof(qint64)*2)&& (imageSize == 0))
        {
            // 接收数据总大小信息和文件名大小信息
            in >> totalBytes  >> imageSize;
            bytesReceived += sizeof(qint64) * 2;
            if(imageSize == 0)
                  ui->label_show->setText(tr("显示的图片为空!"));
        }
        if((tcpClient->bytesAvailable() >= imageSize)&& (imageSize != 0))
        {
            // 接收图片内容
            in >> imageContent;
            QImage imageData = getImage(imageContent);
            QPixmap resImage = QPixmap::fromImage(imageData);
            QPixmap* imgPointer = &resImage;
            imgPointer->scaled(ui->label_show->size(), Qt::IgnoreAspectRatio);//重新调整图像大小以适应窗口
            ui->label_show->setScaledContents(true);//设置label的属性,能够缩放pixmap充满整个可用的空间。
            ui->label_show->setPixmap(*imgPointer);
            bytesReceived += imageSize;
            //接收图片成功
            if(bytesReceived == totalBytes)
            {
                //发送一个确认
                tcpClient->write("1");
                totalBytes = 0;
                bytesReceived = 0;
                imageSize = 0;
            }
         }
     }
}

	

2.控制数据传输的线程

发送端关键代码:对于发送端来说,需要实时获取用户在屏幕上的鼠标点击以及键盘的键值输入,这个功能QT已经帮我们封装好了,只用定义同名的函数,就可以实时获取用户的操作。这个只对Windows有效,Linux并未实现这个功能,所以我这个程序下Linux只能作为被控制端。


/*键盘按下*/
void CmdThread::cmdKeyPress(QKeyEvent *e)
{
    uchar uc[16];
    uc[0] = CMD_KEY_PRESS;
    uc[1] = translateKey(e->key());
    uc[2] = Find_Key_linux(uc[1]);
    qDebug()<<uc[1]<<uc[2];
    writeAndBlock(cmdSocket, uc, 16);
    e->ignore();
}
/*键盘释放*/
void CmdThread::cmdKeyRelease(QKeyEvent *e)
{
    uchar uc[16];
    uc[0] = CMD_KEY_RELEASE;
    uc[1] = translateKey(e->key());//Windows端使用的字段
    uc[2] = Find_Key_linux(uc[1]); //Linux端使用的字段
    writeAndBlock(cmdSocket, uc, 16);
    e->ignore();
}
//鼠标移动
void CmdThread::cmdMouseMoveTo(int x, int y,int frameWidth,int frameHeight)
{
    uchar uc[16];
    uc[0] = CMD_MOUSE_MOVE_TO;
    setUchar( x,  y, frameWidth, frameHeight, uc);
    writeAndBlock(cmdSocket, uc, 16);
}
//鼠标左键按下
void CmdThread::cmdMouseLeftDown(int x, int y,int frameWidth,int frameHeight)
{
    uchar uc[16];
    uc[0] = CMD_MOUSE_LEFT_DOWN;
    setUchar( x,  y, frameWidth, frameHeight, uc);
    writeAndBlock(cmdSocket, uc, 16);
}
//鼠标左键释放
void CmdThread::cmdMouseLeftUp(int x, int y,int frameWidth,int frameHeight)
{
    uchar uc[16];
    uc[0] = CMD_MOUSE_LEFT_UP;
    setUchar( x,  y, frameWidth, frameHeight, uc);
    writeAndBlock(cmdSocket, uc, 16);
}
//鼠标右键按下
void CmdThread::cmdMouseRightDown(int x, int y,int frameWidth,int frameHeight)
{
    uchar uc[16];
    uc[0] = CMD_MOUSE_RIGHT_DOWN;
    setUchar( x,  y, frameWidth, frameHeight, uc);
    writeAndBlock(cmdSocket, uc, 16);
}
//鼠标右键释放
void CmdThread::cmdMouseRightUp(int x, int y,int frameWidth,int frameHeight)
{
    uchar uc[16];
    uc[0] = CMD_MOUSE_RIGHT_UP;
    setUchar( x,  y, frameWidth, frameHeight, uc);
    writeAndBlock(cmdSocket, uc, 16);
}
//鼠标滚轮事件
void CmdThread::cmdMouseWheel(int delta, int x, int y,int frameWidth,int frameHeight)
{
    uchar uc[16];
    uc[0] = CMD_MOUSE_WHEEL;
    setUchar( x,  y, frameWidth, frameHeight, uc);
    //滚轮的数据,先除以256,再保留余数
    uc[11] = delta / 0x100;
    uc[12] = delta % 0x100;
    //uc[13]用来判断delta的正负,负数为0,非负为1
    uc[13] = delta < 0 ? 0 : 1;
    writeAndBlock(cmdSocket, uc, 16);
}
对于鼠标来说,需要获取鼠标在界面上点击的相对位置以及滚轮滚动的角度等。对于键盘就只需要获取键值,但是QT与Windows及Linux对键盘的键值对应是不同的,这里采用一个Map保存好QT与Windows以及QT与Linux的键值对应关系。 //查找Linux下的键值 uchar CmdThread::Find_Key_linux(int key) { //Linux与Windows的键盘映射表<Windows,Linux> QMap<int,uchar> LinuxAndWindows_KeyMap; LinuxAndWindows_KeyMap.insert(8,14);//KEY_BACKSPACE LinuxAndWindows_KeyMap.insert(9,15);//KEY_TAB LinuxAndWindows_KeyMap.insert(13,28);//KEY_ENTER LinuxAndWindows_KeyMap.insert(16,42);//KEY_LEFTSHIFT LinuxAndWindows_KeyMap.insert(17,29);//KEY_LEFTCTRL LinuxAndWindows_KeyMap.insert(27,1);//KEY_ESC LinuxAndWindows_KeyMap.insert(32,57);//KEY_SPACE LinuxAndWindows_KeyMap.insert(37,125);//KEY_LEFT LinuxAndWindows_KeyMap.insert(38,103);//KEY_UP LinuxAndWindows_KeyMap.insert(39,126);//KEY_RIGHT LinuxAndWindows_KeyMap.insert(40,108);//KEY_DOWN LinuxAndWindows_KeyMap.insert(190,52);//KEY_DOT LinuxAndWindows_KeyMap.insert(46,52);//KEY_DOT LinuxAndWindows_KeyMap.insert(48,11);//KEY_0 LinuxAndWindows_KeyMap.insert(49,2);//KEY_1 LinuxAndWindows_KeyMap.insert(50,3);//KEY_2 LinuxAndWindows_KeyMap.insert(51,4);//KEY_3 LinuxAndWindows_KeyMap.insert(52,5);//KEY_4 LinuxAndWindows_KeyMap.insert(53,6);//KEY_5 LinuxAndWindows_KeyMap.insert(54,7);//KEY_6 LinuxAndWindows_KeyMap.insert(55,8);//KEY_7 LinuxAndWindows_KeyMap.insert(56,9);//KEY_8 LinuxAndWindows_KeyMap.insert(57,10);//KEY_9 LinuxAndWindows_KeyMap.insert(65,30);//KEY_A LinuxAndWindows_KeyMap.insert(66,48);//KEY_B LinuxAndWindows_KeyMap.insert(67,46);//KEY_C LinuxAndWindows_KeyMap.insert(68,32);//KEY_D LinuxAndWindows_KeyMap.insert(69,18);//KEY_E LinuxAndWindows_KeyMap.insert(70,33);//KEY_F LinuxAndWindows_KeyMap.insert(71,34);//KEY_G LinuxAndWindows_KeyMap.insert(72,35);//KEY_H LinuxAndWindows_KeyMap.insert(73,23);//KEY_I LinuxAndWindows_KeyMap.insert(74,36);//KEY_J LinuxAndWindows_KeyMap.insert(75,37);//KEY_K LinuxAndWindows_KeyMap.insert(76,38);//KEY_L LinuxAndWindows_KeyMap.insert(77,50);//KEY_M LinuxAndWindows_KeyMap.insert(78,49);//KEY_N LinuxAndWindows_KeyMap.insert(79,24);//KEY_O LinuxAndWindows_KeyMap.insert(80,25);//KEY_P LinuxAndWindows_KeyMap.insert(81,16);//KEY_Q LinuxAndWindows_KeyMap.insert(82,19);//KEY_R LinuxAndWindows_KeyMap.insert(83,31);//KEY_S LinuxAndWindows_KeyMap.insert(84,20);//KEY_T LinuxAndWindows_KeyMap.insert(85,22);//KEY_U LinuxAndWindows_KeyMap.insert(86,47);//KEY_V LinuxAndWindows_KeyMap.insert(87,17);//KEY_W LinuxAndWindows_KeyMap.insert(88,45);//KEY_X LinuxAndWindows_KeyMap.insert(89,21);//KEY_Y LinuxAndWindows_KeyMap.insert(90,44);//KEY_Z uchar k = 57;//找不到的字符用空格代替 if(LinuxAndWindows_KeyMap.contains(key)) k = LinuxAndWindows_KeyMap[key]; qDebug()<<"Windows:"<<key<<"Linux:"<<k; return k; } void CmdThread::KeyMap() { // {Qt::Key_Up, VK_UP} m_KeyMap.insert(Qt::Key_Left,0x25); m_KeyMap.insert(Qt::Key_Up,0x26); m_KeyMap.insert(Qt::Key_Right,0x27); m_KeyMap.insert(Qt::Key_Down,0x28); m_KeyMap.insert(Qt::Key_Backspace,0x08); m_KeyMap.insert(Qt::Key_Tab,0x09); m_KeyMap.insert(Qt::Key_Clear,0x0C); m_KeyMap.insert(Qt::Key_Return,0x0D); m_KeyMap.insert(Qt::Key_Enter,0x0D); m_KeyMap.insert(Qt::Key_Shift,0x10); m_KeyMap.insert(Qt::Key_Control,0x11); m_KeyMap.insert(Qt::Key_Alt,0x12); m_KeyMap.insert(Qt::Key_Pause,0x13); m_KeyMap.insert(Qt::Key_CapsLock,0x14); m_KeyMap.insert(Qt::Key_Escape,0x1B); m_KeyMap.insert(Qt::Key_Space,0x20); m_KeyMap.insert(Qt::Key_PageUp,0x21); m_KeyMap.insert(Qt::Key_PageDown,0x22); m_KeyMap.insert(Qt::Key_End,0x23); m_KeyMap.insert(Qt::Key_Home,0x24); m_KeyMap.insert(Qt::Key_Select,0x29); m_KeyMap.insert(Qt::Key_Print,0x2A); m_KeyMap.insert(Qt::Key_Execute,0x2B); m_KeyMap.insert(Qt::Key_Printer,0x2C); m_KeyMap.insert(Qt::Key_Insert,0x2D); m_KeyMap.insert(Qt::Key_Delete,0x2E); m_KeyMap.insert(Qt::Key_Help,0x2F); m_KeyMap.insert(Qt::Key_0,0x30); m_KeyMap.insert(Qt::Key_ParenRight,0x30); // ) m_KeyMap.insert(Qt::Key_1,0x31); m_KeyMap.insert(Qt::Key_Exclam,0x31); // ! m_KeyMap.insert(Qt::Key_2,0x32); m_KeyMap.insert(Qt::Key_At,0x32); // @ m_KeyMap.insert(Qt::Key_3,0x33); m_KeyMap.insert(Qt::Key_NumberSign,0x33); // # m_KeyMap.insert(Qt::Key_4,0x34); m_KeyMap.insert(Qt::Key_Dollar,0x34); // $ m_KeyMap.insert(Qt::Key_5,0x35); m_KeyMap.insert(Qt::Key_Percent,0x35); // % m_KeyMap.insert(Qt::Key_6,0x36); m_KeyMap.insert(Qt::Key_AsciiCircum,0x36); // ^ m_KeyMap.insert(Qt::Key_7,0x37); m_KeyMap.insert(Qt::Key_Ampersand,0x37); // & m_KeyMap.insert(Qt::Key_8,0x38); m_KeyMap.insert(Qt::Key_Asterisk,0x38); // * m_KeyMap.insert(Qt::Key_9,0x39); m_KeyMap.insert(Qt::Key_ParenLeft,0x39); // ( m_KeyMap.insert(Qt::Key_A,0x41); m_KeyMap.insert(Qt::Key_B,0x42); m_KeyMap.insert(Qt::Key_C,0x43); m_KeyMap.insert(Qt::Key_D,0x44); m_KeyMap.insert(Qt::Key_E,0x45); m_KeyMap.insert(Qt::Key_F,0x46); m_KeyMap.insert(Qt::Key_G,0x47); m_KeyMap.insert(Qt::Key_H,0x48); m_KeyMap.insert(Qt::Key_I,0x49); m_KeyMap.insert(Qt::Key_J,0x4A); m_KeyMap.insert(Qt::Key_K,0x4B); m_KeyMap.insert(Qt::Key_L,0x4C); m_KeyMap.insert(Qt::Key_M,0x4D); m_KeyMap.insert(Qt::Key_N,0x4E); m_KeyMap.insert(Qt::Key_O,0x4F); m_KeyMap.insert(Qt::Key_P,0x50); m_KeyMap.insert(Qt::Key_Q,0x51); m_KeyMap.insert(Qt::Key_R,0x52); m_KeyMap.insert(Qt::Key_S,0x53); m_KeyMap.insert(Qt::Key_T,0x54); m_KeyMap.insert(Qt::Key_U,0x55); m_KeyMap.insert(Qt::Key_V,0x56); m_KeyMap.insert(Qt::Key_W,0x57); m_KeyMap.insert(Qt::Key_X,0x58); m_KeyMap.insert(Qt::Key_Y,0x59); m_KeyMap.insert(Qt::Key_Z,0x5A); m_KeyMap.insert(Qt::Key_multiply,0x6A); m_KeyMap.insert(Qt::Key_F1,0x70); m_KeyMap.insert(Qt::Key_F2,0x71); m_KeyMap.insert(Qt::Key_F3,0x72); m_KeyMap.insert(Qt::Key_F4,0x73); m_KeyMap.insert(Qt::Key_F5,0x74); m_KeyMap.insert(Qt::Key_F6,0x75); m_KeyMap.insert(Qt::Key_F7,0x76); m_KeyMap.insert(Qt::Key_F8,0x77); m_KeyMap.insert(Qt::Key_F9,0x78); m_KeyMap.insert(Qt::Key_F10,0x79); m_KeyMap.insert(Qt::Key_F11,0x7A); m_KeyMap.insert(Qt::Key_F12,0x7B); m_KeyMap.insert(Qt::Key_F13,0x7C); m_KeyMap.insert(Qt::Key_F14,0x7D); m_KeyMap.insert(Qt::Key_F15,0x7E); m_KeyMap.insert(Qt::Key_F16,0x7F); m_KeyMap.insert(Qt::Key_F17,0x80); m_KeyMap.insert(Qt::Key_F18,0x81); m_KeyMap.insert(Qt::Key_F19,0x82); m_KeyMap.insert(Qt::Key_F20,0x83); m_KeyMap.insert(Qt::Key_F21,0x84); m_KeyMap.insert(Qt::Key_F22,0x85); m_KeyMap.insert(Qt::Key_F23,0x86); m_KeyMap.insert(Qt::Key_F24,0x87); m_KeyMap.insert(Qt::Key_NumLock,0x90); m_KeyMap.insert(Qt::Key_ScrollLock,0x91); m_KeyMap.insert(Qt::Key_VolumeDown,0xAE); m_KeyMap.insert(Qt::Key_VolumeUp,0xAF); m_KeyMap.insert(Qt::Key_VolumeMute,0xAD); m_KeyMap.insert(Qt::Key_MediaStop,0xB2); m_KeyMap.insert(Qt::Key_MediaPlay,0xB3); m_KeyMap.insert(Qt::Key_Plus,0xBB); // + m_KeyMap.insert(Qt::Key_Minus,0xBD); // - m_KeyMap.insert(Qt::Key_Underscore,0xBD); // _ m_KeyMap.insert(Qt::Key_Equal,0xBB); // = m_KeyMap.insert(Qt::Key_Semicolon,0xBA); // ; m_KeyMap.insert(Qt::Key_Colon,0xBA); // : m_KeyMap.insert(Qt::Key_Comma,0xBC); // , m_KeyMap.insert(Qt::Key_Less,0xBC); // < m_KeyMap.insert(Qt::Key_Period,0xBE); // . m_KeyMap.insert(Qt::Key_Greater,0xBE); // > m_KeyMap.insert(Qt::Key_Slash,0xBF); // / m_KeyMap.insert(Qt::Key_Question,0xBF); // ? m_KeyMap.insert(Qt::Key_BracketLeft,0xDB); // [ m_KeyMap.insert(Qt::Key_BraceLeft,0xDB); // { m_KeyMap.insert(Qt::Key_BracketRight,0xDD); // ] m_KeyMap.insert(Qt::Key_BraceRight,0xDD); // } m_KeyMap.insert(Qt::Key_Bar,0xDC); // | m_KeyMap.insert(Qt::Key_Backslash,0xDC); // m_KeyMap.insert(Qt::Key_Apostrophe,0xDE); // ' m_KeyMap.insert(Qt::Key_QuoteDbl,0xDE); // " m_KeyMap.insert(Qt::Key_QuoteLeft,0xC0); // ` m_KeyMap.insert(Qt::Key_AsciiTilde,0xC0); // ~ } //获取鼠标点击位置在屏幕中的比例 void setUchar(int x, int y,int frameWidth,int frameHeight,uchar uc[]) { //获取比例的小数点后1~2位 uc[1] = ((double)x/frameWidth)*100; uc[2] = ((double)y/frameHeight)*100; //获取比例的小数点后3~4位 uc[3] = (int)((double)x/frameWidth*10000)%100; uc[4] = (int)((double)y/frameHeight*10000)%100; //获取比例的小数点后5~6位 uc[5] = (int)((double)x/frameWidth*1000000)%100; uc[6] = (int)((double)y/frameHeight*1000000)%100; //获取比例的小数点后7~8位 uc[7] = (int)((double)x/frameWidth*100000000)%100; uc[8] = (int)((double)y/frameHeight*100000000)%100; //获取比例的小数点后9~10位 uc[9] = (long long)((long double)x/frameWidth*10000000000)%100; uc[10] = (long long)((long double)y/frameHeight*10000000000)%100; }

接收端关键代码:对于被控端来说,接收到控制数据之后就需要在当前系统上响应,这个对于Windows和Linux两种系统是不同的处理。

Windows系统:使用mouse_event()和keybd_event()函数可以直接进行响应。

/*被控端 只接收 控制端 的数据,不发送控制数据*/
Pos_CmdThread::Pos_CmdThread(QTcpSocket* socket, QObject *parent) :
    QThread(parent)
{
    cmdSocket = socket;
    cmd_buf_fill = 0;
    connect(cmdSocket, SIGNAL(readyRead()), this, SLOT(newData()));
}
void Pos_CmdThread::run()
{
    QThread::run();
}

//当tcp socket有新数据到达时运行此函数
void Pos_CmdThread::newData()
{
    while(true)
    {
        int r = cmdSocket->read((char*)(cmd_buf + cmd_buf_fill), 16 - cmd_buf_fill);
        if(r <= 0)
        {
            qWarning()<<"被控端:控制功能-控制数据读取发生错误!";
            return;
        }
        cmd_buf_fill += r;
        //每16个字节为一个完整命令数据
        if(cmd_buf_fill == 16)
        {
            newCommand();
            cmd_buf_fill = 0;
        }
    }

}

void Pos_CmdThread::newCommand()
{
    qDebug()<<"被控端:被控线程-接收到新的控制信息-"<<cmd_buf[0];
    int cmd = cmd_buf[0];
    switch(cmd)
    {
        case CMD_MOUSE_MOVE_TO:
            cmdMouseMoveTo();
            break;
        case CMD_MOUSE_LEFT_DOWN:
            cmdMouseLeftDown();
            break;
        case CMD_MOUSE_LEFT_UP:
            cmdMouseLeftUp();
            break;
        case CMD_MOUSE_RIGHT_DOWN:
            cmdMouseRightDown();
            break;
        case CMD_MOUSE_RIGHT_UP:
            cmdMouseRightUp();
            break;
        case CMD_MOUSE_WHEEL:
            cmdMouseWheel();
            break;
        case CMD_KEY_PRESS:
            cmdKeyPressed();
            break;
        case CMD_KEY_RELEASE:
            cmdKeyReleased();
            break;
        default:
            qWarning()<<"被控端:被控线程-控制命令类型出错!";
            break;
    }
}
//鼠标移动
void Pos_CmdThread::cmdMouseMoveTo()
{
    QPoint p = transformCoordinate();
    mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE, p.x(), p.y(), 0, 0);
}
//获取鼠标转换后所在的位置
QPoint Pos_CmdThread::transformCoordinate()
{
    //获取比例;
    long double x = cmd_buf[1]*0.01+cmd_buf[3]*0.0001+cmd_buf[5]*0.000001+cmd_buf[7]*0.00000001+cmd_buf[9]*0.0000000001;
    long double y = cmd_buf[2]*0.01+cmd_buf[4]*0.0001+cmd_buf[6]*0.000001+cmd_buf[8]*0.00000001+cmd_buf[10]*0.0000000001;
    //计算鼠标位置,将鼠标映射到65535*65535的矩阵上
    int point_x = x*65535;
    int point_y = y*65535;
    return QPoint(point_x, point_y);
}
//鼠标左键按下
void Pos_CmdThread::cmdMouseLeftDown()
{
    //执行点击事件
    QPoint p = transformCoordinate();
    mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTDOWN, p.x(), p.y(), 0, 0);
}
//鼠标左键释放
void Pos_CmdThread::cmdMouseLeftUp()
{
    QPoint p = transformCoordinate();
    mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTUP, p.x(), p.y(), 0, 0);
}
//鼠标右键按下
void Pos_CmdThread::cmdMouseRightDown()
{
    //执行点击事件
    QPoint p = transformCoordinate();
    mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTDOWN, p.x(), p.y(), 0, 0);
}
//鼠标右键释放
void Pos_CmdThread::cmdMouseRightUp()
{
    //执行点击事件
    QPoint p = transformCoordinate();
    mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_RIGHTUP, p.x(), p.y(), 0, 0);
}
//鼠标滚轮事件
void Pos_CmdThread::cmdMouseWheel()
{
    int delta = cmd_buf[11];
    //乘以256加余数得到原值
    delta = delta << 8;
    delta += cmd_buf[12];
    //判断正负
    delta = cmd_buf[13]==0 ? delta*(-1) :delta;
    QPoint p = transformCoordinate();
    qDebug()<<p.x()<<p.y()<<delta;
    mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_WHEEL, p.x(), p.y(), delta, 0);
}
//键盘按键按下
void Pos_CmdThread::cmdKeyPressed()
{
    uchar key = cmd_buf[1];//Windows端,所以用【1】字段
    keybd_event(key, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
}
//键盘按键释放
void Pos_CmdThread::cmdKeyReleased()
{
    uchar key = cmd_buf[1];//Windows端,所以用【1】字段
    keybd_event(key, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}

Linux系统:采用写入事件文件的方式来处理控制响应。

#include "pos_cmdthread.h"

/*被控端 只接收 控制端 的数据,不发送控制数据*/
Pos_CmdThread::Pos_CmdThread(QTcpSocket* socket, QObject *parent) :
    QThread(parent)
{
    cmdSocket = socket;
    cmd_buf_fill = 0;
    connect(cmdSocket, SIGNAL(readyRead()), this, SLOT(newData()));
}
void Pos_CmdThread::run()
{
    QThread::run();
}

//当tcp socket有新数据到达时运行此函数
void Pos_CmdThread::newData()
{
//    qDebug("被控端:获取到操作事件!");1

    while(true)
    {
        int r = cmdSocket->read((char*)(cmd_buf + cmd_buf_fill), 16 - cmd_buf_fill);
        if(r <= 0)
        {
            qWarning()<<"被控端:控制功能-控制数据读取发生错误!";
            return;
        }
        cmd_buf_fill += r;
        //每16个字节为一个完整命令数据
        if(cmd_buf_fill == 16)
        {
            newCommand();
            cmd_buf_fill = 0;
        }
    }

}

void Pos_CmdThread::newCommand()
{
    qDebug()<<"被控端:被控线程-接收到新的控制信息-"<<cmd_buf[0]<<cmd_buf[1]<<cmd_buf[2];
    int cmd = cmd_buf[0];
    switch(cmd)
    {
        case CMD_MOUSE_MOVE_TO:
            cmdMouseMoveTo();
            break;
        case CMD_MOUSE_LEFT_DOWN:
            cmdMouseLeftDown();
            break;
        case CMD_MOUSE_LEFT_UP:
            cmdMouseLeftUp();
            break;
        case CMD_MOUSE_RIGHT_DOWN:
            cmdMouseRightDown();
            break;
        case CMD_MOUSE_RIGHT_UP:
            cmdMouseRightUp();
            break;
        case CMD_MOUSE_WHEEL:
            cmdMouseWheel();
            break;
        case CMD_KEY_PRESS:
            cmdKeyPressed();
            break;
        case CMD_KEY_RELEASE:
            cmdKeyReleased();
            break;
        default:
            qWarning()<<"被控端:被控线程-控制命令类型出错!";
            break;
    }
}
//鼠标移动
void Pos_CmdThread::cmdMouseMoveTo()
{
    QPoint p = transformCoordinate();
    int fd_kbd = open("/dev/input/event2",O_RDWR);
    if(fd_kbd<=0)
    {
        qWarning("Can not open mouse input file\n");
        return ;
    }
    simulate_mouse(fd_kbd,p.x(),p.y());
    close(fd_kbd);
}
//获取鼠标转换后所在的位置
QPoint Pos_CmdThread::transformCoordinate()
{
    //获取比例;
    long double x = cmd_buf[1]*0.01+cmd_buf[3]*0.0001+cmd_buf[5]*0.000001+cmd_buf[7]*0.00000001+cmd_buf[9]*0.0000000001;
    long double y = cmd_buf[2]*0.01+cmd_buf[4]*0.0001+cmd_buf[6]*0.000001+cmd_buf[8]*0.00000001+cmd_buf[10]*0.0000000001;
    //计算鼠标位置,将鼠标映射到65535*65535的矩阵上
    int point_x = x*65535;
    int point_y = y*65535;
    return QPoint(point_x, point_y);
}
//鼠标左键按下
void Pos_CmdThread::cmdMouseLeftDown()
{
    int fd_mouse = open("/dev/input/event2",O_RDWR);
    if(fd_mouse<=0)
    {
        qWarning("Can not open mouse input file\n");
        return ;
    }
    simulate_key_pressed(fd_mouse,BTN_LEFT);
    close(fd_mouse);
}
//鼠标左键释放
void Pos_CmdThread::cmdMouseLeftUp()
{
    int fd_mouse = open("/dev/input/event2",O_RDWR);
    if(fd_mouse<=0)
    {
        qWarning("Can not open mouse input file\n");
        return ;
    }
    simulate_key_released(fd_mouse,BTN_LEFT);
    close(fd_mouse);
}
//鼠标右键按下
void Pos_CmdThread::cmdMouseRightDown()
{
    int fd_mouse = open("/dev/input/event2",O_RDWR);
    if(fd_mouse<=0)
    {
        qWarning("Can not open mouse input file\n");
        return ;
    }
    simulate_key_pressed(fd_mouse,BTN_RIGHT);
    close(fd_mouse);
}
//鼠标右键释放
void Pos_CmdThread::cmdMouseRightUp()
{
    int fd_mouse = open("/dev/input/event2",O_RDWR);
    if(fd_mouse<=0)
    {
        qWarning("Can not open mouse input file\n");
        return ;
    }
    simulate_key_released(fd_mouse,BTN_RIGHT);
    close(fd_mouse);
}
//鼠标滚轮事件
void Pos_CmdThread::cmdMouseWheel()
{
    int delta = cmd_buf[11];
    //乘以256加余数得到原值
    delta = delta << 8;
    delta += cmd_buf[12];
    //判断正负
    delta = cmd_buf[13]==0 ? delta*(-1) :delta;
    QPoint p = transformCoordinate();
    qDebug()<<p.x()<<p.y()<<delta;
//    mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_WHEEL, p.x(), p.y(), delta, 0);
}

//键盘按键按下
void Pos_CmdThread::cmdKeyPressed()
{
    uchar key = cmd_buf[2];//Linux端,所以用【2】字段
    int fd_kbd = open("/dev/input/event1",O_RDWR);
    if(fd_kbd<=0)
    {
        qWarning("Can not open keyboard input file\n");
        return ;
    }
    simulate_key_pressed(fd_kbd,key);
//    simulate_key(fd_kbd,key);
    close(fd_kbd);
}
//键盘按键释放
void Pos_CmdThread::cmdKeyReleased()
{
    uchar key = cmd_buf[2];//Linux端,所以用【2】字段
    int fd_kbd = open("/dev/input/event1",O_RDWR);
    if(fd_kbd<=0)
    {
        qWarning("Can not open keyboard input file\n");
        return ;
    }
    simulate_key_released(fd_kbd,key);
    close(fd_kbd);
}

//按键模拟,按键包含按下和松开两个环节
void Pos_CmdThread::simulate_key(int fd, int kval)
{
    qDebug("Pos_CmdThread::simulate_key-按键模拟");
    struct input_event event;
    gettimeofday(&event.time, 0);

    //按下kval键
    event.type = EV_KEY;
    event.value = 1;
    event.code = kval;
    write(fd, &event, sizeof(event));

    //同步,也就是把它报告给系统
    event.type = EV_SYN;
    event.value = 1;
    event.code = SYN_REPORT;
    write(fd, &event, sizeof(event));

    memset(&event, 0, sizeof(event));
    gettimeofday(&event.time, 0);

    //松开kval键
    event.type = EV_KEY;
    event.value = 0;
    event.code = kval;
    write(fd, &event, sizeof(event));


    //同步,也就是把它报告给系统
    event.type = EV_SYN;
    event.value = 0;
    event.code = SYN_REPORT;
    write(fd, &event, sizeof(event));
}

//按键按下
void Pos_CmdThread::simulate_key_pressed(int fd, int kval)
{
    qDebug("Pos_CmdThread::simulate_key_pressed——按下按键模拟");
    struct input_event event;
    gettimeofday(&event.time, 0);

    //按下kval键
    event.type = EV_KEY;
    event.value = 1;
    event.code = kval;
    write(fd, &event, sizeof(event));

    //同步,也就是把它报告给系统
    event.type = EV_SYN;
    event.value = 1;
    event.code = SYN_REPORT;
    write(fd, &event, sizeof(event));

    memset(&event, 0, sizeof(event));
}

//按键释放
void Pos_CmdThread::simulate_key_released(int fd, int kval)
{
    qDebug("Pos_CmdThread::simulate_key_released——释放按键模拟");
    struct input_event event;
    gettimeofday(&event.time, 0);

    //按下kval键
    event.type = EV_KEY;
    event.value = 0;
    event.code = kval;
    write(fd, &event, sizeof(event));

    //同步,也就是把它报告给系统
    event.type = EV_SYN;
    event.value = 0;
    event.code = SYN_REPORT;
    write(fd, &event, sizeof(event));

    memset(&event, 0, sizeof(event));
}
//鼠标移动模拟
void Pos_CmdThread::simulate_mouse(int fd, int rel_x, int rel_y)
{
    qDebug("鼠标移动模拟");
    struct input_event event;
    gettimeofday(&event.time, 0);

    //x轴坐标的相对位移
    event.type = EV_ABS;
    event.value = rel_x;
    event.code = ABS_X;
    write(fd, &event, sizeof(event));

    //y轴坐标的相对位移
    event.type = EV_ABS;
    event.value = rel_y;
    event.code = ABS_Y;
    write(fd, &event, sizeof(event));

    //同步
    event.type = EV_SYN;
    event.value = 0;
    event.code = SYN_REPORT;
    write(fd, &event, sizeof(event));

}

 

3.文件传输的线程

发送端关键代码:很常规的文件传输,没什么可说的。

//发送文件数据
void TransFile::startTransfer()
{
    QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_5_7);

    localFile=new QFile(fileName);
    if(!localFile->open(QFile::ReadOnly))
    {
        qWarning()<<"控制端:"<<"打开文件出错!";
        return;
    }
    //文件大小
    totalBytes=localFile->size();
    //传输总大小,文件总大小、文件名大小、文件名
    sendOut<<qint64(0)<<qint64(0)<<qint64(0)<<currentFileName;
    //传输总大小
    totalBytes+=outBlock.size();
    sendOut.device()->seek(0);
    //填充 传输总大小,文件总大小、文件名大小, 发送大小等头部信息
    sendOut<<totalBytes<<localFile->size()<<qint64(outBlock.size()-sizeof(qint64)*3);
    tcpClient->write(outBlock);
    //发送真实数据
    int sendSize = 0 , len = 0;
    do
    {
        //每次发送数据的大小
        char buf[1024] = {0};
        len=0;
        //往文件里读数据
        len = localFile->read(buf,sizeof(buf));
        if(len<=0)
        {
            qWarning()<<"发送端:文件传输-读取文件数据失败!";
            return;
        }
        //发送数据,读多少,发多少
        len = tcpClient->write(buf,len);
        if(len<=0)
        {
            qWarning()<<"发送端:文件传输-发送数据失败!";
            return;
        }
        sendSize+=len;
    }while(len>0);
    ui->label_Filestate->setText(tr("传送文件 %1 成功,对方已断开!").arg(currentFileName));
    ui->pBt_Trans->setText("已发送");
    ui->pBt_Trans->setEnabled(false);
    outBlock.resize(0);
    totalBytes = 0;
    qDebug()<<"控制端:"<<"发送文件"<<currentFileName<<"成功!";
}

接收端关键代码:

//当tcp socket有新数据到达时运行此函数
void Pos_TransThread::newData()
{
    qDebug()<<"接收端:"<<"开始接收文件!";
    //使用数据流读取
    QDataStream in(transSocket);
    in.setVersion(QDataStream::Qt_5_7);
    // 如果接收到的数据小于24个字节,保存到来的文件头结构
    if (m_bytesReceived<=sizeof(qint64)*3)
    {
        if((transSocket->bytesAvailable()>=sizeof(qint64)*3)&&(m_fileNameSize==0))
        {
            // 接收数据总大小信息,文件大小 和文件名大小信息
            in>>m_totalBytes>>m_fileSize>>m_fileNameSize;
            m_bytesReceived +=sizeof(qint64)*3;
        }
        if((transSocket->bytesAvailable()>=m_fileNameSize)&&(m_fileNameSize!=0))
        {
            // 接收文件名,并建立文件
            in>>m_fileName;
            m_bytesReceived+=m_fileNameSize;
            m_localFile = new QFile(m_fileName);
            //打开文件
            if (!m_localFile->open(QFile::WriteOnly|QIODevice::Append)){
                qWarning() << "接收端:文件打开失败!"<<m_fileName;
                return;
            }
        }
        else return;
    }
    // 如果接收的数据小于总数据,那么写入文件
    if(m_bytesReceived<m_totalBytes) {
        m_bytesReceived+=transSocket->bytesAvailable();
        m_inBlock = transSocket->readAll();
        quint64 len = m_localFile->write(m_inBlock);
        if(len<=0)
        {
            qWarning()<<"文件传输接收端出现错误,写入文件失败!";
            return;
        }
        m_inBlock.resize(0);
    }
    // 接收数据完成时
    if (m_bytesReceived==m_totalBytes)
    {
        qDebug()<<"接收端:接收文件成功"<<m_fileName<<"自动断开连接!";
        //弹窗提醒接收成功
        QMessageBox::about(NULL,"","接收文件成功!");
        transSocket->close();
        m_localFile->close();
    }
}

转发地址:
链接:https://pan.baidu.com/s/1q4UyaVszfsW_aKy5YF6fNQ 
提取码:wcnk 

 


相关推荐
发表评论

评论列表(条)