# #HotIf

创建上下文相关的热键和热字串. 这样的热键会根据表达式的结果执行不同的操作(或什么都不做).

    #HotIf Expression

## 参数

Expression

  类型: 布尔值

  任何有效的表达式. 这将成为隐式函数的返回值, 该函数有一个参数(ThisHotkey). 该函数不能直接修改全局变量(因为它通常是假定-局部函数, 而且不能包含声明), 但可以调用其他函数来修改全局变量.

## 基本操作

#HotIf 指令设置表达式, 随后创建的热键将使用该表达式来确定是否应激活它们. 当按下键, 鼠标按钮或组合键, 或者在程序需要知道热键是否处于活动状态时, 将对该表达式求值.

要生成上下文敏感的热键和热字串, 只需在它们前面加上 #HotIf 指令. 例如:

    #HotIf WinActive("ahk_class Notepad") or WinActive(MyWindowTitle)
    #Space::MsgBox "You pressed Win+Spacebar in Notepad or " MyWindowTitle

#HotIf 指令是与位置相关的: 它会影响脚本中在它后面的所有热键和热字串, 直到下一个 #HotIf 指令.

注意: 与 if 语句不同, 大括号对 #HotIf 指令无效.

要关闭热键的上下文相关性, 请指定不带任何表达式的 #HotIf 指令. 例如:

    #HotIf

和其他指令一样, #HotIf 不能有条件地执行.

当通过 #HotIf 禁用鼠标或键盘热键时, 它会执行其原来的功能; 也就是说, 它传递到活动窗口, 就好像不存在热键一样. 但有一个例外: 操纵杆热键: 尽管 #HotIf 有效, 它始终不会阻止其他程序看到操纵杆按钮按下.

#HotIf 也可以用来改变普通按键(例如 `Enter` 或 `Space`) 的行为. 当某个特定窗口忽略该键或执行某些您认为不需要的操作时, 这是非常有用的. 例如:

    #HotIf WinActive("Reminders ahk_class #32770")  ; Outlook 中的 "reminders" 窗口.
    Enter::Send "!o"  ; 按下 "Enter" 打开 reminder, 而不是 snoozing.
    #HotIf

## 变体(副本) 热键

一个特定的热键或热字串在脚本中可以被创建多次, 如果每个定义有不同的 #HotIf 条件. 这被称为 热键变体. 例如:

    #HotIf WinActive("ahk_class Notepad")
    ^!c::MsgBox "You pressed Control+Alt+C in Notepad."
    #HotIf WinActive("ahk_class WordPadClass")
    ^!c::MsgBox "You pressed Control+Alt+C in WordPad."
    #HotIf
    ^!c::MsgBox "You pressed Control+Alt+C in a window other than Notepad/WordPad."

