zoukankan      html  css  js  c++  java
  • Win32 SDK 创建加速键表。

     
    加速键与菜单密切相关——都向用户提供一个应用程序的命令集的操作。通常情况下,用户依靠菜单来了解命令集合,在熟悉了应用程序后转而使用加速键。加速键提供比菜单更快、更直接的命令操作。虽然加速键通常产生菜单中存在的命令,但也可以产生菜单中不存在的命令。

    加速键表

    加速键表由一个ACCEL结构数组构成。每个结构定义一个独立的加速键,由以下信息组成:

    1. 击键组合

    2. 标识符

    3. 一些标记。

    要处理加速键,开发人员必须在线程消息队列相关的消息循环中调用TranslateAccelerator函数。此函数监控消息队列中的键盘输入,检查与加速键表中条目匹配的击键组合。若匹配,则将键盘输入(WM_KEYUP和WM_KEYDOWN消息)转换为WM_COMMAND或WM_SYSCOMMAND消息并发送给指定窗口的窗口过程。

    WM_COMMAND消息包含加速键的标识符。窗口过程检查此标识符以确定消息源然后进行相应地消息处理。

    加速键表存在两种不同的等级:系统级(单一的、系统范围的应用于所有程序)和应用程序级。系统加速键表不允许修改。

    应用程序可定义多个加速键表。每个表用一个32位句柄标识。不过,对一个特定线程,任一时刻只会有一个加速键表处于活动状态。在一个加速键表句柄被传递给TranslateAccelerator函数后,对应的加速键表即进入活动状态。

    加速键表的创建

    创建加速表分为几个步骤:

    首先,用资源编译器创建加速键表资源并加入应用程序的可执行文件。

    然后,在运行时使用LoadAccelerators将加速键表加载到内存并获取其句柄。

    也可以通过向CreateAcceleratorTable传递一个ACCEL结构的数组来创建一个加速键表,此方法可用于用户自定义加速键。

    系统会自动销毁由LoadAccelerators加载的加速键表。但CreateAcceleratorTable创建的加速键表必须由应用程序销毁,否则,在应用程序关闭后还将一直存在在内存中。

    加速键表可被复制和更改。

    加速键击键分配

    ASCII字符编码和虚拟键码可用于定义加速键。使用ASCII字符编码定义的加速键是区分大小写的。因此,通常使用虚拟键码。

    应避免加速键与菜单助词符冲突,因为加速键会覆盖助记符,那样将使用户混淆。

    若在应用程序中定义了与系统加速键表中已存在的加速键,则应用程序的加速键将覆盖系统加速键,不过仅在应用程序的上下文中。由于会使系统加速键出现不正常的表现,因此应避免这种情况。

    系统加速键包括:

    ALT+ESC Switches to the next application.

    ALT+F4 Closes an application or a window.

    ALT+HYPHEN Opens the Window menu for a document window.

    ALT+PRINT SCREEN Copies an image in the active window onto the clipboard.

    ALT+SPACEBAR Opens the Window menu for the application's main window.

    ALT+TAB Switches to the next application.

    CTRL+ESC Switches to the Start menu.

    CTRL+F4 Closes the active group or document window.

    F1 Starts the application's help file, if one exists.

    PRINT SCREEN Copies an image on the screen onto the clipboard.

    SHIFT+ALT+TAB Switches to the previous application. The user must press and hold down ALT+SHIFT while pressing TAB.

    加速键与菜单

    使用加速键就像选择菜单项一样:都导致系统向相应的窗口过程发送一个WM_COMMAND或WM_SYSCOMMAND消息。由于加速键提供种从菜单中选择命令的快捷方式,应用程序通常为加速键和相应的菜单项使用相同的标识符。

    应用程序处理加速键WM_COMMAND消息与处理菜单项WM_COMMAND消息完全一样。不过,为了支持可能存在的差异处理,WM_COMMAND也包含了一个确定消息来源的标记。WM_SYSCOMMAND不包含此标记。

    标识符决定了加速键将产生WM_COMMAND还是WM_SYSCOMMAND消息。如果标识符与系统菜单中菜单项相同,则产生WM_SYSCOMMAND,否则产生WM_COMMAND消息。

    如果加速键与某菜单项的标识符相同并且此菜单项被禁用,则此加速键也被禁用,将不产生WM_COMMAND或WM_SYSCOMMAND消息。如果对应的窗口被最小化了,加速键同样不会产生命令消息。

    热键

    热键通过RegisterHotKey注册。

    按下键时,Windows查找所有已注册热键,存在匹配项时,向注册热键的线程的消息队列发送WM_HOTKEY消息。WM_HOTKEY将被放置在队列的前端。

    热键的击键组合不能重复注册。

    加速键与热键

    均用于将键盘事件转换成其它消息,但使用场合不同。

    加速键在应用程序上下文中有效,不同应用程序可定义多套加速键表。

    热键在系统范围内有效,但关联到特定线程上的特定窗体。

     
     
     
    添加加速键有几种办法,最直接的就是在资源文件中添加,然后使用 LoadAccelerators 加载。
    这篇文字说明了如何在运行时创建加速键表。


    // accelerator.h

    #include <windows.h>
    #include <windowsx.h>
    #include <tchar.h>

    #define ID_PRIN 25


    // accelerator.cpp

    #include "accelerator.h"

    BOOL OnCreate(HWND, LPCREATESTRUCT lpCreateStruct)
    {
         ACCEL accel[] =
         {
              { FSHIFT | FVIRTKEY, 'N', SC_MINIMIZE }, // 最小化窗口Shift+ N
              { FSHIFT | FVIRTKEY, 'X', SC_MAXIMIZE }, // 最大化窗口 Shift + X
              { FSHIFT | FVIRTKEY, 'R', SC_RESTORE }, // 还原窗口 Shift + R
              { FALT | FCONTROL | FVIRTKEY, 'P', ID_PRIN }, // 输出文字 Ctrl + Alt + P
              { FCONTROL | FVIRTKEY, VK_F4, SC_CLOSE }, // 退出 Ctrl + F4
         };

         // 创建加速键表
         *(HACCEL*)lpCreateStruct->lpCreateParams = CreateAcceleratorTable(accel, 5);

         return TRUE;
    }

    VOID OnCommand(HWND hwnd, INT id, HWND, UINT)
    {
         HDC hDC;
         RECT rc;
         TCHAR szTime[32];
         SYSTEMTIME systime;

         switch (id)
         {
              // 输出文字
              case ID_PRIN:
                   GetClientRect(hwnd, &rc);
                   GetLocalTime(&systime);
                   wsprintf(szTime, _T("%04d.%02d.%02d %02d:%02d:%02d"),
                   systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond);
                   DrawText(hDC = GetDC(hwnd), szTime, -1, &rc, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
                   ReleaseDC(hwnd, hDC);
                   break;
         }
    }

    VOID OnDestroy(HWND) { PostQuitMessage(0); }

    LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
         switch (uMsg)
         {
              HANDLE_MSG(hwnd, WM_CREATE, OnCreate);
              HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
              HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy);

              default: return DefWindowProc(hwnd, uMsg, wParam, lParam);
         }

         return 0;
    }

    VOID AcceleratorMain()
    {
         WNDCLASS wnd = { 0 };
         MSG msg;
         HACCEL hAccel;

         wnd.lpfnWndProc        = WndProc;
         wnd.hInstance        = GetModuleHandle(NULL);
         wnd.hCursor            = LoadCursor(NULL, IDC_ARROW);
         wnd.hbrBackground    = (HBRUSH)COLOR_WINDOWFRAME;
         wnd.lpszClassName    = _T("Accelerator");

         RegisterClass(&wnd);

         if (!CreateWindow((TCHAR*)_T("Accelerator"), _T("Accelerator"),
              WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
              NULL, NULL, wnd.hInstance, &hAccel)) ExitProcess(0);

         while (GetMessage(&msg, NULL, 0, 0))
         {
              // 变换加速键消息
              if (!TranslateAccelerator(msg.hwnd, hAccel, &msg))
              {
                   TranslateMessage(&msg);
                   DispatchMessage(&msg);
              }
         }

    //    DestroyAcceleratorTable(hAccel);

         ExitProcess(msg.wParam);
    }
  • 相关阅读:
    angular的路由例子
    angular自定义module
    docker配置phpadmin需要注意的地方
    linux下钉钉,微信
    debian shell脚本关联
    debian下安装带界面的qemu
    ros的一些设置
    新闻排重方案设计
    细解动态规划(一)
    漫画谈-微积分(二)
  • 原文地址:https://www.cnblogs.com/zhiweiyouzhishenghuo/p/5005548.html
Copyright © 2011-2022 走看看