使用 GetAsyncKeyState() 识别按下的热键仅在 [重复]

Posted

技术标签:

【中文标题】使用 GetAsyncKeyState() 识别按下的热键仅在 [重复]【英文标题】:Idenifying pressed HotKey with GetAsyncKeyState() only returns correct result if it's called once before [duplicate] 【发布时间】:2019-07-04 21:29:41 【问题描述】:

我对这个很困惑。我有一种方法可以检查是否按下了热键(使用RegisterHotkey)。 我在热键上调用GetAsyncKeyState(vKey),它的修饰符决定了哪个已注册的热键被这样调用。

    public bool IsPressed()
    
         // Checks if the key and any (but not all) required modifiers are pressed
        // Int16.MinValue indicates that a key is pressed - 0 indicates it isn't - Keys.None cannot be used
        return GetAsyncKeyState(Key) == Int16.MinValue && (Modifier == ModifierKeys.None ||
            (Modifier == ModifierKeys.Shift && GetAsyncKeyState(Keys.ShiftKey) == Int16.MinValue) ||
            (Modifier == ModifierKeys.Alt && GetAsyncKeyState(Keys.Alt) == Int16.MinValue) ||
            (Modifier == ModifierKeys.Control && GetAsyncKeyState(Keys.ControlKey) == Int16.MinValue) ||
            (Modifier == ModifierKeys.Windows && (GetAsyncKeyState(Keys.LWin) == Int16.MinValue || GetAsyncKeyState(Keys.RWin) == Int16.MinValue))
            );
    

以上返回false。所以我尝试单独添加语句以查看问题所在:

public bool IsPressed()


var keything =  GetAsyncKeyState(Key);

bool a = GetAsyncKeyState(Key) == Int16.MinValue && (Modifier == ModifierKeys.None);
bool b = (Modifier == ModifierKeys.Shift && GetAsyncKeyState(Keys.ShiftKey) == Int16.MinValue);
bool c = (Modifier == ModifierKeys.Alt && GetAsyncKeyState(Keys.Alt) == Int16.MinValue);
bool d = (Modifier == ModifierKeys.Control && GetAsyncKeyState(Keys.ControlKey) == Int16.MinValue);
bool e = (Modifier == ModifierKeys.Windows && (GetAsyncKeyState(Keys.LWin) == Int16.MinValue || GetAsyncKeyState(Keys.RWin) == Int16.MinValue));
bool f = GetAsyncKeyState(Key) == Int16.MinValue && (Modifier == ModifierKeys.None ||
    (Modifier == ModifierKeys.Shift && GetAsyncKeyState(Keys.ShiftKey) == Int16.MinValue) ||
    (Modifier == ModifierKeys.Alt && GetAsyncKeyState(Keys.Alt) == Int16.MinValue) ||
    (Modifier == ModifierKeys.Control && GetAsyncKeyState(Keys.ControlKey) == Int16.MinValue) ||
    (Modifier == ModifierKeys.Windows && (GetAsyncKeyState(Keys.LWin) == Int16.MinValue || GetAsyncKeyState(Keys.RWin) == Int16.MinValue))
    );


// Checks if the key and any (but not all) required modifiers are pressed
// Int16.MinValue indicates that a key is pressed - 0 indicates it isn't - Keys.None cannot be used
return GetAsyncKeyState(Key) == Int16.MinValue && (Modifier == ModifierKeys.None ||
    (Modifier == ModifierKeys.Shift && GetAsyncKeyState(Keys.ShiftKey) == Int16.MinValue) ||
    (Modifier == ModifierKeys.Alt && GetAsyncKeyState(Keys.Alt) == Int16.MinValue) ||
    (Modifier == ModifierKeys.Control && GetAsyncKeyState(Keys.ControlKey) == Int16.MinValue) ||
    (Modifier == ModifierKeys.Windows && (GetAsyncKeyState(Keys.LWin) == Int16.MinValue || GetAsyncKeyState(Keys.RWin) == Int16.MinValue))
    );

A 和 F 返回 true - 应该如此(F 也只是被返回的语句的副本)... 然而,让我没想到的是,方法本身也返回了true。

因此,在实际查询之前添加对 GetAsyncKeyState() 的调用会使其正常工作。 为什么会这样以及解决这个问题的最佳方法是什么(除了对函数的死调用)

【问题讨论】:

我无法运行此程序(病毒扫描程序阻止了我),但您不应该屏蔽 (state & SomeKey == SomeKey) 吗?因为"if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState". 只是 ESET 检测到对 GetAsyncKeyState() 的调用作为键盘记录器并擦除了我的可执行文件。 为什么要这样做,因为热键会将特定消息发布到它的窗口? It's just that ESET detects the presence of the call to GetAsyncKeyState() as a keylogger and wipes my executable. 太好了,正是我们需要的(!) 您正在错误地测试结果。见GetAsyncKeyState "strange" behavior 【参考方案1】:

而不是建议的 HotKey.IsPressed() 使用 GetAsyncKeyState() - 您可以改为从侦听器的 lParam 确定热键,如下所示:

热键类中的 IsPressed 如下所示:

public bool IsPressed(IntPtr lParam)

    uint param = (uint)lParam.ToInt64();
    var inputKey = (Keys)((param & 0xffff0000) >> 16);
    var inputModifier = (ModifierKeys)(param & 0x0000ffff);

    return inputKey == this.Key && inputModifier == this.Modifier;

或者使用它的一些变体,它不必在每次 IsPressed 调用时计算它。

【讨论】:

以上是关于使用 GetAsyncKeyState() 识别按下的热键仅在 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用 GetAsyncKeyState() 的键监听器/记录器

GetRawInputData 与 GetAsyncKeyState()

GetAsyncKeyState 使用 cin 创建问题

杂文虚拟键码表(供函数GetAsyncKeyState()使用)

为啥在 Win32 中使用 `GetAsyncKeyState()` 时我的热键会出错?

将 GetAsyncKeyState() 重置为默认值