Visitar URL original
GitHub - baendlorel/capslock-switcher · GitHub
Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

32 Commits

Folders and files

Repository files navigation

CapsLock切换器 (CapsLock Switcher)

Windows 输入模式切换工具:中文切换中/英,日语循环平假名/片假名/英文。

功能特性

  • ✅ 中文输入法:CapsLock 发送 Ctrl+Space,保持原来的中/英切换
  • ✅ 日语输入法:CapsLock 循环 平假名 → 全角片假名 → 半角英文 → 平假名,每次按实际状态决定下一档
  • ✅ 其它语言不接管,CapsLock 原样放行;启用映射和 Alt+CapsLock 放行开关继续有效
  • ✅ 后台运行,无窗口界面
  • ✅ 系统托盘图标显示运行状态
  • ✅ 右键托盘图标可退出程序
  • ✅ 防止程序重复运行
  • ✅ 退出后CapsLock恢复原有功能
  • ✅ 长时间运行自愈:键盘钩子失效后自动重装,Explorer重启后自动恢复托盘图标
  • ✅ 托盘图标创建失败时自动重试,不再直接退出
  • ✅ 设置页里可随时开启/关闭映射、Alt+CapsLock 放行、鼠标指针变色和开机启动;变色开着时 用滑块调浓度。改动立刻写进 exe 旁边的 capslock-switcher.ini,下次启动照旧
  • ✅ 每次切换在屏幕中央显示输入模式:中文红底"中文"、英文蓝底"English";日语下字符换成 A / あ / ア,其中平假名 #FFC900 黄底、片假名 #FF8B31 橙底,都写黑字,英文那档仍是蓝底白字
  • ✅ 鼠标指针也跟着变色:中文红、平假名黄、片假名橙、英文蓝,和横幅底色是同一份颜色。按 CapsLock 立刻变, 切换窗口也会跟着变(切到中文的窗口就变红,切回英文的窗口就变蓝),不按 CapsLock 直接用 Ctrl+Space 或点任务栏切换也能在半秒内跟上
  • ✅ CapsLock 每按一下都往 capslock-switcher.log 写一行:切换输入法、Alt+CapsLock 放行 (还会记下结果是大写还是小写)、"映射已关闭"、非中/日输入法下原样放行都能看出来(设置页上的 打开日志文件 能直接打开看)
  • ✅ 双击托盘图标(或右键菜单里的"设置...")打开设置页:四个勾选项,鼠标颜色开关右边就是浓度滑块
  • ✅ Alt+CapsLock 触发原本的大写锁定(可以在设置页里关掉),放行时中央会闪一个紫色 横幅,白色文字写着"大写"或"小写"(小写的紫色淡一半),告诉你现在是什么状态
  • ✅ 可开关开机启动(设置页里勾),以计划任务方式登录时自动运行且带管理员权限
  • ✅ 程序启动时在屏幕中央显示 umbral-keys.png,随后淡出
  • ✅ 出错退出时把详细错误信息写入 exe 同目录的 capslock-switcher.log

