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

安装依赖

1
install-package SuperWebSocket

图片传输

C#获取屏幕二进制数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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();
}
}
}
}
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void SendPic()
{
new Thread(
() =>
{
while (true)
{
ZwsServer wsServer = ZwsServer.GetInstance();
var screenshot = ZScreenUtils.GetScreenshot();
wsServer.SendMessageToAll(screenshot);
}
}
).Start();
}

Web端接收显示

1
2
3
4
5
6
7
8
9
10
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鼠标事件

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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。

元素监听事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 + ')');
});
},

注意

这是用来禁用右键菜单

1
2
3
myimg.addEventListener('contextmenu', function (e) {
e.preventDefault();
});

C#模拟鼠标事件

在C#中触发鼠标事件:

SendInput(推荐)

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
namespace z_remote_control.Utils
{
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using static vpxmd.VpxCodecCxPkt;

public class ZMouseKeyEvent
{
[DllImport("user32.dll")]
static extern bool SetCursorPos
(
int x,
int y
);

[DllImport(
"user32.dll",
SetLastError = true
)]
static extern uint SendInput
(
uint nInputs,
Input[] pInputs,
int cbSize
);

[StructLayout(LayoutKind.Sequential)]
struct Input
{
public int type;
public InputUnion U;
}

[StructLayout(LayoutKind.Explicit)]
struct InputUnion
{
[FieldOffset(0)]
public Mouseinput mi;

[FieldOffset(0)]
public Keybdinput ki;
}

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

[StructLayout(LayoutKind.Sequential)]
struct Keybdinput
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}

//事件类型
private const uint INPUT_MOUSE = 0;
private const uint INPUT_KEYBOARD = 1;

//键盘事件
private const uint KEYEVENTF_KEYDOWN = 0;
private const uint KEYEVENTF_KEYUP = 0x0002;

//鼠标事件
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_MIDDLEDOWN = 0x0020;
private const uint MOUSEEVENTF_MIDDLEUP = 0x0040;
private const uint MOUSEEVENTF_WHEEL = 0x0800;

/// <summary>
/// 鼠标移动
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public static void MouseMove
(
int x,
int y
)
{
SetCursorPos(
x,
y
);
}

/// <summary>
/// 鼠标左键按下
/// </summary>
public static void MouseLeftKeyDown()
{
Input[] input = new Input[1];
input[0].type = (int)INPUT_MOUSE;
input[0].U.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
SendInput(
1,
input,
Marshal.SizeOf(input[0])
);
}

/// <summary>
/// 鼠标左键抬起
/// </summary>
public static void MouseLeftKeyUp()
{
Input[] input = new Input[1];
input[0].type = (int)INPUT_MOUSE;
input[0].U.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(
1,
input,
Marshal.SizeOf(input[0])
);
}

/// <summary>
/// 鼠标右键按下
/// </summary>
public static void MouseRightKeyDown()
{
Input[] input = new Input[1];
input[0].type = (int)INPUT_MOUSE;
input[0].U.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
SendInput(
1,
input,
Marshal.SizeOf(input[0])
);
}

/// <summary>
/// 鼠标右键抬起
/// </summary>
public static void MouseRightKeyUp()
{
Input[] input = new Input[1];
input[0].type = (int)INPUT_MOUSE;
input[0].U.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
SendInput(
1,
input,
Marshal.SizeOf(input[0])
);
}

/// <summary>
/// 鼠标中键按下
/// </summary>
public static void MouseMidKeyDown()
{
Input[] input = new Input[1];
input[0].type = (int)INPUT_MOUSE;
input[0].U.mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;
SendInput(
1,
input,
Marshal.SizeOf(input[0])
);
}

/// <summary>
/// 鼠标中键抬起
/// </summary>
public static void MouseMidKeyUp()
{
Input[] input = new Input[1];
input[0].type = (int)INPUT_MOUSE;
input[0].U.mi.dwFlags = MOUSEEVENTF_MIDDLEUP;
SendInput(
1,
input,
Marshal.SizeOf(input[0])
);
}

/// <summary>
/// 滚轮事件
/// </summary>
/// <param name="delta">delta表示鼠标滚轮的旋转量,正值表示向上滚动,负值表示向下滚动。</param>
public static void SendMouseWheel(uint delta)
{
Input[] input = new Input[1];
input[0].type = (int)INPUT_MOUSE;
input[0].U.mi.dwFlags = MOUSEEVENTF_WHEEL;
input[0].U.mi.mouseData = delta;
SendInput(
1,
input,
Marshal.SizeOf(input[0])
);
}

/// <summary>
/// 键盘A点击
/// </summary>
public static void KeyAClick()
{
Input[] input = new Input[1];
input[0].type = (int)INPUT_KEYBOARD;
input[0].U.ki.wVk = (ushort)Keys.A; // A key
input[0].U.ki.dwFlags = KEYEVENTF_KEYDOWN; // key down
SendInput(
1,
input,
Marshal.SizeOf(input[0])
);
input[0].U.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(
1,
input,
Marshal.SizeOf(input[0])
);
}
}
}

调用

模拟鼠标左键点击后移动框选

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Task.Run(
() =>
{
ZMouseKeyEvent.MouseMove(
200,
200
);
Thread.Sleep(600);
ZMouseKeyEvent.MouseLeftKeyDown();
Thread.Sleep(600);
ZMouseKeyEvent.MouseMove(
400,
400
);
Thread.Sleep(600);
ZMouseKeyEvent.MouseLeftKeyUp();
}
);

