您的位置 首页 > 电脑资讯

键盘驱动程序源码_键盘驱动原理

1.为什么键盘拆开再装上就不能打字了?开机时上面的灯还会闪

2.扩展名大解释

3.如何配置虚拟主机如何配置虚拟主机网络

4.《单片机C语言程序设计实训100例——基于8051+Proteus仿真》 第03篇源代码

5.控制面板的“添加或删除程序”列表里很奇怪

6.XP系统键盘windows键被屏蔽了怎么恢复

7.vc/mfc 进程消息队列,线程消息队列,和系统消息队列,该如何处理

键盘驱动程序源码_键盘驱动原理

1、Linux 基础

安装Linux操作系统 Linux文件系统 Linux常用命令 Linux启动过程详解 熟悉Linux服务能够独立安装Linux操作系统

能够熟练使用Linux系统的基本命令 认识Linux系统的常用服务安装Linux操作系统 Linux基本命令实践 设置Linux环境变量 定制Linux的服务

Shell 编程基础使用vi编辑文件 使用Emacs编辑文件 使用其他编辑器

2、Shell 编程基础

Shell简介 认识后台程序Bash编程熟悉Linux系统下的编辑环境 熟悉Linux下的各种Shell 熟练进行shell编程熟悉vi基本操作

熟悉Emacs的基本操作 比较不同shell的区别 编写一个测试服务器是否连通的shell脚本程序 编写一个查看进程是否存在的shell脚本程序

编写一个带有循环语句的shell脚本程序

3、Linux 下的C 编程基础

linux C语言环境概述 G使用方法 Gdb调试技术 Autoconf Automake Makefile 代码优化

熟悉Linux系统下的开发环境 熟悉G编译器 熟悉Makefile规则编写Hello,World程序 使用 make命令编译程序 编写带有一个循环的程序

调试一个有问题的程序

4、嵌入式系统开发基础

嵌入式系统概述交叉编译 配置TFTP服务 配置NFS服务 下载Bootloader和内核

嵌入式Linux应用软件开发流程熟悉嵌入式系统概念以及开发流程 建立嵌入式系统开发环境制作cross_g工具链 编译并下载U-boot

编译并下载Linux内核 编译并下载Linux应用程序

5、嵌入式系统移植

Linux内核代码 平台相关代码分析 ARM平台介绍 平台移植的关键技术 移植Linux内核到 ARM平台 了解移植的概念

能够移植Linux内核移植Linux2.6内核到 ARM9开发板

6、嵌入式 Linux 下串口通信

串行I/O的基本概念 嵌入式Linux应用软件开发流程 Linux系统的文件和设备 与文件相关的系统调用 配置超级终端和MiniCOM

能够熟悉进行串口通信 熟悉文件I/O 编写串口通信程序 编写多串口通信程序

7、嵌入式系统中多进程程序设计

Linux系统进程概述 嵌入式系统的进程特点 进程操作 守护进程 相关的系统调用了解Linux系统中进程的概念 能够编写多进程程序编写多进程程序

编写一个守护进程程序 sleep系统调用任务管理、同步与通信 Linux任务概述任务调度 管道 信号 共享内存 任务管理 API 了解Linux系统任务管理机制

熟悉进程间通信的几种方式 熟悉嵌入式Linux中的任务间同步与通信编写一个简单的管道程序实现文件传输 编写一个使用共享内存的程序

8、嵌入式系统中多线程程序设计

线程的基础知识 多线程编程方法 线程应用中的同步问题了解线程的概念 能够编写简单的多线程程序编写一个多线程程序

9、嵌入式 Linux 网络编程

网络基础知识 嵌入式Linux中TCP/IP网络结构 socket 编程 常用 API函数 分析Ping命令的实现 基本UDP套接口编程 许可证管理

PPP协议 GPRS 了解嵌入式Linux网络体系结构 能够进行嵌入式Linux环境下的socket 编程 熟悉UDP协议、PPP协议 熟悉GPRS

使用socket 编写代理服务器 使用socket 编写路由器 编写许可证服务器 指出TCP和UDP的优缺点 编写一个web服务器 编写一个运行在

ARM平台的网络播放器

10、GUI 程序开发

GUI基础 嵌入式系统GUI类型 编译QT 进行QT开发熟悉嵌入式系统常用的GUI 能够进行QT编程使用QT编写“Hello,World”程序

调试一个加入信号/槽的实例 通过重载QWidget 类方法处理

11、Linux 字符设备驱动程序

设备驱动程序基础知识 Linux系统的模块 字符设备驱动分析 fs_operation结构 加载驱动程序了解设备驱动程序的概念

了解Linux字符设备驱动程序结构 能够编写字符设备驱动程序编写Skull驱动 编写键盘驱动 编写I/O驱动 分析一个看门狗驱动程序

对比Linux2.6内核与2.4内核中字符设备驱动的不同Linux 块设备驱动程序块设备驱动程序工作原理 典型的块设备驱动程序分析

块设备的读写请求队列了解Linux块设备驱动程序结构 能够编写简单的块设备驱动程序比较字符设备与块设备的异同 编写MMC卡驱动程序 分析一个文件系统

对比Linux2.6内核与2.4内核中块设备驱动的不同

12、文件系统

虚拟文件系统 文件系统的建立 ramfs内存文件系统 proc文件系统 devfs 文件系统 MTD技术简介 MTD块设备初始化

MTD块设备的读写操作了解Linux系统的文件系统 了解嵌入式Linux的文件系统 了解MTD技术 能够编写简单的文件系统为 ARM9开发板添加 MTD支持

移植JFFS2文件系统 通过proc文件系统修改操作系统参数 分析romfs 文件系统源代码 创建一个cramfs 文件系统

无论选择哪一方向,基本的linux的知识是需要具备的,其他还需要掌握的知识有ARM(最常用的一款嵌入式处理器)和C语言编程,每一方面知识的掌握熟练程度都最终决定了个人进行嵌入式linux开发的综合能力。

为什么键盘拆开再装上就不能打字了?开机时上面的灯还会闪

嵌入式开发主要有两种,像STM32、飞思卡尔等系列5261单片机属于无操作系统的,直接对寄存器或者利用库函数操作的,这种学习来难度相对小一些,就业前景也不错。

还有一些像ARM9,或者CortexA8、A9系列的可以运行Linux或者安卓操作系统的嵌入式软件系统开发,由于需要学习的内容较多,学习时间较长,那么学习起来就有一定的难度,工资也相对高一些。

课程内容主要包括:

①C,Ja核心编程:c语言核心编程,Ja核心编程;

②Linux核心操作与算法:Linux系统使用,Linux-c编程核心技术,精品数据结构,Linux-c编程精髓;

③核心操作与算法:Linux系统编程,Linux网络编程核心技术,UI编程,Ja核心编程,安卓核心技术;

④ARM+Linux底层开发:数字电路,ARM编程核心,Linux系统开发,嵌入式Linux驱动开发;

⑤大型项目实践:每期安排各类型真实的项目,详细可以找我要资料。

互联网行业目前还是最热门的行业之一,学习IT技能之后足够优秀是有机会进入腾讯、阿里、网易等互联网大厂高薪就业的,发展前景非常好,普通人也可以学习。

想要系统学习,你可以考察对比一下开设有相关专业的热门学校,好的学校拥有根据当下企业需求自主研发课程的能力,能够在校期间取得大专或本科学历,中博软件学院、南京课工场、南京北大青鸟等开设相关专业的学校都是不错的,建议实地考察对比一下。

祝你学有所成,望纳。

扩展名大解释

械式键盘

机械式键盘它一般类似金属接触式开关的原理使触点导通或断开。在实际应用中机械开头的结构形式很多,最常用的是交叉接触式。它的优点是结实耐用, 缺点是不防水。敲击比较费力,打字速度快时容易漏字。不过现在比较好的机械键盘都增加了Click功能, click功能实际上就是从机械结构上进行了改进,加大了缓存,防止快速打字时漏掉字符。它的使用寿命5000万到一亿次左右,普通用户10年大约键盘敲击20万次左右。所以一款好的机械键盘够用一辈子了。

塑料薄膜式键盘

塑料薄膜式键盘内有四层,塑料薄膜一层有凸起的导电橡胶,当中一层为隔离层,上下两层有触点。通过按键使橡胶凸起按下,使其上下两层触点接触,输出编码。这种键盘无机械磨损,可靠性较高,目前在市场占相当大的比重,不过很多JS也将这种成本相对较低的键盘当成电容式键盘。它最大的特点就是低价格, 低噪音,低成本。

导电橡胶式键盘

导电橡胶式键盘触点的接触是通过导电的橡胶接通。其结构是有一层带有凸起的导电橡胶,凸起部分导电,而这部分对准每个按键,互相连接的平面部分不导电,当键帽按下去时,由于凸起部分导电,把下面的触点按通,不按时,凸起部分会弹起。目前使用的也较多。

电容式键盘

电容式键盘它是一种类似电容式开关的原理,通过按键改变电极间的距离而产生电容量的变化,暂时形成震荡脉冲允许通过的条件。我们知道,电容的容量是由介质,两极的距离及两极的面积来决定的。所以当键帽按下时,两极的距离发生变化,这就引起电容容量发生改变,当参数设计合适时,按键时就有输出,而不按键就无输出,这个输出再经过整形放大,去驱动编码器。由于电容器无接触,所以这种键在工作过程中不存在磨损、接触不良等问题,耐久性、灵敏度和稳定性都比较好。为了避免电极间进入灰尘,电容式按键开关用了密封组装。1000万到3000万次寿命。但目前市场上真正的电容式键盘并不多,大部分是前面两种键盘,一款真正的电容键盘价格是比较高的。

无线键盘

当然最先进的就是无线键盘,顾名思义这种键盘与电脑间没有直接的物理连线,通过红外线或无线电波将输入信息传送给特制的接收器。接收器的连接与普通键盘基本相同,也只需简单地连接到PS/2或COM口、USB口等上,购买时必须注意区别,一般无线的键盘在标识后有"RF"后缀(radio frequency),表示支持无线电波传输。现在大部分产品频点都在900 MHz,455 MHz, 330MHz。左右。

无线键盘需要使用干电池供电,对于红外线型的无线键盘具有较严格的方向性,尤其是水平位置的关系更为敏感,由于接收器接收角度有限(中心直线范围内6公尺)在键盘距离接收器太近时,会出现失灵的情况,同时灵敏度低时不能快速敲键,否则肯定会漏字符。而用无线电的键盘要灵活得多,考虑到无线电是辐射状传播的,为了避免在近距离内有同类型(同频率)的键盘工作,导致互相干扰,一般都备有4个以上的频道,如遇干扰可以手动转频。无线键盘为了配合移动的需要,一般体积较小巧并集成有鼠标的功能,注意接收器和主机连接有两个接口,一个是PS2、一个是COM口,把这两个接口一一对应都接在主机上就可以了,但如果你不想使用键盘上的鼠标,那就只需把接收器的PS2口接在主机上就可以了,COM不接!接收器不需要外接电源,而键盘里内置的3号碱性电池可以正常使用3个月。

键盘的发展趋势

就键盘的发展来看,键盘的键位是逐渐的增多(但不是无限制的增加毕竟键盘的面积是有限的),而且是向着多功能多媒体的方向发展。从早期推出的电脑用83键键盘,随后又推出了84键的设计标准,该标准将键盘分为三个区,即功能区、打字键区、负责光标控制和编辑的副键盘区。其中功能键区的光标键与数字键作为双功能符号键使用,使用一个"Numlock"键来控制这两种功能的切换。虽然两种规格的键盘现在已经不多见了,但是键盘主要区域的划分仍然沿用当时的标准,至今没有什么变化。直到1986年IBM公司推出了101键键盘,才在功能上实现了进一步的扩充,除了添加了F11、F12两个功能键之外,还在键盘的中部多加了一组专用的光标控制和编辑的键,在微软推出WIN95操作系统之后,出现Windows启动键,时至今日大量带各种附加功能键的键盘出现在我们的面前。例如Fn键、快捷键、带鼠标和手写板的键盘等等。

常用的键盘的接口有AT接口、PS/2接口和USB接口,现在绝大部分主板都是提供PS/2键盘接口,也称为"小口"。而兼容机尤其是较老的主板常常提供AT接口也被称为"大口",所幸的是市场上有一种大小口键盘转换连接器,售价只有区区几元钱,它一举解决了两种接口键盘的兼容性问题。一些公司还推出了USB接口的键盘。根据最新公布的 PC2001规范,以后所有通过ISA 总线工作的接口都会随着ISA总线的消亡而被USB取代。USB 允许同时将其他一些设备接入,相当于集成了一个HUB,比如可以将鼠标接入,这实际上节约了主板的COM或PS/2口。有的键盘甚至本身就集成了PS/2 转USB的电路,这样就更方便了。目前阻碍其普及的原因还是价格太高。集成USB HUB的键盘,这类键盘大多用USB接口,由于外设使用USB的机会增加,为了使用更多的USB设备,需要添加一种USB HUB的装置扩展USB接口数量,但是专业的USB HUB价格比较昂贵,所以人们尝试将USB HUB集成到键盘或显示器中并得到成功。集成USB HUB的键盘往往自身占用一个USB接口,用以保持键盘信号与主机的传输,同时提供2到4个USB接口供其他设备连结,简单地说是一进多出,价格上要比专业的USB HUB便宜得多。

在单片机系统中,经常使用的键盘都是专用键盘。这类键盘都是单独设计制作的,成本高,连线多,且可靠性不高。这些问题在那些要求键盘按键较多的应用系统中显得更加突出。与此相比,在PC系统中广泛使用的PS/2键盘具有价格低、通用可靠,且使用的连线少(仅使用2根信号线)的特点,并可满足多数系统的要求。因此,在单片机系统中应用PS/2键盘是一种很好的选择。

