使用 ahk 的用户是否遇到过 alt 物理上释放(松开按键), 但逻辑上还是按下的状态

在写 ahk 脚本的时候, 使用 alt 做修饰键遇到的问题, 热键执行完毕后, alt 仍然是处于被按下状态, 这样的问题要如何解决。

已知的解决方案:

  1. 再次按下 alt 键即可恢复
  2. 再开一个脚本, 脚本中安装键盘钩子, 可以不加任何功能, 但要能确保在后台运行, 此时的 alt 卡死现象将会得到改善
  3. 启动一个计时器, 检测 alt 的逻辑状态和物理按下状态, 如果 alt 的物理状态是松开, 但逻辑状态是按下, 那么发送一个释放命令 [ 例如: send("{blind}{alt up}")) ] , 参考: 如何使用 AutoHotkey 解决 Alt 键被卡住的问题 - 知乎 (zhihu.com)

问题:

  1. autohotkey 检测按键的物理状态函数有时会失效, 即 getKeyState("keyname", "P") 失效, 这就导致了第 3 个解决方案有时会无效。造成这种现象出现的原因是, ahk 忽略了 alt 键的物理释放, 以至于 alt 键已经物理释放, 但是使用getKeyState("keyname", "P") 返回的仍然是按下的状态。

是什么样的脚本咧?脚本里面是否用到 Alt 键?

我看到 AutoHotkey_L (1.1) 更新历史里面似乎提到一些关于 Alt 键的修复,
或许你还可以尝试更新一下 AutoHotkey 的版本~

经常遇到,但代码中明明没有对应的键操作。有时候是Ctrl,有时候是Alt,Win键有时候也有。

临时解决方法就是这三个键按一下,有解决办法了踢我一脚。

我用的版本是1.1.33.9,准备更新一下新版试试看。

遇到过,但那是因为我把Capslock remap成了长按Ctrl短按Esc,每次切到日文输入法时,只要按了Ctrl组合键就会炸,因为在日文输入法里Capslock有别的功能,一起触发就混乱了。这个问题我没有办法解决,只是提供一个思路看看是不是跟在使用的别的软件有冲突。

这个需求你可以试试别的映射软件,比如

g_LastCtrlKeyDownTime := 0
g_AbortSendEsc := false
g_ControlRepeatDetected := false
*CapsLock::
    if (g_ControlRepeatDetected)
    {
        return
    }

    send,{Ctrl down}
    g_LastCtrlKeyDownTime := A_TickCount
    g_AbortSendEsc := false
    g_ControlRepeatDetected := true

    return

*CapsLock Up::
    send,{Ctrl up}
    g_ControlRepeatDetected := false
    if (g_AbortSendEsc)
    {
        return
    }
    current_time := A_TickCount
    time_elapsed := current_time - g_LastCtrlKeyDownTime
    if (time_elapsed <= 250)
    {
        SendInput {Esc}
    }
    return

