Python 如何关注应用程序';当任务管理器';s窗口聚焦了吗?

Python 如何关注应用程序';当任务管理器';s窗口聚焦了吗?,python,winapi,focus,foreground,Python,Winapi,Focus,Foreground,我有一个Python脚本,它创建了一个应用程序的实例,并显示了应用程序的窗口 我正在尝试激活/聚焦窗口,使其位于前台/顶部,并具有键盘输入焦点 def bring_window_to_top(window_handle): import ctypes # import win32com.client # from win32con import HWND_TOP, HWND_TOPMOST, SWP_NOMOVE, SWP_NOSIZE current_thread_id =

我有一个Python脚本,它创建了一个应用程序的实例,并显示了应用程序的窗口

我正在尝试激活/聚焦窗口,使其位于前台/顶部,并具有键盘输入焦点

def bring_window_to_top(window_handle):
  import ctypes
  # import win32com.client
  # from win32con import HWND_TOP, HWND_TOPMOST, SWP_NOMOVE, SWP_NOSIZE

  current_thread_id = ctypes.windll.kernel32.GetCurrentThreadId()
  foreground_window_handle = ctypes.windll.user32.GetForegroundWindow()
  foreground_thread_id = ctypes.windll.user32.GetWindowThreadProcessId(foreground_window_handle, None)
  ctypes.windll.user32.AttachThreadInput(current_thread_id, foreground_thread_id, True)
  ctypes.windll.user32.BringWindowToTop(window_handle)
  # ctypes.windll.user32.SwitchToThisWindow(window_handle, True)
  # ctypes.windll.user32.SwitchToThisWindow(window_handle, False)
  # ctypes.windll.user32.SetWindowPos(window_handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
  # ctypes.windll.user32.SetWindowPos(window_handle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
  # wscript_shell = win32com.client.Dispatch('WScript.Shell')
  # wscript_shell.SendKeys('%')
  # ctypes.windll.user32.SetForegroundWindow(window_handle)
  # ctypes.windll.user32.SetFocus(window_handle)
  # ctypes.windll.user32.SetActiveWindow(window_handle)
  # ctypes.windll.user32.AttachThreadInput(current_thread_id, foreground_thread_id, False)
下面的代码通常可以工作,但是当任务管理器的窗口在代码执行之前打开并聚焦时,应用程序的窗口会显示在任务管理器的下面,任务管理器会保持键盘输入的焦点

def bring_window_to_top(window_handle):
  import ctypes
  # import win32com.client
  # from win32con import HWND_TOP, HWND_TOPMOST, SWP_NOMOVE, SWP_NOSIZE

  current_thread_id = ctypes.windll.kernel32.GetCurrentThreadId()
  foreground_window_handle = ctypes.windll.user32.GetForegroundWindow()
  foreground_thread_id = ctypes.windll.user32.GetWindowThreadProcessId(foreground_window_handle, None)
  ctypes.windll.user32.AttachThreadInput(current_thread_id, foreground_thread_id, True)
  ctypes.windll.user32.BringWindowToTop(window_handle)
  # ctypes.windll.user32.SwitchToThisWindow(window_handle, True)
  # ctypes.windll.user32.SwitchToThisWindow(window_handle, False)
  # ctypes.windll.user32.SetWindowPos(window_handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
  # ctypes.windll.user32.SetWindowPos(window_handle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
  # wscript_shell = win32com.client.Dispatch('WScript.Shell')
  # wscript_shell.SendKeys('%')
  # ctypes.windll.user32.SetForegroundWindow(window_handle)
  # ctypes.windll.user32.SetFocus(window_handle)
  # ctypes.windll.user32.SetActiveWindow(window_handle)
  # ctypes.windll.user32.AttachThreadInput(current_thread_id, foreground_thread_id, False)
代码中的注释是我试图绕过特定问题的尝试,但也没有奏效。只有在将
切换到此窗口
False
SetWindowPos
HWND\u TOPMOST
(将窗口设置为最顶部)一起使用时,该窗口才会显示在任务管理器窗口的顶部,但任务管理器仍保持键盘输入焦点

