c++visual-c++mfckeyboard-layout

How to get keyboard name? (to visually distinguish keyboards in a specific language)


I have for example 2 languages installed — English and Russian. And Russian has 2 keyboards — Ordinary and Mnemonic:

enter image description here

When I run the code:

UINT uLayouts;
HKL  *lpList = NULL;
wchar_t szBufLng[512], szBufCtry[512];

uLayouts = GetKeyboardLayoutList(0, NULL);
lpList   = (HKL*)LocalAlloc(LPTR, (uLayouts * sizeof(HKL)));
uLayouts = GetKeyboardLayoutList(uLayouts, lpList);

for(int i = 0; i < uLayouts; ++i)
{
    GetLocaleInfo(MAKELCID(((UINT)lpList[i] & 0xffffffff), 
    SORT_DEFAULT), LOCALE_SISO639LANGNAME, szBufLng, 512);
    GetLocaleInfo(MAKELCID(((UINT)lpList[i] & 0xffffffff), 
    SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, szBufCtry, 512);
    wprintf(L"%s-%s, %x\n", szBufLng, szBufCtry, (UINT)lpList[i]);
    memset(szBufLng, 0, 512);
    memset(szBufCtry, 0, 512);
}

if(lpList)
    LocalFree(lpList);

I get the following result:

en-US, 04090409
ru-RU, 04190419
ru-RU, f0330419

My question is how to distinguish the mnemonic? At least to display something like this:

en-US,  04090409
ru-RU,  04190419
rum-RU, f0330419

How to get keyboard name?

Same problem is discussed here (no solution): https://forums.codeguru.com/showthread.php?492287-Keyboard-Layout-Name

http://web.archive.org/web/20081025132249/http://blogs.msdn.com/michkap/archive/2004/12/05/275231.aspx

http://web.archive.org/web/20100330193933/http://blogs.msdn.com/michkap/archive/2008/09/29/8968315.aspx


Solution

  • I exported data from the registry (\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts) in Windows 10 and based on it created a table. And with the help of SHLoadIndirectString got the localized name of the keyboard.

    struct LAYOUT_KEYBOARD_INFO {
        LCID layout_id;
        short display_name_id;
        wchar_t default_keyboard_name[64];
    };
    
    LAYOUT_KEYBOARD_INFO LAYOUT_KEYBOARDS[] = {
        {0x0401, 5084, L"Arabic (101)"},
        {0x0402, 5053, L"Bulgarian (Typewriter)"},
        {0x0404, 5065, L"Chinese (Traditional) - US Keyboard"},
        {0x0405, 5031, L"Czech"},
        {0x0406, 5007, L"Danish"},
        {0x0407, 5011, L"German"},
        {0x0408, 5046, L"Greek"},
        {0x0409, 5000, L"US"},
        {0x040A, 5020, L"Spanish"},
        {0x040B, 5009, L"Finnish"},
        {0x040C, 5010, L"French"},
        {0x040D, 5083, L"Hebrew"},
        {0x040E, 5033, L"Hungarian"},
        {0x040F, 5013, L"Icelandic"},
        {0x0410, 5015, L"Italian"},
        {0x0411, 5061, L"Japanese"},
        {0x0412, 5063, L"Korean"},
        {0x0413, 5008, L"Dutch"},
        {0x0414, 5018, L"Norwegian"},
        {0x0415, 5035, L"Polish (Programmers)"},
        {0x0416, 5003, L"Portuguese (Brazilian ABNT)"},
        {0x0418, 5037, L"Romanian (Legacy)"},
        {0x0419, 5055, L"Russian"},
        {0x041A, 5030, L"Standard"},
        {0x041B, 5039, L"Slovak"},
        {0x041C, 5029, L"Albanian"},
        {0x041D, 5022, L"Swedish"},
        {0x041E, 5079, L"Thai Kedmanee"},
        {0x041F, 5060, L"Turkish Q"},
        {0x0420, 5129, L"Urdu"},
        {0x0422, 5058, L"Ukrainian"},
        {0x0423, 5052, L"Belarusian"},
        {0x0424, 5041, L"Slovenian"},
        {0x0425, 5042, L"Estonian"},
        {0x0426, 5043, L"Latvian"},
        {0x0427, 5045, L"Lithuanian IBM"},
        {0x0428, 5151, L"Tajik"},
        {0x0429, 5124, L"Persian"},
        {0x042A, 5118, L"Vietnamese"},
        {0x042B, 5120, L"Armenian Eastern"},
        {0x042C, 5117, L"Azeri Latin"},
        {0x042E, 5163, L"Sorbian Standard (Legacy)"},
        {0x042F, 5109, L"Macedonian (FYROM)"},
        {0x0432, 5191, L"Setswana"},
        {0x0437, 5119, L"Georgian"},
        {0x0438, 5108, L"Faeroese"},
        {0x0439, 5096, L"Devanagari - INSCRIPT"},
        {0x043A, 5140, L"Maltese 47-Key"},
        {0x043B, 5138, L"Norwegian with Sami"},
        {0x043F, 5113, L"Kazakh"},
        {0x0440, 5128, L"Kyrgyz Cyrillic"},
        {0x0442, 5150, L"Turkmen"},
        {0x0444, 5116, L"Tatar (Legacy)"},
        {0x0445, 5135, L"Bengali"},
        {0x0446, 5101, L"Punjabi"},
        {0x0447, 5097, L"Gujarati"},
        {0x0448, 5100, L"Oriya"},
        {0x0449, 5102, L"Tamil"},
        {0x044A, 5103, L"Telugu"},
        {0x044B, 5098, L"Kannada"},
        {0x044C, 5139, L"Malayalam"},
        {0x044D, 5177, L"Assamese - INSCRIPT"},
        {0x044E, 5104, L"Marathi"},
        {0x0450, 5127, L"Mongolian Cyrillic"},
        {0x0451, 5154, L"Tibetan (PRC)"},
        {0x0452, 5145, L"United Kingdom Extended"},
        {0x0453, 5161, L"Khmer"},
        {0x0454, 5162, L"Lao"},
        {0x045A, 5130, L"Syriac"},
        {0x045B, 5166, L"Sinhala"},
        {0x045C, 5209, L"Cherokee Nation"},
        {0x0461, 5169, L"Nepali"},
        {0x0463, 5159, L"Pashto (Afghanistan)"},
        {0x0465, 5132, L"Divehi Phonetic"},
        {0x0468, 5187, L"Hausa"},
        {0x046A, 5189, L"Yoruba"},
        {0x046C, 5186, L"Sesotho sa Leboa"},
        {0x046D, 5148, L"Bashkir"},
        {0x046E, 5168, L"Luxembourgish"},
        {0x046F, 5170, L"Greenlandic"},
        {0x0470, 5188, L"Igbo"},
        {0x0474, 5231, L"Guarani"},
        {0x0475, 5198, L"Hawaiian"},
        {0x0480, 5165, L"Uyghur (Legacy)"},
        {0x0481, 5146, L"Maori"},
        {0x0485, 5160, L"Sakha"},
        {0x0488, 5190, L"Wolof"},
        {0x0492, 5199, L"Central Kurdish"},
        {0x0804, 5072, L"Chinese (Simplified) - US Keyboard"},
        {0x0807, 5024, L"Swiss German"},
        {0x0809, 5025, L"United Kingdom"},
        {0x080A, 5017, L"Latin American"},
        {0x080C, 5002, L"Belgian French"},
        {0x0813, 5001, L"Belgian (Period)"},
        {0x0816, 5019, L"Portuguese"},
        {0x081A, 5038, L"Serbian (Latin)"},
        {0x082C, 5115, L"Azeri Cyrillic"},
        {0x083B, 5144, L"Swedish with Sami"},
        {0x0843, 5114, L"Uzbek Cyrillic"},
        {0x0850, 5158, L"Mongolian (Mongolian Script)"},
        {0x085D, 5156, L"Inuktitut - Latin"},
        {0x085F, 5229, L"Central Atlas Tamazight"},
        {0x0C04, 5192, L"Chinese (Traditional, Hong Kong S.A.R.) - US Keyboard"},
        {0x0C0C, 5005, L"Canadian French (Legacy)"},
        {0x0C1A, 5057, L"Serbian (Cyrillic)"},
        {0x0C51, 5235, L"Dzongkha"},
        {0x1004, 5193, L"Chinese (Simplified, Singapore) - US Keyboard"},
        {0x1009, 5004, L"Canadian French"},
        {0x100C, 5023, L"Swiss French"},
        {0x105F, 5207, L"Tifinagh (Basic)"},
        {0x1404, 5194, L"Chinese (Traditional, Macao S.A.R.) - US Keyboard"},
        {0x1809, 5014, L"Irish"},
        {0x201A, 5155, L"Bosnian (Cyrillic)"},
        {0x4009, 5196, L"India"},
    // Added F to "Layout Id"
        {0xF028, 5085, L"Arabic (102)"},
        {0xF004, 5054, L"Bulgarian (Latin)"},
        {0xF005, 5032, L"Czech (QWERTY)"},
        {0xF012, 5012, L"German (IBM)"},
        {0xF016, 5048, L"Greek (220)"},
        {0xF002, 5092, L"United States-Dvorak"},
        {0xF086, 5021, L"Spanish Variation"},
        {0xF006, 5034, L"Hungarian 101-key"},
        {0xF003, 5016, L"Italian (142)"},
        {0xF007, 5036, L"Polish (214)"},
        {0xF010, 5126, L"Portuguese (Brazilian ABNT2)"},
        {0xF0A5, 5175, L"Romanian (Standard)"},
        {0xF008, 5056, L"Russian (Typewriter)"},
        {0xF013, 5040, L"Slovak (QWERTY)"},
        {0xF021, 5080, L"Thai Pattachote"},
        {0xF014, 5059, L"Turkish F"},
        {0xF015, 5044, L"Latvian (QWERTY)"},
        {0xF027, 5088, L"Lithuanian"},
        {0xF025, 5121, L"Armenian Western"},
        {0xF0BD, 5234, L"Azerbaijani (Standard)"},
        {0xF09F, 5164, L"Sorbian Extended"},
        {0xF0A4, 5174, L"Macedonian (FYROM) - Standard"},
        {0xF0AB, 5182, L"Georgian (QWERTY)"},
        {0xF00C, 5105, L"Hindi Traditional"},
        {0xF02B, 5141, L"Maltese 48-Key"},
        {0xF02C, 5143, L"Sami Extended Norway"},
        {0xF0BC, 5233, L"Tatar"},
        {0xF02A, 5136, L"Bengali - INSCRIPT (Legacy)"},
        {0xF0B5, 5222, L"Tibetan (PRC) - Updated"},
        {0xF02F, 5200, L"Khmer (NIDA)"},
        {0xF00E, 5131, L"Syriac Phonetic"},
        {0xF0A0, 5167, L"Sinhala - Wij 9"},
        {0xF037, 5201, L"Cherokee Nation Phonetic"},
        {0xF0A7, 5171, L"Inuktitut - Naqittaut"},
        {0xF00D, 5133, L"Divehi Typewriter"},
        {0xF0AD, 5185, L"Uyghur"},
        {0xF01E, 5089, L"Belgian (Comma)"},
        {0xF02D, 5137, L"Finnish with Sami"},
        {0xF0B2, 5225, L"Traditional Mongolian (Standard)"},
        {0xF030, 5249, L"Myanmar (Phonetic order)"},
        {0xF020, 5110, L"Canadian Multilingual Standard"},
        {0xF036, 5208, L"Tifinagh (Full)"},
        {0xF026, 5125, L"Gaelic"},
        {0xF029, 5086, L"Arabic (102) AZERTY"},
        {0xF0A3, 5173, L"Bulgarian (Phonetic)"},
        {0xF00A, 5087, L"Czech Programmers"},
        {0xF018, 5049, L"Greek (319)"},
        {0xF001, 5026, L"United States-International"},
        {0xF03D, 5214, L"Hebrew (Standard)"},
        {0xF0A6, 5176, L"Romanian (Programmers)"},
        {0xF033, 5203, L"Russian - Mnemonic"},
        {0xF022, 5081, L"Thai Kedmanee (non-ShiftLock)"},
        {0xF0A8, 5179, L"Ukrainian (Enhanced)"},
        {0xF0B1, 5224, L"Latvian (Standard)"},
        {0xF0A1, 5172, L"Lithuanian Standard"},
        {0xF038, 5217, L"Armenian Phonetic"},
        {0xF0AE, 5184, L"Sorbian Standard"},
        {0xF0AC, 5181, L"Georgian (Ergonomic)"},
        {0xF0A9, 5178, L"Bengali - INSCRIPT"},
        {0xF0C8, 5246, L"Tamil 99"},
        {0xF02E, 5142, L"Sami Extended Finland-Sweden"},
        {0xF031, 5204, L"New Tai Lue"},
        {0xF0AA, 5180, L"Bulgarian"},
        {0xF017, 5050, L"Greek (220) Latin"},
        {0xF01A, 5027, L"United States-Dvorak for left hand"},
        {0xF023, 5082, L"Thai Pattachote (non-ShiftLock)"},
        {0xF039, 5218, L"Armenian Typewriter"},
        {0xF03B, 5215, L"Georgian Ministry of Education and Science Schools"},
        {0xF034, 5205, L"Tai Le"},
        {0xF0AF, 5195, L"Bulgarian (Phonetic Traditional)"},
        {0xF011, 5051, L"Greek (319) Latin"},
        {0xF01B, 5028, L"United States-Dvorak for right hand"},
        {0xF03C, 5216, L"Georgian (Old Alphabets)"},
        {0xF032, 5206, L"Ogham"},
        {0xF019, 5047, L"Greek Latin"},
        {0xF00B, 5123, L"US English Table for IBM Arabic 238_L"},
        {0xF03A, 5213, L"Persian (Standard)"},
        {0xF01F, 5122, L"Greek Polytonic"},
        {0xF03E, 5210, L"Lisu (Basic)"},
        {0xF03F, 5211, L"Lisu (Standard)"},
        {0xF040, 5212, L"N’Ko"},
        {0xF041, 5219, L"Phags-pa"},
        {0xF0B3, 5220, L"Buginese"},
        {0xF0B4, 5221, L"Gothic"},
        {0xF0B6, 5223, L"Ol Chiki"},
        {0xF0B7, 5226, L"Osmanya"},
        {0xF0B8, 5227, L"Old Italic"},
        {0xF0B9, 5228, L"Sora"},
        {0xF0BA, 5230, L"Javanese"},
        {0xF0BB, 5232, L"Futhark"},
        {0xF0CB, 5250, L"Myanmar (Visual Order)"},
        {0xF0CC, 5251, L"ADLaM"},
        {0xF0CD, 5252, L"Osage"}
    };
    
    CString GetLayoutKeyboardDisplayName(DWORD layout, bool fLocalized = true) {
        DWORD layout_id = layout >> 16;
        CString keyboard_name = L"";    
        int number_of_elements = sizeof(LAYOUT_KEYBOARDS)/sizeof(LAYOUT_KEYBOARDS[0]);
        for (int i = 0; i < number_of_elements; i++)
            if (LAYOUT_KEYBOARDS[i].layout_id == layout_id) {
                wchar_t szBuf[512];
                if (fLocalized && SHLoadIndirectString(L"@%SystemRoot%\\system32\\input.dll,-" + IntToStr(LAYOUT_KEYBOARDS[i].display_name_id), szBuf, 512, NULL) == S_OK)
                    keyboard_name.Format(L"%s", szBuf);
                else
                    keyboard_name = LAYOUT_KEYBOARDS[i].default_keyboard_name;
                memset(szBuf, 0, 512);
                return keyboard_name;
            }
    
        keyboard_name.Format(L"%X", layout_id);
        keyboard_name.TrimLeft(L"0");
        return keyboard_name;
    }    
    //...
    wprintf(L"%X, %s\n", (UINT)lpList[i], GetLayoutKeyboardDisplayName((UINT)lpList[i]));