Skip to content

whyb/PinYinIME

Repository files navigation

极简拼音输入法 (PinyinIME)

为什么会有这个项目

受够了某狗输入法。

弹窗广告铺天盖地,关都关不掉——关闭按钮小得跟蚂蚁似的,点歪了直接弹出一整个浏览器窗口。这还不算完,用着用着发现电脑上莫名其妙多了一堆根本没装过的软件:某狗桌面壁纸、某狗浏览器、某某垃圾清理工具……我保证不是我装的,我绝对没有点过任何"安装"按钮。某狗在后台一声不吭就给你塞进来,跟小偷没什么两样。

这种流氓行径必须谴责。一个输入法而已,凭什么监听你的键盘、统计你的词频、扫描你的硬盘、把你的输入习惯上传到它们服务器?凭什么弹广告、装全家桶?

于是就有了这个项目——一个极简的拼音输入法,开源,不需要联网,隐私完全可控。没有广告,没有后台,没有全家桶,更没有藏在角落里的"推荐安装"。核心代码一千行出头,无任何第三方库依赖,干净透明,每一行都看得见。

功能上也没含糊:支持全拼/简拼、模糊音(z/zh、c/ch、s/sh、n/l、f/h、en/eng、in/ing)、繁简体一键切换(2000+ 字符映射 + 词汇级消歧 + 两岸 IT 术语差异)、用户自定义词库、词频自动学习、DP 拼音分割(输入 haiyoumeiyou 自动拆成「还有没有」)、多皮肤配色、候选词数量可调……该有的都有。

一句话:我的输入法,我做主。

使用实录

gif

特性

🚫 反流氓

  • 零联网: 不联网、不上传、不收集隐私
  • 零广告: 没有弹窗,没有推广,永远不会有
  • 零捆绑: 不安装任何第三方软件
  • 代码可审计: 开源,核心代码一千余行,每个人都能看

🎯 核心输入

  • 全拼 / 简拼: 支持完整拼音和首字母缩写(nh → 你好)
  • DP 拼音分割: 输入长串拼音自动拆成词组(haiyoumeiyou → 还有没有)
  • 内置词库: 基于 rime-ice 词典,直接加载原版 YAML 格式,46,000+ 单字,540,000+ 词组,480,000+ 简拼
  • 可配置热键: 切换热键支持 Alt+Shift / Ctrl+Shift / Right Shift / Ctrl+Space
  • 系统注册: 可注册为系统输入法,设置开机自启,集成到 Windows 语言栏
  • 用户词库: 自学习,自动记录选词频率,越用越顺手
  • 词频动态调整: 每次选择自动 +1 频率,下次优先显示

🎨 外观

  • 预设皮肤: 6 款配色(默认浅灰、简约白、深邃黑、护眼绿、暖米黄、清爽蓝)
  • 自定义配色: 通过取色器自由选择主色调,自动生成整套配色
  • 候选词数量: 5-9 个可调
  • 字体大小: 12-36px 可调
  • 横排 / 竖排: 候选框自由切换
  • 微软雅黑: 设置界面统一使用微软雅黑字体

🔧 高级功能

  • 模糊音: 支持 7 组模糊音(z/zh、c/ch、s/sh、n/l、f/h、en/eng、in/ing)
  • 繁简体转换: 2000+ 字符映射 + 180 词汇级消歧 + 40 两岸 IT 术语
    • 一简对多繁智能消歧(如「发」→「發/髮」、「后」→「後/后」)
    • 最长词匹配优先策略
  • 智能拼音纠错: 自动识别常见拼写错误
  • 中文标点: 自动转换 ,。!?——「」
  • 设置窗口: 纯 Win32 手写 UI,无资源文件依赖
  • 用户词典管理: 可视化增删改查

🖥️ 技术亮点

  • UIAutomation 光标检测: 精准定位文本输入光标,候选框绝不挡字
  • PageUp / PageDown 翻页: 除了 -/=,也支持 PageUp/PageDown
  • ⚙ 设置按钮: 候选框上可直接点击齿轮图标打开设置

编译

环境要求

  • Windows 8+
  • Visual Studio 2019+

方式一:CMake

cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
cd build && PinyinIME.exe

方式二:build.bat

VS2012 Developer Command Prompt 中:

cd D:\codes\github\InputMethod
build.bat

编译产出一个 PinyinIME.exe,静态链接 CRT,无需安装任何运行时,拷贝到哪跑到哪。


