我如何使用Python编程在Windows中自动激活窗口?我正在向其发送按键,并且目前我只是确保它是上次使用的应用程序,然后发送Alt+Tab按键来从DOS控制台切换到它。有更好的方法吗(因为我根据经验已经知道这种方法绝不是万无一失的)?
import win32gui
import re
class WindowMgr:
"""Encapsulates some calls to the winapi for window management"""
def __init__ (self):
"""Constructor"""
self._handle = None
def find_window(self, class_name, window_name=None):
"""find a window by its class_name"""
self._handle = win32gui.FindWindow(class_name, window_name)
def _window_enum_callback(self, hwnd, wildcard):
"""Pass to win32gui.EnumWindows() to check all the opened windows"""
if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) is not None:
self._handle = hwnd
def find_window_wildcard(self, wildcard):
"""find a window whose title matches the wildcard regex"""
self._handle = None
win32gui.EnumWindows(self._window_enum_callback, wildcard)
def set_foreground(self):
"""put the window in the foreground"""
win32gui.SetForegroundWindow(self._handle)
w = WindowMgr()
w.find_window_wildcard(".*Hello.*")
w.set_foreground()
Pywinauto和SWAPY可能需要最少的努力来设置窗口的焦点。
使用SWAPY自动生成Python代码以检索窗口对象,例如:
import pywinauto
# SWAPY will record the title and class of the window you want activated
app = pywinauto.application.Application()
t, c = u'WINDOW SWAPY RECORDS', u'CLASS SWAPY RECORDS'
handle = pywinauto.findwindows.find_windows(title=t, class_name=c)[0]
# SWAPY will also get the window
window = app.window_(handle=handle)
# this here is the only line of code you actually write (SWAPY recorded the rest)
window.SetFocus()
# minimize then maximize to bring this window in front of all others
window.Minimize()
window.Maximize()
# now you can set its focus
window.SetFocus()
import ctypes, platform
if platform.system() == 'Windows':
Active_W = ctypes.windll.user32.GetActiveWindow()
ctypes.windll.user32.SetWindowPos(Active_W,0,0,0,0,0,0x0002|0x0001)
让我们开始吧。您只需要存储活动窗口的值。
使用Pip安装键盘库。
在设置前景窗口之前,模拟按下Esc键,即keyboard.send('esc')。
您可能需要对以下任一项执行三次:
Python3
安装库
pip install pywin32
将下面的代码保存为alive.pyw
文件
from ctypes import windll, wintypes, byref, c_uint, sizeof, Structure
import tkinter as tk
import ctypes
import sys
import threading
import time
import win32api
import win32con
stop_threads = True
SET_IDLE_TIME = 40 #in seconds
tm1 = time.time()
value = 0
class LASTINPUTINFO(Structure):
_fields_ = [
('cbSize', c_uint),
('dwTime', c_uint),
]
def get_idle_duration():
global value, tm1
lastInputInfo = LASTINPUTINFO()
lastInputInfo.cbSize = sizeof(lastInputInfo)
windll.user32.GetLastInputInfo(byref(lastInputInfo))
# millis = 4294967 - lastInputInfo.dwTime - windll.kernel32.GetTickCount()
# print(windll.kernel32.GetTickCount(), lastInputInfo.dwTime, sizeof(lastInputInfo), millis)
tm2 = time.time() - tm1
last_idel_time = lastInputInfo.dwTime
# print()
if value != last_idel_time:
value = last_idel_time
tm2 = time.time() - time.time()
tm1 = time.time()
# print("time:", tm1)
return tm2
def press_key_2():
global stop_threads, tm1
while True:
if not stop_threads:
break
idle_time = get_idle_duration() #seconds
# print(idle_time)
g = float("{:.2f}".format(idle_time))
st = str(g) + " / " + str(SET_IDLE_TIME)
var.set(st)
time.sleep(0.1)
if idle_time < SET_IDLE_TIME:
continue
print("in ideal state pressing cltr")
win32api.keybd_event(ord('x'), 0, win32con.KEYEVENTF_EXTENDEDKEY, 0)
tm1 = time.time()
#---------------- Monitor threads ------------------------------
t1 = threading.Thread(target=press_key_2, name='t1')
t1.daemon = True
#----------------- TK functions ----------------------
def display_on():
global tk, t1, stop_threads
stop_threads = True
print("Always On")
ctypes.windll.kernel32.SetThreadExecutionState(0x80000002)
root.iconify()
t1.start()
# t2.start()
def display_reset():
print("quit pressed")
global stop_threads
stop_threads = False
ctypes.windll.kernel32.SetThreadExecutionState(0x80000000)
sys.exit(0)
root = tk.Tk()
root.geometry("200x110")
root.title("Devil")
frame = tk.Frame(root)
frame.pack()
var = tk.StringVar()
var_idle = tk.StringVar()
label = tk.Label(frame, textvariable = var)#, bd = 5, justify = tk.RIGHT, padx = 10, pady = 10)
label_idle = tk.Label(frame,textvariable = var_idle)
var_idle.set("Idle Time")
var.set("-")
button = tk.Button(frame,
text="Quit",
fg="red",
command=display_reset)
slogan = tk.Button(frame,
text="Always ON",
command=display_on)
label_idle.pack(side=tk.BOTTOM,padx=15, pady=13)
label.pack(side=tk.BOTTOM,padx=15, pady=5)
slogan.pack(side=tk.LEFT,padx=15, pady=5)
button.pack(side=tk.LEFT,padx=15, pady=5)
root.mainloop()
ctypes.windll.kernel32.SetThreadExecutionState(0x80000000)
如果窗口被最小化(即IsIconic
),使用SetWindowPos
或SetForegroundWindow
可能不足够!我们可以使用ShowWindow
与SW_RESTORE
(9):
import ctypes
def activate_window(hwnd):
user32 = ctypes.windll.user32
user32.SetForegroundWindow(hwnd)
if user32.IsIconic(hwnd):
user32.ShowWindow(hwnd, 9)
hwnd
,也就是窗口句柄。pid
使用 user32.GetWindowThreadProcessId
或使用窗口名称 user32.GetWindowTextW
。wmic
。它还有许多其他方便的用途。(所有属性: wmic process get /?
) (get handle
已损坏) 例如:def get_pids(proc_name):
out = subprocess.check_output('wmic process where Name="%s" get ProcessId' % proc_name)
pids = out.decode().strip().split()[1:]
if not pids:
raise WindowsError('Could not find pids for process')
return [int(pid) for pid in pids]
补充 @luc 的回答,以下是代码如何更详细地处理存在多个窗口时所选的句柄:
在 pip install pywin32
后运行
import win32gui
import re
class WindowMgr:
"""Encapsulates some calls to the winapi for window management"""
def __init__ (self):
"""Constructor"""
self._handle = None
self._handles = []
def find_window(self, class_name, window_name=None):
"""find a window by its class_name"""
self._handle = win32gui.FindWindow(class_name, window_name)
def _window_enum_callback(self, hwnd, wildcard):
"""Pass to win32gui.EnumWindows() to check all the opened windows"""
if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) is not None:
self._handles.append(hwnd)
self._handle = hwnd
def find_window_wildcard(self, wildcard):
"""find a window whose title matches the wildcard regex"""
self._handle = None
self._handles = []
win32gui.EnumWindows(self._window_enum_callback, wildcard)
self.set_handle()
def set_foreground(self):
"""put the window in the foreground"""
if self._handle != None:
win32gui.SetForegroundWindow(self._handle)
else:
print("No handle is selected, couldn't set focus")
def set_handle(self):
"""get one handle to operate on from all the matched handles"""
if len(self._handles) < 1:
print("Matched no window")
return False
if len(self._handles) > 1:
print("Selecting the first handle of multiple windows:")
else: # len(self._handles) == 1:
print("Matched a single window:")
self.print_matches()
self._handle = self._handles[0]
return True
def print_matches(self):
"""print the title of each matched handle"""
for hwnd in self._handles:
print("- " + str(win32gui.GetWindowText(hwnd)))
w = WindowMgr()
w.find_window_wildcard(".*Hello.*")
w.set_foreground()
注意:由于建议编辑队列已满,我无法通过编辑@luc的答案进行添加。
SendKeys()
函数从当前窗口中获取焦点。这在使用Python 3.10.6测试的Windows 11上进行了测试。import re
import win32gui
import win32com.client
class WindowMgr:
""" Encapsulates calls to the winapi for window management
Forces context window to take focus
Based on:
- https://dev59.com/ZnI95IYBdhLWcg3w7SlZ
- https://dev59.com/SmYq5IYBdhLWcg3wrSas
"""
def __init__ (self):
self._handle = None
def find_window(self, class_name, window_name=None):
"""find a window by its class_name"""
self._handle = win32gui.FindWindow(class_name, window_name)
return self
def _window_enum_callback(self, hwnd, wildcard):
"""Pass to win32gui.EnumWindows() to check all the opened windows"""
if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) is not None:
self._handle = hwnd
def find_window_wildcard(self, wildcard):
"""find a window whose title matches the wildcard regex"""
self._handle = None
win32gui.EnumWindows(self._window_enum_callback, wildcard)
return self
def set_foreground(self):
"""put the window in the foreground"""
shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys('%') # left shift key sent, this shifts focus from current window
win32gui.SetForegroundWindow(self._handle)
这个函数的一个简单用法是可以使用链式调用,如下所示:
WindowMgr().find_window_wildcard("My Window Title").set_foreground()