本文在分析PS/2协议和PS/2键盘工作原理与特点的基础上,给出在AT89C51单片机上实现对PS/2键盘支持的硬件连接方法以及驱动程序的设计实现。

1PS/2协议

现在PC机广泛用的PS/2接口为miniDIN 6引脚的连接器。其引脚如图1所示。

1—数据线(DATA);2—未用;3—电源地(GND);

4—电源(+5 V);5—时钟(CLK);6—未用。

图1PS/2连接器PS/2设备有主从之分,主设备用female插座,从设备用male插座。现在广泛使用的PS/2键盘鼠标均工作在从设备方式下。PS/2接口的时钟与数据线都是集电极开路结构的,必须外接上拉电阻。一般上拉电阻设置在主设备中。主从设备之间数据通信用双向同步串行方式传输,时钟信号由从设备产生。

(1) 从设备到主设备的通信

当从设备向主设备发送数据时,首先会检查时钟线,以确认时钟线是否是高电平。如果是高电平,从设备就可以开始传输数据;否则,从设备要等待获得总线的控制权,才能开始传输数据。传输的每一帧由11位组成,发送时序及每一位的含义如图2所示。

图2从设备到主设备的通信每一帧数据中开始位总是为0,数据校验用奇校验方式,停止位始终为1。从设备到主设备通信时,从设备总是在时钟线为高时改变数据线状态,主设备在时钟下降沿读入数据线状态。

(2) 主设备到从设备的通信

主设备与从设备进行通信时,主设备首先会把时钟线和数据线设置为“请求发送”状态。具体方式为:首先下拉时钟线至少100 μs来抑制通信,然后下拉数据线“请求发送”,最后释放时钟线。在此过程中,从设备在不超过10 μs的间隔内就要检查这个状态。当设备检测到这个状态时,将开始产生时钟信号。

此时数据传输的每一帧由12位构成,其时序和每一位含义如图3所示。

图3主设备到从设备的通信与从设备到主设备通信相比,其每帧数据多了一个ACK位。这是从设备应答接收到的字节的应答位,由从设备通过拉低数据线产生,应答位ACK总是为0。主设备到从设备通信过程中,主设备总是在时钟为低电平时改变数据线的状态,从设备在时钟的上升沿读入数据线状态。

2PS/2键盘的编码与命令集

(1) PS/2键盘的编码

现在PC机使用的PS/2键盘都默认用第二套扫描码集。该扫描码集可参考文献\[1\]。扫描码有两种不同的类型:通码(make code)和断码(break code)。当一个键被按下或持续按住时,键盘会将该键的通码发送给主机;而当一个键被释放时,键盘会将该键的断码发送给主机。

根据键盘按键扫描码的不同,在此可将按键分为如下几类:

第一类按键,通码为1字节,断码为0xF0+通码形式。如A键,其通码为0x1C,断码为0xF0 0x1C。

第二类按键,通码为2字节0xE0+0xXX形式,断码为0xE0+0xF0+0xXX形式。如right ctrl键,其通码为0xE0 0x14,断码为0xE0 0xF0 0x14。

第三类特殊按键有两个,print screen键通码为0xE0 0x12 0xE0 0x7C,断码为0xE0 0xF0 0x7C 0xE0 0xF0 0x12; pause键通码为0x E1 0x14 0x77 0xE1 0xF0 0x14 0xF0 0x77,断码为空。

组合按键的扫描码发送按照按键发生的次序,如以下面顺序按左SHIFT+A键:1按下左SHIFT键,2按下A键,3释放A键,4释放左SHIFT键,那么计算机上接收到的一串数据为0x12 0x1C 0xF0 0x1C 0xF0 0x12。

在驱动程序设计中,就是根据这样的分类来对不同的按键进行不同处理的。

(2) PS/2键盘的命令集

主机可以通过向PS/2键盘发送命令来对键盘进行设置或者获得键盘的状态等操作。每发送一个字节,主机都会从键盘获得一个应答0xFA(“重发 resend”和“回应echo”命令例外)。下面简要介绍驱动程序在键盘初始化过程中所用的指令(详细键盘命令集见参考文献\[1\]):

0xED主机在本命令后跟随发送一个参数字节,用于指示键盘上num lock, caps lock, scroll lock led的状态;

0xF3主机在这条命令后跟随发送一个字节参数来定义键盘机打的速率和延时;

0xF4用于在当主机发送0xF5禁止键盘后,重新使能键盘。

3PS/2键盘与单片机的连接电路

PS/2键盘与AT89C51单片机的连接方式如图4所示。P1.0接PS/2数据线,P3.2(INT0)接PS/2时钟线。因为单片机的P1、P3口内部是带上拉电阻的,所以PS/2的时钟线和数据线可以直接与单片机的P1、P3相连接。

4驱动程序设计

驱动程序使用Keil C51语言,Keil uVision2编程环境。PS/2 104键盘驱动程序的主要任务,是实现单片机与键盘间PS/2通信,以及将接收到的按键扫描码转换为该按键的键值KeyVal,提供给系统上层软件使用。

(1) 单片机与键盘间PS/2通信的程序设计

在PS/2通信过程中,主设备(单片机)是在时钟信号为低时发送和接收数据信号的。因为单片机到键盘发送的是指令,需要键盘回应,所以这部分程序用查询方式;而单片机接收键盘数据时,数据线上的信号在时钟为低时已经稳定,所以这部分程序用中断方式,且不需要在程序中加入延时程序。单片机的键盘发送接口程序见本刊网站.dpj.cn。

(2) 键盘扫描码转换程序设计

由于键盘扫描码无规律可循,因此由键盘扫描码获得相应按键的键值(字符键为其ASCII值,控制键如F1、CTRL等为自定义值),只能通过查表的方式。由于按键的三种类型及部分按键对应着两个键值(如A键的键值根据CAPS和SHIFT键状态有0x41(A)和0x61(a)两种),因此综合考虑查表转换速度和消耗,设计中使用4个键盘表:键盘扫描码转换基本集和切换集kb_plain_map\[NR_KEYS\]与 kb_shift_map\[NR_KEYS\];包含E0前缀的键盘扫描码转换基本集和切换集kbe0_plain_map\[NR_KEYS\]与 kbe0_shift_map\[NR_KEYS\]。PS/2 104键盘按键扫描码最大值为0x83,所以设置NR_KEYS为132。所有四个键盘表的定义均为如下形式:KB_MAP\[MAKE CODE\]=KEYVAL,如果扫描码对应的按键为空,如KB_MAP\[0x00\],则定义相应键值为NULL_KEY(0x00)。以下是键盘扫描码基本集的部分代码实例:kb_plain_map\[NR_KEYS\]={……

NULL_KEY;0x2C;0x6B;0x69;0x6F;0x30;0x39;NULL_KEY;// 扫描码0x40~0x47

file://对应按键空,逗号,K,I,O,0,9,空

file://对应键值 0x00,’,’,’k’,’i’,’o’,’0’,’9’,0x00

……};图4硬件连接电路如此设计键盘转换表的另一个好处在于,以后如需扩展支持有ACPI、Windows多媒体按键键盘时,只需要将键表中相应处修改即可。如ACPI power按键通码为0xE0 0x37,修改kbe0_plain_map\[0x37\]=KB_ACPI_PWR即可。

特殊按键PAUSE使用单独程序处理,如果接收到0xE1就转入这段程序;而print screen键则将其看作是两个通码分别为0xE0 0x12和0xE0 0x7C的“虚键”的组合键来处理。

在驱动程序中声明如下全局变量:led_status其bit0-scroll lock led关0、开1;bit1-num lock led关为0,开为1;bit2-caps lock led关为0,开为1;bit3~bit7总是0;agcs_status记录左右shift ctrl gui alt状态,bit0-左shift键,bit1-左ctrl键,bit2-左gui键,bit3-左alt键,bit4-右shift键,bit5-右 ctrl键,bit6-右gui键,bit7-右alt键,相应键按下则对应位为1,释放为0。E0_FL接到0xE0置1;E1_FL接收到 0xE1置1;F0_FL接收到0xF0置1。按键键值通过KeyVal提供给上层使用。

PS/2键盘扫描码键值转换程序ps2_codetrans()流程如图5所示。

图5扫描码键值转换程序流程第一类按键的扫描码键值转换程序代码:if (F0_FL) {//接收扫描码为断码

switch (mcu_revchar){//处理控制键

case 0x11: agcs_status&=0xF7;break;//左alt释放

case 0x12: agcs_status&=0xFE;break;//左shift释放

case 0x14: agcs_status&=0xFD;break;//左ctrl释放

case 0x58: if(led_status&0x04)

led_status&=0x03;//caps lock键

else led_status =0x04;

ps2_ledchange();

break;

case 0x59: agcs_status&=0xEF;break;//右shift释放

case 0x77: if(led_status&0x02)

led_status&=0x05;//num lock键

else led_status =0x02;

ps2_ledchange();

break;

case 0x7E: if(led_status&0x01)

led_status&=0x06;//scroll lock键

else led_status =0x01;

ps2_ledchange();

break;

default:break;

}

F0_FL = 0;

}

else {//接收扫描码为通码

if (led_status & 0x04) caps_flag = 1; else caps_flag = 0;

if (led_status & 0x02) num_flag = 1; else num_flag = 0;

if (scga_status & 0x11) shift_flag = 1; else shift_flag = 0;

file://扫描码键值转换

if ((caps_flag == shift_flag) (!num_flag)) KeyVal=kb_plain_map\[mcu_revchar\];

else KeyVal=kb_shift_map\[mcu_revchar\];

switch(mcu_revchar){//处理控制键或状态键

case 0x11: agcs_status = 0x08;//左alt按下

case 0x12: agcs_status = 0x01;//左shift按下

case 0x14: agcs_status = 0x02;//左ctrl按下

case 0x59: agcs_status = 0x10;//右shift按下

default: break;

}

}第二类按键的扫描码键值转换程序与上相似。要注意的是在退出该程序段时对E0_FL和F0_FL标志的清0。

PAUSE键的处理程序:如果接收到0xE1,置E1_FL=1,然后顺次将后续接收到的7个字节数据和PAUSE的通码后7个字节比较,一致则返回KeyVal=KB_PAUSE。在比较完所有7个字节后清除E1_FL标志。

键盘初始化程序kb_init()流程:

① 上电后,接收键盘上电自检通过信号0xAA,或者自检出错信号0xFC。单片机接收为0xAA,进入下一步,否则,进行出错处理。

② 关LED指示,单片机发送0xED,然后接收键盘回应0xFA,接着发送送0x00接收0xFA。

③ 设置机打延时和速率。 单片机发送0xF3,接收0xFA,发送0x00(250ms,2.0cps),接收0xFA。

④ 检查LED,发送0xED,接收0xFA,发送0x07(开所有LED),接收0xFA。发送0xED,接收0xFA,发送0x00(关LED),接收0xFA。

⑤ 允许键盘发送0xF4,接收0xFA。

键盘LED改变ps2_ledchange()函数流程:发送0xED→接收0xFA→发送led_status→接收0xFA。

结语

该驱动程序经Keil uVision2编译,在AT89C51单片机上运行通过,实现了对PS/2 104键盘的支持,以及对字符按键大小写切换,num lock切换,控制键及组合按键的支持。该程序对其他嵌入式或单片机系统中PS/2键盘的应用也有借鉴意义。

参考文献

1Adam Chapweske. The ATPS/2 Keyboard Interface. ://panda.cs.ndsu.nodak.edu/%7Eachapwes/PICmicro/keyboard/atkeyboard.html

2Adam Chapweske. PS/2 Mouse/Keyboard Protocol. ://govschl.ndsu.nodak.edu/~achapwes/PICmicro/PS2/ps2.htm

3Network Technologies Incorporated. PS/2 Keyboard & Mouse Protocols. ://.networktechinc/ps2prots.html

4 Linux 2.4.10内核程序 defkeymap.c dn_keyb.c kbd.c keybdev.c keyboard.c kbd_kern.h kd.h keyboard.h

PS/2帧的第一位是起始位,为0,然后是8位数据位,发送键盘扫描码的一个字节(扫描码为1-4个字节),然后是奇偶校验位,最后是停止位,为1。这些是在数据线(即1号引脚线)上发送的。无键按下时,数据线和始终线都保持为1。当有键按下时,时钟线CLOCK送出脉冲,同时数据线送出数据。主机(此处是89c51 MCU)在始终脉冲的下降沿对数据线样获得数据。键盘扫描码包括通码和断码,当键按下时发送通码,抬起时发送断码。更详细的内容可参考所附的《PS/2 技术参考》。

根据上述原理,我们可以将键盘的脉冲线接至89c51的外部中断输入口(INT0或INT1),当键按下和抬起时有脉冲产生,此脉冲引发MCU 中断。将键盘的DATA线连至89c51的输入口(如P1.0)。在中断处理程序中,从输入口读入数据,然后通过循环移位对读进的数据位进行处理,1(起始位)、10(奇偶校验)、11(停止位)可抛弃,如不嫌麻烦也可将奇偶校验位加以应用。当一个数据帧收完后,将处理后剩下的2-9位(即扫描码)通过串口发至PC机,通过PC机的串口监视软件(如“串口调试助手”)来查看。硬件连线和源码如下:

源码:

ORG 0000H

AJMP MAIN;转入主程序

ORG 0003H ;外部中断P3.2脚INT0入口地址

AJMP INT ;转入外部中断服务子程序

;以下为主程序进行CPU中断方式设置

MAIN:MOV SCON,#50H;设置成串口1方式

MOV TMOD,#20H;波特率发生器T1工作在模式2上

MOV PCON,#80H;波特率翻倍为2400x2=4800BPS

