KeyDown,KeyPress 和KeyUp详解

来源:互联网 发布:u盘安装linux 编辑:程序博客网 时间:2024/05/16 05:49

  Windows窗体通过引发键盘事件来处理键盘输入以响应Windows消息,大多数Windows窗体应用程序都通过处理键盘事件来以独占方式处理键盘输入。

1.按键的类型

  Windows窗体将键盘输入标识为由按位Keys枚举表示的虚拟键代码。使用Keys枚举,可以综合一系列按键以生成单个值,这些值与WM_KEYDOWN和WM_SYSKEYDOWNWindows消息所伴随的值相对应。另外,程序开发人员可通过处理KeyDown或KeyUp 事件来检测大多数物理按键操作。字符键是Keys枚举的子集,它们与WM_CHAR和WM_SYSCHAR Windows消息所伴随的值相对应,如果通过组合按键得到一个字符,则可以通过处理KeyPress事件来检测该字符。

2. 定义

KeyDown:在控件有焦点的情况下按下键时发生。

KeyPress:在控件有焦点的情况下按下键时发生。(下面会说和KeyDown 的区别)

KeyUp:在控件有焦点的情况下释放键时发生。

注意:KeyDown触发后,不一定触发KeyUp,当KeyDown 按下后,拖动鼠标,那么将不会触发KeyUp事件。

3.键盘事件的顺序

  一个控件上可能出现3个与键盘相关的事件,下面是这些事件发生的常规顺序:

  • 用户按“a”键,该键将被预处理和调度,而且会发生KeyDown事件。
  • 用户按住“a”键,该键将被预处理和调度,而且会发生KeyPress事件。
  • 用户松开“a”键,该键将被预处理和调度,而且会发生KeyUp事件。

4.键的预处理

  像其他消息一样,键盘消息是在窗体或控件的WndProc方法中处理的。窗体或控件在处理键盘消息之前,PreProcessMessage方法会调用一个或多个方法,这些方法可被重写以处理特殊的字符键和物理按键。

 

5. KeyPress 和KeyDown 、KeyPress之间的区别

  • KeyPress主要用来捕获数字(注意:包括Shift+数字的符号)、字母(注意:包括大小写)、小键盘等除了F1-12、SHIFT、Alt、Ctrl、Insert、Home、PgUp、Delete、End、PgDn、ScrollLock、Pause、NumLock、{菜单键}、{开始键}和方向键外的ANSI字符。
    KeyDown 和KeyUp 通常可以捕获键盘除了PrScrn所有按键(这里不讨论特殊键盘的特殊键)。
  • KeyPress 只能捕获单个字符
  • KeyDown 和KeyUp 可以捕获组合键(任何时候都可用Control.ModifierKeys属性获取SHIFT、Alt、Ctrl的状态,这对于不支持KeyDown 事件的控件非常有用)。
  • KeyPress 可以捕获单个字符的大小写
  • KeyDown和KeyUp 对于单个字符捕获的KeyValue 都是一个值,也就是不能判断单个字符的大小写。 (可通过.net 2.0中新增Control.IsKeyLocked(Keys.CapsLock)方法判断CapsLock的状态,类似,Scroll Lock和Num Lock也可通过Control.IsKeyLocked()方法来判断)。
  • KeyPress 不区分小键盘和主键盘的数字字符。
  • KeyDown 和KeyUp 区分小键盘和主键盘的数字字符。
  • 其中PrScrn 按键KeyPress、KeyDown和KeyUp 都不能捕获。

  以上说明可以通过一些简单代码测试,例如:

    private void txtKey_KeyPress(object sender, KeyPressEventArgs e)
        {
            label1.Text = "key press:" + e.KeyChar.ToString();
        }

        private void txtKey_KeyDown(object sender, KeyEventArgs e)
        {
            label2.Text = "key code:" + e.KeyCode.ToString();
            label2.Text += "/nkey value:" + e.KeyValue.ToString();
            label2.Text += "/nkey data:" + e.KeyData.ToString();
        }

