1、键盘(键盘基础,按键消息)在 Microsoft Windows 98 中,键盘和鼠标是两个标准的使用者输入来源,在一些连贯操作中常产生互补作用。当然,鼠标在今天的应用程序中比十年前使用得更为广泛。甚至在一些应用程序中,我们更习惯于使用鼠标,例如在游戏、画图程序、音乐程序以及Web 浏览器等程序中就是这样。然而,我们可以不使用鼠标,但绝对不能从一般的 PC 中把键盘拆掉。相对于个人计算机的其它组件,键盘有非常久远的历史,它起源于 1874 年的第一台 Remington 打字机。早期的计算机程序员用键盘在 Hollerith 卡片上打孔,后来在终端机上用键盘直接与大型主机沟通。PC 上的键盘在
2、某些方面进行了扩充,加上了功能键、光标移动键和单独的数字键盘,但它们的输入原理基本相同。键盘基础您大概已经猜到 Windows 程序是如何获得键盘输入的:键盘输入以消息的形式传递给程序的窗口消息处理程序。实际上,第一次学习消息时,键盘事件就是一个消息如何将不同型态信息传递给应用程序的显例。Windows 用八种不同的消息来传递不同的键盘事件。这好像太多了,但是(就像我们所看到的一样)程序可以忽略其中至少一半的消息而不会有任何问题。并且,在大多数情况下,这些消息中包含的键盘信息会多于程序所需要的。处理键盘的部分工作就是识别出哪些消息是重要的,哪些是不重要的。忽略键盘虽然键盘是 Windows 程
3、序中使用者输入的主要来源,但是程序不必对它接收的所有消息都作出响应。Windows 本身也能处理许多键盘功能。例如,您可以忽略那些属于系统功能的按键,它们通常用到 Alt 键。程序不必监视这些按键,因为Windows 会将按键的作用通知程序(当然,如果程序想这么做,它也能监视这些按键) 。虽然呼叫程序菜单的按键将通过窗口的窗口消息处理程序,但通常内定的处理方式是将按键传递给 DefWindowProc。最终,窗口消息处理程序将获得一个消息,表示一个菜单项被选择了。通常,这是所有窗口消息处理程序需要知道的(在第十章将介绍菜单) 。有些 Windows 程序使用键盘快捷键 来启动通用菜单项。快捷键
4、通常是功能键或字母同 Ctrl 键的组合(例如,Ctrl-S 用于保存文件) 。这些键盘快捷键与程序菜单一起在程序的资源描述文件中定义(我们可以在第十章看到) 。Windows 将这些键盘快捷键转换为菜单命令消息,您不必自己去进行转换。对话框也有键盘接口,但是当对话框处于活动状态时,应用程序通常不必监视键盘。键盘接口由 Windows处理,Windows 把关于按键作用的消息发送给程序。对话框可以包含用于输入文字的编辑控件。它们一般是小方框,使用者可以在框中键入字符串。Windows处理所有编辑控件逻辑,并在输入完毕后,将编辑控件的最终内容传送给程序。关于对话框的详细信息,请参见第十一章。编辑
5、控件不必局限于单独一行,而且也不限于只在对话框中。一个在程序主窗口内的多行编辑控件就能够作为一个简单的文字编辑器了(参见第九、十、十一和十三章的 POPPAD 程序) 。Windows 甚至有一个Rich Text 文字编辑控件,允许您编辑和显示格式化的文字(请参见/Platform SDK/User Interface Services/Controls/Rich Edit Controls) 。您将会发现,在开发 Windows 程序时,可以使用处理键盘和鼠标输入的子窗口控件来将较高层的信息传递回父窗口。只要这样的控件用得够多,您就不会因处理键盘消息而烦恼了。谁获得了焦点与所有的个人计算机
6、硬件一样,键盘必须由在Windows 下执行的所有应用程序共享。有些应用程序可能有多个窗口,键盘必须由该应用程序内的所有窗口共享。回想一下,程序用来从消息队列中检索消息的 MSG结构包括 hwnd 字段。此字段指出接收消息的窗口控件码。消息循环中的 DispatchMessage 函数向窗口消息处理程序发送该消息,此窗口消息处理程序与需要消息的窗口相联系。在按下键盘上的键时,只有一个窗口消息处理程序接收键盘消息,并且此消息包括接收消息的窗口控件码。接收特定键盘事件的窗口具有输入焦点。输入焦点的概念与活动窗口的概念很相近。有输入焦点的窗口是活动窗口或活动窗口的衍生窗口(活动窗口的子窗口,或者活动
7、窗口子窗口的子窗口等等) 。通常很容易辨别活动窗口。它通常是顶层窗口也就是说,它的父窗口句柄是 NULL。如果活动窗口有标题列,Windows 将突出显示标题列。如果活动窗口具有对话框架(对话框中很常见的格式)而不是标题列,Windows 将突出显示框架。如果活动窗口目前是最小化的,Windows 将在工作列中突出显示该项,其显示就像一个按下的按钮。如果活动窗口有子窗口,那么有输入焦点的窗口既可以是活动窗口也可以是其子窗口。最常见的子窗口有类似以下控件:出现在对话框中的下压按钮、单选钮、复选框、滚动条、编辑方块和清单方块。子窗口不能自己成为活动窗口。只有当它是活动窗口的衍生窗口时,子窗口才能有
8、输入焦点。子窗口控件一般通过显示一个闪烁的插入符号或虚线来表示它具有输入焦点。有时输入焦点不在任何窗口中。这种情况发生在所有程序都是最小化的时候。这时,Windows 将继续向活动窗口发送键盘消息,但是这些消息与发送给非最小化的活动窗口的键盘消息有不同的形式。窗口消息处理程序通过拦截 WM_SETFOCUS 和WM_KILLFOCUS 消息来判定它的窗口何时拥有输入焦点。WM_SETFOCUS 指示窗口正在得到输入焦点,WM_KILLFOCUS 表示窗口正在失去输入焦点。我将在本章的后面详细说明这些消息。队列和同步当使用者按下并释放键盘上的键时,Windows 和键盘驱动程序将硬件扫描码转换为
9、格式消息。然而,这些消息并不保存在消息队列中。实际上, Windows在所谓的系统消息队列中保存这些消息。系统消息队列是独立的消息队列,它由 Windows 维护,用于初步保存使用者从键盘和鼠标输入的信息。只有当Windows 应用程序处理完前一个使用者输入消息时,Windows 才会从系统消息队列中取出下一个消息,并将其放入应用程序的消息队列中。此过程分为两步:首先在系统消息队列中保存消息,然后将它们放入应用程序的消息队列,其原因是需要同步。就像我们刚才所学的,假定接收键盘输入的窗口就是有输入焦点的窗口。使用者的输入速度可能比应用程序处理按键的速度快,并且特定的按键可能会使焦点从一个窗口切换
10、到另一个窗口,后来的按键就输入到了另一个窗口。但如果后来的按键已经记下了目标窗口的地址,并放入了应用程序消息队列,那么后来的按键就不能输入到另一个窗口。按键和字符应用程序从 Windows 接收的关于键盘事件的消息可以分为按键和字符两类,这与您看待键盘的两种方式一致。首先,您可以将键盘看作是键的集合。键盘只有唯一的 A 键,按下该键是一次按键,释放该键也是一次按键。但是键盘也是能产生可显示字符或控制字符的输入设备。根据 Ctrl、 Shift 和 Caps Lock 键的状态,A 键能产生几个字符。通常情况下,此字符为小写a。如果按下 Shift 键或者打开了 Caps Lock,则该字符就变
11、成大写 A。如果按下了 Ctrl,则该字符为 Ctrl-A(它在 ASCII 中有意义,但在 Windows 中可能是某事件的键盘快捷键) 。在一些键盘上,A 按键之前可能有死字符键(dead-character key)或者Shift、Ctrl 或者 Alt 的不同组合,这些组合可以产生带有音调标记的小写或者大写,例如,、狻、或拧?/p对产生可显示字符的按键组合,Windows 不仅给程序发送按键消息,而且还发送字符消息。有些键不产生字符,这些键包括 shift 键、功能键、光标移动键和特殊字符键如 Insert 和 Delete。对于这些键,Windows 只产生按键消息。按键消息当您按下
12、一个键时,Windows 把 WM_KEYDOWN或者 WM_SYSKEYDOWN 消息放入有输入焦点的窗口的消息队列;当您释放一个键时,Windows 把WM_KEYUP 或者 WM_SYSKEYUP 消息放入消息队列中。表 6-1键按下键释放非系统键WM_KEYDOWNWM_KEYUP系统键WM_SYSKEYDOWNWM_SYSKEYUP通常down(按下) 和up(放开) 消息是成对出现的。不过,如果您按住一个键使得自动重复功能生效,那么当该键最后被释放时, Windows 会给窗口消息处理程序发送一系列 WM_KEYDOWN(或者WM_SYSKEYDOWN)消息和一个WM_KEYUP(或者 WM_SYSKEYUP)消息。像所有放入队列的消息一样,按键消息也有时间信息。通过呼叫 GetMessageTime,您可以获得按下或者释放键的相对时间。