python写的自动按键和鼠标连点。源码分享,一起学习。
自己用python写的自动按键和鼠标自动点击。分享一下源码和成品,比较干净的,缺点就是是python打包有点大50多M
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 = 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 = 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.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_()
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>wwwww</class>
<widget class="QMainWindow" name="wwwww">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>500</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>40</x>
<y>80</y>
<width>173</width>
<height>31</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>按键:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineName"/>
</item>
<item>
<widget class="QPushButton" name="Add">
<property name="text">
<string>添加</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget_2">
<property name="geometry">
<rect>
<x>40</x>
<y>30</y>
<width>171</width>
<height>51</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>F1按键开关</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget_3">
<property name="geometry">
<rect>
<x>40</x>
<y>110</y>
<width>97</width>
<height>31</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>延迟:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox"/>
</item>
</layout>
</widget>
<widget class="QListWidget" name="listWidget">
<property name="geometry">
<rect>
<x>40</x>
<y>140</y>
<width>101</width>
<height>73</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="statusButton">
<property name="geometry">
<rect>
<x>140</x>
<y>110</y>
<width>73</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
<widget class="QPushButton" name="mouseStatusButton">
<property name="geometry">
<rect>
<x>360</x>
<y>110</y>
<width>73</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget_4">
<property name="geometry">
<rect>
<x>260</x>
<y>110</y>
<width>97</width>
<height>31</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>延迟:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="mouseDelay"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget_5">
<property name="geometry">
<rect>
<x>260</x>
<y>80</y>
<width>173</width>
<height>31</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>X:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="xPos"/>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Y:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="yPos"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget_6">
<property name="geometry">
<rect>
<x>260</x>
<y>30</y>
<width>224</width>
<height>51</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>F2鼠标连点F3鼠标长按 F12采集坐标 </string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QListWidget" name="listWidgetMap">
<property name="geometry">
<rect>
<x>40</x>
<y>380</y>
<width>101</width>
<height>73</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="mapStatusButton">
<property name="geometry">
<rect>
<x>140</x>
<y>350</y>
<width>73</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget_7">
<property name="geometry">
<rect>
<x>40</x>
<y>350</y>
<width>97</width>
<height>31</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>映射:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="toKey"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget_8">
<property name="geometry">
<rect>
<x>40</x>
<y>320</y>
<width>173</width>
<height>31</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>按键:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="fromKey"/>
</item>
<item>
<widget class="QPushButton" name="AddMap">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>添加</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget_9">
<property name="geometry">
<rect>
<x>40</x>
<y>270</y>
<width>171</width>
<height>51</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>F4按键映射</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
成品链接:链接:https://pan.baidu.com/s/1T3cpJ62nksrI9oPah2Xy_Q?pwd=59sz
提取码:59sz
--来自百度网盘超级会员V5的分享
WangWhereGo 发表于 2023-7-27 14:56
亲测能用,但是貌似出了个bug f2启动之后停不掉了, 于是把鼠标移动到软件右上角让他把自己干掉就ok了
应该是按键冲突 本帖最后由 aakgbb 于 2023-7-27 23:07 编辑
感觉分享,我之前也想过用python写,后面找了pygui,pywin好像是这两模块学,后来发现这两模块好久没更新了,然后还是用易来写了。用习惯了易,想转其它语言还是有些不习惯。而且打包出来也挺小的估计不会超过1M 十分有用,非常感谢。 亲测能用,但是貌似出了个bug f2启动之后停不掉了, 于是把鼠标移动到软件右上角让他把自己干掉就ok了
学习{:1_893:}{:1_893:}十分有用,非常感谢。 不错,必须点赞 WangWhereGo 发表于 2023-7-27 14:56
亲测能用,但是貌似出了个bug f2启动之后停不掉了, 于是把鼠标移动到软件右上角让他把自己干掉就ok了
再按F2就可以关闭,如果不能关闭的话。界面上有个状态按钮,点击一下,也能关闭。 学习了感谢分享 tk做界面会小一些,qt打包的就是大