6. 获取按键状态

需获取各键状态,要用到GetKeyState()及GetAsyncKeyState()方法,如下:

[DllImport("User32.dll")]
private static extern short GetKeyState(System.Windows.Forms.Keys key);

......
if (GetKeyState(Keys.Insert) == 1)
{
  // Overwrite mode is on.
}
else
{
  // Insert mode is on.
}

 

[DllImport("User32.dll")]
private static extern short GetAsyncKeyState(System.Windows.Forms.Keys key);

 

...........

     short state = GetAsyncKeyState(Keys.D);
     switch (state)
     {
         case 0:
              lbl.Text = "D has not been pressed since the last call.";
              break;
         case 1:
               lbl.Text = "D is not currently pressed, but has been pressed since the last call.";
               break;
         case -32767:
               lbl.Text = "D is currently pressed.";
               break;
    }

    那么两者有什么区别呢?查了下,有人提到说:GetKeyState得到的结果是在获取到当前消息时的键盘上按键状态的一个映像,也就是说,这个状态不会随着按键真实按键状态的改变而改变。其实通常情况下得到这样非实时的结果就足够了。由于只是查表,所以速度较快,但是决不能写出下面的代码

      while(GetKeyState(nVirKey))

      {

            //code here

      }

  而要得到某一个键实时的状态,则应该使用GetAsyncKeyState,这个函数通过查询Driver而得到实时的信息。但是这个函数较GetKeyState慢。(KeyDown,KeyPress <wbr>和KeyUp详解这点还不大明白···)

 

7. 系统组合键的判定

  在使用键盘的时候,通常会使用到CTRL+SHIFT+ALT 类似的组合键功能。对于此,我们如何来判定?

    通过KeyUp 事件能够来处理(这里说明一下为什么不用KeyDown,因为在判定KeyDown的时候,CTRL、SHIFT和ALT 属于一直按下状态,然后再加另外一个键是不能准确捕获组合键,所以使用KeyDown 是不能准确判断出的,要通过KeyUp 事件来判定 )

    这里简单的列举出CTRL+其它7键的组合判定代码:
        private void Form3_KeyUp(object sender, KeyEventArgs e)
        {
            
if (e.Control)
            {
                MessageBox.Show(
"KeyUp:Ctrl+" + e.KeyValue.ToString());
            }
        }

 

 8. 捕获PrScrn按键事件

   通过一种钩子的方式可以判定PrScrn 按键事件,钩子可以获取任何键盘事件。

     这里给出CodeProject 上面的开源代码的解决方案。大家有兴趣自己研究吧:Global System Hooks in .NET 。

 

  其实我们按下一个键时,KeyDownKeyPress是都要发生的,而且两个人看上去没有什么区别。但是其实两者还是有实质的区别的。

  例如:在一个多行文本框里面输入字符,为什么我们没有定义一个键盘响应事件,但是键盘却响应了,把字符输入到了文本框呢?其实我觉得因为这个事件就是系统默认的一个消息响应,它就KeyPress。如果你自己还给KeyPress定义了自己的响应的话,那么程序会先执行你定义的程序,然后完成系统要求的显示字符事件的响应过程,但是如果你在自己定义KeyPress事件如:private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)里面增加语句:e.Handled=true;那么系统要求的显示字符响应过程就不会被执行,原因就是这个语句的意思就是这个消息响应已经完成。但是如果你在KeyDown,KeyUp里面加这条语句,显示字符串等消息还是会发生,这说明系统的显示字符串和KeyDown,KeyUp是没有关系的,而对于回车和退格消息响应则是由KeyDown控制,增加那条语句则回车换行不会执行,退格响应也不会执行。

  综上:要屏蔽键盘上的一个字符的输入,可以在KeyPress里面进行增加语句,而要屏蔽回车和退格则可以在KeyDown里面进行增加语句。

原创粉丝点击