16:10起点
键盘鼠标统计:开机自启后报告生成失败
改名前夜。程序已经装进媒体分区,自启拉起的却是四小时前的旧构建。
- 根因旧构建的 make_report 把输出目录算成 dirname(__file__);在 zipapp 里它等于 ~/.cache/keymouse-stat/run.pyz——一个文件,不是目录。makedirs 直接抛 FileExistsError,界面只显示「生成失败」。AI 文件夹那份新版早就改成写 kmd.app_dir(),但自启拉起的是旧的那份。
- 修复输出目录统一走 kmd.app_dir();systemd unit 加 ExecStartPre,最多等 90 秒直到程序文件出现。原因很实在:程序装在 /dev/nvme0n1p6,没有 fstab 条目,靠 udisks 登录时挂载,而 linger 让服务开机就跑——挂载必然晚于服务。
- 修复新增 exe_file():zipapp 里 __file__ 是 xxx.pyz/kmd.py 这种包内假路径,self_cmd() 与 launch_prefix() 拼出来的启动命令根本不存在。改从 sys.argv[0] + zipfile.is_zipfile 判定。
- 重构运行形态改为 .pyz 优先。ELF 在这台机器上约 1/5 概率报 Failed to load Python shared library(KYSEC 扫描态下重新解包 40MB 会被拦);.pyz 只有 45KB,不解包,直接吃系统 python3.8 + PyQt5 5.12.8。
- 数据收敛到单一安装位,整目录从 200M+ 降到 54M。删掉旧安装、旧 run.pyz 缓存、dist、旧源码副本共四处重复。
- 验证沙箱里 /usr/bin/python3 xxx.py 被 KYSEC 拦,但 .pyz 放行。于是把 tray.py + kmd.py + 测试入口压成临时 zipapp,在 DISPLAY=:0 下真跑 PyQt5,直接调 make_report(),today/week/month/year 四个周期全部生成成功——之前几轮「GUI 无法验证」的死结就是这么解开的。
—1.1.0
改名狂键疯鼠,第一次出 deb
从「疯狂的键鼠」升级。目录重建为 源码/ + 发布/ 两层,之后所有交付都从这里走。
- 约定内部标识 APP_NAME = keymouse-stat 永不改——改了数据目录和服务名就失联;显示名只在 kmd.DISPLAY_NAME 一处改。这条约定后面救了无数麻烦。
- 新增deb 打包全链路:/opt/keymouse-stat 程序目录、/usr/bin/狂键疯鼠 命令、xdg autostart、systemd 用户服务、udev uaccess 规则、hicolor 矢量图标。
- 新增开机自启只出托盘不弹窗(tray --silent);sync_autostart() 发现系统级自启存在时主动删掉用户级,避免双开。
- 新增设备识别:/proc/bus/input/devices 加 /sys USB 厂商型号,得到型号 / VID:PID / 总线;有真键鼠时过滤掉「AT Raw Set」这类幽灵设备。
- 新增换键鼠自动归零:新设备身份要稳定 20 秒才落锤(防插拔抖动),单纯拔掉不重置,device_changes 表留档,托盘弹气泡提示。
- 移除删掉「阶段重置」,只保留「清空全部统计」,且理由必填留档。
—1.1.1
快捷方式、旧残留、报告存放位置
装完菜单里显示旧名、点了没反应。这是文件优先级打架,不是打包漏了。
- 根因旧版把 keymouse-stat.desktop 写进 ~/.local/share/applications,用户级优先于系统级,直接把 deb 装的菜单项遮蔽了——于是菜单显示旧名,点下去拉起的是已经不存在的旧路径。
- 新增shortcut 子命令:清旧菜单项、旧桌面图标、旧自启项、旧用户服务单元,然后重建桌面图标并打上 gio trusted 标记。
- 修复postinst 建 /opt/keymouse-stat/统计报告 并 chown 给安装用户(775);拿不到安装用户时退 1777。
- 坑报告目录故意不打进 deb,否则卸载时 dpkg 会因 directory not empty 报错。postrm 卸载前先把报告拷到用户目录保留,删软件不删数据。
- 坑sh 脚本在 set -e 下,[ x = y ] && cmd 判定失败返回 1 会直接退出整个脚本,一律改 if 形式。这条在 postinst 里能坑死人。
- 坑deb/control 的 Version 原来写死,改成 @VER@ 由 build_deb.sh 替换,否则改版本号要改两处、迟早不同步。
—Win11 版
Windows 11 移植版(旁支,不进 deb)
麒麟版之外临时开的一条线,用来在家里 Windows 上跑同一套统计。
- 新增平台层整体替换:evdev → WH_KEYBOARD_LL / WH_MOUSE_LL 低级钩子 + 消息泵 + 1 秒定时器;udev 授权 → 恒真;systemd → HKCU Run 注册表;flock → CreateMutexW 命名互斥体;/proc → Raw Input API 加注册表读型号;xdg-open → os.startfile。
- 复用数据库 schema、报告、查询层原样保留。热力图按名查数据,VK 名与布局表对齐即可复用。
- 坑初次清理时把 KEY_NAMES 当成死代码删了,导致 svg_keyboard 抛 NameError。恢复为「布局专用查名表」,跟 VK 映射表分开。
- 数据低级钩子拿不到设备归属,DB 里的设备名统一记「电脑」。
- 限制真 Windows 钩子回调、Raw Input 枚举、注册表写入、PowerShell 建 .lnk 本机一条都测不了,只验证了数据层和报告层,剩下的交给真机 doctor。
—1.2.2
报告口径修正:月/年汇总混进了全库累计
用户看到的「数据错位」,根子在汇总口径,不在渲染。
- 根因月/年汇总原本取全库累计再展示,区间报告里塞着历史总量,任何两个周期看起来都对不上。
- 修复改为区间内过滤。新增全部汇总卡 + 按型号汇总卡(含备注名),当前设备卡移到最前并显示备注名。
- 新增24 小时 / 每日趋势加柱状与曲线切换(双 SVG + 几行 JS,不引任何库)。
- 新增设置菜单加「统计报告存放位置」,可改目录并直接打开。
- 坑db.q1 只返回首列,要拿多列必须用 db.q。汇总卡第一版就是被这个坑的,数值全错位到下一列。
10:321.2.4
输入洞察 + 设备刷新降频
这一版在所有工作日志里都没有记录,下面三条是从 1.2.3 与 1.2.4 两个包内的 pyz 逐行比对反推出来的。
- 新增报告新增「输入洞察」:工作节奏(工作日日均 vs 周末日均)、最高频按键及其占比、键鼠配比(每点 1 次鼠标敲几个键)、时段峰值。全部从现有查询结果派生,不新增任何 SQL——报告生成速度不受影响。
- 性能设备型号解析要全量读 /proc/bus/input/devices 并开库读备注名,在麒麟 arm64 上不便宜。tray 改为每 10 轮刷一次(约 30 秒),数据本身仍然 3 秒一刷。
- 打磨doctor 的结论提示从「见上面标红的项」改成「见上面标出 [!] 的项」——不假设终端一定有色。
- 数据实测差异:kmd.py +75/−2 行,tray.py +7/−4 行,app.py +1/−1 行。没有文件增删,纯逻辑改动。
09:471.4.0
麒麟版对齐家里 Win11 版:合并 + 重写 HID++
整份报告的分水岭。kmd.py 一次跳了 2132 行。
- 重构新增组装脚本 .merge/build_kmd.py:Win11 1.4.0 底座(数据层 / 报告 / DPI / 分段重置 / 设备标签)+ 麒麟 1.2.3 的 Linux 层(evdev / systemd / 桌面),再新写一段 Linux hidraw HID++(罗技型号与 DPI 自动读)。
- 新增timing / speed / issues 三张新表;dev_tag 设备标签与分段统计。
- 数据旧数据迁移 _migrate_dev_tags:stats.dev 按行类别加「键盘 /鼠标 」前缀,meta 打幂等标记。真实库 838 行全部迁移成功,一条没丢。
- 坑组装脚本按行号切片,端点锚不唯一就会切空,全局量跟着消失,运行时 NameError。四个坑依次处理:^# ------ 换成 ^def _hexbits(、^def _hid_strings(;_logi_paired 的无参替换;A_PATH 指向备份而不是产物自身(否则脚本不能重跑)。
- 新增udev 规则补 hidraw / idVendor 046d / TAG+=uaccess——HID++ 读 DPI 没有这个权限进不去。
- 验证无头测试加 PyQt5 桩:迁移 / 新表 / 分段重置 / DPI / fetch_range 新字段 / 报告栏目 / CLI 全过。
- 坑本机 KYSEC 拦 bash build_deb.sh(脚本文件 exec),bash < build_deb.sh 管道方式才能跑。这条以后每次打包都要记得。
—1.4.0 补丁
装完没有桌面快捷方式,也没有开始菜单
同一个版本号重打了一次。问题不在包内,在安装器给的运行环境。
- 排查先证伪代码:shortcut 命令链完整,app.py 依赖的 kmd 函数全在;vermin 全量分析三个源文件,最低要求 3.5——代码在麒麟 python3.8 上没有任何兼容问题。视线转向安装环境。
- 根因图形安装器走 pkexec,postinst 里 SUDO_USER 和 logname 两个都拿不到,脚本静默跳过建图标那一段。命令行 dpkg -i 就正常,所以一直没发现。
- 修复三处加固:① 扫 /home/* 兜底找真实用户(uid ≥ 1000 且有 桌面 或 Desktop 目录);② su 调 shortcut 失败时由 root 直写桌面图标再 chown;③ 菜单文件缺失时打警告,不再静默。
- 处置用同一个版本号重打。用户端应急办法:终端跑 疯键狂鼠 shortcut,或 sudo dpkg -i 重装一遍;菜单缓存没刷新就注销重登。
10:121.4.1
去 Win 残留 + 性能优化
用户要的「去掉 win 版代码和无用代码,提高效率」。静态分析翻出四个一调用就崩的名字。
- 修复symtable 静态分析抓出 4 个组装时被切丢的名字:UNIT / AUTOSTART / UDEV_RULE_TMPL / GRANT_SCRIPT 四个模板常量,加 default_report_path。等于授权、开机自启、默认报告路径这三条路一调用就 NameError——只是没走到那儿。
- 重构删 Win 残留:RUN_KEY 注册表自启块、VK_NAMES、app_path / child_env、os.startfile 分支、Raw Input 措辞;再删 CAT_WHEELS / KEY_STUCK_SEC / FS_TITLE 死代码。kmd.py 定在 6292 行。
- 性能device_snapshot 加 3 秒缓存。托盘每 3 秒刷设备卡,原来每次都重开库,200 次调用 0.234s → 0s。
- 性能删掉每 5 秒一次的 wal_checkpoint(TRUNCATE)。实测与 commit+close 几乎无差别,唯一作用是白白截断 WAL 文件,纯负担。
- 性能新增 idx_stats_cat_day / idx_stats_dev 两个索引,报表按分类按天、按设备的聚合不再全表扫。
- 修复托盘单实例锁原来是 Win 命名互斥体,Linux 分支直接 return True——等于没锁。改成 flock 锁 ~/.cache/keymouse-stat/tray.lock,实测第二个实例被拦。
- 修复demo 数据改用 _VK2KEY,VK → Linux 键码 78 个全映射,之前 28 个映射导致演示数据里一堆 ? 键名。
- 约定工具留档在 .merge/:audit2.py(symtable 查未定义引用)、deadcode.py(死函数死常量)、test_cleanup.py(模板常量 / demo / 缓存 / 锁 的回归)。
16:501.4.2
图标接入 + hicolor 多尺寸通道(未发布,已删除)
这一版我越界了:用户还没确认就把图标换进了软件。包在下一轮被删掉。
- 打包deb/keymouse-stat.svg 换成 v3;build_deb.sh 新增 hicolor 16~512 全套 PNG 通道——UKUI 的桌面、任务栏、菜单各取不同尺寸,部分场景只认 PNG,矢量图读不出来。
- 图标按用户要求重排:鼠标从「与键盘底边齐平的右侧」下沉到键盘右下角,全局重新配平,键鼠净空 3.3 格。
- 坑发布/疯键狂鼠.pyz 是陈年拷贝,build_deb 从不刷新它。校验版本要看 源码/dist/ 或包内 pyz,不能看发布目录那个文件——它当时还停在 1.4.1。
- 处置用户随后澄清要的是「重叠」而不是「并排偏下」,构图整个重做;这个 1.4.2 包直接删除,不对外留。教训:确认之前不动软件。
17:391.4.3
叠放构图定稿 + 整体方正化(后被打包取代)
鼠标压在键盘右下角、有重叠,不是并排。线稿叠放的技术难点在这一版解决。
- 图标键盘加宽到 43 格、鼠标缩到 14 格,重叠约 8 格宽 × 15 格高,右下探出一条边。纯放框里像键盘的部件,纯放外面又退回并排——六成在框内、四成在外才对。
- 图标线稿叠放必然穿线。解法:背景渐变改成 gradientUnits=userSpaceOnUse 用整幅画布坐标,鼠标内部填同一个渐变,颜色与背景严丝合缝,看起来就是「盖住了」。用默认的 objectBoundingBox 会跟背景错开,一眼假。
- 图标键盘 USB 线从顶部引出、右转横穿上方,插头右缘与鼠标右缘同列。整体方正化:键盘外框圆角 3→1.4、键帽 0.9→0.4,鼠标从蛋形改圆角矩形 + 方形滚轮 + 一道直腰线。
- 坑透明底版本填不了背景色,只能用白色挡片:浅色界面看不出,深色界面上鼠标内部会显白一块。深色场景只能用绿底版——这是叠放构图的固有代价。
- 处置校验做了四道:包内 SVG 含新线缆走向与方正鼠标、包内 pyz 版本号、64px 位图与 SVG 渲染结果像素级一致、hicolor 下 31 个条目。包在下一轮被 rm 掉。
18:051.4.4
托盘 / 关于 / 报告图标统一
用户一句话点破:「托盘、关于和报告里没有更换图标」。查下去是两个完全不同的问题。
- 根因托盘和关于对话框里的图标是 tray.py 里纯代码手画的旧键盘图形,跟 deb 装的图标文件是两套东西,改资源文件当然不生效;报告页眉则压根没放图标。
- 重构make_icon 改为优先读系统 hicolor PNG(256 → 128 → 64 → 48 → 32,最后才 SVG),原手绘降级成 _draw_icon 兜底,只在便携运行、系统里没装图标时启用;加 _ICON_CACHE 缓存。位图优先是刻意的——有些环境缺 QtSvg 插件,读 SVG 会拿到空图。
- 新增报告页眉加 30px 圆角 logo,浏览器标签加 favicon,都以 base64 内嵌进 HTML——报告仍然是单文件,拷到别的机器照样能看。找不到图标文件时自动退化成纯文字标题。
- 打包所有改动落在组装脚本 .merge/build_kmd.py 的补丁里。kmd.py 和 tray.py 都是它的产物,直接改会被下次组装覆盖。
- 坑重跑组装后 kmd.py 行号 +1(多了 import base64),按行号 sed 改版本号会静默落空,打出来的包版本还是旧的。改用整行匹配 s/^APP_VERSION = "x.y.z"$/.../。
- 坑KYSEC 拦 .py 直接执行,PyQt5 测试必须 python3 -m zipapp 打成包再跑;另外 /tmp 在沙箱每次调用间隔离,临时文件一律放项目目录并设 TMPDIR。
- 验证离屏 make_icon(64):读系统 256px 图标缩放后非空 ✓,把图标路径置空后手绘兜底也正常 ✓;报告页眉 logo 与 favicon 就位 ✓;包内 pyz 版本 1.4.4 ✓。