def bring_window_to_top(window_handle):
  import ctypes
  # import win32com.client
  # from win32con import HWND_TOP, HWND_TOPMOST, SWP_NOMOVE, SWP_NOSIZE

  current_thread_id = ctypes.windll.kernel32.GetCurrentThreadId()
  foreground_window_handle = ctypes.windll.user32.GetForegroundWindow()
  foreground_thread_id = ctypes.windll.user32.GetWindowThreadProcessId(foreground_window_handle, None)
  ctypes.windll.user32.AttachThreadInput(current_thread_id, foreground_thread_id, True)
  ctypes.windll.user32.BringWindowToTop(window_handle)
  # ctypes.windll.user32.SwitchToThisWindow(window_handle, True)
  # ctypes.windll.user32.SwitchToThisWindow(window_handle, False)
  # ctypes.windll.user32.SetWindowPos(window_handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
  # ctypes.windll.user32.SetWindowPos(window_handle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE)
  # wscript_shell = win32com.client.Dispatch('WScript.Shell')
  # wscript_shell.SendKeys('%')
  # ctypes.windll.user32.SetForegroundWindow(window_handle)
  # ctypes.windll.user32.SetFocus(window_handle)
  # ctypes.windll.user32.SetActiveWindow(window_handle)
  # ctypes.windll.user32.AttachThreadInput(current_thread_id, foreground_thread_id, False)
我还尝试使用函数
AllowSetForeGroundIndow
LockSetForeGroundIndow
SystemParametersInfoW
SPI\u SETFOREGROUNDLOCKTIMEOUT
设置为
0
,但我收到的错误是
访问被拒绝。


有什么方法可以实现吗?

您需要在清单中将UIAccess设置为true以支持可访问性功能

使用UIAccess权限启动的进程具有以下特性 能力:

  • 设置前景窗口。
  • 使用SendInput功能驱动任何应用程序窗口
  • 通过使用低级钩子、原始输入、GetKeyState、GetAsyncKeyState和GetKeyboardInput,对所有完整性级别使用读取输入
  • 设置日志挂钩
  • 使用
    AttachThreadInput
    将线程附加到更高完整性的输入队列。
首先,在清单中设置
uiAccess=true

然后,在代码上签名

最后,将其放在文件系统上的安全位置:

  • \程序文件\包括子目录
  • \Windows\system32\
  • \程序文件(x86)\n包括64位版本的 窗户
你可以参考和

更新:

要设置对python脚本的UIAccess,请执行以下操作:

  • 安装PyInstaller:
    pip安装PyInstaller
  • 使用Pyinstaller从Python脚本生成可执行文件
  • 这是我的测试示例,它设置了一个5秒的计时器,使窗口处于顶部

    hello.pyw:

    import win32api, win32con, win32gui
    import ctypes
    class MyWindow:
            
        def __init__(self):
            win32gui.InitCommonControls()
            self.hinst = win32api.GetModuleHandle(None)
            className = 'MyWndClass'
            message_map = {
                win32con.WM_DESTROY: self.OnDestroy,
                win32con.WM_TIMER: self.OnTimer,
            }
            wndcls = win32gui.WNDCLASS()
            wndcls.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW
            wndcls.lpfnWndProc = message_map
            wndcls.lpszClassName = className
            win32gui.RegisterClass(wndcls)
            style = win32con.WS_OVERLAPPEDWINDOW
            self.hwnd = win32gui.CreateWindow(
                className,
                'Title',
                style,
                win32con.CW_USEDEFAULT,
                win32con.CW_USEDEFAULT,
                500,
                500,
                0,
                0,
                self.hinst,
                None
            )
            win32gui.UpdateWindow(self.hwnd)
            win32gui.ShowWindow(self.hwnd, win32con.SW_SHOW)
            ctypes.windll.user32.SetTimer(self.hwnd,1,5000,0)
        def OnDestroy(self, hwnd, message, wparam, lparam):
            win32gui.PostQuitMessage(0)
            return True
        def OnTimer(self, hwnd, message, wparam, lparam):
            current_thread_id = ctypes.windll.kernel32.GetCurrentThreadId()
            foreground_window_handle = ctypes.windll.user32.GetForegroundWindow()
            foreground_thread_id = ctypes.windll.user32.GetWindowThreadProcessId(foreground_window_handle, None)
            ctypes.windll.user32.BringWindowToTop(hwnd)
            return True
    
    w = MyWindow()
    win32gui.PumpMessages()
    
    使用
    --manifest
    选项或直接使用
    pyinstaller--uac uiaccess hello.pyw
    ,则exe文件位于
    dist\\hello

  • 创建证书并对应用程序进行签名,示例(不要忘记将证书安装到受信任的根证书颁发机构):
  • 将其放在文件系统上的安全位置,例如,我将
    dist\\hello
    放在
    C:\\Program Files
  • 结果:

    需要。