当前位置:   article > 正文

python:写个简陋的按键精灵_python 按键精灵

python 按键精灵

1.介绍说明

本程序类似于按键精灵,代替用户执行重复性的的按键、输入文本、鼠标点击功能,可设置时间延迟。

示例如图:


使用流程:
1.共有ABCDEF六套方案,用户编辑任意方案
2.点击打开,可打开之前保存的方案
  点击保存,可保存方案。
  点击生成之后将不可编辑,并且开始监听热键,启动热键执行方案,结束热键均为F12
  点击修改之后可以修改,结束监听按键,按键将无法执行,修改完成点击生成
3.按键框可输入普通按键,如N,1,t等,执行时会按压此键
  按键框可输入文本,如:adsaf,123234等,执行时会输入此文本    
  按键框激活时,按压TAB 或者回车键,按键框会相应,,执行时照此执行
  按键框激活时,在按键框以外点击鼠标左键或者右键,按键框会相应显示,执行时照此执行
  延迟框可输入上次按键后需要间隔的时间,单位是秒,如:1  或者  1.3   等,输入汉字会崩溃

2、开发构思

三个功能同时工作,互相影响,所以需要三个线程,分别是

1.主线程,ui界面需要ui.show,所以一直占用一个线程,如果其他动作时间过长,会无响应

       使用qtdesigner.exe设置ui界面,然后调用,尽量多的在qtdesigner完成设置

2.监听线程,持续监听全局热键,以便控制方案的开启和关闭

        使用QThread多线程, pyqtSignal线程间传输信号.

        使用pyhooked import Hook, KeyboardEvent全局监听热键,本打算用PYHK,但是安装不了,听说pyhk也是有大佬打包好的,看来还有其他方法可以

3.自动化线程,收到接听到的信号之后,开始执行,自动化输入

         使用pyautogui#实现自动化

