windows SDK编程 --- 消息之键盘消息(4)

前置知识

一、 键盘消息

在Windows操作系统中,键盘消息是用来通知应用程序有关键盘输入事件的一种机制。当用户在键盘上进行操作,比如按键或释放键时,Windows会生成相应的消息并发送给处理这些输入的应用程序。这些消息对于开发图形用户界面(GUI)应用程序至关重要,因为它们允许应用程序响应用户的输入。

下面是几种主要的键盘消息及其用途的详细说明:

  1. WM_KEYDOWN
描述:
当用户按下一个键盘键(并未完全释放)时发送此消息给拥有焦点的窗口。
参数:
wParam:虚拟键码。
lParam:提供了有关按键的更多信息,如重复次数、扫描码、ALT键是否被按下等。
lParam 参数的详细位分布:
0-15位:重复计数(Repeat count)。这表示自从用户开始按下键以来,由于按键保持不放,相同的消息被自动重复发送的次数。这个计数不是累积的,每次消息发送时都是独立的计数。
16-23位:扫描码(Scan code)。这是键盘硬件产生的代码,用于识别物理键。
24位:扩展键标志(Extended-key flag)。如果是扩展键(如功能键、方向键等),该位为125-28位:保留,未使用。
29位:上下文代码。对于 WM_KEYDOWN 消息,这个值始终为030位:上一个键状态(Previous key state)。如果在发送此消息之前键是未按下的,则此位为1;如果键已经是按下状态,则此位为031位:转换状态(Transition state)。对于 WM_KEYDOWN,该位总是为0;对于 WM_KEYUP,该位为1
  1. WM_KEYUP
描述:
当用户释放一个键盘键时发送此消息。
参数:
wParam:虚拟键码。
lParam:同样包含键的重复次数、扫描码、是否有ALT键等信息。
  1. WM_CHAR
描述:
用于处理字符输入,当按下能产生字符的键时,通过 TranslateMessage 函数生成。例如,按下 A 键时,如果启用了大写锁定或者同时按住了Shift键,可能会发送 WM_CHAR 消息并携带字符 ‘A’。
参数:
wParam:字符的ASCII或Unicode值。
lParam:与 WM_KEYDOWN 和 WM_KEYUP 相同,提供了关于按键事件的更多细节。
  1. WM_SYSKEYDOWN 和 WM_SYSKEYUP
描述:
这些消息类似于 WM_KEYDOWN 和 WM_KEYUP,但它们用于处理系统键(如Alt和F10)。
参数:
wParam:虚拟键码。
lParam:包含与普通键盘消息相同的额外信息。

二、什么是虚拟键码

虚拟键码是Windows操作系统定义的一组常数,用于表示键盘上的每一个按键。这些键码可以让开发者在编程时准确地识别用户按下或释放的具体键,无论键盘布局和硬件如何。虚拟键码在处理键盘输入提供了一个硬件无关的方法来识别键盘动作。简而言之,虚拟键码就是对键盘按键的一种编程上的抽象表示。wParam 参数会包含被按下或释放键的虚拟键码。

VK_A:字母 'A' 键(值为 0x41)
VK_0:数字 '0' 键(值为 0x30)
VK_ESCAPE:Esc键(值为 0x1B)
VK_RETURN:回车键(值为 0x0D)
VK_LEFT:左方向键(值为 0x25)
VK_RIGHT:右方向键(值为 0x27)
VK_UP:上方向键(值为 0x26)
VK_DOWN:下方向键(值为 0x28

三、什么是扫描码?扫描码和虚拟键码的关系?

在Windows编程中,处理键盘事件如 WM_KEYDOWN 时,可以通过消息的 lParam 获取扫描码,而 wParam 提供虚拟键码。这允许程序同时利用键的物理位置(扫描码)和逻辑功能(虚拟键码)来响应用户的键盘操作。

键盘扫描码(Scan Code)

键盘扫描码是键盘硬件为每次按键生成的原始代码,表示按下的是键盘上的哪一个物理键。这些代码通常是硬件级的,与操作系统和键盘布局无关。扫描码的主要作用是在最底层—即硬件和操作系统的界面—提供键位信息。

  • 特点:扫描码直接来自键盘,不受键盘语言布局的影响。
  • 用途:用于在低级别(如驱动程序或操作系统核心)处理键盘输入。

虚拟键码(Virtual-Key Code)

虚拟键码是操作系统级的抽象,它将扫描码转换为一个标准化的代码,这反映了按键的“功能”,而不仅仅是位置。例如,无论在哪种键盘布局中,字母“A”的虚拟键码都是相同的,即使其物理位置可能不同。

  • 特点:虚拟键码依赖于键盘布局,因为它反映了按键的逻辑功能(如字符、命令等)。
  • 用途:用于编写应用程序时处理更高级的输入(如文字输入、控制命令等)。

两者的区别

  • 来源:扫描码来自键盘硬件;虚拟键码由操作系统提供。
  • 依赖性:扫描码与键盘布局无关,与物理键位置直接相关;虚拟键码依赖于键盘布局,反映键的逻辑功能。
  • 用途:扫描码通常在较低的系统级别(如操作系统或驱动程序)使用,用于识别物理键位;虚拟键码在更高级的应用程序中使用,用于处理具体的键盘功能,如文本输入或用户界面控制。

三、快捷键Shortcut Keys)和热键(Hotkeys)有什么区别