使用方法

  1. 在Visual Studio中打开 capslock-switcher.slnx 并编译
  2. x64 的产物在仓库根目录:调试用 x64\Debug\capslock-switcher.exe,发布用 x64\Release\capslock-switcher.exe。发布就是这一个文件:静态链接 CRT、不依赖任何 运行库,拷到哪台 Win10/11 x64 机器上双击就能跑(发版前改 capslock-switcher/version.h 那一行)
  3. 双击运行程序(设置页在主程序里:双击托盘图标,或右键菜单里的"设置...")
  4. 程序会在系统托盘右下角显示图标
  5. 中文输入法下按 CapsLock 发送 Ctrl+Space;日语输入法下每按一次循环 平假名 → 全角片假名 → 半角英文 → 平假名。英文仍属于日语输入法内部的模式,不切到英语布局。 横幅显示真实读到的模式:中文红、英文蓝,日语下字符是 A / あ / ア(平假名黄底、片假名橙底, 都是黑字);鼠标指针始终和横幅同色(中文红、平假名黄、片假名橙、英文蓝)。 读不到状态时不猜测、不切换日语模式;横幅不显示新状态,指针保留已有颜色。 单独英语等其它语言布局不被接管。日语切换时请松开 Ctrl/Alt/Win 等修饰键,以免触发其它 IME 命令。
  6. 右键点击托盘图标打开菜单;双击托盘图标直接打开设置页(菜单里也有"设置...")。 开关都挪到设置页了:四个勾选项,鼠标颜色开关右边就是浓度滑块。 勾选项和滑块改完立刻生效,也不会再弹提示气泡;失败原因只写进日志:
    • 启用映射 (中文 / 日语):取消后 CapsLock 恢复成普通大写锁定键, 程序仍在后台运行,随时可以再勾回来
    • Alt+CapsLock = 原来的大写锁定:勾上(默认)时 Alt+CapsLock 等于原来的大写锁定; 取消后 Alt 不再特殊,Alt+CapsLock 和 CapsLock 一样照样切换输入法
    • 鼠标随语言变色勾选框:总开关。取消勾选立刻把你的指针方案原样装回去,旁边 的浓度滑块同时变灰、拖不动;再勾回来马上按原来的浓度重新上色,浓度值不会被清掉
    • 颜色浓度滑块(鼠标随语言变色 右边):100%(默认)就是完整的中文红/英文蓝,0% 相当于关掉,中间的数值 按比例把红/蓝减淡。滑块点哪跳哪,按住还能接着拖(系统的默认行为是点一下只挪一页)。 染的是箭头、文本 I 型、链接手型、十字、横向拉伸、纵向拉伸这六个 系统指针;具体边界见下面的"注意事项"
    • 开机启动 (管理员):勾选时会弹一次 UAC 提权确认,随后创建名为 CapsLock Switcher 的计划任务("登录时"触发、最高权限),之后开机自启不会再弹 UAC;升级换了目录或 exe 名字之后,下次启动会把任务里的 exe 路径改成当前这份(日志里记一行 计划任务的exe路径从 x 改为 y),这一步同样要提权,所以也会弹一次 UAC
    • 打开日志文件:用系统默认程序打开 capslock-switcher.log
    • 关掉设置页(或按 Esc)只是收起来,程序继续在托盘里跑
  7. 右键菜单本身只有三项:当前输入法(灰显)、设置...、Exit——开关全在设置页里,菜单不再重复一份。
  8. 想临时用一次大写锁定,按 Alt+CapsLock 即可(等同于原来的 CapsLock);松手时屏幕中央 会闪一个紫色横幅,显示"大写"或"小写"。这一条可以在设置页里关掉,关掉之后 Alt+CapsLock 就和 CapsLock 一样切换输入法。另外它受"启用映射"开关控制:映射关掉时, 单独按 CapsLock 也是普通大写锁定。

启动时屏幕中央会显示一次 umbral-keys.png(键帽图),停留0.5秒后在0.3秒内淡出, 用来提示程序已经起来了。

设置文件

设置存在 exe 旁边的 capslock-switcher.ini 里,绿色版,不写注册表:

[General]
MappingEnabled=1
AltCapsLockPassThrough=1
CursorTintEnabled=1
CursorTintPercent=100
  • 只认 0/1(三个开关)和 0~100(浓度)的整数,而且整数要完整占满整行, 多一个字符就算写坏。
  • 文件不存在、某一项缺失或写坏:那一项退回上面的默认值,其余项照原样保留,并立刻把整份 文件重写成合法内容(日志里记一行)。所以手改坏了不会让程序启动不了,也不会一直坏下去。
  • 开机启动不在这个文件里:它本身就是系统的计划任务,状态直接查任务,不由程序另记一份。
  • 文件写不进去(例如放在只读目录)只记一行日志,程序照常跑,只是设置不跨启动保留。

编译环境

  • Visual Studio 2026(平台工具集 v145)
  • Windows SDK
  • C++20标准
  • 版本号是手写的:capslock-switcher/version.h 里一行 #define APP_VERSION "x.y.z", C++ 代码(设置页标题栏、日志)用它;不需要 Node.js 之类的额外工具

