使用python来保存键盘输入情况,可保存到sqlite3数据库

ops/2024/10/22 13:32:52/

1.代码单次保存最大键盘输入数目是300,全局变量可改

2、在gui界面可以设置单次保存的名字,方便下次查找,录入数据库

3. gui界面有串口选择按钮,需要有硬件串口转hid模块ch9329的,可以直接发送串口数据来实现模拟键盘输入.  没有硬件的直接注释即可.

好了, 不说多,直接上代码

ch9329的github地址

ch9329 github

python">import sys
import threading
import sqlite3
from PyQt5.QtWidgets import (QApplication, QComboBox,QWidget, QPushButton,QHBoxLayout, QVBoxLayout, QLineEdit, QLabel, QTextEdit)
from pynput import keyboard
from serial import Serial  # 串口模块
import serial.tools.list_ports  # 用于列出本地可用的串口from ch9329 import keyboard as ch9329Keyboard
from ch9329 import mouse
from ch9329.config import get_manufacturer
from ch9329.config import get_product
from ch9329.config import get_serial_number# 定义全局变量来存储键盘事件
key_events = []
MAX_EVENTS = 5 * 60  # 最大事件数量# 定义键盘事件处理函数
def on_press(key):if len(key_events) < MAX_EVENTS:key_events.append(('pressed', str(key)))def on_release(key):if len(key_events) < MAX_EVENTS:key_events.append(('released', str(key)))if str(key) == 'Key.esc':  # 如果按下的是Esc键,停止监听return False# 启动键盘监听器的函数
def start_listener():with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:listener.join()# 保存数据到文件
def save_to_file():with open('key_events.txt', 'w') as file:for event in key_events:file.write(f"{event[0]} {event[1]}\n")# 将数据保存到 SQLite 数据库
def save_to_database(name):if not name:return# 连接到 SQLite 数据库(如果不存在则创建)conn = sqlite3.connect('key_events.db')cursor = conn.cursor()# 创建表格(如果不存在)cursor.execute('''CREATE TABLE IF NOT EXISTS events (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,event_type TEXT,key TEXT)''')# 插入数据for event in key_events:cursor.execute('''INSERT INTO events (name, event_type, key)VALUES (?, ?, ?)''', (name, event[0], event[1]))# 提交事务并关闭连接conn.commit()conn.close()# 查找数据库中的数据
def find_in_database(name):if not name:return "Please enter a name."# 连接到 SQLite 数据库conn = sqlite3.connect('key_events.db')cursor = conn.cursor()# 查询匹配的记录cursor.execute('''SELECT * FROM events WHERE name = ?''', (name,))results = cursor.fetchall()# 关闭连接conn.close()if results:return '\n'.join([f"{row[1]} - {row[2]} - {row[3]}" for row in results])else:return "No records found."# 删除数据库中的数据
def delete_from_database(name):if not name:return "Please enter a name."# 连接到 SQLite 数据库conn = sqlite3.connect('key_events.db')cursor = conn.cursor()# 查询并删除匹配的记录cursor.execute('''SELECT * FROM events WHERE name = ?''', (name,))results = cursor.fetchall()if results:cursor.execute('''DELETE FROM events WHERE name = ?''', (name,))conn.commit()conn.close()return f"Deleted {len(results)} records for name: {name}"else:conn.close()return "No records found to delete."# 串口功能:打开串口
def open_serial(com_port, baud_rate):global serial_porttry:serial_port = Serial(com_port, baud_rate)return f"Serial port {com_port} opened at {baud_rate} baud."except Exception as e:return f"Failed to open serial port: {str(e)}"# 获取本地可用的串口
def get_available_ports():ports = serial.tools.list_ports.comports()return [port.device for port in ports]# 串口功能:关闭串口
def close_serial():global serial_portif serial_port and serial_port.is_open:serial_port.close()return "Serial port closed."else:return "No serial port is open."# GUI 窗口类
class KeyboardListenerApp(QWidget):def __init__(self):super().__init__()self.initUI()self.parse_res = []def initUI(self):# 创建 UI 元素self.start_button = QPushButton('Start Listening', self)self.save_button = QPushButton('Save Data', self)self.find_button = QPushButton('Find Data', self)self.delete_button = QPushButton('Delete Data', self)  # 增加删除按钮self.open_serial_button = QPushButton('Open Serial', self)  # 打开串口按钮self.close_serial_button = QPushButton('Close Serial', self)  # 关闭串口按钮self.name_edit = QLineEdit(self)self.name_edit.setPlaceholderText("Enter your name")self.query_edit = QLineEdit(self)self.query_edit.setPlaceholderText("Enter name to search")self.results_area = QTextEdit(self)self.results_area.setReadOnly(True)self.send_serial_button = QPushButton('SendSerialData', self)  # 发送串口数据按钮# 串口选择和波特率选择self.com_port_select = QComboBox(self)self.baud_rate_select = QComboBox(self)self.baud_rate_select.addItems(["9600", "19200", "38400", "57600", "115200"])# 获取可用的串口self.update_ports()# 创建布局namelayout = QHBoxLayout()layout = QVBoxLayout()namelayout.addWidget(QLabel("Name:"))namelayout.addWidget(self.name_edit)layout.addLayout(namelayout)layout.addWidget(self.start_button)layout.addWidget(self.save_button)Searchnamelayout = QHBoxLayout()Searchnamelayout.addWidget(QLabel("Search Name:"))Searchnamelayout.addWidget(self.query_edit)layout.addLayout(Searchnamelayout)layout.addWidget(self.find_button)layout.addWidget(self.delete_button)  # 增加删除按钮到布局layout.addWidget(QLabel("Results:"))layout.addWidget(self.results_area)# add串口配置布局serial_layout = QHBoxLayout()serial_layout.addWidget(QLabel("COM Port:"))serial_layout.addWidget(self.com_port_select)serial_layout.addWidget(QLabel("Baud Rate:"))serial_layout.addWidget(self.baud_rate_select)layout.addLayout(serial_layout)layout.addWidget(self.open_serial_button)layout.addWidget(self.close_serial_button)layout.addWidget(self.send_serial_button)self.setLayout(layout)# 设置窗口属性self.setWindowTitle('Keyboard Listener')self.setGeometry(300, 300, 600, 400)# 绑定按钮事件self.start_button.clicked.connect(self.start_listening)self.save_button.clicked.connect(self.save_data)self.find_button.clicked.connect(self.find_data)self.delete_button.clicked.connect(self.delete_data)  # 绑定删除按钮事件self.open_serial_button.clicked.connect(self.open_serial)self.close_serial_button.clicked.connect(self.close_serial)# 绑定按钮事件self.send_serial_button.clicked.connect(self.send_serial_data)def update_ports(self):"""更新可用的串口列表"""available_ports = get_available_ports()self.com_port_select.clear()self.com_port_select.addItems(available_ports)# 如果没有可用串口,禁用“Open Serial”按钮if not available_ports:self.open_serial_button.setEnabled(False)else:self.open_serial_button.setEnabled(True)def _send_serialdata(self,res,port):import timeif res is None:returnif len(res) == 0:returnfor i in res:ch9329Keyboard.press_and_release(port, i,min_interval=0.2,max_interval=0.3)time.sleep(0.5)def send_serial_data(self):global serial_portif serial_port and serial_port.is_open:"""发送串口数据"""send_thread = threading.Thread(target=self._send_serialdata, args=(self.parse_res, serial_port), daemon=True)send_thread.start()def start_listening(self):# 创建并启动一个新的线程来运行键盘监听器listener_thread = threading.Thread(target=start_listener, daemon=True)listener_thread.start()def save_data(self):name = self.name_edit.text()if key_events:# 使用线程来保存数据到文件和数据库save_thread = threading.Thread(target=self.save_data_in_background, args=(name,), daemon=True)save_thread.start()def save_data_in_background(self, name):# 在后台线程中保存数据save_to_file()save_to_database(name)print("Data saved successfully.")def parse_and_execute(self,result):res = []"""解析查找结果并执行按键事件"""# 将结果按行拆分lines = result.splitlines()print("解析查找结果并执行按键事件.")for line in lines:# 分割每行的内容parts = line.split(" - ")if len(parts) >= 3:action = parts[1]  # "pressed" 或 "released"key = parts[2]     # 键值('a' 或者 Key.ctrl_l)# 去除多余的引号,例如 'a' -> akey = key.strip("'")if len(key) >= 3:key = key.strip("Key.")# 执行键盘操作if action == 'pressed':#print(key)res.append(key)#keyboard_controller.press(key)#elif action == 'released':#keyboard_controller.release(key)else:print("len < 3.")return resdef find_data(self):name = self.query_edit.text()result = find_in_database(name)self.results_area.setText(result)self.parse_res = self.parse_and_execute(result)def delete_data(self):name = self.query_edit.text()result = delete_from_database(name)self.results_area.setText(result)def open_serial(self):com_port = self.com_port_select.currentText()baud_rate = int(self.baud_rate_select.currentText())result = open_serial(com_port, baud_rate)self.results_area.setText(result)def close_serial(self):result = close_serial()self.results_area.setText(result)
# 主函数
def main():app = QApplication(sys.argv)ex = KeyboardListenerApp()ex.show()sys.exit(app.exec_())if __name__ == '__main__':main()