MOV TH1,#0F3H;预置初值(按照波特率2400BPS预置初值)

MOV TL1,#0F3H;预置初值(按照波特率2400BPS预置初值)

SETB EA ;打开CPU总中断请求

SETB IT0 ;设定INT0的触发方式为脉冲负边沿触发

SETB EX0 ;打开INT0中断请求

SJMP $

INT: CLR EA ;暂时关闭CPU的所有中断请求

CJNE R0,#0,L1

L3: INC R0

SJMP L5

L1: CJNE R0,#9,L2

SJMP L3

L2: CJNE R0,#10,L4

SETB TR1;启动定时器T1

MOV SBUF,A

MOV R0,#0

L5: SETB EA ;允许中断

RETI ;退出子程序

L4: MOV C,P1.0

RRC A

SJMP L3

END

搞定后,当按下和释放键时,会在PC机上显示其扫描码。

通电时键盘会自检,此时键盘上三个灯全亮,自检完成后熄灭,并向主机发送十六进制字符AA.。

如何配置虚拟主机如何配置虚拟主机网络

所有的扩展名,是不可能统计全的,有些软件还有自己独立的扩展名.

下面给你列出些扩展名:

A 对象代码库文件 AAM Authorware shocked文件 AAS Authorware shocked包 ABF Adobe二进制屏幕字体 ABK CorelDRAW自动备份文件 ABS 该类文件有时用于指示一个摘要(就像在一篇有关科学方面的文章的一个摘要或概要,取自abstract) ACE Ace压缩档案格式 ACL CorelDRAW 6键盘快捷键文件 ACM Windows系统目录文件 ACP Microsoft office助手预览文件 ACR 美国放射医学大学文件格式 ACT Microsoft office助手文件 ACV OS/2的驱动程序,用于压缩或解压缩音频数据 AD After Dark屏幕保护程序 ADA Ada源文件(非-GNAT) ADB Ada源文件主体(GNAT);HP100LX组织者的约定数据库 ADD OS/2用于引导过程的适配器驱动程序 ADF Amiga磁盘文件 ADI AutoCAD设备无关二进制绘图仪格式 ADM After Dark多模块屏幕保护;Windows NT策略模板 ADP FaxWork用于传真调制解调器的交互安装文件;Astound Dynamite文件 ADR After Dark随机屏幕保护;Smart Address的地址簿 ADS Ada源文件说明书(GNAT) AFM Adobe的字体尺度 AF2,AF3 ABC的FlowChat文件 AI Adobe Illustrator格式图形 AIF,AIFF 音频互交换文件,Silicon Graphic and Macintosh应用程序的声音格式 AIFC 压缩AIF AIM AOL即时信息传送 AIS ACDSee图形序列文件;Velvet Studio设备文件 AKW RoboHELP的帮助工程中所有A-关键词 ALAW 欧洲电话音频格式 ALB JASC Image Commander相册 ALL 艺术与书信库 AMS Velvet Studio音乐模块(MOD)文件;Extreme的Tracker模块文件 ANC Canon Computer的调色板文件,包含一系列可选的颜色板 ANI Windows系统中的动画光标 ANS ANSI文本文件 ANT SimAnt For Windows中保存的游戏文件 API Adobe Acrobat使用的应用程序设计接口文件 APR Lotus Approach 文件 APS Microsoft Visual C++文件 ARC LH ARC的压缩档案文件 ARI Aristotle声音文件 ARJ Robert Jung ARJ压缩包文件 ART Xara Studio绘画文件;Canon Crayola美术文件;Clip Art文件格式;另一种光线跟踪格式;AOL使用的用Johnson—Grace压缩算法压缩的标记文件 ASA Microsoft Visual InterDev文件 ASC ASCⅡ文本文件;PGP算法加密文件 ASD Microsoft Word的自动保存文件;Microsoft高级流媒体格式(microsoft advanced streaming format,A)的描述文件;可用NSREX打开 Velvet Studio例子文件 ASE Velvet Studio样文件 A Microsoft高级流媒体格式文件 ASM 汇编语言源文件,Pro/E装配文件 ASO Astound Dynamite对象文件 ASP 动态网页文件;ProComm Plus安装与连接脚本文件;Astound介绍文件 AST Astound多媒体文件;ClarisWorks“助手”文件 ASV DataCAD自动保存文件 ASX Cheyenne备份脚本文件;Microsoft高级流媒体重定向器文件,文件 ATT AT< Group 4位图文件 ATW 来自个人软件的Any Time Deluxe For Windows个人信息管理员文件 AU Sun/NeXT/DEC/UNIX声音文件;音频U-Law(读作“mu-law”)文件格式 AVB Computer Associates Inoculan反软件的感染后文件 AVI Microsoft Audio Video Interlee**格式 AVR Audio Visual Researc件格式 AVS 应用程序可视化格式 AWD FaxVien文档 AWR Telsis数字储存音频文件扩展名格式 Axx ARJ压缩文件的分包序号文件,用于将一个大文件压至几个小的压缩包中(xx取01-99的数字) A3L Authorware 3.x库文件 A4L Authorware 4.x库文件 A5L Authorware 5.x库文件 A3M,A4M Authorware Macintosh未打包文件 A4P Authorware无运行时间的打包文件 A3W,A4W,A5W 未打包的Authorware Windows文件 BAK 备份文件 BAS BASIC源文件 BAT 批处理文件 BDF West Point Bridger Designer文件 BFC Windows 95 Briefcase文档 BG Backgammon For Windows下的游戏文件 BGL Microsoft Flight Simulator(微软飞行模拟器)的视景文件 BI 二进制文件 BIF Group Wise的初始化文件 BIFF XLIFE 3D格式文件 BIN 二进制文件 BK,BK$ 有时用于代表备份版本 BKS IBM BookManager Read书架文件 BMK 书签文件 BMP Windows或OS/2位图文件 BMI Apogee BioMenace数据文件 BOOK Adobe FrameMaker Book文件 BOX Lotus Notes的邮箱文件 BPL Borlard Delph 4打包库 BQY BrioQuery文件 BRX 用于查看多媒体对象目录的文件 BSC MS Developer Studio浏览器信息文件 BSP Quake图形文件 BS1 Apogee Blake Stone数据文件 BS_ Microsoft Bookshelf Find菜单外壳扩展名 BTM Norton 应用程序使用的批处理文件 BUD Quicken的备份磁盘 BUN CakeWalk 声音捆绑文件(一种MIDI程序) BW SGI黑白图像文件 BWV 商业波形文件 BYU BYU的**文件格式 B4 Helix Nuts and Bolts文件 C C代码文件 C0l 台风波形文件 CAB Microsoft压缩档案文件 CAD Softdek的Drafix CAD文件 CAL CALS压缩位图;日历表数据 CAM Casio照相机格式 CAP 压缩音乐文件格式 CAS 逗号分开的ASCⅡ文件 CAT Quicken使用 的IntellCharge分类文件 CB Microsoft干净引导文件 CBI 二进制卷格式文件(用于IBM大型机系统) CC Visual dBASE用户自定义类文件 CCA cc:邮件文件 CCB Visual Basic动态按钮配置文件 CCF 多媒体查看器配置文件,用于OS/2 CCH Corel图表文件 CCM Lotus cc:邮箱(例如“INBOX.CCM”) CCO CyberChat数据文件 CCT Macromedia Director Shockwe投影 CDA CD音频轨道 CDF Microsoft频道定义格式文件 CDI Philip的高密盘交互格式 CDM Visual dBASE自定义数据模块文件 CDR CorelDRAW绘图文件;原始音频CD数据文件 CDT CorelDRAW模板 CDX CorelDRAW压缩绘图文件;Microsoft Visual FoxPro索引文件 CEL CIMFast语言文件 CER 证书文件(MIME x-x509-ca-cert) CFB Compton的多媒文件 CFG 配置文件 CFM CotdFusion模板文件;Visual dBASE Windows用户定制表单 CGI 公共网关接口脚本文件 CGM 计算机图形元文件 CH OS/2配置文件 CHK 由Windows磁盘碎片整理器或磁盘扫描保存的文件碎片 CHM 编译过的HTML文件 CHR 字符集(字体文件) CHP Ventura Publisher章节文件 CHT ChartViem文件;Harvard Graphics矢量文件 CIF Adaptec CD 创建器 CD映像文件 CIL Clip Gallery下载包 CIM SimCity 2000文件 CIN OS/2改变控制文件用于跟踪INI文件中的变化 CK1 iD/Apogee Commander Keen 1数据文件 CK2 iD/Apogee Commander Keen 2数据文件 CK3 iD/Apogee Commander Keen 3数据文件 CK4 iD /Apogee Commander Keen 4数据文件 CK5 iD /Apogee Commander Keen 5数据文件 CK6 iD /Apogee Commander Keen 6数据文件 CLASS Ja类文件 CLL Crick Software Clicker文件 CLP Windows 剪贴板文件 CLS Visual Basic类文件 CMD Windows NT,OS/2的命令文件;DOS CD/M命令文件;dBASEⅡ程序文件 CMF Corel元文件 CMG Chessmaster保存的游戏文件 CMP JPEG位图文件;地址文档 CMV Corel Move动画文件 CMX Corel Presentation Exchange图像 CNF Telnet,Windows和其他其内格式会发生改变的应用程序使用的配置文件 CNM Windows应用程序菜单选项和安装文件 CNQ Compuworks Design Shop文件 CNT Windows(或其他)系统用于帮助索引或其他目的内容文件 COB TrueSpace 2对象文件 COD Microsoft C编译器产生的可显示机器码/汇编代码文件,其中附有源C代码作为注释 COM 命令文件(程序) CPD Corel Print Office文件(图形) CPD,CPE 传真覆盖文档 CPI Microsoft MS-DOS代码页信息文件 CPL 控制面板扩展名,Corel颜色板 CPO Corel打印存储文件 CPP C++代码文件 CPR Corel提供说明书文件 CPT Corel 照片-绘画图像 CPX Corel Presentation Exchange压缩图形文件 CRD Windows Cardfile文件 CRP Corel 提供的运行时介绍文件;Visual dBASE自定义报表文件 CRT 认证文件 CSC Corel脚本文件 CSP PC Emcee On_Screen图像 CSS 瀑布式表格文件 CST Macromedia Director Cast文件 CSV 逗号分隔的值文件 CT Scitex CT位图文件;Paint Shop Pro Grapic编辑器文件 CTL 通常用于表示一个包含控件信息的文件;FaxWork用它来保持有关每个传真收到或发出的信息 CUE Microsoft提示牌数据文件 CUR Windows光标文件 CUT Dr Halo位图文件 CV Corel版本的档案文件;Microsoft CodeView信息屏幕文件 CWK ClarisWorks数据文件. CWS ClarisWorks模块 CXT Macromedia Director受保护的(不可编辑的)投影文件 CXX C++源代码文件 DAT 数据文件;WrodPerfect合并数据文件;用于一些MPEG格式的文件 DB Borland的Paradox 7表 DBC Microsoft Visual FoxPro数据库容器文件 DBF dBASE文件,一种由Ashton-Tate创建的格式,可以被ACT!、Lipper、FoxPro、Arago、Wordtech、Xbase和类似数据库或与数据库有关产品识别;可用数据文件(能被Excel 打开);Oracle 8.1.x表格空间文件 DBX DataBearn图像;Microsoft Visual FoxPro表格文件 DCM DCM模块格式文件 DCR 冲击波文件 DCS 桌面颜色分隔文件 DCT Microsoft Visual FoxPro数据库容器 DCU Delphi编译单元文件 DCX Microsoft Visual FoxPro数据库容器;基于PCX的传真图像;宏 DC5 DataCAD绘图文件 DDF Btrieve或Xtrieve数据定义文件,它包含用于描述Btrieve或Xtrieve文件的元数据 DDIF Digital Equipment或 Compaq格式,用于保存他们图像与字处理文档 DEF SmartWareⅡ数据文件;C++模块定义文件 DEFI Oracle 7 卸载脚本文件 DEM 用于表示数字高度模型的USGS基准的文件 DER 认证文件 DEWF Macintosh Sound Cap/Sound Edit录音设备格式 DGN Macintosh 95 CAD绘图文件 DIB 设备无关位图 DIC 目录 DIF 可进行数据互换的电子表格 DIG DigiLink格式;Sound DesignerⅠ音频文件 DIR MacromediaDirector文件 DIZ 描述文件 DLG C++对话框脚本文件 DLL 动态链接库 DLS 可下载声音文件 DMD Visual dBASE数据模块文件 DMF X-Trakker音乐模块(MOD)文件 DOC FrameMaker或FrameBuilder文档;Word Star文档、Word Perfect文档、Microsoft Word文档;DisplayWrite文档 DOT Microsoft Word文档模板 DPL Borland Delph3压缩库 DPR Borland Delphi工程头文件 DRAW Acorn的基于对象的矢量图像文件 DRV 驱动程序 DRW Micrografx Designer/Draw;Pro/E绘画文件 D Micrografx Designer VFX文件 DSG DOOM保存的文件 DSM Dynamic Studio音乐模块(MOD)文件 DSP Microsoft Developer Studio工程文件 DSQ Corel QUERY(查询)文件 DST 刺绣机图形文件 DSW Microsoft Developer Studio工作区文件 DTA Word Bank(世界银行)的STARS数据文件 DTD SGML文档类型定义(DTD)文件 DTED 地面高度数字数据(图形的数据格式)文件 DTF Symantec Q&A相关的数据库数据文件 DTM DigiTrakker模块文件 DUN Microsoft拔号网络导出文件 DV 数字文件(MIME) DWD DiamondWare数字化文件 DWG AutoCAD工程图文件;AutoCAD或Generic CADD老版本的绘图格式 DXF 可进行互交换的绘图文件格式,二进制的DWG格式的文本表示;数据交换文件 DXR Macromedia Director受保护(不可编辑)**文件 D64 Commodore的64位模拟磁盘图像文件 EDA Ensoniq ASR磁盘映像 EDD 元素定义文档(FrameMaker+SGML文档) EDE Ensoniq EPS磁盘映像 EDK Ensoniq KT磁盘映像 EDQ Ensoniq SQ1/SQ2/Ks32磁盘映像 EDS Ensoniq SQ80磁盘映像 EDV Ensoniq VFX-SD磁盘映像 EFA Ensoniq ASR文件 EFE Ensoniq EPS文件 EFK Ensoniq KT文件 EFQ Ensoniq SQ1/SQ2/Ks32文件 EFS Ensoniq SQ80文件 EFV Ensoniq VFX-SD文件 EMD ABT扩展模块 EMF Windows增强元文件 EML Microsoft Outlook Express邮件消息(MIME RTC822)文件 ENC 重演文件 ENFF 中性文件格式扩展名 EPHTML Perl解释增强HTML文件 EPS 压缩的PostScript图像 EP 压缩的PostScript文件 ERI ERWin文件 ERR 当RobooHELP帮助编译器企图编译一个帮助系统源文件时用来存储错误消息的文件 EPX ERWin文件 ESPS ESPS音频文件 EUI Ensoniq ESP家族的压缩磁盘映像 EVY 特使文档 EWL Microsoft Encarta文档 EXC Microsoft Word禁止字字典 EXE 可执行文件(程序) F FORTRAN文件 F2R Farandoyle线性模块格式 F3R Farandoyle分块线性模块格式 F77 FORTRAN文件 F90 FORTRAN文件 FAR Fradole Composer音乐模块(MOD)文件 FAV Microsoft Outlook导航条 FAX 传真类型图像 FBK Nison 金融备份 FCD 虚拟CD-ROM FDB Nison 金融数据库 FDF Adobe Acrobat表单文档文件 FEM CADRE有限元素网络文件 FFA,FFL,FFO,FFK Microsoft快速查找文件 FFF GUS PnP银行文件格式 FFT 最终格式文本(IBM的DCA一部分) FH3 Aldus Freehand 3绘图文件 FIF Fractal图像文件 FIG REND386/AVRIL使用的文件格式 FITS CCD照相机图像;灵活图像传输系统 FLA Macromedia Flash** FLC Autodesk FLIC动画文件 FLF Corel Paradox产生的格式:Nison Financials许可文件;OS/2驱动程序文件 PLI Autodesk FLIC动画 FLT StarTrekker音乐模块(MOD)文件;MultiGen Inc的Open Flight使用的文件格式;Corel过滤器文件 FM Adobe FrameMaker文档 FMB Oracle4.0版或以后版本表单的二进制源代码文件 FML 文件镜象列表(GetRight) FMT Oracle 4.0版或以后版本表单的文本格式;Microsoft Schedule+ 打印文件 FMX Oracle 4.0版或以后版本可执行表单 FND Microsoft Explorer保存的搜索文件(Find let) FNG 字体组文件(字体导航器,Font Nigator) FNK Funk Tracker模块格式 FOG Fontographer模块字体 FON 系统字体 FOR FORTRAN文件 FOT 字体相关文件 FP FileMaker Pro文件 FP1 Flying Pigs for Windows数据文件 FP3 FileMaker Pro文件 FPT FileMaker Pro文件;Microsoft Fox Pro备注字体文件 FPX FlashPix位图 FRM 表单;Frame Maker或Frame Builder文档;Oracle可执行表(3.0版或早期版本);Visual Basic表单;WordPerfect Merge表单;DataCAD标志报表文件 FRT Microsoft FoxPro报表文件 FRX Visual Basic表单文本;Microsoft FoxPro报表文件 F fPrint Audit Tool文件格式 FSL Borland的Paradox 7表单;Corel Paradox保存的表单 FSM Parandoyle示例格式 FT Lotus Notes全文本索引 FTG 全文本搜索组文件,由Windows帮助系统查找时产生——可以删除,并在需要时重建起来 FTS 全文本搜索引文件,由Windows帮助系统查找时产生 FW2 Framework Ⅱ文件 FW3 Framework Ⅲ文件 FW4 Framework Ⅳ文件 FXP 经Microsoft FoxPro编译的源文件 FZB Casio FZ-1银行转储 FZF Casio FZ-1完全转储 FZV Casio FZ-1声音转储G721 Raw CCITT G.721 $bit ADPCM格式数据 G723 Raw CCITT G.723 3或5bit ADPCM格式数据 GAL Corel多媒体管理器相集 GCD Generic CADD绘画文件(后续版本) GCP Ground Control Point(地面控制点)文件,用于远景数据形成图像过程,经常用于生成图工程—CHIPS(copenhagen image processing system)使用这些文件 GDB InterBase数据库文件 GDM 铃声、口哨声和声音板模块格式 GED GEDCOM 系谱数据文件,用于记录和交换系谱数据的流行格式;图形环境文档绘画 GEM GEM元文件 GEN Ventura产生的文本文件 GetRight GetRight未完成的下载文件 GFC Patton&Patton FlowCharting 4 flowchart文件 GFI,GFX Genigraphics图形链接表示文件 GHO Norton 克隆磁盘映像 GID Windows 95全局索引文件(包括帮助状态) GIF CompuServe位图文件 GIM,GIX Genigraphics图形链接介绍文件 GKH Ensoniq EPS家簇磁盘映像文件 GKS Gris Grip Key文档 GL 动画格式 GNA Genigraphics图形链接介绍文件 GNT 生成代码,Micro Focus属性格式里的可执行代码 GNX Genigraphics图形链接介绍文件 GRA Microsoft Grap件 GRD 用于远程视景数据产生地图过程的格式文件,通常应用于形成地图工程—CHIPS(copenhagen image processing system)使用这些文件 GRF Grapher(Golden Software公司)图形文件 GRP 程序管理组 GSM Raw GSM 6.10音频流;Raw“byte aligned(比特对齐的)” GSM 6.10音频流;US Robotics语音调制解调器 GTK Graoumftracker(老)音乐模块(MOD)文件 GT2 Graoumftracker(新)音乐模块(MOD)文件 GWX,GWZ Cenigraphis图形链接介绍文件 GZ UNIX gzip压缩文件 H C程序头文件 HCM IBM HCM配置文件 HCOM 声音工具HCOM格式 HCR IBM HCD/HCM产品配置文件 HDF 高级计算机应用程序本地中心(NCSA) geospatial Hierarchial数据格式文件 HED HighEdit文档 HEL Microsoft Hellbender格式保存的游戏文件 HEX Macintosh BinHex2.0文件 HGL HP图形语言绘图文件 HH 映射文件,包括一些话题ID和在帮助文件系统中话题的映射数字—允许运行中应用程序发送给用户合适的上下文帮助话题 HLP 帮助文件;Date CAD Windows帮助文件 HOG Lucas Arts的Dark Forces WAD文件 HPJ Visual Basic帮助工程 HPP C++程序头文件 HQX Macintosh BinHex 4.0文件 HST 历史文件 HT HyperTerminal(超级终端) HTM,HTML 超文本文档 HTT Microsoft超文本模板 HTX 扩展HTML模板 HXM Descent2 HAM文件扩展 ICA Citrix文件 ICB Targa位图文件 ICC Kodak打印机格式文件 ICL 图标库文件 ICM 图形颜色匹配配置文件 ICO Windows图标 IDB MSDev中间层文件 IDD MIDI设备定义 IDF MIDI设备定义(Windows 95需要的文件) IDQ Internet数据查询文件 IDX Microsoft FoxPro相关数据库索引文件;Symantec Q&A相关数据库索引文件;Microsoft Outlook Express文件 IFF 交换格式文件;Amiga ILBM IGES 初始图形交换说明文件 IGF 插入系统元文件 IIF QuickBooks for Windows交换文件 ILBM 位图图形文件 IMA WinImage磁盘映像文件 IMG GEM映像 IMZ WinImage压缩磁盘映像文件 INC 汇编语言或动态服务器包含文件 INF 信息文件 INI 初始化文件;MWe DSP Synth的“nwsynth.ini” GMS安装;Cris Ultrasound bank安装 INP Oracle 3.0版或早期版本的表单源代码 INRS INRS远程通信声频 INS InstallShield安装脚本;X-Internet签字文件;Ensoniq EPS字簇设备;Cell/ⅡMAC/PC抽样设备 INT 中间代码,当一个源程序经过语法检查后编译产生一个可执行代码 IOF Findit文档 IQY Microsoft Internet查询文件 ISO 根据ISD 9660有关CD-ROM文件系统标准列出CD-ROM上的文件 ISP X-Internet签字文件 IST 数字跟踪设备文件 ISU InstallShield卸装脚本 IT 脉冲跟踪系统音乐模块(MOD)文件 ITI 脉冲跟踪系统设备 ITS 脉冲跟踪系统抽样,Internet文档位置 IV Open Inventor中使用的文件格式 IVD 超过20/20微观数据维数或变量等级文件 IVP 超过20/20的用户子集配置文件 IVT 超过20/20表或集合数据文件 IVX 超过20/20微数据目录文件 IW Idlewild屏幕保护程序 IWC Install Watc档 J62 Ricoh照相机格式 JAR Ja档案文件(一种用于let和相关文件的压缩文件) JAVA Ja源文件 JBF Paint Shop Pro图像浏览文件 JFF,JFIF,JIF JPEG文件 JMP SAS的JMPDiscovery表格统计文件 JN1 Epic MegaGames的Jill of the Jungle数据文件 JPE,JPEG,JPG JPEG图形文件 JS jascript源文件 JSP HTML网页,其中包含有对一个Ja servlet的参考 JTF JPEG位图文件 K25 Kurzweil 2500抽样文件 KAR 卡拉OK MIDI文件(文本+MIDI) KDC Kodak光增强器 KEY DataCAD图标工具条文件 KFX KoFak Group 4图像文件 KIZ Kodak数字明信片文件 KKW RoboHELP帮助工程索引设计器中与主题无关的K开头的所有关键字 KMP Korg Trinity KeyMap文件 KQP Konica照相机本地文件 KR1 Kurzweil 2000抽样(多软驱)文件 KRZ Kurzweil 2000抽样文件 K Korg Trinity抽样文件 KYE Kye游戏数据 LAB Visual dBASE标签文件 LBM Deluxe Paint位图文件 LBT,LBX Microsoft FoxPro标签文件 LDB Microsoft Access加锁文件 LDL Corel Paradox分发库 LEG Legacy文档 LES Logitech系统游戏配置文件(与REC文件一样) LFT 3D Studio(DOS)放样文件 LGO Paintbrush(Microsoft画图应用程序)的徽标文件 LHA LZH更换文件后缀 LIB 库文件 LIN DataCAD线型文件 LIS 结构化查询报告(SQR)程序产生的输出文件 LLX Laplink交换代理 LNK Windows快捷方式文件 LOG 日志文件 LPD Helix Nut和Bolt文件 LRC Intel可视电话文件 LSL Corel Paradox保存的库文件 LSP AutoLISP、CommonLISP和其他LISP语言文件 LST 列表文件 LU ThoughtWing库单元文件 LVL Parallax Software的 Miner Descent/D2 Level扩展 LWLO Lightwe分层对象文件 LWOB Lightwe对象文件 LWP Lotus WordPro 96/文件 LWSC Lightwe视景文件 LYR DataCAD层文件 LZH LH ARC压缩档案 LZS Skyroads数据文件M1V MPEG相关文件(MIME“mpeg”类型) M3D Corel Motion 3D动画文件 M3U MPEG URL(MIME声音文件) MAC MacPaint图像文件 MAD Microsoft Access模块文件 MAF Microsoft Access表单文件 M 在一些日本文件中发现的图形文件格式 MIC 魔力邮件监视器配置文件 MAK Visual Basil或Microsoft Visual C++工程文件 MAM Microsoft Access宏 MAN UNIX手册页输出 MAP 映射文件;Duke Nukem 3D WAD游戏文件 MAQ Microsoft Access查询文件 MAR Microsoft Access报表文件 MAS Lotus Freelance Graphics Smart Master文件 MAT Microsoft Access表;3D Studio MAX材料库 MAUD MAUD抽样格式 MAX Kinetx的3DStudio MAX文件;该格式用于一个3D场景文件;Paperport文件;OrCAD设计文件 MAZ Hover迷路数据;Division的dVS/dVISE使用的文件格式 MB1 Apogee Monster Bash数据文件 MBOX Berkeley Unix邮箱格式 MBX Microsoft Outlook保存email格式;Eudora邮箱 MCC Dailerl0呼叫卡 MCP Metrowerks CodeWarrior工程文件 MCR DataCAD键盘宏文件 MCW Microsoft Word的Macintos档 MDA Microsoft Access内抽入器;Microsoft Access 2.0版及其后续版本的工作组 MDB Microsoft Access数据库 MDE Microsoft Access MDE文件 MDL 数字跟踪器音乐模块(MOD)文件;Quake模 块文件 MDN Microsoft Access空数据库模板 MDW Microsoft Access工作组文件 MDZ Microsoft Access向导模板文件 MED 音乐编辑器,OctaMED音乐模块(MOD)文件 MER 电子表格/数据库数据交换格式;FileMaker、Excel及其他软件能识别 MET 表示管理器元文件 MFG Pro/ENGINEER制造文件 MGF 在材料与几何学里的文件格式 MHTM,MHTML MHTML文档(MIME) MI 杂项 MIC Microsoft Image Composer文件 MID MIDI音乐 MIF Adobe FramMaker交换格式 MIFF 与机器无关格式文件 MIM,MIME,MME Internet邮件扩展格式的多用途文件,经常作为发送e-mail时在AOL里附件而创建的文件;在一个多区MIM文件里的文件能用WinZip或其他类似程序打开 MLI 3D Studio的材料库格式文件 MMF Meal Master格式;一个处方类格式;Microsoft邮件文件 MMG 超过20/20表或集会数据文件 MMM Microsoft多媒体** MMP Mindmapor Mind Manager文件 MN2 Descent2任务文件 MND,MNI Mandelbort for Windows MNG 多映像网络图形 MNT,MNX Microsoft FoxPro菜单文件 MNU Visual dBASE菜单文件;Intertel Systems Interact菜单文件 MOD Fast Tracker、Star Trekker、Noise Tracker(等等)音乐模块文件;Microsoft多电子表格;Amiga/PC磁道文件 MOV QuickTime for Windows** MP2 第二层MPEG音频文件 MP3 第三层MPEG音频文件 MPA MPEG相关文件,MIME“mpeg类型” MPE,MPEG,MPG MPEG动画文件 MPP Microsoft工程文件;CAD绘图文件格式 MPR Microsoft FoxPro菜单(已编译) MRI MRI扫描文件 MSA 魔术阴影档案 MSDL Manchester的场景描述语言 MSG Microsoft邮件消息 MSI Windows 安装器包 MSN Microsoft网络文档;Descent Mission文件 MSP Microsoft Paint(画图)位图文件;Windows Installer路径文件 MST Windows 安装器传输文件 MTM Multi 跟踪器音乐模块(MOD)文件 MUL Ultima在线 MUS 音乐 MUS10 Mus10声音 MVB Microsoft多媒体查看器文件 MWP Lotus WordPro Smart Master文件 NAN Nanoscope文件(Raw Grayscale) NAP NAP元文件 NCB Microsoft Developer Studio文件 NCD Norton改变目录 NCF NetWare命令文件;Lotus Notes内部剪切板 NDO 3D 低多边形建模器,Nendo netCDF 网络公用数据表单 NFF 中性文件格式 NFT NetObject Fusion模板文件 NIL Norton光标库文件(EasyIcons-兼容) NIST NIST Sphere声音 NLB Oracle 7数据 NLM NetWare可装载模块 NLS 用于本地化的国家语言支持文件(例如,Uniscape) NLU Norton Live Update e-mail 触发器文件 NOD NetObject Fusion文件 N Lotus Notes数据库 NSO NetObject Fusion文档文件 NST Noise Tracker音乐模块(MOD)文件 NS2 Lotus Notes数据库(第二版) NTF Lotus Notes数据库模板 NTX CA-Clipper索引文件 NWC Noteworthy Composer歌曲文件 NWS Microsoft Outlook Express新闻消息(MIME RFC822)O01 台风声音文件 OBD Microsoft Office活页夹 OBJ 对象文件 OBZ Microsoft Office活页夹向导 OCX Microsoft对象链接与嵌入定制控件 ODS Microsoft Out