3.代码部分

  1. # -*- coding:utf-8 -*-
  2. import sys#读取数据文件用
  3. import time#控制按键的延迟
  4. import pyautogui#实现自动化
  5. from PyQt5.QtCore import Qt, QThread, pyqtSignal# QThread多线程, pyqtSignal线程间传输信号
  6. from PyQt5.QtGui import QDoubleValidator#延迟框只能输入数字
  7. from PyQt5.QtWidgets import QApplication, QMainWindow
  8. from PyQt5 import sip#打包时显示WARNING: Hidden import "sip" not found!,加上也没啥用
  9. from pyhooked import Hook, KeyboardEvent#全局监听热键,本打算用PYHK,但是安装不了
  10. from anjian_ui_main import Ui_MainWindow # 调用qtdesigner.exe生成的主窗口,好省事
  11. # 子线程1_执行命令,自动化线程
  12. class BackendThread(QThread):
  13. def __init__(self, e=0):
  14. super().__init__()
  15. self.e = e # 传入的按键值,F6=0,使用方案A
  16. def run(self):
  17. while 1: # 默认一直循环
  18. # 执行A方案的文本框内容
  19. for index, step in enumerate(ui.dataALL[self.e]):
  20. if step: # 若不为空
  21. if index % 2 != 1: # 除2无余数,也是就是偶数,按键信息框
  22. if len(step) == 1: # 只是1个按键,那就是按键,按压它
  23. pyautogui.press(step)
  24. elif step == "左键":#那就点击左键
  25. pyautogui.leftClick()
  26. elif step == "右键":#那就是右键
  27. pyautogui.rightClick()
  28. elif step == "tab":#那就按压tab键
  29. print(f"输入{step}")
  30. pyautogui.press("tab")
  31. elif step == "Enter":
  32. pyautogui.press("Enter")
  33. print(f"输入{step}")
  34. else:
  35. pyautogui.write(step) # 否则就是输入文本
  36. print(f"输入{step}")
  37. else: # 是时间框体
  38. time.sleep(float(step))#延迟数秒
  39. print(f"延迟{step}秒")
  40. # 若是执行一次,索引为1,退出循环
  41. if ui.comboBoxall[self.e].currentIndex() == 0:
  42. print("仅执行一次")
  43. break
  44. print("再循环一次")
  45. # 子线程2_hotkey
  46. class hotkeynew(QThread):
  47. sinOut = pyqtSignal(int) # 监听到热键后,传出的信号
  48. def run(self):
  49. def handle_events(args):
  50. if isinstance(args, KeyboardEvent):
  51. if args.current_key == "F5" and args.event_type == "key down": # 如果F5按下了,传出0,也就是方案A
  52. self.sinOut.emit(0)
  53. if args.current_key == "F6" and args.event_type == "key down":
  54. self.sinOut.emit(1)
  55. if args.current_key == "F7" and args.event_type == "key down":
  56. self.sinOut.emit(2)
  57. if args.current_key == "F8" and args.event_type == "key down":
  58. self.sinOut.emit(3)
  59. if args.current_key == "F9" and args.event_type == "key down":
  60. self.sinOut.emit(4)
  61. if args.current_key == "F10" and args.event_type == "key down":
  62. self.sinOut.emit(5)
  63. if args.current_key == "F12" and args.event_type == "key down":# 如果F12按下了,传出12,关闭线程
  64. self.sinOut.emit(12)
  65. hk = Hook()#实例化线程
  66. hk.handler = handle_events
  67. hk.hook()#启动热键监控
  68. class MainWindow(QMainWindow, Ui_MainWindow): # 多重继承QMainWindow和Ui_MainWindow
  69. def __init__(self):
  70. super(MainWindow, self).__init__() # 先调用父类QMainWindow的初始化方法
  71. self.setupUi(self) # 再调用setupUi方法
  72. # 实例化热键线程
  73. self.treadhotkey = hotkeynew()
  74. self.treadhotkey.sinOut.connect(self.doit) # 热键后发送信号给执行
  75. # 实例化执行线程
  76. self.treaddoit = BackendThread()
  77. self.dataALL = [[], [], [], [], [], []] # 用来存储6种方案
  78. self.anjianlei = [self.anjianA, self.anjianB, self.anjianC, self.anjianD, self.anjianE, self.anjianF]
  79. self.deleylei = [self.deleyA, self.deleyB, self.deleyC, self.deleyD, self.deleyE, self.deleyF]
  80. self.comboBoxall = [self.comboBox1, self.comboBox2, self.comboBox3, self.comboBox4, self.comboBox5,
  81. self.comboBox6]
  82. self.saveaction.triggered.connect(self.savenow) # 保存连接到savenow
  83. self.openaction.triggered.connect(self.opennow) # 打开连接到opennow
  84. self.finishwriteaction.triggered.connect(self.finishwrite) # 生成按键连接到finishwrite
  85. self.rewriteaction.triggered.connect(self.rewrite) # 修改按键连接到rewrite
  86. #重新定义主页面的按键,去掉焦点,否则不能输入TAB。其实可以在qtdesigner.exe设置
  87. for u in range(6): # 6种方案
  88. for i in range(8): # 8个按键
  89. self.anjianlei[u].itemAt(i).widget().setFocusPolicy(Qt.ClickFocus) # 单击成为焦点,为了tab能用
  90. self.deleylei[u].itemAt(i).widget().setFocusPolicy(Qt.ClickFocus) # 单击成为焦点
  91. self.deleylei[u].itemAt(i).widget().setValidator(QDoubleValidator()) # 时间框体只能输入数字
  92. def savenow(self): # 保存的动作
  93. self.dataALL = [[], [], [], [], [], []] # 6种方案,之前的清理掉,重新保存现在的
  94. #现在的方案都保存进去
  95. for u in range(6): # 6种方案
  96. for i in range(8): # 8个按键
  97. self.dataALL[u].append(self.anjianlei[u].itemAt(i).widget().text())
  98. self.dataALL[u].append(self.deleylei[u].itemAt(i).widget().text())
  99. file = open("anjiandata.txt", "w")#打开txt。数据较少,为了方便,习惯用txt保存数据
  100. file.write(str(self.dataALL))#写入
  101. print("写入成功")
  102. file.close()#关闭
  103. def opennow(self): # 打开之前保存的数据
  104. with open("anjiandata.txt", "r") as file:
  105. self.dataALL = eval(file.read()) # 之前保存的数据,file.read()是str格式,需要转化为list,用eval,字典转化用ast
  106. #把打开的输入输入到各个文本框
  107. for u in range(6): # 6种方案
  108. for i in range(8): # 8个按键
  109. self.anjianlei[u].itemAt(i).widget().setText(self.dataALL[u][i * 2])
  110. self.deleylei[u].itemAt(i).widget().setText(self.dataALL[u][i * 2 + 1])
  111. def finishwrite(self): # 生成之后不可写
  112. if self.focusWidget(): # 保存以后有焦点就清除
  113. self.focusWidget().clearFocus()
  114. for u in range(6): # 6种方案
  115. for i in range(8): # 8个按键
  116. self.anjianlei[u].itemAt(i).widget().setReadOnly(1) # 设置不可写
  117. self.deleylei[u].itemAt(i).widget().setReadOnly(1)# 设置不可写
  118. self.anjianlei[u].itemAt(i).widget().setFocusPolicy(Qt.NoFocus) # 不能设为焦点
  119. self.deleylei[u].itemAt(i).widget().setFocusPolicy(Qt.NoFocus) # 不能设为焦点
  120. self.dataALL[u].append(self.anjianlei[u].itemAt(i).widget().text()) # 储存下文本
  121. self.dataALL[u].append(self.deleylei[u].itemAt(i).widget().text()) # 储存下文本
  122. print("生成之后开启监控热键线程")
  123. self.treadhotkey.start()#生成之后开启监控热键线程
  124. def rewrite(self): # 重写之后可以写
  125. for u in range(6): # 6种方案
  126. for i in range(8): # 8个按键
  127. self.anjianlei[u].itemAt(i).widget().setReadOnly(0)#设置可以写
  128. self.deleylei[u].itemAt(i).widget().setReadOnly(0)#设置可以写
  129. self.anjianlei[u].itemAt(i).widget().setFocusPolicy(Qt.ClickFocus) # 设只能单击为焦点
  130. self.deleylei[u].itemAt(i).widget().setFocusPolicy(Qt.ClickFocus) # 设只能单击为焦点
  131. # 重写之后关闭监控热键线程
  132. self.treadhotkey.terminate()
  133. # 如过还有执行线程,关闭他
  134. if self.treaddoit.isRunning():
  135. self.treaddoit.terminate()
  136. print("关闭线程")
  137. # 重写鼠标事件
  138. def mousePressEvent(self, event):
  139. if event.button() == Qt.LeftButton and self.focusWidget(): # 如果左键并且有焦点
  140. self.focusWidget().setText("左键")#这个框体的文本设为左键
  141. if event.button() == Qt.RightButton and self.focusWidget():
  142. self.focusWidget().setText("右键")
  143. # 执行热键的方案,重写事件
  144. def keyPressEvent(self, event):
  145. if event.key() == Qt.Key_Tab and self.focusWidget():#如果按了tab并且有焦点
  146. self.focusWidget().setText("tab")#这个框体的文本设为tab
  147. if event.key() == 16777220 and self.focusWidget(): #如果按了回车并且有焦点
  148. self.focusWidget().setText("Enter")
  149. def doit(self, e): # e是按键的表示,F6用6表示
  150. if e == 12: # 按了F12
  151. if self.treaddoit.isRunning():#若有线程就关闭他
  152. self.treaddoit.terminate()
  153. print("关闭线程")
  154. else:
  155. pass
  156. else:
  157. # 实例化线程
  158. self.treaddoit = BackendThread(e)
  159. self.treaddoit.start()
  160. print(f"启动线程{e}")
  161. if __name__ == '__main__':
  162. app = QApplication(sys.argv)
  163. ui = MainWindow()
  164. ui.show()
  165. sys.exit(app.exec_())