滚轮滚动

1
2
3
4
//向上滚动
ZMouseKeyEvent.SendMouseWheel(100);
//向下滚动
ZMouseKeyEvent.SendMouseWheel(-100);

误区

移动不能使用下面的这种方式,这种方式是相对于当前位置进行移动,而不是移动到某个坐标。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const uint MOUSEEVENTF_MOVE = 0x0001;

/// <summary>
/// 鼠标移动
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public static void MouseMove
(
int x,
int y
)
{
Input[] input = new Input[1];
input[0].type = (int)INPUT_MOUSE;
input[0].U.mi.dx = x; // absolute x coordinate
input[0].U.mi.dy = y; // absolute y coordinate
input[0].U.mi.dwFlags = MOUSEEVENTF_MOVE;
SendInput(
1,
input,
Marshal.SizeOf(input[0])
);
}

mouse_event

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
namespace z_remote_control.Utils
{
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class ZMouseEvent
{
[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_RIGHTDOWN = 0x0008;
private const uint MOUSEEVENTF_RIGHTUP = 0x0010;
private const uint MOUSEEVENTF_MIDDLEDOWN = 0x0020;
private const uint MOUSEEVENTF_MIDDLEUP = 0x0040;
private const uint MOUSEEVENTF_WHEEL = 0x0800;

/// <summary>
/// 鼠标移动
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public static void MouseMove
(
int x,
int y
)
{
SetCursorPos(
x,
y
);
}

/// <summary>
/// 鼠标左键按下
/// </summary>
public static void MouseLeftKeyDown()
{
mouse_event(
MOUSEEVENTF_LEFTDOWN,
Cursor.Position.X,
Cursor.Position.Y,
0,
0
);
}

/// <summary>
/// 鼠标左键抬起
/// </summary>
public static void MouseLeftKeyUp()
{
mouse_event(
MOUSEEVENTF_LEFTUP,
Cursor.Position.X,
Cursor.Position.Y,
0,
0
);
}

/// <summary>
/// 鼠标右键按下
/// </summary>
public static void MouseRightKeyDown()
{
mouse_event(
MOUSEEVENTF_RIGHTDOWN,
Cursor.Position.X,
Cursor.Position.Y,
0,
0
);
}

/// <summary>
/// 鼠标右键抬起
/// </summary>
public static void MouseRightKeyUp()
{
mouse_event(
MOUSEEVENTF_RIGHTUP,
Cursor.Position.X,
Cursor.Position.Y,
0,
0
);
}

/// <summary>
/// 鼠标中键按下
/// </summary>
public static void MouseMidKeyDown()
{
mouse_event(
MOUSEEVENTF_MIDDLEDOWN,
Cursor.Position.X,
Cursor.Position.Y,
0,
0
);
}

/// <summary>
/// 鼠标中键抬起
/// </summary>
public static void MouseMidKeyUp()
{
mouse_event(
MOUSEEVENTF_MIDDLEUP,
Cursor.Position.X,
Cursor.Position.Y,
0,
0
);
}

public static void SendMouseWheel(int delta)
{
int x = Cursor.Position.X;
int y = Cursor.Position.Y;
mouse_event(
MOUSEEVENTF_WHEEL,
x,
y,
(uint)(delta),
0
);
}
}
}

调用

模拟鼠标左键点击后移动框选

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Task.Run(
() =>
{
ZMouseEvent.MouseMove(
200,
200
);
Thread.Sleep(600);
ZMouseEvent.MouseLeftKeyDown();
Thread.Sleep(600);
ZMouseEvent.MouseMove(
400,
400
);
Thread.Sleep(600);
ZMouseEvent.MouseLeftKeyUp();
}
);

鼠标中键点击

1
2
3
4
5
6
7
8
9
10
11
12
Task.Run(
() =>
{
ZMouseEvent.MouseMove(
600,
600
);
Thread.Sleep(600);
ZMouseEvent.MouseMidKeyDown();
ZMouseEvent.MouseMidKeyUp();
}
);

滚轮滚动

1
2
3
4
//向上滚动
ZMouseEvent.SendMouseWheel(100);
//向下滚动
ZMouseEvent.SendMouseWheel(-100);

误区

移动不要使用下面的这种方式

这种方式是相对于当前位置进行移动,而不是移动到某个坐标。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private const uint MOUSEEVENTF_MOVE = 0x0001;
/// <summary>
/// 鼠标移动
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public static void MouseMove
(
int x,
int y
)
{
mouse_event(
MOUSEEVENTF_MOVE,
x,
y,
0,
0
);
}

对比

SendInput 和 mouse_event 都可以用于模拟鼠标事件

它们的主要区别在于:

  1. SendInput 是 Windows 操作系统提供的 API,而 mouse_event 是 Win32 API。
  2. SendInput 是较新的 API,可以用于模拟更多种类的输入设备(如键盘、鼠标、触摸屏等),而 mouse_event 只能模拟鼠标事件。
  3. SendInput 的精度比 mouse_event 更高,可以模拟出更精确的鼠标操作。
  4. SendInput 可以通过异步方式模拟鼠标事件,而 mouse_event 只能同步方式模拟。
  5. mouse_event 函数则更加简单易用,它只能模拟鼠标相关的输入操作,包括鼠标移动、鼠标单击、双击、右击等。

因此,如果需要模拟多种输入设备事件或需要精确模拟鼠标操作,建议使用 SendInput。

如果只需要模拟鼠标事件并且需求不是很高,则可以使用 mouse_event。