《单片机C语言程序设计实训100例——基于8051+Proteus仿真》 第03篇源代码

如何配置虚拟主机

要完全配置虚拟主机,您可以按照下列步骤操作:

通过开始-设置-控制面板,可以在控制面板上完成设置。比如你想绑定一个域名到一个虚拟主机,你只要点击控制面板上的addon域,输入你想绑定的域名。

虚拟服务器

众所周知,网站的统计化可以让搜索引擎更好的收录,对网站也是非常有利的。那么如何才能做到伪静态呢?

虚拟主机的伪静态状态也可以通过虚拟主机上方的控制面板进行设置。首先,我们需要知道如果访问链接以。php格式,说明这个网站没有设置伪静态。然后,我们可以在控制面板上找到伪静态设置,打开伪静态设置弹出对话窗口,在对话窗口上选择Discuz,点击确定。不要以为这个时候伪静态已经成立了。还需要在Discuz的后台进行设置,通过浏览器访问一个网站,输入账号和密码登录网站后台。进入后台页面后,点击全局-SEO设置按钮,静态设置页面就会显示在上面。然后检查所有可用的小框,并单击提交按钮完成。当你可以再次访问网站的时候,只要页面链接的结尾是html,就会显示伪静态已经设置好了。

我想在服务器建立虚拟主机,该怎么做?

