{"id":44695925,"url":"https://github.com/whynusn/typetype","last_synced_at":"2026-04-25T08:09:10.506Z","repository":{"id":336226677,"uuid":"1146036405","full_name":"whynusn/typetype","owner":"whynusn","description":"中文跟打器，支持 Linux Wayland 下的码长/击键统计（evdev 全局键盘监听）","archived":false,"fork":false,"pushed_at":"2026-04-24T04:42:42.000Z","size":24422,"stargazers_count":3,"open_issues_count":1,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-24T06:24:09.859Z","etag":null,"topics":["chinese-typing","evdev","fcitx","ime","keystroke-statistics","linux","pyside6","qml","type","typing-practice","typing-tutor","wayland"],"latest_commit_sha":null,"homepage":"","language":"QML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/whynusn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-30T14:40:58.000Z","updated_at":"2026-04-24T04:42:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/whynusn/typetype","commit_stats":null,"previous_names":["whynusn/typetype"],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/whynusn/typetype","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whynusn%2Ftypetype","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whynusn%2Ftypetype/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whynusn%2Ftypetype/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whynusn%2Ftypetype/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/whynusn","download_url":"https://codeload.github.com/whynusn/typetype/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/whynusn%2Ftypetype/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32254716,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T04:23:17.126Z","status":"ssl_error","status_checked_at":"2026-04-25T04:21:53.360Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chinese-typing","evdev","fcitx","ime","keystroke-statistics","linux","pyside6","qml","type","typing-practice","typing-tutor","wayland"],"created_at":"2026-02-15T08:14:24.289Z","updated_at":"2026-04-25T08:09:10.500Z","avatar_url":"https://github.com/whynusn.png","language":"QML","readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"resources/images/TypeTypeLogo.png\" alt=\"TypeType Logo\" width=\"200\" /\u003e\n  \u003ch1\u003eTypeType\u003c/h1\u003e\n  \u003cp\u003e中文打字练习 \u0026 跟打器 — 支持 \u003cb\u003e码长 / 击键 / 速度\u003c/b\u003e 专业统计，\u003cb\u003eLinux Wayland\u003c/b\u003e 原生可用\u003c/p\u003e\n  \u003cp\u003eChinese typing practice tool with keystroke statistics (码长/击键), native Linux Wayland support via evdev\u003c/p\u003e\n\n  [![Python](https://img.shields.io/badge/Python-3.12+-3776AB?logo=python\u0026logoColor=white)](https://www.python.org/)\n  [![PySide6](https://img.shields.io/badge/PySide6-QML-41CD52?logo=qt\u0026logoColor=white)](https://www.qt.io/qt-for-python)\n  [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n  [![CI](https://img.shields.io/github/actions/workflow/status/whynusn/typetype/ci.yml?branch=main\u0026label=ci)](https://github.com/whynusn/typetype/actions)\n  [![Tests](https://img.shields.io/github/actions/workflow/status/whynusn/typetype/multi-platform-tests.yml?branch=main\u0026label=tests)](https://github.com/whynusn/typetype/actions)\n  [![Ruff](https://img.shields.io/badge/style-ruff-261230?logo=ruff\u0026logoColor=white)](https://github.com/astral-sh/ruff)\n  [![uv](https://img.shields.io/badge/pkg-uv-DE5FE9?logo=python\u0026logoColor=white)](https://github.com/astral-sh/uv)\n\n  [![Linux](https://img.shields.io/badge/Linux-Wayland-449DD1?logo=linux\u0026logoColor=black)](https://github.com/whynusn/typetype)\n  [![Linux](https://img.shields.io/badge/Linux-X11-FCC624?logo=linux\u0026logoColor=black)](https://github.com/whynusn/typetype)\n  [![Windows](https://img.shields.io/badge/Windows-0078D6?logo=windows\u0026logoColor=white)](https://github.com/whynusn/typetype)\n  [![Nuitka](https://img.shields.io/badge/pack-Nuitka-2B69C3)](https://github.com/Nuitka/Nuitka)\n\n  ---\n\n\u003c/div\u003e\n\nTypeType 是一个基于 **PySide6 + QML** 的中文打字练习跟打器，提供打字圈常用的专业统计指标：\n\n- **码长**（击/字）— 每个中文字符平均消耗的按键次数\n- **击键**（击/秒）— 每秒物理按键次数\n- **速度**（字/分钟）— 每分钟输入中文字符数\n- **错误数 / 准确率 / 有效速度**\n\n\u003e **核心优势：** 通过 Linux evdev 直接读取内核键盘事件，**完全绕过 Wayland text-input-v3 协议对浏览器/应用层按键事件的屏蔽**，实现 Wayland 下真实的物理击键统计。这是目前少数能在 Wayland 上准确统计码长和击键的打字工具之一。\n\n---\n\n## 功能概览\n\n- 📊 实时 码长 / 击键 / 速度 / 错误数统计\n- 📈 字符级统计（SQLite 持久化）与薄弱字分析\n- 🏆 服务端排行榜与成绩提交\n- 📝 本地文本与网络文本统一载文\n- 🐧 Linux Wayland 原生支持（evdev 全局键盘监听）\n- 🪟 跨平台：Linux (Wayland / X11) + Windows\n\n---\n\n## 为什么 Wayland 下大部分打字工具统计不准？\n\n浏览器（Firefox / Chromium）在 Wayland 下使用 text-input-v3 协议与输入法通信。拼音输入时，**每个按键走 IME composition 流程，浏览器的 keydown/keyup 事件不为拼音按键触发**，只在 compositionend 时提交最终中文字符。因此：\n\n- ❌ 网页版跟打器（jsxiaoshi.com、91小键人等）在 Wayland 上无法统计真实击键数和码长\n- ✅ TypeType 使用 **evdev 直接读取 `/dev/input/event*`**，在物理键盘层面计数，不依赖任何显示协议\n\n\u003e 原理：evdev 是 Linux 内核的输入设备接口，在 Wayland 合成器处理键盘事件之前就能拿到原始按键数据。\n\n---\n\n## 快速开始\n\n```bash\nuv sync\nuv run python main.py\n```\n\n\u003e **联网功能说明：** 排行榜、载文等联网功能依赖 [typetype-server](https://github.com/whynusn/typetype-server) 服务端，默认配置指向 `127.0.0.1:8080`。当前服务端还存在不少安全性问题，所以 IP 暂不便公开。想体验在线服务可以联系 `whynusn@qq.com`，或者参考服务端仓库自行本地部署后修改 `config/config.example.json` 中的 `base_url`。仅使用本地打字功能则无需服务端。\n\n### Linux Wayland 权限\n\n全局键盘监听需要读取 `/dev/input/event*`，通常需要将用户加入 `input` 组：\n\n```bash\nsudo usermod -aG input $USER\n```\n\n重新登录后生效。即使没有该权限，程序也会优雅降级，不影响基础打字功能。\n\n---\n\n## 常用命令\n\n```bash\n# 运行\nuv run python main.py\n\n# 测试\nuv run pytest\n\n# 代码检查\nuv run ruff check .\nuv run ruff format --check .\n\n# 自动格式化\nuv run ruff format .\n```\n\n---\n\n## 当前技术栈\n\n| 层 | 技术 |\n|------|------|\n| 桌面 UI | PySide6 + QML + RinUI |\n| 后端语言 | Python 3.12+ |\n| 架构 | Clean Architecture + Ports \u0026 Adapters |\n| 本地持久化 | SQLite |\n| 网络请求 | httpx |\n| 包管理 | uv |\n| 击键监听 | evdev（Linux 全局键盘事件） |\n\n---\n\n## 当前项目结构（核心）\n\n```text\ntypetype/\n├── main.py\n├── docs/\n├── config/\n├── resources/\n├── src/\n│   ├── backend/\n│   └── qml/\n├── tests/\n└── RinUI/\n```\n\n### `src/backend/` 分层\n\n```text\npresentation/   # Bridge + Adapters，负责 QML/Qt 适配\napplication/    # UseCases + Gateways，负责编排与边界整合\ndomain/         # 纯业务逻辑（TypingService 计算码长/击键）\nports/          # 抽象协议\nintegration/    # Port 实现（GlobalKeyListener 读 evdev）\ninfrastructure/ # ApiClient / 网络异常等通用基础设施\nmodels/         # Entity / DTO\nworkers/        # 后台任务\n```\n\n### 击键统计链路\n\n```text\n物理按键 → evdev (/dev/input/event*) → GlobalKeyListener\n  → keyPressed 信号 → TypingAdapter.handlePressed()\n    → TypingService.accumulate_key() → SessionStat.key_stroke_count\n      → codeLength = key_stroke_count / char_count\n      → keyStroke = key_stroke_count / time\n```\n\n---\n\n## 文本来源\n\n当前默认配置中包含：\n\n- 网络来源：`jisubei`\n- 本地来源：`builtin_demo`、`fst_500`、`mid_500`、`lst_500`、`essential_single_char`\n\n配置文件示例见：`config/config.example.json`\n\n---\n\n## 日志开关\n\n默认只输出 warning 及以上日志，可通过环境变量调整：\n\n- `TYPETYPE_DEBUG=1`\n- `TYPETYPE_LOG_LEVEL=debug|info|warning|error|none`\n\n示例：\n\n```bash\nTYPETYPE_DEBUG=1 uv run python main.py\n```\n\n---\n\n## 打包（Nuitka）\n\n```bash\nuv run python -m ensurepip --upgrade\nuv pip install --upgrade nuitka --index-url https://pypi.org/simple\nuv run python -m nuitka main.py \\\n  --follow-imports \\\n  --enable-plugin=pyside6 \\\n  --include-qt-plugins=qml \\\n  --include-package=RinUI \\\n  --include-data-dir=RinUI=RinUI \\\n  --include-data-dir=config=config \\\n  --output-dir=deployment \\\n  --quiet \\\n  --noinclude-qt-translations \\\n  --standalone \\\n  --noinclude-dlls=libQt6WebEngine* \\\n  --include-data-dir=src/qml=src/qml \\\n  --include-data-dir=resources/texts=resources/texts \\\n  --include-data-files=resources/images/TypeTypeLogo.png=resources/images/TypeTypeLogo.png \\\n  --include-data-files=resources/fonts/HarmonyOS_Sans_SC_Regular-subset.ttf=resources/fonts/HarmonyOS_Sans_SC_Regular-subset.ttf \\\n  --include-data-files=resources/fonts/LXGWWenKai-Regular-subset.ttf=resources/fonts/LXGWWenKai-Regular-subset.ttf\n```\n\nWindows 建议追加：\n\n```text\n--assume-yes-for-downloads --windows-console-mode=disable --include-windows-runtime-dlls=yes --noinclude-dlls=Qt6WebEngine*\n```\n\n---\n\n## 开发者文档\n\n从 [ARCHITECTURE.md](./docs/ARCHITECTURE.md) 开始 — 快速开始、架构、数据流、陷阱全在里面。\n\n- [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) — 唯一事实来源（\"宪法\"）\n- [docs/reference/](./docs/reference/) — 配置/QML/API 速查表\n- [docs/history/](./docs/history/) — 历史设计文档归档\n- [AGENTS.md](./AGENTS.md) — AI Agent 开发约束\n\n---\n\n## 相关搜索关键词\n\n\u003e 中文打字练习, 跟打器, 码长统计, 击键统计, 打字速度测试, Wayland 打字工具, evdev 键盘监听, Linux 中文输入练习, Chinese typing practice, typing tutor, keystroke statistics, code length, typing speed test\n\n---\n\n## 致谢\n\n- [RinUI](https://github.com/RinLit-233-shiroko/Rin-UI) — Fluent Design 风格 QML 组件库（MIT License © 2025 RinLit）\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n## 许可证\n\nMIT © 2026 [whynusn](https://github.com/whynusn)\n\n\u003c/div\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwhynusn%2Ftypetype","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwhynusn%2Ftypetype","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwhynusn%2Ftypetype/lists"}