Избегайте переключения фокуса при использовании автоматизации пользовательского интерфейса

Просто из любопытства я решил написать простой инструмент с функциональностью, аналогичной UI Spy< /а>. По сути, он отображает дерево элементов управления и позволяет просматривать свойства каждого элемента управления. Теперь я начал реализовывать взаимодействие шаблонов и столкнулся со следующей проблемой: как только пользователь нажимает, например, «InvokePatter.Invoke» в моем приложении, автоматизация пользовательского интерфейса переключает фокус на приложение, на которое я нацеливаюсь. То же самое происходит и с другими шаблонами. Точно так же он ведет себя и в оригинальном приложении UI Spy.

Такое поведение делает невозможным управление меню с помощью моего приложения, потому что, когда я снова нажимаю на свое приложение, тестируемое приложение теряет фокус, и меню закрывается. Что я хотел бы сделать, так это взаимодействовать с приложением, используя автоматизацию пользовательского интерфейса, но сохраняя при этом свое (UI Spy) приложение. Любые идеи, как этого достичь? Или, по крайней мере, как добиться желаемой функциональности — разрешить пользователям взаимодействовать с меню?


person Snowbear    schedule 19.02.2012    source источник


Ответы (2)


UIAutomation делает это намеренно: приложения обычно ожидают получения ввода только тогда, когда они находятся в фокусе. Чтобы отправить ввод с клавиатуры, вы должны сначала сфокусировать его. Или, если вы нажмете на элемент управления, чтобы взаимодействовать с ним, он обычно получает фокус в результате щелчка, а затем выполняет действие. Есть некоторые приложения, которые очень запутываются (иногда вплоть до сбоя), если вы отправляете им ввод без предварительной отправки им фокуса.

(Эти приложения могут, например, инициализировать некоторое внутреннее состояние в WM_SETFOCUS и полагаться на то, что это состояние будет готово, когда они получат ввод. действительно быть инструментом, который отправляет «поддельные» входные данные, которые нарушают контракт здесь.)

С меню дело обстоит сложнее: во-первых, в Windows меню всегда присутствует только в приложении, которое имеет фокус. Таким образом, чтобы отобразить меню, приложение с меню должно иметь фокус, поэтому фокус должен переключиться с UISpy: это невозможно. Но реальная проблема с меню заключается не в том, что UIAutomation переключает фокус на приложение: щелчок по инструменту (UISpy) приводит к закрытию меню. Это не проблема UIAutomation — просто Win32 обрабатывает меню. Итак, реальный вопрос здесь заключается в следующем: как мне использовать инструмент для просмотра или иного управления меню, когда щелчок по инструменту закроет то самое меню, с которым я пытаюсь работать?

Есть несколько способов обойти это — оба из них Инструмент проверки объектов (inspect.exe) использует. Inspect.exe был старым MSAA-предшественником UISpy, но обновленная версия, доступная как часть SDK, теперь поддерживает как MSAA, так и UIAutomation. Следующие методы реализованы только в нескольких местах (например, SetFocus, команды навигации, но не Invoke.Invoke()), но вы можете использовать их в своем собственном инструменте по мере необходимости.

Он решает эту проблему, используя два подхода:

  • Горячие клавиши. Горячие клавиши сами по себе не изменяют фокус и не закрывают меню, поэтому используйте RegisterHotKey(), чтобы назначить горячую клавишу (например, Ctrl-Shift-X) для каждого действия, которое вы, возможно, захотите выполнить с текущим объектом. Теперь, когда целевое приложение находится в фокусе и присутствует меню, вы можете использовать комбинацию горячих клавиш, чтобы сигнализировать инструменту о выполнении соответствующего действия.

  • Креативное использование мыши: вы не можете использовать мышь, чтобы щелкнуть пользовательский интерфейс, но вы все равно можете воспользоваться положением мыши. Inspect имеет параметр «Активная панель инструментов при наведении» (в меню «Параметры»): если он выбран, если вы наведете указатель мыши на элемент панели инструментов на несколько секунд, он будет обрабатывать его так, как если бы он был нажат. Это позволяет вам перемещаться по пунктам меню, например, фактически не нажимая на какой-либо пользовательский интерфейс Inspect. Внутри, возможно, используется некоторая комбинация опроса и TB_HITTEST, чтобы выяснить, над какой кнопкой находится указатель.

Или вы можете использовать комбинацию из них: используйте горячую клавишу, чтобы вызвать команду в инструменте, над которой находится указатель мыши — в зависимости от того, что работает для вас.

person BrendanMcK    schedule 20.02.2012
comment
Спасибо, это то, чего я ожидал, хотя у меня была надежда, что есть лучший обходной путь. Мне не нравится идея этих двух обходных путей, потому что они, похоже, делают пользовательский интерфейс непригодным для использования (по крайней мере, не удобным для пользователя). Но я посмотрю на инструмент, который вы упомянули, может быть, я работаю над его удобством использования. - person Snowbear; 23.02.2012

Как насчет таймера, который запускается каждые x (милли) секунд и возвращает фокус, если фокус был потерян.

person Four_0h_Three    schedule 20.02.2012
comment
Это не поможет с меню: как только вы снова щелкнете по инструменту, меню будет закрыто, и возврат фокуса не вернет его снова. Кроме того, некоторые элементы управления выполняют определенные действия, когда они получают фокус — редактируемая комбинация выделит весь текст в ней, когда получит фокус, поэтому перемещение фокуса от него, а затем обратно будет иметь побочный эффект выделения всего текста. - person BrendanMcK; 20.02.2012