KeyPress/main.py

739 lines
27 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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_())