把"文本逐字符"打"进任意 Windows 窗口的桌面工具。粘贴内容、点开始,倒计时结束后 Typer 会模拟键盘把文字输入到当前焦点窗口——全部是真实按键,远程桌面 / 云桌面这类只转发键盘事件的环境也能用。
只输入"键盘上按得出来"的字符。 支持可打印 ASCII 与目标键盘布局(US / UK / DE / FR / ES)收录的符号;中文 / 全角标点会映射成对应的英文标点,汉字、日文、emoji 等没法转换的字符会直接忽略。开始前会提示这次会怎么处理,确认后才开始,内容区原文不变。
它也能把整个文件切成"每片一行"的纯 ASCII 帧逐片发送:接收端逐片校验、支持断点续传,合并后再按整文件哈希复核。
技术栈:electron-vite + Vue 3(Vapor Mode)+ Element Plus + Pinia + UnoCSS,界面按 Windows 11(Fluent 2)的组织方式设计。
仅支持 Windows 10/11。 注入依赖 Win32
SendInput,打包配置与 CI 也只覆盖 Windows。
- 真实键盘事件:只走虚拟键(
SendInput),不依赖KEYEVENTF_UNICODE报文,因此远程桌面 / Citrix 也能用。 - 修饰键时序适配:远程桌面会把同一次
SendInput里的修饰键与主键合批丢掉,宿主会单独按下修饰键、留出间隔再打主键,并让连续同修饰键的字符保持按住。两个间隔(按下后 / 抬起前,默认 15 / 10 毫秒)可在设置里调大,应对延迟更高的云桌面。 - 换行与行首:换行键可换成 Shift+Enter / Ctrl+Enter(避开"Enter 会直接提交"的聊天框与表单);编辑器的自动缩进可以把行首拉回列 0——开启「归位并清残留」后每次换行先
Home+Shift+End选中自动插入的缩进,再由输入覆盖。 - 动作组原子化:「修饰键 + 主键」是一个不可打断的动作组——暂停 / 停止只在字符之间生效,不会停在"Shift 已按下、字符还没打"的中间态;进入暂停时立即抬起修饰键,继续时先重新走一次开始倒计时。
- 节奏与拟人:支持字符/秒、词/分钟、固定间隔三种速度模式;均匀或正态抖动;标点、空格、换行、空行与周期性停顿;可配置错字概率、错字方式与自动纠正。
- 两档注入:标准档逐字下发,节奏与停止最灵敏;极速档放开每字符的固定间隔,实际速度由目标窗口的输入处理能力决定。
- 键盘布局:US / UK / DE / FR / ES;布局里没有收录的英文符号会在开始前明确报错,不会静默丢字。
- 打不出来的字符自动处理:中文 / 全角标点映射成对应的英文标点(如
,→,、。→.),汉字、emoji 等没法转换的直接忽略;开始前只提示数量并征求确认,不阻止继续输入,内容区原文不变。 - 焦点守护:开始前记录前台窗口,运行中窗口变化可提示或直接中止;
Ctrl+Alt+X/Ctrl+Alt+P(可改)全局停止与暂停;结束后统一释放按键,并可自检粘键。 - 运行浮窗:开始后主窗口最小化,屏幕边缘留一条固定尺寸的细进度条(贴左右边时竖条、贴上下边时横条)。鼠标靠近时细条淡出、卡片从屏幕边缘滑入,显示进度、剩余时间与暂停 / 停止 / 回到主窗口。浮窗窗口尺寸恒定,展开收起只做合成层位移与淡入淡出,不会触发窗口 resize 或布局重排;卡片可拖动、贴边吸附,位置下次沿用。输入结束后默认留在浮窗(不抢焦点、不弹回主界面),点卡片上的「返回主窗口」才回去;也可在设置里改回「自动返回」。
- 新手引导:首次启动自动播放漫游式引导,指出模式切换、内容区、目标窗口、开始与停止;「关于」页可随时重看。
- 隐私:输入内容默认只在内存中处理,不写入磁盘。
- 任意文件,纯文本帧:文件按原字节编码成每片一行的帧逐片输入,避开
\0、\n、\t、超长行以及终端的粘贴与回显问题。 - 远程桌面可用:只发真实键盘事件(不发
KEYEVENTF_UNICODE报文),因此 RDP / Citrix / 云桌面都能用;修饰键会单独下发并留出间隔,避免被客户端合批丢弃。详见 远程桌面的修饰键时序。 - 字符即带宽:默认用零 Shift 的 5 bit 符号表(数字 + 小写字母),字符数约为原始字节数的 1.6 倍;目标端是终端时还可换 Base47 档(用满 47 个零 Shift 键,同一份数据再少 8% 字符);再叠加整文件 Brotli 压缩,文本/代码/JSON 通常还要再小一半以上。
- 只传原字节:不做容器重打包/解包,接收端合并后的
SHA-256等于源文件,签名与哈希都不受影响。 - 完整性校验:每片带
CRC32,整文件再按SHA-256复核;坏片会被准确定位并要求重传。 - 断点续传:接收端打印
@T2R续传令牌,粘回 Typer 后只补缺失片;也可只发指定片或从某片开始重发。 - 零依赖接收端:单个
typer-recv.mjs(Node ≥ 14)即可接收;可从文件页导出、直接"打"进目标机终端,或从安装目录取。 - 三档节奏:只差两个参数——字符间隔(1ms / 0ms)与是否采用「片间停顿」。稳健:字符 1ms + 片间按设置;快速:字符 1ms、片间固定 0(片间停顿为 0 时与稳健一致);极速:字符 0ms,速度上限由目标端输入队列的消化能力决定。三档都逐动作投递(攒批直投实测会丢字符);丢字符由该片 CRC 检出并单独重传,开始帧/结束帧连发 3 遍。
- 耗时是算出来的:界面直接显示字符数、线上字节与预计耗时,并给出 1 小时 / 2 小时预算是否可达;不可压缩的大文件会明确标注不可行。
| 页面 | 内容 |
|---|---|
| 输入 | 文本 / 文件两种模式。文本模式支持导入文本文件、一键清空,并提供实时统计、预计耗时与"转英文 / 忽略"提示;文件模式提供文件摘要、Hex 预览、续传与重传。开始/暂停/停止常驻页面底部,内容区 Ctrl+Enter 开始。 |
| 日志 | 运行记录,按级别筛选、复制、清空,新条目自动滚动。 |
| 设置 | 按「通用 / 文本输入 / 文件输入」分组;右侧锚点目录随滚动高亮、点击跳转;底部保存条提示未保存改动;主题即时生效。 |
| 关于 | 版本与更新中心、外部链接、已知限制,以及重看新手引导。 |
窗口为无边框 + 自绘标题栏,左侧导航;主题可跟随 Windows 或手动选择亮 / 暗。文本与文件模式切换不丢失各自的内容和展开状态。
运行浮窗:贴边时只剩一条进度条,鼠标靠近才展开成卡片。
设置分组:
- 通用:外观(跟随系统 / 亮暗)、倒计时、注入档位、每批动作数、每字符最小间隔、修饰键时序、进度浮窗(结束后手动返回 / 自动返回)、焦点守护、热键、粘键自检、隐私、更新
- 文本输入:换行与行首(换行键、行首归位)、速度与抖动、停顿节奏、错字与纠正、键盘布局、文本导入编码
- 文件输入:字符档、压缩与等级、目标端(终端 / 编辑器 / 单行框)、传输节奏、片大小、单帧字符上限、片间停顿、导出接收脚本 / 打开脚本目录
设置默认保存在 %APPDATA%\Typer\settings.json(原子写,损坏时备份并回退默认值;可在隐私设置中关闭持久化);主题偏好存在渲染进程本地。
直接使用可从 Releases 下载 Typer-<version>-setup.exe。
开发或构建需要 Node ≥ 20.19,pnpm 由 corepack 提供(版本见 packageManager)。
pnpm install
pnpm dev # 开发模式(HMR),会先打包接收端脚本
pnpm build # 类型检查 + 打包接收端 + 构建到 out/
pnpm build:win # Windows 安装包 → dist/Typer-<version>-setup.exe
pnpm start # 运行已构建的产物
pnpm icons # 由 resources/icon.svg 生成 PNG / ICO / 预览图使用(文本模式):
- 粘贴或导入要输入的内容。
- 点「开始输入」;内容里有键盘打不出来的字符时会先弹提示(标点映射成英文、其余忽略),确认后才开始。主窗口自动最小化,屏幕边缘出现进度条,在倒计时内切到目标窗口并点一下输入位置。
- 需要中断时按全局热键,或把鼠标移到进度条上展开卡片后暂停 / 停止。暂停会在当前这一小批字符打完之后生效(并先把修饰键抬起),点「继续」会重新走一次开始倒计时再接着打。
- 打完之后主窗口不会自己弹出来抢焦点:进度浮窗停在完成态,点卡片上的「返回主窗口」再回去(可在设置里改成自动返回)。
目标程序若开着中文输入法,真实按键会被它截获成候选上屏。倒计时结束后 Typer 会先查一次目标窗口的键盘布局与输入法状态:处于中文/日文/韩文布局或输入法正在合成时,自动切到英文(US)并关掉输入法;切不动则在日志里提示手动切换(可在「设置 → 键盘布局」关掉这项自动切换)。这不是编码问题:中文本身没有物理键位,Typer 无法输入。
目标机运行接收端:
node typer-recv.mjs -o received.bin --token发送端在「文件」模式选择文件,点「发送 N 片」。接收端脚本可从文件页「插入接收脚本到文本输入」打进目标终端,用「导出脚本」复制脚本与 run.bat 到指定目录,或直接使用安装目录下的 resources\tools。完整参数与线格式见 tools/README.md。
| 字符档 | 每个字符承载 | 说明 |
|---|---|---|
| Base47(终端推荐) | 5.447 bit | 用满美式布局上 47 个零 Shift 可打印键:比 5 位档再少 8% 字符;仅限终端(编辑器会自动更正 --、引号与括号) |
| ASCII 5 位(默认) | 5 bit | 只用 0-9 与小写字母:完全不发 Shift,远程桌面下不会被输入法中英文切换干扰,字符数约为原始字节的 1.6 倍 |
| ASCII 6 位(字符最少) | 6 bit | 数字/大小写字母/-/_:字符数最少,但大写字母需要 Shift,每个修饰键切换要多花约 25ms |
| Hex 4 位(诊断) | 4 bit | 只有 0-9 A-F,最抗终端与远控干扰;字符数最多,仅在排查链路问题时使用 |
- 压缩:默认「自动」——先采样试压,已经压缩过的 ZIP/图片/视频等直接发原字节(省掉准备时间)。
文本/代码/JSON 用整文件 Brotli 压缩,质量默认
9,但 8 MB 以内的文件会在准备时自动升到 q11 (多花不到 2 秒,换 3%~7% 更少的线上字节);想要固定质量就把压缩等级设成 9 以外的值 (9与默认值同值,一律按“自动”处理)。 - 片大小:预设「小片 / 默认 / 大片」(2 KiB / 16 KiB / 64 KiB 线上字节)。帧长上限按最坏情况预先校验,超限会在开始前报错并给出建议值。
- 目标端:终端与编辑器都用真回车(关回显,最快);单行输入框不加换行,靠
@T2标记切分帧。 - 接收端场景:终端会进入 raw 模式(不回显、不限行宽);
--probe可先确认链路能原样送过一帧,--stats打印字符数与吞吐。 - 结果位置:不指定
-o时,接收端按开始帧里的原始文件名写入分片目录(-d,默认./.typer-<job>),完成后清掉分片与续传报告;同名文件默认覆盖,--no-overwrite可拒绝。 - 重传:接收端报
#FAIL时,用@T2R续传令牌或「只发指定片 / 起始片号」补传,不必重跑整个文件。 - 速度怎么算:
字符数 ÷ 实测字符/秒。5 位档下字符数 ≈ 原始字节 × 1.6(Base47 档 ≈ × 1.47),例如 4.59 MiB 的 VSIX 约 7.7 M 字符; 按稳健档 ≈446 字符/秒约 4.8 小时,极速档 ≈700 字符/秒约 3 小时。详见 字符密度与 Shift 的取舍。
应用可自动检查 GitHub Releases 的新版本(「设置 → 更新」可关闭),也可在「关于」页手动检查。
- 流式下载安装包到
%TEMP%\Typer-update,支持进度与取消。 - 用发布附带的
SHA256SUMS.txt或 GitHub 的asset.digest校验;摘要不符会删除文件并拒绝安装,两种来源都拿不到时只提供手动下载入口。 - 校验通过后启动安装程序并退出本程序,由安装向导完成替换。
- 检查带 30 秒节流;离线、限流等失败只写日志,不打扰操作。
- 更新不会重置设置:这是"覆盖安装"(安装器用
--updated调用旧卸载程序),%APPDATA%\Typer\settings.json与缓存都保持原样;只有卸载才会清掉用户数据(deleteAppDataOnUninstall: true)。所以「先卸载再装」等于重置,要保留就先拷走settings.json,装完再放回去。 - 设置文件损坏时不会直接丢:会另存为
settings.json.corrupt并回退默认值,原文件可供排查。
发布新版本:更新 package.json 的 version,然后推送 v* 标签。release.yml 会在 windows-latest 上构建安装包、生成 SHA256SUMS.txt,并把接收端脚本一并上传到 Release。
- 不依赖原生模块:独立 PowerShell 进程内联 C# 调用
SendInput,避开 node-gyp / MSVC 工具链;Windows 自带 PowerShell 5.1 即可运行。 - 宿主通信:stdin/stdout 上的 JSON Lines,非 ASCII 预先转义成
\uXXXX,不受控制台代码页影响。 - 时序:高分辨率可等待定时器(
CreateWaitableTimerExW)+ 最后 0.3ms 自旋;Windows 默认定时粒度约 15.6ms,无法靠Start-Sleep做到毫秒级。 - 攒批与背压:连续的小间隔合并成一次请求;宿主记录每次下发被输入队列拖住的时长,并从后续间隔中扣除,避免长时间占满队列。数据帧始终逐动作投递(攒批直投实测会静默丢字符)。
- 线格式单一实现:
src/main/util/frame.ts同时用于主进程与接收端脚本,构建时内联进脚本产物,收发两端不会漂移。 - 运行浮窗:独立的透明置顶窗口,不抢焦点;窗口尺寸恒定(阴影余量 + 卡片 + 间距 + 细条,当前 264×196),贴边几何由主进程计算,展开 / 收起只改页面里的
transform与opacity。不做setBounds尺寸动画,既避免透明窗口逐帧 resize 触发 DWM 重排,也避免"窗口变大把进度条拉伸成巨宽"。 - 更新:检查、下载、校验与安装均由主进程实现,不依赖 electron-updater。
src/main/ 主进程:窗口、设置、IPC、输入引擎与驱动器、文件传输、更新、浮窗
src/preload/ 受控 API 与类型声明
src/renderer/ 主窗口与浮窗(Vue 3 + Element Plus + UnoCSS)
src/shared/ 跨进程共享的纯类型、常量与纯函数
tools/ 接收端 TS 源码与构建产物(typer-recv.mjs / run.bat)
scripts/ 输入宿主、构建脚本、图标生成与吞吐基准
tests/ 单元测试与系统测试
上手时可先看 src/main/index.ts(主进程组装)与 src/renderer/src/views/TyperView.vue(输入页)。
- 自动导入:Vue / Pinia / Vue Router 的 API、
composables、store与components都无需手写 import;类型与 ESLint 全局声明由dev/build生成。 - Vapor 是文件级 opt-in:每个 SFC 的
<script setup>必须写vapor,遗漏会静默退回 vdom,由tests/unit/renderer/vaporConvention.spec.ts守护。确需 vdom 的组件不写属性,并在测试 allowlist 中登记。 - 路径别名:跨目录引用走
@renderer/*、@main/*、@shared/*,不写深层相对路径。 - 纯逻辑放
src/shared:渲染进程不能引用node:*;必须与接收端共用的线格式放在src/main/util/frame.ts,由构建脚本内联进接收端产物。 - 多窗口各有入口:
index.html/float.html,入口在src/renderer/src/windows/,由electron.vite.config.ts的rollupOptions.input声明。浮窗不引入路由与 Element Plus。
pnpm test # 单元测试:假时钟 + Mock 驱动,不产生真实按键
pnpm test:watch # 监听模式
pnpm test:cov # 覆盖率
pnpm test:system # 系统测试:宿主脚本 + 接收端端到端 + 真实注入
pnpm test:e2e # 端到端:远程调试驱动真实应用,宿主 dry-run,不产生真实按键
pnpm test:all # 单元 + 系统(端到端要拉起界面,故不在其中;真实注入默认跳过)
node scripts/bench-throughput.mjs # 注入吞吐基准(默认 dry-run)
node scripts/bench-throughput.mjs --real "<窗口标题>" # 真实按键到指定窗口
node scripts/bench-transfer.mjs <文件> --emit frames.txt --verify # 文件传输:字符数、各档耗时、接收端逐字节校验提交前也可运行 pnpm lint、pnpm typecheck、pnpm format:check。
- 单元测试覆盖文本归一化、ASCII 键位完整性、动作规划、节奏与错字、引擎状态机、文件传输(线格式、CRC32、续传、压缩、耗时估算)、协议分片与粘包、浮窗几何、主题、设置夹取、IPC 校验与更新流程。
- 端到端测试(
tests/e2e)用远程调试端口(CDP)驱动真实应用,并校验“到底收到了什么”:宿主虽然以 dry-run 启动(TYPER_DRY_RUN=1),但会把本来会发出的按键事件记进keys.txt,测试据此重放出“目标窗口本该收到的文本”与源文本逐字符比对;文件用例再把重放出来的帧文本交给真正的接收端tools/typer-recv.mjs还原文件,并与源文件逐字节比对。子进程的APPDATA指向临时目录,不碰本机配置;不引入 Playwright,直接用 Node 自带的 WebSocket 说 CDP。 - 系统测试使用真实 PowerShell 宿主与构建后的接收端脚本;
pnpm test:system会开启真实注入,在自建 WinForms 窗口中逐字比对WM_CHAR,抢不到前台焦点时自动跳过,不会打到其它窗口。字符只到一部分(含 0 个,但内容与预期一致)视为环境限制——托管 runner 的会话可能没有输入桌面或中途丢焦点——用例会跳过而不报假红;字符内容对不上才判失败。 - CI 在
windows-latest上执行格式检查、Lint、类型检查、单元与系统测试、构建。
- 权限(UIPI):无法向"以管理员身份运行"的窗口注入按键;目标程序需与本程序权限一致,否则会返回可读错误。
- 安全桌面:锁屏、UAC 弹窗与
Ctrl+Alt+Del界面无法注入。 - 安全软件:部分杀毒 / EDR 会拦截合成输入,此时
SendInput的成功事件数会少于请求数并明确报错。 - 游戏与自绘界面:少数程序只认扫描码或忽略
WM_CHAR,需要专门的输入方式。 - 键盘布局与输入法:真实按键由目标窗口的布局解释;非 US 布局下不确定时请确认字符已被该布局收录。中文输入法可能截获真实按键,建议输入前切到英文。
- 汉字 / emoji 等没有物理键位的字符不会被输入:这是"只发真实键盘事件"的必然结果(远程桌面不支持
KEYEVENTF_UNICODE报文)。中文 / 全角标点会映射成对应的英文标点,剩下的没法转换的字符直接忽略,其它内容照常输入;开始前会提示会映射多少个、忽略多少个,不会静默丢内容。设置里的「文本导入编码(UTF-8 / GBK)」只影响读文件时的解码,不会让这些字符变得可以输入。 - 焦点:开始后不要移动鼠标或切换窗口;
strict模式下窗口变化会直接中止。浮窗上的暂停 / 停止与全局热键都不需要聚焦。 - 文件传输的节奏:帧是逐字符发送的,耗时由帧字符数 ÷ 链路字符速度决定;目标端丢字符时该片
CRC32会失败并给出缺失片号,补传即可,不会写出坏数据。每帧帧头还带独立 CRC32,帧头被改写会在解析阶段直接拒绝。用文本模式发送帧文本时,请把「错字概率」设为 0。 - 不可压缩的大文件:图片、视频、已压缩的 ZIP 等几乎压不动,只能靠字符密度与链路速度。 100 MB 这类文件在 5 位档下约 1.7 亿字符,键入方式不可能在小时级完成——界面会直接标注不可行。
- 字符档与代码页:四个字符档都是纯 ASCII,不依赖代码页;大写字母(6 位/Hex 档)会引入 Shift 切换开销,在远程桌面下优先用零 Shift 的 5 位档;目标端是终端时用 Base47 档更省字符(编辑器会把
--、引号与括号自动更正,所以编辑器模式下不提供这一档)。 - 远程桌面只转发真实键盘事件:Typer 因此只使用虚拟键,大写/符号依赖单独按下并留间隔的 Shift;文件传输默认用零 Shift 的 5 位档(数字 + 小写字母),详见 远程桌面适配与提速。
- 编辑器自动缩进:VS Code 这类编辑器会把上一行缩进(以及行尾是
{/(时的一级缩进)自动带到新行,叠加源文本自带的缩进后整行右移。两种解法:把目标编辑器关掉editor.autoIndent/editor.autoClosingBrackets/editor.formatOnType,或在设置 → 文本输入 → 换行与行首里开启「归位并清残留」。终端类目标没有自动缩进,保持「不处理」即可。
本工具用于自动化填表、演示、批处理与测试等合法用途。请勿用于绕过安全控制、未获授权的自动化操作或违反目标程序服务条款的场景;使用前请自行确认合规性。


