好友
阅读权限10
听众
最后登录1970-1-1
|
vsked
发表于 2025-10-13 17:31
在上一个版本中,我们通过API来调用键盘传输。
java通过网页监控屏幕并控制键盘
https://www.52pojie.cn/thread-2063450-1-1.html
(出处: 吾爱破解论坛)
在这个版本中,我们为远程监控软件实现反向控制功能,不仅可以查看屏幕,还可以进行鼠标操作哟,支持的鼠标操作有单击,双击,右击 操作。
想自己整合键盘或拖动可以自己试着修改下代码.
在这个版本中用了极少的代码就实现了java版本的websocket实时的远程屏幕监控,远程鼠标单击,远程鼠标双击,远程鼠标右击相关功能。
键盘操作API已经写好技术示例,下一步将会将键盘相关功能也整合进来。
先修改前台实现类,用js来捕捉鼠标相关操作,并封装成事件,通过websocket传到后台
[JavaScript] 纯文本查看 复制代码 "use strict"
class Index2 {
baseWebsocketServerUrl = "ws://192.168.100.74:80/imageWebsocket";
websocket = null;
initUI() {
}
initEvent() {
$("#runStateBt").on("click", () => {
if ($("#runStateBt").html() === "开始") {
console.log("hello");
$("#runStateBt").html("停止");
this.initWebsocketConnect();
} else {
console.log("bye");
$("#runStateBt").html("开始");
if (this.websocket) {
this.websocket.close();
this.websocket = null;
}
}
});
// 添加图片点击事件监听器
$("#currentScreenVsk").on("click", (event) => {
this.handleImageClick(event);
});
// 添加双击事件监听器
$("#currentScreenVsk").on("dblclick", (event) => {
this.handleImageDoubleClick(event);
});
// 添加右键点击事件监听器并阻止默认菜单
$("#currentScreenVsk").on("contextmenu", (event) => {
event.preventDefault();
this.handleImageRightClick(event);
});
}
initWebsocketConnect(){
// 如果已有连接,先关闭
if (this.websocket) {
this.websocket.close();
}
// 创建WebSocket连接
this.websocket = new WebSocket(this.baseWebsocketServerUrl);
// 监听WebSocket连接打开
this.websocket.onopen = (event) => {
console.log("WebSocket连接已建立");
// 连接建立后发送消息以启动服务端的数据发送
this.websocket.send("start monitor");
};
// 监听WebSocket消息
this.websocket.onmessage = (event) => {
// 将接收到的数据更新到图片元素
$("#currentScreenVsk").attr("src", event.data);
};
// 监听WebSocket连接关闭
this.websocket.onclose = (event) => {
console.log("WebSocket连接已关闭");
};
// 监听WebSocket错误
this.websocket.onerror = (error) => {
console.error("WebSocket错误:", error);
};
}
handleImageClick(event) {
const img = $("#currentScreenVsk")[0];
const offsetX = event.offsetX;
const offsetY = event.offsetY;
const imgWidth = img.width;
const imgHeight = img.height;
// 计算相对于图片的坐标比例
const xRatio = offsetX / imgWidth;
const yRatio = offsetY / imgHeight;
// 构造坐标数据对象
const clickData = {
type: "mouseClick",
x: xRatio,
y: yRatio,
offsetX: offsetX,
offsetY: offsetY,
imgWidth: imgWidth,
imgHeight: imgHeight
};
// 通过WebSocket发送坐标数据到后台
if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
this.websocket.send(clickData.type+","+clickData.x+","+clickData.y);
} else {
console.warn("WebSocket未连接,无法发送点击坐标");
}
}
handleImageDoubleClick(event) {
const img = $("#currentScreenVsk")[0];
const offsetX = event.offsetX;
const offsetY = event.offsetY;
const imgWidth = img.width;
const imgHeight = img.height;
// 计算相对于图片的坐标比例
const xRatio = offsetX / imgWidth;
const yRatio = offsetY / imgHeight;
// 构造双击事件数据对象
const clickData = {
type: "mouseDoubleClick",
x: xRatio,
y: yRatio,
offsetX: offsetX,
offsetY: offsetY,
imgWidth: imgWidth,
imgHeight: imgHeight
};
// 通过WebSocket发送坐标数据到后台
if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
this.websocket.send(clickData.type+","+clickData.x+","+clickData.y);
} else {
console.warn("WebSocket未连接,无法发送双击坐标");
}
}
handleImageRightClick(event) {
const img = $("#currentScreenVsk")[0];
const offsetX = event.offsetX;
const offsetY = event.offsetY;
const imgWidth = img.width;
const imgHeight = img.height;
// 计算相对于图片的坐标比例
const xRatio = offsetX / imgWidth;
const yRatio = offsetY / imgHeight;
// 构造右键点击事件数据对象
const clickData = {
type: "mouseRightClick",
x: xRatio,
y: yRatio,
offsetX: offsetX,
offsetY: offsetY,
imgWidth: imgWidth,
imgHeight: imgHeight
};
// 通过WebSocket发送坐标数据到后台
if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
this.websocket.send(clickData.type+","+clickData.x+","+clickData.y);
} else {
console.warn("WebSocket未连接,无法发送右键点击坐标");
}
}
}
$(document).ready(function () {
const index = new Index2();
index.initUI();
index.initEvent();
});
再通过后台java代码处理websocket接收到的鼠标坐标与操作类型,然后使用robot类,先获取到屏幕宽与高再乘以点击的坐标,这样就还原点击的位置了,详细代码如下。
[Java] 纯文本查看 复制代码 package com.vsked.web;
import com.vsked.remote.GlobalObj;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnError;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.awt.event.InputEvent;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@Component
@ServerEndpoint("/imageWebsocket")
public class ImageWebSocket {
private static final Logger log = LoggerFactory.getLogger(ImageWebSocket.class);
private static List<Session> sessions = new CopyOnWriteArrayList<>();
private static volatile boolean sending = false;
private static Thread sendingThread = null;
@OnOpen
public void onOpen(Session session) {
log.info("New connection: {}", session.getId());
sessions.add(session);
}
@OnClose
public void onClose(Session session) {
log.info("Connection closed: {}", session.getId());
Iterator<Session> it = sessions.iterator();
Session s;
while (it.hasNext()) {
s = it.next();
if (s.getId().equals(session.getId())) {
it.remove();
}
}
// 如果没有会话了,停止发送数据
if (sessions.isEmpty()) {
sending = false;
if (sendingThread != null) {
sendingThread.interrupt();
}
}
}
@OnError
public void onError(Session session, Throwable throwable) {
log.error("Error: {}", throwable.getMessage());
}
@OnMessage
public void onMessage(Session session, String message) {
log.info("Received message: {}", message);
double baseWith=GlobalObj.getRe().getWidth();
double baseHeight=GlobalObj.getRe().getHeight();
boolean isMouseEvent = false;
if(message.contains("mouseClick")){
try {
String[] arr=message.split(",");
int myX= (int) (baseWith*Double.parseDouble(arr[1]));
int myY= (int) (baseHeight*Double.parseDouble(arr[2]));
GlobalObj.getRobot().mouseMove( myX,myY);
GlobalObj.getRobot().mousePress(InputEvent.BUTTON1_DOWN_MASK);
GlobalObj.getRobot().mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
isMouseEvent = true;
} catch (Exception e) {
log.error("Error processing mouseClick: {}", e.getMessage());
}
}
if(message.contains("mouseRightClick")){
try {
String[] arr=message.split(",");
int myX= (int) (baseWith*Double.parseDouble(arr[1]));
int myY= (int) (baseHeight*Double.parseDouble(arr[2]));
GlobalObj.getRobot().mouseMove(myX,myY);
GlobalObj.getRobot().mousePress(InputEvent.BUTTON3_DOWN_MASK);
GlobalObj.getRobot().mouseRelease(InputEvent.BUTTON3_DOWN_MASK);
isMouseEvent = true;
} catch (Exception e) {
log.error("Error processing mouseRightClick: {}", e.getMessage());
}
}
if(message.contains("mouseDoubleClick")){
try {
String[] arr=message.split(",");
int myX= (int) (baseWith*Double.parseDouble(arr[1]));
int myY= (int) (baseHeight*Double.parseDouble(arr[2]));
GlobalObj.getRobot().mouseMove(myX,myY);
GlobalObj.getRobot().mousePress(InputEvent.BUTTON1_DOWN_MASK);
GlobalObj.getRobot().mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
GlobalObj.getRobot().delay(50); // 短暂延迟,模拟真实双击
GlobalObj.getRobot().mousePress(InputEvent.BUTTON1_DOWN_MASK);
GlobalObj.getRobot().mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
isMouseEvent = true;
} catch (Exception e) {
log.error("Error processing mouseDoubleClick: {}", e.getMessage());
}
}
// 如果是鼠标事件,处理完后继续执行发送任务逻辑
if (isMouseEvent) {
log.info("Mouse event processed, continuing with image sending,{}",sending);
sending=false;
}
// 如果已经在发送数据,则停止之前的发送任务
if (sending) {
sending = false;
if (sendingThread != null) {
try {
sendingThread.join(); // 等待线程结束
} catch (InterruptedException e) {
log.error("Thread join interrupted: {}", e.getMessage());
}
}
}
// 启动新的发送任务
sending = true;
sendingThread = new Thread(() -> {
while (sending) {
try {
for (Session s : sessions) {
try {
if(s.isOpen()){
s.getBasicRemote().sendText(GlobalObj.getImg());
}else {
//如果会话已关闭,则从sessions中移除
sessions.remove(s);
}
} catch (Exception e) {
log.error("Error sending message: {}", e.getMessage());
}
}
// Thread.sleep(1500); // 每隔1.5秒发送一次
} catch (Exception e) {
log.info("Sending thread interrupted");
break;
}
}
});
sendingThread.start();
}
}
测试的时候请先修改下index2.js里局域网IP地址,并用另外一台电脑测试这样更好一点,毕竟远程监控嘛,控制当然是另一台电脑啦。
你也可以到github上去下载最新版本
https://github.com/brucevsked/vskedremote
详细代码在附件中
vskedremote.zip
(61.51 KB, 下载次数: 10)
|
免费评分
-
查看全部评分
|