python+flask_socketio+pyautogui实现简易远程桌面功能

python+flask_socketio+pyautogui实现简易远程桌面功能

python 复制代码
import base64
import pyautogui
from flask import Flask
import time
from flask_socketio import SocketIO, emit
from io import BytesIO
import pyperclip


app=Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'

socketio = SocketIO(app)

@socketio.on('connect')
def handle_connect():
    """客户端连接时触发"""
    print('客户端已连接')
    emit('server_response', {'data': '连接成功'})
    # 连接成功后,获取最新的远程屏幕
    client_get_screen()

@socketio.on('client_send_keyboard_input')
def client_send_keyboard_input(json):
    """处理来自客户端的消息"""
    print('收到客户端消息:', json)
    # 模拟键盘输入
    client_input=json['data']
    print('客户端输入:', client_input)
    # typewrite只会输入字母,其他字符会被忽略
    pyautogui.typewrite(client_input)
    client_get_screen()


@socketio.on('client_send_paste_key')
def client_send_paste_key(json):
    """处理来自客户端的粘贴消息"""
    print('收到客户端粘贴消息:', json)
    # 模拟粘贴操作
    client_paste_text=json['data']
    print('客户端粘贴文本:', client_paste_text)
    # 先将文本复制到剪贴板
    pyperclip.copy(client_paste_text)
    # 模拟粘贴键
    pyautogui.hotkey('ctrl', 'v')
    client_get_screen()
    

@socketio.on('client_get_screen')
def client_get_screen():
    """处理获取远程屏幕请求"""
    print('收到获取远程屏幕请求')    
    # 循环刷新3次
    for i in range(5):
        # 延迟0.2秒
        time.sleep(0.2)
        screen = pyautogui.screenshot()
        # 将屏幕图片转换为base64编码
        buffered = BytesIO()
        screen.save(buffered, format="PNG")
        screen_base64 = base64.b64encode(buffered.getvalue()).decode('utf-8')
        # 发送base64编码的屏幕图片给所有客户端
        emit('remote_screen_update', {'data': screen_base64},broadcast=False)


@socketio.on('client_click_screen')
def handle_client_click(json):
    """处理来自客户端的点击事件"""
    print('收到客户端点击事件:', json)
    x, y = json['x'], json['y']
    # 映射到主机屏幕坐标
    screen_width, screen_height = pyautogui.size()
    x, y = int(x * screen_width), int(y * screen_height)
    pyautogui.moveTo(x, y)
    pyautogui.click(x, y)
    # emit('server_response', {'data': f'已点击屏幕位置: ({x}, {y})'},broadcast=False)
    # 点击鼠标事件后,获取最新的远程屏幕
    client_get_screen()

@socketio.on('client_dbclick_screen')
def handle_client_dbclick(json):
    """处理来自客户端的双击事件"""
    print('收到客户端双击事件:', json)
    x, y = json['x'], json['y']
    # 映射到主机屏幕坐标
    screen_width, screen_height = pyautogui.size()
    x, y = int(x * screen_width), int(y * screen_height)
    pyautogui.doubleClick(x, y)
    # 双击鼠标事件后,获取最新的远程屏幕
    client_get_screen()

@socketio.on('client_send_enter_key')
def handle_client_send_enter_key():
    """处理来自客户端的Enter键事件"""
    print('收到客户端Enter键事件')
    # 模拟键盘输入Enter键
    pyautogui.press('enter')
    client_get_screen()



@socketio.on('client_send_delete_key')
def handle_client_send_delete_key():
    """处理来自客户端的Delete键事件"""
    print('收到客户端Delete键事件')
    # 模拟键盘输入Delete键
    pyautogui.press('backspace')
    client_get_screen()