技术实现

  • 代码按职责拆成几个模块,各自一对 .cpp/.h:main.cpp 只管进程外壳(单实例、 隐藏主窗口、消息循环),键盘钩子在 keyboard.cpp,托盘在 tray.cpp,开机启动在 startup.cpp,启动画面在 splash.cpp,设置页在 settings.cpp,日志在 logging.cpp, 分层窗口和 DPI 辅助在 surface.cpp,鼠标指针在 cursor.cpp
  • 使用Windows低级键盘钩子(WH_KEYBOARD_LL)捕获CapsLock按键
  • 中文继续注入 Ctrl+Space;日语通过 VK_IME_ON 进入平假名、Shift + VK_IME_ON 进入全角片假名、 VK_IME_OFF 进入半角英文。两种语言共用按键注入和部分失败后的补抬逻辑,不合成 CapsLock, 不使用 F6/F7/F10 转换组合中的文字,不设置全局循环计数器,不改变罗马字/假名键盘输入偏好。 依据 Microsoft Learn 的 Keyboard Japan - ImeOn / ImeOff Implementation(见下方来源); 面向支持这些原生键的微软日语 IME,不添加旧 IME 或第三方输入法的兼容分支。
  • 输入状态统一由 keyboard.cpp 的 GetInputMode 读取:GetGUIThreadInfo 找焦点控件, ImmGetDefaultIMEWnd 取得默认 IME 窗口,再发带超时的 WM_IME_CONTROL。 日语先读 IMC_GETOPENSTATUS(0x0005),关闭就是英文;打开后读 IMC_GETCONVERSIONMODE(0x0001), 用 IME_CMODE_NATIVE 和 IME_CMODE_KATAKANA 区分三态。中文沿用原来的 NATIVE 位判断。 不再枚举线程内第一个名为 IME 的窗口;链接 Windows 自带的 imm32,没有新增随包 DLL。
  • 第三方输入法不再仅因名称而禁用状态横幅:每次切换前读取焦点控件的 IMM 原始开关/转换位, 切换后约 50ms 读取;未确认时再等 100ms,最多读三次(单次 IMM 查询共用 50ms 超时预算)。 只有同一输入框、同一 IME 窗口、本次中英文/假名状态确实变化才显示模式;中文也接受 “NATIVE 保留、open 改变”的开关式切换。固定 0/0、固定非零值、仅标点/全半角变化、 错误码、超时或名称缺失均不猜测,显示白字、#00BEB6 底的“切换”。 不注入 DLL、不安装新的全局钩子、不自动试按键、不跨切换缓存支持状态。窗口/布局/已知名称 改变时丢弃过期横幅。微软系继续使用原本模式读取,失败时也使用“切换”提示。 非微软输入法的鼠标仍恢复原状、不染色,这次开放的是切换横幅,不是持续光标染色。 这是基于本次状态变化的尽力探测,不保证所有第三方输入法都提供准确的 IMM 数据。
  • 提示横幅在屏幕中央停留约 0.5 秒后淡出:中文红底 #FF1F45、英文蓝底 #0073FF、 日语假名暖底色,上面写黑字:平假名 #FFC900 黄、片假名 #FF8B31 橙(日语的英文档仍是 #0073FF 白字 A)、 大写紫底 #9333EA、 小写用淡一半的紫 #C999F4,除日语外文字都是白的;圆角和逐像素 Alpha 的做法与启动画面相同(GDI+ 画形状、GDI 画字、最后补 Alpha 蒙版)
  • 鼠标指针变色(cursor.cpp)走的是 SetSystemCursor:把 OCR_NORMAL(32512)、 OCR_IBEAM(32513)、OCR_HAND(32649)、OCR_CROSS(32515)、OCR_SIZEWE(32644)、 OCR_SIZENS(32645) 六个槽换成我们自己造的 32bpp 带 Alpha 光标 (热点从原光标继承过来,I 型的热点不在角上,丢了点击就不准; 掩码按 Alpha 反推,免得在忽略 Alpha 的路径上画出一整块色块)。三个触发点:CapsLock 切换时(和横幅一样先等 50ms 让注入的模式键生效)、SetWinEventHook 的 EVENT_SYSTEM_FOREGROUND(切窗口,同样去抖 50ms)、以及 500ms 一次的兜底轮询 (覆盖同窗口内用 Ctrl+Space/Shift/点任务栏换输入法的情况,这种换法不产生前台事件)。 染色强度由设置页的滑块给:先按上面的公式算出满色,再和用户原来的像素按百分比线性插值 ——100% 是满色,0% 还原,中间越小红/蓝越淡。
  • 原图直接读取注册表方案指向的 .cur 文件,不读取已经可能被染色的系统槽。 目标尺寸取用户的 CursorBaseSize × 鼠标所在显示器 DPI / 96:例如基础大小 48、 150% 缩放,对应 72×72 原生帧,而不是 SM_CXCURSOR 返回的 48×48。 显式解析多尺寸目录并用 CreateIconFromResourceEx 解码选中的帧,避免 LoadImage 自动选帧再次缩放;没有精确匹配时优先缩小较大的原生帧,只有源文件没有足够大的图像 才放大。鼠标跨显示器后,500ms 轮询会按新 DPI 重建,即使输入法状态没有变化。
  • 上色只改预乘 RGB,每个像素的 Alpha、尺寸、热点原样保留:先判断亮体/暗体, 再让本体朝目标色靠拢,另一头的描边不动;半透明暗体的白边也按 Alpha 预乘,避免亮边 溢出。亮暗的判据是贴着透明的那一圈描边,不是整张图的平均亮度——I 型、十字这类 细长形状的白填充面积小,用平均亮度会被黑描边压过去,方向反过来就只剩描边变色。 整个图形看不到描边时按亮体处理,最坏只是不染,不会染错方向。无 Alpha 的彩色光标 按 AND 掩码区分透明与黑色;单色光标按上下两半 AND/XOR 掩码解码,不按系统默认尺寸 猜高度。
  • SetSystemCursor 对普通静态光标还会做一次 DPI 归一化:本机实测原生 72px 经 72 → 48 → 72 后,即使宽高没变,像素也已经模糊。提交时使用两帧完全相同的 ANI, 视觉仍然静止,但系统保留原像素;只用一帧会再次退化为静态路径。实机集成测试必须在 写入系统槽后回读比较,不能只测试创建前的内存位图。
  • 正常退出或滑到 0% 时,将缓存的原始 .cur 字节同样双帧提交,保留原调色板、 掩码和热点,不重新编码原图,也不调用 SPI_SETCURSORS 重载所有槽或写注册表。强杀 不能自动还原,但下次启动从磁盘重新读源,不会叠加颜色,也不需要猜测原色再“反染”。每 10 秒补刷一次 可能被 Windows 冲掉的颜色;高对比度下不染。动画 .ani、没有可读静态方案文件的槽 和自带光标的应用保持原样。
  • 大写锁定现在开着还是关着,是钩子自己数出来的:系统的开关位(GetKeyState(VK_CAPITAL) 的低位)只在有焦点的线程输入队列里更新,本程序没有焦点,读到的会是过期值。所以程序在 钩子线程起来时读一次(那时队列刚建好,拿到的是系统当前状态),之后每放行一次 CapsLock (记在按键抬起时)就翻一次;别的程序注入的 CapsLock 也会跟着数,免得慢慢跑偏
  • 钩子运行在独立线程,回调只在每次 CapsLock 首次按下时投递 PostMessage, 由主线程执行 SendInput;长按不会反复切换,耗时操作也不会阻塞钩子线程。 如果前台窗口或键盘布局已改变,则丢弃排队的切换请求
  • 进程在初始化时声明 Per-Monitor V2 DPI 感知(SetProcessDpiAwarenessContext), 设置页是同一个进程里的 Win32 窗口,跟着进程一起走。窗口尺寸和字体都按它所在显示器的 DPI 缩放,WM_DPICHANGED 里换字体并按系统给的位置重排,拖到别的显示器不会发虚。
  • Alt+CapsLock:以 CapsLock 首次按下时的 Alt 状态决定是否放行,并保持到该键抬起; 中途松开 Alt 或改变映射开关,都不会拆散按下/抬起事件
  • 语言分流直接按前台线程键盘布局的 PRIMARYLANGID 判 LANG_CHINESE / LANG_JAPANESE, 不依赖本地化名字。首次按下时记录目标窗口及完整 HKL,重复键和抬起保持同一决策; 主线程在 IME 查询前后复核窗口和布局,过期请求直接丢弃。
  • 启动画面 umbral-keys.png 以 RCDATA 资源嵌进 exe(见 capslock-switcher.rc), 用 GDI+ 解码后画进一张**预乘 Alpha(PARGB)**的 DIB,再交给 UpdateLayeredWindow ——所以它是真正的逐像素透明,键帽边缘不会出现黑框。 淡出就是拿同一个 DIB 反复调用 UpdateLayeredWindow 并逐级降低 SourceConstantAlpha, 不需要重新解码或重绘
  • 设置的读写就在 config.cpp 里,GetPrivateProfileStringW/WritePrivateProfileStringW 直接操作 exe 旁边的 ini,没有额外的配置层:读取时逐项校验,坏值退默认并重写文件; 每次改动只写回那四个键。设置页改完写盘后立刻重读一遍应用下去,启动时也走同一条路径。
  • 开机启动用计划任务实现(schtasks /SC ONLOGON /RL HIGHEST),因为"登录时以管理员身份 启动且不弹 UAC"只有计划任务的"最高权限"能做到,启动文件夹的快捷方式做不到。 创建任务本身需要管理员权限,所以菜单项会用 ShellExecuteW(..., "runas", ...) 以 --startup-enable / --startup-disable 参数重新拉起自己;这个提权副本 在抢互斥体之前就完成工作并退出,不创建任何窗口,结果写进日志
  • 任务名固定(不带版本号),所以每次启动都会用 schtasks /Query /TN "CapsLock Switcher" /XML 看一眼任务动作里记的 exe 路径:和当前这份 exe 不一致(换过目录、改过文件名)就用 /F 重建同一条任务改指过来,并记下 计划任务的exe路径从 x 改为 y;任务不存在、或者路径已经 一致时什么都不做
  • 使用Shell_NotifyIcon创建系统托盘图标
  • 使用互斥体(Mutex)防止程序重复运行

