Получить направление прокрутки другого окна/приложения

Я хочу определить направление прокрутки другого приложения. Я могу сделать это, если пользователь прокручивает колесико мыши или клавиатуру (клавиши вверх/вниз/влево/вправо) через крючки. Но я не могу зафиксировать то же самое, когда пользователь использует полосы прокрутки, присутствующие в таких приложениях, как Chrome.

Я пробовал ниже собственный метод, но он не работает для многих приложений, таких как Chrome, и работает для Notepad ++, так как он не может обнаруживать полосы прокрутки для Chrome. Я хочу что-то, что работает для всех приложений.

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi);

У меня есть довольно много исследований, но я не смог найти ничего, что могло бы указать мне направления, в которых прокручивается страница. Пожалуйста, дайте мне знать, если потребуется дополнительная информация.

Обновление:

Я пытаюсь использовать автоматизацию пользовательского интерфейса, чтобы получить информацию о полосе прокрутки для Chrome.

Вот как?

Я сделал коллекцию Windows Gui Rectangles, используя EnumChildWindows, которая также извлекает дочерние элементы управления. Основываясь на положении мыши, выберите дескриптор окна, прямоугольник графического интерфейса которого содержит мою позицию мыши. У дескриптора, который я получил, прямоугольник Gui = клиентская область хрома.

Проблема:

Ниже приведен код. И это дает мне пустую коллекцию в elementCollection в случае Chrome и успешно возвращает 2 элемента полосы прокрутки в случае Notepad++.

var element = AutomationElement.FromHandle(handle);
if(element != null)
{
    Condition condition = 
       new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ScrollBar);

    // Find all children that match the specified conditions.
    AutomationElementCollection elementCollection =
        element.FindAll(TreeScope.SubTree, condition);
 }

person shruti singh    schedule 14.11.2018    source источник
comment
Для чего бы вы использовали эту информацию сделать? Вы уверены, что думаете о своей проблеме на правильном уровне? Например. если это какой-то инструмент доступности, существуют способы взаимодействия с другими приложениями более высокого уровня, которые позволяют вам работать на более семантическом уровне, чем пытаться самостоятельно анализировать движения прокрутки.   -  person Damien_The_Unbeliever    schedule 14.11.2018
comment
Хочу сделать панорамный снимок для приложений. Пользователь может зайти в приложение и прокрутить, а я буду делать снимки экрана, а позже объединять все снимки экрана в одно изображение. Требование таково, что пользователь должен вручную прокручивать, и я не могу использовать SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); для имитации движения полосы прокрутки.   -  person shruti singh    schedule 14.11.2018


Ответы (1)


Что вам нужно сделать, так это вызвать метод GetScrollInfo дважды и сравнить эти значения, чтобы выяснить это; прокручивается ли элемент управления и вычислять (предыдущее ‹ текущее) направление. Вам нужно повторять этот процесс до тех пор, пока вы хотите следить за направлением прокрутки.

Теперь вы должны создать какой-то рабочий класс, чтобы хорошо справляться с проблемами. Для этого вопроса я использовал простое консольное приложение, которое опрашивает структуру SCROLLINFO дескриптора с помощью цикла while:

static void Main(string[] args)
{
    var handle = (IntPtr)0x35087C; // notepad textbox handle

    var prevInfo = default(SCROLLINFO);
    int iterations = 1000;

    while (iterations > 0)
    {
        var curInfo = new SCROLLINFO();
        curInfo.cbSize = Marshal.SizeOf(curInfo);
        curInfo.fMask = (int)ScrollInfoMask.SIF_ALL;

        if (GetScrollInfo(handle, (int)ScrollBarDirection.SB_VERT, ref curInfo))
        {
            var dir = curInfo.nPos < prevInfo.nPos ? "Up" : "Down";
            dir = curInfo.nPos == prevInfo.nPos ? "Unchanged" : dir;

            Console.WriteLine(dir);

            prevInfo = curInfo;
        }
        else
        {
            Console.WriteLine($"No scrolling.. {Marshal.GetLastWin32Error()}");
        }

        System.Threading.Thread.Sleep(100);
        iterations--;
    }

    Console.ReadLine();
}

Обратите внимание, что переменная handle содержит указатель на текстовое поле процесса блокнота (что НЕ совпадает с дескриптором процесса блокнота). Я использовал WinSpy++ для получения дескриптора из процесса блокнота.

Я использовал страницу MSDN GetScrollInfo чтобы прочитать о самом вызове API, GetScrollInfo Pinvoke.NET page, чтобы получить все необходимые структуры/перечисления.