一、定义所谓虚拟主机是指在一台服务器里运行几个网站,提供WEB、FTP、Mail等服务。二、虚拟主机的实现方法有三种:基于IP的方法,基于主机名的方法和基于端口的法官法。①基于IP的方法:在服务器里绑定多个IP,然后配置WEB服务器,把多个网站绑定在不同的IP上。访问不同的IP,就看到不同的网站。②基于端口的方法:一个IP地址,通过不同的端口实在不同网站的访问。③基于主机名的方法:设置多个域名的A记录,使它们解析到同一个IP地址上,即同一个服务器上。然后,在服务器上配置WEB服务端,添加多个网站,为每个网站设定一个主机名。因为HTTP协议访问请求里包含有主机名信息,当WEB服务器收到访问请求时,就可以根据不同的主机名来访问不同的网站。

如何配置虚拟主机?

要想完整的配置一个虚拟主机可以按照以下步骤:

通过开始-设置-控制面板,在控制面板上面就可以完成设置。例如你要是想把域名和虚拟主机进行绑定的话,你只要点击控制面板上的域名绑定,再在输入你要绑定的域名就可以啦。

大家都知道网站的静态化是可以使搜索引擎更好的收录,对于网站也是非常有利的,那么要怎样才可以实现伪静态呢?

虚拟主机伪静状态也是可以通过虚拟主机上面的控制面板来设置的,首先我们要了解访问链接如果结尾是.php的格式的话,那就说明这个网站还没有设置伪静态。然后我们再在控制面板上面找到伪静态设置,打开伪静态设置弹出对话窗,选择对话窗上面的Discuz点击确认就可以啦。这个时候不要以为伪静态已经设置好。你还需要到Discuz后台去设置一下,通过浏览器来访问一个网站,输入账号和密码登入网站的后台。进入后台页面后点击全局-SEO设置按钮后,上面就会显示静态化设置页面,然后再把可用里面的小方框全部勾选上,点击提交按钮就完成了。你可以再去访问网站的时候,只要页面链接的结尾是html,这会说明伪静态已设置好了。

如何创建虚拟主机?

1、注册免费空间账号,成功登陆后,进入会员中心2、进入用户中心后,点击“点击一键初始化”按钮,初始化免费虚拟主机3、初始化成功后,会提示没有绑定域名,无需理会,直接关闭即可4、点击管理,进入虚拟主机面板5、设置ftp密码,这样就可以使用ftp上传到免费空间了6、进入数据库管理界面——点击初始化数据库——数据库管理,记住数据库名和密码,进行网站安装的时候需要用到。

数据库初始化后,会自动创建一个跟用户名一样的数据库,这个数据库可以直接用来安装数据库用。

7、创建数据库,大部分建站系统需要手动创建数据库的,可以通过这些操作创建:在数据库管理界面——高级管理——,然后点击“数据库”,输入数据库名,点击创建,数据库就创建成功了。

8、可以直接在免费空间的“虚拟主机控制面板中”安装空间附带的一些预装网站系统。不过,免费空间中预装的网站系统一般都不是最新版本的,且有些开源系统的升级不能跨版本,相对来说,升级起来就比较麻烦了。

如果一次次安装每个版本的升级补丁升级到最新版本的话,倒还不如直接用ftp上传最新的网站系统源码进行安装。

怎么在自己的电脑上搭建虚拟主机?

创建虚拟主机的方法有很多,推荐用vmware创建虚拟机。操作简单容易上手。现在用win7系统安装win7系统作为分享。

浏览器搜索vmware,解压运行安装程序点击下一步,进行安装

选中“我接受许可协议中的条款”复选框,然后单击“下一步”按钮,

然后选中“增强型键盘驱动程序”复选框后单击“下一步”按钮,

检查更细和客户体验,可以不勾选。

然后下一步,下一步直至完成。最后一步点击许可证,可以通过浏览器搜索对应版本的许可证。复制到许可证输入框即可。

接下来创建虚拟机。打开vmware

点击新建虚拟机,选择典型推荐,点击下一步

选择稍后安装操作系统

然后根据需要安装的系统做对应的选择。

然后点击下一步选择位置,建议不要选择默认的C盘,可以选择空间比较充足的磁盘。然后下一步下一步直至完成

选择创建的虚拟机,然后找到编辑设置虚拟机。

找到iso选项,点击浏览到本地的iso镜像。然后点击确定。

回到界面,点击开启虚拟机。

接下来就是系统安装。与普通的U盘和光盘装系统一样,一部一部的安装直至完成即可完成虚拟机安装。

磁盘可以先不分区直接选择整个磁盘安装。

等待安装完成。完成后自动重启进入系统。

完成最终安装,设置电脑用户名。然后下一步,下一步,跳过激活,下一步直至完成。

开机进入操作系统。

一个干净的虚拟机下的win7系统就完成了。

用同样的方法创建,win10,Linux,mac等都可以,只要有对应的iso文件,都可以创建。

控制面板的“添加或删除程序”列表里很奇怪

单片机c语言编程100个实例目录1

函数的使用和熟悉

实例3:用单片机控制第一个灯亮

实例4:用单片机控制一个灯闪烁:认识单片机的工作频率

实例5:将 P1口状态分别送入P0、P2、P3口:认识I/O口的引脚功能

实例6:使用P3口流水点亮8位LED

实例7:通过对P3口地址的操作流水点亮8位LED

实例8:用不同数据类型控制灯闪烁时间

实例9:用P0口、P1 口分别显示加法和减法运算结果

实例10:用P0、P1口显示乘法运算结果

实例11:用P1、P0口显示除法运算结果

实例12:用自增运算控制P0口8位LED流水花样

实例13:用P0口显示逻辑"与"运算结果

实例14:用P0口显示条件运算结果

实例15:用P0口显示按位"异或"运算结果

实例16:用P0显示左移运算结果

实例17:"万能逻辑电路"实验

实例18:用右移运算流水点亮P1口8位LED

实例19:用if语句控制P0口8位LED的流水方向

实例20:用swtich语句的控制P0口8位LED的点亮状态

实例21:用for语句控制蜂鸣器鸣笛次数

实例22:用while语句控制LED

实例23:用do-while语句控制P0口8位LED流水点亮

实例24:用字符型数组控制P0口8位LED流水点亮

实例25: 用P0口显示字符串常量

实例26:用P0 口显示指针运算结果

实例27:用指针数组控制P0口8位LED流水点亮

实例28:用数组的指针控制P0 口8 位LED流水点亮

实例29:用P0 、P1口显示整型函数返回值

实例30:用有参函数控制P0口8位LED流水速度

实例31:用数组作函数参数控制流水花样

实例32:用指针作函数参数控制P0口8位LED流水点亮

实例33:用函数型指针控制P1口灯花样

实例34:用指针数组作为函数的参数显示多个字符串

单片机c语言编程100个实例目录2

实例35:字符函数ctype.h应用举例

实例36:内部函数intrins.h应用举例

实例37:标准函数stdlib.h应用举例

实例38:字符串函数string.h应用举例

实例39:宏定义应用举例2

实例40:宏定义应用举例2

实例41:宏定义应用举例3

* 中断、定时器中断、定时器 *中断、定时器*中断、定时器 /

实例42:用定时器T0查询方式P2口8位控制LED闪烁

实例43:用定时器T1查询方式控制单片机发出1KHz音频

实例44:将计数器T0计数的结果送P1口8位LED显示

实例45:用定时器T0的中断控制1位LED闪烁

实例46:用定时器T0的中断实现长时间定时

实例47:用定时器T1中断控制两个LED以不同周期闪烁

实例48:用计数器T1的中断控制蜂鸣器发出1KHz音频

实例49:用定时器T0的中断实现"渴望"主题曲的播放

实例50-1:输出50个矩形脉冲

实例50-2:计数器T0统计外部脉冲数

实例51-2:定时器T0的模式2测量正脉冲宽度

实例52:用定时器T0控制输出高低宽度不同的矩形波

实例53:用外中断0的中断方式进行数据集

实例54-1:输出负脉宽为200微秒的方波

实例54-2:测量负脉冲宽度

实例55:方式0控制流水灯循环点亮

实例56-1:数据发送程序

实例56-2:数据接收程序

实例57-1:数据发送程序

实例57-2:数据接收程序

实例58:单片机向PC发送数据

实例59:单片机接收PC发出的数据

*数码管显示*数码管显示 数码管显示数码管显示*/

实例60:用LED数码显示数字5

实例61:用LED数码显示器循环显示数字0~9

实例62:用数码管慢速动态扫描显示数字"1234"

实例63:用LED数码显示器伪静态显示数字1234

实例64:用数码管显示动态检测结果

实例65:数码秒表设计

实例66:数码时钟设计

实例67:用LED数码管显示计数器T0的计数值

实例68:静态显示数字“59”

单片机c语言编程100个实例目录3

键盘控制*键盘控制* *键盘控制 *键盘控制 */

实例69:无软件消抖的独立式键盘输入实验

实例70:软件消抖的独立式键盘输入实验

实例71:CPU控制的独立式键盘扫描实验

实例72:定时器中断控制的独立式键盘扫描实验

实例73:独立式键盘控制的4级变速流水灯

实例74:独立式键盘的按键功能扩展:"以一当四"

实例75:独立式键盘调时的数码时钟实验

实例76:独立式键盘控制步进电机实验

实例77:矩阵式键盘按键值的数码管显示实验

//实例78:矩阵式键盘按键音

实例79:简易电子琴

实例80:矩阵式键盘实现的电子密码锁

液晶显示LCD*液晶显示LCD *液晶显示LCD * *液晶显示LCD*液晶显示LCD *液晶显示LCD */

实例81:用LCD显示字符'A'

