所以,今天你敲了多少下键盘?

写在前面

每到年末各大App都会给你来一次年度总结,最近突发奇想,键盘是每天必备的工具,为啥不给键盘也来个工作总结,记录一下所以每天的工作中我到底敲了多少下键盘。

分析

语言用python,实现方式那必然是要监听键盘的输入信号,然后对每个按键做统计,最后显示结果。

核心代码

查阅一下,python中有一个pynput库是专门用来做键盘、鼠标操作相关的,可以对事件进行监听,同时还可以模拟键盘、鼠标进行操作(感觉这个功能很强大,顺带成为了我后续的一个项目的解决方案)。

bash 复制代码
pip install pynput

直接装就行,示例代码如下:

python 复制代码
from pynput.keyboard import Listener

def on_press(key):
    pass

def on_release(key):
    pass


with Listener(on_press=on_press, on_release=on_release) as listener:
    listener.join()

很直观,自己实现一个on_press和on_release的方法赋给Listener对象,启动现成监听即可。其中,on_press和on_release分别代表按下和释放时的相应操作,传入的key类型为pynput内定的Key类,具体细节大家可以看源代码。

按键统计

有了核心代码之后,剩下的就是在这个基础上进行功能扩展了,先实现统计功能

python 复制代码
from pynput.keyboard import Listener

# 单个按键次数
key_counts = {}

# key格式化函数
def format_key(key):
    if hasattr(key, 'name'):
        return key.name
    elif hasattr(key, 'vk'):
        if 65 <= key.vk <= 127:
            return chr(key.vk)
        else:
            return str(key.char)

def on_press(key):
    current_key.add(key_id)
    print(key_id)

    if key_counts.get(key_id):
        key_counts[key_id] += 1
    else:
        key_counts[key_id] = 1

def on_release(key):
    pass
        
with Listener(on_press=on_press, on_release=on_release) as listener:
    listener.join()

这里我除了引入一个key_counts来计数之外,还专门写了一个key格式化的函数,因为如果debug的话就会发现,除了标准的可见字符之外,当输入类似Ctrl+A这种实际传入的是一个不可见的控制字符的十六进制编码,这里将类似的字符做了一层转换。

现在整个雏形就搞定了。

设定组合键

这个程序是要后台运行的,那么就要考虑两点,程序怎么退出?我怎么看到按键的统计?

于是乎就需要设定组合键来做一些操作。

python 复制代码
from pynput.keyboard import Listener
import time

from ui.TextDialog import create_window_with_text


# 单个按键次数
key_counts = {}

exit_cmd = {'alt_l', 'ctrl_l', 'shift', 'A'}
show_cmd = {'alt_l', 'ctrl_l', 'shift', 'space'}

current_key = set()

def format_key(key):
    if hasattr(key, 'name'):
        return key.name
    elif hasattr(key, 'vk'):
        if 65 <= key.vk <= 127:
            return chr(key.vk)
        else:
            return str(key.char)

def get_result():
    pass

def cmd_parse():
    if exit_cmd.issubset(current_key):
        get_result()
        return False

    if show_cmd.issubset(current_key):
        get_result()

    return True


def on_press(key):
    key_id = format_key(key)
    current_key.add(key_id)
    print(key_id)

    if key_counts.get(key_id):
        key_counts[key_id] += 1
    else:
        key_counts[key_id] = 1

    if not cmd_parse():
        return False


def on_release(key):
    try:
        key_id = format_key(key)
        current_key.remove(key_id)
    except KeyError:
        pass


with Listener(on_press=on_press, on_release=on_release) as listener:
    listener.join()

根据代码,我新增了组合键的功能,同时引入了current_key作为集合变量,来存储当前按住的按键。

  • Ctrl+Shift+Alt+空格:显示统计结果
  • Ctrl+Shift+Alt+A:显示统计结果并退出

值得一提的是,键盘on_press或者on_release方法默认是没有返回值的,如果返回False,则就会退出线程,进而结束程序。

那么如此一来,基础功能就有了,咱们再补充上get_result()这个用来显示统计结果的函数。

