Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

codingfarm

5. 리소스 - 액셀러레이터(Accelerator) 본문

Windows/윈도우즈 API

5. 리소스 - 액셀러레이터(Accelerator)

scarecrow1992 2021. 5. 1. 23:08

흔히들 말하는 단축키이지만 윈도우즈에서 단축키(ShortCut)라는 말은 다른 의미로 사용되므로 엄격히 구분지어야 한다.

ShortCut Accelerator
$\bullet$ 메뉴 이름에 &을 넣어 Alt키와 함께 사용하는 키
$\bullet$ 메뉴에 있는 항목을 키보드로 선택하는 방법
$\bullet$ 메뉴와 상관없이 사용 가능

 

 

액셀러레이터 만들기

우선 리소스뷰에서 메뉴 리소스 파일을 더블클릭하여 편집기를 연다.

메뉴만 봐도 한눈에 단축키가 무엇인지 알 수 있도록 이름 옆에 단축키 값을 입력해준다.

그러기위해 각 메뉴 항목들의 캡션을 아래처럼 바꾼다.

이제 실행해보면

Alt + F 키를 누르면 File 메뉴가 열리는것을 볼 수 있다.

아직은 이름만 수정한것이므로 실제 단축키가 작동하진 않는다.

 

엑셀러레이터를 만드려면 별도의 리소스를 작성해야 한다.

리소스 추가 대화상자에서 Accelerator를 선택한다.

새로 추가된 액셀러레이터를 더블클릭하면 편집화면이 나온다.

위와 같은 액셀러레이터 편집기가 열린다.

빈칸을 더블클릭하면 액셀러레이터의 각 속성을 편집할 수 있다

이제 단축키의 입력을 통해 이에 대응되는 메시지를 윈도우에 보낼 수 있다.

 

이제 각 단축키에 대한 메시지에 맞는 효과가 발생하게끔 코드를 작성한다.

액셀러레이터의 ID를 메뉴의 ID와 같도록 해두었으므로 WndProc의 WM_COMMAND는 수정할 필요가 없다. WinMain의 선두에 hAccel 변수를 선언하고 메시지 루프만 다음과 같이 수정한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <windows.h>
#include "resource.h"
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("Menu");
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
    , LPSTR lpszCmdParam, int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
HACCEL hAccel;
 
    g_hInst = hInstance;
 
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = (WNDPROC)WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
    //WndClass.lpszMenuName = TEXT("MyMenu");
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);
 
    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
 
  hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
    while (GetMessage(&Message, NULL00)) {
        if (!TranslateAccelerator(hWnd, hAccel, &Message)) {
            TranslateMessage(&Message);
            DispatchMessage(&Message);
        }
    }
    return Message.wParam;
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    switch (iMessage) {
    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case ID_FILE_MENU1:
            MessageBox(hWnd, TEXT("첫 번째 메뉴를 선택했습니다."), TEXT("Menu Demo"), MB_OK);
            break;
        case ID_FILE_MENU2:
            MessageBox(hWnd, TEXT("두 번째 메뉴를 선택했습니다."), TEXT("Menu Demo"), MB_OK);
            break;
        case ID_FILE_EXIT:
            DestroyWindow(hWnd);
            break;
        }
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
 
cs

메시지 루프도 고정도어있지 않고, 함수도 2개가 새로 추가되었다.

 

HACCEL LoadAccelerators( HINSTANCE hInstance, LPCSTR lpTableName );
  • 리소스로부터 액셀러레이터 테이블의 핸들을 리턴한다.
  • return value를 통해 액셀러레이터 테이블을 읽을 수 있다.

 

int TranslateAccelerator( HWND hWnd, HACCEL hAccTable, LPMSG lpMsg );
  • 키보드 메시지를 WM_COMMAND 메시지로 변경하여 액셀러레이터가 동작할 수 있도록 하는 함수

액셀러레이터 Ctrl+A가 입력되었다고 가정해보자. Ctrl + A는 액셀러레이터이기 이전에 키보드로부터의 입력이므로 먼저 WM_KEYDOWN 메시지가 발생할것이며, 그대로 두면 WndProc의 WM_KEYDOWN 메시지 처리 루틴에서 이 값을 처리하게 된다. 그래서 TranslateAccelerator 함수는 lpMsg의 키보드 입력값을 읽어 이 키 값이 hAccTable에 있는지 먼저 살펴보고 있을 경우 그 키에 해당하는 WM_COMMAND 메시지를 hWnd 윈도우로 전달하고 TRUE를 리턴해 버린다. 그래서 액세러 레이터가 입력되면 TranslateMessage, DispatchMessage 함수가 실행되지 못하게 처리해야한다.

문자나 명령이나 둘 다 키보드를 눌렀을 때의 사건이므로 WM_KEYDOWN에서 시작한다.

다만, TranslateAccelerator의 경우, WM_COMMAND로 변형되면서 WM_KEYDOWN이 사라지지만,

TranslateMessage는 WH_CHAR가 추가발생하며 WM_KEYDOWN은 그대로 남게된다.

 

이제 액셀러레이터가 제대로 작동하는것을 확인할 수 있다.

 

 

요약

  • WM_COMMAND 메시지를 호출시키는 방법은 크게 2가지이다.
    • Menu에서 적당한 항목을 클릭
    • 단축키 입력
  • 엑셀러레이터 편집기를 통해 각 항목에 대응되는 단축키를 설정 가능하다.
  • 단축키를 쓰기 위해선 2가지 과정을 거쳐야 한다.
    1. LoadAccelerators : 엑셀러레이터 테이블 ID값을 통해 리소스의 핸들을 얻는다.
    2. TranslateAccelerator : 입력된 값이 평범한 키보드 입력인지(WM_CHAR) 단축키 입력인지(WM_COMMAND) 판별

 

 

 

 

'Windows > 윈도우즈 API' 카테고리의 다른 글

6. 그래픽 - DC의 정보 수정  (0) 2021.05.04
5. 리소스 - 문자열 테이블(string table)  (0) 2021.05.01
5. 리소스 - 메뉴  (0) 2021.05.01
5. 리소스  (0) 2021.05.01
4. 윈도우 관리 메시지  (0) 2021.04.29
Comments