实例82:用LCD循环右移显示"Welcome to China"

实例83:用LCD显示适时检测结果

实例84:液晶时钟设计

*一些芯片的使用*24c02 DS18B20 X5045 ADC0832 DAC0832 DS1302 红外遥控/

实例85:将数据"0x0f"写入AT24C02再读出送P1口显示

实例86:将按键次数写入AT24C02,再读出并用1602LCD显示

实例87:对I2C总线上挂接多个AT24C02的读写操作

实例88:基于AT24C02的多机通信 读取程序

实例89:基于AT24C02的多机通信 写入程序

实例90:DS18B20温度检测及其液晶显示

实例91:将数据"0xaa"写入X5045再读出送P1口显示

实例92:将流水灯控制码写入X5045并读出送P1口显示

实例93:对SPI总线上挂接多个X5045的读写操作

实例94:基于ADC0832的数字电压表

实例95:用DAC0832产生锯齿波电压

实例96:用P1口显示红外遥控器的按键值

实例:用红外遥控器控制继电器

实例98:基于DS1302的日历时钟

实例99:单片机数据发送程序

实例100:电机转速表设计

模拟霍尔脉冲

://.dzkfw.cn/myxin/51c_language.chm 单片机c语言一百例子

XP系统键盘windows键被屏蔽了怎么恢复

RmtCtrlCenter 是一种ASP磁盘管理工具。可以充当一个在线FTP软件的功能,如果服务器没有系统帐号的限制,可以访问服务器上面全部目录,下载,上传,复制,粘贴,功能方便易用

软件大小: 38 K

软件语言: 简体中文

软件类别: 程序源码 / 免费版 / ASP.Net

运行环境: ASP.Net

Microsoft User-Mode Driver Framework Feature Pack 1.0

Windows 用户模式驱动程序是将原本用于核心模式的驱动程序从核心态脱离出来,缓解了由于驱动程序崩溃造成的系统崩溃的现象。关于用户模式下驱动程序,最典型的可能要属打印机驱动了,根据微软的相关文档,打印机驱动在Windows里面,需要运行在用户态下,而在以往,打印机驱动是运行在核心态下的。

当然他也用于WMP后台及联网搜索

Legend Standard Keyboard

联想天骄键盘驱动

看着删吧,觉得哪个没用就删掉

vc/mfc 进程消息队列,线程消息队列,和系统消息队列,该如何处理

