reactos/base/setup/usetup/mui.c
2017-12-09 23:33:02 +01:00

750 lines
19 KiB
C

/*
* ReactOS kernel
* Copyright (C) 2008 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS text-mode setup
* FILE: base/setup/usetup/mui.c
* PURPOSE: Text-mode setup
* PROGRAMMER:
*/
#include "usetup.h"
#include "muifonts.h"
#include "muilanguages.h"
#define NDEBUG
#include <debug.h>
extern
VOID
PopupError(IN PCCH Text,
IN PCCH Status,
IN PINPUT_RECORD Ir,
IN ULONG WaitEvent);
static
ULONG
FindLanguageIndex(VOID)
{
ULONG lngIndex = 0;
if (SelectedLanguageId == NULL)
{
/* default to english */
return 0;
}
do
{
if (_wcsicmp(MUILanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
{
return lngIndex;
}
lngIndex++;
} while (MUILanguageList[lngIndex].MuiPages != NULL);
return 0;
}
BOOLEAN
IsLanguageAvailable(
PWCHAR LanguageId)
{
ULONG lngIndex = 0;
do
{
if (_wcsicmp(MUILanguageList[lngIndex].LanguageID , LanguageId) == 0)
return TRUE;
lngIndex++;
} while (MUILanguageList[lngIndex].MuiPages != NULL);
return FALSE;
}
static
const MUI_ENTRY *
FindMUIEntriesOfPage(
IN ULONG PageNumber)
{
ULONG muiIndex = 0;
ULONG lngIndex;
const MUI_PAGE * Pages = NULL;
lngIndex = max(FindLanguageIndex(), 0);
Pages = MUILanguageList[lngIndex].MuiPages;
do
{
if (Pages[muiIndex].Number == PageNumber)
return Pages[muiIndex].MuiEntry;
muiIndex++;
}while (Pages[muiIndex].MuiEntry != NULL);
return NULL;
}
static
const MUI_ERROR *
FindMUIErrorEntries(VOID)
{
ULONG lngIndex = max(FindLanguageIndex(), 0);
return MUILanguageList[lngIndex].MuiErrors;
}
static
const MUI_STRING *
FindMUIStringEntries(VOID)
{
ULONG lngIndex = max(FindLanguageIndex(), 0);
return MUILanguageList[lngIndex].MuiStrings;
}
LPCWSTR
MUIDefaultKeyboardLayout(VOID)
{
ULONG lngIndex = max(FindLanguageIndex(), 0);
return MUILanguageList[lngIndex].MuiLayouts[0].LayoutID;
}
PWCHAR
MUIGetGeoID(VOID)
{
ULONG lngIndex = max(FindLanguageIndex(), 0);
return MUILanguageList[lngIndex].GeoID;
}
const MUI_LAYOUTS *
MUIGetLayoutsList(VOID)
{
ULONG lngIndex = max(FindLanguageIndex(), 0);
return MUILanguageList[lngIndex].MuiLayouts;
}
VOID
MUIClearPage(
IN ULONG page)
{
const MUI_ENTRY * entry;
int index;
entry = FindMUIEntriesOfPage(page);
if (!entry)
{
PopupError("Error: Failed to find translated page",
NULL,
NULL,
POPUP_WAIT_NONE);
return;
}
index = 0;
do
{
CONSOLE_ClearStyledText(entry[index].X,
entry[index].Y,
entry[index].Flags,
strlen(entry[index].Buffer));
index++;
}
while (entry[index].Buffer != NULL);
}
VOID
MUIDisplayPage(
IN ULONG page)
{
const MUI_ENTRY * entry;
int index;
entry = FindMUIEntriesOfPage(page);
if (!entry)
{
PopupError("Error: Failed to find translated page",
NULL,
NULL,
POPUP_WAIT_NONE);
return;
}
index = 0;
do
{
CONSOLE_SetStyledText(entry[index].X,
entry[index].Y,
entry[index].Flags,
entry[index].Buffer);
index++;
}
while (entry[index].Buffer != NULL);
}
VOID
MUIDisplayError(
IN ULONG ErrorNum,
OUT PINPUT_RECORD Ir,
IN ULONG WaitEvent,
...)
{
const MUI_ERROR * entry;
CHAR Buffer[2048];
va_list ap;
if (ErrorNum >= ERROR_LAST_ERROR_CODE)
{
PopupError("Invalid error number provided",
"Press ENTER to continue",
Ir,
POPUP_WAIT_ENTER);
return;
}
entry = FindMUIErrorEntries();
if (!entry)
{
PopupError("Error: Failed to find translated error message",
NULL,
NULL,
POPUP_WAIT_NONE);
return;
}
va_start(ap, WaitEvent);
vsprintf(Buffer, entry[ErrorNum].ErrorText, ap);
va_end(ap);
PopupError(Buffer,
entry[ErrorNum].ErrorStatus,
Ir,
WaitEvent);
}
LPSTR
MUIGetString(
ULONG Number)
{
ULONG i;
const MUI_STRING * entry;
CHAR szErr[128];
entry = FindMUIStringEntries();
if (entry)
{
for (i = 0; entry[i].Number != 0; i++)
{
if (entry[i].Number == Number)
{
return entry[i].String;
}
}
}
sprintf(szErr, "Error: failed find string id %lu for language index %lu\n", Number, FindLanguageIndex());
PopupError(szErr,
NULL,
NULL,
POPUP_WAIT_NONE);
return "<nostring>";
}
static
BOOLEAN
AddHotkeySettings(
IN LPCWSTR Hotkey,
IN LPCWSTR LangHotkey,
IN LPCWSTR LayoutHotkey)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
HANDLE KeyHandle;
ULONG Disposition;
NTSTATUS Status;
RtlInitUnicodeString(&KeyName,
L"\\Registry\\User\\.DEFAULT\\Keyboard Layout\\Toggle");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateKey(&KeyHandle,
KEY_SET_VALUE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
if(!NT_SUCCESS(Status))
{
DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
return FALSE;
}
RtlInitUnicodeString(&ValueName,
L"Hotkey");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)Hotkey,
(1 + 1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
RtlInitUnicodeString(&ValueName,
L"Language Hotkey");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)LangHotkey,
(1 + 1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
RtlInitUnicodeString(&ValueName,
L"Layout Hotkey");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)LayoutHotkey,
(1 + 1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
NtClose(KeyHandle);
return TRUE;
}
BOOLEAN
AddKbLayoutsToRegistry(
IN const MUI_LAYOUTS *MuiLayouts)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
HANDLE KeyHandle;
HANDLE SubKeyHandle;
NTSTATUS Status;
ULONG Disposition;
ULONG uIndex = 0;
ULONG uCount = 0;
WCHAR szKeyName[48] = L"\\Registry\\User\\.DEFAULT\\Keyboard Layout";
WCHAR szValueName[3 + 1];
WCHAR szLangID[8 + 1];
// Open the keyboard layout key
RtlInitUnicodeString(&KeyName,
szKeyName);
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateKey(&KeyHandle,
KEY_CREATE_SUB_KEY,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
if(NT_SUCCESS(Status))
NtClose(KeyHandle);
else
{
DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
return FALSE;
}
KeyName.MaximumLength = sizeof(szKeyName);
Status = RtlAppendUnicodeToString(&KeyName, L"\\Preload");
if(!NT_SUCCESS(Status))
{
DPRINT1("RtlAppend failed! (%lx)\n", Status);
DPRINT1("String is %wZ\n", &KeyName);
return FALSE;
}
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateKey(&KeyHandle,
KEY_SET_VALUE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
return FALSE;
}
RtlInitUnicodeString(&KeyName, L"\\Registry\\User\\.DEFAULT\\Keyboard Layout\\Substitutes");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateKey(&SubKeyHandle,
KEY_SET_VALUE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition);
if(!NT_SUCCESS(Status))
{
DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
NtClose(SubKeyHandle);
NtClose(KeyHandle);
return FALSE;
}
do
{
if (uIndex > 19) break;
swprintf(szValueName, L"%u", uIndex + 1);
RtlInitUnicodeString(&ValueName, szValueName);
swprintf(szLangID, L"0000%s", MuiLayouts[uIndex].LangID);
if (_wcsicmp(szLangID, MuiLayouts[uIndex].LayoutID) == 0)
{
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)MuiLayouts[uIndex].LayoutID,
(wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
NtClose(SubKeyHandle);
NtClose(KeyHandle);
return FALSE;
}
}
else
{
swprintf(szLangID, L"d%03lu%s", uCount, MuiLayouts[uIndex].LangID);
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)szLangID,
(wcslen(szLangID)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
NtClose(SubKeyHandle);
NtClose(KeyHandle);
return FALSE;
}
RtlInitUnicodeString(&ValueName, szLangID);
Status = NtSetValueKey(SubKeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)MuiLayouts[uIndex].LayoutID,
(wcslen(MuiLayouts[uIndex].LayoutID)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %u)\n", Status, uIndex);
NtClose(SubKeyHandle);
NtClose(KeyHandle);
return FALSE;
}
uCount++;
}
uIndex++;
}
while (MuiLayouts[uIndex].LangID != NULL);
if (uIndex > 1)
AddHotkeySettings(L"2", L"2", L"1");
else
AddHotkeySettings(L"3", L"3", L"3");
NtClose(SubKeyHandle);
NtClose(KeyHandle);
return TRUE;
}
BOOLEAN
AddKeyboardLayouts(VOID)
{
ULONG lngIndex = 0;
do
{
if (_wcsicmp(MUILanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
{
return AddKbLayoutsToRegistry(MUILanguageList[lngIndex].MuiLayouts);
}
lngIndex++;
}
while (MUILanguageList[lngIndex].MuiPages != NULL);
return FALSE;
}
static
BOOLEAN
AddCodepageToRegistry(
IN LPCWSTR ACPage,
IN LPCWSTR OEMCPage,
IN LPCWSTR MACCPage)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
HANDLE KeyHandle;
NTSTATUS Status;
// Open the nls codepage key
RtlInitUnicodeString(&KeyName,
L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenKey(&KeyHandle,
KEY_WRITE,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
return FALSE;
}
// Set ANSI codepage
RtlInitUnicodeString(&ValueName, L"ACP");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)ACPage,
(wcslen(ACPage)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
// Set OEM codepage
RtlInitUnicodeString(&ValueName, L"OEMCP");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)OEMCPage,
(wcslen(OEMCPage)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
// Set MAC codepage
RtlInitUnicodeString(&ValueName, L"MACCP");
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)MACCPage,
(wcslen(MACCPage)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
NtClose(KeyHandle);
return FALSE;
}
NtClose(KeyHandle);
return TRUE;
}
static
BOOLEAN
AddFontsSettingsToRegistry(
IN const MUI_SUBFONT * MuiSubFonts)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
HANDLE KeyHandle;
NTSTATUS Status;
ULONG uIndex = 0;
RtlInitUnicodeString(&KeyName,
L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenKey(&KeyHandle,
KEY_WRITE,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
return FALSE;
}
do
{
RtlInitUnicodeString(&ValueName, MuiSubFonts[uIndex].FontName);
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
(PVOID)MuiSubFonts[uIndex].SubFontName,
(wcslen(MuiSubFonts[uIndex].SubFontName)+1) * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status = %lx, uIndex = %d)\n", Status, uIndex);
NtClose(KeyHandle);
return FALSE;
}
uIndex++;
}
while (MuiSubFonts[uIndex].FontName != NULL);
NtClose(KeyHandle);
return TRUE;
}
BOOLEAN
AddCodePage(VOID)
{
ULONG lngIndex = 0;
do
{
if (_wcsicmp(MUILanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
{
if (AddCodepageToRegistry(MUILanguageList[lngIndex].ACPage,
MUILanguageList[lngIndex].OEMCPage,
MUILanguageList[lngIndex].MACCPage)&&
AddFontsSettingsToRegistry(MUILanguageList[lngIndex].MuiSubFonts))
{
return TRUE;
}
else
{
return FALSE;
}
}
lngIndex++;
}
while (MUILanguageList[lngIndex].MuiPages != NULL);
return FALSE;
}
VOID
SetConsoleCodePage(VOID)
{
ULONG lngIndex = 0;
UINT wCodePage;
do
{
if (_wcsicmp(MUILanguageList[lngIndex].LanguageID , SelectedLanguageId) == 0)
{
wCodePage = (UINT) wcstoul(MUILanguageList[lngIndex].OEMCPage, NULL, 10);
SetConsoleOutputCP(wCodePage);
return;
}
lngIndex++;
}
while (MUILanguageList[lngIndex].MuiPages != NULL);
}
/* EOF */