mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-16 09:50:40 +08:00
Merge branch 'refactor'
This commit is contained in:
@@ -21,10 +21,11 @@
|
||||
#include "AsstDef.h"
|
||||
#include "Logger.hpp"
|
||||
#include "Resource.h"
|
||||
#include "UserConfiger.h"
|
||||
|
||||
asst::Controller::Controller()
|
||||
: m_rand_engine(static_cast<unsigned int>(time(nullptr)))
|
||||
asst::Controller::Controller(AsstCallback callback, void* callback_arg)
|
||||
: m_callback(callback),
|
||||
m_callback_arg(callback_arg),
|
||||
m_rand_engine(static_cast<unsigned int>(time(nullptr)))
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
@@ -87,7 +88,7 @@ asst::Controller::~Controller()
|
||||
#else
|
||||
if (true) {
|
||||
#endif
|
||||
call_command(m_emulator_info.adb.release);
|
||||
call_command(m_adb.release);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -103,155 +104,58 @@ asst::Controller::~Controller()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool asst::Controller::connect_adb(const std::string & address)
|
||||
{
|
||||
LogTraceScope("connect_adb " + address);
|
||||
|
||||
std::string connect_cmd = utils::string_replace_all(
|
||||
utils::string_replace_all(m_emulator_info.adb.connect, "[Adb]", m_emulator_info.adb.path),
|
||||
"[Address]", address);
|
||||
|
||||
std::string display_id;
|
||||
auto connect_ret = call_command(connect_cmd);
|
||||
// 端口即使错误,命令仍然会返回0,TODO 对connect_result进行判断
|
||||
if (!connect_ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 按需获取display ID 信息
|
||||
if (!m_emulator_info.adb.display_id.empty()) {
|
||||
std::string display_id_cmd = utils::string_replace_all(
|
||||
utils::string_replace_all(m_emulator_info.adb.display_id, "[Adb]", m_emulator_info.adb.path),
|
||||
"[Address]", address);
|
||||
auto display_id_ret = call_command(display_id_cmd);
|
||||
if (!display_id_ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& display_id_result = display_id_ret.value();
|
||||
convert_lf(display_id_result);
|
||||
std::string display_id_pipe_str(
|
||||
std::make_move_iterator(display_id_result.begin()),
|
||||
std::make_move_iterator(display_id_result.end()));
|
||||
auto last = display_id_pipe_str.rfind(':');
|
||||
if (last == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
display_id = display_id_pipe_str.substr(last + 1);
|
||||
// 去掉换行
|
||||
display_id.pop_back();
|
||||
}
|
||||
std::vector<std::pair<std::string, std::string>> replaces = {
|
||||
{"[Adb]", m_emulator_info.adb.path},
|
||||
{"[Address]", address},
|
||||
{"[DisplayId]", display_id}
|
||||
};
|
||||
|
||||
std::string display_cmd = utils::string_replace_all_batch(
|
||||
m_emulator_info.adb.display, replaces);
|
||||
|
||||
auto display_ret = call_command(display_cmd);
|
||||
if (!display_ret) {
|
||||
return false;
|
||||
}
|
||||
auto& display_result = display_ret.value();
|
||||
std::string display_pipe_str(
|
||||
std::make_move_iterator(display_result.begin()),
|
||||
std::make_move_iterator(display_result.end()));
|
||||
int size_value1 = 0;
|
||||
int size_value2 = 0;
|
||||
#ifdef _MSC_VER
|
||||
sscanf_s(display_pipe_str.c_str(), m_emulator_info.adb.display_format.c_str(), &size_value1, &size_value2);
|
||||
#else
|
||||
sscanf(display_pipe_str.c_str(), m_emulator_info.adb.display_format.c_str(), &size_value1, &size_value2);
|
||||
#endif
|
||||
// 为了防止抓取句柄的时候手机是竖屏的(还没进游戏),这里取大的值为宽,小的为高
|
||||
// 总不能有人竖屏玩明日方舟吧(?
|
||||
m_emulator_info.adb.display_width = (std::max)(size_value1, size_value2);
|
||||
m_emulator_info.adb.display_height = (std::min)(size_value1, size_value2);
|
||||
|
||||
constexpr double DefaultRatio =
|
||||
static_cast<double>(WindowWidthDefault) / static_cast<double>(WindowHeightDefault);
|
||||
double cur_ratio = static_cast<double>(m_emulator_info.adb.display_width) / static_cast<double>(m_emulator_info.adb.display_height);
|
||||
|
||||
if (cur_ratio >= DefaultRatio // 说明是宽屏或默认16:9,按照高度计算缩放
|
||||
|| std::fabs(cur_ratio - DefaultRatio) < DoubleDiff) {
|
||||
int scale_width = static_cast<int>(cur_ratio * WindowHeightDefault);
|
||||
m_scale_size = std::make_pair(scale_width, WindowHeightDefault);
|
||||
m_control_scale = static_cast<double>(m_emulator_info.adb.display_height) / static_cast<double>(WindowHeightDefault);
|
||||
}
|
||||
else { // 否则可能是偏正方形的屏幕,按宽度计算
|
||||
int scale_height = static_cast<int>(WindowWidthDefault / cur_ratio);
|
||||
m_scale_size = std::make_pair(WindowWidthDefault, scale_height);
|
||||
m_control_scale = static_cast<double>(m_emulator_info.adb.display_width) / static_cast<double>(WindowWidthDefault);
|
||||
}
|
||||
|
||||
m_emulator_info.adb.click = utils::string_replace_all_batch(
|
||||
m_emulator_info.adb.click, replaces);
|
||||
m_emulator_info.adb.swipe = utils::string_replace_all_batch(
|
||||
m_emulator_info.adb.swipe, replaces);
|
||||
m_emulator_info.adb.screencap_raw_with_gzip =
|
||||
utils::string_replace_all_batch(
|
||||
m_emulator_info.adb.screencap_raw_with_gzip, replaces);
|
||||
m_emulator_info.adb.screencap_encode = utils::string_replace_all_batch(m_emulator_info.adb.screencap_encode, replaces);
|
||||
m_emulator_info.adb.release = utils::string_replace_all(m_emulator_info.adb.release, "[Adb]", m_emulator_info.adb.path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
asst::Rect asst::Controller::shaped_correct(const Rect & rect) const
|
||||
{
|
||||
if (rect.empty()
|
||||
|| m_scale_size.first == 0
|
||||
|| m_scale_size.second == 0) {
|
||||
return rect;
|
||||
}
|
||||
// 明日方舟在异形屏上,有的地方是按比例缩放的,有的地方又是直接位移。没法整,这里简单粗暴一点截一个长条
|
||||
Rect dst = rect;
|
||||
if (m_scale_size.first != WindowWidthDefault) { // 说明是宽屏
|
||||
if (rect.width <= WindowWidthDefault / 2) {
|
||||
if (rect.x + rect.width <= WindowWidthDefault / 2) { // 整个矩形都在左半边
|
||||
dst.x = 0;
|
||||
dst.width = m_scale_size.first / 2;
|
||||
}
|
||||
else if (rect.x >= WindowWidthDefault / 2) { // 整个矩形都在右半边
|
||||
dst.x = m_scale_size.first / 2;
|
||||
dst.width = m_scale_size.first / 2;
|
||||
}
|
||||
else { // 整个矩形横跨了中线
|
||||
dst.x = 0;
|
||||
dst.width = m_scale_size.first;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dst.x = 0;
|
||||
dst.width = m_scale_size.first;
|
||||
}
|
||||
}
|
||||
else if (m_scale_size.second != WindowHeightDefault) { // 说明是偏方形屏
|
||||
if (rect.height <= WindowHeightDefault / 2) {
|
||||
if (rect.y + rect.height <= WindowHeightDefault / 2) { // 整个矩形都在上半边
|
||||
dst.y = 0;
|
||||
dst.height = m_scale_size.second / 2;
|
||||
}
|
||||
else if (rect.y >= WindowHeightDefault / 2) { // 整个矩形都在下半边
|
||||
dst.y = m_scale_size.second / 2;
|
||||
dst.height = m_scale_size.second / 2; // 整个矩形横跨了中线
|
||||
}
|
||||
else {
|
||||
dst.y = 0;
|
||||
dst.height = m_scale_size.second;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
dst.y = 0;
|
||||
dst.height = m_scale_size.second;
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
//asst::Rect asst::Controller::shaped_correct(const Rect & rect) const
|
||||
//{
|
||||
// if (rect.empty()
|
||||
// || m_scale_size.first == 0
|
||||
// || m_scale_size.second == 0) {
|
||||
// return rect;
|
||||
// }
|
||||
// // 明日方舟在异形屏上,有的地方是按比例缩放的,有的地方又是直接位移。没法整,这里简单粗暴一点截一个长条
|
||||
// Rect dst = rect;
|
||||
// if (m_scale_size.first != WindowWidthDefault) { // 说明是宽屏
|
||||
// if (rect.width <= WindowWidthDefault / 2) {
|
||||
// if (rect.x + rect.width <= WindowWidthDefault / 2) { // 整个矩形都在左半边
|
||||
// dst.x = 0;
|
||||
// dst.width = m_scale_size.first / 2;
|
||||
// }
|
||||
// else if (rect.x >= WindowWidthDefault / 2) { // 整个矩形都在右半边
|
||||
// dst.x = m_scale_size.first / 2;
|
||||
// dst.width = m_scale_size.first / 2;
|
||||
// }
|
||||
// else { // 整个矩形横跨了中线
|
||||
// dst.x = 0;
|
||||
// dst.width = m_scale_size.first;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// dst.x = 0;
|
||||
// dst.width = m_scale_size.first;
|
||||
// }
|
||||
// }
|
||||
// else if (m_scale_size.second != WindowHeightDefault) { // 说明是偏方形屏
|
||||
// if (rect.height <= WindowHeightDefault / 2) {
|
||||
// if (rect.y + rect.height <= WindowHeightDefault / 2) { // 整个矩形都在上半边
|
||||
// dst.y = 0;
|
||||
// dst.height = m_scale_size.second / 2;
|
||||
// }
|
||||
// else if (rect.y >= WindowHeightDefault / 2) { // 整个矩形都在下半边
|
||||
// dst.y = m_scale_size.second / 2;
|
||||
// dst.height = m_scale_size.second / 2; // 整个矩形横跨了中线
|
||||
// }
|
||||
// else {
|
||||
// dst.y = 0;
|
||||
// dst.height = m_scale_size.second;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// else {
|
||||
// dst.y = 0;
|
||||
// dst.height = m_scale_size.second;
|
||||
// }
|
||||
// }
|
||||
// return dst;
|
||||
//}
|
||||
|
||||
std::pair<int, int> asst::Controller::get_scale_size() const noexcept
|
||||
{
|
||||
@@ -292,148 +196,6 @@ void asst::Controller::pipe_working_proc()
|
||||
}
|
||||
}
|
||||
|
||||
void asst::Controller::set_dirname(std::string dirname) noexcept
|
||||
{
|
||||
m_dirname = std::move(dirname);
|
||||
}
|
||||
|
||||
bool asst::Controller::try_capture(const EmulatorInfo & info, bool without_handle)
|
||||
{
|
||||
LogTraceScope("try_capture | " + info.name);
|
||||
|
||||
const HandleInfo& handle_info = info.handle;
|
||||
|
||||
std::string adb_path;
|
||||
if (!without_handle) { // 使用模拟器自带的adb
|
||||
#ifdef _WIN32 // Only support Windows
|
||||
// 转成宽字符的
|
||||
wchar_t* class_wbuff = nullptr;
|
||||
if (!handle_info.class_name.empty()) {
|
||||
int class_len = static_cast<int>(handle_info.class_name.size() + 1U) * 2;
|
||||
class_wbuff = new wchar_t[class_len];
|
||||
::MultiByteToWideChar(CP_UTF8, 0, handle_info.class_name.c_str(), -1, class_wbuff, class_len);
|
||||
}
|
||||
wchar_t* window_wbuff = nullptr;
|
||||
if (!handle_info.window_name.empty()) {
|
||||
int window_len = static_cast<int>(handle_info.window_name.size() + 1U) * 2;
|
||||
window_wbuff = new wchar_t[window_len];
|
||||
memset(window_wbuff, 0, window_len);
|
||||
::MultiByteToWideChar(CP_UTF8, 0, handle_info.window_name.c_str(), -1, window_wbuff, window_len);
|
||||
}
|
||||
// 查找窗口句柄
|
||||
HWND window_handle = nullptr;
|
||||
window_handle = ::FindWindowExW(window_handle, nullptr, class_wbuff, window_wbuff);
|
||||
|
||||
if (class_wbuff != nullptr) {
|
||||
delete[] class_wbuff;
|
||||
class_wbuff = nullptr;
|
||||
}
|
||||
if (window_wbuff != nullptr) {
|
||||
delete[] window_wbuff;
|
||||
window_wbuff = nullptr;
|
||||
}
|
||||
if (window_handle == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string emulator_path;
|
||||
if (info.path.empty()) {
|
||||
// 获取模拟器窗口句柄对应的进程句柄
|
||||
DWORD process_id = 0;
|
||||
::GetWindowThreadProcessId(window_handle, &process_id);
|
||||
HANDLE process_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_id);
|
||||
|
||||
// 获取模拟器程序所在路径
|
||||
LPSTR path_buff = new CHAR[MAX_PATH];
|
||||
memset(path_buff, 0, MAX_PATH);
|
||||
DWORD path_size = MAX_PATH;
|
||||
QueryFullProcessImageNameA(process_handle, 0, path_buff, &path_size);
|
||||
emulator_path = std::string(path_buff);
|
||||
if (path_buff != nullptr) {
|
||||
delete[] path_buff;
|
||||
path_buff = nullptr;
|
||||
}
|
||||
if (emulator_path.empty()) {
|
||||
return false;
|
||||
}
|
||||
Resrc.cfg().set_emulator_path(info.name, emulator_path);
|
||||
Resrc.user().set_emulator_path(info.name, emulator_path);
|
||||
}
|
||||
else {
|
||||
emulator_path = info.path;
|
||||
}
|
||||
|
||||
// 到这一步说明句柄和权限没问题了,接下来就是adb的事情了
|
||||
m_emulator_info = info;
|
||||
Log.trace("Handle:", window_handle, "Name:", m_emulator_info.name);
|
||||
|
||||
adb_path = emulator_path.substr(0, emulator_path.find_last_of('\\') + 1);
|
||||
adb_path = '"' + utils::string_replace_all(m_emulator_info.adb.path, "[EmulatorPath]", adb_path) + '"';
|
||||
adb_path = utils::string_replace_all(adb_path, "[ExecDir]", m_dirname);
|
||||
#else
|
||||
Log.error("Capture handle is only supported on Windows!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
else { // 使用辅助自带的标准adb
|
||||
m_emulator_info = info;
|
||||
#ifdef _WIN32
|
||||
adb_path = '"' + utils::string_replace_all(m_emulator_info.adb.path, "[ExecDir]", m_dirname) + '"';
|
||||
#else
|
||||
adb_path = m_emulator_info.adb.path;
|
||||
#endif
|
||||
}
|
||||
|
||||
m_emulator_info.adb.path = std::move(adb_path);
|
||||
|
||||
// 优先使用addresses里指定的地址
|
||||
for (const std::string& address : info.adb.addresses) {
|
||||
if (connect_adb(address)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 若指定地址都没连上,再尝试用devices查找地址
|
||||
std::string devices_cmd = utils::string_replace_all(m_emulator_info.adb.devices, "[Adb]", m_emulator_info.adb.path);
|
||||
auto devices_ret = call_command(devices_cmd);
|
||||
if (!devices_ret) {
|
||||
return false;
|
||||
}
|
||||
auto& devices_result = devices_ret.value();
|
||||
std::string devices_pipe_str(
|
||||
std::make_move_iterator(devices_result.begin()),
|
||||
std::make_move_iterator(devices_result.end()));
|
||||
auto lines = utils::string_split(devices_pipe_str, "\r\n");
|
||||
|
||||
std::string address;
|
||||
const std::regex address_regex(m_emulator_info.adb.address_regex);
|
||||
for (const std::string& line : lines) {
|
||||
std::smatch smatch;
|
||||
if (std::regex_match(line, smatch, address_regex)) {
|
||||
address = smatch[1];
|
||||
}
|
||||
}
|
||||
Log.trace("device address", address);
|
||||
if (address.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return connect_adb(address);
|
||||
}
|
||||
|
||||
//void asst::Controller::set_idle(bool flag)
|
||||
//{
|
||||
// LogTraceFunction;
|
||||
//
|
||||
// m_thread_idle = flag;
|
||||
// if (!flag) {
|
||||
// // 开始前,立即截一张图,保证第一张图片非空
|
||||
// //screencap();
|
||||
//
|
||||
// m_cmd_condvar.notify_one();
|
||||
// }
|
||||
//}
|
||||
|
||||
std::optional<std::vector<unsigned char>> asst::Controller::call_command(const std::string & cmd)
|
||||
{
|
||||
LogTraceFunction;
|
||||
@@ -617,15 +379,13 @@ bool asst::Controller::screencap()
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
auto& adb = m_emulator_info.adb;
|
||||
|
||||
DecodeFunc decode_raw_with_gzip = [&](const std::vector<uchar>& data) -> bool {
|
||||
auto unzip_data = gzip::decompress(data.data(), data.size());
|
||||
Log.trace("unzip data size:", unzip_data.size());
|
||||
if (unzip_data.empty()) {
|
||||
return false;
|
||||
}
|
||||
size_t std_size = adb.display_height * adb.display_width * 4;
|
||||
size_t std_size = m_width * m_height * 4;
|
||||
if (unzip_data.size() < std_size) {
|
||||
return false;
|
||||
}
|
||||
@@ -639,11 +399,7 @@ bool asst::Controller::screencap()
|
||||
if (is_all_zero) {
|
||||
return false;
|
||||
}
|
||||
cv::Mat temp = cv::Mat(
|
||||
adb.display_height,
|
||||
adb.display_width,
|
||||
CV_8UC4,
|
||||
unzip_data.data() + header_size);
|
||||
cv::Mat temp(m_height, m_width, CV_8UC4, unzip_data.data() + header_size);
|
||||
if (temp.empty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -663,29 +419,29 @@ bool asst::Controller::screencap()
|
||||
return true;
|
||||
};
|
||||
|
||||
switch (adb.screencap_method) {
|
||||
case AdbCmd::ScreencapMethod::UnknownYet:
|
||||
switch (m_adb.screencap_method) {
|
||||
case AdbProperty::ScreencapMethod::UnknownYet:
|
||||
{
|
||||
if (screencap(adb.screencap_raw_with_gzip, decode_raw_with_gzip)) {
|
||||
adb.screencap_method = AdbCmd::ScreencapMethod::RawWithGzip;
|
||||
if (screencap(m_adb.screencap_raw_with_gzip, decode_raw_with_gzip)) {
|
||||
m_adb.screencap_method = AdbProperty::ScreencapMethod::RawWithGzip;
|
||||
return true;
|
||||
}
|
||||
else if (screencap(adb.screencap_encode, decode_encode)) {
|
||||
adb.screencap_method = AdbCmd::ScreencapMethod::Encode;
|
||||
else if (screencap(m_adb.screencap_encode, decode_encode)) {
|
||||
m_adb.screencap_method = AdbProperty::ScreencapMethod::Encode;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case AdbCmd::ScreencapMethod::RawWithGzip:
|
||||
case AdbProperty::ScreencapMethod::RawWithGzip:
|
||||
{
|
||||
return screencap(adb.screencap_raw_with_gzip, decode_raw_with_gzip);
|
||||
return screencap(m_adb.screencap_raw_with_gzip, decode_raw_with_gzip);
|
||||
}
|
||||
break;
|
||||
case AdbCmd::ScreencapMethod::Encode:
|
||||
case AdbProperty::ScreencapMethod::Encode:
|
||||
{
|
||||
return screencap(adb.screencap_encode, decode_encode);
|
||||
return screencap(m_adb.screencap_encode, decode_encode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -695,7 +451,6 @@ bool asst::Controller::screencap()
|
||||
|
||||
bool asst::Controller::screencap(const std::string & cmd, DecodeFunc decode_func)
|
||||
{
|
||||
auto& adb = m_emulator_info.adb;
|
||||
auto ret = call_command(cmd);
|
||||
|
||||
if (!ret || ret.value().empty()) {
|
||||
@@ -704,25 +459,25 @@ bool asst::Controller::screencap(const std::string & cmd, DecodeFunc decode_func
|
||||
}
|
||||
auto data = std::move(ret).value();
|
||||
|
||||
if (adb.screencap_end_of_line == AdbCmd::ScreencapEndOfLine::CRLF) {
|
||||
if (m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::CRLF) {
|
||||
convert_lf(data);
|
||||
}
|
||||
|
||||
if (decode_func(data)) {
|
||||
if (adb.screencap_end_of_line == AdbCmd::ScreencapEndOfLine::UnknownYet) {
|
||||
adb.screencap_end_of_line = AdbCmd::ScreencapEndOfLine::LF;
|
||||
if (m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::UnknownYet) {
|
||||
m_adb.screencap_end_of_line = AdbProperty::ScreencapEndOfLine::LF;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Log.info("data is not empty, but image is empty");
|
||||
|
||||
if (adb.screencap_end_of_line == AdbCmd::ScreencapEndOfLine::UnknownYet) {
|
||||
if (m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::UnknownYet) {
|
||||
Log.info("try to cvt lf");
|
||||
convert_lf(data);
|
||||
|
||||
if (decode_func(data)) {
|
||||
adb.screencap_end_of_line = AdbCmd::ScreencapEndOfLine::CRLF;
|
||||
m_adb.screencap_end_of_line = AdbProperty::ScreencapEndOfLine::CRLF;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@@ -763,10 +518,10 @@ int asst::Controller::click(const Rect & rect, bool block)
|
||||
|
||||
int asst::Controller::click_without_scale(const Point & p, bool block)
|
||||
{
|
||||
if (p.x < 0 || p.x >= m_emulator_info.adb.display_width || p.y < 0 || p.y >= m_emulator_info.adb.display_height) {
|
||||
if (p.x < 0 || p.x >= m_width || p.y < 0 || p.y >= m_height) {
|
||||
Log.error("click point out of range");
|
||||
}
|
||||
std::string cur_cmd = utils::string_replace_all(m_emulator_info.adb.click, "[x]", std::to_string(p.x));
|
||||
std::string cur_cmd = utils::string_replace_all(m_adb.click, "[x]", std::to_string(p.x));
|
||||
cur_cmd = utils::string_replace_all(cur_cmd, "[y]", std::to_string(p.y));
|
||||
int id = push_cmd(cur_cmd);
|
||||
if (block) {
|
||||
@@ -798,10 +553,10 @@ int asst::Controller::swipe(const Rect & r1, const Rect & r2, int duration, bool
|
||||
|
||||
int asst::Controller::swipe_without_scale(const Point & p1, const Point & p2, int duration, bool block, int extra_delay, bool extra_swipe)
|
||||
{
|
||||
if (p1.x < 0 || p1.x >= m_emulator_info.adb.display_width || p1.y < 0 || p1.y >= m_emulator_info.adb.display_height || p2.x < 0 || p2.x >= m_emulator_info.adb.display_width || p2.y < 0 || p2.y >= m_emulator_info.adb.display_height) {
|
||||
if (p1.x < 0 || p1.x >= m_width || p1.y < 0 || p1.y >= m_height || p2.x < 0 || p2.x >= m_width || p2.y < 0 || p2.y >= m_height) {
|
||||
Log.error("swipe point out of range");
|
||||
}
|
||||
std::string cur_cmd = utils::string_replace_all(m_emulator_info.adb.swipe, "[x1]", std::to_string(p1.x));
|
||||
std::string cur_cmd = utils::string_replace_all(m_adb.swipe, "[x1]", std::to_string(p1.x));
|
||||
cur_cmd = utils::string_replace_all(cur_cmd, "[y1]", std::to_string(p1.y));
|
||||
cur_cmd = utils::string_replace_all(cur_cmd, "[x2]", std::to_string(p2.x));
|
||||
cur_cmd = utils::string_replace_all(cur_cmd, "[y2]", std::to_string(p2.y));
|
||||
@@ -819,7 +574,7 @@ int asst::Controller::swipe_without_scale(const Point & p1, const Point & p2, in
|
||||
|
||||
// 额外的滑动:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来
|
||||
if (extra_swipe && extra_swipe_duration >= 0) {
|
||||
std::string extra_cmd = utils::string_replace_all(m_emulator_info.adb.swipe, "[x1]", std::to_string(p2.x));
|
||||
std::string extra_cmd = utils::string_replace_all(m_adb.swipe, "[x1]", std::to_string(p2.x));
|
||||
extra_cmd = utils::string_replace_all(extra_cmd, "[y1]", std::to_string(p2.y));
|
||||
int end_x = 0, end_y = 0;
|
||||
if (p2.x != p1.x) {
|
||||
@@ -855,6 +610,131 @@ int asst::Controller::swipe_without_scale(const Rect & r1, const Rect & r2, int
|
||||
return swipe_without_scale(rand_point_in_rect(r1), rand_point_in_rect(r2), duration, block, extra_delay, extra_swipe);
|
||||
}
|
||||
|
||||
bool asst::Controller::connect(const std::string & adb_path, const std::string & address, const std::string & config)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
auto adb_ret = Resrc.cfg().get_adb_cfg(config);
|
||||
if (!adb_ret) {
|
||||
json::value info = json::object{
|
||||
{"what", "ConnectFailed"},
|
||||
{"why", "ConfigNotFound"},
|
||||
{"details", json::object{}}
|
||||
};
|
||||
m_callback(AsstMsg::ConnectionError, info, m_callback_arg);
|
||||
return false;
|
||||
}
|
||||
const auto adb_cfg = std::move(adb_ret.value());
|
||||
std::string display_id;
|
||||
|
||||
auto cmd_replace = [&](const std::string& cfg_cmd) -> std::string {
|
||||
const std::unordered_map<std::string, std::string> replacements = {
|
||||
{"[Adb]", address},
|
||||
{"[Address]", address},
|
||||
{"[DisplayId]", display_id}
|
||||
};
|
||||
std::string formatted = cfg_cmd;
|
||||
for (const auto& [key, value] : replacements) {
|
||||
utils::string_replace_all(formatted, key, value);
|
||||
}
|
||||
return formatted;
|
||||
};
|
||||
|
||||
/* connect */
|
||||
{
|
||||
auto connect_ret = call_command(cmd_replace(adb_cfg.connect));
|
||||
// 端口即使错误,命令仍然会返回0,TODO 对connect_result进行判断
|
||||
if (!connect_ret) {
|
||||
json::value info = json::object{
|
||||
{"what", "ConnectFailed"},
|
||||
{"why", "Connection command failed to exec"},
|
||||
{"details", json::object{}}
|
||||
};
|
||||
m_callback(AsstMsg::ConnectionError, info, m_callback_arg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 按需获取display ID 信息
|
||||
if (!adb_cfg.display_id.empty()) {
|
||||
auto display_id_ret = call_command(cmd_replace(adb_cfg.display_id));
|
||||
if (!display_id_ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& display_id_result = display_id_ret.value();
|
||||
convert_lf(display_id_result);
|
||||
std::string display_id_pipe_str(
|
||||
std::make_move_iterator(display_id_result.begin()),
|
||||
std::make_move_iterator(display_id_result.end()));
|
||||
auto last = display_id_pipe_str.rfind(':');
|
||||
if (last == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
display_id = display_id_pipe_str.substr(last + 1);
|
||||
// 去掉换行
|
||||
display_id.pop_back();
|
||||
}
|
||||
|
||||
/* display */
|
||||
{
|
||||
auto display_ret = call_command(cmd_replace(adb_cfg.display));
|
||||
if (!display_ret) {
|
||||
json::value info = json::object{
|
||||
{"what", "ConnectFailed"},
|
||||
{"why", "Display command failed to exec"},
|
||||
{"details", json::object{}}
|
||||
};
|
||||
m_callback(AsstMsg::ConnectionError, info, m_callback_arg);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& display_result = display_ret.value();
|
||||
std::string display_pipe_str(
|
||||
std::make_move_iterator(display_result.begin()),
|
||||
std::make_move_iterator(display_result.end()));
|
||||
int size_value1 = 0;
|
||||
int size_value2 = 0;
|
||||
#ifdef _MSC_VER
|
||||
sscanf_s(display_pipe_str.c_str(), adb_cfg.display_format.c_str(), &size_value1, &size_value2);
|
||||
#else
|
||||
sscanf(display_pipe_str.c_str(), adb_cfg.display_format.c_str(), &size_value1, &size_value2);
|
||||
#endif
|
||||
// 为了防止抓取句柄的时候手机是竖屏的(还没进游戏),这里取大的值为宽,小的为高
|
||||
// 总不能有人竖屏玩明日方舟吧(?
|
||||
m_width = (std::max)(size_value1, size_value2);
|
||||
m_height = (std::min)(size_value1, size_value2);
|
||||
}
|
||||
|
||||
/* calc ratio */
|
||||
{
|
||||
constexpr double DefaultRatio =
|
||||
static_cast<double>(WindowWidthDefault) / static_cast<double>(WindowHeightDefault);
|
||||
double cur_ratio = static_cast<double>(m_width) / static_cast<double>(m_height);
|
||||
|
||||
if (cur_ratio >= DefaultRatio // 说明是宽屏或默认16:9,按照高度计算缩放
|
||||
|| std::fabs(cur_ratio - DefaultRatio) < DoubleDiff) {
|
||||
int scale_width = static_cast<int>(cur_ratio * WindowHeightDefault);
|
||||
m_scale_size = std::make_pair(scale_width, WindowHeightDefault);
|
||||
m_control_scale = static_cast<double>(m_height) / static_cast<double>(WindowHeightDefault);
|
||||
}
|
||||
else { // 否则可能是偏正方形的屏幕,按宽度计算
|
||||
int scale_height = static_cast<int>(WindowWidthDefault / cur_ratio);
|
||||
m_scale_size = std::make_pair(WindowWidthDefault, scale_height);
|
||||
m_control_scale = static_cast<double>(m_width) / static_cast<double>(WindowWidthDefault);
|
||||
}
|
||||
}
|
||||
|
||||
m_adb.click = cmd_replace(adb_cfg.click);
|
||||
m_adb.swipe = cmd_replace(adb_cfg.swipe);
|
||||
m_adb.screencap_raw_with_gzip = cmd_replace(adb_cfg.screencap_raw_with_gzip);
|
||||
m_adb.screencap_encode = cmd_replace(adb_cfg.screencap_encode);
|
||||
m_adb.release = cmd_replace(adb_cfg.release);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cv::Mat asst::Controller::get_image()
|
||||
{
|
||||
// 有些模拟器adb偶尔会莫名其妙截图失败,多试几次
|
||||
|
||||
Reference in New Issue
Block a user