基于Win32api向未聚焦窗口模拟Key Press的脚本实现咨询
Absolutely, this is totally achievable! The core issue with your current script is that it’s tied to the focused window for input—but we can fix this by sending keyboard events directly to the target window’s underlying handle, regardless of whether it’s in the background, minimized, or unfocused. Let’s break down how to implement this across major operating systems with practical, working code examples.
Windows Platform
On Windows, the most reliable way to send keystrokes to a background window is using the PostMessage API, which lets you send WM_KEYDOWN and WM_KEYUP messages directly to a window’s handle (HWND). Here’s a Python example using the pywin32 library:
import win32gui import win32api import win32con import time def send_key_to_window(window_title, key_code): # Locate the target window by its title hwnd = win32gui.FindWindow(None, window_title) if not hwnd: print(f"Window '{window_title}' not found—double-check the title!") return # Simulate key press (WM_KEYDOWN) win32api.PostMessage(hwnd, win32con.WM_KEYDOWN, key_code, 0) time.sleep(0.1) # Mimic natural key hold duration # Simulate key release (WM_KEYUP) win32api.PostMessage(hwnd, win32con.WM_KEYUP, key_code, 0) # Example: Send Enter key to Notepad every 2 seconds while True: send_key_to_window("Notepad", win32con.VK_RETURN) time.sleep(2)
Notes for Windows:
- Use
win32con.VK_*constants for standard keys (e.g.,VK_SPACE,VK_TAB). For character keys, you may need to useMapVirtualKeyto convert ASCII to virtual key codes. - Some apps (like certain games) block
PostMessage—if that’s the case, you can look intoSendInputwith temporary window focus (but that will briefly bring the window to the foreground).
Linux Platform
On Linux, you can use xdotool (a command-line utility) for quick implementation, or the python-xlib library for more control. Here’s both approaches:
Using xdotool (Command Line)
# Get the target window ID by title WINDOW_ID=$(xdotool search --name "Your Target Window Title") # Send Enter key every 2 seconds while true; do xdotool key --window $WINDOW_ID Return sleep 2 done
Using Python & python-xlib
from Xlib import X, display import time def send_key_to_window(window_title, key_symbol): d = display.Display() root = d.screen().root target_win = None # Search for the window by title for win in root.query_tree().children: try: if win.get_wm_name() == window_title: target_win = win break except: continue if not target_win: print(f"Window '{window_title}' not found!") return # Convert key symbol to keycode keycode = d.keysym_to_keycode(key_symbol) # Send key press event target_win.send_event(X.KeyPressEvent( time=X.CurrentTime, root=root, window=target_win, same_screen=0, child=X.NONE, root_x=0, root_y=0, event_x=0, event_y=0, state=0, detail=keycode )) time.sleep(0.1) # Send key release event target_win.send_event(X.KeyReleaseEvent( time=X.CurrentTime, root=root, window=target_win, same_screen=0, child=X.NONE, root_x=0, root_y=0, event_x=0, event_y=0, state=0, detail=keycode )) d.sync() # Example: Send Enter key to a Terminal window every 2 seconds while True: send_key_to_window("Terminal", X.K_Return) time.sleep(2)
macOS Platform
On macOS, you can use AppleScript for a no-compile solution, or pyobjc to call the Quartz Event Services API. Here’s how:
Using AppleScript
repeat tell application "System Events" tell process "YourAppName" key code 36 -- Keycode for Enter; look up others online end tell end tell delay 2 end repeat
Save this as send_keys.scpt and run it with osascript send_keys.scpt. Note: You’ll need to grant accessibility permissions to your terminal/script runner in System Preferences → Security & Privacy → Privacy → Accessibility.
Using Python & pyobjc
from Quartz import CGEventCreateKeyboardEvent, CGEventPostToPSN, ProcessSerialNumber import time import LaunchServices def send_key_to_window(app_name, key_code): # Get the app's process serial number psn = ProcessSerialNumber(highLongOfPSN=0, lowLongOfPSN=0) if not LaunchServices.LSCopyApplicationURLsForBundleIdentifier(app_name, None): print(f"App '{app_name}' not found!") return LaunchServices.LSFindApplicationForInfo(None, None, app_name, None, psn) # Send key press down_event = CGEventCreateKeyboardEvent(None, key_code, True) CGEventPostToPSN(psn, down_event) time.sleep(0.1) # Send key release up_event = CGEventCreateKeyboardEvent(None, key_code, False) CGEventPostToPSN(psn, up_event) # Example: Send Enter key to TextEdit every 2 seconds while True: send_key_to_window("com.apple.TextEdit", 36) time.sleep(2)
General Tips
- Always test with a simple app (like Notepad/TextEdit/Terminal) first to verify functionality.
- Key codes vary by platform—look up the correct codes for the keys you need to simulate.
- Some apps have anti-cheat or input blocking mechanisms that may prevent background input; in those cases, you may need more advanced tools or hooks.
内容的提问来源于stack exchange,提问作者user5457708

