You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

590 lines
18 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.example.jmacro.wjdr;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReUtil;
import com.example.jmacro.wjdr.base.ScreenPoint;
import com.example.jmacro.wjdr.base.ScreenRect;
import com.example.jmacro.wjdr.util.ColorUtil;
import com.example.jmacro.wjdr.util.Imager;
import com.example.jmacro.wjdr.util.Logger;
import com.example.jmacro.wjdr.util.TaskUtil;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.concurrent.TimeUnit;
/**
* Java脚本精灵
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class JMacro {
/**
* 机器人操作实例
*/
private final Robot robot;
/**
* 图例目录
*/
private File legend;
public JMacro() throws AWTException {
// 机器人初始化
this.robot = new Robot();
this.robot.setAutoDelay(100);
}
public JMacro(File legend) throws AWTException {
this();
this.legend = legend;
}
/**
* 键盘按键组
*/
public void keyInput(int... keycodes) {
for (int keycode : keycodes) {
keyPress(keycode);
}
}
/**
* 键盘按键
* keycode Key to press (e.g. <code>KeyEvent.VK_A)
*/
public void keyPress(int keycode) {
this.robot.keyPress(keycode);
}
/**
* 鼠标移动
*
* @param point 坐标点
*/
public void mouseMove(ScreenPoint point) {
mouseMove(point, false);
}
/**
* 鼠标移动
*
* @param point 坐标点
* @param smooth 平滑移动
*/
public void mouseMove(ScreenPoint point, boolean smooth) {
if (smooth) {
// 获取当前鼠标位置
Point mousePoint = MouseInfo.getPointerInfo().getLocation();
int startX = mousePoint.x;
int startY = mousePoint.y;
// 求两点距离
double absX = Math.abs(startX - point.getX());
double absY = Math.abs(startY - point.getY());
double absZ = Math.sqrt(Math.pow(absX, 2) + Math.pow(absY, 2));
int times = (int) (absZ / 30 + (absZ % 30 > 0 ? 1 : 0));
int interval = Math.min(500 / times, 10);
times = Math.min(times, 10);
// 分times次移动到指定点
for (int i = 1; i <= times; i++) {
float d = i * 1.0f / times;
int dx = (int) (startX + (point.getX() - startX) * d);
int dy = (int) (startY + (point.getY() - startY) * d);
robot.mouseMove(dx, dy);
robot.delay(RandomUtil.randomInt(interval - 10, interval + 10));
}
} else {
robot.mouseMove(point.getX(), point.getY());
}
}
/**
* 鼠标左键单击
*
* @param rect 点
*/
public void mouseLeftClick(ScreenPoint rect) {
mouseMove(rect);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
delayTap();
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
}
/**
* 鼠标左键单击
*
* @param rect 矩形区域
*/
public void mouseLeftClick(ScreenRect rect) {
mouseLeftClick(new ScreenPoint(rect.getCenter()[0], rect.getCenter()[1]));
}
/**
* 鼠标左键拖拽
*
* @param start 开始位置
* @param end 结束位置
*/
public void mouseLeftDrag(ScreenPoint start, ScreenPoint end) {
mouseLeftDrag(start, end, false);
}
/**
* 鼠标左键拖拽
*
* @param start 开始位置
* @param end 结束位置
* @param smooth 平滑移动
*/
public void mouseLeftDrag(ScreenPoint start, ScreenPoint end, boolean smooth) {
mouseMove(start, smooth);
delayTap();
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
delayTap();
mouseMove(end, smooth);
delayTap();
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
}
/**
* 鼠标右键拖拽
*
* @param start 开始位置
* @param end 结束位置
*/
public void mouseRightDrag(ScreenPoint start, ScreenPoint end) {
mouseRightDrag(start, end, false);
}
/**
* 鼠标右键拖拽
*
* @param start 开始位置
* @param end 结束位置
* @param smooth 平滑移动
*/
public void mouseRightDrag(ScreenPoint start, ScreenPoint end, boolean smooth) {
mouseMove(start, smooth);
delayTap();
robot.mousePress(InputEvent.BUTTON3_DOWN_MASK);
delayTap();
mouseMove(end, smooth);
delayTap();
robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK);
}
/**
* 鼠标滚轮单击
*
* @param rect 矩形区域
*/
public void mouseWheelClick(ScreenRect rect) {
delayTap();
robot.mouseMove(rect.getCenter()[0], rect.getCenter()[1]);
delayTap();
robot.mousePress(InputEvent.BUTTON2_DOWN_MASK);
delayTap();
robot.mouseRelease(InputEvent.BUTTON2_DOWN_MASK);
}
/**
* 鼠标右键单击
*
* @param rect 矩形区域
*/
public void mouseRightClick(ScreenRect rect) {
delayTap();
robot.mouseMove(rect.getCenter()[0], rect.getCenter()[1]);
delayTap();
robot.mousePress(InputEvent.BUTTON3_DOWN_MASK);
delayTap();
robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK);
}
/**
* 鼠标左键双击
*
* @param rect 矩形区域
*/
public void mouseLeftDoubleClick(ScreenRect rect) {
delayTap();
robot.mouseMove(rect.getCenter()[0], rect.getCenter()[1]);
delayTap();
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.delay(100);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.delay(100);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.delay(100);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
}
/**
* 捕获指定区域屏幕
*/
public BufferedImage capture(Robot robot, ScreenRect screenRect) {
return robot.createScreenCapture(new Rectangle(screenRect.getLeft(), screenRect.getTop(), screenRect.getWidth(), screenRect.getHeight()));
}
/**
* 获取屏幕范围
*/
public ScreenRect getScreenRect() {
Toolkit tk = Toolkit.getDefaultToolkit();
return new ScreenRect(0, 0, tk.getScreenSize().width, tk.getScreenSize().height);
}
/**
* 全屏查找图片
*
* @param legendName 图例名称
* @param minSimilar 最低相似度
* @return 匹配图片区域
*/
public ScreenRect findPic(String legendName, double minSimilar) {
if (!legendName.endsWith(".png")) {
legendName = legendName + ".png";
}
return findPic(new File(legend, legendName), minSimilar);
}
/**
* 全屏查找图片
*
* @param pic 图片
* @param minSimilar 最低相似度
* @return 匹配图片区域
*/
public ScreenRect findPic(File pic, double minSimilar) {
return findPic(getScreenRect(), Imager.load(pic), minSimilar);
}
/**
* 全屏查找图片
*
* @param pic 图片
* @param minSimilar 最低相似度
* @return 匹配图片区域
*/
public ScreenRect findPic(BufferedImage pic, double minSimilar) {
return findPic(getScreenRect(), pic, minSimilar);
}
/**
* 应用视口查找图例
*
* @param screenRect 应用视口
* @param legendName 图例名称
* @param minSimilar 最低相似度
* @return 匹配图片区域
*/
public ScreenRect findPic(ScreenRect screenRect, String legendName, double minSimilar) {
if (!legendName.endsWith(".png")) {
legendName = legendName + ".png";
}
return findPic(screenRect, new File(legend, legendName), minSimilar);
}
/**
* 应用视口查找图例
*
* @param screenRect 应用视口
* @param legend 图例文件
* @param minSimilar 最低相似度
* @return 匹配图片区域
*/
public ScreenRect findPic(ScreenRect screenRect, File legend, double minSimilar) {
return findPic(screenRect, Imager.load(legend), minSimilar);
}
/**
* 获取定位
*
* @param pic 参考图
* @param screenRect 查找范围
* @param minSimilar 相似度
* @return 匹配图片区域
*/
public ScreenRect findPic(ScreenRect screenRect, BufferedImage pic, double minSimilar) {
// 当查找区域比图片还小时,直接返回失败
if (screenRect.getWidth() < pic.getWidth() || screenRect.getHeight() < pic.getHeight()) {
Logger.error("视口尺寸小于图片");
return null;
}
// 获取实时屏幕
BufferedImage screen = capture(robot, screenRect);
int[][] screenData = Imager.getImageRGB(screen);
int[][] picData = Imager.getImageRGB(pic);
// 得到图片左上角范围
int xMin = screenRect.getLeft();
// 因为坐标取像素点是从0开始因此需要-1
int xMax = screenRect.getRight() - pic.getWidth();
int yMin = screenRect.getTop();
// 因为坐标取像素点是从0开始因此需要-1
int yMax = screenRect.getBottom() - pic.getHeight();
for (int y = yMin; y <= yMax; y++) {
for (int x = xMin; x <= xMax; x++) {
// 对关键点进行先期匹配,降低运算复杂度。如果关键点本身就不匹配,就没必要再去匹配小图的每一个像素点
// 左上角
boolean lt = ColorUtil.isSimilar(screenData[x - xMin][y - yMin], picData[0][0]);
// 右上角
boolean rt = ColorUtil.isSimilar(screenData[x - xMin + pic.getWidth() - 1][y - yMin], picData[pic.getWidth() - 1][0]);
// 左下角
boolean lb = ColorUtil.isSimilar(screenData[x - xMin][y - yMin + pic.getHeight() - 1], picData[0][pic.getHeight() - 1]);
// 右下角
boolean rb = ColorUtil.isSimilar(screenData[x - xMin + pic.getWidth() - 1][y - yMin + pic.getHeight() - 1], picData[pic.getWidth() - 1][pic.getHeight() - 1]);
//中心点
boolean cc = ColorUtil.isSimilar(screenData[x - xMin + pic.getWidth() / 2][y - yMin + pic.getHeight() / 2], picData[pic.getWidth() / 2][pic.getHeight() / 2]);
if (lt && rt && lb && rb && cc) {
// 进行全像素匹配
double similar = Imager.calcSimilar(x - xMin, y - yMin, pic.getHeight(), pic.getWidth(), screenData, picData);
if (similar >= minSimilar) {
return new ScreenRect(x, y, x + pic.getWidth(), y + pic.getHeight(), similar);
}
}
}
}
// try {
// ImgUtil.write(screen,"png", new FileOutputStream("D://1.png"));
// } catch (FileNotFoundException e) {
//
// }
return null;
}
public void delay() {
delayNormal();
}
public void delayTap() {
int i = RandomUtil.randomInt(100, 500);
robot.delay(i);
}
public void delayNormal() {
int i = RandomUtil.randomInt(500, 1500);
robot.delay(i);
}
public void delayLong() {
int i = RandomUtil.randomInt(1500, 3000);
robot.delay(i);
}
/**
* 等待并查找图片
*
* @param file 图例
* @param minSimilar 最低相似度
* @return 匹配图片区域
*/
public ScreenRect waitAndFindPic(File file, double minSimilar) {
return waitAndFindPic(getScreenRect(), file, minSimilar, 10, TimeUnit.SECONDS);
}
/**
* 等待并查找图片
*
* @param rect 查找区域
* @param file 图例
* @param minSimilar 最低相似度
* @return 匹配图片区域
*/
public ScreenRect waitAndFindPic(ScreenRect rect, File file, double minSimilar) {
return waitAndFindPic(rect, file, minSimilar, 10, TimeUnit.SECONDS);
}
/**
* 等待并查找图片
*
* @param rect 查找区域
* @param legendName 图例名称
* @param minSimilar 最低相似度
* @return 匹配图片区域
*/
public ScreenRect waitAndFindPic(ScreenRect rect, String legendName, double minSimilar) {
if (!legendName.endsWith(".png")) {
legendName = legendName + ".png";
}
return waitAndFindPic(rect, new File(legend, legendName), minSimilar, 10, TimeUnit.SECONDS);
}
/**
* 等待并查找图片
*
* @param file 图例
* @param minSimilar 最低相似度
* @param time 最长等待时间
* @param unit 最长等待时间单位
* @return 匹配图片区域
*/
public ScreenRect waitAndFindPic(File file, double minSimilar, long time, TimeUnit unit) {
return waitAndFindPic(getScreenRect(), file, minSimilar, time, unit);
}
/**
* 等待并查找图片
*
* @param rect 查找区域
* @param file 图例
* @param minSimilar 最低相似度
* @param time 最长等待时间
* @param unit 最长等待时间单位
* @return 匹配图片区域
*/
public ScreenRect waitAndFindPic(ScreenRect rect, File file, double minSimilar, long time, TimeUnit unit) {
return TaskUtil.timeTask(() -> {
BufferedImage image = Imager.load(file);
if (rect.getWidth() < image.getWidth()) {
Logger.error("查找图片区域宽度{}小于图片宽度{}", rect.getWidth(), image.getWidth());
return null;
}
if (rect.getHeight() < image.getHeight()) {
Logger.error("查找图片区域宽度{}小于图片宽度{}", rect.getHeight(), image.getHeight());
return null;
}
while (true) {
delayTap();
ScreenRect pic = findPic(rect, image, minSimilar);
if (pic != null) {
return pic;
}
}
}, time, unit);
}
/**
* 等待并匹配图例
*
* @param rect 参照区域
* @param legendName 图例名称
* @param minSimilar 最低相似度
* @return 匹配图片区域
*/
public ScreenRect waitAndMatchPic(ScreenRect rect, String legendName, double minSimilar) {
if (!legendName.endsWith(".png")) {
legendName = legendName + ".png";
}
return waitAndMatchPic(rect, new File(legend, legendName), minSimilar, 10, TimeUnit.SECONDS);
}
/**
* 等待并匹配图例
*
* @param rect 参照区域
* @param file 图例
* @param minSimilar 最低相似度
* @return 匹配图片区域
*/
public ScreenRect waitAndMatchPic(ScreenRect rect, File file, double minSimilar) {
return waitAndMatchPic(rect, file, minSimilar, 10, TimeUnit.SECONDS);
}
/**
* 等待并匹配图例
*
* @param rect 参照区域
* @param file 图例
* @param minSimilar 最低相似度
* @param time 最长等待时间
* @param unit 最长等待时间单位
* @return 匹配图片区域
*/
public ScreenRect waitAndMatchPic(ScreenRect rect, File file, double minSimilar, long time, TimeUnit unit) {
return TaskUtil.timeTask(() -> {
while (true) {
delayTap();
ScreenRect matchPic = matchPic(rect, file, minSimilar);
if (matchPic != null) {
return matchPic;
}
}
}, time, unit);
}
/**
* 匹配图片
*
* @param rect 程序窗口(参照系)
* @param file 图例
* @param minSimilar 最低相似度
* @return 匹配图片
*/
public ScreenRect matchPic(ScreenRect rect, File file, double minSimilar) {
if (!file.exists()) {
Logger.error("file [{}] not exist", file.getAbsolutePath());
return null;
}
String name = file.getName();
int offsetX = 0;
int offsetY = 0;
if (name.matches("L[0-9]+,[0-9]+-[\\S\\s]+")) {
offsetX = Convert.toInt(ReUtil.get("L([0-9]+),[0-9]+-[\\S\\s]+", name, 1), 0);
offsetY = Convert.toInt(ReUtil.get("L[0-9]+,([0-9]+)-[\\S\\s]+", name, 1), 0);
}
ScreenRect screenRect = new ScreenRect();
screenRect.setLeft(rect.getLeft() + offsetX);
screenRect.setTop(rect.getTop() + offsetY);
BufferedImage image = Imager.load(file);
screenRect.setRight(screenRect.getLeft() + image.getWidth());
screenRect.setBottom(screenRect.getTop() + image.getHeight());
return findPic(screenRect, image, minSimilar);
}
/**
* 匹配图片
*
* @param rect 程序窗口(参照系)
* @param legendName 图例名称
* @param minSimilar 最低相似度
* @return 匹配图片
*/
public ScreenRect matchPic(ScreenRect rect, String legendName, double minSimilar) {
if (!legendName.endsWith(".png")) {
legendName = legendName + ".png";
}
return matchPic(rect, new File(legend, legendName), minSimilar);
}
/**
* 是否匹配图片
*
* @param rect 程序窗口(参照系)
* @param file 图例
* @param minSimilar 最低相似度
* @return 匹配图片
*/
public boolean isMatchPic(ScreenRect rect, File file, double minSimilar) {
return matchPic(rect, file, minSimilar) != null;
}
/**
* 是否匹配图片
*
* @param rect 程序窗口(参照系)
* @param legendName 图例名称
* @param minSimilar 最低相似度
* @return 匹配图片
*/
public boolean isMatchPic(ScreenRect rect, String legendName, double minSimilar) {
if (!legendName.endsWith(".png")) {
legendName = legendName + ".png";
}
return matchPic(rect, new File(legend, legendName), minSimilar) != null;
}
}

Powered by TurnKey Linux.