使用方法

  1. 运行 PinyinIME.exe(需管理员权限
  2. Ctrl+Shift(默认,可在设置中修改)切换中英文模式
  3. 中文模式下输入拼音:
    • 空格 确认第一个候选
    • 数字 1-9 选择对应候选
    • EnterShift 将拼音字母直接上屏(不选候选)
    • - /PageUp / PageDown 翻页
    • Backspace 删除最后一个字母
    • Escape 清空输入
    • 点击 图标打开设置
  4. Ctrl+Shift 切回英文模式

💡 打开设置 → 点击「📌 注册输入法到系统」可将 PinyinIME 注册为系统输入法,并设为开机自启。


文件说明

文件 行数 说明
main.cpp ~1180 主程序:键盘钩子、拼音引擎、候选窗口、文本注入、UIA 光标检测、拼音分割
settings.h ~1140 设置系统:设置窗口 UI、皮肤管理、用户词典对话框、系统注册
s2t_data.h ~810 简繁转换:2000+ 字符映射 + 词汇消歧 + 两岸 IT 术语
dictionary.h ~230 词库加载器:直接读取 rime-ice 原版 YAML 词库,支持字符→拼音自动注音、简拼生成
trie_dict.h ~100 前缀树 (Trie) 内存数据库:26 分支固定数组,O(L+M) 前缀查找
trie_dict.cpp ~170 TrieDict 实现:插入、精确查找、前缀搜索(带深度限制)、遍历
CMakeLists.txt ~85 CMake 构建脚本
build.bat ~40 一键编译脚本
rime-ice/ - rime-ice 词库(git submodule),cn_dicts/ 目录在构建时自动复制到输出目录
user.dict - 用户自学习词库(运行时自动生成)

TrieDict 高性能前缀树内存数据库

节点结构

每个节点 216 字节,固定 26 子节点指针(a-z),无哈希、无碰撞:

     ┌───────────────────────────────────────────────┐
     │              TrieNode (216 bytes)              │
     │                                               │
     │  children[26]:  TrieNode* 数组 (208 bytes)     │
     │  ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐   │
     │  │ a │ b │ c │ d │ e │ f │ g │ h │ i │ j │...│   │
     │  └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘   │
     │    ↓   ↓   ↓   ↓   ↓           ↓               │
     │  ...  ... ... ... ...         ...              │
     │                                               │
     │  entries:  vector<Entry>* (8 bytes)            │
     │    仅终端节点非空 ← 避免空 vector 浪费          │
     └───────────────────────────────────────────────┘

索引: ch - 'a' 直接定位,一条 mov 指令完成,比 std::unordered_map 哈希快 3-5 倍。

拼音键存储示例

                        [root]
                    /    |    \            ← 26 分支
                   a     b     c   ...
                  /      |
                 n      ban ───── terminal ──── [办 956075]  ← 已按词频降序
                /                [半 663254]
               g                 [版 432109]
              /                  [班 321098]
           ang ── terminal       [般 210987]
          [昂 38921]             ...
          [肮 12340]
         /
    xiang ── terminal
    [想 500000]
    [向 450000]              ← 向量中词条已按 freq 降序
    [像 400000]
    [象 350000]
    /
   xian                              ← 非终端节点 (entries=nullptr)
      \
       z                              ← 非终端节点
         \
          ai ── terminal ──── [现在 501033]
              [先在   8234]
              [贤才   1230]
            \
             ao ── terminal ──── [先造   500]

键空间: ~50k 拼音键 (xianzai, jintian, zhongguo...), 全部由小写字母 a-z 组成。

前缀查找过程 (输入 "xianz")

1. 沿树走到前缀节点 ───────────────── O(5) 步
   
   root → x → i → a → n → z
                           ↑
                      当前节点 (非终端)

2. DFS 收集子树所有终端词条 ───────── O(M) 节点
   
                      z               ← depthLeft=6 (从子节点起计)
                      │
                      ai ── [现在 501033]  ← 第1层
                      │    [先在   8234]
                      │    [贤才   1230]
                      │
                      ao ── [先造   500]   ← 第1层
                      │
                      ... (最多再搜 5 层深)

   每终端取前 3 高频词条 → 合并到结果 map (word → max freq)
   
3. 结果按词频降序排列

   现在  501033
   先在    8234
   贤才    1230
   先造     500
   ...

深度自适应策略

输入长度    maxDepth    覆盖范围
────────────────────────────────────────
  1 字母       6       全部单音节 (zhuang=6)
  2 字母       5       "zh" → zhuang (再5层)
  3+字母       0(无限)   前缀已具体, 子树很小

复杂度对比

                 std::unordered_map      TrieDict
─────────────────────────────────────────────────────
 精确查找           O(1) 哈希             O(L) 指针追
 前缀查找           O(N) 全表扫描 ⚠️       O(L+M) DFS
 单次按键耗时      10-50ms (卡顿)         0.1-0.5ms
 内存 (索引)        ~30MB (bucket开销)    ~43MB (节点)
  • L = key 长度 (≤6 单音节, ≤12 双音节)
  • M = 子树内终端节点数 (通常 < 100)
  • 写入仅初始化时发生,运行时只读 → 无锁、无内存分配

技术架构

┌─────────────────────────────────────────────────────────┐
│  WinMain (消息循环)                                       │
│                                                         │
│  ┌──────────────┐  ┌──────────────┐                     │
│  │ KeyboardHook │  │ CandidateWin │                     │
│  │ WH_KEYBOARD_LL│  │ WS_POPUP    │                     │
│  │ + Caps/Shift │  │ + GDI 自绘   │                     │
│  └──────┬───────┘  └──────▲───────┘                     │
│         │                 │                              │
│  ┌──────▼─────────────────┴────────────────────┐        │
│  │          PinyinEngine (拼音引擎)              │        │
│  │  ┌────────────────┐  ┌──────────────────┐   │        │
│  │  │ 候选词匹配      │  │ 拼音分割 (DP)    │   │        │
│  │  │ + 精确匹配     │  │ + 410 有效音节   │   │        │
│  │  │ + 前缀联想     │  │ + 束搜索 top-8   │   │        │
│  │  │ + 大小写忽略   │  │ + 多策略组合     │   │        │
│  │  └───────┬────────┘  └──────────────────┘   │        │
│  │          │                                   │        │
│  │  ┌───────▼────────────────────────────┐     │        │
│  │  │    TrieDict (前缀树内存数据库)       │     │        │
│  │  │    · 26 分支固定数组,无哈希         │     │        │
│  │  │    · O(L+M) 前缀查找                │     │        │
│  │  │    · DFS 深度自适应限制             │     │        │
│  │  │    · ~50k 拼音键, ~540k 候选词条    │     │        │
│  │  └────────────────────────────────────┘     │        │
│  │  ┌────────────────────────────────────┐     │        │
│  │  │ 用户词库 + 模糊音 + 简繁转换        │     │        │
│  │  └────────────────────────────────────┘     │        │
│  └─────────────────────────────────────────────┘        │
│                                                         │
│  ┌──────────────────────┐  ┌──────────────────────┐    │
│  │  SettingsWindow      │  │  IUIAutomation       │    │
│  │  + 皮肤/配色         │  │  + TextPattern2      │    │
│  │  + 用户词典管理       │  │  + GetCaretRange     │    │
│  │  + 系统注册           │  │  → 精准光标定位       │    │
│  └──────────────────────┘  └──────────────────────┘    │
└─────────────────────────────────────────────────────────┘

简繁转换

基于《简化字总表》三表体系:

  • 表一 (~350 字):不作简化偏旁的简化字
  • 表二 (~132 字 + 14 简化偏旁):可作简化偏旁的简化字
  • 表三 (类推简化,1500+ 字):应用表二偏旁类推简化

转换策略:最长词匹配优先 → 单字映射回退,确保「一简对多繁」正确消歧。

词汇覆盖:

  • 一简对多繁词组消歧 ~180 对(如 出发→出發 / 头发→頭髮)
  • 两岸 IT 词汇差异 ~40 对(如 软件→軟體、鼠标→滑鼠、服务器→伺服器)

自学习机制

每次选择候选时:

  1. 该候选在用户词库中频率 +1
  2. 自动保存到 user.dict 文件
  3. 下次输入相同拼音时,高频词优先显示
  4. 候选排序 = 系统词库基础频率 + 用户学习频率

注意事项

  • 全局键盘钩子(WH_KEYBOARD_LL)需以管理员权限运行,否则在某些应用中无法正常输入
  • 候选框使用 GDI 纯手工绘制,无任何 UI 框架依赖,无任何第三方库依赖
  • 首次运行会在同目录生成 pinyin_config.ini(配置文件)和 user.dict(用户词库)
  • UIAutomation 光标检测在 Chrome/Edge/VSCode/Office 等现代应用中工作良好,老旧程序回退到 Win32/MSAA 检测

许可证

MIT License

About

不超过1000行的极简拼音输入法实现

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages