キーボード アクセラレータの使用
このセクションでは、キーボード アクセラレータに関連付けられているタスクについて説明します。
アクセラレータ テーブル リソースの使用
アプリケーションにアクセラレータのサポートを追加する最も一般的な方法は、アプリケーションの実行可能ファイルにアクセラレータ テーブル リソースを含め、実行時にリソースを読み込む方法です。
このセクションでは、次のトピックについて説明します。
- アクセラレータ テーブル リソースの作成
- アクセラレータ テーブル リソースの読み込み
- 変換アクセラレータ関数の呼び出し
- 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
次の例は、ファイル操作のアクセラレータを定義するアクセラレータ テーブル リソースを示しています。 リソースの名前は 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
アクセラレータ テーブル リソースの読み込み
アプリケーションは、 LoadAccelerators 関数を呼び出し、実行可能ファイルにリソースとリソースの名前または識別子が含まれているアプリケーションへのインスタンス ハンドルを指定することで、アクセラレータ テーブル リソースを読み込みます。 LoadAccelerators は、 指定されたアクセラレータ テーブルをメモリに読み込み、ハンドルをアクセラレータ テーブルに返します。
アプリケーションは、アクセラレータ テーブル リソースをいつでも読み込むことができます。 通常、シングルスレッド アプリケーションは、メイン メッセージ ループに入る前にアクセラレータ テーブルを読み込みます。 通常、複数のスレッドを使用するアプリケーションは、スレッドのメッセージ ループに入る前に、スレッドのアクセラレータ テーブル リソースを読み込みます。 アプリケーションまたはスレッドでは、複数のアクセラレータ テーブルを使用する場合もあります。各テーブルは、アプリケーション内の特定のウィンドウに関連付けられています。 このようなアプリケーションは、ユーザーがウィンドウをアクティブ化するたびに、ウィンドウのアクセラレータ テーブルを読み込みます。 スレッドの詳細については、「 プロセスとスレッド」を参照してください。
変換アクセラレータ関数の呼び出し
アクセラレータを処理するには、アプリケーション (またはスレッド) のメッセージ ループに 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 アクセラレータ テーブルの作成
実行時にアクセラレータ テーブルを作成する最初の手順は、 ACCEL 構造体の配列を入力することです。 配列内の各構造体は、テーブルにアクセラレータを定義します。 アクセラレータの定義には、そのフラグ、キー、および識別子が含まれます。 ACCEL 構造体の形式は次のとおりです。
typedef struct tagACCEL { // accl
BYTE fVirt;
WORD key;
WORD cmd;
} ACCEL;
アクセラレータのキーストロークを定義するには、ACCEL 構造体のキー メンバーに ASCII 文字コードまたは仮想キー コードを指定します。 仮想キー コードを指定する場合は、まず fVirt メンバーに FVIRTKEY フラグを含める必要があります。それ以外の場合、システムはコードを ASCII 文字コードとして解釈します。 FCONTROL、FALT、または FSHIFT フラグ、または 3 つすべてを含め、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 構造体の配列が使用され、それぞれにキーストローク テキスト文字列とアクセラレータ テキスト文字列が含まれています。 ダイアログ ボックスが作成されると、配列が解析され、各キーストローク テキスト文字列が [キーストロークの選択 ] コンボ ボックスに追加されます。 ユーザーが [OK ] ボタンをクリックすると、選択したキーストローク テキスト文字列がダイアログ ボックスで検索され、対応するアクセラレータ テキスト文字列が取得されます。 ダイアログ ボックスは、ユーザーが選択したメニュー項目のテキストにアクセラレータ テキスト文字列を追加します。 次の例は、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;
}