From cefad834c76635d9efb045d650a9557c85d49396 Mon Sep 17 00:00:00 2001 From: slava Date: Sat, 21 Mar 2026 18:14:05 +0700 Subject: [PATCH] Enhance `findPinCodeNodes` logic in `ScreenXmlParser` with regex support and size tolerance improvements Refactored the PIN pad detection method to support flexible text matching using regex (e.g., "1", "key 1"). Updated node grouping logic to allow size tolerance for identifying clickable nodes, enabling fallback handling when exact matches fail. Improved debugging output for easier issue diagnosis. --- android/ozon/ScreenXmlParser.cpp | 78 ++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/android/ozon/ScreenXmlParser.cpp b/android/ozon/ScreenXmlParser.cpp index f0f5951..0c71a85 100644 --- a/android/ozon/ScreenXmlParser.cpp +++ b/android/ozon/ScreenXmlParser.cpp @@ -398,12 +398,14 @@ QString ScreenXmlParser::parseProfilePhone() { QList ScreenXmlParser::findPinCodeNodes(const QString &pinCode) { // Способ 1: ищем кликабельные ноды с текстом-цифрой (0-9) + // Поддерживаем форматы: "1", "key 1", и т.п. QMap digitMap; + static const QRegularExpression digitRx(R"(^(?:key\s+)?(\d)$)", QRegularExpression::CaseInsensitiveOption); for (const Node &node : m_nodes) { if (!node.clickable || node.width() <= 0 || node.height() <= 0) continue; const QString t = node.text.trimmed(); - if (t.size() == 1 && t.at(0).isDigit()) { - digitMap[t] = node; + if (const auto match = digitRx.match(t); match.hasMatch()) { + digitMap[match.captured(1)] = node; } } @@ -421,42 +423,62 @@ QList ScreenXmlParser::findPinCodeNodes(const QString &pinCode) { return result; } - // Способ 2 (fallback): группируем clickable-ноды одинакового размера, + // Способ 2 (fallback): группируем clickable-ноды похожего размера, // ищем сетку 4x3 по паттерну (не привязываясь к координатам экрана) - QMap, QList> sizeGroups; + constexpr int SIZE_TOLERANCE = 10; // допуск в пикселях + + // Собираем все clickable ноды с положительным размером + QList allClickable; for (const Node &node : m_nodes) { if (!node.clickable || node.width() <= 0 || node.height() <= 0) continue; - if (node.width() == node.height()) { // кнопки пин-пада квадратные - sizeGroups[{node.width(), node.height()}].append(node); - } + allClickable.append(node); } - // Ищем группу из >= 12 одинаковых кнопок (пин-пад: 3x4 = 12) - QList candidates; - for (auto it = sizeGroups.begin(); it != sizeGroups.end(); ++it) { - if (it.value().size() >= 12 && - (candidates.isEmpty() || it.value().size() < candidates.size())) { - candidates = it.value(); - } - } + // Группируем с допуском: для каждой ноды проверяем, подходит ли она к существующей группе + auto fuzzyGroup = [&](bool squareOnly) -> QList { + QList> groups; + QList> groupSizes; // эталонный размер каждой группы - if (candidates.size() < 12) { - // Попробуем без ограничения на квадрат, но с >= 12 - sizeGroups.clear(); - for (const Node &node : m_nodes) { - if (!node.clickable || node.width() <= 0 || node.height() <= 0) continue; - sizeGroups[{node.width(), node.height()}].append(node); - } - for (auto it = sizeGroups.begin(); it != sizeGroups.end(); ++it) { - if (it.value().size() >= 12 && - (candidates.size() < 12 || it.value().size() < candidates.size())) { - candidates = it.value(); + for (const Node &node : allClickable) { + if (squareOnly && std::abs(node.width() - node.height()) > SIZE_TOLERANCE) + continue; + bool placed = false; + for (int g = 0; g < groups.size(); ++g) { + if (std::abs(node.width() - groupSizes[g].first) <= SIZE_TOLERANCE && + std::abs(node.height() - groupSizes[g].second) <= SIZE_TOLERANCE) { + groups[g].append(node); + placed = true; + break; + } + } + if (!placed) { + groups.append({node}); + groupSizes.append({node.width(), node.height()}); } } - } + + QList best; + for (const auto &grp : groups) { + if (grp.size() >= 12 && (best.size() < 12 || grp.size() < best.size())) + best = grp; + } + return best; + }; + + // Сначала квадратные, потом любые + QList candidates = fuzzyGroup(true); + if (candidates.size() < 12) + candidates = fuzzyGroup(false); if (candidates.size() < 12) { - qWarning() << "[findPinCodeNodes] grid not found: no group of 12+ same-sized clickable nodes"; + // Дебаг: выводим все clickable ноды и их размеры + qWarning() << "[findPinCodeNodes] grid not found. Total clickable nodes:" << allClickable.size(); + for (const Node &n : allClickable) { + qDebug() << " clickable:" << n.width() << "x" << n.height() + << "pos:" << n.x() << "," << n.y() + << "class:" << n.className + << "text:" << n.text.left(30); + } return {}; }