python+flask_socketio+pyautogui实现简易远程桌面功能
python+flask_socketio+pyautogui实现简易远程桌面功能
import base64
import pyautogui
from flask import Flask
import time
from flask_socketio import SocketIO, emit
from io import BytesIO
import pyperclipapp=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)