CSharp通过Websocket传输图片在WEB端显示及传递鼠标事件

2023-05-31 10:58:17 浏览数 (2)

图片传输

C#获取屏幕二进制数据

代码语言:javascript复制
using System.IO;

namespace z_remote_control.Utils
{
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Windows.Forms;

    public class ZScreenUtils
    {
        public static byte[] GetScreenshot()
        {
            using (Bitmap screenshot = new Bitmap(
                       Screen.PrimaryScreen.Bounds.Width,
                       Screen.PrimaryScreen.Bounds.Height
                   ))
            {
                using (Graphics gfx = Graphics.FromImage(screenshot))
                {
                    gfx.CopyFromScreen(
                        Screen.PrimaryScreen.Bounds.X,
                        Screen.PrimaryScreen.Bounds.Y,
                        0,
                        0,
                        Screen.PrimaryScreen.Bounds.Size,
                        CopyPixelOperation.SourceCopy
                    );
                    using (MemoryStream ms = new MemoryStream())
                    {
                        screenshot.Save(
                            ms,
                            ImageFormat.Png
                        );
                        return ms.ToArray();
                    }
                }
            }
        }
    }
}

我们使用单独的线程不停发送图片

代码语言:javascript复制
private void SendPic()
{
    new Thread(
        () =>
        {
            while (true)
            {
                ZwsServer wsServer = ZwsServer.GetInstance();
                var screenshot = ZScreenUtils.GetScreenshot();
                wsServer.SendMessageToAll(screenshot);
            }
        }
    ).Start();
}

Web端接收显示

代码语言:javascript复制
socket.onmessage = (evt) => {
    if (typeof evt.data === 'string') {
      // 处理字符串类型的数据

    } else if (evt.data instanceof Blob) {
      // 处理 Blob 类型的数据
      const imageUrl = URL.createObjectURL(evt.data);
      this.img_url = imageUrl;
    }
};

鼠标事件传递

Web鼠标事件

获取鼠标所在元素内的位置

代码语言:javascript复制
get_pos (e, box) {
  // 获取鼠标相对于浏览器窗口视口的位置
  var mouseX = e.clientX;
  var mouseY = e.clientY;

  // 获取元素相对于浏览器窗口视口的位置
  var boxRect = box.getBoundingClientRect();
  var boxX = boxRect.left;
  var boxY = boxRect.top;

  // 计算鼠标在元素内的相对位置
  var relativeX = mouseX - boxX;
  var relativeY = mouseY - boxY;
  const width = box.offsetWidth;
  const height = box.offsetHeight;
  if (relativeX < 0) {
    relativeX = 0;
  }
  if (relativeY < 0) {
    relativeY = 0;
  }
  if (relativeX > width) {
    relativeX = width;
  }
  if (relativeY > height) {
    relativeY = height;
  }
  return {
    btn: e.button,//0左键  2右键
    x: relativeX / width,
    y: relativeY / height
  }
},

注意

这里返回的值是0-1。

元素监听事件

代码语言:javascript复制
init_mouse_event () {
  let myimg = this.$refs["myimg"];
  let that = this;
  myimg.addEventListener('contextmenu', function (e) {
    e.preventDefault();
  });
  myimg.addEventListener('mousedown', function (e) {
    var pos = that.get_pos(e, this);
    console.log(pos.btn, "鼠标按下", '('   pos.x   ','   pos.y   ')');
  });

  myimg.addEventListener('mouseup', function (e) {
    var pos = that.get_pos(e, this);
    console.log(pos.btn, "鼠标抬起", '('   pos.x   ','   pos.y   ')');
  });

  myimg.addEventListener('mousemove', function (e) {
    var pos = that.get_pos(e, this);
    console.log(pos.btn, "移动", '('   pos.x   ','   pos.y   ')');
  });
},

注意

这是用来禁用右键菜单

代码语言:javascript复制
myimg.addEventListener('contextmenu', function (e) {
e.preventDefault();
});

C#模拟鼠标事件

在C#中触发鼠标事件:

SendInput

使用Windows API函数

  1. 首先导入Windows API类库,包括“using System.Runtime.InteropServices;”等命名空间。
  2. 在程序中定义鼠标事件的常量和结构体,如下所示:
代码语言:javascript复制
public const int MOUSEEVENTF_MOVE = 0x0001; //移动鼠标
public const int MOUSEEVENTF_LEFTDOWN = 0x0002; //左键按下
public const int MOUSEEVENTF_LEFTUP = 0x0004; //左键抬起
public const int MOUSEEVENTF_RIGHTDOWN = 0x0008; //右键按下
public const int MOUSEEVENTF_RIGHTUP = 0x0010; //右键抬起

