Python使用pynput模擬實現(xiàn)鍵盤自動輸入工具
概述:當(dāng)自動化遇上可視化
在日常辦公和軟件開發(fā)中,我們經(jīng)常需要處理大量重復(fù)的文本輸入工作。傳統(tǒng)的人工輸入不僅效率低下,還容易出錯。本文將介紹如何使用Python的PyQt5庫結(jié)合pynput鍵盤控制模塊,開發(fā)一款帶可視化倒計時提示的自動輸入工具。
本工具的特色在于:
- 采用現(xiàn)代化GUI界面設(shè)計
- 輸入前提供5秒可視化倒計時
- 支持從文件導(dǎo)入文本內(nèi)容
- 實時狀態(tài)反饋機制
- 可自定義的窗口置頂功能
相比市面上其他自動化工具,我們的解決方案更加用戶友好且安全可控,特別適合以下場景:
- 自動化測試中的表單填充
- 批量數(shù)據(jù)錄入工作
- 演示時的自動輸入展示
- 需要延遲執(zhí)行的文本輸入任務(wù)
功能全景圖
核心功能矩陣
| 功能模塊 | 技術(shù)實現(xiàn)方案 | 用戶體驗亮點 |
|---|---|---|
| 文本編輯區(qū) | QTextEdit控件 | 支持大文本流暢編輯 |
| 文件導(dǎo)入 | QFileDialog+多編碼處理 | 自動識別GBK/UTF-8編碼 |
| 倒計時顯示 | QDialog+QTimer | 居中大號紅色數(shù)字 |
| 鍵盤模擬 | pynput.keyboard.Controller | 非侵入式輸入模擬 |
| 狀態(tài)反饋 | QLabel動態(tài)更新 | 表情符號+顏色狀態(tài)指示 |
技術(shù)棧深度
- PyQt5:Qt框架的Python綁定,提供豐富的GUI組件
- pynput:底層輸入設(shè)備監(jiān)控庫,支持跨平臺鍵盤控制
- QThread:實現(xiàn)后臺鍵入操作,避免界面凍結(jié)
- 信號槽機制:解耦UI與業(yè)務(wù)邏輯的關(guān)鍵設(shè)計
效果展示
主界面截圖

倒計時動效演示

