Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4270 lines
116 KiB

/*++
Copyright (c) 1994-1995, Microsoft Corporation All rights reserved.
Module Name:
locdlg.c
Abstract:
This module implements the input locale property sheet for the Regional
Settings applet.
Revision History:
--*/
//
// Include Files.
//
#include "intl.h"
#include <windowsx.h>
#include <regstr.h>
#include <setupapi.h>
#include <syssetup.h>
#include <winuserp.h>
#include <help.h>
#include "locdlg.h"
#ifdef DBCS
#include <imm.h>
#endif
//
// Context Help Ids.
//
static int aLocaleHelpIds[] =
{
IDC_KBDL_LOCALE, IDH_KEYB_INPUT_LIST,
IDC_KBDL_LAYOUT_TEXT, IDH_KEYB_INPUT_LIST,
IDC_KBDL_LOCALE_LIST, IDH_KEYB_INPUT_LIST,
IDC_KBDL_ADD, IDH_KEYB_INPUT_ADD,
IDC_KBDL_EDIT, IDH_KEYB_INPUT_PROP,
IDC_KBDL_DELETE, IDH_KEYB_INPUT_DEL,
IDC_KBDL_DISABLED, NO_HELP,
IDC_KBDL_DISABLED_2, NO_HELP,
IDC_KBDL_DEFAULT_LABEL, IDH_KEYB_INPUT_DEF_LANG,
IDC_KBDL_DEFAULT, IDH_KEYB_INPUT_DEF_LANG,
IDC_KBDL_INPUT_FRAME, IDH_COMM_GROUPBOX,
IDC_KBDL_SET_DEFAULT, IDH_KEYB_INPUT_DEFAULT,
IDC_KBDL_SHORTCUT_FRAME, IDH_KEYB_INPUT_SHORTCUT,
IDC_KBDL_ALT_SHIFT, IDH_KEYB_INPUT_SHORTCUT,
IDC_KBDL_CTRL_SHIFT, IDH_KEYB_INPUT_SHORTCUT,
IDC_KBDL_NO_SHIFT, IDH_KEYB_INPUT_SHORTCUT,
IDC_KBDL_INDICATOR, IDH_KEYB_INPUT_INDICATOR,
IDC_KBDL_ONSCRNKBD, IDH_KEYB_INPUT_ONSCRN_KEYB,
0, 0
};
#define IDH_KEYB_DEF_KEYB_FOR_LOCALE 4033
static int aAddLocaleHelpIds[] =
{
IDC_KBDLA_LOCALE, IDH_KEYB_INPUT_LANG,
IDC_KBDLA_DEFAULT, IDH_KEYB_DEF_KEYB_FOR_LOCALE,
0, 0
};
static int aLocalePropHelpIDs[] =
{
IDC_KBDLE_LOCALE_TXT, IDH_KEYB_INPUT_PROP_LANG,
IDC_KBDLE_LOCALE, IDH_KEYB_INPUT_PROP_LANG,
IDC_KBDLE_LAYOUT, IDH_KEYB_INPUT_PROP_KEYLAY,
0, 0
};
//
// Global Variables.
//
TCHAR szPropHwnd[] = TEXT("PROP_HWND");
TCHAR szPropIdx[] = TEXT("PROP_IDX");
////////////////////////////////////////////////////////////////////////////
//
// GetKbdSwitchHotkey
//
// Gets the hotkey keyboard switch value from the registry and then
// sets the appropriate radio button in the dialog.
//
////////////////////////////////////////////////////////////////////////////
int GetKbdSwitchHotkey(
HWND hwnd)
{
TCHAR sz[10];
DWORD cb;
HKEY hkey;
//
// Get the hotkey value from the registry.
//
sz[0] = 0;
if (RegOpenKey(HKEY_CURRENT_USER, szKbdToggleKey, &hkey) == ERROR_SUCCESS)
{
cb = sizeof(sz);
RegQueryValueEx(hkey, TEXT("Hotkey"), NULL, NULL, (LPBYTE)sz, &cb);
RegCloseKey(hkey);
}
//
// Set the appropriate radio button in the dialog.
//
if ((sz[0] != 0) && (sz[1] == 0))
{
switch (sz[0])
{
case ( TEXT('2') ) :
{
CheckRadioButton( hwnd,
IDC_KBDL_ALT_SHIFT,
IDC_KBDL_NO_SHIFT,
IDC_KBDL_CTRL_SHIFT );
return (2);
}
case ( TEXT('3') ) :
{
CheckRadioButton( hwnd,
IDC_KBDL_ALT_SHIFT,
IDC_KBDL_NO_SHIFT,
IDC_KBDL_NO_SHIFT );
return (3);
}
}
}
//
// Default case.
//
CheckRadioButton( hwnd,
IDC_KBDL_ALT_SHIFT,
IDC_KBDL_NO_SHIFT,
IDC_KBDL_ALT_SHIFT );
return (1);
}
////////////////////////////////////////////////////////////////////////////
//
// TransNum
//
// Converts a number string to a dword value.
//
////////////////////////////////////////////////////////////////////////////
DWORD TransNum(
LPTSTR lpsz)
{
DWORD dw = 0L;
TCHAR c;
while (*lpsz)
{
c = *lpsz++;
if (c >= TEXT('A') && c <= TEXT('F'))
{
c -= TEXT('A') - 0xa;
}
else if (c >= TEXT('0') && c <= TEXT('9'))
{
c -= TEXT('0');
}
else if (c >= TEXT('a') && c <= TEXT('f'))
{
c -= TEXT('a') - 0xa;
}
else
{
break;
}
dw *= 0x10;
dw += c;
}
return (dw);
}
////////////////////////////////////////////////////////////////////////////
//
// ErrorMsg
//
// Sound a beep and put up the given error message.
//
////////////////////////////////////////////////////////////////////////////
void ErrorMsg(
HWND hwnd,
UINT iErr)
{
TCHAR sz[DESC_MAX];
//
// Sound a beep.
//
MessageBeep(MB_OK);
//
// Put up the appropriate error message box.
//
if (LoadString(hInstance, iErr, sz, DESC_MAX))
{
MessageBox(hwnd, sz, NULL, MB_OK_OOPS);
}
}
////////////////////////////////////////////////////////////////////////////
//
// ApplyError
//
// Put up the given error message with the language name in it.
//
// NOTE: This error is NOT fatal - as we could be half way through the
// list before an error occurs. The registry will already have
// some information and we should let them have what comes next
// as well.
//
////////////////////////////////////////////////////////////////////////////
int ApplyError(
HWND hwnd,
LPLANGNODE pLangNode,
UINT iErr,
UINT iStyle)
{
UINT idxLang, idxLayout;
TCHAR sz[MAX_PATH];
TCHAR szTemp[MAX_PATH];
TCHAR szLangName[MAX_PATH * 2];
LPTSTR pszLang;
//
// Load in the string for the given string id.
//
LoadString(hInstance, iErr, sz, MAX_PATH);
//
// Get the language name to fill into the above string.
//
if (pLangNode)
{
idxLang = pLangNode->iLang;
idxLayout = pLangNode->iLayout;
GetAtomName(lpLang[idxLang].atmLanguageName, szLangName, MAX_PATH);
if (lpLang[idxLang].dwID != lpLayout[idxLayout].dwID)
{
pszLang = szLangName + lstrlen(szLangName);
pszLang[0] = TEXT(' ');
pszLang[1] = TEXT('-');
pszLang[2] = TEXT(' ');
GetAtomName( lpLayout[idxLayout].atmLayoutText,
pszLang + 3,
MAX_PATH - 3 );
}
}
else
{
LoadString(hInstance, IDS_UNKNOWN, szLangName, MAX_PATH);
}
//
// Put up the error message box.
//
wsprintf(szTemp, sz, szLangName);
return ( MessageBox(hwnd, szTemp, NULL, iStyle) );
}
////////////////////////////////////////////////////////////////////////////
//
// FetchIndicator
//
// Saves the two letter indicator symbol for the given language in the
// lpLang array.
//
////////////////////////////////////////////////////////////////////////////
void FetchIndicator(
LPLANGNODE pLangNode)
{
TCHAR szData[MAX_PATH];
LPINPUTLANG pInpLang = &lpLang[pLangNode->iLang];
pLangNode->wStatus |= ICON_LOADED;
#ifdef DBCS
if (pLangNode->wStatus & LANG_IME)
{
TCHAR szFileName[MAX_PATH];
HICON hIcon = NULL;
if (himIndicators != NULL)
{
GetAtomName( lpLayout[pLangNode->iLayout].atmIMEFile,
szFileName,
MAX_PATH );
ExtractIconEx(szFileName, 0, (HICON *)&hIcon, NULL, 1);
if (hIcon)
{
pLangNode->niconIME = ImageList_AddIcon( himIndicators,
hIcon );
}
else
{
pLangNode->niconIME = -1;
}
DestroyIcon(hIcon);
if (pLangNode->niconIME != -1)
{
return;
}
}
}
#endif
//
// Get the indicator by using the first 2 characters of the
// abbreviated language name.
//
if (GetLocaleInfo( LOWORD(pInpLang->dwID),
LOCALE_SABBREVLANGNAME | LOCALE_NOUSEROVERRIDE,
szData,
MAX_PATH ))
{
//
// Save the first two characters.
//
pInpLang->szSymbol[0] = szData[0];
pInpLang->szSymbol[1] = szData[1];
pInpLang->szSymbol[2] = TEXT('\0');
}
else
{
//
// Id wasn't found. Return question marks.
//
pInpLang->szSymbol[0] = TEXT('?');
pInpLang->szSymbol[1] = TEXT('?');
pInpLang->szSymbol[2] = TEXT('\0');
}
}
////////////////////////////////////////////////////////////////////////////
//
// SetSecondaryControls
//
// Sets the secondary controls to either be enabled or disabled. When
// there is only 1 active keyboard layout, then this function will be
// called to disable these controls.
//
////////////////////////////////////////////////////////////////////////////
void SetSecondaryControls(
HWND hwndMain,
BOOL bOn)
{
EnableWindow(GetDlgItem(hwndMain, IDC_KBDL_INDICATOR), bOn);
CheckDlgButton(hwndMain, IDC_KBDL_INDICATOR, bOn);
EnableWindow(GetDlgItem(hwndMain, IDC_KBDL_DELETE), bOn);
EnableWindow(GetDlgItem(hwndMain, IDC_KBDL_SET_DEFAULT), bOn);
EnableWindow(GetDlgItem(hwndMain, IDC_KBDL_ALT_SHIFT), bOn);
CheckDlgButton(hwndMain, IDC_KBDL_ALT_SHIFT, bOn);
EnableWindow(GetDlgItem(hwndMain, IDC_KBDL_CTRL_SHIFT), bOn);
CheckDlgButton(hwndMain, IDC_KBDL_CTRL_SHIFT, 0);
EnableWindow(GetDlgItem(hwndMain, IDC_KBDL_NO_SHIFT), bOn);
CheckDlgButton(hwndMain, IDC_KBDL_NO_SHIFT, 0);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_AddToLinkedList
//
// Adds an Input Locale to the main lpLang array.
//
////////////////////////////////////////////////////////////////////////////
LPLANGNODE Locale_AddToLinkedList(
UINT idx,
HKL hkl)
{
LPINPUTLANG pInpLang = &lpLang[idx];
LPLANGNODE pLangNode;
LPLANGNODE pTemp;
HANDLE hLangNode;
//
// Create the new node.
//
if (!(hLangNode = GlobalAlloc(GHND, sizeof(LANGNODE))))
{
return (NULL);
}
pLangNode = GlobalLock(hLangNode);
//
// Fill in the new node with the appropriate info.
//
pLangNode->wStatus = 0;
pLangNode->iLayout = (UINT)(-1);
pLangNode->hkl = hkl;
pLangNode->hklUnload = hkl;
pLangNode->iLang = idx;
pLangNode->hLangNode = hLangNode;
pLangNode->pNext = NULL;
//
// Put the new node in the list.
//
pTemp = pInpLang->pNext;
if (pTemp == NULL)
{
pInpLang->pNext = pLangNode;
}
else
{
while (pTemp->pNext != NULL)
{
pTemp = pTemp->pNext;
}
pTemp->pNext = pLangNode;
}
//
// Increment the count.
//
pInpLang->iNumCount++;
//
// Return the pointer to the new node.
//
return (pLangNode);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_RemoveFromLinkedList
//
// Removes a link from the linked list.
//
////////////////////////////////////////////////////////////////////////////
void Locale_RemoveFromLinkedList(
LPLANGNODE pLangNode)
{
LPINPUTLANG pInpLang;
LPLANGNODE pPrev;
LPLANGNODE pCur;
HANDLE hCur;
pInpLang = &lpLang[pLangNode->iLang];
//
// Find the node in the list.
//
pPrev = NULL;
pCur = pInpLang->pNext;
while (pCur && (pCur != pLangNode))
{
pPrev = pCur;
pCur = pCur->pNext;
}
if (pPrev == NULL)
{
pInpLang->pNext = NULL;
}
else if (pCur)
{
pPrev->pNext = pCur->pNext;
}
//
// Remove the node from the list.
//
if (pCur)
{
hCur = pCur->hLangNode;
GlobalUnlock(hCur);
GlobalFree(hCur);
}
}
////////////////////////////////////////////////////////////////////////////
//
// AddLanguage
//
// Adds the new input locale to the list in the property page.
//
////////////////////////////////////////////////////////////////////////////
BOOL AddLanguage(
HWND hwndMain,
LPLANGNODE pLangNode)
{
HWND hwndLang;
UINT iCount;
//
// See if the user has Admin privileges. If not, then don't allow
// them to install any NEW layouts.
//
if ((!g_bAdmin_Privileges) &&
(!lpLayout[pLangNode->iLayout].bInstalled))
{
//
// The layout is not currently installed, so don't allow it
// to be added.
//
ErrorMsg(hwndMain, IDS_ML_LAYOUTFAILED);
return (FALSE);
}
//
// Set the language to active.
// Also, set the status to changed so that the layout will be added.
//
pLangNode->wStatus |= (LANG_CHANGED | LANG_ACTIVE);
//
// Get the number of items in the input locale list box.
//
hwndLang = GetDlgItem(hwndMain, IDC_KBDL_LOCALE_LIST);
iCount = ListBox_GetCount(hwndLang);
//
// Add the new item data to the list box.
//
ListBox_AddItemData(hwndLang, pLangNode);
//
// Get the indicator symbol.
//
if ((pLangNode->wStatus & ICON_LOADED))
{
FetchIndicator(pLangNode);
}
//
// See if the original count (before the addition) was 1. If so,
// enable the secondary controls, since there are now 2 items in
// the list box.
//
if (iCount == 1)
{
SetSecondaryControls(hwndMain, TRUE);
}
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_SetupKeyboardLayouts
//
// Calls setup to get all of the new keyboard layout files.
//
////////////////////////////////////////////////////////////////////////////
BOOL Locale_SetupKeyboardLayouts(
HWND hwnd,
HWND hwndList,
UINT nLocales)
{
HINF hKbdInf;
HSPFILEQ FileQueue;
PVOID QueueContext;
UINT i;
LPLANGNODE pLangNode;
int count;
BOOL bInitInf = FALSE;
TCHAR szSection[MAX_PATH];
BOOL bRet = TRUE;
for (i = 0; i < nLocales; i++)
{
pLangNode = (LPLANGNODE)ListBox_GetItemData(hwndList, i);
if ((pLangNode->wStatus & LANG_CHANGED) &&
(pLangNode->wStatus & LANG_ACTIVE))
{
if (!bInitInf)
{
//
// Open the Inf file.
//
hKbdInf = SetupOpenInfFile(szKbdInf, NULL, INF_STYLE_WIN4, NULL);
if (hKbdInf == INVALID_HANDLE_VALUE)
{
return (FALSE);
}
if (!SetupOpenAppendInfFile(NULL, hKbdInf, NULL))
{
SetupCloseInfFile(hKbdInf);
return (FALSE);
}
//
// Create a setup file queue and initialize default setup
// copy queue callback context.
//
FileQueue = SetupOpenFileQueue();
if ((!FileQueue) || (FileQueue == INVALID_HANDLE_VALUE))
{
SetupCloseInfFile(hKbdInf);
return (FALSE);
}
QueueContext = SetupInitDefaultQueueCallback(hwnd);
if (!QueueContext)
{
SetupCloseFileQueue(FileQueue);
SetupCloseInfFile(hKbdInf);
return (FALSE);
}
bInitInf = TRUE;
}
//
// Get the layout name.
//
wsprintf( szSection,
TEXT("%ws%8.8lx"),
szPrefixCopy,
lpLayout[pLangNode->iLayout].dwID );
//
// Enqueue the keyboard layout files so that they may be
// copied. This only handles the CopyFiles entries in the
// inf file.
//
if (!SetupInstallFilesFromInfSection( hKbdInf,
NULL,
FileQueue,
szSection,
NULL,
SP_COPY_NEWER ))
{
//
// Setup failed to find the keyboard. Make it inactive
// and remove it from the list.
//
// This shouldn't happen - the inf file is messed up.
//
ErrorMsg(hwnd, IDS_ML_SETUPFAILED);
pLangNode->wStatus & ~(LANG_CHANGED | LANG_ACTIVE);
if ((count = ListBox_GetCount(hwndList)) > 1)
{
ListBox_DeleteString(hwndList, i);
ListBox_SetCurSel(hwndList, 0);
if (count == 2)
{
SetSecondaryControls(hwnd, FALSE);
}
nLocales = count - 1;
(lpLang[pLangNode->iLang].iNumCount)--;
Locale_RemoveFromLinkedList(pLangNode);
}
}
}
}
if (bInitInf)
{
DWORD d;
//
// See if we need to install any files.
//
// d = 0: User wants new files or some files were missing;
// Must commit queue.
//
// d = 1: User wants to use existing files and queue is empty;
// Can skip committing queue.
//
// d = 2: User wants to use existing files, but del/ren queues
// not empty. Must commit queue. The copy queue will
// have been emptied, so only del/ren functions will be
// performed.
//
if ((SetupScanFileQueue( FileQueue,
SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_INFORM_USER,
hwnd,
NULL,
NULL,
&d )) && (d != 1))
{
//
// Copy the files in the queue.
//
if (!SetupCommitFileQueue( hwnd,
FileQueue,
SetupDefaultQueueCallback,
QueueContext ))
{
//
// This can happen if the user hits Cancel from within
// the setup dialog.
//
ErrorMsg(hwnd, IDS_ML_SETUPFAILED);
bRet = FALSE;
goto Locale_SetupError;
}
}
//
// Execute all of the other entries in the inf file.
//
// Currently, there are no other entries within the inf file
// other than the CopyFiles entry. Therefore, this loop does
// nothing at the moment.
//
for (i = 0; i < nLocales; i++)
{
pLangNode = (LPLANGNODE)ListBox_GetItemData(hwndList, i);
if ((pLangNode->wStatus & LANG_CHANGED) &&
(pLangNode->wStatus & LANG_ACTIVE))
{
//
// Get the layout name.
//
wsprintf( szSection,
TEXT("%ws%8.8lx"),
szPrefixCopy,
lpLayout[pLangNode->iLayout].dwID );
//
// Call setup to copy the keyboard layout file.
//
if (!SetupInstallFromInfSection( hwnd,
hKbdInf,
szSection,
SPINST_ALL & ~SPINST_FILES,
NULL,
NULL,
0,
NULL,
NULL,
NULL,
NULL ))
{
//
// Setup failed.
//
// Already copied the keyboard layout file, so no
// need to change the status of the keyboard info here.
//
// This shouldn't happen - the inf file is messed up.
//
ErrorMsg(hwnd, IDS_ML_SETUPFAILED);
}
}
}
Locale_SetupError:
//
// Terminate the Queue.
//
SetupTermDefaultQueueCallback(QueueContext);
//
// Close the file queue.
//
SetupCloseFileQueue(FileQueue);
//
// Close the Inf file.
//
SetupCloseInfFile(hKbdInf);
}
//
// Return success.
//
return (bRet);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_ApplyInputs
//
// 1. make sure we have all the layout files required.
// 2. write the information into the registry
// 3. call Load/UnloadKeyboardLayout where relevant
//
// Note that this will trash the previous preload and substitutes sections,
// based on what is actually loaded. Thus if something was wrong before in
// the registry, it will be corrected now.
//
////////////////////////////////////////////////////////////////////////////
BOOL Locale_ApplyInputs(
HWND hwnd)
{
HKL *pLangs = NULL;
UINT nLangs;
UINT idx;
LPLANGNODE pLangNode, pTemp;
LPINPUTLANG pInpLang;
UINT nLocales;
UINT i, j;
UINT iPreload = 0;
UINT iVal;
DWORD dwID;
TCHAR sz[DESC_MAX]; // temp - build the name of the reg entry
TCHAR szPreload10[10];
TCHAR szTemp[MAX_PATH];
HWND hwndIndicate;
HKEY hkeyLayouts;
HKEY hkeySubst;
HKEY hkeyPreload;
HKEY hkeyToggle;
HWND hwndList = GetDlgItem(hwnd, IDC_KBDL_LOCALE_LIST);
HKL hklDefault = 0;
HKL hklLoad, hklUnload;
HCURSOR hcurSave;
#ifdef DBCS
HKEY hkeyScanCode;
DWORD cb;
TCHAR szShiftL[8];
TCHAR szShiftR[8];
#endif
//
// See if the pane is disabled. If so, then there is nothing to
// Apply.
//
if (!IsWindowEnabled(hwndList))
{
return (TRUE);
}
//
// First make sure we are left with a layout.
//
// This actually shouldn't happen, since the "Remove" button is
// disabled when there is only one input locale left in the list.
//
nLocales = ListBox_GetCount(hwndList);
if (nLocales < 1)
{
ErrorMsg(hwnd, IDS_ML_NEEDLAYOUT);
return (FALSE);
}
//
// Put up the hour glass.
//
hcurSave = SetCursor(LoadCursor(NULL, IDC_WAIT));
//
// Make sure there are actually changes since the last save when
// OK is selected. If the user hits OK without anything to Apply,
// then we should do nothing.
//
if (!bSwitchChange && !bDefaultChange)
{
pLangNode = NULL;
for (idx = 0; idx < iLangBuff; idx++)
{
pLangNode = lpLang[idx].pNext;
while (pLangNode != NULL)
{
if (pLangNode->wStatus & (LANG_CHANGED | LANG_DEF_CHANGE))
{
break;
}
pLangNode = pLangNode->pNext;
}
if (pLangNode != NULL)
{
break;
}
}
if ((idx == iLangBuff) && (pLangNode == NULL))
{
SetCursor(hcurSave);
PropSheet_UnChanged(GetParent(hwnd), hwnd);
return (TRUE);
}
}
//
// Queue up the new layouts and copy the appropriate files to
// disk using the setup apis. Only do this if the user has
// Admin privileges.
//
if (g_bAdmin_Privileges &&
!Locale_SetupKeyboardLayouts(hwnd, hwndList, nLocales))
{
SetCursor(hcurSave);
return (FALSE);
}
//
// Clean up the registry.
//
#ifdef DBCS
//
// In the DBCS world, there is a keyboard which has a different
// scan code for shift keys - eg. NEC PC9801.
// We have to keep information about scan codes for shift keys in
// the registry under the 'toggle' sub key as named values.
//
szShiftL[0] = TEXT('\0');
szShiftR[0] = TEXT('\0');
if (RegOpenKey( HKEY_CURRENT_USER,
szScanCodeKey,
&hkeyScanCode ) == ERROR_SUCCESS)
{
cb = sizeof(szShiftL);
RegQueryValueEx( hkeyScanCode,
szValueShiftLeft,
NULL,
NULL,
(LPBYTE)szShiftL,
&cb );
cb = sizeof(szShiftR);
RegQueryValueEx( hkeyScanCode,
szValueShiftRight,
NULL,
NULL,
(LPBYTE)szShiftR,
&cb );
RegCloseKey(hkeyScanCode);
}
#endif
//
// Delete the HKCU\Keyboard Layout key and all subkeys.
//
if (RegOpenKeyEx( HKEY_CURRENT_USER,
szKbdLayouts,
0,
KEY_ALL_ACCESS,
&hkeyLayouts ) == ERROR_SUCCESS)
{
//
// Delete the HKCU\Keyboard Layout\Preload, Substitutes, and Toggle
// keys in the registry so that the Keyboard Layout section can be
// rebuilt.
//
RegDeleteKey(hkeyLayouts, szPreloadKey);
RegDeleteKey(hkeyLayouts, szSubstKey);
RegDeleteKey(hkeyLayouts, szToggleKey);
RegCloseKey(hkeyLayouts);
RegDeleteKey(HKEY_CURRENT_USER, szKbdLayouts);
}
//
// Create the HKCU\Keyboard Layout key.
//
if (RegCreateKey( HKEY_CURRENT_USER,
szKbdLayouts,
&hkeyLayouts ) == ERROR_SUCCESS)
{
//
// Create the HKCU\Keyboard Layout\Substitutes key.
//
if (RegCreateKey( hkeyLayouts,
szSubstKey,
&hkeySubst ) == ERROR_SUCCESS)
{
//
// Create the HKCU\Keyboard Layout\Preload key.
//
if (RegCreateKey( hkeyLayouts,
szPreloadKey,
&hkeyPreload ) == ERROR_SUCCESS)
{
//
// Initialize the iPreload variable to 1 to show
// that the key has been created.
//
iPreload = 1;
//
// Create the HKCU\Keyboard Layout\Toggle key.
//
RegCreateKey(hkeyLayouts, szToggleKey, &hkeyToggle);
}
else
{
RegCloseKey(hkeySubst);
}
}
RegCloseKey(hkeyLayouts);
}
if (!iPreload)
{
//
// Registry keys could not be created. Now what?
//
MessageBeep(MB_OK);
SetCursor(hcurSave);
return (FALSE);
}
//
// Get the list of the currently active keyboard layouts from
// the system.
//
nLangs = GetKeyboardLayoutList(0, NULL);
if (nLangs != 0)
{
pLangs = (HKL *)LocalAlloc(LPTR, sizeof(DWORD) * nLangs);
GetKeyboardLayoutList(nLangs, (HKL *)pLangs);
}
//
// Set all usage counts to zero in the language array.
//
for (idx = 0; idx < iLangBuff; idx++)
{
lpLang[idx].iUseCount = 0;
}
//
// The order in the registry is based on the order in which they
// appear in the list box.
//
// The only exception to this is that the default will be number 1.
//
// If no default is found, the last one in the list will be used as
// the default.
//
iVal = 2;
for (i = 0; i < nLocales; i++)
{
//
// Get the pointer to the lang node from the list box
// item data.
//
pLangNode = (LPLANGNODE)ListBox_GetItemData(hwndList, i);
pInpLang = &(lpLang[pLangNode->iLang]);
//
// See if it's the default input locale.
//
if (pLangNode->wStatus & LANG_DEFAULT)
{
//
// Default input locale, so the preload value should be
// set to 1.
//
iPreload = 1;
}
else if (i == (nLocales - 1))
{
//
// We're on the last one. Make sure there was a default.
//
iPreload = (iVal <= nLocales) ? iVal : 1;
}
else
{
//
// Set the preload value to the next value.
//
iPreload = iVal;
iVal++;
}
//
// Store the preload value as a string so that it can be written
// into the registry (as a value name).
//
wsprintf(sz, TEXT("%d"), iPreload);
//
// Store the locale id as a string so that it can be written
// into the registry (as a value).
//
#ifdef DBCS
if (pLangNode->wStatus & LANG_IME)
{
wsprintf( szPreload10,
TEXT("%8.8lx"),
lpLayout[pLangNode->iLayout].dwID );
}
else
#endif
{
dwID = pInpLang->dwID;
idx = pInpLang->iUseCount;
if ((idx == 0) || (idx > 0xfff))
{
idx = 0;
wsprintf(szPreload10, TEXT("%8.8x"), dwID);
}
else
{
dwID |= ((DWORD)(0xd000 | ((WORD)(idx - 1))) << 16);
wsprintf(szPreload10, TEXT("%8.8x"), dwID);
}
(pInpLang->iUseCount)++;
}
//
// Set the new entry in the registry. It is of the form:
//
// HKCU\Keyboard Layout
// Preload: 1 = <locale id>
// 2 = <locale id>
// etc...
//
RegSetValueEx( hkeyPreload,
sz,
0,
REG_SZ,
(LPBYTE)szPreload10,
(DWORD)(lstrlen(szPreload10) + 1) * sizeof(TCHAR) );
//
// See if we need to add a substitute for this input locale.
//
if ((pInpLang->dwID != lpLayout[pLangNode->iLayout].dwID) || idx)
{
//
// Get the layout id as a string so that it can be written
// into the registry (as a value).
//
wsprintf( szTemp,
TEXT("%8.8lx"),
lpLayout[pLangNode->iLayout].dwID );
#ifdef DBCS
if (!(pLangNode->wStatus & LANG_IME))
#endif
//
// Set the new entry in the registry. It is of the form:
//
// HKCU\Keyboard Layout
// Substitutes: <locale id> = <layout id>
// <locale id> = <layout id>
// etc...
//
RegSetValueEx( hkeySubst,
szPreload10,
0,
REG_SZ,
(LPBYTE)szTemp,
(DWORD)(lstrlen(szTemp) + 1) * sizeof(TCHAR) );
}
//
// Make sure all of the changes are written to disk.
//
RegFlushKey(hkeySubst);
RegFlushKey(hkeyPreload);
RegFlushKey(HKEY_CURRENT_USER);
//
// See if the keyboard layout needs to be loaded.
//
if (pLangNode->wStatus & (LANG_CHANGED | LANG_DEF_CHANGE))
{
//
// Load the keyboard layout into the system.
//
if (pLangNode->hklUnload)
{
hklLoad = LoadKeyboardLayoutEx( pLangNode->hklUnload,
szPreload10,
KLF_SUBSTITUTE_OK |
KLF_NOTELLSHELL );
}
else
{
hklLoad = LoadKeyboardLayout( szPreload10,
KLF_SUBSTITUTE_OK |
KLF_NOTELLSHELL );
}
if (hklLoad)
{
pLangNode->wStatus &= ~(LANG_CHANGED | LANG_DEF_CHANGE);
pLangNode->wStatus |= (LANG_ACTIVE | LANG_ORIGACTIVE);
if (pLangNode->wStatus & LANG_DEFAULT)
{
hklDefault = hklLoad;
}
pLangNode->hkl = hklLoad;
pLangNode->hklUnload = hklLoad;
}
else
{
ApplyError(hwnd, pLangNode, IDS_ML_LOADKBDFAILED, MB_OK_OOPS);
}
}
}
//
// Close the handles to the registry keys.
//
RegCloseKey(hkeySubst);
RegCloseKey(hkeyPreload);
//
// Make sure the default is set properly. The layout id for the
// current default input locale may have been changed.
//
// NOTE: This should be done before the Unloads occur in case one
// of the layouts to unload is the old default layout.
//
if (hklDefault != 0)
{
if (!SystemParametersInfo( SPI_SETDEFAULTINPUTLANG,
0,
(LPVOID)((LPDWORD)&hklDefault),
0 ))
{
//
// Failure is not fatal. The old default language will
// still work.
//
ErrorMsg(hwnd, IDS_ML_NODEFLANG2);
}
else
{
//
// Activate the new default keyboard layout.
//
// ActivateKeyboardLayout(hklDefault, KLF_REORDER);
}
}
//
// Search through the list to see if any keyboard layouts need to be
// unloaded from the system.
//
for (idx = 0; idx < iLangBuff; idx++)
{
pLangNode = lpLang[idx].pNext;
while (pLangNode != NULL)
{
if ( (pLangNode->wStatus & LANG_ORIGACTIVE) &&
!(pLangNode->wStatus & LANG_ACTIVE) )
{
//
// Started off with this active, deleting it now.
// Failure is not fatal.
//
if (!UnloadKeyboardLayout(pLangNode->hkl))
{
ApplyError( hwnd,
pLangNode,
IDS_ML_UNLOADKBDFAILED,
MB_OK_OOPS );
//
// Failed to unload layout, put it back in the list,
// and turn ON the indicator whether it needs it or not.
//
if (AddLanguage(hwnd, pLangNode))
{
CheckDlgButton(hwnd, IDC_KBDL_INDICATOR, TRUE);
}
pLangNode = pLangNode->pNext;
}
else
{
//
// Succeeded, no longer in USER's list.
//
// Reset flag, this could be from ApplyInput and we'll
// fail on the OK if we leave it marked as original
// active.
//
pLangNode->wStatus &= ~(LANG_ORIGACTIVE | LANG_CHANGED);
//
// Remove the link in the language array.
//
// NOTE: pLangNode could be null here.
//
pTemp = pLangNode->pNext;
Locale_RemoveFromLinkedList(pLangNode);
pLangNode = pTemp;
}
}
else
{
pLangNode = pLangNode->pNext;
}
}
}
//
// Handle the task bar indicator option.
//
hwndIndicate = FindWindow(szIndicator, NULL);
if (RegCreateKey( HKEY_CURRENT_USER,
REGSTR_PATH_RUN,
&hkeySubst ) != ERROR_SUCCESS)
{
ErrorMsg(hwnd, IDS_ML_LOADLINEBAD);
hkeySubst = NULL;
}
//
// See if the task bar indicator check box is set.
//
if (IsDlgButtonChecked(hwnd, IDC_KBDL_INDICATOR))
{
//
// User wants the indicator.
//
// See if the indicator is already enabled.
//
if (hwndIndicate && IsWindow(hwndIndicate))
{
SendMessage(hwndIndicate, WM_COMMAND, IDM_NEWSHELL, 0L);
}
else
{
WinExec(szInternatA, SW_SHOWMINNOACTIVE);
}
if (hkeySubst)
{
RegSetValueEx( hkeySubst,
szInternat,
0,
REG_SZ,
(LPBYTE)szInternat,
sizeof(szInternat) );
}
}
else
{
//
// Either the user doesn't want the indicator or there are less
// than two input locales.
//
if (hwndIndicate && IsWindow(hwndIndicate))
{
//
// It's on, turn it off again.
//
SendMessage(hwndIndicate, WM_COMMAND, IDM_EXIT, 0L);
}
if (hkeySubst)
{
//
// Clean up the registry.
//
RegDeleteValue(hkeySubst, szInternat);
}
}
if (hkeySubst)
{
RegCloseKey(hkeySubst);
}
//
// See which of the toggle hotkeys is set.
//
idx = 1;
if (IsDlgButtonChecked(hwnd, IDC_KBDL_CTRL_SHIFT))
{
idx = 2;
}
else if (IsDlgButtonChecked(hwnd, IDC_KBDL_NO_SHIFT))
{
idx = 3;
}
//
// Get the toggle hotkey as a string so that it can be written
// into the registry (as data).
//
wsprintf(szTemp, TEXT("%d"), idx);
//
// Set the new entry in the registry. It is of the form:
//
// HKCU\Keyboard Layout
// Toggle: Hotkey = <hotkey number>
//
if (hkeyToggle)
{
RegSetValueEx( hkeyToggle,
TEXT("Hotkey"),
0,
REG_SZ,
(LPBYTE)szTemp,
(DWORD)(lstrlen(szTemp) + 1) * sizeof(TCHAR) );
RegCloseKey(hkeyToggle);
}
#ifdef DBCS
//
// Set the scan code entries in the registry.
//
if (RegCreateKey( HKEY_CURRENT_USER,
szScanCodeKey,
&hkeyScanCode ) == ERROR_SUCCESS)
{
if (szShiftL[0])
{
RegSetValueEx( hkeyScanCode,
szValueShiftLeft,
0,
REG_SZ,
(LPBYTE)szShiftL,
(DWORD)(lstrlen(szShiftL) + 1) * sizeof(TCHAR) );
}
if (szShiftR[0])
{
RegSetValueEx( hkeyScanCode,
szValueShiftRight,
0,
REG_SZ,
(LPBYTE)szShiftR,
(DWORD)(lstrlen(szShiftR) + 1) * sizeof(TCHAR) );
}
RegCloseKey(hkeyScanCode);
}
#endif
//
// Call SystemParametersInfo to enable the toggle.
//
SystemParametersInfo(SPI_SETLANGTOGGLE, 0, NULL, 0);
//
// Turn off the hourglass.
//
SetCursor(hcurSave);
//
// Free any allocated memory.
//
if (pLangs != NULL)
{
LocalFree((HANDLE)pLangs);
}
//
// Return success.
//
bSwitchChange = FALSE;
bDefaultChange = FALSE;
PropSheet_UnChanged(GetParent(hwnd), hwnd);
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// EnablePane
//
// The controls in "iControl" are the controls that get disabled if the
// pane can't come up.
//
////////////////////////////////////////////////////////////////////////////
static UINT iControls[] =
{
IDC_KBDL_LOCALE, IDC_KBDL_LAYOUT_TEXT, IDC_KBDL_LOCALE_LIST,
IDC_KBDL_ADD, IDC_KBDL_EDIT, IDC_KBDL_DELETE,
IDC_KBDL_DEFAULT, IDC_KBDL_INPUT_FRAME, IDC_KBDL_SET_DEFAULT,
IDC_KBDL_SHORTCUT_FRAME, IDC_KBDL_ALT_SHIFT, IDC_KBDL_CTRL_SHIFT,
IDC_KBDL_NO_SHIFT, IDC_KBDL_DEFAULT_LABEL, IDC_KBDL_INDICATOR,
IDC_KBDL_ONSCRNKBD, IDC_KBDL_DISABLED, IDC_KBDL_DISABLED_2
};
#define NCONTROLS sizeof(iControls) / sizeof(UINT)
void EnablePane(
HWND hwnd,
BOOL bEnable,
UINT DisableId)
{
HWND hwndItem;
int i;
if (bEnable)
{
//
// Enable all of the controls except for the "pane disabled"
// strings.
//
for (i = 0; i < NCONTROLS; i++)
{
hwndItem = GetDlgItem(hwnd, iControls[i]);
ShowWindow(hwndItem, SW_SHOW);
EnableWindow(hwndItem, TRUE);
}
//
// Disable the "pane disabled" strings.
//
EnableWindow(GetDlgItem(hwnd, IDC_KBDL_DISABLED), FALSE);
ShowWindow(GetDlgItem(hwnd, IDC_KBDL_DISABLED), SW_HIDE);
EnableWindow(GetDlgItem(hwnd, IDC_KBDL_DISABLED_2), FALSE);
ShowWindow(GetDlgItem(hwnd, IDC_KBDL_DISABLED_2), SW_HIDE);
}
else
{
//
// Disable all of the controls except for the "pane disabled"
// string.
//
for (i = 0; i < NCONTROLS; i++)
{
hwndItem = GetDlgItem(hwnd, iControls[i]);
EnableWindow(hwndItem, FALSE);
ShowWindow(hwndItem, SW_HIDE);
}
hwndItem = GetDlgItem(hwnd, DisableId);
ShowWindow(hwndItem, SW_SHOW);
EnableWindow(hwndItem, TRUE);
}
}
////////////////////////////////////////////////////////////////////////////
//
// FileExists
//
// Determines if the file exists and is accessible.
//
////////////////////////////////////////////////////////////////////////////
BOOL FileExists(
LPTSTR pFileName)
{
WIN32_FIND_DATA FindData;
HANDLE FindHandle;
BOOL bRet;
UINT OldMode;
OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
FindHandle = FindFirstFile(pFileName, &FindData);
if (FindHandle == INVALID_HANDLE_VALUE)
{
bRet = FALSE;
}
else
{
FindClose(FindHandle);
bRet = TRUE;
}
SetErrorMode(OldMode);
return (bRet);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_LoadLayouts
//
// Loads the layouts from the registry.
//
////////////////////////////////////////////////////////////////////////////
BOOL Locale_LoadLayouts(
HWND hwnd)
{
HKEY hKey;
HKEY hkey1;
DWORD cb;
DWORD dwIndex;
LONG dwRetVal;
DWORD dwValue;
DWORD dwType;
TCHAR szValue[MAX_PATH]; // language id (number)
TCHAR szData[MAX_PATH]; // language name
TCHAR szSystemDir[MAX_PATH * 2];
UINT SysDirLen;
//
// Now read all of the layouts from the registry.
//
if (RegOpenKey(HKEY_LOCAL_MACHINE, szLayoutPath, &hKey) != ERROR_SUCCESS)
{
EnablePane(hwnd, FALSE, IDC_KBDL_DISABLED);
return (FALSE);
}
dwIndex = 0;
dwRetVal = RegEnumKey( hKey,
dwIndex,
szValue,
sizeof(szValue) / sizeof(TCHAR) );
if (dwRetVal != ERROR_SUCCESS)
{
EnablePane(hwnd, FALSE, IDC_KBDL_DISABLED);
RegCloseKey(hKey);
return (FALSE);
}
hLayout = GlobalAlloc(GHND, ALLOCBLOCK * sizeof(LAYOUT));
nLayoutBuffSize = ALLOCBLOCK;
iLayoutBuff = 0;
lpLayout = GlobalLock(hLayout);
if (!hLayout)
{
EnablePane(hwnd, FALSE, IDC_KBDL_DISABLED);
RegCloseKey(hKey);
return (FALSE);
}
//
// Save the system directory string.
//
szSystemDir[0] = 0;
if (SysDirLen = GetSystemDirectory(szSystemDir, MAX_PATH))
{
if (SysDirLen > MAX_PATH)
{
SysDirLen = 0;
szSystemDir[0] = 0;
}
else if (szSystemDir[SysDirLen - 1] != TEXT('\\'))
{
szSystemDir[SysDirLen] = TEXT('\\');
szSystemDir[SysDirLen + 1] = 0;
SysDirLen++;
}
}
do
{
//
// New language - get the language name, the language
// description, and the language id.
//
if (iLayoutBuff + 1 == nLayoutBuffSize)
{
HANDLE hTemp;
GlobalUnlock(hLayout);
nLayoutBuffSize += ALLOCBLOCK;
hTemp = GlobalReAlloc( hLayout,
nLayoutBuffSize * sizeof(LAYOUT),
GHND );
if (hTemp == NULL)
{
break;
}
hLayout = hTemp;
lpLayout = GlobalLock(hLayout);
}
lpLayout[iLayoutBuff].dwID = TransNum(szValue);
lstrcpy(szData, szLayoutPath);
lstrcat(szData, TEXT("\\"));
lstrcat(szData, szValue);
if (RegOpenKey(HKEY_LOCAL_MACHINE, szData, &hkey1) == ERROR_SUCCESS)
{
szValue[0] = TEXT('\0');
cb = sizeof(szValue);
if ((RegQueryValueEx( hkey1,
szLayoutFile,
NULL,
NULL,
(LPBYTE)szValue,
&cb ) == ERROR_SUCCESS) &&
(cb > sizeof(TCHAR)))
{
//
// Grab the layout, this one is a language only.
// NULL terminated string gives cb == sizeof(TCHAR), so
// we need to have the check.
//
lpLayout[iLayoutBuff].atmLayoutFile = AddAtom(szValue);
//
// See if the layout file exists already.
//
lpLayout[iLayoutBuff].bInstalled = FALSE;
lstrcpy(szSystemDir + SysDirLen, szValue);
if (FileExists(szSystemDir))
{
lpLayout[iLayoutBuff].bInstalled = TRUE;
}
szValue[0] = TEXT('\0');
cb = sizeof(szValue);
lpLayout[iLayoutBuff].iSpecialID = 0;
if (RegQueryValueEx( hkey1,
szLayoutText,
NULL,
NULL,
(LPBYTE)szValue,
&cb ) == ERROR_SUCCESS)
{
lpLayout[iLayoutBuff].atmLayoutText = AddAtom(szValue);
szValue[0] = TEXT('\0');
cb = sizeof(szValue);
#ifdef DBCS
if ((HIWORD(lpLayout[iLayoutBuff].dwID) & 0xf000) == 0xe000)
{
if (RegQueryValueEx( hkey1,
szIMEFile,
NULL,
NULL,
(LPBYTE)szValue,
&cb ) == ERROR_SUCCESS)
{
lpLayout[iLayoutBuff].atmIMEFile = AddAtom(szValue);
szValue[0] = TEXT('\0');
cb = sizeof(szValue);
iLayoutBuff++;
}
}
else
#endif
{
if (RegQueryValueEx( hkey1,
szLayoutID,
NULL,
NULL,
(LPBYTE)szValue,
&cb ) == ERROR_SUCCESS)
{
//
// This may not exist!
//
lpLayout[iLayoutBuff].iSpecialID =
(UINT)TransNum(szValue);
}
iLayoutBuff++;
}
}
}
RegCloseKey(hkey1);
}
dwIndex++;
szValue[0] = TEXT('\0');
dwRetVal = RegEnumKey( hKey,
dwIndex,
szValue,
sizeof(szValue) / sizeof(TCHAR) );
} while (dwRetVal == ERROR_SUCCESS);
RegCloseKey(hKey);
return (iLayoutBuff);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_LoadLocales
//
// Loads the locales from the registry.
//
////////////////////////////////////////////////////////////////////////////
BOOL Locale_LoadLocales(
HWND hwnd)
{
HKEY hKey;
DWORD cch;
DWORD dwIndex;
LONG dwRetVal;
#ifdef DBCS
UINT i, j = 0;
#endif
TCHAR szValue[MAX_PATH]; // language id (number)
TCHAR szData[MAX_PATH]; // language name
if (!(hLang = GlobalAlloc(GHND, ALLOCBLOCK * sizeof(INPUTLANG))))
{
EnablePane(hwnd, FALSE, IDC_KBDL_DISABLED);
return (FALSE);
}
nLangBuffSize = ALLOCBLOCK;
iLangBuff = 0;
lpLang = GlobalLock(hLang);
//
// Now read all of the locales from the registry.
//
if (RegOpenKey(HKEY_LOCAL_MACHINE, szLocaleInfo, &hKey) != ERROR_SUCCESS)
{
EnablePane(hwnd, FALSE, IDC_KBDL_DISABLED);
return (FALSE);
}
dwIndex = 0;
cch = sizeof(szValue) / sizeof(TCHAR);
dwRetVal = RegEnumValue( hKey,
dwIndex,
szValue,
&cch,
NULL,
NULL,
NULL,
NULL );
if (dwRetVal != ERROR_SUCCESS)
{
EnablePane(hwnd, FALSE, IDC_KBDL_DISABLED);
RegCloseKey(hKey);
return (FALSE);
}
do
{
if ((cch > 1) && (cch < HKL_LEN))
{
//
// Check for cch > 1: an empty string will be enumerated,
// and will come back with cch == 1 for the null terminator.
//
// New language - get the language name, the language
// description, and the language id.
//
if ((iLangBuff + 1) == nLangBuffSize)
{
HANDLE hTemp;
GlobalUnlock(hLang);
nLangBuffSize += ALLOCBLOCK;
hTemp = GlobalReAlloc( hLang,
nLangBuffSize * sizeof(INPUTLANG),
GHND );
if (hTemp == NULL)
{
break;
}
hLang = hTemp;
lpLang = GlobalLock(hLang);
}
lpLang[iLangBuff].dwID = TransNum(szValue);
lpLang[iLangBuff].iUseCount = 0;
lpLang[iLangBuff].iNumCount = 0;
lpLang[iLangBuff].pNext = NULL;
//
// Get the full localized name of the language.
//
if (GetLocaleInfo( LOWORD(lpLang[iLangBuff].dwID),
LOCALE_SLANGUAGE,
szData,
MAX_PATH ))
{
lpLang[iLangBuff].atmLanguageName = AddAtom(szData);
iLangBuff++;
#ifdef DBCS
//
// We have a valid language, so now get the layout data.
//
for (i = j; i < iLayoutBuff; i++)
{
if (LOWORD(lpLayout[i].dwID) ==
LOWORD(lpLang[iLangBuff - 1].dwID) &&
(HIWORD(lpLayout[i].dwID) & 0xf000) == 0xe000)
{
lpLang[iLangBuff - 1].wStatus |= LANG_IME;
lpLang[iLangBuff - 1].hkl = (HKL)lpLayout[i].dwID;
lpLang[iLangBuff - 1].iLayout = i;
break;
}
}
for (j = i + 1; j < iLayoutBuff; j++)
{
if ((HIWORD(lpLayout[j].dwID) & 0xf000) == 0xe000 &&
LOWORD(lpLayout[j].dwID) ==
LOWORD(lpLang[iLangBuff - 1].dwID))
{
break;
}
}
//
// See if there are more IME layouts for this language.
//
if (j < iLayoutBuff)
{
continue;
}
else
{
j = 0;
}
#endif
}
}
dwIndex++;
cch = sizeof(szValue) / sizeof(TCHAR);
szValue[0] = TEXT('\0');
dwRetVal = RegEnumValue( hKey,
dwIndex,
szValue,
&cch,
NULL,
NULL,
NULL,
NULL );
} while (dwRetVal == ERROR_SUCCESS);
RegCloseKey(hKey);
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_GetActiveLocales
//
// Gets the active locales.
//
////////////////////////////////////////////////////////////////////////////
BOOL Locale_GetActiveLocales(
HWND hwnd)
{
HKL *pLangs;
UINT nLangs, i, j, k, id;
HWND hwndList = GetDlgItem(hwnd, IDC_KBDL_LOCALE_LIST);
HKL hklSystem;
int idxListBox;
DWORD langLay;
HANDLE hLangNode;
LPLANGNODE pLangNode;
//
// Initialize US layout option.
//
iUsLayout = -1;
//
// Get the active keyboard layout list from the system.
//
if (!SystemParametersInfo( SPI_GETDEFAULTINPUTLANG,
0,
(LPVOID)((LPDWORD)&hklSystem),
0 ))
{
hklSystem = GetKeyboardLayout(0);
}
nLangs = GetKeyboardLayoutList(0, NULL);
if (nLangs == 0)
{
EnablePane(hwnd, FALSE, IDC_KBDL_DISABLED);
return (FALSE);
}
pLangs = (HKL *)LocalAlloc(LPTR, sizeof(DWORD) * nLangs);
GetKeyboardLayoutList(nLangs, (HKL *)pLangs);
#ifdef DBCS
himIndicators = ImageList_Create( GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
TRUE,
0,
0 );
#endif
//
// Replace default with US (default).
//
for (i = 0; i < iLayoutBuff; i++)
{
if (lpLayout[i].dwID == US_LOCALE)
{
iUsLayout = i;
break;
}
}
if (i == iLayoutBuff)
{
EnablePane(hwnd, FALSE, IDC_KBDL_DISABLED);
return (FALSE);
}
//
// Get the active keyboard information and put it in the internal
// language structure.
//
for (j = 0; j < nLangs; j++)
{
for (i = 0; i < iLangBuff; i++)
{
if (LOWORD(pLangs[j]) == LOWORD(lpLang[i].dwID))
{
//
// Found a match.
//
#ifdef DBCS
if (lpLang[i].wStatus & LANG_IME)
{
if (lpLang[i].hkl == pLangs[j])
{
idxListBox = ListBox_AddItemData(hwndList, i);
lpLang[i].wStatus |= (LANG_ORIGACTIVE | LANG_ACTIVE);
FetchIndicator(pLangNode);
}
else
{
continue;
}
}
else
#endif
{
//
// Create a node for this language.
//
pLangNode = Locale_AddToLinkedList(i, pLangs[j]);
if (!pLangNode)
{
EnablePane(hwnd, FALSE, IDC_KBDL_DISABLED);
return (FALSE);
}
//
// Add the item data to the list box, mark the
// language as original and active, save the pointer
// to the match in the layout list, and get the
// 2 letter indicator symbol.
//
idxListBox = ListBox_AddItemData(hwndList, pLangNode);
pLangNode->wStatus |= (LANG_ORIGACTIVE | LANG_ACTIVE);
pLangNode->hkl = pLangs[j];
pLangNode->hklUnload = pLangs[j];
FetchIndicator(pLangNode);
//
// Match the language to the layout.
//
pLangNode->iLayout = 0;
langLay = (DWORD)HIWORD(pLangs[j]);
if ((HIWORD(pLangs[j]) == 0xffff) ||
(HIWORD(pLangs[j]) == 0xfffe))
{
//
// Mark default or previous error as US - this
// means that the layout will be that of the basic
// keyboard driver (the US one).
//
pLangNode->wStatus |= LANG_CHANGED;
pLangNode->iLayout = iUsLayout;
langLay = 0;
}
else if ((HIWORD(pLangs[j]) & 0xf000) == 0xf000)
{
//
// Layout is special, need to search for the ID
// number.
//
id = HIWORD(pLangs[j]) & 0x0fff;
for (k = 0; k < iLayoutBuff; k++)
{
if (id == lpLayout[k].iSpecialID)
{
pLangNode->iLayout = k;
langLay = 0;
break;
}
}
if (langLay)
{
//
// Didn't find the id, so reset to basic for
// the language.
//
langLay = (DWORD)LOWORD(pLangs[j]);
}
}
if (langLay)
{
//
// Search for the id.
//
for (k = 0; k < iLayoutBuff; k++)
{
if (langLay == (DWORD)LOWORD(lpLayout[k].dwID))
{
pLangNode->iLayout = k;
break;
}
}
if (k == iLayoutBuff)
{
//
// Something went wrong or didn't load from
// the registry correctly.
//
MessageBeep(MB_ICONEXCLAMATION);
pLangNode->wStatus |= LANG_CHANGED;
pLangNode->iLayout = iUsLayout;
}
}
}
//
// If this is the current language, then it's the default
// one.
//
if (pLangNode->hkl == hklSystem)
{
TCHAR sz[DESC_MAX];
LPINPUTLANG pInpLang = &lpLang[i];
//
// Found the default. Set the Default input locale
// text in the property sheet.
//
#ifdef DBCS
if (pLangNode->wStatus & LANG_IME)
{
GetAtomName( lpLayout[pLangNode->iLayout].atmLayoutText,
sz,
DESC_MAX );
}
else
#endif
GetAtomName(pInpLang->atmLanguageName, sz, DESC_MAX);
pLangNode->wStatus |= LANG_DEFAULT;
ListBox_SetCurSel( GetDlgItem(hwnd, IDC_KBDL_LOCALE_LIST),
idxListBox );
SetDlgItemText(hwnd, IDC_KBDL_DEFAULT, sz);
}
//
// Break out of inner loop - we've found it.
//
break;
}
}
}
LocalFree((HANDLE)pLangs);
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_InitPropSheet
//
// Processing for a WM_INITDIALOG message for the Input Locales
// property sheet.
//
////////////////////////////////////////////////////////////////////////////
void Locale_InitPropSheet(
HWND hwnd)
{
HKEY hKey;
HANDLE hlib;
#ifdef DBCS
HWND hwndList;
LPLANGNODE pLangNode;
WORD wLangID;
#endif
//
// See if there are any other instances of this property page.
// If so, disable this page.
//
if (g_hMutex && (WaitForSingleObject(g_hMutex, 0) != WAIT_OBJECT_0))
{
EnablePane(hwnd, FALSE, IDC_KBDL_DISABLED_2);
return;
}
else
{
EnablePane(hwnd, TRUE, 0);
}
//
// See if the user has Administrative privileges by checking for
// write permission to the registry key.
//
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
szLocaleInfo,
0L,
KEY_WRITE,
&hKey ) == ERROR_SUCCESS)
{
//
// We can write to the HKEY_LOCAL_MACHINE key, so the user
// has Admin privileges.
//
g_bAdmin_Privileges = TRUE;
RegCloseKey(hKey);
}
else
{
//
// The user does not have admin privileges.
//
g_bAdmin_Privileges = FALSE;
}
//
// Initialize all of the global variables.
//
if ((!Locale_LoadLayouts(hwnd)) ||
(!Locale_LoadLocales(hwnd)) ||
(!Locale_GetActiveLocales(hwnd)))
{
return;
}
cxIcon = GetSystemMetrics(SM_CXSMICON);
cyIcon = GetSystemMetrics(SM_CYSMICON);
GetKbdSwitchHotkey(hwnd);
bSwitchChange = FALSE;
bDefaultChange = FALSE;
//
// See how many active keyboard layouts are in the input locale list.
//
if (ListBox_GetCount(GetDlgItem(hwnd, IDC_KBDL_LOCALE_LIST)) < 2)
{
//
// Only 1 active keyboard, so disable the secondary controls.
//
SetSecondaryControls(hwnd, FALSE);
#ifdef DBCS
hwndList = GetDlgItem(hwnd, IDC_KBDL_LOCALE_LIST);
pLangNode = (LPLANGNODE)ListBox_GetItemData(hwndList, 0);
wLangID = LOWORD(pLangNode->hkl);
if (wLangID = 0x0404 || wLangID == 0x0411 ||
wLangID == 0x0412 || wLangID == 0x0804)
{
//
// Enable the indicator symbol check box and check it.
//
EnableWindow(GetDlgItem(hwnd, IDC_KBDL_INDICATOR), TRUE);
CheckDlgButton( hwnd,
IDC_KBDL_INDICATOR,
FindWindow(szIndicator, NULL) != NULL );
}
#endif
}
else
{
//
// Set the indicator symbol check box to the "checked" state
// if the check box is enabled.
//
CheckDlgButton( hwnd,
IDC_KBDL_INDICATOR,
FindWindow(szIndicator, NULL) != NULL );
}
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_CommandConfigIME
//
// Configures the IME.
//
////////////////////////////////////////////////////////////////////////////
#ifdef DBCS
void Locale_CommandConfigIME(
HWND hwnd)
{
LPLANGNODE pLangNode;
int idxList;
HWND hwndList = GetDlgItem(hwnd, IDC_KBDL_LOCALE_LIST);
if ((idxList = ListBox_GetCurSel(hwndList)) == LB_ERR)
{
MessageBeep(MB_ICONEXCLAMATION);
return;
}
pLangNode = (LPLANGNODE)ListBox_GetItemData(hwndList, idxList);
if ((!(pLangNode->wStatus & LANG_IME)) ||
(!(pLangNode->wStatus & LANG_ORIGACTIVE)))
{
MessageBeep(MB_ICONEXCLAMATION);
return;
}
ImmConfigureIME(pLangNode->hkl, hwnd, IME_CONFIG_GENERAL, NULL);
}
#endif
////////////////////////////////////////////////////////////////////////////
//
// Locale_DrawItem
//
// Processing for a WM_DRAWITEM message.
//
////////////////////////////////////////////////////////////////////////////
BOOL Locale_DrawItem(
HWND hwnd,
LPDRAWITEMSTRUCT lpdi)
{
switch (lpdi->CtlID)
{
#ifdef ON_SCREEN_KEYBOARD
case ( IDC_KBDL_UP ) :
case ( IDC_KBDL_DOWN ) :
{
UINT wFlags;
wFlags = ((lpdi->CtlID == IDC_KBDL_UP)
? DFCS_SCROLLUP
: DFCS_SCROLLDOWN);
if (lpdi->itemState & ODS_SELECTED)
{
wFlags |= DFCS_PUSHED;
}
else if (lpdi->itemState & ODS_DISABLED)
{
wFlags |= DFCS_INACTIVE;
}
DrawFrameControl(lpdi->hDC, &lpdi->rcItem, DFC_SCROLL, wFlags);
break;
}
#endif
case ( IDC_KBDL_LOCALE_LIST ) :
{
LPLANGNODE pLangNode;
LPINPUTLANG pInpLang;
TCHAR sz[DESC_MAX];
UINT len;
DWORD rgbBk;
DWORD rgbText;
UINT oldAlign;
RECT rc;
if (ListBox_GetCount(lpdi->hwndItem) == 0)
{
break;
}
pLangNode = (LPLANGNODE)lpdi->itemData;
pInpLang = &lpLang[pLangNode->iLang];
rgbBk = SetBkColor( lpdi->hDC,
(lpdi->itemState & ODS_SELECTED)
? GetSysColor(COLOR_HIGHLIGHT)
: GetSysColor(COLOR_WINDOW) );
rgbText = SetTextColor( lpdi->hDC,
(lpdi->itemState & ODS_SELECTED)
? GetSysColor(COLOR_HIGHLIGHTTEXT)
: GetSysColor(COLOR_WINDOWTEXT) );
len = GetAtomName(pInpLang->atmLanguageName, sz, DESC_MAX);
ExtTextOut( lpdi->hDC,
lpdi->rcItem.left+cyIcon+ 3 * LIST_MARGIN + 2,
lpdi->rcItem.top + (cyListItem - cyText) / 2,
ETO_OPAQUE,
&lpdi->rcItem,
sz,
len,
NULL );
oldAlign = GetTextAlign(lpdi->hDC);
SetTextAlign(lpdi->hDC, TA_RIGHT | (oldAlign & ~TA_CENTER));
len = GetAtomName( lpLayout[pLangNode->iLayout].atmLayoutText,
sz,
DESC_MAX );
ExtTextOut( lpdi->hDC,
lpdi->rcItem.right - LIST_MARGIN,
lpdi->rcItem.top + (cyListItem - cyText) / 2,
0,
NULL,
sz,
len,
NULL );
SetTextAlign(lpdi->hDC, oldAlign);
if (!(pLangNode->wStatus & ICON_LOADED))
{
FetchIndicator(pLangNode);
}
#ifdef DBCS
if ((himIndicators != NULL) &&
(pLangNode->wStatus & LANG_IME) &&
(pLangNode->niconIME != -1))
{
ImageList_Draw( himIndicators,
pLangNode->niconIME,
lpdi->hDC,
lpdi->rcItem.left + 3 * LIST_MARGIN,
lpdi->rcItem.top + LIST_MARGIN,
ILD_TRANSPARENT );
}
else
#endif
{
rgbBk = SetBkColor( lpdi->hDC,
(lpdi->itemState & ODS_SELECTED)
? GetSysColor(COLOR_WINDOW)
: GetSysColor(COLOR_HIGHLIGHT) );
rgbText = SetTextColor( lpdi->hDC,
(lpdi->itemState & ODS_SELECTED)
? GetSysColor(COLOR_WINDOWTEXT)
: GetSysColor(COLOR_HIGHLIGHTTEXT) );
rc.left = lpdi->rcItem.left + 3 * LIST_MARGIN;
rc.right = rc.left + cxIcon;
rc.top = lpdi->rcItem.top + LIST_MARGIN;
rc.bottom = rc.top + cyIcon;
ExtTextOut( lpdi->hDC,
rc.left,
rc.top,
ETO_OPAQUE,
&rc,
TEXT(""),
0,
NULL );
DrawText( lpdi->hDC,
pInpLang->szSymbol,
2,
&rc,
DT_CENTER | DT_VCENTER | DT_SINGLELINE );
}
SetBkColor(lpdi->hDC, rgbBk);
SetTextColor(lpdi->hDC, rgbText);
if (lpdi->itemState & ODS_FOCUS)
{
DrawFocusRect(lpdi->hDC, &lpdi->rcItem);
}
break;
}
default :
{
return (FALSE);
}
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_KillPaneDialog
//
// Processing for a WM_DESTROY message.
//
////////////////////////////////////////////////////////////////////////////
void Locale_KillPaneDialog(
HWND hwnd)
{
UINT i;
HANDLE hCur;
LPLANGNODE pCur;
//
// Delete all Language Name atoms and free the lpLang array.
//
for (i = 0; i < iLangBuff; i++)
{
if (lpLang[i].atmLanguageName)
{
DeleteAtom(lpLang[i].atmLanguageName);
}
pCur = lpLang[i].pNext;
lpLang[i].pNext = NULL;
while (pCur)
{
hCur = pCur->hLangNode;
pCur = pCur->pNext;
GlobalUnlock(hCur);
GlobalFree(hCur);
}
}
#ifdef DBCS
if (himIndicators != NULL)
{
ImageList_Destroy(himIndicators);
}
#endif
GlobalUnlock(hLang);
GlobalFree(hLang);
//
// Delete all layout text and layout file atoms and free the
// lpLayout array.
//
for (i = 0; i < iLayoutBuff; i++)
{
if (lpLayout[i].atmLayoutText)
{
DeleteAtom(lpLayout[i].atmLayoutText);
}
if (lpLayout[i].atmLayoutFile)
{
DeleteAtom(lpLayout[i].atmLayoutFile);
}
#ifdef DBCS
if (lpLayout[i].atmIMEFile)
{
DeleteAtom(lpLayout[i].atmIMEFile);
}
#endif
}
GlobalUnlock(hLayout);
GlobalFree(hLayout);
if (g_hMutex)
{
ReleaseMutex(g_hMutex);
}
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_MeasureItem
//
// Processing for a WM_MEASUREITEM message.
//
////////////////////////////////////////////////////////////////////////////
void Locale_MeasureItem(
HWND hwnd,
LPMEASUREITEMSTRUCT lpmi)
{
HFONT hfont;
HDC hdc;
TEXTMETRIC tm;
switch (lpmi->CtlID)
{
case ( IDC_KBDL_LOCALE_LIST ) :
{
hfont = (HFONT) SendMessage(hwnd, WM_GETFONT, 0, 0);
hdc = GetDC(NULL);
hfont = SelectObject(hdc, hfont);
GetTextMetrics(hdc, &tm);
SelectObject(hdc, hfont);
ReleaseDC(NULL, hdc);
cyText = tm.tmHeight;
lpmi->itemHeight = cyListItem =
MAX(cyText, GetSystemMetrics(SM_CYSMICON)) + 2 * LIST_MARGIN;
break;
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_CommandAddEdit
//
// Invokes either the Add dialog or the Properties dialog.
//
// Returns 1 if a dialog box was invoked and the dialog returned IDOK.
// Otherwise, it returns 0.
//
////////////////////////////////////////////////////////////////////////////
int Locale_CommandAddEdit(
HWND hwnd,
UINT iRes,
LPLANGNODE pLangNode,
FARPROC lpfnDlg)
{
DLGPROC lpDialog;
HWND hwndList;
int idxList;
UINT nList;
int rc = 0;
INITINFO InitInfo;
//
// Initialize hwndList and pLangNode.
//
if (pLangNode == NULL)
{
hwndList = GetDlgItem(hwnd, IDC_KBDL_LOCALE_LIST);
if (hwndList == NULL)
{
return (0);
}
idxList = ListBox_GetCurSel(hwndList);
pLangNode = (LPLANGNODE)ListBox_GetItemData(hwndList, idxList);
}
else
{
hwndList = GetDlgItem(hwnd, IDC_KBDLA_LOCALE);
if (hwndList == NULL)
{
return (0);
}
idxList = ListBox_GetCurSel(hwndList);
}
//
// Make sure we haven't added all possible combinations to the system.
//
if (iRes == DLG_KEYBOARD_LOCALE_ADD)
{
nList = ListBox_GetCount(hwndList);
if (nList == (iLangBuff * iLayoutBuff))
{
//
// No languages left!
//
ErrorMsg(hwnd, IDS_ML_NOMORETOADD);
return (rc);
}
}
//
// Bring up the appropriate dialog box.
//
if ((pLangNode != (LPLANGNODE)LB_ERR) && (pLangNode != NULL))
{
lpDialog = (DLGPROC)MakeProcInstance(lpfnDlg, hInstance);
#ifdef DBCS
if ((pLangNode->wStatus & LANG_IME) &&
(iRes == DLG_KEYBOARD_LOCALE_EDIT))
{
Locale_CommandConfigIME(hwnd);
}
else
#endif
{
//
// Return value can be 1:IDOK, 2:IDCANCEL or -1:Error (from USER)
//
// If adding a language, it goes at the end of the list, so get
// the end and make that the current selection.
//
InitInfo.hwndMain = hwnd;
InitInfo.pLangNode = pLangNode;
if ((rc = DialogBoxParam( hInstance,
MAKEINTRESOURCE(iRes),
hwnd,
lpDialog,
(LPARAM)(&InitInfo) )) == IDOK)
{
//
// See if it's the Add dialog box.
//
if (iRes == DLG_KEYBOARD_LOCALE_ADD)
{
//
// Get the number of items in the input locale list and
// enable the Properties and Remove push buttons.
//
nList = ListBox_GetCount(hwndList) - 1;
EnableWindow(GetDlgItem(hwnd, IDC_KBDL_EDIT), TRUE);
EnableWindow(GetDlgItem(hwnd, IDC_KBDL_DELETE), TRUE);
//
// Set the current selection to be the last one in the
// list (the one that was just added).
//
ListBox_SetCurSel(hwndList, nList);
#ifdef DBCS
pLangNode = (LPLANGNODE)ListBox_GetItemData(hwndList, nList);
if (pLangNode->wStatus & LANG_IME)
{
EnableWindow(GetDlgItem(hwnd, IDC_KBDL_EDIT), FALSE);
}
#endif
}
else
{
//
// Reset the current selection to be the one that was
// previously set.
//
ListBox_SetCurSel(hwndList, idxList);
}
//
// Enable the Apply button.
//
PropSheet_Changed(GetParent(hwnd), hwnd);
}
else
{
//
// Failure, so need to return 0.
//
ListBox_SetCurSel(hwndList, idxList);
rc = 0;
}
}
FreeProcInstance((FARPROC)lpDialog);
}
else
{
MessageBeep(MB_ICONEXCLAMATION);
}
return (rc);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_CommandLocaleList
//
// Handles changes to the input locales list box in the property sheet.
//
////////////////////////////////////////////////////////////////////////////
void Locale_CommandLocaleList(
HWND hwnd,
WPARAM wParam,
LPARAM lParam)
{
#ifdef DBCS
HWND hwndList = (HWND)LOWORD(lParam);
LPLANGNODE pLangNode;
BOOL bOn;
if (HIWORD(wParam) == LBN_SELCHANGE || HIWORD(wParam) == LBN_SETFOCUS)
{
pLangNode = (LPLANGNODE)ListBox_GetItemData( hwndList,
ListBox_GetCurSel(hwndList) );
bOn = (pLangNode->wStatus & LANG_IME) &&
(!(pLangNode->wStatus & LANG_ORIGACTIVE)) ? FALSE : TRUE;
EnableWindow(GetDlgItem(hwnd, IDC_KBDL_EDIT), bOn);
}
else
#endif
if (HIWORD(wParam) == LBN_DBLCLK)
{
//
// User double clicked on an input locale. Invoke the Properties
// dialog.
//
Locale_CommandAddEdit( hwnd,
DLG_KEYBOARD_LOCALE_EDIT,
NULL,
(FARPROC)KbdLocaleEditDlg);
}
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_CommandSetDefault
//
// Sets the new default when the Set as Default button is pressed.
//
////////////////////////////////////////////////////////////////////////////
void Locale_CommandSetDefault(
HWND hwnd)
{
UINT idx;
int idxList;
LPLANGNODE pLangNode;
HWND hwndList = GetDlgItem(hwnd, IDC_KBDL_LOCALE_LIST);
TCHAR sz[DESC_MAX];
if ((idxList = ListBox_GetCurSel(hwndList)) == LB_ERR)
{
MessageBeep(MB_ICONEXCLAMATION);
return;
}
//
// Remove the LANG_DEFAULT flag from the current default.
//
pLangNode = NULL;
for (idx = 0; idx < iLangBuff; idx++)
{
pLangNode = lpLang[idx].pNext;
while (pLangNode != NULL)
{
if (pLangNode->wStatus & LANG_DEFAULT)
{
if (pLangNode ==
(LPLANGNODE)ListBox_GetItemData(hwndList, idxList))
{
return;
}
pLangNode->wStatus &= ~(LANG_DEFAULT | LANG_DEF_CHANGE);
break;
}
pLangNode = pLangNode->pNext;
}
if (pLangNode != NULL)
{
break;
}
}
//
// Mark the current selection as the new default.
//
pLangNode = (LPLANGNODE)ListBox_GetItemData(hwndList, idxList);
pLangNode->wStatus |= (LANG_DEFAULT | LANG_DEF_CHANGE);
//
// Update the "Default input locale" text in the dialog.
//
#ifdef DBCS
if ((pLangNode->wStatus & LANG_IME) != 0)
{
GetAtomName(lpLayout[pLangNode->iLayout].atmLayoutText, sz, DESC_MAX);
}
else
#endif
GetAtomName(lpLang[pLangNode->iLang].atmLanguageName, sz, DESC_MAX);
SetDlgItemText(hwnd, IDC_KBDL_DEFAULT, sz);
//
// Enable the Apply button.
//
bDefaultChange = TRUE;
PropSheet_Changed(GetParent(hwnd), hwnd);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_CommandDelete
//
// Removes the currently selected input locale from the list.
//
////////////////////////////////////////////////////////////////////////////
void Locale_CommandDelete(
HWND hwnd)
{
LPLANGNODE pLangNode;
int idxList;
HWND hwndList = GetDlgItem(hwnd, IDC_KBDL_LOCALE_LIST);
int count;
#ifdef DBCS
WORD wLangID;
#endif
//
// Get the current selection in the input locale list.
//
if ((idxList = ListBox_GetCurSel(hwndList)) == LB_ERR)
{
MessageBeep(MB_ICONEXCLAMATION);
return;
}
//
// Make sure we're not removing the only entry in the list.
//
if (ListBox_GetCount(hwndList) == 1)
{
MessageBeep(MB_ICONEXCLAMATION);
return;
}
//
// Get the pointer to the lang node from the list box
// item data.
//
pLangNode = (LPLANGNODE)ListBox_GetItemData(hwndList, idxList);
//
// Set the input locale to be not active and show that its state
// has changed. Also, delete the string from the input locale list
// in the property sheet.
//
// Decrement the number of nodes for this input locale.
//
pLangNode->wStatus &= ~LANG_ACTIVE;
pLangNode->wStatus |= LANG_CHANGED;
ListBox_DeleteString(hwndList, idxList);
lpLang[pLangNode->iLang].iNumCount--;
//
// See how many entries are left in the input locale list box.
//
if (count = ListBox_GetCount(hwndList))
{
//
// Set the new current selection.
//
ListBox_SetCurSel(hwndList, (count <= idxList) ? (count - 1) : idxList);
//
// See if there is only one entry left in the list.
//
if (count < 2)
{
//
// Only 1 entry in list. Disable the secondary controls.
//
SetSecondaryControls(hwnd, FALSE);
#ifdef DBCS
pLangNode = (LPLANGNODE)ListBox_GetItemData(hwndList, 0);
wLangID = LOWORD(pLangNode->hkl);
if (wLangID == 0x0404 || wLangID == 0x0411 ||
wLangID == 0x0412 || wLangID == 0x0804)
{
EnableWindow(GetDlgItem(hwnd, IDC_KBDL_INDICATOR), TRUE);
CheckDlgButton( hwnd,
IDC_KBDL_INDICATOR,
FindWindow(szIndicator, NULL) != NULL );
}
#endif
}
}
else
{
//
// No entries left. Disable the secondary controls.
// This should never happen since we check for this above.
//
SetSecondaryControls(hwnd, FALSE);
}
//
// If it was the default input locale, change the default to something
// else.
//
if (pLangNode->wStatus & LANG_DEFAULT)
{
pLangNode->wStatus &= ~LANG_DEFAULT;
Locale_CommandSetDefault(hwnd);
}
//
// If it wasn't originally active, then remove it from the list.
// There's nothing more to do with this node.
//
if (!(pLangNode->wStatus & LANG_ORIGACTIVE))
{
Locale_RemoveFromLinkedList(pLangNode);
}
//
// Enable the Apply button.
//
PropSheet_Changed(GetParent(hwnd), hwnd);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_UpdateActiveLocales
//
// Updates the active locales.
//
////////////////////////////////////////////////////////////////////////////
BOOL Locale_UpdateActiveLocales(
HWND hwnd)
{
HKL *pLangs;
UINT nLangs, i, j;
UINT iOldLayout;
HWND hwndList = GetDlgItem(hwnd, IDC_KBDL_LOCALE_LIST);
HKL hklSystem;
int idxListBox;
DWORD langLay;
BOOL bApply;
int iOldCount;
LPLANGNODE pDefault = NULL;
LPLANGNODE pLangNode, pTemp;
//
// See if the pane is disabled. If so, then there is nothing to
// update.
//
if (!IsWindowEnabled(hwndList))
{
return (TRUE);
}
//
// Clear out the combo box.
//
iOldCount = ListBox_GetCount(hwndList);
SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
//
// Get the active keyboard layout list from the system.
//
if (!SystemParametersInfo( SPI_GETDEFAULTINPUTLANG,
0,
(LPVOID)((LPDWORD)&hklSystem),
0 ))
{
hklSystem = GetKeyboardLayout(0);
}
nLangs = GetKeyboardLayoutList(0, NULL);
if (nLangs == 0)
{
EnablePane(hwnd, FALSE, IDC_KBDL_DISABLED);
return (FALSE);
}
pLangs = (HKL *)LocalAlloc(LPTR, sizeof(DWORD) * nLangs);
GetKeyboardLayoutList(nLangs, (HKL *)pLangs);
//
// Mark all of the Original & Active entries with the LANG_UPDATE
// value so that these can be added to the list if they were deleted
// from the original list by another process.
//
for (i = 0; i < iLangBuff; i++)
{
pLangNode = lpLang[i].pNext;
while (pLangNode)
{
if ((pLangNode->wStatus & LANG_ORIGACTIVE) &&
(pLangNode->wStatus & LANG_ACTIVE))
{
pLangNode->wStatus |= LANG_UPDATE;
}
if ((pLangNode->wStatus & LANG_DEFAULT) &&
(pLangNode->wStatus & LANG_DEF_CHANGE))
{
pDefault = pLangNode;
}
pLangNode = pLangNode->pNext;
}
}
//
// Get the active keyboard information and put it in the internal
// language structure.
//
for (j = 0; j < nLangs; j++)
{
for (i = 0; i < iLangBuff; i++)
{
if (LOWORD(pLangs[j]) == LOWORD(lpLang[i].dwID))
{
//
// Found a match.
//
#ifdef DBCS
if ((pLangNode->wStatus & LANG_IME) &&
(pLangNode->hkl != pLangs[j]))
{
continue;
}
#endif
//
// Find the correct entry for the hkl.
//
pLangNode = lpLang[i].pNext;
while (pLangNode)
{
if (pLangNode->hkl == pLangs[j])
{
break;
}
pLangNode = pLangNode->pNext;
}
if (pLangNode == NULL)
{
pLangNode = Locale_AddToLinkedList(i, pLangs[j]);
if (!pLangNode)
{
continue;
}
}
//
// Make sure it wasn't one that was removed by the user
// before the Apply button was hit.
//
if ((pLangNode->wStatus & LANG_ORIGACTIVE) &&
(!(pLangNode->wStatus & LANG_ACTIVE)))
{
if ((pLangNode->hkl == hklSystem) &&
(!pDefault || (pLangNode == pDefault)))
{
//
// Override the user's removal if it is now the
// system default.
//
pLangNode->wStatus |= LANG_ACTIVE;
pLangNode->wStatus &= ~LANG_CHANGED;
lpLang[i].iNumCount++;
}
else
{
//
// Want to break out of the inner loop so that this
// one won't be added to the list.
//
break;
}
}
//
// Add the item data to the list box, mark the
// language as original and active, save the pointer
// to the match in the layout list, and get the
// 2 letter indicator symbol.
//
idxListBox = ListBox_AddItemData(hwndList, pLangNode);
pLangNode->wStatus |= (LANG_ORIGACTIVE | LANG_ACTIVE);
pLangNode->wStatus &= ~LANG_UPDATE;
pLangNode->hkl = pLangs[j];
pLangNode->hklUnload = pLangs[j];
FetchIndicator(pLangNode);
//
// Save the iLayout value to see if it's changed.
//
iOldLayout = pLangNode->iLayout;
//
// Match the language to the layout.
// The hiword of pLangs[j] is the layout id.
//
pLangNode->iLayout = 0;
langLay = (DWORD)HIWORD(pLangs[j]);
if ((HIWORD(pLangs[j]) == 0xffff) ||
(HIWORD(pLangs[j]) == 0xfffe))
{
//
// Mark default or previous error as US - this
// means that the layout will be that of the basic
// keyboard driver (the US one).
//
pLangNode->wStatus |= LANG_CHANGED;
pLangNode->iLayout = iUsLayout;
langLay = 0;
}
else if ((HIWORD(pLangs[j]) & 0xf000) == 0xf000)
{
//
// Layout is special, need to search for the ID
// number.
//
UINT k;
UINT id;
id = HIWORD(pLangs[j]) & 0x0fff;
for (k = 0; k < iLayoutBuff; k++)
{
if (id == lpLayout[k].iSpecialID)
{
pLangNode->iLayout = k;
langLay = 0;
break;
}
}
if (langLay)
{
//
// Didn't find the id, so reset to basic for
// the language.
//
langLay = (DWORD)LOWORD(pLangs[j]);
}
}
if (langLay)
{
UINT k;
for (k = 0; k < iLayoutBuff; k++)
{
if (langLay == (DWORD)LOWORD(lpLayout[k].dwID))
{
pLangNode->iLayout = k;
break;
}
}
if (k == iLayoutBuff)
{
//
// Something went wrong or didn't load from
// the registry correctly.
//
MessageBeep(MB_ICONEXCLAMATION);
pLangNode->wStatus |= LANG_CHANGED;
pLangNode->iLayout = iUsLayout;
}
}
//
// See if the user changed the layout.
//
if ((pLangNode->wStatus & LANG_OAC) == LANG_OAC)
{
if ((pLangNode->iLayout == iOldLayout) ||
((pLangNode->hkl == hklSystem) &&
(!(pLangNode->wStatus & LANG_DEFAULT))))
{
pLangNode->wStatus &= ~LANG_CHANGED;
}
else
{
pLangNode->iLayout = iOldLayout;
}
}
//
// If this is the current language, then it's the default
// one.
//
if ((pLangNode == pDefault) ||
((pLangNode->hkl == hklSystem) && !pDefault))
{
TCHAR sz[DESC_MAX];
//
// Found the default. Set the Default input locale
// text in the property sheet.
//
#ifdef DBCS
if (pLangNode->wStatus & LANG_IME)
{
GetAtomName( lpLayout[pLangNode->iLayout].atmLayoutText,
sz,
DESC_MAX );
}
else
#endif
GetAtomName(lpLang[i].atmLanguageName, sz, DESC_MAX);
pLangNode->wStatus |= LANG_DEFAULT;
if (pLangNode->hkl == hklSystem)
{
pLangNode->wStatus &= ~LANG_DEF_CHANGE;
bDefaultChange = FALSE;
}
pDefault = pLangNode;
ListBox_SetCurSel( GetDlgItem(hwnd, IDC_KBDL_LOCALE_LIST),
idxListBox );
SetDlgItemText(hwnd, IDC_KBDL_DEFAULT, sz);
}
//
// Break out of inner loop - we've found it.
//
break;
}
}
}
//
// Need to see if any items are marked to be updated, if any were
// added to the list before the Apply button was hit, and if
// the default has changed.
//
bApply = FALSE;
for (i = 0; i < iLangBuff; i++)
{
lpLang[i].iNumCount = 0;
pLangNode = lpLang[i].pNext;
while (pLangNode)
{
//
// See if this item is an update item.
//
if (pLangNode->wStatus & LANG_UPDATE)
{
pLangNode->wStatus = 0;
}
//
// See if this item needs to be added to the combo box.
//
else if ((pLangNode->wStatus & LANG_ACTIVE) &&
(!(pLangNode->wStatus & LANG_ORIGACTIVE)))
{
//
// In this case, the Apply button should already be enabled.
//
ListBox_AddItemData(hwndList, pLangNode);
FetchIndicator(pLangNode);
}
//
// See if the default has changed.
//
if ((pLangNode->wStatus & LANG_DEFAULT) &&
(pDefault) && (pLangNode != pDefault))
{
pLangNode->wStatus &= ~LANG_DEFAULT;
}
//
// See if the Apply button should be enabled or disabled.
//
if (pLangNode->wStatus & LANG_CHANGED)
{
bApply = TRUE;
}
//
// Advance the pointer.
//
if (pLangNode->wStatus == 0)
{
//
// Remove the node - it's no longer needed.
//
pTemp = pLangNode;
pLangNode = pLangNode->pNext;
Locale_RemoveFromLinkedList(pTemp);
}
else
{
//
// Increment the active count.
//
if (pLangNode->wStatus & LANG_ACTIVE)
{
(lpLang[i].iNumCount)++;
}
pLangNode = pLangNode->pNext;
}
}
}
//
// See if the user specifically changed the "Switch locales" choice
// or the "Enable indicator on taskbar" check box.
//
if (bSwitchChange || bDefaultChange)
{
bApply = TRUE;
}
//
// Enable or Disable the Apply button.
//
SendMessage( GetParent(hwnd),
bApply ? PSM_CHANGED : PSM_UNCHANGED,
(WPARAM)hwnd,
0L );
//
// See if we need to enable the secondary controls.
//
if ((iOldCount < 2) && (ListBox_GetCount(hwndList) > 1))
{
//
// Enable the secondary controls.
//
SetSecondaryControls(hwnd, TRUE);
//
// Set the appropriate toggle key.
//
GetKbdSwitchHotkey(hwnd);
//
// See if the taskbar indicator should be on or off.
//
CheckDlgButton( hwnd,
IDC_KBDL_INDICATOR,
FindWindow(szIndicator, NULL) != NULL );
}
//
// Return success.
//
LocalFree((HANDLE)pLangs);
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// LocaleDlgProc
//
// This is the dialog proc for the Input Locales property sheet.
//
////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK LocaleDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case ( WM_DESTROY ) :
{
Locale_KillPaneDialog(hDlg);
break;
}
case ( WM_INITDIALOG ) :
{
Locale_InitPropSheet(hDlg);
break;
}
case ( WM_MEASUREITEM ) :
{
Locale_MeasureItem(hDlg, (LPMEASUREITEMSTRUCT)lParam);
break;
}
case ( WM_DRAWITEM ) :
{
return Locale_DrawItem(hDlg, (LPDRAWITEMSTRUCT)lParam);
}
case ( WM_ACTIVATE ) :
{
if (IsWindowEnabled(GetDlgItem(hDlg, IDC_KBDL_DISABLED_2)))
{
Locale_InitPropSheet(hDlg);
}
else
{
Locale_UpdateActiveLocales(hDlg);
}
break;
}
case ( WM_NOTIFY ) :
{
switch (((NMHDR *)lParam)->code)
{
case ( PSN_SETACTIVE ) :
{
if (IsWindowEnabled(GetDlgItem(hDlg, IDC_KBDL_DISABLED_2)))
{
Locale_InitPropSheet(hDlg);
}
else
{
Locale_UpdateActiveLocales(hDlg);
}
break;
}
case ( PSN_APPLY ) :
{
Locale_ApplyInputs(hDlg);
break;
}
default :
{
return (FALSE);
}
}
break;
}
case ( PSM_QUERYSIBLINGS ) :
{
Locale_UpdateActiveLocales(hDlg);
break;
}
case ( WM_COMMAND ) :
{
switch (LOWORD(wParam))
{
case ( IDC_KBDL_ALT_SHIFT ) :
case ( IDC_KBDL_CTRL_SHIFT ) :
case ( IDC_KBDL_NO_SHIFT ) :
case ( IDC_KBDL_INDICATOR ) :
{
//
// Care about these for "ApplyNow" only.
//
bSwitchChange = TRUE;
PropSheet_Changed(GetParent(hDlg), hDlg);
break;
}
case ( IDC_KBDL_LOCALE_LIST ) :
{
Locale_CommandLocaleList(hDlg, wParam, lParam);
break;
}
case ( IDC_KBDL_ADD ) :
{
Locale_CommandAddEdit( hDlg,
DLG_KEYBOARD_LOCALE_ADD,
NULL,
(FARPROC)KbdLocaleAddDlg );
break;
}
case ( IDC_KBDL_EDIT ) :
{
Locale_CommandAddEdit( hDlg,
DLG_KEYBOARD_LOCALE_EDIT,
NULL,
(FARPROC)KbdLocaleEditDlg);
break;
}
case ( IDC_KBDL_DELETE ) :
{
Locale_CommandDelete(hDlg);
break;
}
case ( IDC_KBDL_SET_DEFAULT ) :
{
Locale_CommandSetDefault(hDlg);
break;
}
case ( IDOK ) :
{
if (!Locale_ApplyInputs(hDlg))
{
break;
}
// fall thru...
}
case ( IDCANCEL ) :
{
EndDialog(hDlg, TRUE);
break;
}
default :
{
return (FALSE);
}
}
break;
}
case ( WM_HELP ) :
{
WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
NULL,
HELP_WM_HELP,
(DWORD)(LPTSTR)aLocaleHelpIds );
break;
}
case ( WM_CONTEXTMENU ) : // right mouse click
{
WinHelp( (HWND)wParam,
NULL,
HELP_CONTEXTMENU,
(DWORD)(LPTSTR)aLocaleHelpIds );
break;
}
default :
{
return (FALSE);
}
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_AddDlgInit
//
// Processing for a WM_INITDIALOG message for the Add dialog box.
//
////////////////////////////////////////////////////////////////////////////
void Locale_AddDlgInit(
HWND hwnd,
LPARAM lParam)
{
UINT i;
HWND hwndLang = GetDlgItem(hwnd, IDC_KBDLA_LOCALE);
UINT idx;
TCHAR sz[DESC_MAX];
//
// Go through all of the input locales. Display all of them,
// since we can have multiple layouts per locale.
//
// Do NOT go down the links in this case. We don't want to display
// the language choice multiple times.
//
for (i = 0; i < iLangBuff; i++)
{
//
// Make sure there are layouts to be added for this
// input locale.
//
if (lpLang[i].iNumCount != iLayoutBuff)
{
//
// Get the language name, add the string to the
// combo box, and set the index into the lpLang
// array as the item data.
//
#ifdef DBCS
if (lpLang[i].wStatus & LANG_IME)
{
GetAtomName( lpLayout[lpLang[i].iLayout].atmLayoutText,
sz,
DESC_MAX );
}
else
#endif
GetAtomName(lpLang[i].atmLanguageName, sz, DESC_MAX);
idx = ComboBox_AddString(hwndLang, sz);
ComboBox_SetItemData(hwndLang, idx, MAKELONG(i, 0));
}
}
//
// Set the current selection to the first one in the list.
//
ComboBox_SetCurSel(hwndLang, 0);
idx = (UINT)ComboBox_GetItemData(hwndLang, 0);
SetProp(hwnd, szPropHwnd, (HANDLE)((LPINITINFO)lParam)->hwndMain);
SetProp(hwnd, szPropIdx, (HANDLE)idx);
//
// Always check the "Use default properties" check box.
//
CheckDlgButton(hwnd, IDC_KBDLA_DEFAULT, BST_CHECKED);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_GetProperLayout
//
// Returns the offset to the layout selection that matches the given
// input locale selection.
//
// NOTE: This function will return -1 if the offset has already been
// used by the given input locale.
//
////////////////////////////////////////////////////////////////////////////
int Locale_GetProperLayout(
UINT idxLang)
{
DWORD dwID = lpLang[idxLang].dwID;
UINT i;
int idxusa = -1;
int idxBaseLang = -1;
int idxSel = -1;
int idxOther = -1;
UINT iBaseLang = (LOWORD(dwID) & 0xff) | 0x400;
LPLANGNODE pTemp;
//
// Search through all of the layouts to try to find a match.
//
for (i = 0; i < iLayoutBuff; i++)
{
if (lpLayout[i].dwID == US_LOCALE)
{
idxusa = i;
}
if (lpLayout[i].dwID == iBaseLang)
{
idxBaseLang = i;
}
if (LOWORD(lpLayout[i].dwID) == LOWORD(dwID))
{
if (HIWORD(lpLayout[i].dwID) == 0)
{
idxSel = i;
break;
}
else
{
idxOther = i;
}
}
}
//
// Take the best fit.
//
if (idxSel == -1)
{
if (idxOther != -1)
{
//
// Locale has nonstandard layout.
//
idxSel = idxOther;
}
else if (idxBaseLang != -1)
{
//
// Other locale in language has a layout, take that.
//
idxSel = idxBaseLang;
}
else if (idxusa != -1)
{
//
// We found the standard usa layout.
//
idxSel = idxusa;
}
else
{
//
// Found nothing, use first. (should never get here!)
//
idxSel = 0;
}
}
//
// Make sure this isn't a duplicate entry. If so, return -1.
//
pTemp = lpLang[idxLang].pNext;
while (pTemp)
{
if ((pTemp->wStatus & LANG_ACTIVE) &&
(pTemp->iLayout == (UINT)idxSel))
{
idxSel = -1;
break;
}
pTemp = pTemp->pNext;
}
//
// Return the selection.
//
return (idxSel);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_AddCommandOK
//
// Gets the currently selected input locale from the combo box and marks
// it as active in the lpLang list. It then gets the requested layout
// and sets that in the list. It then adds the new input locale string
// to the input locale list in the property sheet.
//
////////////////////////////////////////////////////////////////////////////
int Locale_AddCommandOK(
HWND hwnd)
{
HWND hwndLang = GetDlgItem(hwnd, IDC_KBDLA_LOCALE);
int idxLang = ComboBox_GetCurSel(hwndLang);
LPLANGNODE pLangNode;
HANDLE hLangNode;
//
// Get the offset for the language to add.
//
idxLang = (int)ComboBox_GetItemData(hwndLang, idxLang);
//
// Insert a new language node.
//
pLangNode = Locale_AddToLinkedList(idxLang, 0);
if (!pLangNode)
{
return (0);
}
#ifdef DBCS
if (pLangNode->wStatus & LANG_IME)
{
//
// IME. Add the new language.
//
if (!AddLanguage(GetProp(hwnd, szPropHwnd), pLangNode))
{
//
// Unable to add the language. Need to return the user back
// to the Add dialog.
//
Locale_RemoveFromLinkedList(pLangNode);
return (0);
}
return (1);
}
#endif
//
// Get the layout that best fits the current language.
//
pLangNode->iLayout = Locale_GetProperLayout(idxLang);
//
// See if the "Use default properties" button is still checked.
// If it's not, then bring up the Properties dialog.
//
if ((IsDlgButtonChecked(hwnd, IDC_KBDLA_DEFAULT) == BST_UNCHECKED) ||
(pLangNode->iLayout == (UINT)(-1)))
{
if (!Locale_CommandAddEdit( hwnd,
DLG_KEYBOARD_LOCALE_EDIT,
pLangNode,
(FARPROC)KbdLocaleEditDlg ))
{
//
// The user hit cancel in the properties dialog box or the
// properties dialog failed to be invoked. Need to return
// the user back to the Add dialog.
//
Locale_RemoveFromLinkedList(pLangNode);
return (0);
}
}
//
// Add the new language.
//
if (!AddLanguage(GetProp(hwnd, szPropHwnd), pLangNode))
{
//
// Unable to add the language. Need to return the user back
// to the Add dialog.
//
Locale_RemoveFromLinkedList(pLangNode);
return (0);
}
//
// Return success.
//
return (1);
}
////////////////////////////////////////////////////////////////////////////
//
// KbdLocaleAddDlg
//
// This is the dialog proc for the Add button of the Input Locales
// property sheet.
//
////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK KbdLocaleAddDlg(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case ( WM_INITDIALOG ) :
{
Locale_AddDlgInit(hwnd, lParam);
break;
}
case ( WM_DESTROY ) :
{
RemoveProp(hwnd, szPropHwnd);
RemoveProp(hwnd, szPropIdx);
break;
}
case ( WM_COMMAND ) :
{
switch (LOWORD(wParam))
{
case ( IDOK ) :
{
if (!Locale_AddCommandOK(hwnd))
{
//
// This means the properties dialog was cancelled.
// The Add dialog should remain active.
//
break;
}
// fall thru...
}
case ( IDCANCEL ) :
{
EndDialog(hwnd, (wParam == IDOK) ? 1 : 0);
break;
}
default :
{
return (FALSE);
}
}
break;
}
case ( WM_HELP ) :
{
WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
NULL,
HELP_WM_HELP,
(DWORD)(LPTSTR)aAddLocaleHelpIds );
break;
}
case ( WM_CONTEXTMENU ) : // right mouse click
{
WinHelp( (HWND)wParam,
NULL,
HELP_CONTEXTMENU,
(DWORD)(LPTSTR)aAddLocaleHelpIds );
break;
}
default :
{
return (FALSE);
}
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_EditDlgInit
//
// Processing for a WM_INITDIALOG message for the Edit dialog box.
//
////////////////////////////////////////////////////////////////////////////
void Locale_EditDlgInit(
HWND hwnd,
LPARAM lParam)
{
UINT i;
UINT idx;
int idxSel;
int idxUSA;
TCHAR sz[DESC_MAX];
HWND hwndLayout = GetDlgItem(hwnd, IDC_KBDLE_LAYOUT);
HWND hwndMain = ((LPINITINFO)lParam)->hwndMain;
LPLANGNODE pLangNode, pTemp;
//
// Get the language name for the currently selected input locale
// and display it in the dialog.
//
pLangNode = ((LPINITINFO)lParam)->pLangNode;
GetAtomName(lpLang[pLangNode->iLang].atmLanguageName, sz, DESC_MAX);
SetDlgItemText(hwnd, IDC_KBDLE_LOCALE, sz);
//
// Search through all of the layouts.
//
idxSel = -1;
idxUSA = -1; // last resort default
for (i = 0; i < iLayoutBuff; i++)
{
#ifdef DBCS
//
// We don't show IME layout in change layout list.
//
if ((HIWORD(lpLayout[i].dwID) & 0xf000) == 0xe000)
{
continue;
}
#endif
//
// Make sure this layout isn't already used for this input locale.
// If it is, then don't display it in the properties dialog.
//
if (i != pLangNode->iLayout)
{
pTemp = lpLang[pLangNode->iLang].pNext;
while (pTemp)
{
if (pTemp->wStatus & LANG_ACTIVE)
{
if (i == pTemp->iLayout)
{
break;
}
}
pTemp = pTemp->pNext;
}
if (pTemp && (i == pTemp->iLayout))
{
continue;
}
}
//
// Get the layout text. If it doesn't already exist in the
// combo box, then add it to the list of possible layouts.
//
GetAtomName(lpLayout[i].atmLayoutText, sz, DESC_MAX);
if ((idx = ComboBox_FindStringExact(hwndLayout, 0, sz)) == CB_ERR)
{
//
// Add the layout string and set the item data to be the
// index into the lpLayout array.
//
idx = ComboBox_AddString(hwndLayout, sz);
ComboBox_SetItemData(hwndLayout, idx, MAKELONG(i, 0));
//
// See if it's the US layout. If so, save the index.
//
if (lpLayout[i].dwID == US_LOCALE)
{
idxUSA = i;
}
}
//
// Edit box, we want the one ALREADY associated.
//
if (i == pLangNode->iLayout)
{
idxSel = i;
}
}
//
// If a default layout was not found, then set it to the US layout.
//
if (idxSel == -1)
{
idxSel = idxUSA;
}
//
// Set the current selection.
//
if (idxSel == -1)
{
//
// Simply set the current selection to be the first entry
// in the list.
//
ComboBox_SetCurSel(hwndLayout, 0);
}
else
{
//
// The combo box is sorted, but we need to know where
// lpLayout[idxSel] was stored. So, get the atom again, and
// search the list.
//
GetAtomName(lpLayout[idxSel].atmLayoutText, sz, DESC_MAX);
idx = ComboBox_FindStringExact(hwndLayout, 0, sz);
ComboBox_SetCurSel(hwndLayout, idx);
}
SetProp(hwnd, szPropHwnd, (HANDLE)hwndMain);
SetProp(hwnd, szPropIdx, (HANDLE)pLangNode);
}
////////////////////////////////////////////////////////////////////////////
//
// Locale_EditCommandOK
//
// Gets the new keyboard layout selection. If it's different from the
// current one for that locale, then it updates the lpLang array and
// redraws the input locale combo box in the main property sheet.
//
////////////////////////////////////////////////////////////////////////////
void Locale_EditCommandOK(
HWND hwnd)
{
UINT idx;
UINT idxLay;
LPLANGNODE pLangNode;
HWND hwndLay = GetDlgItem(hwnd, IDC_KBDLE_LAYOUT);
HWND hwndMain;
//
// Get the currently selected layout from the combo box.
//
idx = (UINT)ComboBox_GetCurSel(hwndLay);
idxLay = (UINT)ComboBox_GetItemData(hwndLay, idx);
pLangNode = (LPLANGNODE)GetProp(hwnd, szPropIdx);
//
// See if the selected layout has changed.
//
if ((pLangNode->iLayout == (UINT)(-1)) || (pLangNode->iLayout != idxLay))
{
//
// Reset the lpLang array to contain the new layout and show
// that there is a change.
//
pLangNode->iLayout = idxLay;
pLangNode->wStatus |= LANG_CHANGED;
//
// Redraw the input locale list in the property sheet.
//
hwndMain = GetProp(hwnd, szPropHwnd);
InvalidateRect(GetDlgItem(hwndMain, IDC_KBDL_LOCALE_LIST), NULL, FALSE);
}
}
////////////////////////////////////////////////////////////////////////////
//
// KbdLocaleEditDlg
//
// This is the dialog proc for the Properties button of the Input Locales
// property sheet.
//
////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK KbdLocaleEditDlg(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case ( WM_INITDIALOG ) :
{
Locale_EditDlgInit(hwnd, lParam);
break;
}
case ( WM_DESTROY ) :
{
RemoveProp(hwnd, szPropHwnd);
RemoveProp(hwnd, szPropIdx);
break;
}
case ( WM_HELP ) :
{
WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
NULL,
HELP_WM_HELP,
(DWORD)(LPTSTR)aLocalePropHelpIDs );
break;
}
case ( WM_CONTEXTMENU ) :
{
WinHelp( (HWND)wParam,
NULL,
HELP_CONTEXTMENU,
(DWORD)(LPTSTR)aLocalePropHelpIDs );
break;
}
case ( WM_COMMAND ) :
{
switch (LOWORD(wParam))
{
case ( IDOK ) :
{
Locale_EditCommandOK(hwnd);
// fall thru...
}
case ( IDCANCEL ) :
{
EndDialog(hwnd, (wParam == IDOK) ? 1 : 0);
break;
}
default :
{
return (FALSE);
}
}
break;
}
default :
{
return (FALSE);
}
}
return (TRUE);
}