[DllImport("user32.dll")]
static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
   public int dx;
   public int dy;
   public int mouseData;
   public int dwFlags;
   public int time;
   public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
   public int type;
   public MOUSEINPUT mi;
}
  1. 编写代码触发相应的鼠标事件,如下所示:
代码语言:javascript复制
public void MoveMouse(int x, int y)
{
   INPUT input = new INPUT();
   input.type = 0; //0表示鼠标事件
   input.mi.dx = x;
   input.mi.dy = y;
   input.mi.mouseData = 0;
   input.mi.dwFlags = MOUSEEVENTF_MOVE;
   input.mi.time = 0;
   input.mi.dwExtraInfo = IntPtr.Zero;
   SendInput(1, ref input, Marshal.SizeOf(input));
}

public void LeftClick(int x, int y)
{
   INPUT input = new INPUT();
   input.type = 0; //0表示鼠标事件
   input.mi.dx = x;
   input.mi.dy = y;
   input.mi.mouseData = 0;
   input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
   input.mi.time = 0;
   input.mi.dwExtraInfo = IntPtr.Zero;
   SendInput(1, ref input, Marshal.SizeOf(input));

   input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
   SendInput(1, ref input, Marshal.SizeOf(input));
}

mouse_event

使用C#触发鼠标的移动、按下和抬起事件的完整代码:

代码语言:javascript复制
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace MouseOperation
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        static extern bool SetCursorPos(int x, int y);

        [DllImport("user32.dll")]
        static extern void mouse_event(uint dwFlags, int dx, int dy, uint dwData, int dwExtraInfo);

        private const uint MOUSEEVENTF_LEFTDOWN = 0x02;
        private const uint MOUSEEVENTF_LEFTUP = 0x04;
        private const uint MOUSEEVENTF_MOVE = 0x0001;

        public Form1()
        {
            InitializeComponent();
        }

        private void btnMove_Click(object sender, EventArgs e)
        {
            int x = Cursor.Position.X;
            int y = Cursor.Position.Y;
            SetCursorPos(x   10, y   10);
            Thread.Sleep(500);
            SetCursorPos(x, y);
        }

        private void btnClick_Click(object sender, EventArgs e)
        {
            mouse_event(MOUSEEVENTF_LEFTDOWN, Cursor.Position.X, Cursor.Position.Y, 0, 0);
            Thread.Sleep(100);
            mouse_event(MOUSEEVENTF_LEFTUP, Cursor.Position.X, Cursor.Position.Y, 0, 0);
        }

        private void btnDrag_Click(object sender, EventArgs e)
        {
            int x = Cursor.Position.X;
            int y = Cursor.Position.Y;
            mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
            Thread.Sleep(500);
            SetCursorPos(x   10, y   10);
            mouse_event(MOUSEEVENTF_MOVE, x   10, y   10, 0, 0);
            Thread.Sleep(500);
            SetCursorPos(x, y);
            mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0);
        }
    }
}

这个代码示例提供了三个按钮,分别用于模拟鼠标的移动、点击和拖拽操作。在 btnMove_Click 中,我们首先获取当前鼠标光标的位置,并将其向右下角移动 10 个像素,然后等待 500 毫秒,最后将鼠标光标移回原来的位置。在 btnClick_Click 中,我们模拟了鼠标左键按下和抬起的事件。在 btnDrag_Click 中,我们模拟了鼠标的拖拽事件。

为了调用鼠标事件,我们在代码中使用了 DllImport 库引入了 user32.dll,并调用了其中的 SetCursorPosmouse_event 方法。SetCursorPos 方法用于设置鼠标光标的位置,而 mouse_event 方法则用于向系统发送鼠标事件。在 mouse_event 方法中,我们可以使用 dwFlags 参数指定要模拟的鼠标事件类型,如左键按下、左键抬起和鼠标移动等。

需要注意的是

使用Windows API函数触发鼠标事件需要使用[DllImport("user32.dll")]引入相应的函数,并且需要在程序执行时以管理员身份运行。

对比

SendInput 和 mouse_event 都可以用于模拟鼠标事件,它们的主要区别在于:

  1. SendInput 是 Windows 操作系统提供的 API,而 mouse_event 是 Win32 API。
  2. SendInput 是较新的 API,可以用于模拟更多种类的输入设备(如键盘、鼠标、触摸屏等),而 mouse_event 只能模拟鼠标事件。
  3. SendInput 的精度比 mouse_event 更高,可以模拟出更精确的鼠标操作。
  4. SendInput 可以通过异步方式模拟鼠标事件,而 mouse_event 只能同步方式模拟。

因此,如果需要模拟多种输入设备事件或需要精确模拟鼠标操作,建议使用 SendInput。如果只需要模拟鼠标事件并且需求不是很高,则可以使用 mouse_event。

0 人点赞