关于源文件的编码

main.cpp 和 tests/regression.cpp 都保存为 UTF-8 带签名(BOM),注释是中文。 BOM 是必需的:没有 BOM 的 UTF-8 源文件会被 MSVC 按系统代码页(中文系统是936)解释, 一个多字节字符会连带吞掉字符串结尾的引号,直接编译不过(错误 C2001/C4819)。 字符串里的中文仍然写成 \uXXXX 转义(例如 \u542F\u7528 就是"启用"), 这样即使文件哪天被重新存成不带 BOM,也不会波及这些字面量;新写的代码(比如 settings.cpp) 直接写中文即可,BOM 已经保证了正确性。

注意事项

  • 在某些受保护的应用中可能需要管理员权限
  • 退出程序后CapsLock键恢复原有大小写锁定功能
  • 鼠标指针变色的边界(用的是 SetSystemCursor,改的是当前登录会话的系统光标):
    • 自带光标的应用盖不住:Photoshop、游戏、网页里自定义 cursor 的地方仍然是原来的指针
    • 程序被任务管理器强杀时来不及还原,指针颜色会保留到注销为止。下次启动本程序会 按上色公式把残留的颜色拆回灰阶原图再重新上色,不会越染越深(正常退出、滑块拖到 0% 都会立刻把你自己的原图装回去)
    • 开了高对比度时不染色(那套指针是专门挑的高可见度方案,不该乱动)
    • 你自己在"鼠标设置"里换指针方案或改大小,程序会重新读一遍再接着染色
    • 0.0.2 及更早的版本用 SPI_SETCURSORS 还原,会把"辅助功能 → 鼠标指针"调大的尺寸 退回 DPI 默认值,指针从此发虚。升级到这一版后不会再发生;如果升级前已经虚了,把 那个大小滑块动一下再调回来,系统会按你的尺寸重装一遍光标,之后就一直是清晰的
  • 如需开机自启动,可将程序快捷方式放入Windows启动文件夹: C:\Users\你的用户名\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
  • 程序已在运行时再次启动,会提示"Already running",并顺带要求已在运行的实例 重新显示托盘图标(因为它可能已经因为Explorer重启而不可见)

