【python项目推荐】键盘监控--统计打字频率

原文:https://greptime.com/blogs/2024-03-19-keyboard-monitoring
代码:https://github.com/GreptimeTeam/demo-scene/tree/main/keyboard-monitor

项目简介

该项目实现了打字频率统计及可视化功能。
在这里插入图片描述

主要使用的库

pynput:允许您控制和监视输入设备。 这里我们用来获取键盘输入。
SQLAlchemy:数据库操作。 这里我们用来保存键盘输入。
streamlit:提供可视化界面。

项目组成

agent.py :获得键盘输入
display.py:可视化

补充说明

如果你不想用原文的数据库,也可以替换为本地的数据库,如免安装的sqlite

agent.py

# agent.py
from dotenv import load_dotenv
from pynput import keyboard
from pynput.keyboard import Keyimport concurrent.futures
import logging
import os
import queue
import sqlalchemy
import sqlalchemy.exc
import sys
import timeMODIFIERS = {Key.shift, Key.shift_l, Key.shift_r,Key.alt, Key.alt_l, Key.alt_r, Key.alt_gr,Key.ctrl, Key.ctrl_l, Key.ctrl_r,Key.cmd, Key.cmd_l, Key.cmd_r,
}TABLE = sqlalchemy.Table('keyboard_monitor',sqlalchemy.MetaData(),sqlalchemy.Column('hits', sqlalchemy.String),sqlalchemy.Column('ts', sqlalchemy.DateTime),
)if __name__ == '__main__':load_dotenv()log = logging.getLogger("agent")log.setLevel(logging.DEBUG)formatter = logging.Formatter('%(asctime)s %(levelname)s %(funcName)s %(message)s')file_handler = logging.FileHandler(f'agent-{time.time_ns()}.log', encoding='utf-8')file_handler.setLevel(logging.DEBUG)file_handler.setFormatter(formatter)stdout_handler = logging.StreamHandler(sys.stdout)stdout_handler.setLevel(logging.INFO)stdout_handler.setFormatter(formatter)log.addHandler(file_handler)log.addHandler(stdout_handler)#engine = sqlalchemy.create_engine(os.environ['DATABASE_URL'], #                                  echo_pool=True, #                                  isolation_level='AUTOCOMMIT')engine = sqlalchemy.create_engine("sqlite:///keyboard.db")current_modifiers = set()pending_hits = queue.Queue()cancel_signal = queue.Queue()def on_press(key):if key in MODIFIERS:current_modifiers.add(key)else:hits = sorted([ str(key) for key in current_modifiers ]) + [ str(key) ]hits = '+'.join(hits)pending_hits.put(hits)log.debug(f'{key} pressed, current_modifiers: {current_modifiers}')def on_release(key):if key in MODIFIERS:try:current_modifiers.remove(key)except KeyError:log.warning(f'Key {key} not in current_modifiers {current_modifiers}')log.debug(f'{key} released, current_modifiers: {current_modifiers}')#with engine.connect() as connection:#    connection.execute(sqlalchemy.sql.text("""#        CREATE TABLE IF NOT EXISTS keyboard_monitor (#            hits STRING NULL,#            ts TIMESTAMP(3) NOT NULL,#            TIME INDEX ("ts")#        ) ENGINE=mito WITH( regions = 1, ttl = '3months')#    """))# ...from sqlalchemy import create_engine, Table, Column, String, TIMESTAMP, MetaData, Indexmetadata = MetaData()keyboard_monitor = Table('keyboard_monitor', metadata,Column('hits', String, nullable=True),Column('ts', TIMESTAMP, nullable=False),)metadata.create_all(engine)def sender_thread():retries = 0while True:hits = pending_hits.get()log.debug(f'got: {hits}')if hits is None:log.info("Exiting...")breakwith engine.connect() as connection:try:log.debug(f'sending: {hits}')connection.execute(TABLE.insert().values(hits=hits, ts=sqlalchemy.func.now()))connection.commit()# ...log.info(f'sent: {hits}')retries = 0except sqlalchemy.exc.OperationalError as e:if retries >= 10:log.error(f'Retry exceeds. Operational error: {e}')pending_hits.put(hits)continueif e.connection_invalidated:log.warning(f'Connection invalidated: {e}')pending_hits.put(hits)continuemsg = str(e)if "(1815, 'Internal error: 1000')" in msg:# TODO 1815 - should not handle internal error;# see https://github.com/GreptimeTeam/greptimedb/issues/3447log.warning(f'Known operational error: {e}')pending_hits.put(hits)continueelif '2005' in msg and 'Unknown MySQL server host' in msg:log.warning(f'DNS temporary unresolved: {e}')pending_hits.put(hits)continueraise efinally:retries += 1def listener_thread():with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:log.info("Listening...")cancel_signal.get()pending_hits.put(None)log.info("Exiting...")with concurrent.futures.ThreadPoolExecutor() as executor:sender = executor.submit(sender_thread)listener = executor.submit(listener_thread)try:f = concurrent.futures.wait([sender, listener], return_when=concurrent.futures.FIRST_EXCEPTION)for fut in f.done:log.error(f'Unhandled exception for futures: {fut.exception(timeout=0)}')except KeyboardInterrupt as e:log.info("KeyboardInterrupt. Exiting...")except Exception as e:log.error(f'Unhandled exception: {e}')finally:cancel_signal.put(True)