对于用过Windows的人,几乎没有人不知道Ctrl+Alt+Del组合键,尤其是在使用经常死机的Windows9x时,使用它的频率更高,这一组合键是专门为了系统安全起见提供的紧急出口。VC知识库在线杂志第11期,ac952_z_cn在他的个人专栏中写过一篇关于这方面的文章:?WINDOWS NT/2000下如何屏蔽CTRL+ALT+DEL?。因此本文侧重于介绍在Windows XP中如何实现屏蔽CTRL+ALT+DEL组合键,也就是任务管理器,任务切换组合键(Alt+Tab),任务栏和?开始?菜单(Ctrl+Esc,VK_LWIN,VK_RWIN)。这个方法也能应用于Windows 2000环境。在Windows 9x/Me系统中,屏蔽Ctrl+Alt+Del和各种任务开关键的方法是通过下面的方法实现的:BOOL bOldState;SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &bOldState, 0);MS大佬认为这种方法很业余,所以在Windows NT/2000/XP中对此进行了修改。在这些较新的Windows版本中用户登陆使用Winlogon和GINA?Graphical Identification and Authentication,意思是图形化的身份认证,挺吓唬人的是不是!其实就那么回事。Winlogon是Windows系统的一部分,它专门提供交互式登陆支持,而GINA则是Winlogon用来实现认证的一个DLL?这个DLL就是msgina.dll。WlxInitialize、WlxActivateUserShell便是其中输出,当然不知这两个,还有别的。前者进行自身的初始化,后者激活用户的外壳程序。Windows就是用这个DLL来实现用户名+口令的身份认证的,但是开发人员可以用自己的GINA代替msgina.dll。例如,实现智能卡、视网膜扫描仪、DNA检查等等认证机制来代替输入用户名+口令形式的身份检查。 下面的表格中列出了与GINA有关的全部函数。其中有一个是WlxLoggedOnSAS,当按下Ctrl+Alt+Del 键时,Winlogon便调用这个函数。(表一)GINA 函数一览表 函数 描述WlxActivateUserShell激活用户外壳程序WlxDisplayLockedNotice允许GINA DLL 显示锁定信息WlxDisplaySASNotice 当没有用户登陆时,Winlogon调用此函数WlxDisplayStatusMessageWinlogon 用一个状态信息调用此函数进行显示WlxGetConsoleSwitchCredentials Winlogon调用此函数读取当前登陆用户的信任信息,并透明地将它们传到目标会话WlxGetStatusMessage Winlogon 调用此函数获取当前状态信息WlxInitialize 针对指定的窗口位置进行GINA DLL初始化WlxIsLockOk 验证工作站正常锁定WlxIslogoffOk 验证注销正常WlxLoggedOnSAS 用户已登陆并且工作站没有被加锁,如果此时接收到SAS,则Winlogon 调用此函数WlxLoggedOutSAS 没有用户登陆,如果此时收到SAS,则Winlogon 调用此函数WlxLogoff 请求注销操作时通知GINA DLLWlxNegotiate 表示当前的Winlogon版本是否能使用GINA DLLWlxNetworkProviderLoad 在加载网络服务提供程序收集了身份和认证信息后,Winlogon 调用此函数WlxRemoveStatusMessage Winlogon 调用此函数告诉GINA DLL 停止显示状态信息WlxScreenserNotify 允许GINA与屏幕保护操作交互WlxShutdown 在关闭之前Winlogon 调用此函数,允许GINA实现任何关闭任务,例如从读卡器中退出智能卡WlxStartApplication 当系统需要在用户的上下文中启动应用程序时调用此函数WlxWkstaLockedSAS当工作站被锁定,如果接收到一个SAS,则Winlogon 调用此函数在默认情况下,GINA显示登陆对话框,用户输入用户名及口令。所以要想屏蔽掉Ctrl+Alt+Del,则可以写一个新的MyGina.dll,其中提供接口调用msgina.dll的函数WlxLoggedOnSAS,从而实现Ctrl+Alt+Del屏蔽。或者编写一个键盘驱动程序来实现。难道屏蔽Ctrl+Alt+Del真的象上述所说的那么麻烦吗?有没有更好的方法呢?答案是肯定的。所以忘掉GINA吧,使用操作系统的策略设置完全可以搞掂这个问题。方法是进入"开始"菜单,选择"运行",然后在运行对话框中输入"gpedit.msc",启动Windows系统的组策略编辑器。在左边窗格查看"用户配置管理模板系统登录/注销",则在右边窗格策略里不难发现"禁用任务管理器"一项。组策略编辑器通过对这个策略的设置可以屏蔽掉Ctrl+Alt+Del。如果要通过编写代码来实现,则必须操作下面的注册表项:HKCUSoftwareMicrosoftWindowsCurrentVersionPoliciesSystemDisableTaskMgr = dword:1如此设置之后,则在Windows XP中,如果用户按下Ctrl+Alt+Del,则会弹出一个出错对话框,注意这里设在控制面板中?用户帐号?管理的?选择登录和注销选项?设置启用了?使用欢迎屏幕?一项。否则,XP将使用Windows的传统登录模式,要求用户输入帐户名。并且Ctrl+Alt+Del组合键的 行为也和传统的行为一样,注册表中DisableTaskMgr的设置也只是将登录/注销对话框中的任务管理器按钮屏蔽或置灰。 有人可能会问,有关任务管理器的文档又没有明确说明,那你是怎么知道DisableTaskMgr是用来禁用任务管理器的呢?告诉你吧, 我是在使用GPEDIT时发现的。GPEDIT是一个非常有用的工具,不仅可以用它来编辑策略,还可以用它来发现策略。利用这个工具可以轻松控制Windows的许多东西,从许可权限的存取到是否使用IE的传统外观,从是否显示对话框中的Places Bar到是否用Ctrl+Alt+Del 启动任务管理器。总之用它可以配置上百个界面行为,因此它是一个足以让系统管理员垂延三尺的工具。一旦找到了感兴趣的策略,那如何知道相应的注册表位置呢?有两种方法。第一种是比较粗鲁的办法:在修改策略的前后将注册表输出到一个.reg文件,然后比较它们有什么不同。所有的策略无外乎以下的四个注册表键:// 用户指定HKEY_CURRENT_USERSoftwarePoliciesHKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionPolicies// 机器指定HKEY_LOCAL_MACHINESoftwarePoliciesHKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionPolicies第二种方法是直捣信息源头--检查描述策略的管理模板文件(.adm)。下面是Windows XP的system.adm文件对 DisableTaskMgr的描述:(Windows 2000对此的描述稍有不同,其细节请参考Windows 2000的开发包)CATEGORY !!CADOptions#if version >= 4EXPLAIN !!CADOptions_Help#endifKEYNAME "SoftwareMicrosoftWindowsCurrentVersionPoliciesSystem"POLICY !!DisableTaskMgr#if version >= 4SUPPORTED !!SUPPORTED_Win2k#endifEXPLAIN !!DisableTaskMgr_HelpVALUENAME "DisableTaskMgr"END POLICY;; More Ctrl+Alt+Del policies here...;END CATEGORY ; Ctrl+Alt+Del optionsDisableTaskMgr_Help="防止用户启动''任务管理器''(Taskmgr.exe)。nn如果该设置被启用,并且用户试图启动任务管理器,系统会显示消息,解释是一个策略禁止了这个操作。nn任务管理器让用户启动或终止程序,监视计算机性能,查看及监视计算机上所有运行中的程序 (包含系统服务), 搜索程序的执行文件名,及更改程序运行的优先顺序。"DisableTaskMgr="删除任务管理器"以上是DisableTaskMgr的描述片断正是在这段描述中KEYNAME 和VALUENAME指定了注册表的键值对。利用这种方法,你可以为自己的应用程序创建管理模板和策略,但编辑和浏览.adm模板文件的编辑器必须支持Unicode字符。如Notepad或者WordPad等都可以。此外,使用管理模板文件,系统管理员可以用它为整个组织配置需要的策略?由此可以看出,此文件在系统中的地位举足轻重!有关模板管理文件格式的详细信息请参考平台SDK。最后需要强调的是DisableTaskMgr只是禁用Ctrl+Alt+Del的功能。下面我们来讨论如何捕获它的按键序列。要想截获Ctrl+Alt+Del,有三种可选择的方法:1、 编写一个GINA代理;此方法我们在以后的文章中介绍。实际上,ac952_z_cn的个人专栏文章:?WINDOWS NT/2000下如何屏蔽CTRL+ALT+DEL?使用的就是这种方法。2、 编写一个键盘驱动程序;本文例子程序使用的方法。3、 用自己的程序代替任务管理器程序TaskMgr.exe。屏蔽Ctrl+Alt+Del解决方案的具体实现细节请参考本文的例子代码。下面让我们来解决屏蔽任务切换键序列的问题,这些键序列包括Alt+Tab、Ctrl+Esc、Alt+Esc、VK_LWIN/VK_RWIN以及任务栏。在很早以前的Window 3.1年代,处理这个问题的方法是通过WM_SYSKEYDOWN实现。到了Windows 9x时期,本文前面提到过对这个问题的处理方法,使用SPI_SETSCREENSAVERRUNNING。但是进入Windows NT 4.0 (SP3 +),Windows 2000以及Windows XP时代,对这个问题的处理已经有所不同,必须写一个低级的键盘驱动钩子。不要怕,因为要实现这个钩子并不是很难。本文下面会介绍如何实现这个键盘钩子。一般来讲,系统级钩子必须是一个DLL。下面是本文提供的一个键盘钩子DLL的源代码片断(TaskKeyHook.dll):头文件//////////////////////////////////////////////////////////////////TaskKeyHook.h//#define DLLIMPORT __declspec(dllimport)DLLIMPORT BOOL DisableTaskKeys(BOOL bEnable, BOOL bBeep);DLLIMPORT BOOL AreTaskKeysDisabled();实现文件////////////////////////////////////////////////////////////////// TaskKeyHook.cpp//#define _WIN32_WINNT 0x0500 // for KBDLLHOOKSTRUCT#include // MFC core and standard components#define DLLEXPORT __declspec(dllexport)//////////////////// App (DLL) object//class CTaskKeyHookDll : public CWinApp {public:CTaskKeyHookDll() { }~CTaskKeyHookDll() { }} MyDll;////////////////////////////////////////////////// 下面的代码表示这一部分在此DLL所有实例之间共享// 低级键盘钩子一定是系统级的钩子//#pragma data_seg (".mydata")HHOOK g_hHookKbdLL = NULL; // 钩子句柄BOOL g_bBeep = FALSE; // 按下非法键时蜂鸣响铃#pragma data_seg ()#pragma comment(linker, "/SECTION:.mydata,RWS") // 告诉链接器:建立数据共享段//////////////////////////////////// 低级键盘钩子// 截获任务转换键:不传递直接返回//LRESULT CALLBACK MyTaskKeyHookLL(int nCode, WPARAM wp, LPARAM lp){KBDLLHOOKSTRUCT *pkh = (KBDLLHOOKSTRUCT *) lp;if (nCode==HC_ACTION) {BOOL bCtrlKeyDown =GetAsyncKeyState(VK_CONTROL)>>((sizeof(SHORT) * 8) - 1);if ((pkh->vkCode==VK_ESCAPE && bCtrlKeyDown) // Ctrl+Esc// Alt+TAB(pkh->vkCode==VK_TAB && pkh->flags & LLKHF_ALTDOWN) // Alt+Esc(pkh->vkCode==VK_ESCAPE && pkh->flags & LLKHF_ALTDOWN)(pkh->vkCode==VK_LWIN pkh->vkCode==VK_RWIN)) { // 开始菜单if (g_bBeep && (wp==WM_SYSKEYDOWNwp==WM_KEYDOWN))MessageBeep(0); // 蜂鸣return 1; // 不再往CallNextHookEx传递,直接返回}}return CallNextHookEx(g_hHookKbdLL, nCode, wp, lp);}////////////////////////////////////////////////// 是否屏蔽任务键序列?也就是说键盘钩子是否安装?// 注:这里设没有其它钩子做同样的事情//DLLEXPORT BOOL AreTaskKeysDisabled(){return g_hHookKbdLL != NULL;}////////////////////////////////////////////////// 屏蔽任务键:安装低级键盘构// 返回当前是否屏蔽标志(TRUE/FALSE)//DLLEXPORT BOOL DisableTaskKeys(BOOL bDisable, BOOL bBeep){if (bDisable) {if (!g_hHookKbdLL) {g_hHookKbdLL = SetWindowsHookEx(WH_KEYBOARD_LL,MyTaskKeyHookLL, MyDll.m_hInstance, 0);}} else if (g_hHookKbdLL != NULL) {UnhookWindowsHookEx(g_hHookKbdLL);g_hHookKbdLL = NULL;}g_bBeep = bBeep;return AreTaskKeysDisabled();}TaskKeyHook 输出两个函数:DisableTaskKeys 和 AreTaskKeysDisabled。前者安装WH_KEYBOARD_LL 钩子;后者判断这个钩子是否安装。此键盘钩子的处理思路是截获Alt+Tab,Ctrl+Esc,Alt+Esc以及Windows 键VK_LWIN/VK_RWIN,关于这两个键,稍候会有详细描述。当钩子碰到这些键时,它直接返回到调用者,而不是将处理传递给CallNextHookEx 。LRESULT CALLBACK MyTaskKeyHookLL(...){if (/* 任务键*)return 1; // 立即返回return CallNextHookEx(...);}TaskKeyHook的大部分实现都很简单。只有一个地方用到了一点小技巧:既使用#pragma data_seg 命名包含全程数据的数据段,并且用#pragma comment (linker...)告诉链接器让这个数据段为共享段。实现细节请参考源代码。本文附带的例子程序(TrapKeys.exe)汇集了上述几个有关屏蔽键盘按键序列的功能,除此之外,它还有一个功能就是禁用任务栏。因为既然禁用了任务转换键,那么一般来说,也必然要禁用任务栏,否则禁用任务转换键就没有意义了。禁用任务栏的具体方法如下:HWND hwnd = FindWindow("Shell_traywnd", NULL);//找到任务栏EnableWindow(hwnd, FALSE); // 禁用任务栏如图四是例子程序运行画面:图四 TrapKeys程序运行画面以下是TrapKeys程序的实现代码://///////////////////////////////////////////////// TrapKeys.cpp//#include "stdafx.h"#include "resource.h"#include "StatLink.h"#include "TaskKeyMgr.h"////////////////////// 主对话框//class CMyDialog : public CDialog {public:CMyDialog(CWnd* pParent = NULL) : CDialog(IDD_MYDIALOG, pParent) { }protected:HICON m_hIcon;CStaticLink m_wndLink1;CStaticLink m_wndLink2;CStaticLink m_wndLink3;virtual BOOL OnInitDialog();// 命令/UI 的更新处理afx_msg void OnDisableTaskMgr();afx_msg void OnDisableTaskKeys();afx_msg void OnDisableTaskbar();afx_msg void OnUpdateDisableTaskMgr(CCmdUI* pCmdUI);afx_msg void OnUpdateDisableTaskKeys(CCmdUI* pCmdUI);afx_msg void OnUpdateDisableTaskbar(CCmdUI* pCmdUI);afx_msg LRESULT OnKickIdle(WPARAM,LPARAM);DECLARE_MESSE_MAP()};///////////////////////////////////////////////////////// 标准的MFC 对话框应用类代码。//class CMyApp : public CWinApp {public:virtual BOOL InitInstance() {// 初始化:运行对话框CMyDialog dlg;m_pMainWnd = &dlg;dlg.DoModal();return FALSE;}virtual int ExitInstance() {// 为了按全起见,在退出程序的时候,将所有禁用的项目复原CTaskKeyMgr::Disable(CTaskKeyMgr::ALL, FALSE);return 0;}} theApp;BEGIN_MESSE_MAP(CMyDialog, CDialog)ON_COMMAND(IDC_DISABLE_TASKKEYS,OnDisableTaskKeys)ON_COMMAND(IDC_DISABLE_TASKBAR, OnDisableTaskbar)ON_COMMAND(IDC_DISABLE_TASKMGR, OnDisableTaskMgr)ON_UPDATE_COMMAND_UI(IDC_DISABLE_TASKKEYS, OnUpdateDisableTaskKeys)ON_UPDATE_COMMAND_UI(IDC_DISABLE_TASKBAR, OnUpdateDisableTaskbar)ON_UPDATE_COMMAND_UI(IDC_DISABLE_TASKMGR, OnUpdateDisableTaskMgr)ON_MESSE(WM_KICKIDLE,OnKickIdle)END_MESSE_MAP()///////////////////////////////////////////////// 初始化对话框:子类化超链接柄加栽图标//BOOL CMyDialog::OnInitDialog(){CDialog::OnInitDialog();// 初始化超链接m_wndLink1.SubclassDlgItem(IDC_EMAIL,this);m_wndLink2.SubclassDlgItem(IDC_VCKBASEURL,this);m_wndLink3.SubclassDlgItem(IDC_VCKBASELINK,this);// 自己设置对话框图标。MFC不会为对话框应用程序设置它m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);SetIcon(m_hIcon, TRUE); // 打图标SetIcon(m_hIcon, FALSE); // 小图标return TRUE;}////////////////////////////////////////////////////////// 命令/UI 更新处理:写这些东西应该很轻松。void CMyDialog::OnDisableTaskKeys(){CTaskKeyMgr::Disable(CTaskKeyMgr::TASKKEYS,!CTaskKeyMgr::AreTaskKeysDisabled(), TRUE); // 蜂鸣}void CMyDialog::OnUpdateDisableTaskKeys(CCmdUI* pCmdUI){pCmdUI->SetCheck(CTaskKeyMgr::AreTaskKeysDisabled());}void CMyDialog::OnDisableTaskbar(){CTaskKeyMgr::Disable(CTaskKeyMgr::TASKBAR,!CTaskKeyMgr::IsTaskBarDisabled());}void CMyDialog::OnUpdateDisableTaskbar(CCmdUI* pCmdUI){pCmdUI->SetCheck(CTaskKeyMgr::IsTaskBarDisabled());}void CMyDialog::OnDisableTaskMgr(){CTaskKeyMgr::Disable(CTaskKeyMgr::TASKMGR,!CTaskKeyMgr::IsTaskMgrDisabled());}void CMyDialog::OnUpdateDisableTaskMgr(CCmdUI* pCmdUI){pCmdUI->SetCheck(CTaskKeyMgr::IsTaskMgrDisabled());}////////////////////////////////////////////////////////// 要想让ON_UPDATE_COMMAND_UI正常工作,这是必需的。//LRESULT CMyDialog::OnKickIdle(WPARAM wp, LPARAM lCount){UpdateDialogControls(this, TRUE);return 0;}按上述方法尽管禁用了任务栏,但是还有一个机关没有处理,那就是按下Windows键仍然可以弹出?开始?菜单。显然在处理VK_LWIN之前,任务栏不会检查是否被启用。一般来讲,如果某个窗口被屏蔽掉,那么它就不再会处理用户在这个窗口的输入?这就是所谓的禁用(Disable)的含义。通常调用EnableWindow(FALSE)后自然就达到了这个目的。但是处理VK_LWIN/VK_RWIN按键的代码决不会去检查任务栏启用/禁用状态。对此,本文的处理办法仍然是利用键盘钩子。修改一下TaskKeyHook实现,增加对Windows键的捕获。这样按下?开始?菜单键之后什么也不会发生。希望没有漏掉其它的按键。如果哪位读者发现漏掉了什么键,请和我联系,以便把它加到键盘钩子中去。为了简单起见,我在类CTaskKeyMgr中封装了所有禁用的函数。下面是这个类的定义击实现文件:TaskKeyMgr////////////////////////////////////////// TaskKeyMgr.h//#pragma once#include "TaskKeyHook.h"/////////////////////////////////////////////////////////////////////// 使用这个类禁用任务键,任务管理器或任务栏。// 用相应的标志调用Disable,如:CTaskMgrKeys::Disable(CTaskMgrKeys::ALL);//class CTaskKeyMgr {public:enum {TASKMGR = 0x01, // 禁用任务管理器(Ctrl+Alt+Del)TASKKEYS = 0x02, //禁用任务转换键(Alt-TAB, etc)TASKBAR = 0x04, //禁用任务栏ALL=0xFFFF //禁用所有东西L};static void Disable(DWORD dwItem,BOOL bDisable,BOOL bBeep=FALSE);static BOOL IsTaskMgrDisabled();static BOOL IsTaskBarDisabled();static BOOL AreTaskKeysDisabled() {return ::AreTaskKeysDisabled(); // 调用 DLL}};CPP实现////////////////////////////////////////////////////////////////// TaskKeyMgr.cpp//#include "StdAfx.h"#include "TaskKeyMgr.h"#define HKCU HKEY_CURRENT_USER// 用于禁用任务管理器策略的注册表键值对LPCTSTR KEY_DisableTaskMgr ="SoftwareMicrosoftWindowsCurrentVersionPoliciesSystem";LPCTSTR VAL_DisableTaskMgr = "DisableTaskMgr";///////////////////////////////////////////// 禁用相关的任务键//// dwFlags = 表示禁用什么// bDisable = 禁用为 (TRUE) ,否则为启用 (FALSE)// bBeep = 按下非法键是否蜂鸣(指针对任务键)//void CTaskKeyMgr::Disable(DWORD dwFlags, BOOL bDisable, BOOL bBeep){// 任务管理器 (Ctrl+Alt+Del)if (dwFlags & TASKMGR) {HKEY hk;if (RegOpenKey(HKCU, KEY_DisableTaskMgr,&hk)!=ERROR_SUCCESS)RegCreateKey(HKCU, KEY_DisableTaskMgr, &hk);if (bDisable) { // 禁用任务管理器(disable TM): set policy = 1DWORD val=1;RegSetValueEx(hk, VAL_DisableTaskMgr, NULL,REG_DWORD, (BYTE*)&val, sizeof(val));} else { // 启用任务管理器(enable TM)RegDeleteValue(hk,VAL_DisableTaskMgr);}}// 任务键 (Alt-TAB etc)if (dwFlags & TASKKEYS)::DisableTaskKeys(bDisable,bBeep); // 安装键盘钩// 任务栏if (dwFlags & TASKBAR) {HWND hwnd = FindWindow("Shell_traywnd", NULL);EnableWindow(hwnd, !bDisable);}}BOOL CTaskKeyMgr::IsTaskBarDisabled(){HWND hwnd = FindWindow("Shell_traywnd", NULL);return IsWindow(hwnd) ? !IsWindowEnabled(hwnd) : TRUE;}BOOL CTaskKeyMgr::IsTaskMgrDisabled(){HKEY hk;if (RegOpenKey(HKCU, KEY_DisableTaskMgr, &hk)!=ERROR_SUCCESS)return FALSE; // 没有此键,不禁用DWORD val=0;DWORD len=4;return RegQueryValueEx(hk, VAL_DisableTaskMgr,NULL, NULL, (BYTE*)&val, &len)==ERROR_SUCCESS && val==1;}这个类中的函数都是静态的,实际上CTaskKeyMgr完全就是一个名字空间。你可以在自己的程序中随心所欲地使用它。例如,禁用任务转换按键和任务栏,但是不禁用Ctrl+Alt+Del:CTaskKeyMgr::Disable(CTaskKeyMgr::TASKKEYS CTaskKeyMgr::TASKBAR, TRUE);此外,还有几个函数是用来检查当前禁用了哪些东西,甚至可以在用户按下禁用键时发出蜂鸣声?自己去享受Paul的源代码吧!

队列消息和非队列消息

从消息的发送途径来看,消息可以分成2种:队列消息和非队列消息。消息队列由可以分成系统消息队列和线程消息队列。系统消息队列由Windows维护,线程消息队列则由每个GUI线程自己进行维护,为避免给non-GUI现成创建消息队列,所有线程产生时并没有消息队列,仅当线程第一次调用GDI函数数系统给线程创建一个消息队列。队列消息送到系统消息队列,然后到线程消息队列;非队列消息直接送给目的窗口过程。

对于队列消息,最常见的是鼠标和键盘触发的消息,例如WM_MOUSERMOVE,WM_CHAR等消息,还有一些其它的消息,例如:WM_PAINT、WM_TIMER和WM_QUIT。当鼠标、键盘被触发后,相应的鼠标或键盘驱动程序就会把这些转换成相应的消息,然后输送到系统消息队列,由Windows系统去进行处理。Windows系统则在适当的时机,从系统消息队列中取出一个消息,根据前面我们所说的MSG消息结构确定消息是要被送往那个窗口,然后把取出的消息送往创建窗口的线程的相应队列,下面的事情就该由线程消息队列操心了,Windows开始忙自己的事情去了。线程看到自己的消息队列中有消息,就从队列中取出来,通过操作系统发送到合适的窗口过程去处理。

一般来讲,系统总是将消息Post在消息队列的末尾。这样保证窗口以先进先出的顺序接受消息。然而,WM_PAINT是一个例外,同一个窗口的多个 WM_PAINT被合并成一个 WM_PAINT 消息, 合并所有的无效区域到一个无效区域。合并WM_PAIN的目的是为了减少刷新窗口的次数。

