Python+PyQt5开发一个智能键盘模拟输入器(附整体源码)
作者:创客白泽
在当今数字化办公时代,自动化工具已经成为提高工作效率的重要利器,今天我要向大家介绍一款基于PyQt5和pynput库开发的智能键盘模拟输入器,感兴趣的小伙伴可以了解下
概述
在当今数字化办公时代,自动化工具已经成为提高工作效率的重要利器。今天我要向大家介绍一款基于PyQt5和pynput库开发的智能键盘模拟输入器——AQUA INPUT(测试可适用于学某通)。
开发背景
在日常工作和学习中,我们经常会遇到需要重复输入相同内容的场景:
- 批量数据录入
- 模板邮件发送
- 聊天机器人回复
- 测试数据填充
传统的手工输入方式不仅效率低下,而且容易出错。AQUA INPUT应运而生,它通过模拟真实键盘输入的方式,实现了文本内容的自动化输入,大大提升了工作效率。
技术栈
- GUI框架:PyQt5
- 输入模拟:pynput.keyboard
- 界面风格:赛博朋克主题
- 多线程处理:QThread
- 动画效果:QPropertyAnimation
功能特性
视觉设计
核心功能
功能模块 | 图标 | 描述 | 技术特点 |
---|---|---|---|
数据输入 | 📝 | 支持多种数据导入方式 | 多编码文件读取、剪贴板集成 |
参数配置 | ⚙️ | 灵活的输入参数调整 | 滑块控制、实时预览 |
进度监控 | 📊 | 实时显示执行状态 | 多线程进度更新、统计信息 |
安全控制 | ⏹️ | 紧急停止机制 | 线程安全中断、状态恢复 |
工作流程
界面展示
主界面设计
设计亮点:
- 分区明确:数据输入、系统配置、执行进度三大功能区
- 色彩协调:深色背景搭配青色主题,保护视力
- 动态反馈:按钮悬停效果、进度条动画
- 响应式布局:自适应窗口大小变化
特色组件展示
1. 自定义标题栏
class CustomTitleBar(QWidget): def __init__(self, parent): super().__init__(parent) # 实现无边框窗口的自定义拖动功能
特点:
- 渐变背景效果
- 支持窗口拖动
- 自定义最小化/最大化/关闭按钮
- 与主界面风格一致
2. 赛博风格控件
class CyberButton(QPushButton): def __init__(self, text, parent=None): super().__init__(text, parent) # 实现动态发光效果
动画效果:
- 鼠标悬停发光
- 渐变边框
- 平滑过渡动画
3. 倒计时窗口
功能:
- 全屏居中显示
- 数字渐变效果
- 窗口置顶显示
使用教程
第一步:数据准备
- 直接输入:在主文本框中直接输入需要自动输入的内容
- 剪贴板导入:点击📋 剪贴板导入按钮从系统剪贴板获取内容
- 文件加载:点击📂 文件加载按钮从文本文件导入数据
提示:支持多种文件编码格式(UTF-8、GBK、GB2312等)
第二步:参数配置
参数项 | 推荐设置 | 说明 |
---|---|---|
输入速度 | 0.05-0.1秒/字符 | 根据目标应用程序响应速度调整 |
启动延迟 | 3-5秒 | 给予足够时间定位光标 |
窗口置顶 | ✅ 开启 | 避免窗口切换中断输入 |
倒计时界面 | ✅ 开启 | 可视化倒计时提示 |
第三步:执行输入
- 定位光标:将输入光标移动到目标应用程序的输入框
- 启动程序:点击🚀 启动输入序列按钮
- 等待倒计时:程序显示倒计时,此时不要操作键盘鼠标
- 自动输入:程序开始自动输入文本内容
- 完成提示:输入完成后显示状态提示
第四步:异常处理
- 紧急停止:任何时候点击⏹️ 紧急停止按钮可立即中断输入
- 状态恢复:程序中断后会自动恢复控件状态
- 进度保存:中断时已输入的进度会保留在进度条中
高级技巧
代码深度解析
1. 架构设计
# 核心类关系图 classDiagram class MainWindow { -QTextEdit text_edit -TypeThread thread -QProgressBar progress_bar +start_typing() +stop_typing() } class TypeThread { -str text -float speed +run() +stop() } class CustomTitleBar { -QPushButton close_btn +mousePressEvent() +mouseMoveEvent() } MainWindow --> TypeThread MainWindow --> CustomTitleBar
2. 多线程输入核心
class TypeThread(QThread): update_signal = pyqtSignal(str) finished_signal = pyqtSignal() def run(self): keyboard = Controller() total_chars = len(self.text) for i, char in enumerate(self.text): if not self._is_running: break keyboard.type(char) progress = int((i + 1) / total_chars * 100) self.progress_signal.emit(progress) if self.speed > 0: time.sleep(self.speed)
关键技术点:
- 线程安全:使用标志位控制线程退出
- 信号通信:通过pyqtSignal实现线程与UI通信
- 精确控制:可调节的输入速度参数
- 进度反馈:实时更新进度条和状态信息
3. 界面主题系统
def set_aqua_theme(self): """设置青色赛博朋克主题""" self.setStyleSheet(""" QMainWindow { background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #1a1a1a, stop:0.5 #2a2a2a, stop:1 #1a1a1a); color: #00ffff; border: 1px solid #00ffff; border-radius: 8px; } """)
样式特点:
- CSS-like语法:使用Qt样式表实现复杂效果
- 渐变背景:线性渐变营造科技感
- 圆角边框:现代化界面设计
- 色彩系统:统一的青色主题色
4. 资源管理机制
def get_resource_path(relative_path): """获取资源的绝对路径,兼容开发环境和打包后环境""" try: base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") # 多路径查找策略 path = os.path.join(base_path, relative_path) if not os.path.exists(path): # 尝试在当前目录和上级目录查找 current_dir_path = os.path.join(os.path.abspath("."), relative_path) if os.path.exists(current_dir_path): return current_dir_path return path
兼容性设计:
- 打包支持:同时支持开发环境和PyInstaller打包
- 多路径查找:自动在多个位置查找资源文件
- 优雅降级:资源缺失时不影响主要功能
5. 动画效果实现
class CyberButton(QPushButton): def __init__(self, text, parent=None): super().__init__(text, parent) self._glow = 0 self.setMouseTracking(True) def animate_glow(self, target): animation = QPropertyAnimation(self, b"glow") animation.setDuration(300) animation.setStartValue(self._glow) animation.setEndValue(target) animation.setEasingCurve(QEasingCurve.OutCubic) animation.start()
动画技术:
- 属性动画:使用QPropertyAnimation实现平滑过渡
- 事件响应:鼠标悬停触发动画效果
- 性能优化:使用合适的动画时长和缓动函数
源码下载
import os import sys from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QTextEdit, QWidget, QFileDialog, QMessageBox, QSpinBox, QCheckBox, QDialog, QDoubleSpinBox, QGroupBox, QProgressBar, QScrollArea,QSizePolicy, QSlider) from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QPropertyAnimation, QEasingCurve from PyQt5.QtGui import QFont, QIcon, QPalette, QColor, QLinearGradient, QPainter from PyQt5.QtCore import pyqtProperty from pynput.keyboard import Controller import time def get_resource_path(relative_path): """获取资源的绝对路径,兼容开发环境和打包后环境""" try: base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") path = os.path.join(base_path, relative_path) # 如果找不到文件,尝试在多个位置查找 if not os.path.exists(path): # 尝试在当前目录查找 current_dir_path = os.path.join(os.path.abspath("."), relative_path) if os.path.exists(current_dir_path): return current_dir_path # 尝试在上级目录查找 parent_dir_path = os.path.join(os.path.abspath(".."), relative_path) if os.path.exists(parent_dir_path): return parent_dir_path return path class TitleBarButton(QPushButton): def __init__(self, text, parent=None): super().__init__(text, parent) self.setFixedSize(30, 25) self.setStyleSheet(""" QPushButton { background-color: rgba(80, 80, 80, 200); border: 1px solid #00ffff; border-radius: 3px; color: #00ffff; font-size: 10px; font-weight: bold; } QPushButton:hover { background-color: rgba(100, 100, 100, 200); } QPushButton:pressed { background-color: rgba(120, 120, 120, 200); } """) class CloseButton(TitleBarButton): def __init__(self, parent=None): super().__init__("✕", parent) self.setStyleSheet(""" QPushButton { background-color: rgba(80, 80, 80, 200); border: 1px solid #00ffff; border-radius: 3px; color: #00ffff; font-size: 12px; font-weight: bold; } QPushButton:hover { background-color: rgba(255, 0, 0, 100); border: 1px solid #ff0000; color: #ffffff; } QPushButton:pressed { background-color: rgba(200, 0, 0, 150); } """) class MinimizeButton(TitleBarButton): def __init__(self, parent=None): super().__init__("—", parent) class MaximizeButton(TitleBarButton): def __init__(self, parent=None): super().__init__("□", parent) class CyberLabel(QLabel): def __init__(self, text, parent=None): super().__init__(text, parent) self._glow_intensity = 0 self.glow_animation = QPropertyAnimation(self, b"glow_intensity") self.glow_animation.setDuration(2000) self.glow_animation.setLoopCount(-1) self.glow_animation.setStartValue(0) self.glow_animation.setEndValue(100) self.glow_animation.start() def get_glow_intensity(self): return self._glow_intensity def set_glow_intensity(self, value): self._glow_intensity = value self.update() glow_intensity = pyqtProperty(int, get_glow_intensity, set_glow_intensity) def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) # 青色主题 gradient = QLinearGradient(0, 0, self.width(), 0) base_color = QColor(0, 255, 255) # 青色 glow_color = QColor(0, 200, 200, 150 + self._glow_intensity) gradient.setColorAt(0, base_color) gradient.setColorAt(0.5, glow_color) gradient.setColorAt(1, base_color) painter.setPen(QColor(0, 255, 255)) painter.setFont(self.font()) painter.drawText(self.rect(), Qt.AlignCenter, self.text()) class CyberButton(QPushButton): def __init__(self, text, parent=None): super().__init__(text, parent) self._glow = 0 self.setMouseTracking(True) def enterEvent(self, event): self.animate_glow(50) super().enterEvent(event) def leaveEvent(self, event): self.animate_glow(0) super().leaveEvent(event) def animate_glow(self, target): animation = QPropertyAnimation(self, b"glow") animation.setDuration(300) animation.setStartValue(self._glow) animation.setEndValue(target) animation.setEasingCurve(QEasingCurve.OutCubic) animation.start() def get_glow(self): return self._glow def set_glow(self, value): self._glow = value self.update() glow = pyqtProperty(int, get_glow, set_glow) def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) # 灰色背景,青色边框 bg_color = QColor(60, 60, 60, 220) # 深灰色 painter.fillRect(self.rect(), bg_color) # 青色边框 border_color = QColor(0, 255, 255, 60 + self._glow) painter.setPen(border_color) painter.drawRect(1, 1, self.width()-2, self.height()-2) # 青色文字 text_color = QColor(0, 255, 255) painter.setPen(text_color) painter.setFont(self.font()) painter.drawText(self.rect(), Qt.AlignCenter, self.text()) class CyberSpinBox(QSpinBox): def __init__(self, parent=None): super().__init__(parent) self.setStyleSheet(""" QSpinBox { background-color: rgba(80, 80, 80, 200); border: 1px solid #00ffff; border-radius: 4px; color: #00ffff; padding: 5px; font-size: 12px; selection-background-color: #00ffff; selection-color: #000; } QSpinBox:focus { border: 1px solid #00cccc; } QSpinBox::up-button, QSpinBox::down-button { background-color: #00ffff; border: none; width: 15px; border-radius: 2px; } QSpinBox::up-button:hover, QSpinBox::down-button:hover { background-color: #00cccc; } QSpinBox::up-arrow, QSpinBox::down-arrow { width: 8px; height: 8px; color: #000; } """) class CyberDoubleSpinBox(QDoubleSpinBox): def __init__(self, parent=None): super().__init__(parent) self.setStyleSheet(""" QDoubleSpinBox { background-color: rgba(80, 80, 80, 200); border: 1px solid #00ffff; border-radius: 4px; color: #00ffff; padding: 5px; font-size: 12px; selection-background-color: #00ffff; selection-color: #000; } QDoubleSpinBox:focus { border: 1px solid #00cccc; } QDoubleSpinBox::up-button, QDoubleSpinBox::down-button { background-color: #00ffff; border: none; width: 15px; border-radius: 2px; } QDoubleSpinBox::up-button:hover, QDoubleSpinBox::down-button:hover { background-color: #00cccc; } QDoubleSpinBox::up-arrow, QDoubleSpinBox::down-arrow { width: 8px; height: 8px; color: #000; } """) class CyberSlider(QSlider): def __init__(self, orientation=Qt.Horizontal, parent=None): super().__init__(orientation, parent) self.setStyleSheet(""" QSlider::groove:horizontal { border: 1px solid #00ffff; height: 8px; background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #1a1a1a, stop:0.5 #2a2a2a, stop:1 #1a1a1a); border-radius: 4px; } QSlider::handle:horizontal { background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #00ffff, stop:0.5 #00cccc, stop:1 #00ffff); border: 1px solid #00ffff; width: 18px; margin: -5px 0; border-radius: 9px; } QSlider::handle:horizontal:hover { background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #00cccc, stop:0.5 #00aaaa, stop:1 #00cccc); border: 1px solid #00cccc; } QSlider::sub-page:horizontal { background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #00ffff, stop:0.5 #00cccc, stop:1 #00ffff); border-radius: 4px; } """) class CountdownWindow(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("倒计时") self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) self.setStyleSheet(""" background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #2a2a2a, stop:0.5 #3a3a3a, stop:1 #2a2a2a); border: 2px solid #00ffff; border-radius: 10px; """) layout = QVBoxLayout() self.countdown_label = QLabel("5") self.countdown_label.setAlignment(Qt.AlignCenter) self.countdown_label.setStyleSheet(""" color: #00ffff; font-size: 72px; font-weight: bold; font-family: 'Arial'; background: transparent; """) layout.addWidget(self.countdown_label) self.setLayout(layout) self.resize(200, 200) self.move_to_center() def move_to_center(self): screen = QApplication.primaryScreen().geometry() x = (screen.width() - self.width()) // 2 y = (screen.height() - self.height()) // 2 self.move(x, y) def update_countdown(self, seconds): self.countdown_label.setText(str(seconds)) if seconds <= 0: self.close() class TypeThread(QThread): update_signal = pyqtSignal(str) finished_signal = pyqtSignal() status_signal = pyqtSignal(str) progress_signal = pyqtSignal(int) def __init__(self, text, speed=0.05): super().__init__() self.text = text self.speed = speed self._is_running = True def run(self): keyboard = Controller() total_chars = len(self.text) for i, char in enumerate(self.text): if not self._is_running: break keyboard.type(char) progress = int((i + 1) / total_chars * 100) self.progress_signal.emit(progress) status_text = f"正在输入: {i+1}/{total_chars} 字符" self.status_signal.emit(status_text) if self.speed > 0: time.sleep(self.speed) self.finished_signal.emit() def stop(self): self._is_running = False class CyberTextEdit(QTextEdit): def __init__(self, parent=None): super().__init__(parent) self.setStyleSheet(""" QTextEdit { background-color: rgba(80, 80, 80, 200); border: 2px solid #00ffff; border-radius: 8px; color: #00ffff; font-size: 14px; padding: 10px; selection-background-color: #00ffff; selection-color: #000; } QTextEdit:focus { border: 2px solid #00cccc; } """) class CyberCheckBox(QCheckBox): def __init__(self, text, parent=None): super().__init__(text, parent) self.setStyleSheet(""" QCheckBox { color: #00ffff; font-size: 12px; spacing: 5px; } QCheckBox::indicator { width: 15px; height: 15px; border: 1px solid #00ffff; background-color: rgba(80, 80, 80, 200); } QCheckBox::indicator:checked { background-color: #00ffff; } QCheckBox::indicator:hover { border: 1px solid #00cccc; } """)
项目结构
AQUA-INPUT/
├── main.py # 主程序文件
├── icon.ico # 应用程序图标
├── requirements.txt # 依赖包列表
├── README.md # 项目说明文档
└── examples/ # 使用示例
├── sample_texts/ # 示例文本
└── config_examples/ # 配置示例
环境要求
# Python 3.7+ pip install PyQt5==5.15.7 pip install pynput==1.7.6
快速开始
克隆代码:
git clone https://gitee.com/your-repo/aqua-input.git cd aqua-input
安装依赖:
pip install -r requirements.txt
运行程序:
python main.py
打包发布
# 使用PyInstaller打包 pyinstaller --onefile --windowed --icon=icon.ico --name="AQUA_INPUT" main.py
总结与展望
技术总结
AQUA INPUT项目展示了多个重要的软件开发技术:
- 现代GUI开发:使用PyQt5创建美观的用户界面
- 多线程编程:正确处理UI响应与后台任务的协调
- 自动化控制:通过pynput实现系统级输入模拟
- 项目打包:支持从开发到分发的完整流程
实际应用价值
- 办公自动化:提升重复性文字工作的效率
- 软件测试:自动化测试用例的数据输入
- 游戏辅助:合法的游戏内文本输入(如聊天宏)
- 教育培训:演示键盘输入过程的工具
未来扩展方向
扩展功能规划
- 脚本引擎:支持Python脚本控制输入流程
- 插件系统:允许第三方扩展功能
- 云配置同步:用户配置的多设备同步
- 多语言支持:国际化界面和文档
- 使用统计:用户行为分析和优化建议
到此这篇关于Python+PyQt5开发一个智能键盘模拟输入器(附整体源码)的文章就介绍到这了,更多相关Python键盘模拟输入内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!