import sys import time import os import resources_rc from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QLineEdit, QCheckBox, QComboBox, QGridLayout, QMessageBox, QDialog) from PyQt5.QtCore import QTimer, Qt, QSettings import win32gui import win32con import win32api import win32process import ctypes from ctypes import wintypes # 检查并请求管理员权限 def is_admin(): try: return ctypes.windll.shell32.IsUserAnAdmin() except: return False if not is_admin(): # 如果不是管理员权限,则重新以管理员身份启动程序 ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1) sys.exit(0) # Constants for virtual keys VK_SPACE = 0x20 VK_RETURN = 0x0D VK_TAB = 0x09 VK_ESCAPE = 0x1B VK_BACK = 0x08 VK_INSERT = 0x2D VK_DELETE = 0x2E VK_HOME = 0x24 VK_END = 0x23 VK_PRIOR = 0x21 # Page Up VK_NEXT = 0x22 # Page Down VK_LEFT = 0x25 VK_RIGHT = 0x27 VK_UP = 0x26 VK_DOWN = 0x28 VK_F1 = 0x70 VK_F2 = 0x71 VK_F3 = 0x72 VK_F4 = 0x73 VK_F5 = 0x74 VK_F6 = 0x75 VK_F7 = 0x76 VK_F8 = 0x77 VK_F9 = 0x78 VK_F10 = 0x79 VK_F11 = 0x7A VK_F12 = 0x7B VK_SCROLL = 0x91 WM_KEYDOWN = 0x0100 WM_KEYUP = 0x0101 WM_CHAR = 0x0102 # Constants for SendInput INPUT_KEYBOARD = 1 KEYEVENTF_KEYUP = 0x0002 KEYEVENTF_UNICODE = 0x0004 # 鼠标事件常量 MOUSEEVENTF_MOVE = 0x0001 MOUSEEVENTF_LEFTDOWN = 0x0002 MOUSEEVENTF_LEFTUP = 0x0004 MOUSEEVENTF_RIGHTDOWN = 0x0008 MOUSEEVENTF_RIGHTUP = 0x0010 MOUSEEVENTF_MIDDLEDOWN = 0x0020 MOUSEEVENTF_MIDDLEUP = 0x0040 MOUSEEVENTF_ABSOLUTE = 0x8000 # SendInput常量 INPUT_MOUSE = 0 INPUT_KEYBOARD = 1 # Define required structures for SendInput class MOUSEINPUT(ctypes.Structure): _fields_ = [ ("dx", wintypes.LONG), ("dy", wintypes.LONG), ("mouseData", wintypes.DWORD), ("dwFlags", wintypes.DWORD), ("time", wintypes.DWORD), ("dwExtraInfo", ctypes.POINTER(wintypes.ULONG)), ] class KEYBDINPUT(ctypes.Structure): _fields_ = [ ("wVk", wintypes.WORD), ("wScan", wintypes.WORD), ("dwFlags", wintypes.DWORD), ("time", wintypes.DWORD), ("dwExtraInfo", ctypes.POINTER(wintypes.ULONG)), ] class HARDWAREINPUT(ctypes.Structure): _fields_ = [ ("uMsg", wintypes.DWORD), ("wParamL", wintypes.WORD), ("wParamH", wintypes.WORD), ] class INPUT_union(ctypes.Union): _fields_ = [ ("mi", MOUSEINPUT), ("ki", KEYBDINPUT), ("hi", HARDWAREINPUT), ] class INPUT(ctypes.Structure): _fields_ = [ ("type", wintypes.DWORD), ("u", INPUT_union), ] class AboutMeDlg(QDialog): # 从 QWidget 改为 QDialog def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("关于") self.setFixedSize(400, 200) layout = QVBoxLayout() title = QLabel("KeyPresser", self) title.setStyleSheet("font-size: 18pt; font-weight: bold;") layout.addWidget(title) desc = QLabel("一个简单的按键模拟工具", self) layout.addWidget(desc) version = QLabel("版本: 专业版 (Python 无钩子版)", self) layout.addWidget(version) author = QLabel("作者: xiao liu", self) layout.addWidget(author) ok_button = QPushButton("确定", self) ok_button.clicked.connect(self.accept) # 从 self.close 改为 self.accept layout.addWidget(ok_button) self.setLayout(layout) class KeyPresser(QWidget): def __init__(self, parent=None): super().__init__(parent) self.target_hwnd = None self.timers = [] # 设置应用程序和窗口图标 self.setWindowIcon(QIcon(':/aaa.ico')) # 添加这行代码 self.init_ui() self.load_settings() # Add a timer to poll for hotkey self.hotkeyTimer = QTimer(self) self.hotkeyTimer.timeout.connect(self.check_hotkey) self.hotkeyTimer.start(50) # Check every 50ms for more responsive hotkey # 添加到__init__或init_ui方法中 self.mouseTimer = QTimer(self) self.mouseTimer.timeout.connect(self.click_mouse) # Last key state self.lastKeyState = False def init_ui(self): self.setWindowTitle("KeyPresser(无钩子版)") self.setFixedWidth(300) layout = QVBoxLayout(self) # Window selection label = QLabel("选择窗口:", self) layout.addWidget(label) self.selectedWindowLabel = QLabel("未选择窗口", self) self.selectedWindowLabel.setStyleSheet("color: green;") layout.addWidget(self.selectedWindowLabel) selectButton = QPushButton("选择窗口", self) layout.addWidget(selectButton) # Mode selection for key pressing modeLayout = QHBoxLayout() modeLabel = QLabel("按键模式:", self) modeLayout.addWidget(modeLabel) self.modeComboBox = QComboBox(self) self.modeComboBox.addItem("PostMessage (常规模式)", "post") self.modeComboBox.addItem("SendInput (后台模式)", "send") self.modeComboBox.addItem("SendMessage (直接模式)", "send_message") modeLayout.addWidget(self.modeComboBox) layout.addLayout(modeLayout) # Space key settings spaceLayout = QHBoxLayout() self.spaceCheckBox = QCheckBox(self) spaceLayout.addWidget(self.spaceCheckBox) spaceLabel = QLabel("空格键时间间隔 (毫秒):", self) spaceLayout.addWidget(spaceLabel) self.spaceIntervalLineEdit = QLineEdit(self) self.spaceIntervalLineEdit.setText("1000") spaceLayout.addWidget(self.spaceIntervalLineEdit) layout.addLayout(spaceLayout) # 鼠标左键设置 - 修复布局 mouseLayout = QHBoxLayout() self.mouseCheckBox = QCheckBox(self) mouseLayout.addWidget(self.mouseCheckBox) mouseLabel = QLabel("鼠标左键时间间隔 (毫秒):", self) mouseLayout.addWidget(mouseLabel) # 修复:将mouseLabel.addWidget(mouseLabel)改为mouseLayout.addWidget(mouseLabel) self.mouseIntervalLineEdit = QLineEdit(self) self.mouseIntervalLineEdit.setText("1000") mouseLayout.addWidget(self.mouseIntervalLineEdit) layout.addLayout(mouseLayout) # Custom keys keysLabel = QLabel("自定义按键和时间间隔 (毫秒):", self) layout.addWidget(keysLabel) keysLayout = QGridLayout() self.keyCheckBoxes = [] self.keyCombos = [] self.intervalLineEdits = [] for i in range(10): checkbox = QCheckBox(self) keysLayout.addWidget(checkbox, i, 0) self.keyCheckBoxes.append(checkbox) combobox = QComboBox(self) self.populate_key_combos(combobox) keysLayout.addWidget(combobox, i, 1) self.keyCombos.append(combobox) lineEdit = QLineEdit(self) lineEdit.setText("1000") keysLayout.addWidget(lineEdit, i, 2) self.intervalLineEdits.append(lineEdit) # Create timer for this key timer = QTimer(self) timer.timeout.connect(lambda checked=False, index=i: self.press_keys(index)) self.timers.append(timer) layout.addLayout(keysLayout) # Start/Stop buttons startButton = QPushButton("开始", self) layout.addWidget(startButton) stopButton = QPushButton("停止", self) layout.addWidget(stopButton) labelPrompt = QLabel("修改配置后需点击开始按钮以使更改生效。", self) labelPrompt.setStyleSheet("color: red;") layout.addWidget(labelPrompt) self.instructionLabel = QLabel("停止中", self) self.instructionLabel.setStyleSheet("color: green;") layout.addWidget(self.instructionLabel) # Hotkey selection hotkeyLayout = QHBoxLayout() hotkeyLabel = QLabel("开始/停止快捷键:", self) hotkeyLayout.addWidget(hotkeyLabel) self.hotkeyComboBox = QComboBox(self) self.populate_key_combos(self.hotkeyComboBox) self.hotkeyComboBox.setCurrentText("Home") # Default to Home key hotkeyLayout.addWidget(self.hotkeyComboBox) layout.addLayout(hotkeyLayout) # Debug info self.debugLabel = QLabel("状态: 管理员模式 (使用轮询检测热键)", self) self.debugLabel.setStyleSheet("color: blue;") layout.addWidget(self.debugLabel) # Thread input settings threadLayout = QHBoxLayout() self.attachThreadCheckBox = QCheckBox("关联线程输入", self) self.attachThreadCheckBox.setChecked(True) threadLayout.addWidget(self.attachThreadCheckBox) layout.addLayout(threadLayout) aboutButton = QPushButton("关于", self) layout.addWidget(aboutButton) # Connect signals selectButton.clicked.connect(self.select_window) startButton.clicked.connect(self.start_pressing) stopButton.clicked.connect(self.stop_pressing) aboutButton.clicked.connect(self.about_me) self.spaceTimer = QTimer(self) self.spaceTimer.timeout.connect(self.press_space) self.setLayout(layout) def populate_key_combos(self, comboBox): keys = [ ("F1", VK_F1), ("F2", VK_F2), ("F3", VK_F3), ("F4", VK_F4), ("F5", VK_F5), ("F6", VK_F6), ("F7", VK_F7), ("F8", VK_F8), ("F9", VK_F9), ("F10", VK_F10), ("F11", VK_F11), ("F12", VK_F12), ("A", ord('A')), ("B", ord('B')), ("C", ord('C')), ("D", ord('D')), ("E", ord('E')), ("F", ord('F')), ("G", ord('G')), ("H", ord('H')), ("I", ord('I')), ("J", ord('J')), ("K", ord('K')), ("L", ord('L')), ("M", ord('M')), ("N", ord('N')), ("O", ord('O')), ("P", ord('P')), ("Q", ord('Q')), ("R", ord('R')), ("S", ord('S')), ("T", ord('T')), ("U", ord('U')), ("V", ord('V')), ("W", ord('W')), ("X", ord('X')), ("Y", ord('Y')), ("Z", ord('Z')), ("0", ord('0')), ("1", ord('1')), ("2", ord('2')), ("3", ord('3')), ("4", ord('4')), ("5", ord('5')), ("6", ord('6')), ("7", ord('7')), ("8", ord('8')), ("9", ord('9')), ("Space", VK_SPACE), ("Enter", VK_RETURN), ("Tab", VK_TAB), ("Esc", VK_ESCAPE), ("Backspace", VK_BACK), ("Insert", VK_INSERT), ("Delete", VK_DELETE), ("Home", VK_HOME), ("End", VK_END), ("Page Up", VK_PRIOR), ("Page Down", VK_NEXT), ("Left Arrow", VK_LEFT), ("Right Arrow", VK_RIGHT), ("Up Arrow", VK_UP), ("Down Arrow", VK_DOWN),("Scroll", VK_SCROLL) ] for text, value in keys: comboBox.addItem(text, value) def check_hotkey(self): """Check if the selected hotkey is pressed""" # Get the selected hotkey key_code = self.hotkeyComboBox.currentData() # Check if key is pressed key_state = win32api.GetAsyncKeyState(key_code) & 0x8000 != 0 # Detect key press (transition from not pressed to pressed) if key_state and not self.lastKeyState: if self.instructionLabel.text() == "运行中": self.stop_pressing() else: self.start_pressing() self.lastKeyState = key_state def select_window(self): """Allow user to select a target window by clicking on it""" self.selectedWindowLabel.setText("请点击目标窗口...") # Hide our window temporarily self.hide() QApplication.processEvents() time.sleep(0.2) # Give a small delay for user to see the message # Poll for mouse click while True: if win32api.GetAsyncKeyState(0x01) & 0x8000: # Left mouse button pressed cursor_pos = win32gui.GetCursorPos() window_handle = win32gui.WindowFromPoint(cursor_pos) if window_handle: window_text = win32gui.GetWindowText(window_handle) self.target_hwnd = window_handle # Get process ID for debugging try: _, process_id = win32process.GetWindowThreadProcessId(window_handle) self.debugLabel.setText(f"状态: 已选择窗口 (PID: {process_id})") except: pass self.selectedWindowLabel.setText(window_text) break QApplication.processEvents() time.sleep(0.1) # Show our window again time.sleep(0.2) # Wait for mouse release self.show() def start_pressing(self): """Start sending keystrokes to the target window""" if not self.target_hwnd: QMessageBox.warning(self, "警告", "请选择窗口后,再点击开始!") return self.instructionLabel.setText("运行中") self.stop_all_timers() # Check if target window still exists if not win32gui.IsWindow(self.target_hwnd): QMessageBox.warning(self, "警告", "目标窗口已关闭,请重新选择!") self.target_hwnd = None self.selectedWindowLabel.setText("未选择窗口") self.instructionLabel.setText("停止中") return # Try to attach to target window thread if option is checked if self.attachThreadCheckBox.isChecked(): try: target_thread_id = win32process.GetWindowThreadProcessId(self.target_hwnd)[0] current_thread_id = win32api.GetCurrentThreadId() win32process.AttachThreadInput(current_thread_id, target_thread_id, True) self.debugLabel.setText("状态: 已关联线程输入") except Exception as e: self.debugLabel.setText(f"状态: 线程关联失败 ({str(e)})") # Start the space key timer if checked if self.spaceCheckBox.isChecked(): self.press_space() interval = int(self.spaceIntervalLineEdit.text()) self.spaceTimer.start(interval) # 如果选中,启动鼠标点击定时器 if self.mouseCheckBox.isChecked(): self.click_mouse() # 立即执行 interval = int(self.mouseIntervalLineEdit.text()) self.mouseTimer.start(interval) # Start the custom key timers if checked for i in range(10): if self.keyCheckBoxes[i].isChecked() and self.keyCombos[i].currentIndex() != -1: self.press_keys(i) interval = int(self.intervalLineEdits[i].text()) self.timers[i].start(interval) def stop_pressing(self): """Stop sending keystrokes""" self.instructionLabel.setText("停止中") self.stop_all_timers() # Try to detach from target window thread if option is checked if self.attachThreadCheckBox.isChecked() and self.target_hwnd: try: target_thread_id = win32process.GetWindowThreadProcessId(self.target_hwnd)[0] current_thread_id = win32api.GetCurrentThreadId() win32process.AttachThreadInput(current_thread_id, target_thread_id, False) self.debugLabel.setText("状态: 已解除线程关联") except: pass def about_me(self): """Show the about dialog""" about_dialog = AboutMeDlg(self) about_dialog.exec_() def stop_all_timers(self): """Stop all key press timers""" self.spaceTimer.stop() self.mouseTimer.stop() # 添加鼠标定时器停止 for timer in self.timers: timer.stop() def press_space(self): """Send space key to target window""" if self.target_hwnd and win32gui.IsWindow(self.target_hwnd): key_mode = self.modeComboBox.currentData() key_code = VK_SPACE if key_mode == "post": # Use PostMessage method (original method) scan_code = win32api.MapVirtualKey(key_code, 0) # Key down lparam = (scan_code << 16) | 1 win32gui.PostMessage(self.target_hwnd, WM_KEYDOWN, key_code, lparam) # Key up lparam = (scan_code << 16) | (1 | (1 << 30) | (1 << 31)) win32gui.PostMessage(self.target_hwnd, WM_KEYUP, key_code, lparam) elif key_mode == "send_message": # Use SendMessage method (synchronous, might work better for some apps) scan_code = win32api.MapVirtualKey(key_code, 0) # Key down lparam = (scan_code << 16) | 1 win32gui.SendMessage(self.target_hwnd, WM_KEYDOWN, key_code, lparam) # Send WM_CHAR message (important for text input) win32gui.SendMessage(self.target_hwnd, WM_CHAR, ord(' '), lparam) # Key up lparam = (scan_code << 16) | (1 | (1 << 30) | (1 << 31)) win32gui.SendMessage(self.target_hwnd, WM_KEYUP, key_code, lparam) else: # send mode - uses SendInput # Use SendInput method (works for background windows sometimes) self.send_key(key_code) def press_keys(self, index): """Send keys to target window""" if self.target_hwnd and win32gui.IsWindow(self.target_hwnd): key_code = self.keyCombos[index].currentData() key_mode = self.modeComboBox.currentData() if key_mode == "post": # Use PostMessage method (original method) scan_code = win32api.MapVirtualKey(key_code, 0) # Key down lparam = (scan_code << 16) | 1 win32gui.PostMessage(self.target_hwnd, WM_KEYDOWN, key_code, lparam) # Send WM_CHAR for regular keys if key_code >= ord('A') and key_code <= ord('Z'): # Convert to lowercase for character input char_code = key_code + 32 # ASCII difference between uppercase and lowercase win32gui.PostMessage(self.target_hwnd, WM_CHAR, char_code, lparam) elif key_code >= ord('0') and key_code <= ord('9') or key_code == VK_SPACE: win32gui.PostMessage(self.target_hwnd, WM_CHAR, key_code, lparam) # Key up lparam = (scan_code << 16) | (1 | (1 << 30) | (1 << 31)) win32gui.PostMessage(self.target_hwnd, WM_KEYUP, key_code, lparam) elif key_mode == "send_message": # Use SendMessage method (synchronous, might work better for some apps) scan_code = win32api.MapVirtualKey(key_code, 0) # Key down lparam = (scan_code << 16) | 1 win32gui.SendMessage(self.target_hwnd, WM_KEYDOWN, key_code, lparam) # Send WM_CHAR for regular keys if key_code >= ord('A') and key_code <= ord('Z'): # Convert to lowercase for character input char_code = key_code + 32 # ASCII difference between uppercase and lowercase win32gui.SendMessage(self.target_hwnd, WM_CHAR, char_code, lparam) elif key_code >= ord('0') and key_code <= ord('9') or key_code == VK_SPACE: win32gui.SendMessage(self.target_hwnd, WM_CHAR, key_code, lparam) # Key up lparam = (scan_code << 16) | (1 | (1 << 30) | (1 << 31)) win32gui.SendMessage(self.target_hwnd, WM_KEYUP, key_code, lparam) else: # send mode - uses SendInput # Use SendInput method (works for background windows sometimes) self.send_key(key_code) def send_key(self, key_code): """Send a key press using SendInput (works for background windows sometimes)""" # Try to set target window to foreground (optional, may help in some cases) try: if self.target_hwnd: win32gui.SetForegroundWindow(self.target_hwnd) except: pass # Ignore if activation fails # Create Input structure for key down inputs = (INPUT * 2)() # Key down event inputs[0].type = INPUT_KEYBOARD inputs[0].u.ki.wVk = key_code inputs[0].u.ki.wScan = win32api.MapVirtualKey(key_code, 0) inputs[0].u.ki.dwFlags = 0 inputs[0].u.ki.time = 0 inputs[0].u.ki.dwExtraInfo = None # Key up event inputs[1].type = INPUT_KEYBOARD inputs[1].u.ki.wVk = key_code inputs[1].u.ki.wScan = win32api.MapVirtualKey(key_code, 0) inputs[1].u.ki.dwFlags = KEYEVENTF_KEYUP inputs[1].u.ki.time = 0 inputs[1].u.ki.dwExtraInfo = None # Send input ctypes.windll.user32.SendInput(2, ctypes.byref(inputs), ctypes.sizeof(INPUT)) def click_mouse(self): """向目标窗口发送鼠标点击""" if self.target_hwnd and win32gui.IsWindow(self.target_hwnd): key_mode = self.modeComboBox.currentData() # 获取窗口客户区坐标 try: # 获取窗口矩形和客户区矩形 #window_rect = win32gui.GetWindowRect(self.target_hwnd) #client_rect = win32gui.GetClientRect(self.target_hwnd) # 计算客户区中心 #client_center_x = client_rect[2] // 2 #client_center_y = client_rect[3] // 2 # 将客户区坐标映射到屏幕坐标 #pt = win32gui.ClientToScreen(self.target_hwnd, (client_center_x, client_center_y)) if key_mode == "post" or key_mode == "send_message": # 使用PostMessage/SendMessage进行鼠标点击 # 将屏幕坐标转换为客户区坐标 #client_pt = win32gui.ScreenToClient(self.target_hwnd, pt) lparam = 0 #client_pt[0] | (client_pt[1] << 16) if key_mode == "post": # 鼠标按下 win32gui.PostMessage(self.target_hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lparam) # 鼠标抬起 win32gui.PostMessage(self.target_hwnd, win32con.WM_LBUTTONUP, 0, lparam) else: # send_message # 鼠标按下 win32gui.SendMessage(self.target_hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lparam) # 鼠标抬起 win32gui.SendMessage(self.target_hwnd, win32con.WM_LBUTTONUP, 0, lparam) else: # send模式 - 使用SendInput # 移动光标到目标位置(可选,某些应用程序可能需要) #try: # win32api.SetCursorPos(pt) #except: # pass # 初始化鼠标输入结构 inputs = (INPUT * 2)() # 鼠标按下事件 inputs[0].type = INPUT_MOUSE inputs[0].u.mi.dx = 0 #pt[0] inputs[0].u.mi.dy = 0 #pt[1] inputs[0].u.mi.mouseData = 0 inputs[0].u.mi.dwFlags = MOUSEEVENTF_LEFTDOWN inputs[0].u.mi.time = 0 inputs[0].u.mi.dwExtraInfo = None # 鼠标抬起事件 inputs[1].type = INPUT_MOUSE inputs[1].u.mi.dx = 0 #pt[0] inputs[1].u.mi.dy = 0 #pt[1] inputs[1].u.mi.mouseData = 0 inputs[1].u.mi.dwFlags = MOUSEEVENTF_LEFTUP inputs[1].u.mi.time = 0 inputs[1].u.mi.dwExtraInfo = None # 发送输入 ctypes.windll.user32.SendInput(2, ctypes.byref(inputs), ctypes.sizeof(INPUT)) except Exception as e: print(f"发送鼠标点击时出错: {str(e)}") def load_settings(self): """Load saved settings""" settings = QSettings("FinnSoft", "KeyPresser") # 在load_settings方法中添加: self.mouseCheckBox.setChecked(settings.value("mouseCheckBox", False, type=bool)) self.mouseIntervalLineEdit.setText(settings.value("mouseIntervalLineEdit", "1000")) self.spaceCheckBox.setChecked(settings.value("spaceCheckBox", False, type=bool)) self.spaceIntervalLineEdit.setText(settings.value("spaceIntervalLineEdit", "1000")) # Mode selection mode_index = settings.value("modeIndex", 0, type=int) if 0 <= mode_index < self.modeComboBox.count(): self.modeComboBox.setCurrentIndex(mode_index) # Thread attachment option self.attachThreadCheckBox.setChecked(settings.value("attachThread", True, type=bool)) for i in range(10): self.keyCheckBoxes[i].setChecked(settings.value(f"keyCheckBox{i}", False, type=bool)) combo_index = settings.value(f"keyCombo{i}", 0, type=int) if 0 <= combo_index < self.keyCombos[i].count(): self.keyCombos[i].setCurrentIndex(combo_index) self.intervalLineEdits[i].setText(settings.value(f"intervalLineEdit{i}", "1000")) # Hotkey hotkey_index = settings.value("hotkeyIndex", 47, type=int) # Default to Home key if 0 <= hotkey_index < self.hotkeyComboBox.count(): self.hotkeyComboBox.setCurrentIndex(hotkey_index) def save_settings(self): """Save current settings""" settings = QSettings("FinnSoft", "KeyPresser") settings.setValue("spaceCheckBox", self.spaceCheckBox.isChecked()) settings.setValue("spaceIntervalLineEdit", self.spaceIntervalLineEdit.text()) # 在save_settings方法中添加: settings.setValue("mouseCheckBox", self.mouseCheckBox.isChecked()) settings.setValue("mouseIntervalLineEdit", self.mouseIntervalLineEdit.text()) # Mode selection settings.setValue("modeIndex", self.modeComboBox.currentIndex()) # Thread attachment option settings.setValue("attachThread", self.attachThreadCheckBox.isChecked()) for i in range(10): settings.setValue(f"keyCheckBox{i}", self.keyCheckBoxes[i].isChecked()) settings.setValue(f"keyCombo{i}", self.keyCombos[i].currentIndex()) settings.setValue(f"intervalLineEdit{i}", self.intervalLineEdits[i].text()) # Hotkey settings.setValue("hotkeyIndex", self.hotkeyComboBox.currentIndex()) def closeEvent(self, event): """Handle window close event""" self.save_settings() super().closeEvent(event) if __name__ == '__main__': # 启用高DPI缩放支持 if hasattr(Qt, 'AA_EnableHighDpiScaling'): QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True) if hasattr(Qt, 'AA_UseHighDpiPixmaps'): QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True) app = QApplication(sys.argv) app.setWindowIcon(QIcon(':/aaa.ico')) window = KeyPresser() window.show() sys.exit(app.exec_())