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.

444 lines
14 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 {
public static void main(String[] args) throws AWTException {
System.out.println("L0,0-A.png".matches("L[0-9]+,[0-9]+-[\\S\\s]+"));
}
/**
* 机器人操作实例
*/
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_MASK);
waitTap();
robot.mouseRelease(InputEvent.BUTTON1_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);
waitTap();
robot.mousePress(InputEvent.BUTTON1_MASK);
waitTap();
mouseMove(end, smooth);
waitTap();
robot.mouseRelease(InputEvent.BUTTON1_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);
waitTap();
robot.mousePress(InputEvent.BUTTON3_MASK);
waitTap();
mouseMove(end, smooth);
waitTap();
robot.mouseRelease(InputEvent.BUTTON3_MASK);
}
/**
* 鼠标滚轮单击
*
* @param rect 矩形区域
*/
public void mouseWheelClick(ScreenRect rect) {
waitTap();
robot.mouseMove(rect.getCenter()[0], rect.getCenter()[1]);
waitTap();
robot.mousePress(InputEvent.BUTTON2_MASK);
waitTap();
robot.mouseRelease(InputEvent.BUTTON2_MASK);
}
/**
* 鼠标右键单击
*
* @param rect 矩形区域
*/
public void mouseRightClick(ScreenRect rect) {
waitTap();
robot.mouseMove(rect.getCenter()[0], rect.getCenter()[1]);
waitTap();
robot.mousePress(InputEvent.BUTTON3_MASK);
waitTap();
robot.mouseRelease(InputEvent.BUTTON3_MASK);
}
/**
* 鼠标左键双击
*
* @param rect 矩形区域
*/
public void mouseLeftDoubleClick(ScreenRect rect) {
waitTap();
robot.mouseMove(rect.getCenter()[0], rect.getCenter()[1]);
waitTap();
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.delay(100);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
robot.delay(100);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.delay(100);
robot.mouseRelease(InputEvent.BUTTON1_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 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 pic 参考图
* @param screenRect 查找范围
* @param minSimilar 相似度
* @return 匹配图片区域
*/
public ScreenRect findPic(ScreenRect screenRect, BufferedImage pic, double minSimilar) {
// 当查找区域比图片还小时,直接返回失败
if (screenRect.getWidth() < pic.getWidth() || screenRect.getHeight() < pic.getHeight()) {
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);
}
}
}
}
return null;
}
public void waitTap() {
int i = RandomUtil.randomInt(100, 200);
robot.delay(i);
}
public void waitNormal() {
int i = RandomUtil.randomInt(500, 1500);
robot.delay(i);
}
public void waitLong() {
int i = RandomUtil.randomInt(2000, 5000);
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 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) {
waitTap();
ScreenRect pic = findPic(rect, image, minSimilar);
if (pic != null) {
return pic;
}
}
}, time, unit);
}
/**
* 匹配图片
*
* @param point 坐标原点(左上角)
* @param file 图例
* @param minSimilar 最低相似度
* @return 匹配图片
*/
public ScreenRect matchPic(ScreenPoint point, File file, double minSimilar) {
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(point.getX() + offsetX);
screenRect.setTop(point.getY() + offsetY);
BufferedImage image = Imager.load(file);
screenRect.setRight(screenRect.getLeft() + image.getWidth());
screenRect.setBottom(screenRect.getTop() + image.getHeight());
System.out.println(screenRect.toString());
return findPic(screenRect, image, minSimilar);
}
/**
* 是否匹配图片
*
* @param point 坐标原点(左上角)
* @param file 图例
* @param minSimilar 最低相似度
* @return 匹配图片
*/
public boolean isMatchPic(ScreenPoint point, File file, double minSimilar) {
return matchPic(point, file, minSimilar) != null;
}
}

Powered by TurnKey Linux.