防止应用程序窃取焦点

防止应用程序窃取焦点

有什么解决方案可以防止应用程序从活动窗口窃取焦点?

当我启动一个应用程序,切换到做其他事情并且新的应用程序开始接收半句话的文本时,这尤其烦人。

答案1

这是不可能的广泛的对 Windows 内部的操作,你需要克服它。

在日常使用计算机的过程中,有时您需要在操作系统允许您执行另一操作之前执行一项操作,这一点非常重要。为此,操作系统需要将您的注意力锁定在某些窗口上。在 Windows 中,对此行为的控制主要由您使用的各个程序的开发人员负责。

当谈到这个话题时,并不是每个开发人员都能做出正确的决定。

我知道这非常令人沮丧和恼火,但鱼与熊掌不可兼得。在您的日常生活中,可能有很多情况让您完全接受焦点被移到某个 UI 元素或应用程序要求焦点保持锁定在该元素上。但在决定谁是当前领先者时,大多数应用程序在某种程度上是平等的,而且系统永远不可能完美。

不久前,我做了大量研究,想一劳永逸地解决这个问题(但失败了)。我的研究结果可以在烦恼项目页面

该项目还包括一个应用程序,它通过调用以下命令反复尝试获取焦点:

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 调用。
最后一部分很简单,这要归功于非常棒的 AP​​I 挂接库。我使用了非常棒的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_DLL 库当时的方法(这根本不够)。

基本上,这很有效。但我从来没有时间写一些适当地将我的 DLL 注入到新进程中。而这方面投入的时间很大程度上掩盖了焦点窃取给我带来的烦恼。

除了 DLL 注入问题之外,还有一种焦点窃取方法,我在 Google Code 上的实现中没有介绍过。一位同事实际上做了一些额外的研究并介绍了该方法。该问题在 SO 上进行了讨论:https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus

答案2

在 Windows 7 中,ForegroundLockTimeout不再检查注册表项,您可以使用进程监视器来验证这一点。事实上,在 Windows 7 中,它们不允许您更改前台窗口。去阅读关于它的细节,它甚至从 Windows 2000 开始就存在了。

然而,文档很烂,他们互相追逐,想方设法解决这个问题

因此,出现了一些问题SetForegroundWindow,或者类似的API函数……

真正正确做到这一点的唯一方法是制作一个小应用程序,定期调用LockSetForegroundWindow,实际上禁用了对我们有缺陷的 API 函数的任何调用。

如果这还不够(又是一个有问题的 API 调用?),你甚至可以进一步做一些API 监控看看发生了什么,然后你就可以在每个进程上挂接 API 调用之后你就可以摆脱任何调用会弄乱前台。然而讽刺的是,微软并不鼓励这样做……

答案3

有一个选项调整用户界面它可以做到这一点。它可以防止可疑软件开发人员用来强制将焦点放在其应用程序上的大多数常见技巧。

但这是一场正在进行的军备战争,所以我不知道它是否适用于一切。

更新: 根据濒危马萨,TweakUI 在 Windows 7 上不起作用。

答案4

灵感来自Der Hochstapler 的回答因此,我决定编写一个 DLL 注入器,它可以适用于 64 位和 32 位进程,并可防止在 Windows 7 或更新版本上发生焦点窃取:https://blade.sk/stay-focused/

它的工作方式是监视新创建的窗口(使用SetWinEventHook),并将与 Der Hochstapler 的非常相似的 DLL 注入窗口进程(如果不存在)。它会卸载 DLL 并在退出时恢复原始功能。

从我的测试来看,到目前为止,它运行良好。然而,问题似乎比应用程序调用 更深层次SetForegroundWindow。例如,当创建一个新窗口时,它会自动进入前台,这也会干扰用户在另一个窗口中输入。

为了处理其他窃取焦点的方法,需要进行更多的测试,并且我很感激有关发生这种情况的场景的任何反馈。

编辑:源代码现已推出。

相关内容