1
0
forked from BRT/arc

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.
This commit is contained in:
slava 2026-03-21 18:14:05 +07:00
parent 712b73316c
commit cefad834c7

View File

@ -398,12 +398,14 @@ QString ScreenXmlParser::parseProfilePhone() {
QList<Node> ScreenXmlParser::findPinCodeNodes(const QString &pinCode) { QList<Node> ScreenXmlParser::findPinCodeNodes(const QString &pinCode) {
// Способ 1: ищем кликабельные ноды с текстом-цифрой (0-9) // Способ 1: ищем кликабельные ноды с текстом-цифрой (0-9)
// Поддерживаем форматы: "1", "key 1", и т.п.
QMap<QString, Node> digitMap; QMap<QString, Node> digitMap;
static const QRegularExpression digitRx(R"(^(?:key\s+)?(\d)$)", QRegularExpression::CaseInsensitiveOption);
for (const Node &node : m_nodes) { for (const Node &node : m_nodes) {
if (!node.clickable || node.width() <= 0 || node.height() <= 0) continue; if (!node.clickable || node.width() <= 0 || node.height() <= 0) continue;
const QString t = node.text.trimmed(); const QString t = node.text.trimmed();
if (t.size() == 1 && t.at(0).isDigit()) { if (const auto match = digitRx.match(t); match.hasMatch()) {
digitMap[t] = node; digitMap[match.captured(1)] = node;
} }
} }
@ -421,42 +423,62 @@ QList<Node> ScreenXmlParser::findPinCodeNodes(const QString &pinCode) {
return result; return result;
} }
// Способ 2 (fallback): группируем clickable-ноды одинакового размера, // Способ 2 (fallback): группируем clickable-ноды похожего размера,
// ищем сетку 4x3 по паттерну (не привязываясь к координатам экрана) // ищем сетку 4x3 по паттерну (не привязываясь к координатам экрана)
QMap<QPair<int,int>, QList<Node>> sizeGroups; constexpr int SIZE_TOLERANCE = 10; // допуск в пикселях
// Собираем все clickable ноды с положительным размером
QList<Node> allClickable;
for (const Node &node : m_nodes) { for (const Node &node : m_nodes) {
if (!node.clickable || node.width() <= 0 || node.height() <= 0) continue; if (!node.clickable || node.width() <= 0 || node.height() <= 0) continue;
if (node.width() == node.height()) { // кнопки пин-пада квадратные allClickable.append(node);
sizeGroups[{node.width(), node.height()}].append(node);
}
} }
// Ищем группу из >= 12 одинаковых кнопок (пин-пад: 3x4 = 12) // Группируем с допуском: для каждой ноды проверяем, подходит ли она к существующей группе
QList<Node> candidates; auto fuzzyGroup = [&](bool squareOnly) -> QList<Node> {
for (auto it = sizeGroups.begin(); it != sizeGroups.end(); ++it) { QList<QList<Node>> groups;
if (it.value().size() >= 12 && QList<QPair<int,int>> groupSizes; // эталонный размер каждой группы
(candidates.isEmpty() || it.value().size() < candidates.size())) {
candidates = it.value();
}
}
if (candidates.size() < 12) { for (const Node &node : allClickable) {
// Попробуем без ограничения на квадрат, но с >= 12 if (squareOnly && std::abs(node.width() - node.height()) > SIZE_TOLERANCE)
sizeGroups.clear(); continue;
for (const Node &node : m_nodes) { bool placed = false;
if (!node.clickable || node.width() <= 0 || node.height() <= 0) continue; for (int g = 0; g < groups.size(); ++g) {
sizeGroups[{node.width(), node.height()}].append(node); if (std::abs(node.width() - groupSizes[g].first) <= SIZE_TOLERANCE &&
} std::abs(node.height() - groupSizes[g].second) <= SIZE_TOLERANCE) {
for (auto it = sizeGroups.begin(); it != sizeGroups.end(); ++it) { groups[g].append(node);
if (it.value().size() >= 12 && placed = true;
(candidates.size() < 12 || it.value().size() < candidates.size())) { break;
candidates = it.value(); }
}
if (!placed) {
groups.append({node});
groupSizes.append({node.width(), node.height()});
} }
} }
}
QList<Node> best;
for (const auto &grp : groups) {
if (grp.size() >= 12 && (best.size() < 12 || grp.size() < best.size()))
best = grp;
}
return best;
};
// Сначала квадратные, потом любые
QList<Node> candidates = fuzzyGroup(true);
if (candidates.size() < 12)
candidates = fuzzyGroup(false);
if (candidates.size() < 12) { 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 {}; return {};
} }