python实现文字模拟输入解决某些网站的输入框禁止粘贴文字问题
转自 只对无法粘贴中文文字的网页输入框有效
import pyperclip
import pyautogui
import time
from datetime import datetime
import tkinter as tk
from tkinter import scrolledtext
import threading
import win32con
import win32api
import win32gui
import ctypes
from ctypes import wintypes
from pywinauto.keyboard import send_keys# 定义 SendInput 函数需要的结构体
PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):_fields_ = [("wVk", ctypes.c_ushort),("wScan", ctypes.c_ushort),("dwFlags", ctypes.c_ulong),("time", ctypes.c_ulong),("dwExtraInfo", PUL)]class HardwareInput(ctypes.Structure):_fields_ = [("uMsg", ctypes.c_ulong),("wParamL", ctypes.c_short),("wParamH", ctypes.c_ushort)]class MouseInput(ctypes.Structure):_fields_ = [("dx", ctypes.c_long),("dy", ctypes.c_long),("mouseData", ctypes.c_ulong),("dwFlags", ctypes.c_ulong),("time",ctypes.c_ulong),("dwExtraInfo", PUL)]class Input_I(ctypes.Union):_fields_ = [("ki", KeyBdInput),("mi", MouseInput),("hi", HardwareInput)]class Input(ctypes.Structure):_fields_ = [("type", ctypes.c_ulong),("ii", Input_I)]class TyperGUI:def __init__(self):self.root = tk.Tk()self.root.title("文字模拟打字工具")self.root.geometry("400x500")# 设置窗口置顶self.root.attributes('-topmost', True)# 添加停止标志self.stop_flag = False# 创建输入区域self.text_area = scrolledtext.ScrolledText(self.root, width=40, height=15)self.text_area.pack(pady=10)# 延迟时间输入self.delay_frame = tk.Frame(self.root)self.delay_frame.pack(pady=5)tk.Label(self.delay_frame, text="延迟开始时间(秒):").pack(side=tk.LEFT)self.delay_var = tk.StringVar(value="3")self.delay_entry = tk.Entry(self.delay_frame, textvariable=self.delay_var, width=10)self.delay_entry.pack(side=tk.LEFT)# 打字间隔时间self.interval_frame = tk.Frame(self.root)self.interval_frame.pack(pady=5)tk.Label(self.interval_frame, text="打字间隔(秒):").pack(side=tk.LEFT)self.interval_var = tk.StringVar(value="0.1")self.interval_entry = tk.Entry(self.interval_frame, textvariable=self.interval_var, width=10)self.interval_entry.pack(side=tk.LEFT)# 按钮框架self.button_frame = tk.Frame(self.root)self.button_frame.pack(pady=5)# 开始按钮self.start_button = tk.Button(self.button_frame, text="开始打字", command=self.start_typing)self.start_button.pack(side=tk.LEFT, padx=5)# 停止按钮self.stop_button = tk.Button(self.button_frame, text="停止打字", command=self.stop_typing, state=tk.DISABLED)self.stop_button.pack(side=tk.LEFT, padx=5)# 添加置顶控制self.topmost_var = tk.BooleanVar(value=True)self.topmost_check = tk.Checkbutton(self.root, text="窗口置顶", variable=self.topmost_var,command=self.toggle_topmost)self.topmost_check.pack(pady=5)# 倒计时标签self.countdown_label = tk.Label(self.root, text="", font=("Arial", 24))self.countdown_label.pack(pady=5)# 状态标签self.status_label = tk.Label(self.root, text="就绪")self.status_label.pack(pady=5)def toggle_topmost(self):"""切换窗口置顶状态"""self.root.attributes('-topmost', self.topmost_var.get())def stop_typing(self):self.stop_flag = Trueself.start_button.config(state=tk.NORMAL)self.stop_button.config(state=tk.DISABLED)self.status_label.config(text="已停止打字")def start_typing(self):# 获取文本内容text = self.text_area.get("1.0", tk.END).strip()if not text:self.status_label.config(text="请输入要打字的文本内容")returnself.stop_flag = Falseself.start_button.config(state=tk.DISABLED)self.stop_button.config(state=tk.NORMAL)# 开始新线程执行打字threading.Thread(target=self.typing_thread, args=(text,), daemon=True).start()def update_countdown(self, remaining):"""更新倒计时显示"""if remaining > 0:self.countdown_label.config(text=str(remaining))self.root.after(1000, self.update_countdown, remaining - 1)else:self.countdown_label.config(text="开始!")self.root.after(1000, lambda: self.countdown_label.config(text=""))def send_input(self, *inputs):nInputs = len(inputs)LPINPUT = Input * nInputspInputs = LPINPUT(*inputs)cbSize = ctypes.c_int(ctypes.sizeof(Input))return ctypes.windll.user32.SendInput(nInputs, pInputs, cbSize)def press_key(self, key_code):extra = ctypes.c_ulong(0)ii_ = Input_I()ii_.ki = KeyBdInput(key_code, 0x48, 0, 0, ctypes.pointer(extra))x = Input(ctypes.c_ulong(1), ii_)self.send_input(x)def release_key(self, key_code):extra = ctypes.c_ulong(0)ii_ = Input_I()ii_.ki = KeyBdInput(key_code, 0x48, 0x0002, 0, ctypes.pointer(extra))x = Input(ctypes.c_ulong(1), ii_)self.send_input(x)def press_and_release(self, key_code):self.press_key(key_code)time.sleep(0.01)self.release_key(key_code)def simulate_ime_input(self, char):# 模拟输入法输入for event in [win32con.WM_IME_COMPOSITION, win32con.WM_IME_CHAR]:win32api.PostMessage(win32gui.GetForegroundWindow(),event,ord(char),0)time.sleep(0.05)def typing_thread(self, text):try:delay = float(self.delay_var.get())interval = float(self.interval_var.get())except ValueError:self.status_label.config(text="请输入有效的数字")returnself.status_label.config(text="准备开始打字...")self.root.after(0, self.update_countdown, int(delay))time.sleep(delay)if self.stop_flag:returnfor char in text:if self.stop_flag:returnif char == '\n':win32api.PostMessage(win32gui.GetForegroundWindow(),win32con.WM_CHAR,win32con.VK_RETURN,0)else:if ord(char) > 127:# 中文字符使用IME输入self.simulate_ime_input(char)else:# ASCII字符直接发送win32api.PostMessage(win32gui.GetForegroundWindow(),win32con.WM_CHAR,ord(char),0)time.sleep(interval)self.status_label.config(text="打字完成!")self.start_button.config(state=tk.NORMAL)self.stop_button.config(state=tk.DISABLED)if __name__ == "__main__":app = TyperGUI()app.root.mainloop()
z