@app.route('/telescreen')
def index():
    """渲染主页"""
    return '''
        <!DOCTYPE html>
        <html>
        <head>
            <meta lang="zh-CN">
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>teledesk</title>
            <style>
                body{
                    background-color:black;
                }
                #telescreen {
                    position: relative;
                    background-color:skyblue;
                    box-shadow: 0 0 1em rgba(0, 0, 0, 0.5);
                    border:1em solid gray;
                    border-radius: 1em;
                    resize: both;
                    overflow: auto;
                }
                #remote_screen {
                    position: relative;
                    top: 0;
                    left: 0;
                    width: 100%;
                }
                #control_panel{
                    background-color: gray;
                    padding: 1em;
                    border-radius: 1em;                    
                }
                button,input
                {
                    margin: 0.5em;
                    padding: 0.5em 1em;
                    border-radius: 0.5em;
                    border: 1px solid #666;
                }
            </style>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
            <script type="text/javascript">
                document.addEventListener('DOMContentLoaded', () => {
                    // 连接到服务器
                    const socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);
                    
                    // 接收服务器消息
                    socket.on('server_response', (data) => {
                        console.log("收到服务器响应:", data);
                    });

                    // 接收远程屏幕
                    socket.on('remote_screen_update', (data) => {
                        console.log("收到远程屏幕:", data);
                        // 清除旧的远程屏幕图片
                        while (document.getElementById('telescreen').firstChild) {
                            document.getElementById('telescreen').removeChild(document.getElementById('telescreen').firstChild);
                        }
                        //创建新的远程屏幕图片
                        const remote_screen = document.createElement('img');
                        remote_screen.id = 'remote_screen';                        
                        remote_screen.src=` data:image/png;base64,${data.data}`;
                        remote_screen.alt = '远程屏幕';
                        remote_screen.addEventListener('click', (e) => {
                            const rect = e.target.getBoundingClientRect();
                            const x = (e.clientX - rect.left) / rect.width;
                            const y = (e.clientY - rect.top) / rect.height;
                            console.log(`点击位置: (${x}, ${y})`);
                            socket.emit('client_click_screen', {x, y});
                        });
                        remote_screen.addEventListener('dbclick', (e) => {
                            const rect = e.target.getBoundingClientRect();
                            const x = (e.clientX - rect.left) / rect.width;
                            const y = (e.clientY - rect.top) / rect.height;
                            console.log(`点击位置: (${x}, ${y})`);
                            socket.emit('client_dbclick_screen', {x, y});
                        });
                        document.getElementById('telescreen').appendChild(remote_screen);
                    });

                    // 绑定获取屏幕按钮事件
                    document.getElementById('get_screen').addEventListener('click', () => {
                        socket.emit('client_get_screen');
                    });
                    
                    // 绑定发送按钮事件
                    document.getElementById('send_button').addEventListener('click', (e) => {
                        const input = document.getElementById('message_input');
                        socket.emit('client_send_keyboard_input', {data: input.value});
                        input.value = '';
                    });

                    // 绑定粘贴按钮事件
                    document.getElementById('paste_button').addEventListener('click', (e) => {
                        const input = document.getElementById('message_input');
                        socket.emit('client_send_paste_key', {data: input.value});
                        input.value = '';
                    });

                   
                    // 绑定Enter键事件
                    document.getElementById('enter_button').addEventListener('click', (e) => {
                        socket.emit('client_send_enter_key');
                    });

                    // 绑定Delete键事件
                    document.getElementById('delete_button').addEventListener('click', (e) => {
                        socket.emit('client_send_delete_key');
                    });


                });
            </script>
        </head>
        <body>

            <div id="telescreen">
                <img id="remote_screen" src="" alt="远程屏幕">
            </div>

            <div id="control_panel">

                <button id="get_screen">刷新远程屏幕</button>

                <br/>

                <input type="text" id="message_input" placeholder="输入要发送给远程屏幕的消息">

                <br/>

                <button id="send_button">发送输入文本</button>

                <br/>

                <button id="paste_button">粘贴输入文本</button>

                <button id="delete_button">Delete</button>

                <br/>

                <button id="enter_button">Enter</button>

            </div>

        </body>
        </html>


        '''

if __name__ == '__main__':
    socketio.run(app, debug=True,host='0.0.0.0',port=5000)
相关推荐
大鹏说大话17 小时前
从爬虫到决策引擎:大数据下自媒体如何用Python挖掘用户痛点
开发语言·爬虫·python
Niuguangshuo17 小时前
silero-vad:超轻量级开源 VAD 实践指南
开发语言·python
2501_9446761618 小时前
揭秘!WORDTIP公司靠不靠谱?小白必看
大数据·人工智能·python
Minner-Scrapy18 小时前
Scrapy 2.17 源码解析:Scheduler 调度器与磁盘/内存双队列
java·爬虫·python·scrapy·网络爬虫·twisted
CODER030418 小时前
Anaconda和Mamba创建环境管理包常用命令合集
python·深度学习·conda·虚拟环境·mamba·常用命令大全
闲猫18 小时前
LangGraph / Capabilities / Fault tolerance
python·agent·langgraph
IvanCodes19 小时前
Python 基础语法(一):变量、数据类型与运算符
python
程序员三藏20 小时前
浅谈性能测试
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·性能测试
l12586520 小时前
# RAG向量数据库优化实战:HNSW索引调参与生产级性能设计
数据库·python·mysql·langchain
meilindehuzi_a21 小时前
Python 基础语法(1):常量、变量、类型、输入输出与运算符
开发语言·python