如果有多个变体符合触发条件, 那么仅触发最早创建的那个. 这种情况的例外是全局变体(不带 #HotIf 条件的那个): 它的优先级总是最低的, 仅当其他变体都不触发时它才会被触发(此例外不适用热字串).

创建重复热键时, 修饰符的顺序(如 ^!+#) 没有关系. 例如, `^!c` 等同于 `!^c`. 但是, 按键必须拼写一致. 例如, 为了这个目的时, Esc 不同于 Escape(尽管大小写无关). 最后, 任何带有通配符前缀(*) 的热键和不带通配符的热键是完全独立的; 例如, `*F1` 和 `F1` 都可以有他们各自的变体.

窗口组可以用来使热键为一组窗口执行. 例如:

    GroupAdd "MyGroup", "ahk_class Notepad"
    GroupAdd "MyGroup", "ahk_class WordPadClass"

    #HotIf WinActive("ahk_group MyGroup")
    #z::MsgBox "You pressed Win+Z in either Notepad or WordPad."

另外, 也可以通过 `#HotIf WinActive("ahk_group MyGroup")` 来使用窗口组.

要动态地创建热键变体(当脚本运行时), 请参阅 HotIf.

## 表达式的计算

当热键, 鼠标或操纵杆按钮组合被按下时, #HotIf 表达式被计算以确定热键是否应该被激活.

注意: 脚本不应假定表达式只在按键被按下时才被计算(见下文).

只要程序需要知道热键是否被激活, 表达式也可以被计算. 例如, #HotIf 表达式作用于一个自定义组合热键(如 `a & b::`), 当按下前缀按键(这个例子中的 `a`) 时, 表达式将会计算一次, 计算结果将决定组合热键是否起作用.

注意: 使用 #HotIf 时, 在脚本无响应时可能会导致输入滞后或破坏热键(见下文).

对于 #HotIf 指令还有一些注意事项:

- 键盘或鼠标输入通常被缓冲(延迟), 直到表达式计算完成或超时.
- 表达式的计算只能由脚本的主线程(在操作系统级别, 而不是准线程), 而不是由键盘/鼠标钩子直接执行. 如果脚本忙或者没有响应, 比如在进程中出现了 FileCopy, 那么表达式的计算就会被延迟, 并且可能会超时.
- 如果达到系统定义的超时, 系统可能会停止通知脚本键盘或鼠标输入(有关详细信息, 请参阅 #HotIfTimeout).
- 在计算表达式时, 发送击键或鼠标单击(例如, 从它调用的函数中), 可能会导致并发, 应该避免.

ThisHotkey, A_ThisHotkey 和 A_TimeSinceThisHotkey 是基于当前正在计算的 #HotIf 表达式的热键来设置的.

A_PriorHotkey 和 A_TimeSincePriorHotkey 暂时包含对应 "This" 变量的前一个值.

## 优化

为避免对 WinActive 或 WinExist 的简单调用而去计算表达式, 对 #HotIf 进行了优化, 从而降低了在这种情况下出现滞后或其他问题的风险. 具体来说:

- 表达式必须包含一次对 WinExist 或 WinActive 的调用.
- 每个参数必须是一个单引号的字符串, 并且不得使用超过两个参数.
- 结果可以用 `not` 或 `!` 进行反转, 但不能使用其他运算符.
- 当表达式被预编译时, 空白和括号会被完全处理, 因此不会影响这种优化.

如果表达式符合这些条件, 则直接由程序计算, 不会出现在 ListLines 中.

在使用热键函数修改现有的热键变体之前, 通常 HotIf 函数必须与原始表达式文本一起使用. 然而, 第一个具有给定组合条件的唯一表达式也可以被该条件引用. 例如:

    HotIfWinExist "ahk_class Notepad"
    Hotkey "#n", "Off"  ; 关闭热键.
    HotIf 'WinExist("ahk_class Notepad")'
    Hotkey "#n", "On"   ; 打开同一个热键.

    #HotIf WinExist("ahk_class Notepad")
    #n::WinActivate

注意, 任何变量的使用都会取消表达式的资格. 如果在创建热键后, 变量的值永远不会改变, 有两种策略可以最大限度地降低 #HotIf 的滞后风险或其他固有问题:

- 使用 `HotIfWin... MyTitleVar` 来设置条件和 `Hotkey KeyName, Label` 来创建热键变体.
- 使用常量表达式, 如 `#HotIf WinActive("ahk_group MyGroup")` 和并在脚本的其他地方使用 `GroupAdd "MyGroup", MyTitleVar` 定义窗口组.

## 备注

适当的时候, #HotIf 也会将前缀键恢复到它们的原生功能(如 `a & b`, 前缀键是热键中的 `A`). 当给定的前缀键没有启用热键时, 就会发生这种情况.

当 Gosub 或 Goto 用于跳转到一个热键或热字符串标签时, 它会跳转到最接近脚本顶部的变体.

当前被 #HotIf 禁用的热键, 它的按键或鼠标按钮在 KeyHistory 的 "Type" 列中显示时会带有 "#" 字符. 这可以帮助调试脚本.

Alt-tab 热键不受 #HotIf 影响: 它们对所有窗口都有效.

最后找到的窗口可以通过 #HotIf 来设置. 例如:

    #HotIf WinExist("ahk_class Notepad")
    #n::WinActivate  ; 激活由 WinExist() 找到的窗口.

## 相关

#HotIfTimeout 可以用于覆盖默认的超时时间值.

Hotkey 函数, 热键, 热字串, Suspend, WinActive, WinExist, SetTitleMatchMode, DetectHiddenWindows

## 示例

创建只有在记事本处于活动状态时才生效的两个热键和一个热字符串, 而一个热键则适用于除记事本以外的任何窗口.

    #HotIf WinActive("ahk_class Notepad")
    ^!a::MsgBox "You pressed Ctrl-Alt-A while Notepad is active."
    #c::MsgBox "You pressed Win-C while Notepad is active."
    ::btw::This replacement text for "btw" will occur only in Notepad.
    #HotIf
    #c::MsgBox "You pressed Win-C in a window other than Notepad."

允许在任务栏上滚动鼠标滚轮来调节音量.

    #HotIf MouseIsOver("ahk_class Shell_TrayWnd")
    WheelUp::Send "{Volume_Up}"
    WheelDown::Send "{Volume_Down}"

    MouseIsOver(WinTitle) {
        MouseGetPos ,, &Win
        return WinExist(WinTitle " ahk_id " Win)
    }

在所有的编辑控件中的轻松删除单词的快捷键.

    #HotIf ActiveControlIsOfClass("Edit")
    ^BS::Send "^+{Left}{Del}"
    ^Del::Send "^+{Right}{Del}"

    ActiveControlIsOfClass(Cls) {
        FocusedControl := 0
        try FocusedControl := ControlGetFocus("A")
        FocusedControlClass := ""
        try FocusedControlClass := WinGetClass(FocusedControl)
        return (FocusedControlClass=Cls)
    }

与上下文不相关的热键.

    #HotIf
    Esc::ExitApp

动态热键. 这个例子在运行前需要整和示例 #2.

    NumpadAdd::
    {
        static toggle := false
        HotIf 'MouseIsOver("ahk_class Shell_TrayWnd")'
        if (toggle := !toggle)
            Hotkey "WheelUp", DoubleUp
        else
            Hotkey "WheelUp", "WheelUp"
        return
        ; 嵌套函数:
        DoubleUp(ThisHotkey) => Send("{Volume_Up 2}")
    }

dftg