《Windows API每日一练》5.1 键盘基础
本节我们讲述关于键盘的一些基础知识。当我们按下一个键盘按键时,会产生一个键盘按键消息。这一点你能确定吗?假如是一个菜单快捷键消息,或者是一个子窗口控件消息呢?这就超出了本节讨论的范围,我们将在菜单和子窗口控件详细讲述。假设的确是一个按键消息,它将被送入窗口消息队列,做同步处理。在消息循环中,GetMessage函数获取到按键消息后,如果是一个字符按键消息,TranslateMessage函数会将其转化为字符消息WM_CHAR并将其送入消息队列,然后再由DispatchMessage函数继续将按键消息分发给Windows系统。如果是一个非字符按键消息,则直接由DispatchMessage函数将其分发给Windows系统。
本节必须掌握的知识点:
忽略键盘
键盘焦点
队列和同步
击键和字符
5.1.1 忽略键盘
当我们按下键盘按键的时候会产生键盘按键消息,或者我们调用PostMessage或SendMessage函数发送键盘消息,也可能是Windows系统产生的按键消息。所有这些按键消息并不是都需要我们主动去处理的。我们只需要处理真正需要关注的一些按键消息,把一些不需要我们处理的按键消息统统交给Windows系统默认的窗口过程去处理。这些常常忽略的按键消息有以下几类:
■系统按键消息
通常可以忽略一些属于系统功能的按键操作。这些按键一般都包含Alt键。程序不必去监控这些按键消息,因为Windows会将按键的效果通报给程序,在默认情况下,它们会被交付给DefWindowProc函数处理。有时候我们处于某种目的也可能会拦截系统按键消息,在后面的章节中遇到了我们再详细讲述。
■键盘快捷键消息
许多Windows程序用键盘快捷键来调用常用菜单项。快捷键经常是Ctrl键同功能键或 者字母键的组合(例如,Ctrl+S键用于保存一个文件)。这些键盘快捷键和程序菜单一起在程 序的资源脚本中定义,这些我们将在第九章中看到。Windows会把这些键盘快捷键转换为菜单命令消息。你不必自己去做转换,窗口过程只需要处理菜单消息就可以了。
■控件消息
对话框也有键盘接口,但是程序不必在对话框活跃的时候去监视键盘。Windows会处理 键盘接口,接着Windows把击键效果的消息传送给程序。对话框包含了用于文本输入的编 辑控件。它们一般是一些小方框,用户可以输入字符串。Windows处理所有的编辑控件逻辑,并在用户输入完成后,将最终的内容传送给程序。关于对话框,将在第十章详细介绍。
编辑控件不必局限于只有单独的一行,它的位置也不必局限在对话框中。程序主窗口中的多行编辑控件可以用作一个简单的文本编辑器。(参见第八章的POPPAD程序。)另外,Windows也有专业的富文本编辑控件,可以允许你编辑和显示格式化的文本(第十一章我们会详细讲解富文本控件) 。
当你设计Windows程序时,将会发现可以使用子窗口控件来处理键盘和鼠标的输入以 便把更高层的消息传回父窗口。只要积累了足够多的这样的控件,你就不会再为处理键盘消息而烦恼了。
5.1.2 键盘焦点
假如我们现在按下了一个键盘按键,但是桌面当前有多个窗口同时存在,那么就产生了一个问题,这个按键消息会送入到哪个窗口的消息队列呢?
我们在第二章2.3节消息机制中讲述过,当用户按下一个按键时,产生的按键消息会被送入到Windows系统总的消息队列,然后根据按键消息所属的窗口将其送入到对应的窗口消息队列。是否还记得MSG消息结构的第一个字段就是消息所属的窗口句柄。意思是当我们按下按键的那一刻就已经确定了消息所属的窗口,而不是等到送入总消息队列后再确定所属窗口的。那么,确定消息所属窗口的依据是什么呢?就是当前具有键盘输入焦点的窗口。
接收到这个键盘事件的窗口称为有输入焦点的窗口。输入焦点的概念和活动窗口的概 念是紧密相连的。具有输入焦点的窗口要么是活动窗口,要么是活动窗口的子孙窗口——也就是说,活动窗口的子窗口,或者是活动窗口的子窗口的子窗口,等等。
活动窗口通常是很好鉴别的。它总是最上层的窗口——也就是说,它的父窗口句柄是 NULL。如果一个活动窗口有标题栏,Windows会加亮显示其标题栏。如果活动窗口有会话边框(常见的对话框的外形)而不是标题栏,Windows会加亮显示其边框。如果活动窗口目前处于最小化状态,Windows将突出显示它在任务栏中的条目,就像一个按下的按钮似的。
如果活动窗口有子窗口,具有输入焦点的窗口可以是活动窗口,也可以是它的子孙窗口中的一个。最常见的子窗口是出现在对话框中的如下控件:按钮、单选按钮、复选框、滚动条、编辑框或列表框。子窗口自己不能成为活跃窗口。仅当它是活跃窗口的子孙窗口时,该子窗口才具有输入焦点。子窗口控件通常通过显示一个闪烁的插入符号或虚线指出输入焦点。
有时没有窗口具有输入焦点。这种情况会发生在所有程序都最小化时。但Windows仍 将发送键盘消息给活动窗口,只不过此时的消息形式不同于活动窗口没有最小化时发送的 键盘消息。
窗口过程通过捕获WM_SETFOCUS和WM_CILLFOCUS消息来确定自己的窗口是否具有输入焦点。WM_SETFOCUS表明窗口正在接受输入焦点,而WM_KILLFOCUS表明窗口正在失去输入焦点。这些消息将在本章的稍后部分详细介绍。
![]()
总结
1.活动窗口:桌面最上层窗口,其父窗口句柄为NULL,加亮标题栏或突出显示在任务栏。
2.焦点窗口:活动窗口的子孙窗口,通常是一个闪烁的插入符或虚线框指示输入焦点。
3.捕获WM_SETFOCUS来确定其具有输入焦点,WM_KILLFOCUS说明正失去焦点。
4.当所有程序都最小化时,没有窗口具有输入焦点,Windows仍将发送键盘消息给活动窗口。这时所有击键都产生WM_SYSKEYDOWN和WM_SYSKEYUP消息。
5.1.3 队列和同步
当用户按下和释放键盘上的一个键时,Windows和键盘设备驱动程序将硬件扫描码转 换为格式化后的消息。但是,这些消息并不立即被放入应用程序消息队列,而是由Windows 把这些消息存储在系统总消息队列中。系统消息队列是一个单独的消息队列,它被Windows 用来初步存储用户从键盘和鼠标输入的消息。仅当Windows应用程序完成了对前一个用户输入消息的处理后,Windows才从系统消息队列中取出下一条消息,并把它放入应用程序消息队列。
这是一种两步处理法,即先把消息存储在系统消息队列里,再把它们发送到应用程序消息队列。采用两步处理法的原因是需要同步。像我们刚了解的那样,被期望接收键盘输入的窗口是具有活动焦点的窗口。用户输入的速度可能快于应用程序能处理的击键动作,而一个特殊的击键可能会使焦点从一个窗口转换到另一个窗口。后续的击键也应该跟着到了另一个窗口。但如果后续的击键己经被转到了目的窗口,且被放置在了应用程序消息队列中,则它们不能被输入到另一个窗口。

