1
1
Fork 0
mirror of https://github.com/pbatard/rufus.git synced 2024-08-14 23:57:05 +00:00
rufus/src/dos_locale.c
2024-02-09 17:00:42 +00:00

1072 lines
29 KiB
C

/*
* Rufus: The Reliable USB Formatting Utility
* DOS keyboard locale setup
* Copyright © 2011-2024 Pete Batard <pete@akeo.ie>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */
#ifdef _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "rufus.h"
#if defined(_MSC_VER)
// We have a bunch of \xCD characters in this file that MS doesn't like
#pragma warning(disable: 4819)
#endif
/*
* Note: if you want a book that can be used as a keyboards and codepages bible, I
* would recommend the "OS/2 Warp Server for e-business - Keyboards and Codepages".
* See http://www.borgendale.com/keyboard.pdf
*/
/* WinME DOS keyboard 2 letter codes & supported keyboard ID(s), as retrieved
* from the Millennium disk image in diskcopy.dll on a Windows 7 system
*
* KEYBOARD.SYS
* GR 129*
* SP 172
* PO 163*
* FR 120*, 189*
* DK 159*
* SG 000*
* IT 141*, 142*
* UK 166*, 168*
* SF 150*
* BE 120*
* NL 143*
* NO 155*
* CF 058*
* SV 153*
* SU 153
* LA 171*
* BR 274*
* PL 214*
* CZ 243*
* SL 245*
* YU 234*
* HU 208*
* US/XX 103*
* JP defines ID:194 but points to SP entry
*
* KEYBRD2.SYS
* GR 129*
* RU 441
* IT 141*, 142*
* UK 166*, 168*
* NO 155*
* CF 058*
* SV 153*
* SU 153
* BR 274*, 275*
* BG 442*
* PL 214*
* CZ 243*
* SL 245*
* YU 234*
* YC 118
* HU 208*
* RO 333
* IS 161*
* TR 179*, 440*
* GK 319*
* US/XX 103*
*
* KEYBRD3.SYS
* GR 129*
* SP 172*
* FR 189*
* DK 159*
* SG 000*
* IT 141*
* UK 166*
* SF 150*
* BE 120*
* NL 143*
* SV 153*
* SU 153
* PL 214*
* CZ 243*
* SL 245*
* YU 234*
* HU 208*
* RU 091*, 092*, 093*, 341*
* UR 094*, 095*, 096*
* BL 097*, 098*, 099*
* US/XX 103*
* JP defines ID:194 but points to SP entry
*
* KEYBRD4.SYS
* GK 101*, 319*, 220*
* PL 214*
* ET 425*
* HE 400*
* AR 401*, 402*, 403*
* US/XX 103*
*/
/*
* The following lists the keyboard code that are supported in each
* of the WinMe DOS KEYBOARD.SYS, KEYBRD2.SYS, ...
*/
static const char* ms_kb1[] = {
"be", "br", "cf", "cz", "dk", "fr", "gr", "hu", "it", "la",
"nl", "no", "pl", "po", "sf", "sg", "sl", "sp", "su", "sv",
"uk", "us", "yu" };
static const char* ms_kb2[] = {
"bg", "br", "cf", "cz", "gk", "gr", "hu", "is", "it", "no",
"pl", "ro", "ru", "sl", "su", "sv", "tr", "uk", "us", "yc",
"yu" };
static const char* ms_kb3[] = {
"be", "bl", "cz", "dk", "fr", "gr", "hu", "it", "nl", "pl",
"ru", "sf", "sg", "sl", "sp", "su", "sv", "uk", "ur", "us",
"yu" };
static const char* ms_kb4[] = {
"ar", "et", "gk", "he", "pl", "us" };
/*
* The following lists the keyboard code that are supported in each
* of the FreeDOS DOS KEYBOARD.SYS, KEYBRD2.SYS, ...
*/
static const char* fd_kb1[] = {
"be", "br", "cf", "co", "cz", "dk", "dv", "fr", "gr", "hu",
"it", "jp", "la", "lh", "nl", "no", "pl", "po", "rh", "sf",
"sg", "sk", "sp", "su", "sv", "uk", "us", "yu" };
static const char* fd_kb2[] = {
"bg", "ce", "gk", "is", "ro", "ru", "rx", "tr", "tt", "yc" };
static const char* fd_kb3[] = {
"az", "bl", "et", "fo", "hy", "il", "ka", "kk", "ky", "lt",
"lv", "mk", "mn", "mt", "ph", "sq", "tj", "tm", "ur", "uz",
"vi" };
static const char* fd_kb4[] = {
"ar", "bn", "bx", "fx", "ix", "kx", "ne", "ng", "px", "sx",
"ux" };
typedef struct {
const char* name;
ULONG default_cp;
} kb_default;
static kb_default kbdrv_data[] = {
{ "keyboard.sys", 437 },
{ "keybrd2.sys", 850 },
{ "keybrd3.sys", 850 },
{ "keybrd4.sys", 853 }
};
typedef struct {
size_t size;
const char** list;
} kb_list;
static kb_list ms_kb_list[] = {
{ ARRAYSIZE(ms_kb1), ms_kb1 },
{ ARRAYSIZE(ms_kb2), ms_kb2 },
{ ARRAYSIZE(ms_kb3), ms_kb3 },
{ ARRAYSIZE(ms_kb4), ms_kb4 }
};
static kb_list fd_kb_list[] = {
{ ARRAYSIZE(fd_kb1), fd_kb1 },
{ ARRAYSIZE(fd_kb2), fd_kb2 },
{ ARRAYSIZE(fd_kb3), fd_kb3 },
{ ARRAYSIZE(fd_kb4), fd_kb4 }
};
static int ms_get_kbdrv(const char* kb)
{
unsigned int i, j;
for (i = 0; i<ARRAYSIZE(ms_kb_list); i++) {
for (j = 0; j < ms_kb_list[i].size; j++) {
if (safe_strcmp(ms_kb_list[i].list[j], kb) == 0) {
return i;
}
}
}
return -1;
}
static int fd_get_kbdrv(const char* kb)
{
unsigned int i, j;
for (i = 0; i < ARRAYSIZE(fd_kb_list); i++) {
for (j = 0; j < fd_kb_list[i].size; j++) {
if (safe_strcmp(fd_kb_list[i].list[j], kb) == 0) {
return i;
}
}
}
return -1;
}
/*
* We display human readable descriptions of the locale in the menu
* As real estate might be limited, keep it short
*/
static const char* kb_hr_list[][2] = {
{"ar", "Arabic"}, // Left enabled, but doesn't seem to work in FreeDOS
{"bg", "Bulgarian"},
{"ch", "Chinese"},
{"cz", "Czech"},
{"dk", "Danish"},
{"gr", "German"},
{"sg", "Swiss-German"},
{"gk", "Greek"},
{"us", "US-English"},
{"uk", "UK-English"},
{"cf", "CA-French"},
{"dv", "US-Dvorak"},
{"lh", "US-Dvorak (LH)"},
{"rh", "US-Dvorak (RH)"},
{"sp", "Spanish"},
{"la", "Latin-American"},
{"su", "Finnish"},
{"fr", "French"},
{"be", "Belgian-French"},
{"sf", "Swiss-French"},
{"il", "Hebrew"},
{"hu", "Hungarian"},
{"is", "Icelandic"},
{"it", "Italian"},
{"jp", "Japanese"},
// {"ko", "Korean"}, // Unsupported by FreeDOS
{"nl", "Dutch"},
{"no", "Norwegian"},
{"pl", "Polish"},
{"br", "Brazilian"},
{"po", "Portuguese"},
{"ro", "Romanian"},
{"ru", "Russian"},
{"yu", "YU-Latin"},
{"yc", "YU-Cyrillic"},
{"sl", "Slovak"},
{"sq", "Albanian"},
{"sv", "Swedish"},
{"tr", "Turkish"},
{"ur", "Ukrainian"},
{"bl", "Belarusian"},
{"et", "Estonian"},
{"lv", "Latvian"},
{"lt", "Lithuanian"},
{"tj", "Tajik"},
// {"fa", "Persian"}; // Unsupported by FreeDOS
{"vi", "Vietnamese"},
{"hy", "Armenian"},
{"az", "Azeri"},
{"mk", "Macedonian"},
{"ka", "Georgian"},
{"fo", "Faeroese"},
{"mt", "Maltese"},
{"kk", "Kazakh"},
{"ky", "Kyrgyz"},
{"uz", "Uzbek"},
{"tm", "Turkmen"},
{"tt", "Tatar"},
};
static const char* kb_to_hr(const char* kb)
{
int i;
for (i = 0; i < ARRAYSIZE(kb_hr_list); i++) {
if (safe_strcmp(kb, kb_hr_list[i][0]) == 0) {
return kb_hr_list[i][1];
}
}
// Should never happen, so let's try to get some attention here
assert(i < ARRAYSIZE(kb_hr_list));
return NULL;
}
typedef struct {
ULONG cp;
const char* name;
} cp_list;
// From FreeDOS CPX pack as well as
// http://msdn.microsoft.com/en-us/library/dd317756.aspx
static cp_list cp_hr_list[] = {
{ 113, "Lat-Yugoslavian"},
{ 437, "US-English"},
{ 667, "Polish"},
{ 668, "Polish (Alt)"},
{ 708, "Arabic (708)"},
{ 709, "Arabic (709)"},
{ 710, "Arabic (710)"},
{ 720, "Arabic (DOS)"},
{ 737, "Greek (DOS)"},
{ 770, "Baltic"},
{ 771, "Cyr-Russian (KBL)"},
{ 772, "Cyr-Russian"},
{ 773, "Baltic Rim (Old)"},
{ 774, "Lithuanian"},
{ 775, "Baltic Rim"},
{ 777, "Acc-Lithuanian (Old)"},
{ 778, "Acc-Lithuanian"},
{ 790, "Mazovian-Polish"},
{ 808, "Cyr-Russian (Euro)"},
{ 848, "Cyr-Ukrainian (Euro)"},
{ 849, "Cyr-Belarusian (Euro)"},
{ 850, "Western-European"},
{ 851, "Greek"},
{ 852, "Central-European"},
{ 853, "Southern-European"},
{ 855, "Cyr-South-Slavic"},
{ 856, "Hebrew II"},
{ 857, "Turkish"},
{ 858, "Western-European (Euro)"},
{ 859, "Western-European (Alt)"},
{ 860, "Portuguese"},
{ 861, "Icelandic"},
{ 862, "Hebrew"},
{ 863, "Canadian-French"},
{ 864, "Arabic"},
{ 865, "Nordic"},
{ 866, "Cyr-Russian"},
{ 867, "Czech Kamenicky"},
{ 869, "Modern Greek"},
{ 872, "Cyr-South-Slavic (Euro)"},
{ 874, "Thai"},
{ 895, "Czech Kamenicky (Alt)"},
{ 899, "Armenian"},
{ 932, "Japanese"},
{ 936, "Chinese (Simplified)"},
{ 949, "Korean"},
{ 950, "Chinese (Traditional)"},
{ 991, "Mazovian-Polish (Zloty)"},
{ 1116, "Estonian"},
{ 1117, "Latvian"},
{ 1118, "Lithuanian"},
{ 1119, "Cyr-Russian (Alt)"},
{ 1125, "Cyr-Ukrainian"},
{ 1131, "Cyr-Belarusian"},
{ 1250, "Central European"},
{ 1251, "Cyrillic"},
{ 1252, "Western European"},
{ 1253, "Greek"},
{ 1254, "Turkish"},
{ 1255, "Hebrew"},
{ 1256, "Arabic"},
{ 1257, "Baltic"},
{ 1258, "Vietnamese"},
{ 1361, "Korean"},
{ 3012, "Cyr-Latvian"},
{ 3021, "Cyr-Bulgarian"},
{ 3845, "Hungarian"},
{ 3846, "Turkish"},
{ 3848, "Brazilian (ABICOMP)"},
{ 30000, "Saami"},
{ 30001, "Celtic"},
{ 30002, "Cyr-Tajik"},
{ 30003, "Latin American"},
{ 30004, "Greenlandic"},
{ 30005, "Nigerian"},
{ 30006, "Vietnamese"},
{ 30007, "Latin"},
{ 30008, "Cyr-Ossetian"},
{ 30009, "Romani"},
{ 30010, "Cyr-Moldovan"},
{ 30011, "Cyr-Chechen"},
{ 30012, "Cyr-Siberian"},
{ 30013, "Cyr-Turkic"},
{ 30014, "Cyr-Finno-Ugric"},
{ 30015, "Cyr-Khanty"},
{ 30016, "Cyr-Mansi"},
{ 30017, "Cyr-Northwestern"},
{ 30018, "Lat-Tatar"},
{ 30019, "Lat-Chechen"},
{ 30020, "Low-Saxon and Frisian"},
{ 30021, "Oceanian"},
{ 30022, "First Nations"},
{ 30023, "Southern African"},
{ 30024, "North & East African"},
{ 30025, "Western African"},
{ 30026, "Central African"},
{ 30027, "Beninese"},
{ 30028, "Nigerian (Alt)"},
{ 30029, "Mexican"},
{ 30030, "Mexican (Alt)"},
{ 30031, "Northern-European"},
{ 30032, "Nordic"},
{ 30033, "Crimean-Tatar (Hryvnia)"},
{ 30034, "Cherokee"},
{ 30039, "Cyr-Ukrainian (Hryvnia)"},
{ 30040, "Cyr-Russian (Hryvnia)"},
{ 58152, "Cyr-Kazakh (Euro)"},
{ 58210, "Cyr-Azeri"},
{ 58335, "Kashubian"},
{ 59234, "Cyr-Tatar"},
{ 59829, "Georgian"},
{ 60258, "Lat-Azeri"},
{ 60853, "Georgian (Alt)"},
{ 62306, "Cyr-Uzbek"},
{ 65001, "Unicode (UTF-8)" }
};
static const char* cp_to_hr(ULONG cp)
{
int i;
for (i = 0; i < ARRAYSIZE(cp_hr_list); i++) {
if (cp_hr_list[i].cp == cp) {
return cp_hr_list[i].name;
}
}
// Should never happen, so this oughta get some attention
assert(i < ARRAYSIZE(cp_hr_list));
return NULL;
}
// http://blogs.msdn.com/b/michkap/archive/2004/12/05/275231.aspx
static const char* get_kb(void)
{
unsigned int kbid;
char kbid_str[KL_NAMELENGTH];
int pass;
// Count on Microsoft to add convolution to a simple operation.
// We use GetKeyboardLayout() because it returns an HKL, which for instance
// doesn't tell us if the *LAYOUT* is Dvorak or something else. For that we
// need an KLID which GetKeyboardLayoutNameA() does return ...but only as a
// string of an hex value...
GetKeyboardLayoutNameA(kbid_str);
if (sscanf(kbid_str, "%x", &kbid) <= 0) {
uprintf("Could not scan keyboard layout name - defaulting to US");
kbid = 0x00000409;
}
uprintf("Windows KBID 0x%08x\n", kbid);
for (pass = 0; pass < 3; pass++) {
// Some of these return values are defined in
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout\DosKeybCodes
// Others are picked up in FreeDOS official keyboard layouts, v3.0
// Note: keyboard values are meant to start at 0x400. The cases below 0x400 are added
// to attempt to figure out a "best match" in case we couldn't find a supported keyboard
// by using the one most relevant to the language being spoken. Also we intentionally
// group keyboards that shouldn't be together
// Note: these cases are mostly organized first by (kbid & 0x3ff) and then by
// ascending order for same (kbid & 0x3ff)
switch(kbid) {
case 0x00000001:
case 0x00010401: // Arabic (102)
case 0x00020401: // Arabic (102) AZERTY
return "ar";
case 0x00000002:
case 0x00000402: // Bulgarian (Typewriter)
case 0x00010402: // Bulgarian (Latin)
case 0x00020402: // Bulgarian (Phonetic)
case 0x00030402: // Bulgarian
case 0x00040402: // Bulgarian (Phonetic Traditional)
return "bg";
case 0x00000004:
case 0x00000404: // Chinese (Traditional) - US Keyboard
case 0x00000804: // Chinese (Simplified) - US Keyboard
case 0x00000c04: // Chinese (Traditional, Hong Kong) - US Keyboard
case 0x00001004: // Chinese (Simplified, Singapore) - US Keyboard
case 0x00001404: // Chinese (Traditional, Macao) - US Keyboard
return "ch";
case 0x00000005:
case 0x00000405: // Czech
case 0x00010405: // Czech (QWERTY)
case 0x00020405: // Czech Programmers
return "cz";
case 0x00000006:
case 0x00000406: // Danish
return "dk";
case 0x00000007:
case 0x00000407: // German
case 0x00010407: // German (IBM)
return "gr";
case 0x00000807: // Swiss German
return "sg";
case 0x00000008:
case 0x00000408: // Greek
case 0x00010408: // Greek (220)
case 0x00020408: // Greek (319)
case 0x00030408: // Greek (220) Latin
case 0x00040408: // Greek (319) Latin
case 0x00050408: // Greek Latin
case 0x00060408: // Greek Polytonic
return "gk";
case 0x00000009:
case 0x00000409: // US
case 0x00020409: // United States-International
case 0x00050409: // US English Table for IBM Arabic 238_L
return "us";
case 0x00000809: // United Kingdom
case 0x00000452: // United Kingdom Extended (Welsh)
case 0x00001809: // Irish
case 0x00011809: // Gaelic
return "uk";
case 0x00000c0c: // Canadian French (Legacy)
case 0x00001009: // Canadian French
case 0x00011009: // Canadian Multilingual Standard
return "cf";
case 0x00010409: // United States-Dvorak
return "dv";
case 0x00030409: // United States-Dvorak for left hand
return "lh";
case 0x00040409: // United States-Dvorak for right hand
return "rh";
case 0x0000000a:
case 0x0000040a: // Spanish
case 0x0001040a: // Spanish Variation
return "sp";
case 0x0000080a: // Latin American
return "la";
case 0x0000000b:
case 0x0000040b: // Finnish
case 0x0001083b: // Finnish with Sami
return "su";
case 0x0000000c:
case 0x0000040c: // French
case 0x0000046e: // Luxembourgish
return "fr";
case 0x0000080c: // Belgian French
case 0x0001080c: // Belgian (Comma)
return "be";
case 0x0000100c: // Swiss French
return "sf";
case 0x0000000d:
case 0x0000040d: // Hebrew
return "il";
case 0x0000000e:
case 0x0000040e: // Hungarian
case 0x0001040e: // Hungarian 101-key
return "hu";
case 0x0000000f:
case 0x0000040f: // Icelandic
return "is";
case 0x00000010:
case 0x00000410: // Italian
case 0x00010410: // Italian (142)
return "it";
case 0x00000011:
case 0x00000411: // Japanese
return "jp";
// case 0x00000012:
// case 0x00000412: // Korean
// return "ko"; // NOT IMPLEMENTED IN FREEDOS?
case 0x00000013:
case 0x00000413: // Dutch
case 0x00000813: // Belgian (Period)
return "nl";
case 0x00000014:
case 0x00000414: // Norwegian
case 0x0000043b: // Norwegian with Sami
case 0x0001043b: // Sami Extended Norway
return "no";
case 0x00000015:
case 0x00010415: // Polish (214)
case 0x00000415: // Polish (Programmers)
return "pl";
case 0x00000016:
case 0x00000416: // Portuguese (Brazilian ABNT)
case 0x00010416: // Portuguese (Brazilian ABNT2)
return "br";
case 0x00000816: // Portuguese (Portugal)
return "po";
case 0x00000018:
case 0x00000418: // Romanian (Legacy)
case 0x00010418: // Romanian (Standard)
case 0x00020418: // Romanian (Programmers)
return "ro";
case 0x00000019:
case 0x00000419: // Russian
case 0x00010419: // Russian (Typewriter)
return "ru";
case 0x0000001a:
case 0x0000041a: // Croatian
case 0x0000081a: // Serbian (Latin)
case 0x00000024:
case 0x00000424: // Slovenian
return "yu";
case 0x00000c1a: // Serbian (Cyrillic)
case 0x0000201a: // Bosnian (Cyrillic)
return "yc";
case 0x0000001b:
case 0x0000041b: // Slovak
case 0x0001041b: // Slovak (QWERTY)
return "sl";
case 0x0000001c:
case 0x0000041c: // Albanian
return "sq";
case 0x0000001d:
case 0x0000041d: // Swedish
case 0x0000083b: // Swedish with Sami
return "sv";
case 0x0000001f:
case 0x0000041f: // Turkish Q
case 0x0001041f: // Turkish F
return "tr";
case 0x00000022:
case 0x00000422: // Ukrainian
case 0x00020422: // Ukrainian (Enhanced)
return "ur";
case 0x00000023:
case 0x00000423: // Belarusian
return "bl";
case 0x00000025:
case 0x00000425: // Estonian
return "et";
case 0x00000026:
case 0x00000426: // Latvian
case 0x00010426: // Latvian (QWERTY)
return "lv";
case 0x00000027:
case 0x00000427: // Lithuanian IBM
case 0x00010427: // Lithuanian
case 0x00020427: // Lithuanian Standard
return "lt";
case 0x00000028:
case 0x00000428: // Tajik
return "tj";
// case 0x00000029:
// case 0x00000429: // Persian
// return "fa"; // NOT IMPLEMENTED IN FREEDOS?
case 0x0000002a:
case 0x0000042a: // Vietnamese
return "vi";
case 0x0000002b:
case 0x0000042b: // Armenian Eastern
case 0x0001042b: // Armenian Western
return "hy";
case 0x0000002c:
case 0x0000042c: // Azeri Latin
case 0x0000082c: // Azeri Cyrillic
return "az";
case 0x0000002f:
case 0x0000042f: // Macedonian (FYROM)
case 0x0001042f: // Macedonian (FYROM) - Standard
return "mk";
case 0x00000037:
case 0x00000437: // Georgian
case 0x00010437: // Georgian (QWERTY)
case 0x00020437: // Georgian (Ergonomic)
return "ka";
case 0x00000038:
case 0x00000438: // Faeroese
return "fo";
case 0x0000003a:
case 0x0000043a: // Maltese 47-Key
case 0x0001043a: // Maltese 48-Key
return "mt";
case 0x0000003f:
case 0x0000043f: // Kazakh
return "kk";
case 0x00000040:
case 0x00000440: // Kyrgyz Cyrillic
return "ky";
case 0x00000043:
case 0x00000843: // Uzbek Cyrillic
return "uz";
case 0x00000042:
case 0x00000442: // Turkmen
return "tm";
case 0x00000044:
case 0x00000444: // Tatar
return "tt";
// Below are more Windows 7 listed keyboards that were left out
#if 0
case 0x0000041e: // Thai Kedmanee
case 0x0001041e: // Thai Pattachote
case 0x0002041e: // Thai Kedmanee (non-ShiftLock)
case 0x0003041e: // Thai Pattachote (non-ShiftLock)
case 0x00000420: // Urdu
case 0x0000042e: // Sorbian Standard (Legacy)
case 0x0001042e: // Sorbian Extended
case 0x0002042e: // Sorbian Standard
case 0x00000432: // Setswana
case 0x00000439: // Devanagari - INSCRIPT#
case 0x00010439: // Hindi Traditional
case 0x0002083b: // Sami Extended Finland-Sweden
case 0x00000445: // Bengali
case 0x00010445: // Bengali - INSCRIPT (Legacy)
case 0x00020445: // Bengali - INSCRIPT
case 0x00000446: // Punjabi
case 0x00000447: // Gujarati
case 0x00000448: // Oriya
case 0x00000449: // Tamil
case 0x0000044a: // Telugu
case 0x0000044b: // Kannada
case 0x0000044c: // Malayalam
case 0x0000044d: // Assamese - INSCRIPT
case 0x0000044e: // Marathi
case 0x00000450: // Mongolian Cyrillic
case 0x00000451: // Tibetan
case 0x00000850: // Mongolian (Mongolian Script)
case 0x0000085d: // Inuktitut - Latin
case 0x0001045d: // Inuktitut - Naqittaut
case 0x00000453: // Khmer
case 0x00000454: // Lao
case 0x0000045a: // Syriac
case 0x0001045a: // Syriac Phonetic
case 0x0000045b: // Sinhala
case 0x0001045b: // Sinhala - Wij 9
case 0x00000461: // Nepali
case 0x00000463: // Pashto (Afghanistan)
case 0x00000465: // Divehi Phonetic
case 0x00010465: // Divehi Typewriter
case 0x00000468: // Hausa
case 0x0000046a: // Yoruba
case 0x0000046c: // Sesotho sa Leboa
case 0x0000046d: // Bashkir
case 0x0000046f: // Greenlandic
case 0x00000470: // Igbo
case 0x00000480: // Uyghur (Legacy)
case 0x00010480: // Uyghur
case 0x00000481: // Maori
case 0x00000485: // Yakut
case 0x00000488: // Wolof
#endif
default:
if (pass == 0) {
// If we didn't get a match 1st time around, try to match
// the primary language of the keyboard
kbid = PRIMARYLANGID(kbid);
} else if (pass == 1) {
// If we still didn't get a match, use the system's primary language
kbid = PRIMARYLANGID(GetSystemDefaultLangID());
uprintf("Unable to match KBID, trying LangID 0x%04x", kbid);
}
break;
}
}
uprintf("Unable to match KBID and LangID - defaulting to US");
return "us";
}
/*
* From WinME DOS
*
* EGA.CPI:
* 0x01B5 437 (United States)
* 0x0352 850 (Latin 1)
* 0x0354 852 (Latin 2)
* 0x035C 860 (Portuguese)
* 0x035F 863 (French Canadian)
* 0x0361 865 (Nordic)
*
* EGA2.CPI:
* 0x0352 850 (Latin 1)
* 0x0354 852 (Latin 2)
* 0x0359 857 (Turkish)
* 0x035D 861 (Icelandic)
* 0x0365 869 (Greek)
* 0x02E1 737 (Greek II)
*
* EGA3.CPI:
* 0x01B5 437 (United States)
* 0x0307 775 (Baltic)
* 0x0352 850 (Latin 1)
* 0x0354 852 (Latin 2)
* 0x0357 855 (Cyrillic I)
* 0x0362 866 (Cyrillic II)
*/
// Pick the EGA to use according to the DOS target codepage (see above)
static const char* ms_get_ega(ULONG cp)
{
switch(cp) {
case 437: // United States
case 850: // Latin-1 (Western European)
case 852: // Latin-2 (Central European)
case 860: // Portuguese
case 863: // French Canadian
case 865: // Nordic
return "ega.cpi";
// case 850: // Latin-1 (Western European)
// case 852: // Latin-2 (Central European)
case 857: // Turkish
case 861: // Icelandic
case 869: // Greek
case 737: // Greek II
return "ega2.cpi";
// case 437: // United States
case 775: // Baltic
// case 850: // Latin-1 (Western European)
// case 852: // Latin-2 (Central European)
case 855: // Cyrillic I
case 866: // Cyrillic II
return "ega3.cpi";
default:
return NULL;
}
}
// Pick the EGA to use according to the DOS target codepage (from CPIDOS' Codepage.txt)
static const char* fd_get_ega(ULONG cp)
{
switch(cp) {
case 437: // United States
case 850: // Latin-1 (Western European)
case 852: // Latin-2 (Central European)
case 853: // Latin-3 (Southern European)
case 857: // Latin-5
case 858: // Latin-1 with Euro
return "ega.cpx";
case 775: // Latin-7 (Baltic Rim)
case 859: // Latin-9
case 1116: // Estonian
case 1117: // Latvian
case 1118: // Lithuanian
case 1119: // Cyrillic Russian and Lithuanian (*)
return "ega2.cpx";
case 771: // Cyrillic Russian and Lithuanian (KBL)
case 772: // Cyrillic Russian and Lithuanian
case 808: // Cyrillic Russian with Euro
case 855: // Cyrillic South Slavic
case 866: // Cyrillic Russian
case 872: // Cyrillic South Slavic with Euro
return "ega3.cpx";
case 848: // Cyrillic Ukrainian with Euro
case 849: // Cyrillic Belarusian with Euro
case 1125: // Cyrillic Ukrainian
case 1131: // Cyrillic Belarusian
case 3012: // Cyrillic Russian and Latvian ("RusLat")
case 30010: // Cyrillic Gagauz and Moldovan
return "ega4.cpx";
case 113: // Yugoslavian Latin
case 737: // Greek-2
case 851: // Greek (old codepage)
// case 852: // Latin-2
// case 858: // Multilingual Latin-1 with Euro
case 869: // Greek
return "ega5.cpx";
case 899: // Armenian
case 30008: // Cyrillic Abkhaz and Ossetian
case 58210: // Cyrillic Russian and Azeri
case 59829: // Georgian
case 60258: // Cyrillic Russian and Latin Azeri
case 60853: // Georgian with capital letters
return "ega6.cpx";
case 30011: // Cyrillic Russian Southern District
case 30013: // Cyrillic Volga District: // Turkic languages
case 30014: // Cyrillic Volga District: // Finno-ugric languages
case 30017: // Cyrillic Northwestern District
case 30018: // Cyrillic Russian and Latin Tatar
case 30019: // Cyrillic Russian and Latin Chechen
return "ega7.cpx";
case 770: // Baltic
case 773: // Latin-7 (old standard)
case 774: // Lithuanian
// case 775: // Latin-7
case 777: // Accented Lithuanian (old)
case 778: // Accented Lithuanian
return "ega8.cpx";
// case 858: // Latin-1 with Euro
case 860: // Portuguese
case 861: // Icelandic
case 863: // Canadian French
case 865: // Nordic
case 867: // Czech Kamenicky
return "ega9.cpx";
case 667: // Polish
case 668: // Polish (polish letters on cp852 codepoints)
case 790: // Polish Mazovia
// case 852: // Latin-2
case 991: // Polish Mazovia with Zloty sign
case 3845: // Hungarian
return "ega10.cpx";
// case 858: // Latin-1 with Euro
case 30000: // Saami
case 30001: // Celtic
case 30004: // Greenlandic
case 30007: // Latin
case 30009: // Romani
return "ega11.cpx";
// case 852: // Latin-2
// case 858: // Latin-1 with Euro
case 30003: // Latin American
case 30029: // Mexican
case 30030: // Mexican II
case 58335: // Kashubian
return "ega12";
// case 852: // Latin-2
case 895: // Czech Kamenicky
case 30002: // Cyrillic Tajik
case 58152: // Cyrillic Kazakh with Euro
case 59234: // Cyrillic Tatar
case 62306: // Cyrillic Uzbek
return "ega13.cpx";
case 30006: // Vietnamese
case 30012: // Cyrillic Russian Siberian and Far Eastern Districts
case 30015: // Cyrillic Khanty
case 30016: // Cyrillic Mansi
case 30020: // Low saxon and frisian
case 30021: // Oceania
return "ega14.cpx";
case 30023: // Southern Africa
case 30024: // Northern and Eastern Africa
case 30025: // Western Africa
case 30026: // Central Africa
case 30027: // Beninese
case 30028: // Nigerian II
return "ega15.cpx";
// case 858: // Latin-1 with Euro
case 3021: // Cyrillic MIK Bulgarian
case 30005: // Nigerian
case 30022: // Canadian First Nations
case 30031: // Latin-4 (Northern European)
case 30032: // Latin-6
return "ega16.cpx";
case 862: // Hebrew
case 864: // Arabic
case 30034: // Cherokee
case 30033: // Crimean Tatar with Hryvnia
case 30039: // Cyrillic Ukrainian with Hryvnia
case 30040: // Cyrillic Russian with Hryvnia
return "ega17.cpx";
case 856: // Hebrew II
case 3846: // Turkish
case 3848: // Brazilian ABICOMP
return "ega18.cpx";
default:
return NULL;
}
}
// Transliteration of the codepage (to add currency symbol, etc - FreeDOS only)
static ULONG fd_upgrade_cp(ULONG cp)
{
switch(cp) {
case 850: // Latin-1 (Western European)
return 858; // Latin-1 with Euro
default:
return cp;
}
}
// Don't bother about setting up the country or multiple codepages
BOOL SetDOSLocale(const char* path, BOOL bFreeDOS)
{
FILE* fd;
char filename[MAX_PATH];
ULONG cp;
UINT actual_cp;
const char *kb;
int kbdrv;
const char* egadrv;
// First handle the codepage
kb = get_kb();
// We have a keyboard ID, but that doesn't mean it's supported
kbdrv = bFreeDOS ? fd_get_kbdrv(kb) : ms_get_kbdrv(kb);
if (kbdrv < 0) {
uprintf("Keyboard id '%s' is not supported - falling back to 'us'", kb);
kb = "us";
kbdrv = bFreeDOS ? fd_get_kbdrv(kb) : ms_get_kbdrv(kb); // Always succeeds
}
assert(kbdrv >= 0);
uprintf("Will use DOS keyboard '%s' [%s]", kb, kb_to_hr(kb));
// Now get a codepage
cp = GetOEMCP();
if (cp == 65001) {
// GetOEMCP() may return UTF-8 for the codepage (65001),
// in which case we need to find the actual system OEM cp.
if (GetLocaleInfoA(GetUserDefaultUILanguage(), LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
(char*)&actual_cp, sizeof(actual_cp)))
cp = actual_cp;
}
egadrv = bFreeDOS ? fd_get_ega(cp) : ms_get_ega(cp);
if (egadrv == NULL) {
// We need to use the fallback CP from the keyboard we got above, as 437 is not always available
uprintf("Unable to find an EGA file with codepage %d [%s]", cp, cp_to_hr(cp));
cp = kbdrv_data[kbdrv].default_cp;
egadrv = bFreeDOS ? "ega.cpx" : "ega.cpi";
} else if (bFreeDOS) {
cp = fd_upgrade_cp(cp);
}
uprintf("Will use codepage %d [%s]", cp, cp_to_hr(cp));
if ((cp == 437) && (strcmp(kb, "us") == 0)) {
// Nothing much to do if US/US - just notify in autoexec.bat
static_strcpy(filename, path);
static_strcat(filename, "\\AUTOEXEC.BAT");
fd = fopen(filename, "w+");
if (fd == NULL) {
uprintf("Unable to create 'AUTOEXEC.BAT': %s", WindowsErrorString());
return FALSE;
}
fprintf(fd, "@echo off\n");
fprintf(fd, "set PATH=.;\\;\\LOCALE\n");
fprintf(fd, "echo Using %s keyboard with %s codepage [%d]\n", kb_to_hr("us"), cp_to_hr(437), 437);
fclose(fd);
uprintf("Successfully wrote 'AUTOEXEC.BAT'");
return TRUE;
}
// CONFIG.SYS
static_strcpy(filename, path);
static_strcat(filename, "\\CONFIG.SYS");
fd = fopen(filename, "w+");
if (fd == NULL) {
uprintf("Unable to create 'CONFIG.SYS': %s.", WindowsErrorString());
return FALSE;
}
if (bFreeDOS) {
fprintf(fd, "!MENUCOLOR=7,0\nMENU\nMENU FreeDOS Language Selection Menu\n");
fprintf(fd, "MENU \xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\nMENU\n");
} else {
fprintf(fd, "[MENU]\n");
}
fprintf(fd, "MENUDEFAULT=1,5\n");
// Menu item max: 70 characters
fprintf(fd, "%s1%c Use %s keyboard with %s codepage [%d]\n",
bFreeDOS?"MENU ":"MENUITEM=", bFreeDOS?')':',', kb_to_hr(kb), cp_to_hr(cp), (int)cp);
fprintf(fd, "%s2%c Use %s keyboard with %s codepage [%d]\n",
bFreeDOS?"MENU ":"MENUITEM=", bFreeDOS?')':',', kb_to_hr("us"), cp_to_hr(437), 437);
fprintf(fd, "%s", bFreeDOS?"MENU\n12?\n":"[1]\ndevice=\\locale\\display.sys con=(ega,,1)\n[2]\n");
fclose(fd);
uprintf("Successfully wrote 'CONFIG.SYS'");
// AUTOEXEC.BAT
static_strcpy(filename, path);
static_strcat(filename, "\\AUTOEXEC.BAT");
fd = fopen(filename, "w+");
if (fd == NULL) {
uprintf("Unable to create 'AUTOEXEC.BAT': %s", WindowsErrorString());
return FALSE;
}
fprintf(fd, "@echo off\n");
fprintf(fd, "set PATH=.;\\;\\LOCALE\n");
if (bFreeDOS)
fprintf(fd, "display con=(ega,,1)\n");
fprintf(fd, "GOTO %%CONFIG%%\n");
fprintf(fd, ":1\n");
fprintf(fd, "mode con codepage prepare=((%d) \\locale\\%s) > NUL\n", (int)cp, egadrv);
fprintf(fd, "mode con codepage select=%d > NUL\n", (int)cp);
fprintf(fd, "keyb %s,,\\locale\\%s\n", kb, kbdrv_data[kbdrv].name);
fprintf(fd, ":2\n");
fclose(fd);
uprintf("Successfully wrote 'AUTOEXEC.BAT'");
return TRUE;
}