快捷键(Shortcut Keys)

  • 快捷键通常是指在特定应用程序内部使用的键盘组合,用于执行应用程序的特定功能。这些快捷键只在该应用程序具有焦点时有效。例如,许多应用程序都使用 Ctrl + S 作为保存操作的快捷键。
  • 上下文依赖:快捷键的作用依赖于当前应用程序的状态和哪个窗口或控件有焦点。
  • 实现方式:在应用程序的消息处理逻辑中捕捉和处理特定的 WM_KEYDOWN 或 WM_KEYUP 消息来实现快捷键功能。

热键(Hotkeys)

  • 热键是系统级的键盘快捷键,它们在整个操作系统中都是有效的,无论当前哪个应用程序有焦点。热键通常用于操作系统功能或某些特定应用程序的功能,这些功能需要从任何地方快速访问。
  • 全局作用域:热键无论在哪个应用程序中都能被触发
  • 注册使用:通过使用Windows API的 RegisterHotKey 函数来设置。这个函数允许你定义一个热键和一个与之关联的消息,当热键被按下时,这个消息将被发送到指定的窗口处理。

示例代码

#include <windows.h>



//5.消息处理
LRESULT CALLBACK WndProc(
    HWND hwnd,
    UINT msg,
    WPARAM wParam,
    LPARAM lParam
)
{
    // 根据消息类型进行分支处理

    switch (msg)
    {
    case WM_CREATE:
    {
        //注册热键
        RegisterHotKey(hwnd, 5566, MOD_CONTROL, VK_F1);

        return 0;
    }

    //键盘消息
    case WM_KEYDOWN:
    {
        //获得键盘状态
        BYTE KeyState[256];
        if (GetKeyboardState(KeyState)==0)
        {
            return TRUE; 
        }
        //键盘扫描码
        BYTE ScanCode = (int)lParam >> 16 && 0xff;
        WORD ch;
        //将键盘扫描码转换成Ascii码
        ToAscii(wParam, ScanCode, KeyState, &ch, 0);
        
        char buffer[100];
        wsprintf(buffer, "你按下了:%c\n", ch);
        OutputDebugString(buffer);

        return 0;
    }

    case WM_CHAR:
    {
        char buffer[100];
        wsprintf(buffer, "你按下了:%c\n", wParam);
        OutputDebugString(buffer);

        return 0;
    }

    case WM_KEYUP:
    {

        return 0;
    }


    //热键消息
    case WM_HOTKEY:
    {
        MessageBox(NULL, "HotKey!", "WM_HOTKEY", MB_OK);
        return 0;
    }



    case WM_CLOSE:
    {
        //询问是否关闭窗口
        int id = MessageBox(NULL, "你确定关闭窗口吗", "WM_CLOSE", MB_YESNO);
        if (id == IDYES)
        {
            DestroyWindow(hwnd);
        }

        return 0;
    }

    case WM_DESTROY:
    {
        //注销热键
        UnregisterHotKey(hwnd,5566);
        PostQuitMessage(0); 
        return 0;
    }


    }


    return DefWindowProc(hwnd, msg, wParam, lParam);


}

int WINAPI WinMain(
    HINSTANCE hInstance,     // 当前实例的句柄
    HINSTANCE hPrevInstance, // 前一个实例的句柄,现在总是为 NULL
    LPSTR lpCmdLine,         // 命令行参数的字符串
    int nCmdShow             // 指示程序窗口应如何被显示
)
{
    //1.注册窗口
    char MyWindowClassName[] = "MyWindowClass";         //窗口类名
    WNDCLASSEX wc = { 0 };
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_VREDRAW | CS_HREDRAW;     //
    wc.lpfnWndProc = WndProc;    //窗口过程函数(窗口回调函数->处理消息)
    wc.hInstance = hInstance;
    wc.hIcon = NULL;             //图标
    wc.hCursor = NULL;          //光标
    wc.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));    //窗口背景颜色刷子
    wc.lpszMenuName = NULL;     //菜单名称
    wc.lpszClassName = MyWindowClassName;    //窗口类名


    if (RegisterClassEx(&wc) == 0)
    {
        return 0;
    }




    //2.创建窗口
    char MyWindowName[] = "MyWindowClass";         //窗口名称

    HWND hwnd = CreateWindowEx(
        0,
        MyWindowClassName,
        MyWindowName,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL
    );
    if (hwnd == NULL)
    {
        return 0;
    }



    //3.显示更新窗口

    ShowWindow(hwnd, SW_SHOWNORMAL);
    UpdateWindow(hwnd);

    //4.消息循环(消息队列)
    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/579003.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文件夹惊变文件?揭秘原因及解决方案

在日常工作和生活中&#xff0c;电脑已经成为我们不可或缺的助手。然而&#xff0c;有时我们会遇到一些令人困惑的问题&#xff0c;比如&#xff0c;文件夹突然变成了文件。这听起来可能有些匪夷所思&#xff0c;但它确实会发生&#xff0c;而且给用户带来了不小的麻烦。当熟悉…

java-spring-mvc(知识点讲解-第一天)-欢迎各位大佬提建议

目录 &#x1f383;MVC定义 &#x1f9e8;创建工程 &#x1f3a8;SpringMVC处理请求 请求分类及处理方式 静态请求 处理静态前端页面方式 动态请求 处理动态前端页面方式 ⚙小试牛刀 &#x1f3c6;常见问题 &#x1f4cc;HTTP协议 超文本传输协议 请求 &#x1f383;MVC…

Web前端开发 小实训(二) 简易计算器

实训目的 学生能够使用函数完成简易计算器编写 操作步骤 1、请将加减乘除四个方法生成为以下函数&#xff0c;且有返回值 中文英语加法add减法subtract乘法multi除法division次幂pow()平方根sqrt() 提示&#xff1a; 除法中的除数不能为0&#xff01; 参考代码&#xff1…

在线培训考试系统在线考试功能注意事项

在线培训考试系统在线考试功能注意事项 考试前务必注意是否开启防切屏、摄像头监考等防作弊措施&#xff0c;系统一旦检测到触发了疑似作弊行为会立刻自动交卷&#xff0c;考试终止&#xff1b; 答题者准备好后&#xff0c;可点击“开始答题”按钮进入考试&#xff0c;注意考…

代码随想录第49天|121. 买卖股票的最佳时机 122.买卖股票的最佳时机II

121. 买卖股票的最佳时机 121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 动态规划之 LeetCode&#xff1a;121.买卖股票的最佳时机1_哔哩哔哩_bilibili 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一…

#C++里的引用#

目录 引用概念 定义引用类型 引用特性 常引用 传引用传参 传引用做返回值 1.引用概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同一块内存空间。 比如&#xff1a…

【AI】一文介绍索引增强生成RAG的原理和结构

今天向大家介绍一下关于RAG的一些知识和经验。 这里说的RAG可以理解为目前针对企业知识库问答等AI应用场景的解决方案,这个场景就是利用自然语言大模型LLM与用户自有的文件进行对话的能力。 【RAG的优势】 首先,讲一讲RAG的优势特征。 如果把AI想象成一个待上岗的人类助手,…

1、Flink DataStreamAPI 概述(上)

一、DataStream API 1、概述 1&#xff09;Flink程序剖析 1.Flink程序组成 a&#xff09;Flink程序基本组成 获取一个执行环境&#xff08;execution environment&#xff09;&#xff1b;加载/创建初始数据&#xff1b;指定数据相关的转换&#xff1b;指定计算结果的存储…

模型 AIPL(认知、兴趣、购买、忠诚)

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。品牌营销的量化与链路化。 1 AIPL模型的应用 1.1 耐克如何利用AIPL模型来推广其运动鞋和服装产品? 耐克利用AIPL模型来推广其运动鞋和服装产品&#xff0c;具体如下&#xff1a; 认知&#xff08;…

为什么总说抖店做不好?做抖店需要注意这些问题,是不是都占了?

大家好&#xff0c;我是电商花花。 今天给大家总结了4个新手不注意又常犯的几个原因&#xff0c;这些建议都是我们做店这些年的实操经验&#xff0c;可以帮助大家做店自查&#xff0c;有责改之&#xff0c;无责加冕。 1、抖店核心是选品而不是玩法 很多新手在刚开始做店抖音小…

8K+/月!学习就业一把梭,祝贺誉天数通陈同学收获心仪offer !

大家好&#xff0c;我是誉天数通的陈同学。 在武汉&#xff0c;网络运维圈的人应该都会听过誉天的名字。作为华为的授权培训合作伙伴&#xff0c;誉天不仅提供专业全面的工程师培训&#xff0c;还以其独特的环境和氛围吸引着无数有志于在网络领域发展的朋友。 一年前的我&#…

用坐标与碰撞检测效果

用pygame碰撞检测子弹 与 子弹 格子检查是否在墙内 结果差不了多少 输出的是碰撞点坐标 在计算角色与强的距离是 你用了几条射线 2024/4/26 13:20:48 在代码中&#xff0c;用于计算角色与墙之间距离的部分是通过投射多条射线来实现的。具体来说&#xff0c;在循环中&#xf…

IDEA插件

POJO to JSON —— 实体转Json Smart Input —— 自动切换中英文 Translation —— 翻译 Maven Helper —— 依赖管理 .ignore —— 忽略提交文件 enum-quick-generate —— 枚举代码生成 粘贴到项目包下

前端更优雅的使用 jsonp

前端更优雅的使用 jsonp 背景&#xff1a;最近项目中又使用到了 jsonp 这一项跨域的技术&#xff0c;&#xff08;主要还是受同源策略影响&#xff09;&#xff0c;下面有为大家提供封装好的函数及对应使用示例&#xff0c;欢迎大家阅读理解 文章目录 前端更优雅的使用 jsonp同…

基于车载点云数据的城市道路特征目标提取与三维重构

作者&#xff1a;邓宇彤&#xff0c;李峰&#xff0c;周思齐等 来源&#xff1a;《北京工业大学学报》 编辑&#xff1a;东岸因为一点人工一点智能公众号 基于车载点云数据的城市道路特征目标提取与三维重构本研究旨在弥补现有研究在处理复杂环境和大数据量上的不足&#xf…

Qt设置可执行程序图标,并打包发布

一、设置图标 图标png转ico: https://www.toolhelper.cn/Image/ImageToIco设置可执行程序图标 修改可执行程序图标 添加一个rc文件,操作如下,记得后缀改为rc 打开logo.rc文件添加代码IDI_ICON1 ICON DISCARDABLE "logo.ico"在项目pro后缀名的文件中添加代码 RC_…

系统盘空间不足调优方式1-APPData/大文件清理

作者&#xff1a;私语茶馆 1.前言 Windows系统盘&#xff08;C盘&#xff09;很容易剩余空间不足&#xff0c;这种情况下会非常影响Windows系统的运行&#xff0c;系统盘约束非常多&#xff0c;不方便在线扩容&#xff0c;因此规划和利用好系统盘是保障整体运行效率的关键。包…

机器人系统开发ros2-基础实践01-学会自定义一个机器人动作aciton实体类

您之前在了解操作教程中了解了action 。与其他通信类型及其各自的接口&#xff08;主题/消息和服务/srv&#xff09;一样&#xff0c;您也可以在包中自定义操作。本教程向您展示如何定义和构建可与您将在下一个教程中编写的action服务器和action 客户端一起使用的操作。 需要理…

Rust 实战练习 - 12. Axum Web 简单demo

Rust Web 历程 Rust 的异步框架tokio非他莫属&#xff0c;而web框架一直是悬而未决&#xff0c;说到底还是因为没有官方成熟的方案指引&#xff0c;大家各玩各的&#xff0c;互不兼容&#xff0c;白白浪费精力。 这个事情一直等到半官方组织tokio推出axum有了改善。但是市场上…

LeetCode455:分发饼干

题目描述 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1b;并且每块饼干 j&#xff0c;都有一个…