[Python] 纯文本查看 复制代码
from PyQt5 import QtWidgets, uic, QtCore
from pynput import keyboard, mouse
import pygetwindow as gw
from PyQt5.QtGui import QPainter, QColor, QCursor
from PyQt5.QtCore import Qt, QRectF
from pynput.mouse import Button, Controller
import pyautogui
import threading
import time
import os
ui_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'form.ui')
key_time_dict = {} # Global Dictionary to store keys and times
window = None # Global Window
controller = None # Global Controller
mouseX = 0 # Global Mouse X
mouseY = 0 # Global Mouse Y
class MyLineEdit(QtWidgets.QLineEdit):
def mousePressEvent(self, event):
super(MyLineEdit, self).mousePressEvent(event) # 让QLineEdit处理其鼠标点击事件
print(f'----------------Mouse left button pressed: {event.text()}')
def keyPressEvent(self, event):
super(MyLineEdit, self).keyPressEvent(event)
key = event.key()
print(f'------------------Key pressed: {key}')
# Now `key` holds the key code of the pressed key.
# Do something with it…
key_char = event.text()
print(f'-----------------Pressed key char: {key_char}')
class ToggleButton(QtWidgets.QPushButton):
def __init__(self, parent=None):
super(ToggleButton, self).__init__(parent)
self.setCheckable(True)
self.setMinimumWidth(66)
self.setMinimumHeight(28)
def paintEvent(self, event):
label = "ON" if self.isChecked() else "OFF"
bg_color = QColor(0, 155, 0) if self.isChecked() else QColor(155, 155, 155)
radius = 10
width = 28
center = self.rect().center()
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.translate(center)
painter.setBrush(QColor(255, 255, 255))
pen = painter.pen()
pen.setWidth(2)
pen.setColor(QColor(155, 155, 155))
painter.setPen(pen)
painter.drawRoundedRect(QRectF(-width, -radius, 2*width, 2*radius), radius, radius)
painter.setBrush(QColor(bg_color))
sw_rect = QRectF(-radius, -radius, width, 2*radius)
if not self.isChecked():
sw_rect.moveLeft(-width)
else:
sw_rect.moveRight(width)
painter.drawRoundedRect(sw_rect, radius, radius)
painter.setBrush(QColor(255, 255, 255))
painter.drawText(sw_rect, Qt.AlignCenter, label)
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi(ui_path, self)
# ==================== KeyBoard Auto Press ====================
self.button = self.findChild(QtWidgets.QPushButton, 'Add')
self.button.clicked.connect(self.buttonClicked)
self.line_edit = self.findChild(QtWidgets.QLineEdit, 'lineName')
self.spin_box = self.findChild(QtWidgets.QDoubleSpinBox, 'doubleSpinBox')
self.list_widget = self.findChild(QtWidgets.QListWidget, 'listWidget')
self.statusButton = self.findChild(QtWidgets.QPushButton, 'statusButton')
tmpParent = self.statusButton.parent() # Store the parent of the QPushButton
tmpGeometry = self.statusButton.geometry() # Store the geometry of the QPushButton
self.statusButton.setParent(None) # Unparent the QPushButton
self.statusButton = ToggleButton(self) # Replace with ToggleButton
# tmpParent.layout().addWidget(self.statusButton) # Add the ToggleButton to the layout of the parent
self.statusButton.setGeometry(tmpGeometry) # Set geometry or place it where you want
self.statusButton.clicked.connect(lambda: self.statusButtonClicked(keyboard.Key.f1))
self.statusButton.toggled.connect(lambda: print(f"Toggle button state: {self.statusButton.isChecked()}"))
# ==================== Mouse Auto Press ====================
self.xPos = self.findChild(QtWidgets.QLineEdit, 'xPos')
self.yPos = self.findChild(QtWidgets.QLineEdit, 'yPos')
self.mouseDelay = self.findChild(QtWidgets.QDoubleSpinBox, 'mouseDelay')
self.mouseStatusButton = self.findChild(QtWidgets.QPushButton, 'mouseStatusButton')
tmpParent = self.mouseStatusButton.parent() # Store the parent of the QPushButton
tmpGeometry = self.mouseStatusButton.geometry() # Store the geometry of the QPushButton
self.mouseStatusButton.setParent(None) # Unparent the QPushButton
self.mouseStatusButton = ToggleButton(self) # Replace with ToggleButton
# tmpParent.layout().addWidget(self.statusButton) # Add the ToggleButton to the layout of the parent
self.mouseStatusButton.setGeometry(tmpGeometry) # Set geometry or place it where you want
# self.mouseStatusButton.clicked.connect(lambda: self.statusButtonClicked(keyboard.Key.f1))
self.mouseStatusButton.toggled.connect(lambda: print(f"Toggle mouseStatusButton state: {self.mouseStatusButton.isChecked()}"))
# ==================== Key Map ====================
self.buttonAddMap = self.findChild(QtWidgets.QPushButton, 'AddMap')
self.buttonAddMap.clicked.connect(self.addMapButtonClicked)
self.fromKey = self.findChild(QtWidgets.QLineEdit, 'fromKey')
self.toKey = self.findChild(QtWidgets.QLineEdit, 'toKey')
tmpLineEditParent = self.fromKey.parent() # Store the parent of the QPushButton
tmpLineEditGeometry = self.fromKey.geometry() # Store the geometry of the QPushButton
self.fromKey.setParent(None) # Unparent the QPushButton
self.fromKey = MyLineEdit(self) # Replace with ToggleButton
self.fromKey.setGeometry(tmpLineEditGeometry) # Set geometry or place it where you want
# tmpLineEditParent.layout().addWidget(self.fromKey) # Add the ToggleButton to the layout of the parent
self.mapStatusButton = self.findChild(QtWidgets.QPushButton, 'mapStatusButton')
tmpParent = self.mapStatusButton.parent() # Store the parent of the QPushButton
tmpGeometry = self.mapStatusButton.geometry() # Store the geometry of the QPushButton
self.mapStatusButton.setParent(None) # Unparent the QPushButton
self.mapStatusButton = ToggleButton(self) # Replace with ToggleButton
# tmpParent.layout().addWidget(self.statusButton) # Add the ToggleButton to the layout of the parent
self.mapStatusButton.setGeometry(tmpGeometry) # Set geometry or place it where you want
self.mapStatusButton.clicked.connect(lambda: self.statusButtonClicked(keyboard.Key.f4))
self.mapStatusButton.toggled.connect(lambda: print(f"Toggle mapStatusButton state: {self.mapStatusButton.isChecked()}"))
self.show()
def buttonClicked(self):
try:
key = self.line_edit.text()
time = self.spin_box.value()
# 添加前检查是否重复,如果重复则不添加
if key in key_time_dict or key not in pyautogui.KEYBOARD_KEYS:
return
key_time_dict[key] = time
self.list_widget.addItem(f'Key: {key} : Sec: {time}')
except Exception as e:
print(e)
# 按键映射添加按钮 @todo
def addMapButtonClicked(self):
try:
key = self.line_edit.text()
time = self.spin_box.value()
# 添加前检查是否重复,如果重复则不添加
if key in key_time_dict or key not in pyautogui.KEYBOARD_KEYS:
return
key_time_dict[key] = time
self.list_widget.addItem(f'Key: {key} : Sec: {time}')
except Exception as e:
print(e)
def statusButtonClicked(self, key):
print("statusButtonClicked")
try:
controller.on_press(key)
except Exception as e:
print(e)
def contextMenuEvent(self, event):
try:
widget = self.childAt(event.pos())
if widget == self.list_widget or widget.parent() == self.list_widget:
contextMenu = QtWidgets.QMenu(self)
delAction = contextMenu.addAction("Delete")
action = contextMenu.exec_(self.mapToGlobal(event.pos()))
if action == delAction:
current_item = self.list_widget.currentItem()
if current_item:
row = self.list_widget.row(current_item)
self.list_widget.takeItem(row)
del key_time_dict[current_item.text().split(":")[1].strip()]
else:
print("No widget found")
except Exception as e:
print(e)
class Controller:
MOUSE_STATUS_CLICK = 0
MOUSE_STATUS_PRESS = 1
def __init__(self):
self.mouse_controller = mouse.Controller()
self.mouse_pressed = False
self.keyboard_stop_flag = True
self.mouse_auto_stop_flag = True
def on_press(self, key):
try:
# 检查游戏是否运行并且是当前活动窗口
# game_windows = gw.getWindowsWithTitle(self.game_title)
# if game_windows and gw.getActiveWindow() in game_windows:
if key == keyboard.Key.f1:
if self.keyboard_stop_flag:
self.keyboard_stop_flag = False
window.statusButton.setChecked(True)
self.start_keyboard_press_key()
else:
self.keyboard_stop_flag = True
window.statusButton.setChecked(False)
elif key == keyboard.Key.f2:
# 鼠标连点
if self.mouse_auto_stop_flag:
self.mouse_auto_stop_flag = False
window.mouseStatusButton.setChecked(True)
self.start_mouse_auto_click_key(self.MOUSE_STATUS_CLICK)
else:
self.mouse_auto_stop_flag = True
window.mouseStatusButton.setChecked(False)
elif key == keyboard.Key.f3:
# 鼠标长按
if self.mouse_auto_stop_flag:
self.mouse_auto_stop_flag = False
window.mouseStatusButton.setChecked(True)
self.start_mouse_auto_click_key(self.MOUSE_STATUS_PRESS)
else:
self.mouse_auto_stop_flag = True
window.mouseStatusButton.setChecked(False)
elif key == keyboard.Key.f4:
# 按键映射
pass
elif key == keyboard.Key.f12:
mouse_pos = QCursor.pos()
global mouseX, mouseY
mouseX = mouse_pos.x()
mouseY = mouse_pos.y()
window.xPos.setText(str(mouseX))
window.yPos.setText(str(mouseY))
else:
print(f"{key} pressed")
except Exception as e:
import traceback
traceback.print_exc()
def on_release(self, key):
if key == keyboard.Key.esc:
# Stop listener when escape key is released
return False
def on_mouse_press(self, x, y, button, pressed):
if pressed:
print(f'鼠标按键{button}被按下,位置在({x}, {y})')
def on_mouse_release(self, x, y, button, pressed):
if not pressed:
print(f'鼠标按键{button}被释放,位置在({x}, {y})')
# 如果你想在鼠标按键被释放后停止监听,可以返回False:
def start_keyboard_press_key(self):
for key, interval in key_time_dict.items():
if key in pyautogui.KEYBOARD_KEYS:
print("启动线程, 按键: ", key, " 间隔: ", interval)
t = threading.Thread(target=self.press_key, args=(key, interval))
t.daemon = True # 设置为守护线程,当主线程结束时,此线程也会结束
t.start()
else:
print(f"Key: {key} is not a valid key")
def press_key(self, key, interval):
print("按键: ", key, " 间隔: ", interval)
while True:
if self.keyboard_stop_flag:
break
pyautogui.press(key)
time.sleep(interval)
def start_mouse_auto_click_key(self, status):
print("启动鼠标自动点击线程... ")
if status == self.MOUSE_STATUS_CLICK:
print(f"鼠标自动点击... delay:{window.mouseDelay.value()}")
delay = window.mouseDelay.value()
t = threading.Thread(target=self.mouse_click, args=(delay,))
t.daemon = True # 设置为守护线程,当主线程结束时,此线程也会结束
t.start()
elif status == self.MOUSE_STATUS_PRESS:
print("鼠标长按... ")
mouseC = mouse.Controller()
mouseC
pyautogui.mouseDown()
t = threading.Thread(target=self.mouse_press)
t.daemon = True
t.start()
def mouse_click(self, interval):
print("鼠标自动点击, 间隔: ", interval)
while True:
if self.mouse_auto_stop_flag:
break
# 获取鼠标当前位置
print("指定的坐标... {}, {}".format(mouseX, mouseY))
if mouseX == 0 and mouseY == 0:
mouseXx, mouseYy = pyautogui.position()
else:
mouseXx = mouseX
mouseYy = mouseY
pyautogui.click(int(mouseXx), int(mouseYy))
time.sleep(interval)
def mouse_press(self):
print("开启鼠标长按... ")
while True:
if self.mouse_auto_stop_flag:
# 释放鼠标左键并退出循环
pyautogui.mouseUp()
print("鼠标长按结束")
break
print("鼠标长按中... ")
time.sleep(0.3) # 暂停片刻,减少CPU使用率
# 启动键盘监听
def start_listener():
game_title = "Your Game Title" # 替换为你的游戏窗口标题
global controller
controller = Controller()
# 启动一个守护线程
print("启动线程监听...")
daemon = threading.Thread(target=keyboard_listener, args=(controller,))
daemon.daemon = True
daemon.start()
daemon = threading.Thread(target=mouse_listener, args=(controller,))
daemon.daemon = True
daemon.start()
def keyboard_listener(args):
print("启动线程监听键盘...")
controller = args
with keyboard.Listener(
on_press=controller.on_press,
on_release=controller.on_release) as listener:
listener.join()
def mouse_listener(args):
print("启动线程监听鼠标...")
controller = args
with mouse.Listener(
on_click=controller.on_mouse_press,
on_release=controller.on_mouse_release) as listener:
listener.join()
if __name__ == "__main__":
app = QtWidgets.QApplication([])
window = Ui()
window.setWindowTitle("按键助手")
start_listener()
app.exec_()