Использование сочетаний клавиш
В этом разделе рассматриваются задачи, связанные с ускорителями клавиатуры.
- Использование ресурса таблицы ускорителя
- Использование таблицы ускорителей, созданной во время выполнения
Использование ресурса таблицы ускорителя
Наиболее распространенным способом добавления поддержки акселератора в приложение является включение ресурса таблицы ускорителей в исполняемый файл приложения, а затем загрузка ресурса во время выполнения.
В этом разделе рассматриваются следующие темы.
- Создание ресурса таблицы ускорителя
- Загрузка ресурса таблицы ускорителя
- Вызов функции ускорителя перевода
- Обработка сообщений WM_COMMAND
- Уничтожение ресурса таблицы ускорителя
- Создание ускорителей для атрибутов шрифта
Создание ресурса таблицы ускорителя
Ресурс таблицы ускорителей создается с помощью инструкции ACCELERATORS в файле определения ресурсов приложения. Необходимо назначить имя или идентификатор ресурса таблице ускорителя, предпочтительно в отличие от любого другого ресурса. Система использует этот идентификатор для загрузки ресурса во время выполнения.
Для каждого определенного ускорителя требуется отдельная запись в таблице ускорителей. В каждой записи определяется нажатие клавиши (код символа ASCII или код виртуальной клавиши), которое создает ускоритель и идентификатор ускорителя. Необходимо также указать, следует ли использовать сочетание клавиш ALT, SHIFT или CTRL. Дополнительные сведения о виртуальных клавишах см. в разделе Ввод с помощью клавиатуры.
Нажатие клавиши ASCII указывается путем заключения символа ASCII в двойные кавычки или с помощью целочисленного значения символа в сочетании с флагом ASCII. В следующих примерах показано, как определить ускорители ASCII.
"A", ID_ACCEL1 ; SHIFT+A
65, ID_ACCEL2, ASCII ; SHIFT+A
Нажатие клавиш в коде виртуального ключа указывается по-разному в зависимости от того, является ли нажатие клавишой буквенно-цифровой или не буквенно-цифровой клавишей. Для буквенно-цифрового ключа буква или цифра ключа, заключенная в двойные кавычки, объединяется с флагом VIRTKEY . Для ключа, не являющегося буквенно-цифровым, код виртуального ключа для конкретного ключа объединяется с флагом VIRTKEY . В следующих примерах показано, как определить ускорители кода с виртуальным ключом.
"a", ID_ACCEL3, VIRTKEY ; A (caps-lock on) or a
VK_INSERT, ID_ACCEL4, VIRTKEY ; INSERT key
В следующем примере показан ресурс accelerator-table, который определяет ускорители для операций с файлами. Имя ресурса — FileAccel.
FileAccel ACCELERATORS
BEGIN
VK_F12, IDM_OPEN, CONTROL, VIRTKEY ; CTRL+F12
VK_F4, IDM_CLOSE, ALT, VIRTKEY ; ALT+F4
VK_F12, IDM_SAVE, SHIFT, VIRTKEY ; SHIFT+F12
VK_F12, IDM_SAVEAS, VIRTKEY ; F12
END
Если вы хотите, чтобы пользователь нажимал клавиши ALT, SHIFT или CTRL в некотором сочетании с клавишами ускорителя, укажите в определении ускорителя флаги ALT, SHIFT и CONTROL. Ниже приводятся некоторые примеры.
"B", ID_ACCEL5, ALT ; ALT_SHIFT+B
"I", ID_ACCEL6, CONTROL, VIRTKEY ; CTRL+I
VK_F5, ID_ACCEL7, CONTROL, ALT, VIRTKEY ; CTRL+ALT+F5
По умолчанию, когда клавиша ускорителя соответствует элементу меню, система выделяет его. Вы можете использовать флаг NOINVERT , чтобы предотвратить выделение для отдельного ускорителя. В следующем примере показано, как использовать флаг NOINVERT :
VK_DELETE, ID_ACCEL8, VIRTKEY, SHIFT, NOINVERT ; SHIFT+DELETE
Чтобы определить ускорители, соответствующие пунктам меню в приложении, включите ускорители в текст пунктов меню. В следующем примере показано, как включить ускорители в текст пункта меню в файле определения ресурсов.
FilePopup MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&New..", IDM_NEW
MENUITEM "&Open\tCtrl+F12", IDM_OPEN
MENUITEM "&Close\tAlt+F4" IDM_CLOSE
MENUITEM "&Save\tShift+F12", IDM_SAVE
MENUITEM "Save &As...\tF12", IDM_SAVEAS
END
END
Загрузка ресурса таблицы ускорителя
Приложение загружает ресурс accelerator-table, вызывая функцию LoadAccelerators и указывая дескриптор экземпляра для приложения, исполняемый файл которого содержит ресурс и имя или идентификатор ресурса. LoadAccelerators загружает указанную таблицу ускорителей в память и возвращает дескриптор в таблицу ускорителей.
Приложение может загрузить ресурс таблицы ускорителя в любое время. Как правило, однопоточное приложение загружает таблицу ускорителей перед вводом цикла сообщений main. Приложение, использующее несколько потоков, обычно загружает ресурс таблицы ускорителя для потока перед вводом цикла сообщений для потока. Приложение или поток также могут использовать несколько таблиц ускорителей, каждая из которых связана с определенным окном в приложении. Такое приложение будет загружать таблицу ускорителей для окна каждый раз, когда пользователь активирует окно. Дополнительные сведения о потоках см. в разделе Процессы и потоки.
Вызов функции ускорителя перевода
Для обработки ускорителей цикл сообщений приложения (или потока) должен содержать вызов функции TranslateAccelerator . TranslateAccelerator сравнивает нажатия клавиш с таблицей ускорителя и, если находит совпадение, преобразует их в сообщение WM_COMMAND (или WM_SYSCOMMAND). Затем функция отправляет сообщение в процедуру окна. Параметры функции TranslateAccelerator включают дескриптор окна, которое должно получать сообщения WM_COMMAND , дескриптор таблицы ускорителей, используемой для перевода ускорителей, и указатель на структуру MSG , содержащую сообщение из очереди. В следующем примере показано, как вызвать TranslateAccelerator из цикла сообщений.
MSG msg;
BOOL bRet;
while ( (bRet = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
// Check for accelerator keystrokes.
if (!TranslateAccelerator(
hwndMain, // handle to receiving window
haccel, // handle to active accelerator table
&msg)) // message data
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
Обработка сообщений WM_COMMAND
При использовании ускорителя окно, указанное в функции TranslateAccelerator , получает сообщение WM_COMMAND или WM_SYSCOMMAND . Слово нижнего порядка параметра wParam содержит идентификатор ускорителя. Процедура окна проверяет идентификатор, чтобы определить источник сообщения WM_COMMAND и обработать сообщение соответствующим образом.
Как правило, если ускоритель соответствует элементу меню в приложении, ускорителю и элементу меню присваивается один и тот же идентификатор. Если необходимо узнать, было ли сообщение WM_COMMAND создано ускорителем или пунктом меню, можно изучить слово высокого порядка параметра wParam . Если акселератор создал сообщение, слово высокого порядка будет равно 1; Если сообщение создано в пункте меню, слово высокого порядка равно 0.
Уничтожение ресурса таблицы ускорителя
Система автоматически уничтожает ресурсы таблицы ускорителей, загруженные функцией LoadAccelerators , удаляя ресурс из памяти после закрытия приложения.
Создание ускорителей для атрибутов шрифта
В примере в этом разделе показано, как выполнять следующие задачи:
- Создайте ресурс таблицы ускорителей.
- Загрузите таблицу ускорителей во время выполнения.
- Преобразование ускорителей в цикле сообщений.
- Обработка WM_COMMAND сообщений, созданных ускорителями.
Эти задачи демонстрируются в контексте приложения, которое включает меню Символ и соответствующие ускорители, позволяющие пользователю выбирать атрибуты текущего шрифта.
Следующая часть файла определения ресурсов определяет меню Символ и соответствующую таблицу ускорителей. Обратите внимание, что в пунктах меню отображаются сочетания клавиш и каждый ускоритель имеет тот же идентификатор, что и связанный с ним пункт меню.
#include <windows.h>
#include "acc.h"
MainMenu MENU
{
POPUP "&Character"
{
MENUITEM "&Regular\tF5", IDM_REGULAR
MENUITEM "&Bold\tCtrl+B", IDM_BOLD
MENUITEM "&Italic\tCtrl+I", IDM_ITALIC
MENUITEM "&Underline\tCtrl+U", IDM_ULINE
}
}
FontAccel ACCELERATORS
{
VK_F5, IDM_REGULAR, VIRTKEY
"B", IDM_BOLD, CONTROL, VIRTKEY
"I", IDM_ITALIC, CONTROL, VIRTKEY
"U", IDM_ULINE, CONTROL, VIRTKEY
}
В следующих разделах исходного файла приложения показано, как реализовать ускорители.
HWND hwndMain; // handle to main window
HANDLE hinstAcc; // handle to application instance
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg; // application messages
BOOL bRet; // for return value of GetMessage
HACCEL haccel; // handle to accelerator table
// Perform the initialization procedure.
// Create a main window for this application instance.
hwndMain = CreateWindowEx(0L, "MainWindowClass",
"Sample Application", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
hinst, NULL );
// If a window cannot be created, return "failure."
if (!hwndMain)
return FALSE;
// Make the window visible and update its client area.
ShowWindow(hwndMain, nCmdShow);
UpdateWindow(hwndMain);
// Load the accelerator table.
haccel = LoadAccelerators(hinstAcc, "FontAccel");
if (haccel == NULL)
HandleAccelErr(ERR_LOADING); // application defined
// Get and dispatch messages until a WM_QUIT message is
// received.
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
// Check for accelerator keystrokes.
if (!TranslateAccelerator(
hwndMain, // handle to receiving window
haccel, // handle to active accelerator table
&msg)) // message data
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
return msg.wParam;
}
LRESULT APIENTRY MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BYTE fbFontAttrib; // array of font-attribute flags
static HMENU hmenu; // handle to main menu
switch (uMsg)
{
case WM_CREATE:
// Add a check mark to the Regular menu item to
// indicate that it is the default.
hmenu = GetMenu(hwndMain);
CheckMenuItem(hmenu, IDM_REGULAR, MF_BYCOMMAND |
MF_CHECKED);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
// Process the accelerator and menu commands.
case IDM_REGULAR:
case IDM_BOLD:
case IDM_ITALIC:
case IDM_ULINE:
// GetFontAttributes is an application-defined
// function that sets the menu-item check marks
// and returns the user-selected font attributes.
fbFontAttrib = GetFontAttributes(
(BYTE) LOWORD(wParam), hmenu);
// SetFontAttributes is an application-defined
// function that creates a font with the
// user-specified attributes the font with
// the main window's device context.
SetFontAttributes(fbFontAttrib);
break;
default:
break;
}
break;
// Process other messages.
default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}
Использование таблицы ускорителей, созданной во время выполнения
В этом разделе рассматривается использование таблиц ускорителей, созданных во время выполнения.
- Создание таблицы ускорителей Run-Time
- Ускорители обработки
- Уничтожение таблицы ускорителей Run-Time
- Создание редактируемых пользователем ускорителей
Создание таблицы ускорителей Run-Time
Первым шагом при создании таблицы ускорителей во время выполнения является заполнение массива структур ACCEL . Каждая структура в массиве определяет ускоритель в таблице. Определение ускорителя включает его флаги, ключ и идентификатор. Структура ACCEL имеет следующую форму.
typedef struct tagACCEL { // accl
BYTE fVirt;
WORD key;
WORD cmd;
} ACCEL;
Нажатие клавиши ускорителя определяется путем указания кода символа ASCII или кода виртуальной клавиши в элементе ключа структуры ACCEL . Если вы указываете код виртуального ключа, необходимо сначала включить флаг FVIRTKEY в элемент fVirt ; В противном случае система интерпретирует код как код символа ASCII. Вы можете включить флаг FCONTROL, FALT или FSHIFT или все три, чтобы объединить клавиши CTRL, ALT или SHIFT с нажатием клавиш.
Чтобы создать таблицу ускорителя, передайте указатель на массив структур ACCEL в функцию CreateAcceleratorTable . CreateAcceleratorTable создает таблицу ускорителя и возвращает дескриптор в таблицу.
Ускорители обработки
Процесс загрузки и вызова ускорителей, предоставляемых таблицей ускорителей, созданной во время выполнения, совпадает с процессом обработки тех, которые предоставляются ресурсом таблицы ускорителей. Дополнительные сведения см. в разделе Загрузка ресурса таблицы ускорителя с помощью обработки сообщений WM_COMMAND.
Уничтожение таблицы ускорителей Run-Time
Система автоматически уничтожает таблицы ускорителей, созданные во время выполнения, удаляя ресурсы из памяти после закрытия приложения. Вы можете уничтожить таблицу ускорителя и удалить ее из памяти ранее, передав дескриптор таблицы в функцию DestroyAcceleratorTable .
Создание редактируемых пользователем ускорителей
В этом примере показано, как создать диалоговое окно, позволяющее пользователю изменять ускоритель, связанный с элементом меню. Диалоговое окно состоит из поля со списком, содержащего пункты меню, поля со списком с именами клавиш и проверка полей для выбора клавиш CTRL, ALT и SHIFT. На следующем рисунке показано диалоговое окно.
В следующем примере показано, как определяется диалоговое окно в файле определения ресурсов.
EdAccelBox DIALOG 5, 17, 193, 114
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "Edit Accelerators"
BEGIN
COMBOBOX IDD_MENUITEMS, 10, 22, 52, 53,
CBS_SIMPLE | CBS_SORT | WS_VSCROLL |
WS_TABSTOP
CONTROL "Control", IDD_CNTRL, "Button",
BS_AUTOCHECKBOX | WS_TABSTOP,
76, 35, 40, 10
CONTROL "Alt", IDD_ALT, "Button",
BS_AUTOCHECKBOX | WS_TABSTOP,
76, 48, 40, 10
CONTROL "Shift", IDD_SHIFT, "Button",
BS_AUTOCHECKBOX | WS_TABSTOP,
76, 61, 40, 10
COMBOBOX IDD_KEYSTROKES, 124, 22, 58, 58,
CBS_SIMPLE | CBS_SORT | WS_VSCROLL |
WS_TABSTOP
PUSHBUTTON "Ok", IDOK, 43, 92, 40, 14
PUSHBUTTON "Cancel", IDCANCEL, 103, 92, 40, 14
LTEXT "Select Item:", 101, 10, 12, 43, 8
LTEXT "Select Keystroke:", 102, 123, 12, 60, 8
END
Строка меню приложения содержит подменю Character , с элементами которого связаны ускорители.
MainMenu MENU
{
POPUP "&Character"
{
MENUITEM "&Regular\tF5", IDM_REGULAR
MENUITEM "&Bold\tCtrl+B", IDM_BOLD
MENUITEM "&Italic\tCtrl+I", IDM_ITALIC
MENUITEM "&Underline\tCtrl+U", IDM_ULINE
}
}
FontAccel ACCELERATORS
{
VK_F5, IDM_REGULAR, VIRTKEY
"B", IDM_BOLD, CONTROL, VIRTKEY
"I", IDM_ITALIC, CONTROL, VIRTKEY
"U", IDM_ULINE, CONTROL, VIRTKEY
}
Значения элементов меню для шаблона меню определяются следующим образом в файле заголовка приложения.
#define IDM_REGULAR 1100
#define IDM_BOLD 1200
#define IDM_ITALIC 1300
#define IDM_ULINE 1400
В диалоговом окне используется массив структур VKEY, определяемых приложением, каждая из которых содержит строку нажатия клавиши и строку текста ускорителя. При создании диалогового окна выполняется анализ массива и каждая строка нажатия клавиш добавляется в поле со списком Выбор нажатия клавиш . Когда пользователь нажимает кнопку ОК , диалоговое окно ищет выбранную строку нажатия клавиш и извлекает соответствующую строку текста ускорителя. Диалоговое окно добавляет строку акселератора текста к тексту выбранного пользователем пункта меню. В следующем примере показан массив структур VKEY:
// VKey Lookup Support
#define MAXKEYS 25
typedef struct _VKEYS {
char *pKeyName;
char *pKeyString;
} VKEYS;
VKEYS vkeys[MAXKEYS] = {
"BkSp", "Back Space",
"PgUp", "Page Up",
"PgDn", "Page Down",
"End", "End",
"Home", "Home",
"Lft", "Left",
"Up", "Up",
"Rgt", "Right",
"Dn", "Down",
"Ins", "Insert",
"Del", "Delete",
"Mult", "Multiply",
"Add", "Add",
"Sub", "Subtract",
"DecPt", "Decimal Point",
"Div", "Divide",
"F2", "F2",
"F3", "F3",
"F5", "F5",
"F6", "F6",
"F7", "F7",
"F8", "F8",
"F9", "F9",
"F11", "F11",
"F12", "F12"
};
Процедура инициализации диалогового окна заполняет поля со списком Выбор элемента и Выбор нажатия клавиш . После того как пользователь выберет пункт меню и связанный с ним ускоритель, диалоговое окно проверяет элементы управления в диалоговом окне, чтобы получить выбор пользователя, обновляет текст пункта меню, а затем создает новую таблицу ускорителей, содержащую определяемый пользователем новый ускоритель. В следующем примере показана процедура диалогового окна. Обратите внимание, что необходимо инициализировать в процедуре окна.
// Global variables
HWND hwndMain; // handle to main window
HACCEL haccel; // handle to accelerator table
// Dialog-box procedure
BOOL CALLBACK EdAccelProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int nCurSel; // index of list box item
UINT idItem; // menu-item identifier
UINT uItemPos; // menu-item position
UINT i, j = 0; // loop counters
static UINT cItems; // count of items in menu
char szTemp[32]; // temporary buffer
char szAccelText[32]; // buffer for accelerator text
char szKeyStroke[16]; // buffer for keystroke text
static char szItem[32]; // buffer for menu-item text
HWND hwndCtl; // handle to control window
static HMENU hmenu; // handle to "Character" menu
PCHAR pch, pch2; // pointers for string copying
WORD wVKCode; // accelerator virtual-key code
BYTE fAccelFlags; // fVirt flags for ACCEL structure
LPACCEL lpaccelNew; // pointer to new accelerator table
HACCEL haccelOld; // handle to old accelerator table
int cAccelerators; // number of accelerators in table
static BOOL fItemSelected = FALSE; // item selection flag
static BOOL fKeySelected = FALSE; // key selection flag
HRESULT hr;
INT numTCHAR; // TCHARs in listbox text
switch (uMsg)
{
case WM_INITDIALOG:
// Get the handle to the menu-item combo box.
hwndCtl = GetDlgItem(hwndDlg, IDD_MENUITEMS);
// Get the handle to the Character submenu and
// count the number of items it has. In this example,
// the menu has position 0. You must alter this value
// if you add additional menus.
hmenu = GetSubMenu(GetMenu(hwndMain), 0);
cItems = GetMenuItemCount(hmenu);
// Get the text of each item, strip out the '&' and
// the accelerator text, and add the text to the
// menu-item combo box.
for (i = 0; i < cItems; i++)
{
if (!(GetMenuString(hmenu, i, szTemp,
sizeof(szTemp)/sizeof(TCHAR), MF_BYPOSITION)))
continue;
for (pch = szTemp, pch2 = szItem; *pch != '\0'; )
{
if (*pch != '&')
{
if (*pch == '\t')
{
*pch = '\0';
*pch2 = '\0';
}
else *pch2++ = *pch++;
}
else pch++;
}
SendMessage(hwndCtl, CB_ADDSTRING, 0,
(LONG) (LPSTR) szItem);
}
// Now fill the keystroke combo box with the list of
// keystrokes that will be allowed for accelerators.
// The list of keystrokes is in the application-defined
// structure called "vkeys".
hwndCtl = GetDlgItem(hwndDlg, IDD_KEYSTROKES);
for (i = 0; i < MAXKEYS; i++)
{
SendMessage(hwndCtl, CB_ADDSTRING, 0,
(LONG) (LPSTR) vkeys[i].pKeyString);
}
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDD_MENUITEMS:
// The user must select an item from the combo
// box. This flag is checked during IDOK
// processing to be sure a selection was made.
fItemSelected = TRUE;
return 0;
case IDD_KEYSTROKES:
// The user must select an item from the combo
// box. This flag is checked during IDOK
// processing to be sure a selection was made.
fKeySelected = TRUE;
return 0;
case IDOK:
// If the user has not selected a menu item
// and a keystroke, display a reminder in a
// message box.
if (!fItemSelected || !fKeySelected)
{
MessageBox(hwndDlg,
"Item or key not selected.", NULL,
MB_OK);
return 0;
}
// Determine whether the CTRL, ALT, and SHIFT
// keys are selected. Concatenate the
// appropriate strings to the accelerator-
// text buffer, and set the appropriate
// accelerator flags.
szAccelText[0] = '\0';
hwndCtl = GetDlgItem(hwndDlg, IDD_CNTRL);
if (SendMessage(hwndCtl, BM_GETCHECK, 0, 0) == 1)
{
hr = StringCchCat(szAccelText, 32, "Ctl+");
if (FAILED(hr))
{
// TODO: write error handler
}
fAccelFlags |= FCONTROL;
}
hwndCtl = GetDlgItem(hwndDlg, IDD_ALT);
if (SendMessage(hwndCtl, BM_GETCHECK, 0, 0) == 1)
{
hr = StringCchCat(szAccelText, 32, "Alt+");
if (FAILED(hr))
{
// TODO: write error handler
}
fAccelFlags |= FALT;
}
hwndCtl = GetDlgItem(hwndDlg, IDD_SHIFT);
if (SendMessage(hwndCtl, BM_GETCHECK, 0, 0) == 1)
{
hr = StringCchCat(szAccelText, 32, "Shft+");
if (FAILED(hr))
{
// TODO: write error handler
}
fAccelFlags |= FSHIFT;
}
// Get the selected keystroke, and look up the
// accelerator text and the virtual-key code
// for the keystroke in the vkeys structure.
hwndCtl = GetDlgItem(hwndDlg, IDD_KEYSTROKES);
nCurSel = (int) SendMessage(hwndCtl,
CB_GETCURSEL, 0, 0);
numTCHAR = SendMessage(hwndCtl, CB_GETLBTEXTLEN,
nCursel, 0);
if (numTCHAR <= 15)
{
SendMessage(hwndCtl, CB_GETLBTEXT,
nCurSel, (LONG) (LPSTR) szKeyStroke);
}
else
{
// TODO: writer error handler
}
for (i = 0; i < MAXKEYS; i++)
{
//
// lstrcmp requires that both parameters are
// null-terminated.
//
if(lstrcmp(vkeys[i].pKeyString, szKeyStroke)
== 0)
{
hr = StringCchCopy(szKeyStroke, 16, vkeys[i].pKeyName);
if (FAILED(hr))
{
// TODO: write error handler
}
break;
}
}
// Concatenate the keystroke text to the
// "Ctl+","Alt+", or "Shft+" string.
hr = StringCchCat(szAccelText, 32, szKeyStroke);
if (FAILED(hr))
{
// TODO: write error handler
}
// Determine the position in the menu of the
// selected menu item. Menu items in the
// "Character" menu have positions 0,2,3, and 4.
// Note: the lstrcmp parameters must be
// null-terminated.
if (lstrcmp(szItem, "Regular") == 0)
uItemPos = 0;
else if (lstrcmp(szItem, "Bold") == 0)
uItemPos = 2;
else if (lstrcmp(szItem, "Italic") == 0)
uItemPos = 3;
else if (lstrcmp(szItem, "Underline") == 0)
uItemPos = 4;
// Get the string that corresponds to the
// selected item.
GetMenuString(hmenu, uItemPos, szItem,
sizeof(szItem)/sizeof(TCHAR), MF_BYPOSITION);
// Append the new accelerator text to the
// menu-item text.
for (pch = szItem; *pch != '\t'; pch++);
++pch;
for (pch2 = szAccelText; *pch2 != '\0'; pch2++)
*pch++ = *pch2;
*pch = '\0';
// Modify the menu item to reflect the new
// accelerator text.
idItem = GetMenuItemID(hmenu, uItemPos);
ModifyMenu(hmenu, idItem, MF_BYCOMMAND |
MF_STRING, idItem, szItem);
// Reset the selection flags.
fItemSelected = FALSE;
fKeySelected = FALSE;
// Save the current accelerator table.
haccelOld = haccel;
// Count the number of entries in the current
// table, allocate a buffer for the table, and
// then copy the table into the buffer.
cAccelerators = CopyAcceleratorTable(
haccelOld, NULL, 0);
lpaccelNew = (LPACCEL) LocalAlloc(LPTR,
cAccelerators * sizeof(ACCEL));
if (lpaccelNew != NULL)
{
CopyAcceleratorTable(haccel, lpaccelNew,
cAccelerators);
}
// Find the accelerator that the user modified
// and change its flags and virtual-key code
// as appropriate.
for (i = 0; i < (UINT) cAccelerators; i++)
{
if (lpaccelNew[i].cmd == (WORD) idItem)
{
lpaccelNew[i].fVirt = fAccelFlags;
lpaccelNew[i].key = wVKCode;
}
}
// Create the new accelerator table, and
// destroy the old one.
DestroyAcceleratorTable(haccelOld);
haccel = CreateAcceleratorTable(lpaccelNew,
cAccelerators);
// Destroy the dialog box.
EndDialog(hwndDlg, TRUE);
return 0;
case IDCANCEL:
EndDialog(hwndDlg, TRUE);
return TRUE;
default:
break;
}
default:
break;
}
return FALSE;
}