display.py

# display.py
import datetime
import os
from dotenv import load_dotenv
import pytz
import streamlit as st
import tzlocal
import pandasst.title("Keyboard Monitor")load_dotenv()
#conn = st.connection(
##    type="sql",
#    url="sqlite:///keyboard.db",
#)conn = st.connection('keyboard', type='sql', url="sqlite:///keyboard.db")df = conn.query("SELECT COUNT(*) AS total_hits FROM keyboard_monitor")
st.metric("Total hits", df.total_hits[0])most_frequent_key, most_frequent_combo = st.columns(2)
df = conn.query("""
SELECT hits, COUNT(*) as times
FROM keyboard_monitor
WHERE hits NOT LIKE '%+%'
GROUP BY hits
ORDER BY times DESC limit 1;
""")
most_frequent_key.metric("Most frequent key", df.hits[0])
df = conn.query("""
SELECT hits, COUNT(*) as times
FROM keyboard_monitor
WHERE hits LIKE '%+%'
GROUP BY hits
ORDER BY times DESC limit 1;
""")
most_frequent_combo.metric("Most frequent combo", df.hits[0])top_frequent_keys, top_frequent_combos = st.columns(2)
df = conn.query("""
SELECT hits, COUNT(*) as times
FROM keyboard_monitor
WHERE hits NOT LIKE '%+%'
GROUP BY hits
ORDER BY times DESC limit 10;
""")
top_frequent_keys.subheader("Top 10 keys")
top_frequent_keys.dataframe(df)
df = conn.query("""
SELECT hits, COUNT(*) as times
FROM keyboard_monitor
WHERE hits LIKE '%+%'
GROUP BY hits
ORDER BY times DESC limit 10;
""")
top_frequent_combos.subheader("Top 10 combos")
top_frequent_combos.dataframe(df)st.header("Find your inputs frequency of day")
local_tz = tzlocal.get_localzone()
hours = int(local_tz.utcoffset(datetime.datetime.now()).total_seconds() / 3600)
if hours > 0:offset = f" + INTERVAL '{hours} hours'"
elif hours < 0:offset = f" - INTERVAL '{hours} hours'"
else:offset = ''
d = st.date_input("Pick a day:", value=datetime.date.today())
query = f"""
SELECT ts,COUNT(1) AS times
FROM keyboard_monitor
WHERE strftime('%Y-%m-%d', ts, 'localtime') = '{d}'
GROUP BY strftime('%Y-%m-%d %H:00:00', ts)
ORDER BY ts ASC
LIMIT 10;
"""df = conn.query(query)
#print(df.keys())
df['ts'] = pandas.to_datetime(df['ts'])
df['ts'] = df['ts'].dt.tz_localize(pytz.utc).dt.tz_convert(local_tz)
st.dataframe(df)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/2090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【多线程】synchronized原理 | 锁升级| 锁消除 | 锁粗化 | 信号量 | CountDownLatch