使用教程
環(huán)境準備
pip install pyqt5 pynput
四步操作指南
1.文本準備階段
直接在編輯區(qū)粘貼文本
或點擊"導(dǎo)入文件"按鈕選擇TXT文件
2.參數(shù)設(shè)置
勾選"窗口置頂"保持工具在最前端
檢查文本內(nèi)容是否完整
3.執(zhí)行輸入
點擊"開始輸入"觸發(fā)5秒倒計時
倒計時結(jié)束后自動開始鍵入
4.過程控制
隨時可點擊"停止輸入"中斷操作
狀態(tài)欄實時顯示當(dāng)前進度
專業(yè)提示:倒計時期間請將光標(biāo)移動到目標(biāo)輸入位置!
核心代碼解析
1. 倒計時窗口類設(shè)計
class CountdownWindow(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
self.setStyleSheet("background-color: black;")
# 72pt超大紅色數(shù)字
font = QFont("Arial", 72, QFont.Bold)
self.countdown_label.setFont(font)
設(shè)計要點:
- 無邊框窗口確保專注度
- 黑色背景增強視覺對比
- 窗口置頂防止被遮擋
- 使用系統(tǒng)默認等寬字體保證數(shù)字顯示整齊
2. 鍵盤輸入線程
class TypeThread(QThread):
def run(self):
keyboard = Controller()
for char in self.text:
if not self._is_running: # 安全停止檢查點
break
keyboard.type(char) # 非阻塞式鍵入
關(guān)鍵技術(shù):
繼承QThread實現(xiàn)多線程
每個字符獨立鍵入保證可控性
_is_running標(biāo)志位實現(xiàn)優(yōu)雅中止
3. 狀態(tài)機管理

狀態(tài)轉(zhuǎn)換邏輯:
- 通過按鈕的enable/disable控制狀態(tài)流轉(zhuǎn)
- 統(tǒng)一的狀態(tài)欄消息格式:
[圖標(biāo)] 狀態(tài)描述 - 異常狀態(tài)自動恢復(fù)機制
源碼下載
from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout,
QPushButton, QLabel, QTextEdit, QWidget, QFileDialog,
QMessageBox, QSpinBox, QCheckBox, QDialog)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
from PyQt5.QtGui import QFont
from pynput.keyboard import Controller
import time
import sys
class CountdownWindow(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("倒計時")
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
self.setStyleSheet("background-color: black;")
layout = QVBoxLayout()
self.countdown_label = QLabel("5")
self.countdown_label.setAlignment(Qt.AlignCenter)
self.countdown_label.setStyleSheet("color: red;")
font = QFont("Arial", 72, QFont.Bold)
self.countdown_label.setFont(font)
layout.addWidget(self.countdown_label)
self.setLayout(layout)
# 設(shè)置窗口大小并居中
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()
def __init__(self, text):
super().__init__()
self.text = text
self._is_running = True
def run(self):
keyboard = Controller()
for char in self.text:
if not self._is_running:
break
keyboard.type(char)
self.finished_signal.emit()
def stop(self):
self._is_running = False
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("自動輸入工具")
self.setGeometry(100, 100, 600, 400)
# 初始化線程和倒計時窗口
self.thread = None
self.countdown_timer = QTimer()
self.countdown_seconds = 5
self.countdown_window = None
# 創(chuàng)建主部件和布局
main_widget = QWidget()
main_layout = QVBoxLayout()
# 標(biāo)題
title = QLabel("?? 自動輸入工具")
title.setAlignment(Qt.AlignCenter)
title.setStyleSheet("font-size: 20px; font-weight: bold;")
main_layout.addWidget(title)
# 說明
info = QLabel("?? 請將文本粘貼到下方或從文件導(dǎo)入")
info.setAlignment(Qt.AlignCenter)
main_layout.addWidget(info)
# 文本編輯區(qū)
self.text_edit = QTextEdit()
self.text_edit.setPlaceholderText("?? 請在此粘貼要輸入的文本...")
main_layout.addWidget(self.text_edit)
# 控制區(qū)域
control_layout = QHBoxLayout()
# 窗口置頂復(fù)選框
self.topmost_check = QCheckBox("?? 置頂")
self.topmost_check.stateChanged.connect(self.toggle_topmost)
control_layout.addWidget(self.topmost_check)
# 按鈕
btn_layout = QHBoxLayout()
self.load_btn = QPushButton("?? 導(dǎo)入文件")
self.load_btn.clicked.connect(self.load_from_file)
btn_layout.addWidget(self.load_btn)
self.start_btn = QPushButton("?? 開始輸入")
self.start_btn.clicked.connect(self.start_typing)
btn_layout.addWidget(self.start_btn)
self.stop_btn = QPushButton("? 停止輸入")
self.stop_btn.clicked.connect(self.stop_typing)
self.stop_btn.setEnabled(False)
btn_layout.addWidget(self.stop_btn)
control_layout.addLayout(btn_layout)
main_layout.addLayout(control_layout)
# 狀態(tài)欄
self.status_bar = QLabel("?? 準備就緒")
self.status_bar.setAlignment(Qt.AlignCenter)
main_layout.addWidget(self.status_bar)
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
# 樣式
self.setStyleSheet("""
QPushButton {
padding: 8px;
font-size: 14px;
}
QTextEdit {
font-size: 14px;
}
""")
# 連接倒計時定時器
self.countdown_timer.timeout.connect(self.update_countdown)
def toggle_topmost(self, state):
if state == Qt.Checked:
self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
else:
self.setWindowFlags(self.windowFlags() & ~Qt.WindowStaysOnTopHint)
self.show()
def start_countdown(self):
self.countdown_seconds = 5
self.countdown_window = CountdownWindow(self)
self.countdown_window.show()
self.countdown_timer.start(1000) # 1秒間隔
self.status_bar.setText(f"? 倒計時: {self.countdown_seconds}秒...") # 更新狀態(tài)欄
def update_countdown(self):
self.countdown_seconds -= 1
self.countdown_window.update_countdown(self.countdown_seconds)
self.status_bar.setText(f"? 倒計時: {self.countdown_seconds}秒...") # 更新狀態(tài)欄
if self.countdown_seconds <= 0:
self.countdown_timer.stop()
QTimer.singleShot(500, self.countdown_window.close) # 稍后關(guān)閉窗口
self._start_typing_after_delay()
def load_from_file(self):
file_path, _ = QFileDialog.getOpenFileName(self, "?? 打開文本文件", "", "文本文件 (*.txt);;所有文件 (*)")
if file_path:
try:
# 嘗試用UTF-8編碼打開,如果失敗則用GBK編碼
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = f.read()
except UnicodeDecodeError:
try:
with open(file_path, 'r', encoding='gbk') as f:
data = f.read()
except UnicodeDecodeError:
with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
data = f.read()
self.text_edit.setPlainText(data)
self.status_bar.setText(f"? 成功從 {file_path} 加載文本")
except Exception as e:
QMessageBox.critical(self, "? 錯誤", f"無法讀取文件: {str(e)}")
self.status_bar.setText("? 文件加載失敗")
def start_typing(self):
if not self.text_edit.toPlainText().strip():
QMessageBox.warning(self, "?? 警告", "請輸入或?qū)胛谋緝?nèi)容!")
return
self.status_bar.setText("? 準備開始輸入...")
self.start_btn.setEnabled(False)
self.stop_btn.setEnabled(True)
self.load_btn.setEnabled(False)
# 開始倒計時
self.start_countdown()
def _start_typing_after_delay(self):
text = self.text_edit.toPlainText()
self.thread = TypeThread(text)
self.thread.finished_signal.connect(self.typing_finished)
self.thread.start()
self.status_bar.setText("?? 正在輸入中...請勿操作鍵盤!")
def stop_typing(self):
if self.thread and self.thread.isRunning():
self.thread.stop()
self.thread.wait()
# 如果倒計時還在進行也停止
if self.countdown_timer.isActive():
self.countdown_timer.stop()
if self.countdown_window:
self.countdown_window.close()
self.typing_finished()
self.status_bar.setText("?? 輸入已停止")
def typing_finished(self):
self.start_btn.setEnabled(True)
self.stop_btn.setEnabled(False)
self.load_btn.setEnabled(True)
self.status_bar.setText("? 輸入完成!")
def closeEvent(self, event):
# 停止所有正在進行的操作
if self.thread and self.thread.isRunning():
self.thread.stop()
self.thread.wait()
if self.countdown_timer.isActive():
self.countdown_timer.stop()
if self.countdown_window:
self.countdown_window.close()
event.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
文件結(jié)構(gòu):
auto-typer/
├── main.py # 主程序入口
├── requirements.txt # 依賴清單
└── README.md # 項目文檔
開發(fā)心得
遇到的坑與解決方案
1.編碼問題:
現(xiàn)象:中文文本輸入亂碼
排查:發(fā)現(xiàn)pynput對Unicode支持需要特定處理
解決:在文本預(yù)處理階段統(tǒng)一轉(zhuǎn)為UTF-8
2.線程沖突:
現(xiàn)象:界面在輸入時卡頓
分析:GUI線程與輸入線程資源競爭
優(yōu)化:采用信號槽進行跨線程通信
3.焦點丟失:
現(xiàn)象:倒計時后輸入位置錯誤
方案:增加倒計時結(jié)束前的焦點檢查提示
性能優(yōu)化點
使用QTextEdit的逐行加載機制處理大文件
實現(xiàn)鍵入速度動態(tài)調(diào)節(jié)接口
添加輸入歷史記錄功能
未來擴展方向
企業(yè)級功能:
- 增加用戶權(quán)限管理系統(tǒng)
- 添加操作日志審計功能
- 支持LDAP集成認證
AI增強:
- 集成OCR識別自動輸入
- 添加語音控制接口
- 智能表單識別填充
云化部署:
- 開發(fā)WebSocket遠程控制
- 實現(xiàn)移動端APP監(jiān)控
- 增加多設(shè)備同步功能
到此這篇關(guān)于Python使用pynput模擬實現(xiàn)鍵盤自動輸入工具的文章就介紹到這了,更多相關(guān)Python自動輸入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python利用pynimate實現(xiàn)制作動態(tài)排序圖
這篇文章主要為大家詳細介紹了Python如何利用pynimate實現(xiàn)制作動態(tài)排序圖,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-02-02
解決Pycharm調(diào)用Turtle時 窗口一閃而過的問題
今天小編就為大家分享一篇解決Pycharm調(diào)用Turtle時 窗口一閃而過的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-02-02
Python數(shù)據(jù)結(jié)構(gòu)與算法之完全樹與最小堆實例
這篇文章主要介紹了Python數(shù)據(jù)結(jié)構(gòu)與算法之完全樹與最小堆,結(jié)合實例形式分析了Python完全樹定義及堆排序功能實現(xiàn)相關(guān)操作技巧,需要的朋友可以參考下2017-12-12

