diff --git a/main.cpp b/main.cpp index cddc355..ab8040b 100644 --- a/main.cpp +++ b/main.cpp @@ -64,95 +64,6 @@ void wait(const int milliseconds) { int main(int argc, char *argv[]) { - // Шаг 1: запускаем приложение РСХБ - runADBCommand("monkey -p ru.rshb.dbo -c android.intent.category.LAUNCHER 1"); - - wait(4500); // Ждем пока загружается приложение, перед экраном ввода пин-кода - - // Шаг 2: Ввод ПИН - runADBCommand("input tap 275 900"); // Клик по цифре 1 - runADBCommand("input tap 560 900"); // Клик по цифре 2 - runADBCommand("input tap 275 900"); // Клик по цифре 1 - runADBCommand("input tap 275 900"); // Клик по цифре 1 - - wait(5500); - - // Шаг 3: Закрытие рекламы - runADBCommand("input tap 300 2090"); // Закрыть баннер пуш-уведомлений (Баннер высвечивается при каждом 2-м запуске) - // runADBCommand("input tap 993 163"); // Закрыть сторис (только при первом входе после логина) - // runADBCommand("input tap 920 151"); // Закрыть окно перед главным экраном (только при первом входе после логина) - // runADBCommand("input tap 990 170"); // Закрыть другое окно (только при первом входе после логина) - - wait(1500); - - // Шаг 4: Пролистывание до кнопки "Все продукты" - runADBCommand("input swipe 1000 2000 1000 1300"); - - wait(3000); - - // Шаг 5: Нажимаем на кнопку "Все продукты" - runADBCommand("input tap 570 1240"); - - wait(3000); - - // Шаг 6: Выбор карты - // runADBCommand("input tap 530 535"); // Для карты дебетовая, цифровая, **6387 - runADBCommand("input tap 530 675"); // Для карты дебетовая, **0823 - // runADBCommand("input tap 530 800"); // Для карты дебетовая, **7498 - - wait(1500); - - // Шаг 7: Нажимаем на кнопку "Оплатить" - runADBCommand("input tap 430 920"); - - wait(1200); - - // Шаг 8: Нажимаем на блок "По номеру телефона" - runADBCommand("input tap 260 1500"); - - wait(2000); - - // Шаг 8.1: Закрытие окна разрешения доступа к контактам - // runADBCommand("input tap 540 2140"); - // wait(500); - - // Вводим номер телефона для перевода - runADBCommand("input tap 250 250"); - runADBCommand("input text '9272960333'"); - - wait(1200); - - // Шаг 9: Нажимаем на область "Другой банк через СБП" - runADBCommand("input tap 500 600"); - - wait(2000); - - // Шаг 10: Выбор банка - // runADBCommand("input tap 280 280"); // Нажимаем для фокуса у поля ввода текста - // runADBCommand("input text 'Т-Банк'"); // Передаем текст 'Т-банк' (Проблема - выдает NullPointerException из-за кириллицы) - runADBCommand("input tap 420 620"); // Т-Банк (Пока выбираю хардкодовым нажатием по списку) - - wait(2000); - - // Шаг 11: Ввод суммы - runADBCommand("input tap 300 1040"); - runADBCommand("input text '10'"); - - wait(2000); - - // Шаг 11.1: Подтверждаем перевод - runADBCommand("input tap 500 2170"); - - wait(2000); - - // Завершаем перевод - runADBCommand("input tap 500 2170"); - - std::cout << "All commands executed successfully." << std::endl; - - - return 0; - QApplication app(argc, argv); // QList cards = AccountInfoScreener::parseCardData(QByteArray()); @@ -169,7 +80,7 @@ int main(int argc, char *argv[]) { // } - // setupWorkerAndThread(app); + setupWorkerAndThread(app); // // const QDateTime current = QDateTime::currentDateTimeUtc(); // qDebug() << "Обновление lastScan:" << CommonDataDAO::updateLastScan(current); diff --git a/views/DeviceWidget.cpp b/views/DeviceWidget.cpp index 822f179..0ecc584 100644 --- a/views/DeviceWidget.cpp +++ b/views/DeviceWidget.cpp @@ -3,6 +3,7 @@ #include #include #include +#include DeviceWidget::DeviceWidget(const DeviceInfo &device, QWidget *parent): QWidget(parent) { auto *layout = new QVBoxLayout(this); @@ -35,3 +36,17 @@ DeviceWidget::DeviceWidget(const DeviceInfo &device, QWidget *parent): QWidget(p layout->setSpacing(0); layout->addWidget(statusLabel); } + +void DeviceWidget::mouseDoubleClickEvent(QMouseEvent *event) { + if (event->button() == Qt::LeftButton) { + if (scrcpyWindow == nullptr) { + scrcpyWindow = new ScrcpyWindow(); + scrcpyWindow->show(); + + // Подключаем сигнал закрытия окна + connect(scrcpyWindow, &ScrcpyWindow::destroyed, this, [this]() { + scrcpyWindow = nullptr; // Освобождаем память, когда окно закрыто + }); + } + } +} diff --git a/views/DeviceWidget.h b/views/DeviceWidget.h index e2d983f..e74ee17 100644 --- a/views/DeviceWidget.h +++ b/views/DeviceWidget.h @@ -1,10 +1,17 @@ #pragma once #include #include "db/DeviceInfo.h" +#include "scrcpy/ScrcpyWindow.h" class DeviceWidget final : public QWidget { Q_OBJECT public: explicit DeviceWidget(const DeviceInfo& device, QWidget* parent = nullptr); + +private: + ScrcpyWindow *scrcpyWindow = nullptr; + +protected: + void mouseDoubleClickEvent(QMouseEvent *event) override; }; diff --git a/views/MainWindow.cpp b/views/MainWindow.cpp index 1cdd484..2009158 100644 --- a/views/MainWindow.cpp +++ b/views/MainWindow.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "db/DeviceInfo.h" #include "DeviceWidget.h" @@ -12,6 +14,7 @@ #include "widget/FlowLayout.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { + // Инициализируем таймер обновления timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &MainWindow::loadDevices); @@ -21,12 +24,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { createDevicePage(); stackedWidget->addWidget(devicePage); - // stackedWidget->setCurrentWidget(devicePage); FIXME + stackedWidget->setCurrentWidget(devicePage); // FIXME переделать на ленивое создание accountPage = new AccountWindow(this); stackedWidget->addWidget(accountPage); - stackedWidget->setCurrentWidget(accountPage); + // stackedWidget->setCurrentWidget(accountPage); resize(800, 600); @@ -48,9 +51,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { stackedWidget->setCurrentWidget(accountPage); deleteDevicePage(); // освобождаем ресурсы }); - - scrcpyWindow = new ScrcpyWindow(); - scrcpyWindow->show(); } @@ -114,3 +114,18 @@ void MainWindow::loadDevices() { flowLayout->addWidget(new DeviceWidget(device)); } } + +void MainWindow::closeEvent(QCloseEvent *event) { + closeAllWindows(); // Закрываем все окна + // event->accept(); // Разрешаем закрытие окна +} + +void MainWindow::closeAllWindows() { + // QList topLevelWidgets = QApplication::topLevelWidgets(); // Получаем все верхние окна + + // for (QWidget *widget : topLevelWidgets) { + // widget->close(); // Закрываем каждое окно + // } + QApplication::quit(); + // QCoreApplication::exit(0); +} diff --git a/views/MainWindow.h b/views/MainWindow.h index 8d8e001..ca7cb5d 100644 --- a/views/MainWindow.h +++ b/views/MainWindow.h @@ -4,7 +4,6 @@ #include #include #include "db/DeviceInfo.h" -#include "scrcpy/ScrcpyWindow.h" #include "widget/FlowLayout.h" class MainWindow final : public QMainWindow { @@ -13,6 +12,9 @@ public: explicit MainWindow(QWidget *parent = nullptr); void loadDevices(); +protected: + void closeEvent(QCloseEvent *event) override; + private: QWidget* central; FlowLayout* flowLayout; @@ -22,8 +24,8 @@ private: QWidget* devicePage = nullptr; QWidget* accountPage = nullptr; - ScrcpyWindow *scrcpyWindow; - void createDevicePage(); void deleteDevicePage(); + + void closeAllWindows(); }; diff --git a/views/scrcpy/ScrcpyWindow.cpp b/views/scrcpy/ScrcpyWindow.cpp index ee040df..e0b4ac5 100644 --- a/views/scrcpy/ScrcpyWindow.cpp +++ b/views/scrcpy/ScrcpyWindow.cpp @@ -1,13 +1,17 @@ #include "ScrcpyWindow.h" +#include #include +#include #include +#include #ifdef Q_OS_WIN #include +#include #endif ScrcpyWindow::ScrcpyWindow(QWidget *parent) : QWidget(parent), m_process(nullptr) { - setWindowFlag(Qt::WindowStaysOnTopHint); + // setWindowFlag(Qt::WindowStaysOnTopHint); startScrcpy(); } @@ -15,45 +19,161 @@ ScrcpyWindow::~ScrcpyWindow() { stopScrcpy(); } +void ScrcpyWindow::closeEvent(QCloseEvent *event) { + qDebug() << "closeEvent triggered"; + stopScrcpy(); + event->accept(); +} + void ScrcpyWindow::startScrcpy() { - m_process = new QProcess(this); - m_process->start("scrcpy", {"--window-title", "scrcpy", "--always-on-top"}); + int deviceWidth = 720; + int deviceHeight = 1600; + + QScreen* screen = QGuiApplication::primaryScreen(); + int screenHeight = screen->availableGeometry().height(); + int screenWidth = screen->availableGeometry().width(); + + // Вычисляем масштаб так, чтобы устройство влезло в экран (и по ширине, и по высоте) + double scaleW = static_cast(screenWidth) / deviceWidth; + double scaleH = static_cast(screenHeight) / deviceHeight; + double scale = qMin(scaleW, scaleH) * 0.8; // 90% от доступного размера, с отступами + + int windowWidth = static_cast(deviceWidth * scale); + int windowHeight = static_cast(deviceHeight * scale); + qDebug() << "windowWidth:" << windowWidth; + qDebug() << "windowHeight:" << windowHeight; + // Устанавливаем размер вашего окна + setFixedSize(windowWidth + 200, windowHeight); + // setWindowFlags(windowFlags() | Qt::MSWindowsFixedSizeDialogHint); + + // QString("--window-width=%1").arg(windowWidth), QString("--window-height=%1").arg(windowHeight) + // m_process = new QProcess(this); + // m_process->start("scrcpy", { "--window-title", "scrcpy", "--always-on-top"}); // Подождём немного, чтобы окно scrcpy запустилось - QTimer::singleShot(5000, this, &ScrcpyWindow::embedPlatformSpecific); + // QTimer::singleShot(2000, this, &ScrcpyWindow::); + // embedPlatformSpecific(); } void ScrcpyWindow::stopScrcpy() { - if (m_process) { - m_process->terminate(); - m_process->waitForFinished(); - delete m_process; - m_process = nullptr; + // m_process->terminate(); + // if (!m_process->waitForFinished(3000)) { + // qDebug() << "Process did not finish in time, killing it"; + m_process->kill(); // Принудительное завершение процесса + // } + delete m_process; + m_process = nullptr; +#ifdef Q_OS_WIN + HWND hwndScrcpy = FindWindowW(nullptr, L"scrcpy"); + if (hwndScrcpy) { + PostMessage(hwndScrcpy, WM_CLOSE, 0, 0); } +#endif } +LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + OutputDebugString(L"WM_CLOSE received\n"); + + HWND hwndScrcpy = FindWindowW(nullptr, L"scrcpy"); + if (!hwndScrcpy) + return DefWindowProc(hwnd, msg, wParam, lParam); + + if (msg == WM_CLOSE) { + qDebug() << "WM_CLOSE received, closing scrcpy window."; + // Возможно, необходимо обработать конкретно это сообщение + // или сделать дополнительные проверки. + } + switch (msg) { + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MOUSEMOVE: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MOUSEWHEEL: + { + // Перевод координат мыши в координаты окна scrcpy + POINT pt; + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + qDebug() << "Before ClientToScreen: " << pt.x << ", " << pt.y; + ClientToScreen(hwnd, &pt); + qDebug() << "After ClientToScreen: " << pt.x << ", " << pt.y; + ScreenToClient(hwndScrcpy, &pt); + qDebug() << "After ScreenToClient: " << pt.x << ", " << pt.y; + + LPARAM newLParam = MAKELPARAM(pt.x, pt.y); + + SendMessage(hwndScrcpy, msg, wParam, newLParam); + return 0; + } + + case WM_KEYDOWN: + case WM_KEYUP: + case WM_CHAR: + SendMessage(hwndScrcpy, msg, wParam, lParam); + return 0; + } + + return DefWindowProc(hwnd, msg, wParam, lParam); +} void ScrcpyWindow::embedPlatformSpecific() { #ifdef Q_OS_WIN HWND hwndScrcpy = FindWindowW(nullptr, L"scrcpy"); + + int attempts = 0; + while (!hwndScrcpy && attempts < 20) { + hwndScrcpy = FindWindowW(nullptr, L"scrcpy"); + Sleep(100); // Задержка 100 мс + attempts++; + } + if (!hwndScrcpy) { qDebug() << "scrcpy window not found"; return; } + Sleep(1000); + + // Получаем hwnd текущего окна HWND hwndTarget = (HWND)this->winId(); + + // Устанавливаем окно scrcpy как дочернее SetParent(hwndScrcpy, hwndTarget); + // Убираем рамки и заголовок LONG style = GetWindowLong(hwndScrcpy, GWL_STYLE); style &= ~(WS_CAPTION | WS_THICKFRAME | WS_BORDER); SetWindowLong(hwndScrcpy, GWL_STYLE, style); + // Получаем размеры клиентской области RECT rect; GetClientRect(hwndTarget, &rect); + + qDebug() << "Client area size: " << rect.right << ", " << rect.bottom; + + // int deviceWidth = 720; + // int deviceHeight = 1600; + // Client area size: 676 , 1502 + + + // Получаем размеры клиентской области + // RECT rect; + // GetClientRect(hwndTarget, &rect); SetWindowPos(hwndScrcpy, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top, - SWP_SHOWWINDOW); + SWP_SHOWWINDOW | SWP_FRAMECHANGED); + + // rect.right - rect.left, rect.bottom - rect.top, + + + // Сохраняем старую оконную процедуру + // LONG_PTR prevWndProc = GetWindowLongPtr(hwndTarget, GWLP_WNDPROC); + + // SetWindowLongPtr(hwndTarget, GWLP_WNDPROC, (LONG_PTR)wndProc); #elif defined(Q_OS_MAC) diff --git a/views/scrcpy/ScrcpyWindow.h b/views/scrcpy/ScrcpyWindow.h index e52d635..5724bc7 100644 --- a/views/scrcpy/ScrcpyWindow.h +++ b/views/scrcpy/ScrcpyWindow.h @@ -2,6 +2,7 @@ #include #include +#include class ScrcpyWindow final : public QWidget { Q_OBJECT @@ -11,6 +12,9 @@ public: ~ScrcpyWindow() override; +protected: + void closeEvent(QCloseEvent *event) override; + private: QProcess *m_process;