只响应第一个WM_KEYDOWN通知?

4
一个Win32应用程序如何只响应第一个WM_KEYDOWN通知?MSDN文档声称位30“指定先前的键状态。如果在发送消息之前按下该键,则该值为1,否则为0。”但是在我的WndProc中,位30始终为0。
case WM_KEYDOWN:
    // ToDo - stop multiple notifications for repeating keys
    printf("WM_KEYDOWN %i %i", wParam, lParam & 30);
    return 0;
lParam & 30 是查询这个是否错误的正确方法吗?我还有其他做法错误吗?

你是怎么实现这个的?repeatCount=(lParam & 0xffff); if(repeatCount < 1) Action(); 对我来说似乎不起作用。重复次数小于2也不行。我要么得到重复的按键,要么根本没有按键按下。 - Sam Becker
1
我使用了以下代码:if ((lParam & (1 << 30)) == 0)...虽然如果我没记错的话,if (lParam & 0x40000000) 也是可以的。但是我的选择基于可读性,对我来说(1 << 30)比0x40000000更有意义。 - Nick Van Brunt
4个回答

12

要测试第30位,请不要与30进行AND操作,而是与1<<30进行AND操作。

const bool isBitSet = lParam & (1 << 30);

它可能读起来更好,但每次都必须计算(除非编译器正在优化此过程)。0x4000000会更快。 - kjfletch
3
VC++7正在将其优化为一个常量值。 - sharptooth
1
@kjfletch,这种微小的优化已经不再需要了。任何简单的编译器都可以进行优化。 - Davy Landman
@kjfletch,即使您没有进行优化,计时器显示的速度有多快?在我的测试中,WM_KEYDOWN事件每100万纳秒只出现一次,而移位需要多长时间,比如1纳秒?除非这个位真的很、很、非常重,否则它最多只需要_可能_3.5纳秒。最大值. - SO_fix_the_vote_sorting_bug

4
要获取第30位,您需要使用以下代码:
(lParam & 0x40000000)

另一种选择是使用位0-15来获取重复计数:

int repeatCount = (lParam & 0xffff)

仅当重复计数为0时(或可能为1;我不确定第一条消息是否获得重复计数为0或1,并且文档中也不清楚)才执行任何操作。


这个可行 - 谢谢。我的位操作不太稳定。0x40000000具体是什么? - Nick Van Brunt
2
这是一个DWORD,表示由第30位设置和所有其他位清除的位掩码。 - sharptooth
你可能想要阅读十六进制的介绍,例如 http://www.learn-programming.za.net/articles_decbinhexoct.html。这并不太难,但也不是我能在这里解释清楚的那么简单。 - RichieHindle

4

按位与(lParam & 0x4000000)可以使用,但你可以更容易地使用Windows.h中已包含的定义(你已经在使用WM_KEYDOWN)使其更易读:

case WM_KEYDOWN:
    if((HIWORD(lParam) & KF_REPEAT) == 0) //process wParam
    return 0;

HIWORD 取最高的16位。

KF_REPEAT (= 0x4000) 定位代表重复 WM_KEYDOWN 消息的比特位。

这些值的按位与在重复标志关闭时(初始按键)等于0,在之后的每次按键中都等于1(自动重复功能),直到释放按键为止。

这是一个小细节,但它可以大大提高您代码的可读性。对于读者来说,0x40000000 没有意义,而从 KF_REPEAT 中可以推断出更多信息。


1

执行 lParam & 30 的问题在于,这里的“30”被视为十进制数,当转换为二进制时会变成“11110”。因此,您并没有测试第30位,而只是获取了 lParam & 11110 的结果。

希望这能够稍微澄清一下问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接