文章目录 一、synchronized原理synchronized属于哪种锁&#xff1f; 1.锁升级偏向锁&#xff1a; 2.锁消除3.锁粗化锁的粒度 二、信号量 Semaphore三、CountDownLatch1.await方法2.countDown方法 一、synchronized原理 synchronized属于哪种锁&#xff1f; ​ 在初始情况下&am…

【oceanbase】安装ocp,ocp部署oceanbase

https://www.oceanbase.com/docs/common-ocp-1000000000584989 资源 iphostnamecpumem组件192.168.0.71obnode-000-071816oceanbase-ce192.168.0.72obnode-000-072816oceanbase-ce192.168.0.73obnode-000-073816oceanbase-ce192.168.0.74obproxy-000-07424obproxy-ce192.168.0…

【Java EE】网络初识

目录 1.网络发展史 2.局域网LAN 2.1组建方式 2.1.1基于网线直连 2.1.2基于集线器组建 2.1.3基于交换机组建 2.1.4基于交换机和路由器组建 3.广域网WAN 4.网络通信基础 4.1 IP地址 4.1.1概念 4.1.2格式 4.1.3端口号 4.1.3.1概念 4.1.3.2格式 4.2认识协议 4.2.1概…

Qt 跨平台开发的一丢丢总结

Qt 跨平台开发 文章目录 Qt 跨平台开发摘要第一 \ & /第二 神奇{不能换行显示第三 预处理宏 关键字&#xff1a; Qt、 win、 linux、 lib、 MSVC 摘要 最近一直在琢磨Qt跨平台开发的问题&#xff0c;缘由有以下几个&#xff0c; 首先第一个&#xff0c;我们目前开发…

医院敏感文件交互 如何保障安全和效率?

医院会产生大量的敏感文件&#xff0c;这些敏感文件交互时&#xff0c;都需要使用特殊的手段&#xff0c;来保障数据的安全性。 医院的敏感数据主要包括以下几类&#xff1a; 1、患者基本信息&#xff1a;包括患者的姓名、身份证号码、户籍地或现住址、联系方式、文化程度、既…

【数据结构】二叉树链式结构的实现《遍历,实现》(题库+解析+源码)

前言 二叉树的学习离不开对堆的理解&#xff0c;这是上篇堆的传送门 http://t.csdnimg.cn/F6Jp3 1.二叉树链式结构的实现 1.1 前置说明 在学习二叉树的基本操作前&#xff0c;需先要创建一棵二叉树&#xff0c;然后才能学习其相关的基本操作。由于现在大家对二 叉树结构掌握还…

【LLM】向量知识库

文章目录 认识向量知识库向量Embeddings向量数据库向量数据库的作用向量数据库与传统数据库的区别 Embedding API使用公有Embedding API自定义一个Embeedding API 常见文本数据的预处理搭建并使用向量数据库思考向量数据库在LLM中的价值体现向量的妙用&#xff0c;可行&#xf…

gcc,软硬链接和制作动静态库

gcc的操作 预处理 gcc -E file.c -o file.i -E选项表示预处理完就停下来&#xff0c;在编译时-o file.i可以省略&#xff0c;编译器会默认生成同名的.i文件 编译 gcc -S file.i -o file.s -s表示生成完汇编码就停下来&#xff0c;在编译时-o file.s可以省略&#xff0c;编…

kaggle电子邮件分类xgboost建模可视化模型评估混淆矩阵范例

目录 概述 依赖环境 代码解读 库的导入 数据读取 扇形图可视化统计 词云图可视化 分布条形图可视化 数据预处理 划分数据集 模型训练 模型预测和评估 ROC曲线评估 混淆矩阵评估 多维度交叉评估 配套源码和数据集 xgboost邮件分类配套数据集和源码下载地址 概述…

DenseDiffusion:Dense Text-to-Image Generation with Attention Modulation

1 研究目的 该文献的研究目的主要是&#xff1a; 探讨一种更为广泛的调制方法&#xff0c;通过设计多个正则化项来优化图像合成过程中的空间控制。论文的大致思想是&#xff0c;在现有的基于数据驱动的图像合成系统基础上&#xff0c;通过引入更复杂的调制策略&#xff0c;实现…

pip下载包opencv出错(报错failed building wheel for opencv-python解决方法)

文章目录 1 报错2 原因3 解决方法参考 1 报错 ERROR: Could not build wheels for opencv-python, which is required to install pypr2 原因 版本不兼容的问题,当使用pip install opencv-python命令安装的是最新版本&#xff0c;当前python版本不支持。需要安装当前版本pyth…

认识产品经理

一、合格的产品经理 1、什么是产品 解决某个问题的东西&#xff0c;称为产品 键盘可以打字&#xff0c;想喝水了可以用水壶&#xff0c;在超市想找一款扫把会有导购员服务 产品有颜色、大小等等区别&#xff0c;也有有形和无形的区别 2、什么是产品经理 想清楚怎么设计产品…

Leetcode - 周赛394

目录 一&#xff0c;3120. 统计特殊字母的数量 I 二&#xff0c;3121. 统计特殊字母的数量 II 三&#xff0c;3122. 使矩阵满足条件的最少操作次数 四&#xff0c;3123. 最短路径中的边 一&#xff0c;3120. 统计特殊字母的数量 I 本题就是统计有多少个字母的大小写同时出现…

Kimi Chat四大更新详细解读!模型能力提升,支持语音输入输出!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

SpringBoot集成Sharding-JDBC实现主从同步

SpringBoot集成Sharding-JDBC实现主从同步 1.mysql主从配置2.application.properties文件配置3.测试3.1 查询数据3.2 添加数据 1.mysql主从配置 详细内容请参考上一篇文章&#xff1a;MySQL8.0以上实现主从同步配置 2.application.properties文件配置 # ShardingSphere conf…

阿斯达年代记怎么下载 阿斯达年代记三强争霸下载教程

阿斯达年代记怎么下载 阿斯达年代记三强争霸下载教程 阿斯达年代记是一款三国争霸类型的游戏&#xff0c;在游戏中大家可以体验到三权争霸的刺激场景&#xff0c;在战场中大家不仅可以体验到体验到文化交织还可以感受到战场的残酷&#xff0c;本期小编将会给大家带来阿斯达年代…

基于vue+node+mysql的视频校对系统

一、登录注册&#xff1a;包括登录&#xff0c;注册&#xff0c;忘记密码&#xff0c;验证码等常用点。 二、用户管理&#xff1a;包括用户的增删改查 三、权限管理&#xff08;请增加这个权限&#xff1a;任务分配——只有管理者才能发布和删除任务&#xff1b;管理员设置。 四…

R语言绘制动态网络图Network教程WGCNA

今天分享的笔记是使用NetworkD3对WGCNA的共表达网络进行可视化&#xff0c;创建交互式动态网络图&#xff0c;展示基因之间的相互关系&#xff0c;可以用于转录组或者其他调控网络展示。 加权基因共表达网络分析 (WGCNA, Weighted correlation network analysis)是用来描述不同…

MQTT服务器EMQX的安装和使用(Windows)

一、下载地址&#xff1a; 下载 EMQX 二、安装环境&#xff1a; Windows Server2016 16G 500G 三、启动服务&#xff1a; 下载文件解压后放入以下目录&#xff08;注意&#xff0c;目录名一定是英文&#xff0c;否则会造成启动不成功&#xff01;&#xff09;&#xff1a…

mybatis与mybatisplus

mybatis 基本使用 整合springboot 1.添加依赖 2.添加配置 spring:# 数据源相关配置datasource:username: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver#时区必须配置否则报错,注意数据库名切换为自己的数据库名称url: jdbc:mysql://127.0.0.1/ithei…