Toetsenbordversnellers gebruiken
In deze sectie worden taken behandeld die zijn gekoppeld aan toetsenbordversnellers.
- Een Resource voor een Acceleratortabel Gebruiken
- Een acceleratortabel gebruiken die tijdens runtime is gemaakt
Een acceleratortabelresource gebruiken
De meest voorkomende manier om acceleratorondersteuning toe te voegen aan een toepassing is door een accelerator-tabelresource op te nemen met het uitvoerbare bestand van de toepassing en vervolgens de resource tijdens runtime te laden.
In deze sectie worden de volgende onderwerpen behandeld.
- De bron voor de acceleratortabel creëren
- de resource van de acceleratortabel laden
- de functie Translate Accelerator aanroepen
- Het verwerken van WM_COMMAND-berichten
- De Acceleratortabel-resources vernietigen
- Accelerators maken voor lettertypekenmerken
Het maken van de resource voor de acceleratortabel
U maakt een accelerator-tabelresource met behulp van de ACCELERATORS-instructie in het resourcedefinitiebestand van uw toepassing. U moet een naam of resource-id toewijzen aan de acceleratortabel, bij voorkeur in tegenstelling tot die van een andere resource. Het systeem gebruikt deze id om de resource tijdens runtime te laden.
Elke accelerator die u definieert, vereist een afzonderlijke vermelding in de acceleratortabel. In elke vermelding definieert u de toetsaanslag (een ASCII-tekencode of virtuele-sleutelcode) waarmee de accelerator en de id van de accelerator worden gegenereerd. U moet ook opgeven of de toetsaanslag moet worden gebruikt in een combinatie met alt-, Shift- of Ctrl-toetsen. Zie Toetsenbordinvoervoor meer informatie over virtuele toetsen.
Een ASCII-toetsaanslag wordt opgegeven door het ASCII-teken tussen dubbele aanhalingstekens te plaatsen of door de gehele waarde van het teken in combinatie met de ASCII-vlag te gebruiken. In de volgende voorbeelden ziet u hoe u ASCII-accelerators definieert.
"A", ID_ACCEL1 ; SHIFT+A
65, ID_ACCEL2, ASCII ; SHIFT+A
Een toetsaanslag voor virtuele-sleutelcode wordt anders opgegeven, afhankelijk van of de toetsaanslag een alfanumerieke sleutel of een niet-alfanumerieke sleutel is. Voor een alfanumerieke sleutel wordt de letter of het cijfer van de sleutel, tussen dubbele aanhalingstekens, gecombineerd met de vlag VIRTKEY. Voor een niet-alfanumerieke sleutel wordt de code van de virtuele sleutel voor de specifieke sleutel gecombineerd met de vlag VIRTKEY. In de volgende voorbeelden ziet u hoe u codeversnellers voor virtuele sleutels definieert.
"a", ID_ACCEL3, VIRTKEY ; A (caps-lock on) or a
VK_INSERT, ID_ACCEL4, VIRTKEY ; INSERT key
In het volgende voorbeeld ziet u een accelerator-tabelresource die accelerators definieert voor bestandsbewerkingen. De naam van de resource is 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
Als u wilt dat de gebruiker in een combinatie met de toetsaanslag op alt, Shift of Ctrl drukt, geeft u de alt-, Shift- en CONTROL-vlaggen op in de definitie van de accelerator. Hieronder volgen enkele voorbeelden.
"B", ID_ACCEL5, ALT ; ALT_SHIFT+B
"I", ID_ACCEL6, CONTROL, VIRTKEY ; CTRL+I
VK_F5, ID_ACCEL7, CONTROL, ALT, VIRTKEY ; CTRL+ALT+F5
Wanneer een accelerator-toets overeenkomt met een menu-item, markeert het systeem standaard het menu-item. U kunt de vlag NOINVERT gebruiken om markeringen voor een afzonderlijke accelerator te voorkomen. In het volgende voorbeeld ziet u hoe u de vlag NOINVERT gebruikt:
VK_DELETE, ID_ACCEL8, VIRTKEY, SHIFT, NOINVERT ; SHIFT+DELETE
Als u accelerators wilt definiëren die overeenkomen met menu-items in uw toepassing, neemt u de accelerators op in de tekst van de menu-items. In het volgende voorbeeld ziet u hoe u accelerators kunt opnemen in menuopdrachttekst in een resourcedefinitiebestand.
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
De resource van de acceleratortabel laden
Een toepassing laadt een accelerator-tabelresource door de functie LoadAccelerators aan te roepen en de instantiegreep op te geven van de toepassing waarvan het uitvoerbare bestand de resource bevat, samen met de naam of identifier van de resource. LoadAccelerators laadt de opgegeven acceleratortabel in het geheugen en retourneert de handle naar de acceleratortabel.
Een toepassing kan op elk gewenst moment een acceleratortabel-resource laden. Normaal gesproken laadt een toepassing met één thread de acceleratortabel voordat de hoofdberichtlus begint. Een toepassing die meerdere threads gebruikt laadt doorgaans de accelerator-tableresource voor een thread voordat je de berichtlus voor de thread invoert. Een toepassing of thread kan meerdere acceleratortabellen gebruiken, waarbij elke tabel is gekoppeld aan een specifiek venster in de toepassing. Een dergelijke toepassing laadt de acceleratortabel voor het venster telkens wanneer de gebruiker het venster heeft geactiveerd. Zie Processen en Threadsvoor meer informatie over threads.
De functie Translate Accelerator aanroepen
Als u accelerators wilt verwerken, moet de berichtlus van een toepassing (of thread) een aanroep naar de TranslateAccelerator- functie bevatten. TranslateAccelerator toetsaanslagen vergelijkt met een acceleratortabel en, als er een overeenkomst wordt gevonden, worden de toetsaanslagen omgezet in een WM_COMMAND (of WM_SYSCOMMAND) bericht. De functie verzendt het bericht vervolgens naar een vensterprocedure. De parameters van de TranslateAccelerator- functie omvatten de handle naar het venster dat de WM_COMMAND- berichten ontvangt, de handle naar de acceleratortabel die wordt gebruikt om accelerators te vertalen, en een pointer naar een MSG- structuur die een bericht uit de wachtrij bevat. In het volgende voorbeeld ziet u hoe u TranslateAccelerator- aanroept vanuit een berichtenlus.
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 berichten verwerken
Wanneer een accelerator wordt gebruikt, ontvangt het venster dat is opgegeven in de TranslateAccelerator functie een WM_COMMAND of WM_SYSCOMMAND bericht. Het woord in lage volgorde van de parameter wParam bevat de id van de accelerator. De vensterprocedure onderzoekt de identificatie om de bron van het WM_COMMAND-bericht vast te stellen en het bericht dienovereenkomstig te behandelen.
Als een accelerator overeenkomt met een menu-item in de toepassing, krijgen de accelerator en het menu-item dezelfde id toegewezen. Als u wilt weten of een WM_COMMAND bericht is gegenereerd door een accelerator of een menu-item, kunt u het woord in hoge volgorde van de parameter wParam bekijken. Als een accelerator het bericht heeft gegenereerd, is het woord in hoge volgorde 1; als een menu-item het bericht heeft gegenereerd, is het woord in hoge volgorde 0.
Het vernietigen van de acceleratortabelresource
Het systeem vernietigt automatisch resources uit de acceleratortabel die door de LoadAccelerators functie worden geladen, en verwijdert de resource uit het geheugen nadat de toepassing is gesloten.
Snelkoppelingen maken voor lettertypekenmerken
In het voorbeeld in deze sectie ziet u hoe u de volgende taken uitvoert:
- Maak een accelerator-tabelresource.
- Laad de acceleratortabel tijdens runtime.
- Vertaal sneltoetsen in een berichtenlus.
- Verwerken WM_COMMAND berichten die zijn gegenereerd door de accelerators.
Deze taken worden gedemonstreerd in de context van een toepassing met een menu Character en bijbehorende accelerators waarmee de gebruiker kenmerken van het huidige lettertype kan selecteren.
In het volgende gedeelte van een resourcedefinitiebestand wordt het menu Character en de bijbehorende acceleratortabel gedefinieerd. Houd er rekening mee dat in de menu-items de sneltoetsen worden weergegeven en dat elke sneltoets dezelfde identificatie heeft als de bijbehorende menuopdracht.
#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
}
In de volgende secties van het bronbestand van de toepassing ziet u hoe u de accelerators implementeert.
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;
}
Een acceleratortabel gebruiken die tijdens runtime is gemaakt
In dit onderwerp wordt beschreven hoe u acceleratortabellen gebruikt die tijdens de runtime zijn gemaakt.
- Een Run-Time acceleratortabel maken
- Verwerkingsversnellers
- Een Run-Time Accelerator-tabel Vernietigen
- Gebruiker-bewerkbare accelerators maken
Een Run-Time Accelerator-tabel maken
De eerste stap bij het maken van een acceleratortabel tijdens runtime is het vullen van een matrix van ACCEL- structuren. Elke structuur in de matrix definieert een accelerator in de tabel. De definitie van een accelerator bevat de vlaggen, de sleutel en de identificator. De ACCEL- structuur heeft de volgende vorm.
typedef struct tagACCEL { // accl
BYTE fVirt;
WORD key;
WORD cmd;
} ACCEL;
U definieert de toetsaanslag van een accelerator door een ASCII-tekencode of een virtuele toetscode op te geven in het toets lid van de ACCEL structuur. Als u een code voor een virtuele sleutel opgeeft, moet u eerst de vlag FVIRTKEY opnemen in het lid fVirt; anders interpreteert het systeem de code als een ASCII-tekencode. U kunt de vlaggen FCONTROL, FALTof FSHIFT, of alle drie, gebruiken om de Ctrl, Alt of Shift-toets te combineren met de toetsaanslag.
Als u de acceleratortabel wilt maken, geeft u een aanwijzer door aan de matrix van ACCEL- structuren aan de functie CreateAcceleratorTable. CreateAcceleratorTable maakt de acceleratortabel en retourneert de handle naar de tabel.
Verwerkingsversnellers
Het proces voor het laden en aanroepen van accelerators die worden geleverd door een acceleratortabel die tijdens runtime is gemaakt, is hetzelfde als het verwerken van de acceleratortabel-resource. Zie voor meer informatie het laden van de acceleratortabelresource tot en met het verwerken van WM_COMMAND-berichten.
Een Run-Time Accelerator-tabel vernietigen
Het systeem vernietigt automatisch acceleratortabellen die tijdens runtime zijn gemaakt, en verwijdert de resources uit het geheugen nadat de toepassing is gesloten. U kunt een acceleratortabel vernietigen en deze eerder uit het geheugen verwijderen door de greep van de tabel door te geven aan de DestroyAcceleratorTable functie.
Bewerkbare accelerators voor gebruikers maken
In dit voorbeeld ziet u hoe u een dialoogvenster maakt waarmee de gebruiker de accelerator kan wijzigen die is gekoppeld aan een menu-item. Het dialoogvenster bestaat uit een keuzelijst met invoervak met menu-items, een keuzelijst met invoervak met de namen van sleutels en selectievakjes voor het selecteren van de Ctrl-, Alt- en Shift-toetsen. In de volgende afbeelding ziet u het dialoogvenster.
In het volgende voorbeeld ziet u hoe het dialoogvenster wordt gedefinieerd in het resourcedefinitiebestand.
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
De menubalk van een toepassing bevat een submenu Teken, waarvan de items sneltoetsen hebben.
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
}
De menu-itemwaarden voor de menusjabloon zijn constanten die als volgt zijn gedefinieerd in het headerbestand van de toepassing.
#define IDM_REGULAR 1100
#define IDM_BOLD 1200
#define IDM_ITALIC 1300
#define IDM_ULINE 1400
Het dialoogvenster maakt gebruik van een array van door de toepassing gedefinieerde VKEY-structuren, elk met een toetsaanslag tekstreeks en een versneller-tekstreeks. Wanneer het dialoogvenster wordt gemaakt, wordt de array geparseerd en wordt elke tekstreeks van toetsaanslagen toegevoegd aan de Toetsaanslag selecteren keuzelijst. Wanneer de gebruiker op de knop OK klikt, wordt in het dialoogvenster de geselecteerde toetsenreeks opgezocht en wordt de bijbehorende versnellertoetsreeks opgehaald. In het dialoogvenster wordt de tekenreeks accelerator-tekst toegevoegd aan de tekst van het menu-item dat de gebruiker heeft geselecteerd. In het volgende voorbeeld ziet u de matrix van VKEY-structuren:
// 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"
};
De initialisatieprocedure vult de Item selecteren en Toetsaanslag selecteren keuzelijstvakken in het dialoogvenster. Nadat de gebruiker een menu-item en de bijbehorende accelerator heeft geselecteerd, bekijkt het dialoogvenster de besturingselementen in het dialoogvenster om de selectie van de gebruiker op te halen, werkt u de tekst van het menu-item bij en maakt u vervolgens een nieuwe acceleratortabel die de door de gebruiker gedefinieerde nieuwe accelerator bevat. In het volgende voorbeeld ziet u de procedure in het dialoogvenster. Houd er rekening mee dat u uw venster-procedure moet initialiseren.
// 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;
}