~*^a::
~*^b::
~*^c::
~*^d::
~*^e::
~*^f::
~*^g::
~*^h::
~*^i::
~*^j::
~*^k::
~*^l::
~*^m::
~*^n::
~*^o::
~*^p::
~*^q::
~*^r::
~*^s::
~*^t::
~*^u::
~*^v::
~*^w::
~*^x::
~*^y::
~*^z::
~*^1::
~*^2::
~*^3::
~*^4::
~*^5::
~*^6::
~*^7::
~*^8::
~*^9::
~*^0::
~*^Space::
~*^Backspace::
~*^Delete::
~*^Insert::
~*^Home::
~*^End::
~*^PgUp::
~*^PgDn::
~*^Tab::
~*^Return::
~*^,::
~*^.::
~*^/::
~*^;::
~*^'::
~*^[::
~*^]::
~*^\::
~*^-::
~*^=::
~*^`::
~*^F1::
~*^F2::
~*^F3::
~*^F4::
~*^F5::
~*^F6::
~*^F7::
~*^F8::
~*^F9::
~*^F10::
~*^F11::
~*^F12::
    g_AbortSendEsc := true
    return

知乎上一篇文章, 可以参考 如何使用 AutoHotkey 解决 Alt 键被卡住的问题 - 知乎 (zhihu.com)

2 Likes

我用的V2

借楼问个问题
在v2里以下代码怎么实现?

^CapsLock::
	V_keytonum := !V_keytonum
	LockTooltip(V_keytonum ? "模拟NumLock已开启" : "模拟NumLock已关闭", 2000)
Return

一直想跟随时代转到v2,但是一直看不懂怎么v2的!是非符号怎么用
有没有懂哥给个例子

没有标签全变函数了
变量要先声明 (V_keytonum )
LockTooltip 我猜是个延时2000ms自动关闭的ToolTip
最主要是这原始代码没有任何作用,就是个单纯的提示功能
我猜测你是想转换小键盘状态 SetNumLockState

^CapsLock::
{
    static V_keytonum := GetKeyState("NumLock", "T")
    V_keytonum := !V_keytonum
    SetNumLockState(V_keytonum)
	ToolTip(V_keytonum ? "模拟NumLock已开启" : "模拟NumLock已关闭")
    SetTimer(()=>ToolTip(),2000)
}

!就是反转 true false
你不要理解为 true := !true
要这样理解

var := true
var := !true
MsgBox(var == false)

可以试试,但是我有一些脚本是模拟了按下某键后操作,过程大概持续有几秒,这个计时器有可能会导致原有脚本失灵

在你热键语句的return前加上这几行试试能不能用

  state_Alt := GetKeyState("Alt")	;获取Alt键的功能状态,用户或者程序按下为1,否则为0 
	state_Alt_P := GetKeyState("Alt", "P") ;获取Alt键的物理状态,用户或者程序按下为1,否则为0
  if((state_Alt = 1) and (state_Alt_P = 0))
  {
    Send,{Alt}{Up}
  }

我不是要检测实体的numlock状态,是检测随意一个值的是非来给小配列的键盘分层
看了你这个依然不知道怎么先声明,我刚才试了好几次都不行,水平有限
我把我完整的代码贴出来,帮我转换个完整的吧,谢谢大佬

^CapsLock::
	V_keytonum := !V_keytonum
	LockTooltip(V_keytonum ? "模拟NumLock已开启" : "模拟NumLock已关闭", 2000)
Return


#If V_keytonum
0::NumpadDiv      ;/
j::Numpad1
k::Numpad2
l::Numpad3
u::Numpad4
i::Numpad5
o::Numpad6
7::Numpad7
8::Numpad8
9::Numpad9
p::NumpadMult      ;*
`;::NumpadSub      ;-
/::NumpadAdd       ;+
m::Numpad0
,::send {Numpad0 2}    ;00
h::Backspace
z::NumpadDel
.::NumpadDot
w::NumpadUp
s::NumpadDown
a::NumpadLeft
d::NumpadRight
Enter::NumpadEnter
F1::F13
F2::F14
F3::F15
F4::F16
F5::F17
F6::F18
F7::F19
F8::F20
F9::F21
F10::F22
F11::F23
F12::F24
#If


LockTooltip(lockmsg,locksec="",spkmod="") {
    if (spkmod = 1) {
	run mshta vbscript:createobject("sapi.spvoice").speak("%lockmsg%")(window.close)
    }
	ToolTip % lockmsg
	SetTimer, rmtooltip, %locksec%
return
rmtooltip:
	ToolTip
return
}

没有标签意味着原来设置快捷键的标签部分是属于函数了
函数里不能修改全局变量,由于局部变量是临时的所以需要 static
这样写你应该看得明白吧,我以为你是改变小键盘状态所以初始了当前小键盘的状态
你不需要这种的直接初始成 fasle 或者 true就行了
其实没必要非要转V2,能用就行了.毕竟还在beta呢

    static V_keytonum := fasle

懂了,谢谢

遇到過,後面選擇支持固件級別改鍵的鍵盤了,軟件兼容還是差些。

解决方案 4: 使用 sharpkeys 软件 (注册表的方式修改按键映射) 将 alt 映射为 scroll lock 键(这个键我几乎没用过), 然后在 ahk 中让 scroll lock 代替 alt 充当修饰键的角色

使用 KeyWait
例如
!v::
KeyWait, Alt ; 或许解决alt占用问题
Send, +{Ins}
Return

可以试试不同的方案, 来实现 capslock 映射
CapsLock 映射 单击 Esc, 组合键 Ctrl - 知乎 (zhihu.com)