/* * Rufus: The Reliable USB Formatting Utility * DOS keyboard locale setup * Copyright © 2011-2024 Pete Batard * * 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 . */ /* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */ #ifdef _CRTDBG_MAP_ALLOC #include #include #endif #include #include #include #include #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= 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; }