非队列消息将会绕过系统队列和消息队列,直接将消息发送到窗口过程,。系统发送非队列消息通知窗口,系统发送消息通知窗口。 例如,当用户激活一个窗口系统发送WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR。这些消息通知窗口它被激活了。非队列消息也可以由当应用程序调用系统函数产生。例如,当程序调用SetWindowPos系统发送WM_WINDOWPOSCHANGED消息。一些函数也发送非队列消息,例如下面我们要谈到的函数。

消息的发送

了解了上面的这些基础理论之后,我们就可以进行一下简单的消息发送与接收。

把一个消息发送到窗口有3种方式:发送、寄送和广播。

发送消息的函数有SendMessage、SendMessageCallback、SendNotifyMessage、SendMessageTimeout;寄送消息的函数主要有PostMessage、PostThreadMessage、PostQuitMessage;广播消息的函数我知道的只有BroadcastSystemMessage、BroadcastSystemMessageEx。

SendMessage的原型如下:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam),这个函数主要是向一个或多个窗口发送一条消息,一直等到消息被处理之后才会返回。不过需要注意的是,如果接收消息的窗口是同一个应用程序的一部分,那么这个窗口的窗口函数就被作为一个子程序马上被调用;如果接收消息的窗口是被另外的线程所创建的,那么窗口系统就切换到相应的线程并且调用相应的窗口函数,这条消息不会被放进目标应用程序队列中。函数的返回值是由接收消息的窗口的窗口函数返回,返回的值取决于被发送的消息。

PostMessage的原型如下:BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam),该函数把一条消息放置到创建hWnd窗口的线程的消息队列中,该函数不等消息被处理就马上将控制返回。需要注意的是,如果hWnd参数为HWND_BROADCAST,那么,消息将被寄送给系统中的所有的重叠窗口和弹出窗口,但是子窗口不会收到该消息;如果hWnd参数为NULL,则该函数类似于将dwThreadID参数设置成当前线程的标志来调用PostThreadMEssage函数。

从上面的这2个具有代表性的函数,我们可以看出消息的发送方式和寄送方式的区别所在:被发送的消息是否会被立即处理,函数是否立即返回。被发送的消息会被立即处理,处理完毕后函数才会返回;被寄送的消息不会被立即处理,他被放到一个先进先出的队列中,一直等到应用程序空线的时候才会被处理,不过函数放置消息后立即返回。

实际上,发送消息到一个窗口处理过程和直接调用窗口处理过程之间并没有太大的区别,他们直接的唯一区别就在于你可以要作系统截获所有被发送的消息,但是不能够截获对窗口处理过程的直接调用。

以寄送方式发送的消息通常是与用户输入相对应的,因为这些不是十分紧迫,可以进行缓慢的缓冲处理,例如鼠标、键盘消息会被寄送,而按钮等消息则会被发送。

广播消息用得比较少,BroadcastSystemMessage函数原型如下:

long BroadcastSystemMessage(DWORD dwFlags,LPDWORD lpdwRecipients,UINT uiMessage,WPARAM wParam,LPARAM lParam);

该函数可以向指定的接收者发送一条消息,这些接收者可以是应用程序、可安装的驱动程序、网络驱动程序、系统级别的设备驱动消息和他们的任意组合。需要注意的是,如果dwFlags参数是B_QUERY并且至少一个接收者返回了BROADCAST_QUERY_DENY,则返回值为0,如果没有指定B_QUERY,则函数将消息发送给所有接收者,并且忽略其返回值。

窗口过程

窗口过程是一个用于处理所有发送到这个窗口的消息的函数。任何一个窗口类都有一个窗口过程。同一个类的窗口使用同样的窗口过程来响应消息。 系统发送消息给窗口过程将消息数据作为参数传递给他,消息到来之后,按照消息类型排序进行处理,其中的参数则用来区分不同的消息,窗口过程使用参数产生合适行为。

一个窗口过程不经常忽略消息,如果他不处理,它会将消息传回到执行默认的处理。窗口过程通过调用DefWindowProc来做这个处理。窗口过程必须return一个值作为它的消息处理结果。大多数窗口只处理小部分消息和将其他的通过DefWindowProc传递给系统做默认的处理。窗口过程被所有属于同一个类的窗口共享,能为不同的窗口处理消息。下面我们来看一下具体的实例:

 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

 {

int wmId, wmEvent;

PAINTSTRUCT ps;

HDC hdc;

TCHAR szHello[MAX_LOADSTRING];

LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

switch (message)

{

case WM_COMMAND:

wmId = LOWORD(wParam);

wmEvent = HIWORD(wParam);

// Parse the menu selections:

switch (wmId)

{

case IDM_ABOUT:

DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);

break;

case IDM_EXIT:

DestroyWindow(hWnd);

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

break;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

// TODO: Add any drawing code here...

RECT rt;

GetClientRect(hWnd, &rt);

DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);

EndPaint(hWnd, &ps);

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

  }

return 0;

 }

消息分流器

通常的窗口过程是通过一个switch语句来实现的,这个事情很烦,有没有更简便的方法呢?有,那就是消息分流器,利用消息分流器,我们可以把switch语句分成更小的函数,每一个消息都对应一个小函数,这样做的好处就是对消息更容易管理。

之所以被称为消息分流器,就是因为它可以对任何消息进行分流。下面我们做一个函数就很清楚了:

void MsgCracker(HWND hWnd,int id,HWND hWndCtl,UINT codeNotify)

{

switch(id)

{

case ID_A:

if(codeNotify==EN_CHANGE)...

break;

case ID_B:

if(codeNotify==BN_CLICKED)...

break;

....

}

}

然后我们修改一下窗口过程:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

switch(message)

{

HANDLE_MSG(hWnd,WM_COMMAND,MsgCracker);

HANDLE_MSG(hWnd,WM_DESTROY,MsgCracker);

default:

return DefWindowProc(hWnd, message, wParam, lParam);

  }

return 0;

 }

在WindowsX.h中定义了如下的HANDLE_MSG宏:

 #define HANDLE_MSG(hwnd,msg,fn) \

switch(msg): return HANDLE_##msg((hwnd),(wParam),(lParam),(fn));

实际上,HANDLE_WM_XXXX都是宏,例如:HANDLE_MSG(hWnd,WM_COMMAND,MsgCracker);将被转换成如下定义:

 #define HANDLE_WM_COMMAND(hwnd,wParam,lParam,fn)\

((fn)((hwnd),(int)(LOWORD(wParam)),(HWND)(lParam),(UINT)HIWORD(wParam)),0L);

好了,事情到了这一步,应该一切都明朗了。

不过,我们发现在windowsx.h里面还有一个宏:FORWARD_WM_XXXX,我们还是那WM_COMMAND为例,进行分析:

 #define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \

(void)(fn)((hwnd), WM_COMMAND, MAKEWPARAM((UINT)(id),(UINT)(codeNotify)), (LPARAM)(HWND)(hwndCtl))

所以实际上,FORWARD_WM_XXXX将消息参数进行了重新构造,生成了wParam && lParam,然后调用了我们定义的函数。

MFC消息的处理实现方式

初看MFC中的各种消息,以及在头脑中根深蒂固的C++的影响,我们可能很自然的就会想到利用C++的三大特性之一:虚拟机制来实现消息的传递,但是经过分析,我们看到事情并不是想我们想象的那样,在MFC中消息是通过一种所谓的消息映射机制来处理的。

为什么呢?在潘爱民老师翻译的《Visual C++技术内幕》(第4版)中给出了详细的原因说明,我再简要的说一遍。在CWnd类中大约有110个消息,还有其它的MFC的类呢,算起来消息太多了,在C++中对程序中用到的每一个派生类都要有一个vtable,每一个虚函数在vtable中都要占用一个4字节大小的入口地址,这样一来,对于每个特定类型的窗口或控件,应用程序都需要一个440KB大小的表来支持虚拟消息控件函数。

如果说上面的窗口或控件可以勉强实现的话,那么对于菜单命令消息及按钮命令消息呢?因为不同的应用程序有不同的菜单和按钮,我们怎么处理呢?在MFC库的这种消息映射系统就避免了使用大的vtable,并且能够在处理常规Windows消息的同时处理各种各样的应用程序的命令消息。

说白了,MFC中的消息机制其实质是一张巨大的消息及其处理函数的一一对应表,然后加上分析处理这张表的应用框架内部的一些程序代码.这样就可以避免在SDK编程中用到的繁琐的CASE语句。

MFC的消息映射的基类CCmdTarget

如果你想让你的控件能够进行消息映射,就必须从CCmdTarget类中派生。CCmdTarget类是MFC处理命令消息的基础、核心。MFC为该类设计了许多成员函数和一些成员数据,基本上是为了解决消息映射问题的,所有响应消息或的类都从它派生,例如:应用程序类、框架类、文档类、视图类和各种各样的控件类等等,还有很多。

不过这个类里面有2个函数对消息映射非常重要,一个是静态成员函数DispatchCmdMsg,另一个是虚函数OnCmdMsg。

DispatchCmdMsg专门供MFC内部使用,用来分发Windows消息。OnCmdMsg用来传递和发送消息、更新用户界面对象的状态。

CCmdTarget对OnCmdMsg的默认实现:在当前命令目标(this所指)的类和基类的消息映射数组里搜索指定命令消息的消息处理函数。

这里使用虚拟函数GetMessageMap得到命令目标类的消息映射入口数组_messageEntries,然后在数组里匹配命令消息ID相同、控制通知代码也相同的消息映射条目。其中GetMessageMap是虚拟函数,所以可以确认当前命令目标的确切类。

如果找到了一个匹配的消息映射条目,则使用DispachCmdMsg调用这个处理函数;

如果没有找到,则使用_GetBaseMessageMap得到基类的消息映射数组,查找,直到找到或搜寻了所有的基类(到CCmdTarget)为止;

如果最后没有找到,则返回FASLE。

每个从CCmdTarget派生的命令目标类都可以覆盖OnCmdMsg,利用它来确定是否可以处理某条命令,如果不能,就通过调用下一命令目标的OnCmdMsg,把该命令送给下一个命令目标处理。通常,派生类覆盖OnCmdMsg时 ,要调用基类的被覆盖的OnCmdMsg。

在MFC框架中,一些MFC命令目标类覆盖了OnCmdMsg,如框架窗口类覆盖了该函数,实现了MFC的标准命令消息发送路径。必要的话,应用程序也可以覆盖OnCmdMsg,改变一个或多个类中的发送规定,实现与标准框架发送规定不同的发送路径。例如,在以下情况可以作这样的处理:在要打断发送顺序的类中把命令传给一个非MFC默认对象;在新的非默认对象中或在可能要传出命令的命令目标中。

消息映射的内容

通过ClassWizard为我们生成的代码,我们可以看到,消息映射基本上分为2大部分:

在头文件(.h)中有一个宏DECLARE_MESSE_MAP(),他被放在了类的末尾,是一个public属性的;与之对应的是在实现部分(.cpp)增加了一章消息映射表,内容如下:

BEGIN_MESSE_MAP(当前类, 当前类的基类)

file://{{AFX_MSG_MAP(CMainFrame)

 消息的入口项

file://}}AFX_MSG_MAP

END_MESSE_MAP()

但是仅是这两项还远不足以完成一条消息,要是一个消息工作,必须有以下3个部分去协作:

1.在类的定义中加入相应的函数声明;

  2.在类的消息映射表中加入相应的消息映射入口项;

  3.在类的实现中加入相应的函数体;

消息的添加

有了上面的这些只是作为基础,我们接下来就做我们最熟悉、最常用的工作:添加消息。MFC消息的添加主要有2种方法:自动/手动,我们就以这2种方法为例,说一下如何添加消息。

1、利用Class Wizard实现自动添加

在菜单中选择View-->Class Wizard,也可以用单击鼠标右键,选择Class Wizard,同样可以激活Class Wizard。选择Message Map标签,从Class name组合框中选取我们想要添加消息的类。在Object IDs列表框中,选取类的名称。此时, Messages列表框显示该类的大多数(若不是全部的话)可重载成员函数和窗口消息。类重载显示在列表的上部,以实际虚构成员函数的大小写字母来表示。其他为窗口消息,以大写字母出现,描述了实际窗口所能响应的消息ID。选中我们向添加的消息,单击Add Function按钮,Class Wizard自动将该消息添加进来。

有时候,我们想要添加的消息本应该出现在Message列表中,可是就是找不到,怎么办?不要着急,我们可以利用Class Wizard上Class Info标签以扩展消息列表。在该页中,找到Message Filter组合框,通过它可以改变首页中Messages列表框中的选项。这里,我们选择Window,从而显示所有的窗口消息,一把情况下,你想要添加的消息就可以在Message列表框中出现了,如果还没有,那就接着往下看:)

2、手动地添加消息处理函数

如果在Messages列表框中仍然看不到我们想要的消息,那么该消息可能是被系统忽略掉或者是你自己创建的,在这种情况下,就必须自己手工添加。根据我们前面所说的消息工作的3个部件,我们一一进行处理:

1) 在类的. 件中添加处理函数的声明,紧接在//}}AFX_MSG行之后加入声明,注意:一定要以afx_msg开头。

通常,添加处理函数声明的最好的地方是源代码中Class Wizard维护的表下面,但是在它标记其领域的{{}}括弧外面。这些括弧中的任何东西都将会被Class Wizard销毁。

2) 接着,在用户类的.cpp文件中找到//}}AFX_MSG_MAP行,紧接在它之后加入消息入口项。同样,也是放在{ {} }的外面

3) 最后,在该文件中添加消息处理函数的实体。

热门文章