python 复制代码
...
start_time = time.time()


def time_counter(begin_time, end_time):
    # 根据传入的时间计算,通过run_time.round()函数取整
    runtime = round(end_time - begin_time)
    # 计算时分秒
    hour = runtime // 3600
    minute = (runtime - 3600 * hour) // 60
    second = runtime - 3600 * hour - 60 * minute
    # 输出
    return f'程序运行\n{hour}小时 {minute}分钟 {second}秒\n'

def get_result():

    end_time = time.time()
    counts = dict(sorted(key_counts.items(), key=lambda item: item[1], reverse=True))
    content = ""
    count = 0
    col = 0
    for k, v in counts.items():
        col += 1
        content += f"{k}: {v}\t"
        count += v
        if col == 4:
            col = 0
            content += "\n"

    current_key.clear()

    try:
        max_key = list(counts.keys())[0]
    except:
        max_key = None

    fixed = "\n" + time_counter(start_time, end_time) + f"\n你总共敲了 {count} 下键盘\n\n最多使用\n{max_key}"
    print(fixed)
    print(counts)

...

很简单就是打印一下

UI界面

控制台打印肯定不行,太low了而且还看的不直观,于是让ChatGPT简单用tkinter搞了个界面,实际效果如下:

代码如下:

python 复制代码
import tkinter as tk
from tkinter import ttk

def create_window_with_text(title, fixed_text, data):
    window = tk.Tk()
    window.title(title)

    # 设置窗口初始大小和在屏幕上居中显示
    window_width = 400
    window_height = 200
    screen_width = window.winfo_screenwidth()
    screen_height = window.winfo_screenheight()
    center_x = int(screen_width / 2 - window_width / 2)
    center_y = int(screen_height / 2 - window_height / 2)
    window.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')

    # 创建PanedWindow,分为左右两块
    paned_window = tk.PanedWindow(window, orient=tk.HORIZONTAL)
    paned_window.pack(fill=tk.BOTH, expand=1)

    # 左边的面板,设置较大的字体
    left_panel = tk.Frame(paned_window, width=100, height=400, bg='white')
    left_panel.pack_propagate(False)
    label = tk.Label(left_panel, text=fixed_text, bg='white', font=("Arial", 12))
    label.pack(side=tk.TOP, fill=tk.BOTH, padx=20)  # padx为文本增加左侧内边距
    paned_window.add(left_panel, stretch="always")

    # 右边的面板,使用Treeview作为可拖拽的列表
    right_panel = tk.Frame(paned_window, width=100, height=400)
    right_panel.pack_propagate(False)
    tree = ttk.Treeview(right_panel, columns=('Key', 'Count'), show='headings')
    tree.heading('Key', text='按键')
    tree.heading('Count', text='次数')
    tree.column('Key', width=60)  # 调整列的宽度
    tree.column('Count', width=30)
    tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)

    scrollbar = ttk.Scrollbar(right_panel, orient='vertical', command=tree.yview)
    tree.configure(yscroll=scrollbar.set)
    scrollbar.pack(side=tk.RIGHT, fill='y')

    # 将数据添加到Treeview
    for key, count in data.items():
        tree.insert('', 'end', values=(key, count))

    paned_window.add(right_panel, stretch="always")

    # 窗口保持在最前面
    window.attributes('-topmost', True)

    # 启动事件循环
    window.mainloop()

直接将get_result()函数中print()的部分调用该函数传入参数即可。

收工!

相关推荐
数据智能老司机6 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机7 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机7 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机7 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i7 小时前
drf初步梳理
python·django
每日AI新事件7 小时前
python的异步函数
python
这里有鱼汤8 小时前
miniQMT下载历史行情数据太慢怎么办?一招提速10倍!
前端·python
databook17 小时前
Manim实现脉冲闪烁特效
后端·python·动效
程序设计实验室18 小时前
2025年了,在 Django 之外,Python Web 框架还能怎么选?
python
倔强青铜三19 小时前
苦练Python第46天:文件写入与上下文管理器
人工智能·python·面试