update scale and resource
@@ -16,11 +16,11 @@ namespace MeoAssistance {
|
||||
|
||||
bool findHandle();
|
||||
bool resizeWindow(int Width, int Height);
|
||||
bool click(Point p);
|
||||
bool clickRange(Rect rect);
|
||||
cv::Mat getImage(Rect rect);
|
||||
bool click(const Point & p);
|
||||
bool clickRange(const Rect & rect);
|
||||
cv::Mat getImage(const Rect& rect);
|
||||
Rect getWindowRect();
|
||||
double getScreenScale();
|
||||
static double getScreenScale();
|
||||
private:
|
||||
|
||||
HandleType m_handle_type;
|
||||
|
||||
@@ -16,196 +16,177 @@
|
||||
using namespace MeoAssistance;
|
||||
|
||||
WinMacro::WinMacro(HandleType type)
|
||||
: m_handle_type(type),
|
||||
m_rand_engine(time(NULL))
|
||||
: m_handle_type(type),
|
||||
m_rand_engine(time(NULL))
|
||||
{
|
||||
}
|
||||
|
||||
bool WinMacro::findHandle()
|
||||
{
|
||||
json::array handle_arr;
|
||||
switch (m_handle_type) {
|
||||
case HandleType::BlueStacksControl:
|
||||
handle_arr = Configer::handleObj["BlueStacksControl"].as_array();
|
||||
break;
|
||||
case HandleType::BlueStacksView:
|
||||
handle_arr = Configer::handleObj["BlueStacksView"].as_array();
|
||||
break;
|
||||
case HandleType::BlueStacksWindow:
|
||||
handle_arr = Configer::handleObj["BlueStacksWindow"].as_array();
|
||||
break;
|
||||
default:
|
||||
std::cerr << "handle type error! " << static_cast<int>(m_handle_type) << std::endl;
|
||||
return false;
|
||||
}
|
||||
json::array handle_arr;
|
||||
switch (m_handle_type) {
|
||||
case HandleType::BlueStacksControl:
|
||||
handle_arr = Configer::handleObj["BlueStacksControl"].as_array();
|
||||
break;
|
||||
case HandleType::BlueStacksView:
|
||||
handle_arr = Configer::handleObj["BlueStacksView"].as_array();
|
||||
break;
|
||||
case HandleType::BlueStacksWindow:
|
||||
handle_arr = Configer::handleObj["BlueStacksWindow"].as_array();
|
||||
break;
|
||||
default:
|
||||
std::cerr << "handle type error! " << static_cast<int>(m_handle_type) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_handle = NULL;
|
||||
for (auto&& obj : handle_arr)
|
||||
{
|
||||
m_handle = ::FindWindowExA(m_handle, NULL, obj["class"].as_string().c_str(), obj["window"].as_string().c_str());
|
||||
}
|
||||
m_handle = NULL;
|
||||
for (auto&& obj : handle_arr)
|
||||
{
|
||||
m_handle = ::FindWindowExA(m_handle, NULL, obj["class"].as_string().c_str(), obj["window"].as_string().c_str());
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
std::cout << "type: " << static_cast<int>(m_handle_type) << ", handle: " << m_handle << std::endl;
|
||||
std::cout << "type: " << static_cast<int>(m_handle_type) << ", handle: " << m_handle << std::endl;
|
||||
#endif
|
||||
|
||||
if (m_handle != NULL) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
if (m_handle != NULL) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool WinMacro::resizeWindow(int width, int height)
|
||||
{
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::Window))) {
|
||||
return false;
|
||||
}
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::Window))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ::MoveWindow(m_handle, 0, 0, width, height, true);
|
||||
return ::MoveWindow(m_handle, 0, 0, width / getScreenScale(), height / getScreenScale(), true);
|
||||
}
|
||||
|
||||
double WinMacro::getScreenScale()
|
||||
{
|
||||
// 获取窗口当前显示的监视器
|
||||
// 使用桌面的句柄.
|
||||
HWND hWnd = GetDesktopWindow();
|
||||
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
|
||||
static double scale = 0;
|
||||
if (scale == 0) {
|
||||
// 获取窗口当前显示的监视器
|
||||
// 使用桌面的句柄.
|
||||
HWND hWnd = GetDesktopWindow();
|
||||
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
// 获取监视器逻辑宽度与高度
|
||||
MONITORINFOEX miex;
|
||||
miex.cbSize = sizeof(miex);
|
||||
GetMonitorInfo(hMonitor, &miex);
|
||||
int cxLogical = (miex.rcMonitor.right - miex.rcMonitor.left);
|
||||
int cyLogical = (miex.rcMonitor.bottom - miex.rcMonitor.top);
|
||||
// 获取监视器逻辑宽度与高度
|
||||
MONITORINFOEX miex;
|
||||
miex.cbSize = sizeof(miex);
|
||||
GetMonitorInfo(hMonitor, &miex);
|
||||
int cxLogical = (miex.rcMonitor.right - miex.rcMonitor.left);
|
||||
int cyLogical = (miex.rcMonitor.bottom - miex.rcMonitor.top);
|
||||
|
||||
// 获取监视器物理宽度与高度
|
||||
DEVMODE dm;
|
||||
dm.dmSize = sizeof(dm);
|
||||
dm.dmDriverExtra = 0;
|
||||
EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm);
|
||||
int cxPhysical = dm.dmPelsWidth;
|
||||
int cyPhysical = dm.dmPelsHeight;
|
||||
// 获取监视器物理宽度与高度
|
||||
DEVMODE dm;
|
||||
dm.dmSize = sizeof(dm);
|
||||
dm.dmDriverExtra = 0;
|
||||
EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm);
|
||||
int cxPhysical = dm.dmPelsWidth;
|
||||
int cyPhysical = dm.dmPelsHeight;
|
||||
|
||||
// 考虑状态栏大小,逻辑尺寸会比实际小
|
||||
double horzScale = ((double)cxPhysical / (double)cxLogical);
|
||||
double vertScale = ((double)cyPhysical / (double)cyLogical);
|
||||
// 考虑状态栏大小,逻辑尺寸会比实际小
|
||||
double horzScale = ((double)cxPhysical / (double)cxLogical);
|
||||
double vertScale = ((double)cyPhysical / (double)cyLogical);
|
||||
|
||||
// 考虑状态栏大小,选择里面大的那个
|
||||
return std::max(horzScale, vertScale);
|
||||
// 考虑状态栏大小,选择里面大的那个
|
||||
scale = std::max(horzScale, vertScale);
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
bool WinMacro::click(Point p)
|
||||
bool WinMacro::click(const Point& p)
|
||||
{
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::Control))) {
|
||||
return false;
|
||||
}
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::Control))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int x = p.x / getScreenScale();
|
||||
int y = p.y / getScreenScale();
|
||||
#ifdef _DEBUG
|
||||
std::cout << "click: " << p.x << ", " << p.y << std::endl;
|
||||
std::cout << "click: " << x << ", " << y << std::endl;
|
||||
#endif
|
||||
|
||||
LPARAM lparam = MAKELPARAM(p.x, p.y);
|
||||
LPARAM lparam = MAKELPARAM(x, y);
|
||||
|
||||
::SendMessage(m_handle, WM_LBUTTONDOWN, MK_LBUTTON, lparam);
|
||||
::SendMessage(m_handle, WM_LBUTTONUP, 0, lparam);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinMacro::clickRange(Rect rect)
|
||||
bool WinMacro::clickRange(const Rect& rect)
|
||||
{
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::Control))) {
|
||||
return false;
|
||||
}
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::Control))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int x = 0, y = 0;
|
||||
if (rect.width == 0) {
|
||||
x = rect.x;
|
||||
}
|
||||
else {
|
||||
std::poisson_distribution<int> x_rand(rect.width);
|
||||
x = x_rand(m_rand_engine) + rect.x;
|
||||
}
|
||||
int x = 0, y = 0;
|
||||
if (rect.width == 0) {
|
||||
x = rect.x;
|
||||
}
|
||||
else {
|
||||
std::poisson_distribution<int> x_rand(rect.width);
|
||||
x = x_rand(m_rand_engine) + rect.x;
|
||||
}
|
||||
|
||||
if (rect.height == 0) {
|
||||
y = rect.y;
|
||||
}
|
||||
else {
|
||||
std::poisson_distribution<int> y_rand(rect.height);
|
||||
y = y_rand(m_rand_engine) + rect.y;
|
||||
}
|
||||
if (rect.height == 0) {
|
||||
y = rect.y;
|
||||
}
|
||||
else {
|
||||
std::poisson_distribution<int> y_rand(rect.height);
|
||||
y = y_rand(m_rand_engine) + rect.y;
|
||||
}
|
||||
|
||||
return click({ x, y });
|
||||
return click({ x, y });
|
||||
}
|
||||
|
||||
Rect WinMacro::getWindowRect()
|
||||
{
|
||||
RECT rect;
|
||||
bool ret = ::GetWindowRect(m_handle, &rect);
|
||||
if (!ret) {
|
||||
return { 0, 0, 0 ,0 };
|
||||
}
|
||||
double scale = getScreenScale();
|
||||
return Rect{ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top } * scale;
|
||||
RECT rect;
|
||||
bool ret = ::GetWindowRect(m_handle, &rect);
|
||||
if (!ret) {
|
||||
return { 0, 0, 0 ,0 };
|
||||
}
|
||||
return Rect{ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top } *getScreenScale();
|
||||
}
|
||||
|
||||
cv::Mat WinMacro::getImage(Rect rect)
|
||||
cv::Mat WinMacro::getImage(const Rect& rect)
|
||||
{
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::View))) {
|
||||
return cv::Mat();
|
||||
}
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::View))) {
|
||||
return cv::Mat();
|
||||
}
|
||||
|
||||
HDC pDC;// 源DC
|
||||
//判断是不是窗口句柄如果是的话不能使用GetDC来获取DC 不然截图会是黑屏
|
||||
if (m_handle == ::GetDesktopWindow())
|
||||
{
|
||||
pDC = CreateDCA("DISPLAY", NULL, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
pDC = ::GetDC(m_handle);//获取屏幕DC(0为全屏,句柄则为窗口)
|
||||
}
|
||||
int BitPerPixel = ::GetDeviceCaps(pDC, BITSPIXEL);//获得颜色模式
|
||||
if (rect.width == 0 && rect.height == 0)//默认宽度和高度为全屏
|
||||
{
|
||||
rect.width = ::GetDeviceCaps(pDC, HORZRES); //设置图像宽度全屏
|
||||
rect.height = ::GetDeviceCaps(pDC, VERTRES); //设置图像高度全屏
|
||||
}
|
||||
HDC memDC;//内存DC
|
||||
memDC = ::CreateCompatibleDC(pDC);
|
||||
HBITMAP memBitmap, oldmemBitmap;//建立和屏幕兼容的bitmap
|
||||
memBitmap = ::CreateCompatibleBitmap(pDC, rect.width, rect.height);
|
||||
oldmemBitmap = (HBITMAP)::SelectObject(memDC, memBitmap);//将memBitmap选入内存DC
|
||||
if (m_handle == ::GetDesktopWindow())
|
||||
{
|
||||
BitBlt(memDC, 0, 0, rect.width, rect.height, pDC, rect.x, rect.y, SRCCOPY);//图像宽度高度和截取位置
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bret = ::PrintWindow(m_handle, memDC, PW_CLIENTONLY);
|
||||
if (!bret)
|
||||
{
|
||||
BitBlt(memDC, 0, 0, rect.width, rect.height, pDC, rect.x, rect.y, SRCCOPY);//图像宽度高度和截取位置
|
||||
}
|
||||
}
|
||||
HDC pDC;// 源DC
|
||||
pDC = ::GetDC(m_handle);//获取屏幕DC(0为全屏,句柄则为窗口)
|
||||
int BitPerPixel = ::GetDeviceCaps(pDC, BITSPIXEL);//获得颜色模式
|
||||
HDC memDC;//内存DC
|
||||
memDC = ::CreateCompatibleDC(pDC);
|
||||
HBITMAP memBitmap, oldmemBitmap;//建立和屏幕兼容的bitmap
|
||||
memBitmap = ::CreateCompatibleBitmap(pDC, rect.width, rect.height);
|
||||
oldmemBitmap = (HBITMAP)::SelectObject(memDC, memBitmap);//将memBitmap选入内存DC
|
||||
::PrintWindow(m_handle, memDC, PW_CLIENTONLY);
|
||||
|
||||
BITMAP bmp;
|
||||
GetObject(memBitmap, sizeof(BITMAP), &bmp);
|
||||
int nChannels = bmp.bmBitsPixel == 1 ? 1 : bmp.bmBitsPixel / 8;
|
||||
cv::Mat dst_mat;
|
||||
dst_mat.create(cv::Size(bmp.bmWidth, bmp.bmHeight), CV_MAKETYPE(CV_8U, nChannels));
|
||||
GetBitmapBits(memBitmap, bmp.bmHeight * bmp.bmWidth * nChannels, dst_mat.data);
|
||||
BITMAP bmp;
|
||||
GetObject(memBitmap, sizeof(BITMAP), &bmp);
|
||||
int nChannels = bmp.bmBitsPixel == 1 ? 1 : bmp.bmBitsPixel / 8;
|
||||
cv::Mat dst_mat;
|
||||
dst_mat.create(cv::Size(bmp.bmWidth, bmp.bmHeight), CV_MAKETYPE(CV_8U, nChannels));
|
||||
GetBitmapBits(memBitmap, bmp.bmHeight * bmp.bmWidth * nChannels, dst_mat.data);
|
||||
|
||||
DeleteObject(memBitmap);
|
||||
DeleteDC(memDC);
|
||||
ReleaseDC(m_handle, pDC);
|
||||
DeleteObject(memBitmap);
|
||||
DeleteDC(memDC);
|
||||
ReleaseDC(m_handle, pDC);
|
||||
|
||||
#ifdef _DEBUG
|
||||
std::string filename = Configer::getCurDir() + "\\test.bmp";
|
||||
cv::imwrite(filename, dst_mat);
|
||||
std::string filename = Configer::getCurDir() + "\\test.bmp";
|
||||
cv::imwrite(filename, dst_mat);
|
||||
#endif
|
||||
|
||||
return dst_mat;
|
||||
return dst_mat;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 842 KiB |
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 811 KiB |
|
Before Width: | Height: | Size: 938 KiB After Width: | Height: | Size: 952 KiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 988 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 667 KiB |
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 717 KiB |
@@ -29,40 +29,12 @@
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"PRTS": {
|
||||
"viewRect": [
|
||||
1503,
|
||||
65,
|
||||
280,
|
||||
114
|
||||
],
|
||||
"filename": "PRTS.png",
|
||||
"similarity": 0.9,
|
||||
"type": "donothing"
|
||||
},
|
||||
"MissionSucceed": {
|
||||
"viewRect": [
|
||||
255,
|
||||
778,
|
||||
71,
|
||||
38
|
||||
],
|
||||
"filename": "MissionSucceed.png",
|
||||
"similarity": 0.9,
|
||||
"type": "click",
|
||||
"ctrlRect": [
|
||||
50,
|
||||
596,
|
||||
163,
|
||||
29
|
||||
]
|
||||
},
|
||||
"UseMedicine": {
|
||||
"viewRect": [
|
||||
874,
|
||||
157,
|
||||
960,
|
||||
774
|
||||
571,
|
||||
118,
|
||||
621,
|
||||
504
|
||||
],
|
||||
"filename": "UseMedicine.png",
|
||||
"similarity": 0.999,
|
||||
@@ -70,21 +42,38 @@
|
||||
},
|
||||
"UseStone": {
|
||||
"viewRect": [
|
||||
874,
|
||||
157,
|
||||
960,
|
||||
774
|
||||
571,
|
||||
118,
|
||||
621,
|
||||
504
|
||||
],
|
||||
"filename": "UseStone.png",
|
||||
"similarity": 0.999,
|
||||
"type": "stop"
|
||||
},
|
||||
"MissionSucceed": {
|
||||
"viewRect": [
|
||||
186,
|
||||
521,
|
||||
47,
|
||||
26
|
||||
],
|
||||
"filename": "MissionSucceed.png",
|
||||
"similarity": 0.4,
|
||||
"type": "click",
|
||||
"ctrlRect": [
|
||||
977,
|
||||
596,
|
||||
163,
|
||||
29
|
||||
]
|
||||
},
|
||||
"StartButton1": {
|
||||
"viewRect": [
|
||||
1487,
|
||||
940,
|
||||
295,
|
||||
107
|
||||
968,
|
||||
627,
|
||||
193,
|
||||
70
|
||||
],
|
||||
"filename": "StartButton1.png",
|
||||
"similarity": 0.99,
|
||||
@@ -98,10 +87,10 @@
|
||||
},
|
||||
"StartButton2": {
|
||||
"viewRect": [
|
||||
1484,
|
||||
569,
|
||||
190,
|
||||
398
|
||||
966,
|
||||
386,
|
||||
126,
|
||||
259
|
||||
],
|
||||
"filename": "StartButton2.png",
|
||||
"similarity": 0.99,
|
||||
|
||||