基于C#实现类TeamViewer远程鼠标控制技术咨询(已完成屏幕共享)
实现C#远程鼠标控制的分步方案
我之前做过类似的远程控制工具,正好可以给你分享下实现远程鼠标控制的核心步骤,结合你已经有屏幕共享基础的情况,重点放在鼠标事件捕获、数据传输、被控端模拟操作这三块:
一、控制端捕获鼠标事件并转换坐标
首先你需要在控制端的屏幕显示窗口上监听鼠标动作,这里要注意的是:控制端显示的被控端屏幕大概率是缩放后的,所以得把控制端的鼠标相对坐标转换成被控端的绝对屏幕坐标。
举个WinForms的例子:
// 假设controlScreen是显示被控端屏幕的PictureBox private void controlScreen_MouseMove(object sender, MouseEventArgs e) { // 先获取被控端的实际屏幕分辨率(你已经掌握被控端信息,这里直接用已知值) int remoteScreenWidth = 1920; int remoteScreenHeight = 1080; // 计算控制端窗口中显示的屏幕缩放比例 float scaleX = (float)remoteScreenWidth / controlScreen.Width; float scaleY = (float)remoteScreenHeight / controlScreen.Height; // 转换为被控端的绝对坐标 int remoteX = (int)(e.X * scaleX); int remoteY = (int)(e.Y * scaleY); // 打包鼠标移动命令,准备发送 SendMouseCommand(new MouseCommand { CommandType = MouseCommandType.Move, X = remoteX, Y = remoteY }); } // 监听鼠标点击事件 private void controlScreen_MouseDown(object sender, MouseEventArgs e) { // 同样先转换坐标,然后发送点击命令 // ...(坐标转换逻辑同上) MouseButton button = e.Button == MouseButtons.Left ? MouseButton.Left : MouseButton.Right; SendMouseCommand(new MouseCommand { CommandType = MouseCommandType.Down, Button = button, X = remoteX, Y = remoteY }); } private void controlScreen_MouseUp(object sender, MouseEventArgs e) { // 发送松开命令 // ...(坐标转换逻辑同上) MouseButton button = e.Button == MouseButtons.Left ? MouseButton.Left : MouseButton.Right; SendMouseCommand(new MouseCommand { CommandType = MouseCommandType.Up, Button = button, X = remoteX, Y = remoteY }); }
这里我定义了一个简单的命令结构体来统一传输格式:
public enum MouseCommandType { Move, Down, Up } public enum MouseButton { Left, Right } public class MouseCommand { public MouseCommandType CommandType { get; set; } public MouseButton Button { get; set; } public int X { get; set; } public int Y { get; set; } }
二、复用现有通信通道传输命令
既然你已经实现了屏幕共享,肯定已经有了控制端和被控端之间的通信连接(比如TCP Socket),直接把序列化后的MouseCommand通过这个通道发送就行。可以用JSON序列化(比如Newtonsoft.Json)或者二进制序列化,前者更易调试:
private void SendMouseCommand(MouseCommand command) { // 假设socket是已建立的TCP连接 string json = JsonConvert.SerializeObject(command); byte[] data = Encoding.UTF8.GetBytes(json); socket.Send(data); }
三、被控端接收命令并模拟鼠标操作
这一步核心是调用Windows API来模拟鼠标动作,推荐用SendInput函数(mouse_event已经被标记为过时)。首先需要导入user32.dll的相关函数:
using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] public struct INPUT { public uint Type; public MOUSEINPUT MouseInput; } [StructLayout(LayoutKind.Sequential)] public struct MOUSEINPUT { public int dx; public int dy; public uint MouseData; public uint dwFlags; public uint Time; public IntPtr ExtraInfo; } [DllImport("user32.dll", SetLastError = true)] private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); // 鼠标操作的Flag常量 private const uint MOUSEEVENTF_MOVE = 0x0001; private const uint MOUSEEVENTF_LEFTDOWN = 0x0002; private const uint MOUSEEVENTF_LEFTUP = 0x0004; private const uint MOUSEEVENTF_RIGHTDOWN = 0x0008; private const uint MOUSEEVENTF_RIGHTUP = 0x0010; private const uint MOUSEEVENTF_ABSOLUTE = 0x8000;
然后编写处理命令的逻辑:
private void HandleMouseCommand(MouseCommand command) { switch (command.CommandType) { case MouseCommandType.Move: // SendInput的坐标是0-65535的绝对范围,需要转换 int absoluteX = (command.X * 65535) / Screen.PrimaryScreen.Bounds.Width; int absoluteY = (command.Y * 65535) / Screen.PrimaryScreen.Bounds.Height; INPUT[] moveInput = new INPUT[1]; moveInput[0].Type = 0; // 0表示鼠标输入 moveInput[0].MouseInput.dx = absoluteX; moveInput[0].MouseInput.dy = absoluteY; moveInput[0].MouseInput.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; SendInput(1, moveInput, Marshal.SizeOf(typeof(INPUT))); break; case MouseCommandType.Down: INPUT[] downInput = new INPUT[1]; downInput[0].Type = 0; downInput[0].MouseInput.dwFlags = command.Button == MouseButton.Left ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN; SendInput(1, downInput, Marshal.SizeOf(typeof(INPUT))); break; case MouseCommandType.Up: INPUT[] upInput = new INPUT[1]; upInput[0].Type = 0; upInput[0].MouseInput.dwFlags = command.Button == MouseButton.Left ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP; SendInput(1, upInput, Marshal.SizeOf(typeof(INPUT))); break; } }
几个关键注意点
- 坐标转换准确性:一定要确保被控端的实际屏幕分辨率是正确的,不然鼠标位置会偏移;如果被控端有多个屏幕,还要处理目标屏幕的选择。
- 权限问题:有些Windows系统(比如Win10/11的管理员账户)可能需要程序以管理员权限运行才能正常模拟鼠标操作,记得在项目属性里设置
requireAdministrator。 - 延迟优化:连续的鼠标移动事件可以合并成一个或者按频率发送(比如每10ms发送一次),避免过多的网络传输导致卡顿。
内容的提问来源于stack exchange,提问作者Alisa456
相关产品推荐
相关产品推荐

