(——旧的一些废话——)
Win10 1809 LTSC
打字时经常被站在插入点的鼠标指针挡住视线,有时可忍有时不可忍……
尽管Windows 是自带了“在打字时隐藏指针”选项,但该选项•半•点•用•也•没•有!
在中文网络基本上没人讨论,在英文网络倒是找到一些讨论,基本上都是说无效,有人还总结了具体会在什么地方无效……
(搞笑的是,这选项只是提供一个状态标记,其实际生效需要软件自行判断何时是“打字时”并自行检查上述状态标记,如果状态标记为“True”则在打字时自行隐藏鼠标指针;更搞笑的是,连微软自己的软件都不一定鸟这状态标记……)
问最近火爆的AI DeepSeek,其给出的方案一是使用第三方软件,第一个软件是 AutoHideMouseCursor (但它给了个错或过时的网址),第二个软件是 Cursor Hider(它依然给了个错或过时的网址)。第二个软件是试用版(共享)软件,开发商主页已消失;第一个是免费的而且我已经用过,的确是能隐藏鼠标指针,但问题就是其包含了个定时隐藏鼠标指针的主功能,打字隐藏鼠标只是附带的,也就是必需开着主功能不然附带功能也不生效……
方案二是用Windows自己的设置,已经确认无效;方案三和五是将鼠标指针移动到屏幕边缘,只不过方案三是写了个AutoHotkey脚本实现按快捷键移动鼠标指针而已;方案四则是离题了,让设置触摸板敏感度……
最后,在一个对微软的提问贴中找到了解决办法:
AHK脚本 Windows Cursor Hider
完全实现真正的打字时隐藏鼠标指针功能,完美!
↑ 并非完全,在恢复鼠标指针时会造成动画指针只显示第一帧
——
于是,我(以原版脚本为基础?)结合微软资料(winuser.h相关)和AI(Hunyuan & Gemini)重新编写的脚本,使用句柄取代简单图像提取,实现鼠标指针隐藏和恢复提示、可恢复原动画指针、可通过托盘菜单禁用。
与AI的“协作”……
- 因原脚本的缺陷,本来我已经弃用其一段时间了,但因为 鼠标动画不动了 提出其使用原版(并非我的改版)后遇到原版鼠标动画丢失的 bug ,于是我也尝试寻找这 bug 的源头及解决办法
- 基础问题:以原版(提供其 Github 网址)代码为基础,使用句柄方式解决动画指针不能恢复的问题(大概意思;使用句柄方式是在和 Hunyuan 问答中确定的)
-
- 通过几轮和 Hunyuan 的 battle 之后,包括它傻乎乎地自问自答 working in background 指针应该是哪个ID,它终于给出了比较完整的代码,但代码和源脚本完全不是一回事,推测只是阅读了源脚本的说明
-
- 且运行起来就只隐藏了 normal 指针,其他的都没正常隐藏,反馈这 bug 后其非但没修正甚至越改越不知在做什么无用功……
- 因为我也没看出代码问题在哪(涉及 Windows API 的指令不熟),所以同样问题我又找别的 AI 来尝试
-
- 找 DeepSeek ,估计也是没从原网址中查看源代码,只是输出了一通 Basic 代码;我追问 AHK 版本,其给出了一个用快捷键显示隐藏鼠标指针的脚本……根本不用试就知道其理解错了需求……
-
- 找 Gemini ,同样的问题,也是同样给出了用快捷键显隐鼠标指针的 AHK 脚本,而且还漏了持续运行的代码;反馈之后,不知它想通了啥,又自作主张将脚本改成定时三秒自动隐藏、移动鼠标恢复显示的 AHK 脚本……
- 但关键是,Hunyuan 的代码隐藏鼠标指针的响应和功能没问题(因为问了很多,所以其并非仅依据原版脚本的链接去思考,所以代码其实比较全面),只是没隐藏对;而 Gemini 则是非常好地实现了显隐,但没看清题意,而且其自己构建的空白指针是随机雪花的黑块……
- 于是我决定结合其两者的脚本代码,也就是用后者的显隐功能替代前者,但使用前者的响应逻辑和空白指针生成功能(空白指针是我指示 Hunyuan 参考我复制的源脚本代码段给出的),最终结果完满成功!
可在以下链接中下载 【打字隐藏鼠标指针.ahk】 来获取
——
注意:
①如果需要更换鼠标指针图案或主题,需要先关闭该脚本,更换后再重新启动该脚本。(因为脚本启动时会缓存当前在用的整套鼠标指针图案并在恢复显示时调用)
——
——
如果不便访问,以下是【打字隐藏鼠标指针.ahk】的源码:
展开源码
; ==================================================
; 系统光标隐藏与恢复脚本(无外部文件,内存创建透明光标)
; + 托盘菜单开关(启用/禁用功能)
; 触发:主键盘字符键按下(字母、数字、符号键,允许Shift,不含Ctrl/Alt/Win)
; 恢复:鼠标移动超过阈值(10像素)
; 仅针对系统光标,忽略其他程序自定义光标
; ==================================================
#NoEnv
#SingleInstance Force
SetBatchLines, -1
; --- 配置 ---
threshold := 10 ; 鼠标移动恢复阈值(像素)
enabled := true ; 初始启用光标隐藏功能
; --- 系统光标槽 OCR 常量(十进制)---
global CursorIDs := "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650"
global OriginalHandles := {}
cursor_hidden := false
hiddenX := hiddenY := 0
; 创建透明光标(32x32 单色全透明)
blankCursorHandle := CreateBlankCursor()
if !blankCursorHandle {
MsgBox, 创建透明光标失败!
ExitApp
}
; 注册字符键热键(字母、数字、主键盘符号键)
charKeys := "abcdefghijklmnopqrstuvwxyz0123456789"
loop, parse, charKeys
{
hotkey := "~" A_LoopField
Hotkey, %hotkey%, TriggerHide, On
}
symbolKeys := "-=[]\\;',./"
loop, parse, symbolKeys
{
hotkey := "~" A_LoopField
Hotkey, %hotkey%, TriggerHide, On
}
; 启动鼠标位置监控
SetTimer, CheckMouseMove, 50
; === 托盘菜单 ===
Menu, Tray, NoStandard
Menu, Tray, Add, 切换光标隐藏, ToggleEnabled
Menu, Tray, Add, 退出, ExitScript
; 初始化托盘提示文字
UpdateTrayTip()
Menu, Tray, Icon
return
UpdateTrayTip() {
statusText := enabled ? "启用" : "禁用"
Menu, Tray, Tip, 系统光标隐藏脚本`n状态: %statusText%
}
ToggleEnabled:
enabled := !enabled
UpdateTrayTip()
; 先准备 ToolTip 文本
newStatus := enabled ? "启用" : "禁用"
ToolTip, 光标隐藏功能已%newStatus%
SetTimer, RemoveToolTip, 1500
return
RemoveToolTip:
SetTimer, RemoveToolTip, Off
ToolTip
return
ExitScript:
ExitApp
; --------------------------------------------------
TriggerHide:
if !enabled
return
if (cursor_hidden)
return
mods := GetModifiersState()
if (mods.Ctrl || mods.Alt || mods.Win)
return
; 执行隐藏
HideCursors()
cursor_hidden := true
MouseGetPos, hiddenX, hiddenY
ToolTip, 光标已隐藏
SetTimer, RemoveToolTip, 1000
return
; --------------------------------------------------
CheckMouseMove:
if !enabled
return
if (!cursor_hidden)
return
MouseGetPos, curX, curY
dx := curX - hiddenX
dy := curY - hiddenY
if (Abs(dx) > threshold || Abs(dy) > threshold) {
RestoreCursors()
cursor_hidden := false
ToolTip, 光标已恢复
SetTimer, RemoveToolTip, 1000
}
return
; --------------------------------------------------
CreateBlankCursor() {
width := 32
height := 32
rowSize := (width + 7) // 8
totalBytes := rowSize * height
VarSetCapacity(andMask, totalBytes, 0xFF)
VarSetCapacity(xorMask, totalBytes, 0)
andPtr := &andMask
xorPtr := &xorMask
hCursor := DllCall("CreateCursor"
, "uint", 0
, "int", 0
, "int", 0
, "int", width
, "int", height
, "uint", andPtr
, "uint", xorPtr
, "uint")
return hCursor
}
HideCursors() {
; 创建透明光标
hInvisibleCursor := CreateBlankCursor()
Loop, Parse, CursorIDs, `,
{
ID := A_LoopField
; 复制当前光标句柄(包含动画状态)并保存
hCurrent := DllCall("CopyIcon", "Ptr", DllCall("LoadCursor", "Ptr", 0, "Ptr", ID), "Ptr")
OriginalHandles[ID] := hCurrent
; 替换为透明
DllCall("SetSystemCursor", "Ptr", DllCall("CopyIcon", "Ptr", hInvisibleCursor), "Int", ID)
}
}
RestoreCursors() {
Loop, Parse, CursorIDs, `,
{
ID := A_LoopField
hSaved := OriginalHandles[ID]
if (hSaved) {
; 还原保存的句柄
DllCall("SetSystemCursor", "Ptr", DllCall("CopyIcon", "Ptr", hSaved), "Int", ID)
; 清理保存的句柄副本
DllCall("DestroyIcon", "Ptr", hSaved)
OriginalHandles[ID] := 0
}
}
; 刷新系统光标设置
DllCall("SystemParametersInfo", "UInt", 0x57, "UInt", 0, "Ptr", 0, "UInt", 0)
}
; --------------------------------------------------
GetModifiersState() {
state := Object()
state.Ctrl := GetKeyState("Ctrl") ? true : false
state.Alt := GetKeyState("Alt") ? true : false
state.Shift := GetKeyState("Shift") ? true : false
state.Win := GetKeyState("LWin") || GetKeyState("RWin") ? true : false
return state
}
; --------------------------------------------------
; 退出时恢复光标并销毁透明光标句柄
OnExit, Cleanup
Cleanup:
RestoreCursors()
if (blankCursorHandle) {
DllCall("DestroyCursor", "uint", blankCursorHandle)
}
ExitApp
