Вопрос Предотвращение кражи фокуса приложений


Существуют ли какие-либо решения для предотвращения кражи фокуса приложений из активного окна?

Это особенно раздражает, когда я запускаю приложение, переключаюсь на выполнение чего-то еще, и новое приложение начинает получать половину предложения текста.


174
2017-08-05 08:48


происхождения


@Ivo Windows 7 в моем случае, но я думаю, что для SuperUser все версии окон будут актуальны - svandragt
Модератор объединил этот вопрос: superuser.com/questions/199821/... с текущим. Это неправильно, ответ на текущий вопрос не относится к окнам 7, поэтому он не должен быть объединен. До сих пор я не мог найти решение этой проблемы в Windows 7 - Alex Angelico
Это один из моих любимых питомцев номер один с каждым графическим интерфейсом, который я когда-либо использовал. Вы печатаете и обманываете, какое-то диалоговое окно с записями крадет фокус, а половина ваших нажатий - куда-то еще. Вы могли бы подумать, что разработчики оконных систем могли бы это выяснить десятилетиями назад. Если в окне есть активность, задержка экспозиции в новом окне. Например. ничего не набирайте в графическом интерфейсе до трех или четырех секунд с момента последнего нажатия кнопки или нажатия клавиши в текущем сфокусированном окне. Doh! - Kaz
я обнаружил, что когда у меня есть мой внешний жесткий диск (сделанный Seagate) или мой ipod nano (ахм, яблоко), подключенный к моей машине с Windows 7, похоже, что «рабочий стол» будет красть фокус каждые 30 секунд или около того, из того, что когда-либо я просматривал, будь то музыка itunes, результаты поиска Chrome или электронные письма firefox. Я отключил функцию автовоспроизведения, и это помогло некоторое время, но проблема вернулась даже после отключения автовоспроизведения. Наверное, мне приходится отключать внешний HD и флеш-диски по большей части, что отстой, потому что вся моя музыка :( Это очень раздражающая ошибка, которая заставляет меня хотеть S
This is especially annoying when I'm starting an application, switch to do something else and the new application starts receiving half a sentence of text.Это еще более раздражает, когда появляется диалоговое окно, и вы непреднамеренно отклоняете его, даже не видя сообщение, потому что вам пришлось нажать Space или Enter при вводе предложения. - Synetech


ответы:


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

Проект также включает приложение, которое неоднократно пытается захватить фокус, вызывая:

switch( message ) {
  case WM_TIMER:
    if( hWnd != NULL ) {
      // Start off easy
      // SetForegroundWindow will not move the window to the foreground,
      // but it will invoke FlashWindow internally and, thus, show the
      // taskbar.
      SetForegroundWindow( hWnd );

      // Our application is awesome! It must have your focus!
      SetActiveWindow( hWnd );

      // Flash that button!
      FlashWindow( hWnd, TRUE );
    }
    break;

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

Способ, которым я пытался решить это, - загрузить DLL в каждый новый процесс и подключить вызовы API, которые заставляют активировать другие окна.
Последняя часть - легкая, благодаря удивительным API-интерфейсам для подбора API. Я использовал очень Библиотека mhook:

#include "stdafx.h"
#include "mhook-2.2/mhook-lib/mhook.h"

typedef NTSTATUS( WINAPI* PNT_QUERY_SYSTEM_INFORMATION ) ( 
  __in       SYSTEM_INFORMATION_CLASS SystemInformationClass,     
  __inout    PVOID SystemInformation, 
  __in       ULONG SystemInformationLength, 
  __out_opt  PULONG ReturnLength    
);

// Originals
PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindow   = 
  (PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress( 
  ::GetModuleHandle( L"user32" ), "FlashWindow" );

PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindowEx = 
  (PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress( 
  ::GetModuleHandle( L"user32" ), "FlashWindowEx" );

PNT_QUERY_SYSTEM_INFORMATION OriginalSetForegroundWindow = 
  (PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress( 
  ::GetModuleHandle( L"user32" ), "SetForegroundWindow" );

// Hooks
BOOL WINAPI
HookedFlashWindow(
  __in  HWND hWnd,
  __in  BOOL bInvert
  ) {
  return 0;
}

BOOL WINAPI 
HookedFlashWindowEx(
  __in  PFLASHWINFO pfwi
  ) {
  return 0;
}

BOOL WINAPI 
HookedSetForegroundWindow(
  __in  HWND hWnd
  ) {
  // Pretend window was brought to foreground
  return 1;
}


BOOL APIENTRY 
DllMain( 
  HMODULE hModule,
  DWORD   ul_reason_for_call,
  LPVOID  lpReserved
  ) {
  switch( ul_reason_for_call ) {
    case DLL_PROCESS_ATTACH:
      Mhook_SetHook( (PVOID*)&OriginalFlashWindow,         HookedFlashWindow );
      Mhook_SetHook( (PVOID*)&OriginalFlashWindowEx,       HookedFlashWindowEx );
      Mhook_SetHook( (PVOID*)&OriginalSetForegroundWindow, HookedSetForegroundWindow );
      break;

    case DLL_PROCESS_DETACH:
      Mhook_Unhook( (PVOID*)&OriginalFlashWindow );
      Mhook_Unhook( (PVOID*)&OriginalFlashWindowEx );
      Mhook_Unhook( (PVOID*)&OriginalSetForegroundWindow );
      break;
  }
  return TRUE;
}

Из моих тестов тогда это отлично работало. За исключением части загрузки DLL в каждый новый процесс. Как можно себе представить, это не слишком легко. Я использовал AppInit_DLLs подход тогда (чего просто недостаточно).

В принципе, это отлично работает. Но я не нашел времени написать что-то, что должным образом внедряет мою DLL в новые процессы. И время, затраченное на это, в значительной степени затмевает раздражение, которое вызывает кража фокуса.

В дополнение к проблеме инъекции DLL существует также метод фокус-кражи, который я не рассматривал в реализации в Google Code. Сотрудник действительно провел некоторые дополнительные исследования и рассмотрел этот метод. Проблема обсуждалась на SO: https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus


45
2018-03-24 09:56



Считаете ли вы, что это решение может быть перенесено на Java? Я искал и задавал вопросы, но ничего не нашел. Возможно, я мог бы импортировать библиотеку hook в java, используя jne? - Tomáš Zato
@ TomášZato: Не знаю. Я сам не активно использую этот код. - Der Hochstapler
Я пытаюсь скомпилировать его как минимум C ++ (а затем вставлять / удалять скомпилированную DLL из Java). Но это тоже не слишком хорошо. Я не хочу обсуждать это здесь в комментариях, но если бы вы могли помочь мне с его работой, я был бы очень изящным! Я создал чат-комнату, если я получу это для работы, я отправлю комментарий, как это сделать здесь: chat.stackexchange.com/rooms/21637/... - Tomáš Zato


В Windows 7 ForegroundLockTimeout запись реестра больше не проверяется, вы можете проверить это с помощью Process Monitor. Фактически, в Windows 7 они запрещают вам изменять окно переднего плана. Идите и прочитайте о его деталях, он даже был там с Windows 2000.

Однако, документация засасывает, и они преследуют друг друга и находят пути вокруг этого,

Итак, есть что-то нехорошее, что происходит с SetForegroundWindow, или аналогичные функции API ...

Единственный способ сделать это правильно - сделать небольшое приложение, которое периодически вызывает LockSetForegroundWindow, практически отключая любые вызовы функции нашего багги-API.

Если этого недостаточно (другой вызов с ошибкой API), вы можете пойти еще дальше и сделать некоторые Контроль API посмотреть, что происходит, а потом просто перехватывать вызовы API для каждого процесса после чего вы можете избавиться от Любые звонки, которые испортили передний план. Однако, по иронии судьбы, это не поощряет Microsoft ...


22
2018-03-22 09:52



Кто-нибудь имеет воспроизводимый вариант использования этого в Windows 7? Учитывая, что люди скорее переживают обратное (например, я часто нахожу, что требуемые окна скрываются за моим текущим окном), и что я еще не видел этого в Windows 7, было бы очень неприятно писать приложение, но было бы невозможно Попробуй это. Более того, поскольку Microsoft заявляет, что этого больше не должно быть с Windows 7. В лучшем случае люди обнаружили, что он может случайно переключить фокус клавиатуры, этот вызов API будет исправлять это, но я не знаю, как проверить, действительно ли он работает. , - Tom Wijsman
Установщик (основанный на InnoSetup) запускает другие процессы и возможные другие (скрытые) настройки, но я не знаю, на каких установщиках они основаны. - Daniel Beck♦
@TomWijsman: Откройте regedit, найдите какой-то случайный текст, который не будет найден. Зайдите в другое приложение и начните вводить текст. Когда поиск будет завершен, regedit украдет фокус. - endolith
@endolith: Не воспроизводится, но при использовании Windows 8 Replase Preview. Какую ОС вы используете? В моем случае это просто подчеркивает приложение внизу, но не прерывает мой просмотр вообще ... - Tom Wijsman
Да, Win7 Pro 64-бит. И фокус-кража еще хуже для повышенных процессов, так как они захватывают ваше нажатие <Enter>, когда они этого не делают, и вы говорите ему, чтобы случайно направить вашу систему. Ничто не должно Когда-либо быть в состоянии украсть фокус. - endolith


В TweakUI который делает это. Это предотвращает большинство обычных трюков, которые сомнительные разработчики программного обеспечения используют, чтобы заставить сосредоточиться на своем приложении.

Это продолжающаяся война с оружием, хотя я не знаю, работает ли она на все.

Обновить: В соответствии с EndangeredMassa, TweakUI не работает в Windows 7.


18
2017-08-05 09:12



совместима с Windows 7? - frankster
@frankster. Не знаю, извините, я подозреваю, что это, вероятно, нет. Скачайте его и попробуйте. Сообщите, если вы это сделаете, все знают. - Simon P Stevens
Даже с использованием параметра реестра, установленного TweakUI, не работает на Win7. - EndangeredMassa
@EndangeredMassa, какой раздел реестра? - n611x007
Ключ реестра - HKEY_CURRENT_USER \ Панель управления \ Рабочий стол \ ForegroundLockTimeout (в миллисекундах). И да, он больше не работает в Windows 7. - foo


Я считаю, что может возникнуть какая-то путаница, поскольку есть два способа «кражи фокуса»: (1) окно, выходящее на передний план, и (2) окно, получающее нажатия клавиш.

Проблема, о которой идет речь здесь, вероятно, вторая, где окна требуют сосредоточиться, выйдя на передний план - без запроса пользователя или разрешения.

Обсуждение должно быть разделено между XP и 7.

Windows XP

В XP есть хак реестра, который делает XP работать так же, как Windows 7, в предотвращении кражи фокуса приложений:

  1. Используйте regedit, чтобы перейти к: HKEY_CURRENT_USER\Control Panel\Desktop,
  2. Дважды щелкните ForegroundLockTimeout и установите его значение в шестнадцатеричном виде 30d40,
  3. Нажмите OK и выйдите из режима regedit.
  4. Перезагрузите компьютер, чтобы изменения вступили в силу.

Windows 7

(Обсуждение ниже в основном относится и к XP.)

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

В Windows 7 существует только одна модификация поведения самой Windows, которая использовать MS-Windows с фокусом-мышью, где фокус и / или активация всегда идут к окнам под курсором. Задержка может быть добавлена, чтобы избежать появления всплывающих окон на рабочем столе.
См. Эту статью: Windows 7 - Mouse Hover делает окно активным - разрешено,

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

Вы можете использовать скрипт VBS включен в Код VB, который идентифицирует, кто ворует фокус, который автор использовал для идентификации преступник как «домашний вызов» для программного обеспечения принтера.

Отчаянная мера, когда все остальное терпит неудачу, и если вы определили это плохо запрограммированное приложение, состоит в том, чтобы свести его к минимуму и надеяться, что это не приведет к фронту. Более сильная форма минимизации заключается в использовании лотка с использованием одного из бесплатных продуктов, перечисленных в Лучший бесплатный мини-приложение,

Последняя идея в порядке отчаяния состоит в том, чтобы разрушить ваш рабочий стол практически с помощью продукта такие как Настольные компьютеры или Dexpot, и выполняйте свою работу на другом рабочем столе, чем по умолчанию.

[РЕДАКТИРОВАТЬ]

Когда Microsoft ушла в отставку в галерее архивов, вот приведенный выше код VB:

Declare Auto Function GetForegroundWindow Lib "user32.dll" () As Integer
Declare Auto Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As Integer, ByRef procid As Integer) As UInteger

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.RichTextBox1.AppendText("Starting up at " & Now & vbCrLf)
    End Sub

    Private Sub GoingAway(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Deactivate, Me.LostFocus

        Dim hwnd As Integer = GetForegroundWindow()
        ' Note that process_id will be used as a ByRef argument
        ' and will be changed by GetWindowThreadProcessId
        Dim process_id As Integer = 1
        GetWindowThreadProcessId(hwnd, process_id)

        If (process_id <> 1) Then
            Dim appExePath As String = Process.GetProcessById(process_id).MainModule.FileName() 
            Me.RichTextBox1.AppendText("Lost focus at " & Now & " due to " & appExePath & vbCrLf)
        Else
            Me.RichTextBox1.AppendText("Lost focus due to unknown cause.")
        End If

    End Sub

14
2018-06-09 09:22



«если это окно заблокировано, вы никогда не поймете, почему копия никогда не заканчивается». Это неверно. Правильное поведение заключается в том, чтобы уведомить пользователя с мигающим значком панели задач (или, возможно, всплывающим окном всплывающего окна или уведомлением тостера). Прерывание пользователя с окном, которое перехватывает их нажатия клавиш, означает, что они сообщают антивирусному программному обеспечению, чтобы оно выполняло одно действие или другое случайным образом. Определенно, это не хороший способ сделать что-то. - endolith
«если это окно заблокировано, вы никогда не поймете, почему копия никогда не заканчивается». Это неверно. Правильное поведение заключается в том, чтобы уведомить пользователя с мигающим значком панели задач ...   Были времена, когда я нажал кнопку или что-то в запущенной программе, которая вызывает создание нового модального диалога (например, открыть файл), но затем я переключусь на другую программу перед созданием диалога. В результате диалог скрыт, а другую программу нельзя переключить, и диалог не может быть отклонен. Ни кнопка панели задач, ни Alt-Tab работает; только форсируя диалог вперед. - Synetech
@Synetech: Иногда единственным решением для диалога без переднего плана является уничтожение задачи. Алгоритмы фокуса в Windows действительно паршивые. - harrymc
@harrymc, мне никогда не придется прибегать к убийству одного из приложений. Я просто запускаю свою программу управления окнами (WinSpy ++ делает трюк просто великолепно) и спрятать окно впереди, затем я могу отклонить диалог застрявшего назад, а затем снова показать скрытое окно. Это не удобно, но это лучше, чем убивать любой из процессов. - Synetech
@harrymc, не совсем; убить приложение и потерять вещи просто делает больше пара, и если это модальный диалог (который блокирует родительское окно и не имеет кнопки на панели задач), то он не будет отображаться в Alt+Tab список, и, по моему опыту, окно с открытым модальным диалогом не всегда (никогда?) показывает модальное диалоговое окно с Alt+Tab, особенно если в диалоге никогда не было изменений, чтобы получить фокус. :-| - Synetech


У Гаков есть возможное решение:

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

Проректор сайт имеет подсказку   как предотвратить это.   Самый простой способ предотвращения фокуса   воровство заключается в использовании пользовательского интерфейса Tweak   параметр, который называется «Предотвратить   приложений от кражи фокуса ".   Проверка этого параметра предотвращает   другие приложения всплывают внезапно и   украсть фокус окна, в котором вы находитесь   в настоящее время работает.

Это работает только тогда, когда приложение   ранее была сведена к минимуму. Вместо   кража фокуса, он будет мигать   количество раз, которое можно определить   в том же меню в Пользовательский интерфейс Tweak, если ты   не хотите использовать пользовательский интерфейс Tweak, вы можете   изменить настройку в Windows   Реестр.

Перейдите к ключу реестра   HKEY_CURRENT_USER> Панель управления>   Рабочий стол и изменить   Значение ForegroundLockTimeout до 30d40   (Шестнадцатеричный) или 200000 (десятичный).   ключ ForeGroundFlashCount определяет   количество вспышек окна для предупреждения   пользователь, где 0 означает неограниченный.


2
2017-08-05 09:13



Это не работает ни на одной ОС после XP. Это значение реестра уже установлено на это (по умолчанию, я считаю) и не работает в любом случае. - EndangeredMassa
Прежде всего, я нахожусь в Windows 7 (64-разрядная версия), испытывая фокус-кражу (VS 2012, когда наконец-то активен, пример f'r), и вышеупомянутое предложение реестра уже на месте. Техническое подтверждение в этом ответе: superuser.com/a/403554/972 - Michael Paulukonis