稳定性设计说明

程序长时间运行后曾出现「CapsLock没反应、托盘图标也没了」的现象。这两件事各有原因, 而且进程通常并没有真的崩溃:

  1. CapsLock失效:在低级键盘钩子回调里直接调用 SendInput 会拖长回调耗时。一旦超过 LowLevelHooksTimeout,Windows 7 以上会静默卸载该钩子,且没有任何通知或查询接口。 现在钩子使用独立消息线程,回调只投递一条消息,注入动作在主线程完成; 主线程创建计划任务时,钩子仍能处理输入。此外每60秒重新挂一次钩子 (先挂新的再摘旧的,因此不存在「没有钩子」的空档,也不会重复注入), 即使钩子仍被系统摘除也能自行恢复。
  2. 托盘图标消失:Explorer 重启会销毁任务栏上的所有图标。程序现在处理 TaskbarCreated 消息,任务栏重建后自动把图标加回去。

另外,启动时钩子或托盘图标创建失败(例如开机自启时外壳尚未就绪)不再导致程序退出, 而是每2秒重试一次。

项目结构

回归检查可在 PowerShell 中运行 ./tests/run.ps1。脚本自动加载 Visual Studio C++ 环境, 验证按键配对、长按、修饰键、注入失败、钩子线程生命周期,启动图的解码与释放, 以及指针变色的浓度公式(0%/50%/100%)、热点保留和"解码→上色→还原"整条状态机。 各模块的 .cpp 会编进同一个翻译单元,键盘 API 换成替身,所以替身对所有模块都生效。 测试使用模拟键盘 API,不会安装全局键盘钩子或向其他程序发送按键。

