前言
上篇文章中,我们借助WebRTC的P2P能力做了一个远程桌面工具的基础拉流功能,但远程工具只看到画面还不够,我们还需要对画面进行交互,这篇文章我们看一下指针事件如何实现。
指针时间的采集
因为我们使用的是浏览器作为拉流端,那么我的画面在浏览器是一个video标签来作为远程电脑的画面承载容器。我们对这边video标签做的点击事件要作为采集的目标,这里选择的是pointerEvent事件作为采集,相关采集的代码也很简单,我直接贴在下方
function initDcEvent(dataChannel) {
const remoteVideo = document.getElementById('remoteVideo');
remoteVideo.addEventListener('pointerdown', event => {
sendPointerEvent('down', event);
});
remoteVideo.addEventListener('pointerup', event => {
sendPointerEvent('up', event);
});
remoteVideo.addEventListener('pointermove', event => {
if (event.pointerType === 'mouse' && event.buttons === 0) return; // 鼠标滑过忽略
sendPointerEvent('move', event);
});
function sendPointerEvent(type, event) {
const rect = remoteVideo.getBoundingClientRect();
const x = +((event.pageX - (rect.left + window.scrollX)) / widthRatio).toFixed(4);
const y = +((event.pageY - (rect.top + window.scrollY)) / heightRatio).toFixed(4);
const message = {
type: 'pointer',
eventType: type,
x: x,
y: y
};
if (!dataChannel || dataChannel.readyState !== 'open') return;
dataChannel.send(JSON.stringify(message));
}
}
这里的x, y值就是通过计算和比例系数widthRatio算出来的目标电脑的指针坐标,然后数据通过dataChannel通道发送给我们上文写的Mac客户端。
dataChannel通道是WebRTC内的P2P通道,这里不做额外解释,不熟悉的朋友建议查询一下文档
指针事件的模拟
我们的Mac客户端接收到浏览器通过DataChannel通道传输过来Json字符串,我们解析Json之后能得到相应的坐标,我们看下Mac怎么使用代码来模拟鼠标的注入,通过查询我找到了CGEvent的相关能力. 相关核心代码在这里
private func handleCoordinateMessage(_ message: String) {
guard let data = message.data(using: .utf8),
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let type = json["type"] as? String,
type == "pointer",
let eventType = json["eventType"] as? String,
let x = json["x"] as? CGFloat,
let y = json["y"] as? CGFloat else {
return
}
let location = CGPoint(x: x, y: y)
// 检查辅助功能权限
if !AXIsProcessTrusted() {
print("请前往系统设置 -> 隐私与安全性 -> 辅助功能中开启权限")
return
}
switch eventType {
case "move":
let event = CGEvent(mouseEventSource: nil, mouseType: .mouseMoved, mouseCursorPosition: location, mouseButton: .left)
event?.post(tap: .cghidEventTap)
case "down":
let event = CGEvent(mouseEventSource: nil, mouseType: .leftMouseDown, mouseCursorPosition: location, mouseButton: .left)
event?.post(tap: .cghidEventTap)
case "up":
let event = CGEvent(mouseEventSource: nil, mouseType: .leftMouseUp, mouseCursorPosition: location, mouseButton: .left)
event?.post(tap: .cghidEventTap)
default:
break
}
}
大致测试了,鼠标的点击能力和相关坐标对应位置都没问题,完!