Read Windows Forms login fields and associate their labels

This commit is contained in:
Storm Dragon committed 2026-10-10 02:55:42 -04:00
1 parent d7ea005a1f
commit 25e38907d3
9 files changed
+149 -25

No files matched your search

+45 -12
View File
@@ -5,6 +5,7 @@
#include "edit_hook.h"
#include "msaa_states.h"
#include "list_view.h"
#include "control_class.h"
#include <commctrl.h>
#include <gio/gio.h>
@@ -162,12 +163,41 @@ void find_control_label(HWND window, wchar_t *text, int capacity) {
HWND previous = window;
wchar_t className[64] = {};
text[0] = L'\0';
// Managed controls need not be created in label/control order. Prefer a
// visible static label immediately to the left on the same row, among
// siblings only. Keep the existing native-control ordering below.
if (GetClassNameW(window, className, std::size(className)) &&
lstrcmpiW(className, L"Edit") != 0 && wine_access_class_matches(className, L"Edit")) {
RECT controlRect{};
if (GetWindowRect(window, &controlRect)) {
HWND label = nullptr;
LONG bestGap = 201;
HWND sibling = GetWindow(GetParent(window), GW_CHILD);
for (int hop = 0; sibling && hop < 128; ++hop, sibling = GetWindow(sibling, GW_HWNDNEXT)) {
RECT labelRect{};
if (sibling == window || !IsWindowVisible(sibling) ||
!GetClassNameW(sibling, className, std::size(className)) ||
!wine_access_class_matches(className, L"Static") || !GetWindowRect(sibling, &labelRect))
continue;
const LONG gap = controlRect.left - labelRect.right;
if (gap >= 0 && gap < bestGap && labelRect.top < controlRect.bottom &&
labelRect.bottom > controlRect.top) {
label = sibling;
bestGap = gap;
}
}
if (label && get_control_text(label, text, capacity)) {
tidy_text(text, true);
}
}
return;
}
for (int hop = 0; hop < 3; ++hop) {
previous = GetWindow(previous, GW_HWNDPREV);
if (previous == nullptr ||
!GetClassNameW(previous, className, std::size(className)))
return;
if (lstrcmpW(className, L"Static") != 0 && lstrcmpW(className, L"Button") != 0)
if (!wine_access_class_matches(className, L"Static") && !wine_access_class_matches(className, L"Button"))
continue;
if (get_control_text(previous, text, capacity))
tidy_text(text, true);
@@ -211,14 +241,14 @@ ControlDescription describe_standard_control(HWND window) {
if (!GetClassNameW(window, className, std::size(className)))
return control;
const LONG_PTR windowStyle = GetWindowLongPtrW(window, GWL_STYLE);
const bool isEdit = lstrcmpW(className, L"Edit") == 0 ||
lstrcmpW(className, L"RICHEDIT50W") == 0 ||
lstrcmpW(className, L"RichEdit20W") == 0 ||
lstrcmpW(className, L"RichEdit20A") == 0;
const bool isEdit = wine_access_class_matches(className, L"Edit") ||
wine_access_class_matches(className, L"RICHEDIT50W") ||
wine_access_class_matches(className, L"RichEdit20W") ||
wine_access_class_matches(className, L"RichEdit20A");
if (!isEdit || !(windowStyle & ES_PASSWORD))
get_control_text(window, text, std::size(text));
if (lstrcmpW(className, L"Button") == 0) {
if (wine_access_class_matches(className, L"Button")) {
control.name = to_utf8(text);
const LONG_PTR style = GetWindowLongPtrW(window, GWL_STYLE);
DWORD_PTR checked = 0;
@@ -262,8 +292,8 @@ ControlDescription describe_standard_control(HWND window) {
return control;
}
if (lstrcmpW(className, L"ComboBox") == 0 ||
lstrcmpW(className, L"ComboBoxEx32") == 0) {
if (wine_access_class_matches(className, L"ComboBox") ||
wine_access_class_matches(className, L"ComboBoxEx32")) {
find_control_label(window, label, std::size(label));
control.name = to_utf8(label);
control.role = "combo box";
@@ -287,8 +317,8 @@ ControlDescription describe_standard_control(HWND window) {
return control;
}
if (lstrcmpW(className, L"ListBox") == 0 ||
lstrcmpW(className, L"ComboLBox") == 0) {
if (wine_access_class_matches(className, L"ListBox") ||
wine_access_class_matches(className, L"ComboLBox")) {
find_control_label(window, label, std::size(label));
control.name = to_utf8(label);
control.role = "list";
@@ -320,7 +350,7 @@ ControlDescription describe_standard_control(HWND window) {
return control;
}
if (lstrcmpW(className, L"msctls_trackbar32") == 0) {
if (wine_access_class_matches(className, L"msctls_trackbar32")) {
find_control_label(window, label, std::size(label));
control.name = to_utf8(label);
control.role = "slider";
@@ -331,7 +361,7 @@ ControlDescription describe_standard_control(HWND window) {
return control;
}
if (lstrcmpW(className, L"Static") == 0) {
if (wine_access_class_matches(className, L"Static")) {
control.name = to_utf8(text);
control.role = "static text";
return control;
@@ -437,6 +467,9 @@ void present_text_event(const WineAccessTextEvent &event) {
std::string text = to_utf8(event.text);
ControlDescription control;
if (event.kind == WINE_ACCESS_TEXT_PASSWORD) {
wchar_t label[256] = {};
find_control_label(window, label, std::size(label));
control.name = to_utf8(label);
control.role = "edit";
control.description = "password";
} else if (event.kind == WINE_ACCESS_TEXT_FOCUS) {