附赠qtdesigner.exe生成的代码,诸君可以拿去打包,这个不需要看,打包用

  1. # -*- coding: utf-8 -*-
  2. # Form implementation generated from reading ui file 'anjian_ui_main.ui'
  3. #
  4. # Created by: PyQt5 UI code generator 5.15.6
  5. #
  6. # WARNING: Any manual changes made to this file will be lost when pyuic5 is
  7. # run again. Do not edit this file unless you know what you are doing.
  8. from PyQt5 import QtCore, QtGui, QtWidgets
  9. class Ui_MainWindow(object):
  10. def setupUi(self, MainWindow):
  11. MainWindow.setObjectName("MainWindow")
  12. MainWindow.resize(1298, 791)
  13. MainWindow.setLocale(QtCore.QLocale(QtCore.QLocale.Chinese, QtCore.QLocale.China))
  14. self.centralwidget = QtWidgets.QWidget(MainWindow)
  15. self.centralwidget.setObjectName("centralwidget")
  16. self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
  17. self.gridLayout.setObjectName("gridLayout")
  18. self.verticalLayoutA = QtWidgets.QVBoxLayout()
  19. self.verticalLayoutA.setObjectName("verticalLayoutA")
  20. self.label_15 = QtWidgets.QLabel(self.centralwidget)
  21. self.label_15.setObjectName("label_15")
  22. self.verticalLayoutA.addWidget(self.label_15)
  23. self.horizontalLayout = QtWidgets.QHBoxLayout()
  24. self.horizontalLayout.setObjectName("horizontalLayout")
  25. self.verticalLayout_19 = QtWidgets.QVBoxLayout()
  26. self.verticalLayout_19.setObjectName("verticalLayout_19")
  27. self.label = QtWidgets.QLabel(self.centralwidget)
  28. self.label.setObjectName("label")
  29. self.verticalLayout_19.addWidget(self.label)
  30. self.label_3 = QtWidgets.QLabel(self.centralwidget)
  31. self.label_3.setObjectName("label_3")
  32. self.verticalLayout_19.addWidget(self.label_3)
  33. self.label_5 = QtWidgets.QLabel(self.centralwidget)
  34. self.label_5.setObjectName("label_5")
  35. self.verticalLayout_19.addWidget(self.label_5)
  36. self.label_7 = QtWidgets.QLabel(self.centralwidget)
  37. self.label_7.setObjectName("label_7")
  38. self.verticalLayout_19.addWidget(self.label_7)
  39. self.label_9 = QtWidgets.QLabel(self.centralwidget)
  40. self.label_9.setObjectName("label_9")
  41. self.verticalLayout_19.addWidget(self.label_9)
  42. self.label_18 = QtWidgets.QLabel(self.centralwidget)
  43. self.label_18.setObjectName("label_18")
  44. self.verticalLayout_19.addWidget(self.label_18)
  45. self.label_17 = QtWidgets.QLabel(self.centralwidget)
  46. self.label_17.setObjectName("label_17")
  47. self.verticalLayout_19.addWidget(self.label_17)
  48. self.label_21 = QtWidgets.QLabel(self.centralwidget)
  49. self.label_21.setObjectName("label_21")
  50. self.verticalLayout_19.addWidget(self.label_21)
  51. self.horizontalLayout.addLayout(self.verticalLayout_19)
  52. self.anjianA = QtWidgets.QVBoxLayout()
  53. self.anjianA.setObjectName("anjianA")
  54. self.anjianA1 = QtWidgets.QLineEdit(self.centralwidget)
  55. self.anjianA1.setText("")
  56. self.anjianA1.setObjectName("anjianA1")
  57. self.anjianA.addWidget(self.anjianA1)
  58. self.anjianA2 = QtWidgets.QLineEdit(self.centralwidget)
  59. self.anjianA2.setObjectName("anjianA2")
  60. self.anjianA.addWidget(self.anjianA2)
  61. self.anjianA3 = QtWidgets.QLineEdit(self.centralwidget)
  62. self.anjianA3.setObjectName("anjianA3")
  63. self.anjianA.addWidget(self.anjianA3)
  64. self.anjianA4 = QtWidgets.QLineEdit(self.centralwidget)
  65. self.anjianA4.setObjectName("anjianA4")
  66. self.anjianA.addWidget(self.anjianA4)
  67. self.anjianA5 = QtWidgets.QLineEdit(self.centralwidget)
  68. self.anjianA5.setObjectName("anjianA5")
  69. self.anjianA.addWidget(self.anjianA5)
  70. self.anjianA6 = QtWidgets.QLineEdit(self.centralwidget)
  71. self.anjianA6.setObject
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/236598?site
推荐阅读
相关标签
  

闽ICP备14008679号