capslock-switcher/
├── capslock-switcher/
│   ├── main.cpp                    # 进程外壳:单实例、隐藏主窗口、消息循环
│   ├── app.h                       # 共享状态与跨模块入口
│   ├── keyboard.cpp / keyboard.h   # 键盘钩子、输入状态读取与中/日模式切换
│   ├── banner.cpp / banner.h       # 切换提示横幅(中/日文模式,日语假名黄底黑字)
│   ├── cursor.cpp / cursor.h       # 鼠标指针跟着输入模式变色(和横幅同色)
│   ├── tray.cpp / tray.h           # 托盘图标与右键菜单
│   ├── startup.cpp / startup.h     # 开机启动(计划任务 + 提权副本)
│   ├── splash.cpp / splash.h       # 启动画面
│   ├── settings.cpp / settings.h   # 设置页(四个开关 + 浓度滑块),进程内窗口
│   ├── config.cpp / config.h       # ini 读写(键名、取值范围、坏值处理)
│   ├── logging.cpp / logging.h     # 诊断日志
│   ├── surface.cpp / surface.h     # 分层窗口与 DPI 辅助
│   ├── resource.h                  # 资源ID头文件
│   ├── version.h                   # 手写的版本号(发版时改这一行)
│   ├── app.ico                     # 程序/托盘图标(16/24/32/48/256)
│   ├── umbral-keys.png             # 启动画面(以 RCDATA 嵌进 exe)
│   ├── capslock-switcher.rc        # 资源脚本
│   └── capslock-switcher.vcxproj   # 项目文件
├── capslock-switcher.slnx          # 解决方案
├── tests/
│   ├── regression.cpp              # 回归检查
│   └── run.ps1                     # 跑回归检查(自动加载 VS C++ 环境)
└── README.md                       # 本文件

光标清晰度验证

普通回归(不修改系统光标):./tests/run.ps1。覆盖原生多尺寸选帧、逐像素 Alpha/ 热点保真、DPI 切换、异常文件和着色生命周期。

关闭正在运行的 CapsLock Switcher 后,可执行 ./tests/run.ps1 -LiveCursor: 临时替换真实的箭头、I 型、手型、十字、横竖拉伸六个指针,检查中英文两色在 100%、60%、5% 时写入系统槽后的 像素、Alpha、尺寸、热点,以及退出还原结果;不写注册表,完成后按当前方案原图还原。 建议在 150% 等非整数缩放下运行,以抓住普通位图提交造成的二次缩放。

日语实现来源

Microsoft Learn:Keyboard Japan - ImeOn / ImeOff Implementation

https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/keyboard-japan-ime

普通回归覆盖语言分流、日语各状态、按键配对、布局改变、IME 超时/缺失、修饰键冲突和部分注入失败; 实机已在本机日语 IME 的独立编辑窗口中验证两轮三态循环,并另用后台进程验证跨进程读取和切换。 第三方日语 IME 尚未实测。

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages