加速器表

应用程序通常定义键盘快捷方式,例如“文件打开”命令的 Ctrl+O。 可以通过处理单个 WM_KEYDOWN 消息来实现键盘快捷方式,但快捷键表提供了更好的解决方案,

  • 需要更少的编码。
  • 将所有快捷方式合并到一个数据文件中。
  • 支持将本地化为其他语言。
  • 启用快捷方式和菜单命令以使用相同的应用程序逻辑。

快捷键表 是一种数据资源,可将键盘组合(如 Ctrl+O)映射到应用程序命令。 在了解如何使用加速器表之前,需要快速介绍资源。 资源 是内置于应用程序二进制文件(EXE 或 DLL)中的数据 blob。 资源存储应用程序所需的数据,例如菜单、光标、图标、图像、文本字符串或任何自定义应用程序数据。 应用程序在运行时从二进制文件加载资源数据。 若要在二进制文件中包括资源,请执行以下作:

  1. 创建资源定义 (.rc) 文件。 此文件定义资源的类型及其标识符。 资源定义文件可能包括对其他文件的引用。 例如,图标资源在 .rc 文件中声明,但图标图像存储在单独的文件中。
  2. 使用 Microsoft Windows 资源编译器(RC)将资源定义文件编译为已编译的资源(.res)文件。 RC 编译器随 Visual Studio 和 Windows SDK 一起提供。
  3. 将编译的资源文件链接到二进制文件。

这些步骤大致相当于代码文件的编译/链接过程。 Visual Studio 提供了一组资源编辑器,便于创建和修改资源。 (这些工具在 Visual Studio 的 Express 版本中不可用。但 .rc 文件只是一个文本文件,语法记录在 MSDN 上,因此可以使用任何文本编辑器创建 .rc 文件。 有关详细信息,请参阅 关于资源文件

定义加速器表

快捷键表是键盘快捷方式表。 每个快捷方式都由以下各项定义:

  • 数字标识符。 此数字标识将由快捷方式调用的应用程序命令。
  • 快捷方式的 ASCII 字符或虚拟键代码。
  • 可选修饰键:Alt、SHIFT 或 Ctrl。

快捷键表本身具有数字标识符,用于标识应用程序资源列表中的表。 让我们为简单的绘图程序创建快捷键表。 此程序将具有两种模式:绘图模式和选择模式。 在绘图模式下,用户可以绘制形状。 在选择模式下,用户可以选择形状。 对于此程序,我们希望定义以下键盘快捷方式。

捷径 命令
Ctrl+M 在模式之间切换。
F1 切换到绘图模式。
F2 切换到选择模式。

 

首先,为表和应用程序命令定义数字标识符。 这些值是任意的。 可以通过在头文件中定义标识符来为标识符分配符号常量。 例如:

#define IDR_ACCEL1                      101
#define ID_TOGGLE_MODE                40002
#define ID_DRAW_MODE                  40003
#define ID_SELECT_MODE                40004

在此示例中,值 IDR_ACCEL1 标识加速器表,接下来的三个常量定义应用程序命令。 按照约定,定义资源常量的头文件通常命名为 resource.h。 下一个列表显示资源定义文件。

#include "resource.h"

IDR_ACCEL1 ACCELERATORS
{
    0x4D,   ID_TOGGLE_MODE, VIRTKEY, CONTROL    // ctrl-M
    0x70,   ID_DRAW_MODE, VIRTKEY               // F1
    0x71,   ID_SELECT_MODE, VIRTKEY             // F2
}

快捷键在大括号内定义。 每个快捷方式包含以下条目。

  • 调用快捷方式的虚拟键代码或 ASCII 字符。
  • 应用程序命令。 请注意,示例中使用了符号常量。 资源定义文件包括 resource.h,其中定义了这些常量。
  • 关键字 VIRTKEY 意味着第一个条目是虚拟键代码。 另一个选项是使用 ASCII 字符。
  • 可选修饰符:ALT、CONTROL 或 SHIFT。

如果将 ASCII 字符用于快捷方式,则小写字符将不同于大写字符。 (例如,键入“a”可能会调用与键入“A”不同的命令。这可能会使用户感到困惑,因此通常最好对快捷方式使用虚拟密钥代码,而不是 ASCII 字符。

加载加速器表

必须先加载加速器表的资源,然后程序才能使用它。 若要加载加速器表,请调用 LoadAccelerators 函数。

    HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCEL1));

在输入消息循环之前调用此函数。 第一个参数是模块的句柄。 (此参数传递给 WinMain 函数。有关详细信息,请参阅 WinMain:应用程序入口点。)第二个参数是资源标识符。 该函数将返回资源的句柄。 回想一下,句柄是一种不透明类型,引用由系统管理的对象。 如果函数失败,它将返回 NULL

可以通过调用 DestroyAcceleratorTable来释放加速器表。 但是,当程序退出时,系统会自动释放表,因此,如果将一个表替换为另一个表,则只需调用此函数。 本主题 创建用户可编辑加速器有一个有趣的示例。

将键笔划转换为命令

快捷键表的工作原理是将键笔划转换为 WM_COMMAND 消息。 WM_COMMANDwParam 参数包含命令的数字标识符。 例如,使用前面所示的表,键笔划 Ctrl+M 将转换为具有值 ID_TOGGLE_MODEWM_COMMAND 消息。 若要执行此作,请将消息循环更改为以下内容:

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(win.Window(), hAccel, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

此代码在消息循环中添加对 TranslateAccelerator 函数的调用。 TranslateAccelerator 函数检查每个窗口消息,查找向下键消息。 如果用户按下快捷键表中列出的一个组合键,TranslateAccelerator 向窗口发送 WM_COMMAND 消息。 该函数通过直接调用窗口过程发送 WM_COMMANDTranslateAccelerator 成功转换键笔划时,函数将返回非零值,这意味着应跳过消息的正常处理。 否则,TranslateAccelerator 返回零。 在这种情况下,请将窗口消息传递到 TranslateMessage,并 DispatchMessage正常。

下面是绘图程序如何处理 WM_COMMAND 消息:

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case ID_DRAW_MODE:
            SetMode(DrawMode);
            break;

        case ID_SELECT_MODE:
            SetMode(SelectMode);
            break;

        case ID_TOGGLE_MODE:
            if (mode == DrawMode)
            {
                SetMode(SelectMode);
            }
            else
            {
                SetMode(DrawMode);
            }
            break;
        }
        return 0;

此代码假定 SetMode 是由应用程序定义的函数,用于在两种模式之间切换。 如何处理每个命令的详细信息显然取决于程序。

下一个

设置光标图像