图5-1 消息队列
![]()
总结
●两步法处理键消息:先把消息存储在系统消息队列里,再发送到应用程序消息队列里。
1.击键事件:将击键转为消息,放入系统消息队列(注意不立即放入应用程序消息队列);
2.应用程序处理完前一个输入消息,Windows从系统队列取下一条消息放入应用程序消息队列。
●两步处理法的原因——同步
因为当应用程序1接收到一个特殊的、转换窗口焦点的击键动作时,后续的击键消息也应被转移到另一个程序(如应用程序2)的队列中去。如果键盘消息不经系统队列的缓冲,当用户输入太快,而应用程序1来不及没处理完这个特殊消息时,可能后续的击键消息又被发送到应用程序1的队列中来了,从而导致错误。因此,键盘消息要先放到系统队列中,起到同步的作用。
5.1.4 击键和字符
应用程序从Windows接收的关于键盘事件的消息可分为击键和字符两种。
首先,你可以认为键盘是键的集合。键盘上仅有一个键标示为“A”。按下此键是一次击键,释放此键也认为是一次击键。同时键盘也是能产生可显示字符或者控制字符的输入设备。“A”键能产生一些不同的字符,这取决于同Ctrl、Shift、Caps Lock键的组合,通常此字符为小写字母“a”。如果Shift键被按下或者Caps Lock键被锁定,此字符就为大写字母“A”。如果Ctrl键被按下,则此字符就是Ctrl+A(它在ASCII码中有意义,但是在Windows里,就可能是一个键盘快捷键)。在一些键盘上,可能会有死字符键或者 Shift、Ctrl、Alt键与“A”键的组合。这种组合能产生带重音符号的小写字母或大写字母,例如,à、á、â、Ä、或 Å等。
对产生可显示字符的击键组合,Windows在发送击键消息的同时还发送字符消息。有些键不产生字符,如Shift键、功能键、光标移动键和特殊字符键(如Insert键和Delete键)。 对于这些键,Windows只产生击键消息。
相关文章:
《Windows API每日一练》5.1 键盘基础
本节我们讲述关于键盘的一些基础知识。当我们按下一个键盘按键时,会产生一个键盘按键消息。这一点你能确定吗?假如是一个菜单快捷键消息,或者是一个子窗口控件消息呢?这就超出了本节讨论的范围,我们将在菜单和子窗口控…...
Class.forName()方法总结
Class.forName()方法总结 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!Class.forName()方法是Java反射机制中的一个重要方法,它用于动态加载类并返…...
Python | Leetcode Python题解之第168题Excel表列名称
题目: 题解: class Solution:def convertToTitle(self, columnNumber: int) -> str:ans list()while columnNumber > 0:columnNumber - 1ans.append(chr(columnNumber % 26 ord("A")))columnNumber // 26return "".join(an…...
【ARMv8/ARMv9 硬件加速系列 3.5.2 -- SVE 向量寄存器 有多少位数?】
文章目录 SVE 向量寄存器SVE 向量寄存器大小SVE 可伸缩性的好处SVE 寄存器长度示例SVE 向量寄存器 在 ARMv9 架构中,包括其 Scalable Vector Extension (SVE) 和 Scalable Vector Extension 2 (SVE2) 的增强,向量寄存器(通常称为 Z 寄存器)的大小设计为可伸缩的,以便在不…...
Vulkan入门系列2- 绘制三角形(未完待续)
概述: Vulkan的学习曲线是比较陡峭的,学习Vulkan刚开始像是在爬一个陡坡,等上了这个陡坡之后,后面学习曲线就相对比较平缓了。那么在Vulkan中绘制一个三角形,就相当于是在爬这样一个陡坡,因为绘制三角形需…...
企业UDP文件传输工具测速的方式(下)
在前一篇文章中,我们深入讨论了UDP传输的基本概念和镭速UDP文件传输工具如何使用命令行快速进行速度测试。现在,让我们进一步探索更为高级和灵活的方法,即通过整合镭速UDP的动态或静态库来实现网络速度的测量,以及如何利用这一过程…...
Artalk-CORS,跨域拦截问题
今天重新部署Artalk之后,遇到了CORS——跨域拦截的问题,卡了好一会记录一下。 起因 重新部署之后,浏览器一直提示CORS,之前在其他项目也遇到过类似的问题,原因就在于跨域问题。...
SSL证书怎样配置部署更安全?
在互联网上,SSL证书是用于加密网站与用户之间传输的数据的一种数字证书。它通过建立安全的连接,确保网站的身份和保护用户的隐私,是网站安全的重要组成部分。然而,要想让SSL证书发挥最大的作用,除了检查证书是否过期外…...
M1失效后,哪个是观察A股的关键新指标?
M1失效后,哪个是观察A股的关键新指标? 央地支出增速差(地方-中央支出增速的差值)或许是解释沪深300定价更有效的前瞻指标。该数值扩张,则有利于大盘指数,反之亦然,该指标从2017年至今对大盘指数…...
springboot集成积木报表,怎么将平台用户信息传递到积木报表
springboot集成积木报表后怎么将平台用户信息传递到积木报表 起因是因为需要研究在积木报表做数据筛选的时候需要拿到系统当前登录用户信息做筛选新的模块 起因是因为需要研究在积木报表做数据筛选的时候需要拿到系统当前登录用户信息做筛选 官网有详细介绍怎么集成进去的&…...
Spring Bean详解
Spring Bean作用域 默认情况下,所有的 Spring Bean 都是单例的,也就是说在整个 Spring 应用中, Bean 的实例只有一个 如果我们需要创建多个实例的对象,那么应该将 Bean 的 scope 属性定义为 prototype,如果 Spring 需…...
前端根据环境变量配置网页的title和favicon
前端根据环境变量配置网页的title和favicon 前言流程步骤一、设置environment文件二、在入口文件中配置三、删除index.html中的title和 icon link四、使用对应的打包命令进行部署 注意事项一、angular中,需要在angular.json添加favicon.ico额外的构建 前言 有些项目…...
服务器负载均衡
什么是服务器负载 1. 常见理解的平均负载 每次发现系统变慢时,我们通常做的第一件事,就是执行 top 或者 uptime 命令,来了解系统的负载情况。比如下列情况 [rootkube-node1 ~]# uptime09:44:37 up 74 days, 11:53, 1 user, load average:…...
如何设置Excel单元格下拉列表
如何设置Excel单元格下拉列表 在Excel中设置单元格下拉列表可以提高数据输入的准确性和效率。以下是创建下拉列表的步骤: 使用数据验证设置下拉列表: 1. 选择单元格: 选择你想要设置下拉列表的单元格或单元格区域。 2. 打开数据验证&…...
红队内网攻防渗透:内网渗透之Linux内网权限提升技术:LXDDockerRbash限制型bash
红队内网攻防渗透 1. 内网权限提升技术1.1 Linux系统提权-普通用户-LXD容器1.2 Linux系统提权-普通用户-Docker容器1.3 权限在docker里面1.4 Linux系统提权-普通用户-Rbash限制型bash1. 内网权限提升技术 利用参考 https://gtfobins.github.io/LXD、LXC 和 Docker 是三种不同…...
【笔记】复制Edge的网址粘贴后自动变成中文标题超链接
问题 1、从edge复制的网址粘贴直接显示网页内容名称而不是网址url。 2、复制任何网址粘贴到CSDN里面粘贴时直接转换成标题超链接(很讨厌的功能习惯)。 而如上两种问题不是互相影响的,就算设置了Edge的粘贴方式,复制到CSDN的文章…...
HTML5和CSS3总结
HTML5 HTML5是最新的HTML标准,它的主要目标是提供所有内容而不需要任何像flash,silverlight等的额外插件,这些内容来自动画、视频、富GUI等。HTML5是万维网联盟(W3C)和网络超文本应用技术工作组(WHATWG&am…...
探索数据分析无限潜能:vividime Desktop助力企业智能决策
在数字化浪潮席卷全球的今天,数据已经成为企业最宝贵的资产之一。通过对海量数据的深度挖掘和分析,企业能够洞察市场趋势、优化运营流程、提升用户体验,从而在激烈的市场竞争中脱颖而出。永洪科技的vividime Desktop作为一款功能强大、操作简…...
gitee添加别人的仓库后,在该仓库里添加文件夹/文件
一、在指定分支里添加文件夹(如果库主没有创建分支,自己还要先创建分支) eg:以在一个项目里添加视图文件为例,用Echarts分支在usr/views目录下添加Echarts文件夹,usr/views/Echarts目录下添加index.vue 1.切换为本地仓…...
[笔记] CCD相机测距相关的一些基础知识
1.35mm胶片相机等效焦距 https://zhuanlan.zhihu.com/p/419616729 拿到摄像头拍摄的数码照片后,我们会看到这样的信息: 这里显示出了两个焦距:一个是实际焦距:5mm,一个是等效焦距:25mm。 实际焦距很容易…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