http://www.ppmy.cn/ops/111338.html

相关文章

swoole协程 是单线程的,还是多线程的

Swoole 协程本质上是单线程的&#xff0c;但它可以在多个线程中运行。因此&#xff0c;Swoole 协程既可以看作是单线程的&#xff0c;也可以在多线程的环境下运行&#xff0c;这取决于你如何使用 Swoole。 理解 Swoole 协程的运行模式 1 单线程中的协程&#xff1a; 在一个单…

javase复习day22泛型、set、数据结构

泛型 package MyGenerics;import java.util.ArrayList; import java.util.Iterator;public class GenericsTest1 {public static void main(String[] args) {//没有泛型的情况ArrayList list new ArrayList();//所有数据都被认为是Object类型&#xff0c;都可以加入集合中list…

C/C++——野指针处理

在C++中,“野指针”(dangling pointer)指的是指向已释放或无效内存的指针。使用野指针可能导致程序崩溃或产生未定义行为。避免野指针的关键在于确保指针始终指向有效内存。下面是一些避免野指针的方法和最佳实践: 1、释放内存后置空指针 当释放掉分配的动态内存后,将指…

Logstash 配置Java日志格式的方法

Logstash 是用于日志收集的开源工具&#xff0c;通常与 Elasticsearch 和 Kibana 一起使用&#xff0c;形成 ELK Stack&#xff08;现在称为 Elastic Stack&#xff09;。Logstash 非常灵活&#xff0c;可以通过配置文件&#xff08;通常是 .conf 文件&#xff09;来定义数据的…

阿里P8和P9级别有何要求

阿里巴巴的P8和P9级别&#xff0c;代表着公司的资深技术专家或管理者岗位&#xff0c;要求候选人具有丰富的职业经历、深厚的技术能力以及出色的领导力。以下是对P8和P9级别的要求、考察点以及准备建议的详细分析。 P8 级别要求 1. 职业经历&#xff1a; 8年以上的工作经验&a…

企业应该如何安全上网,软件防查盗版,企业防盗版

随着信息化的发展&#xff0c;企业日常办公越来越依赖互联网。终端以及普通PC终端在访问互联网过程中&#xff0c;会遇到各种各样不容忽视的风险&#xff0c;例如员工主动故意的数据泄漏&#xff0c;后台应用程序偷偷向外部发信息&#xff0c;木马间谍软件的外联&#xff0c;以…

KubeCon China 回顾|快手的 100% 资源利用率提升:从裸机迁移大规模 Redis 到 Kubernetes

大家下午好&#xff0c;我是来自 ApeCloud 的吴学强&#xff0c;非常高兴能够在 KubeCon 做分享。今天的分享由我和来自快手的刘裕惺同学共同完成&#xff0c;我们分享的主题是将大规模的 Redis 实例从裸机迁移到 Kubernetes 上来提高资源的利用率。 我们今天的议题包括几个方…

JVM基础概念

一、JVM概述 1. 为什么要学习JVM&#xff1f; 线上系统突然宕机&#xff0c;系统⽆法访问&#xff0c;甚⾄直接 OOM &#xff1b; 线上系统响应速度太慢&#xff0c;优化系统性能过程中发现 CPU 占⽤过⾼&#xff0c;原因是因为 JVM 的 GC 次 数过于频繁&#xff1b; 新项⽬…