person Jevgeni Geurtsen    schedule 14.11.2018
comment
Не могли бы вы попробовать для хрома? Ваше решение дало мне ошибку 1447 для хрома. Некоторые приложения не отвечают на GetScrollInfo и выдают ошибку 1447, которая является ERROR_NO_SCROLLBARS, также известной как Окно не имеет полос прокрутки. experts-exchange.com /вопросы/23496918/ - person shruti singh; 14.11.2018
comment
@shrutisingh Jevgeni уже проделал тяжелую работу, показав вам, как выполнить задание. Вы должны получить свои особенности самостоятельно. Даже если он сделал это с хромом, вы не получите такого же результата, потому что у каждого процесса есть свой собственный дескриптор, и у вас точно такой же дескриптор, как у Евгения, это было бы большим совпадением. Что касается того, почему метод не работает в экземпляре Chrome, очевидным ответом будет то, что у вас неправильный экземпляр. Я предполагаю, что вы проверяете основной экземпляр Chrome вместо средства визуализации, что, вероятно, и происходит. - person Maverik; 14.11.2018
comment
@Maverik Моя проблема в том, что эта логика не работает для всех дочерних дескрипторов. Я знаю, что это работает для Блокнота, поскольку я уже пробовал это. В случае хрома я заменил дескриптор дочерним дескриптором хрома, и он не может получить информацию о прокрутке. И я получаю дочерний дескриптор через EnumChildWindows, что правильно, поскольку я могу имитировать SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam), используя тот же дескриптор. - person shruti singh; 14.11.2018
comment
Вы должны были добавить, что вы нацелены на хром, это важная информация, которая отсутствует в вашем основном посте. Chrome использует рендеринг D3D (DirectX 3D), который сильно отличается от простого элемента управления, такого как текстовое поле блокнота. Зная это, я сомневаюсь, что вы сможете использовать GetScrollInfo API. Вам нужно подключить хром и узнать, где они хранят информацию о прокрутке в памяти, и работать оттуда. - person Jevgeni Geurtsen; 14.11.2018
comment
@mav: Все это звучит убедительно, за исключением того, что это неправильно. Chrome не использует собственные окна ни для чего (кроме окна фрейма и хоста рендеринга). Однако все, что вы видите, сделано с использованием пользовательских реализаций виджетов. Полосы прокрутки могут выглядеть как собственные полосы прокрутки, но они не являются ни одним из два типа полос прокрутки. Таким образом, они не будут отвечать на сообщения или обычный оконный API. Здесь вам нужно найти другое решение, например. Автоматизация пользовательского интерфейса. - person IInspectable; 14.11.2018
comment
@JevgeniGeurtsen Мне нужно решение, которое работает для всех приложений, которые могут иметь полосы прокрутки. Будь то блокнот, хром или IE. Snagit делает то же самое для панорамных снимков. Я не уверен, как он это делает, но я пытаюсь добиться того же. - person shruti singh; 14.11.2018
comment
@IInspectable Не могли бы вы предложить несколько ссылок для автоматизации пользовательского интерфейса с учетом моего требования? - person shruti singh; 14.11.2018
comment
@shr: Специальные возможности. - person IInspectable; 14.11.2018
comment
@IInspectable: с помощью автоматизации пользовательского интерфейса я также могу получить горизонтальные и вертикальные полосы прокрутки только в Notepad ++, а не в Chrome. Не могли бы вы попробовать мой код для этих двух отдельных приложений с соответствующим дескриптором и сообщить мне, где я ошибаюсь? - person shruti singh; 15.11.2018
comment
@shrutisingh Вы уверены, что упомянутое вами приложение использует эту технику? Если речь идет исключительно о записи экрана, то они, вероятно, будут использовать WinAPI, например SendKeys, поэтому прокручивайте страницу. Я сомневаюсь, что они на самом деле будут читать полосы прокрутки - они, вероятно, просто проверят разница между фреймами, и если после вызова SendKeys ничего не изменилось, они знают, что находятся в конце (или начале) страницы. - person Jevgeni Geurtsen; 15.11.2018
comment
@JevgeniGeurtsen: я не уверен, что именно они делают. Это не совсем запись экрана, на самом деле он делает несколько снимков экрана во время прокрутки страницы и объединяет их все в одно изображение. например: hub.mangoapps.com/sf/MTUzMjMwXzE2NDYxMTA - person shruti singh; 17.11.2018
comment
Я понимаю, так зачем вам нужно читать информацию полосы прокрутки, чтобы сделать это? Как было сказано ранее; можно просто сделать несколько скриншотов во время прокрутки (SendKeys) и использовать какую-то дельта-обработку, чтобы узнать, где заканчивается страница (== никаких изменений на последовательных скриншотах = конец страницы). Я думаю, что вы переоцениваете/думаете о проблеме. - person Jevgeni Geurtsen; 20.11.2018