mirror of https://github.com/lianthony/NT4.0
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
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);
|
|
}
|
|
|
|
|