Мне нужно смоделировать ввод, почему HtmlElement.Focus не работает? - PullRequest
0 голосов
/ 27 марта 2019

Я пытаюсь написать веб-бота, который должен быть незамеченным, поэтому я не использую свойство InnerText и вместо этого пытаюсь имитировать нажатия клавиш.Для этого мне нужно сфокусировать элемент <input>, но фокус переключается на другое текстовое поле, а не сразу, даже после вызова element.Focus().

Я пробовал также использовать element.InvokeMember("click");, но это не работаетлибо.

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
    }

    [DllImport("User32.dll")]
    public static extern int SendMessage(IntPtr hWnd, int uMsg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

    public const Int32 WM_CHAR = 0x0102;
    public const Int32 WM_KEYDOWN = 0x0100;
    public const Int32 WM_KEYUP = 0x0101;
    public const Int32 VK_RETURN = 0x0D;

    IntPtr BrowserHandle
    {
        get
        {
            var hwnd = _browser.Handle;
            hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell Embedding", null);
            hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell DocObject View", null);
            hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", null);
            return hwnd;
        }
    }

    readonly Random _rnd = new Random();

    private void Form1_Load(object sender, EventArgs e)
    {
        _browser.Navigate("https://...");
        _browser.DocumentCompleted += _browser_DocumentCompleted;
    }

    private async void _browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        if (e.Url.AbsoluteUri != "https://...") return;
        var inputs = _browser.Document.GetElementsByTagName("input");
        {
            var el = inputs.OfType<HtmlElement>().FirstOrDefault(x => x.GetAttribute("className").Contains("login"));
            await SendTextAsync(el, "sdfoj30jfoigjdlsgfdgd");
        }
    }

    async Task SendTextAsync(HtmlElement element, string text)
    {
        for (var i = 0; i < text.Length; i++, await Task.Delay(_rnd.Next(0, 500)))
        {
            if (_browser.Document.ActiveElement != element)
            {
                element.Focus(); // doesn't work
                if (_browser.Document.ActiveElement != element)
                {
                    element.InvokeMember("click"); // either
                    if (_browser.Document.ActiveElement != element)
                    {
                        element.Focus();
                        await Task.Delay(_rnd.Next(50, 250)); // anyway
                    }
                }
            }

            var c = text[i];
            SendCharacter(c, BrowserHandle);
        }
    }

    static void SendCharacter(char character, IntPtr hWnd)
    {
        var key = new IntPtr(character);
        SendMessage(hWnd, WM_KEYDOWN, key, IntPtr.Zero);
        SendMessage(hWnd, WM_CHAR, key, IntPtr.Zero);
        SendMessage(hWnd, WM_KEYUP, key, IntPtr.Zero);
    }
}

Я ожидал, что этот код заполнит текстовое поле для входа в систему, но вместо этого он записывает туда несколько символов, а другие переходят в текстовое поле для пароля.

1 Ответ

0 голосов
/ 27 марта 2019

Решение состоит в том, чтобы искать элемент с GetElementsByTagName каждый раз вместо повторного использования ссылки.

...