How to create a list of Keyboards. Extract KLID from HKL?

时光毁灭记忆、已成空白 提交于 2021-01-28 05:08:33

问题


Windows 10 / C++ / Win32

I need to make a list of 'installed' Keyboards.

The components of my 'list' needs to contain:

  • The HKL for the keyboard.
  • The KLID for the keyboard.
  • The values of the registry values obtained from:
  • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts
  • Example: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000409
  • Value: Layout File
  • Value: Layout Text

The only way I am aware of enumerating Keyboards is via GetKeyboardLayoutList(), which returns a list of HKL's.

Methodology which works for 'standard' keyboards (HKL's 04090409, 04070407,..).

TCHAR Buffer[50];
TCHAR Buffer2[50];
HKL LoadedKeyboardLayout;

// Hkl: 04090409
_stprintf_s(Buffer, (sizeof(Buffer)/sizeof(TCHAR)), _T("%08X"), (((UINT)Hkl >> 16) & 0xFFFF));
// Buffer: "0000409"
LoadedKeyboardLayout = LoadKeyboardLayout(Buffer, (UINT)0);
// It Loads

ActivateKeyboardLayout(LoadedKeyboardLayout, KLF_SETFORPROCESS);
// It Activates

GetKeyboardLayoutName(Buffer2); 
// Buffer2: "00000409"

// I can now fish the registry HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000409

This DOES not work when the 'device identifier' is NOT 0000.

From LoadKeyboardLayout() documentation:

The name of the input locale identifier to load. This name is a string composed of the hexadecimal value of the Language Identifier (low word) and a device identifier (high word). For example, U.S. English has a language identifier of 0x0409, so the primary U.S. English layout is named "00000409". Variants of U.S. English layout (such as the Dvorak layout) are named "00010409", "00020409", and so on.

If one creates a 'Custom' keyboard, I find it is impossible to get the 'device identifier' from the custom keyboards HKL.

For instance:

  • Create a Custom Keyboard US with MKLCS.
  • Install it.
  • The 'KLID' will be 'A0000409'.
  • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\a0000409
  • The HKL will be 0xF0C00409 (as returned within the HKL list generated by GetKeyboardLayoutList()).
  • In order to load the keyboard with LoadKeyboardLayout(), one needs 'A0000409'.
  • It does not seem possible to create A0000409 from F0C00409.
  • I also created my own keyboard layout without MKLCS.
  • I arbitrarily named it 00060409.
  • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00060409
  • It's HKL is FFFE0409 (as returned within the HKL list generated by GetKeyboardLayoutList()).
  • It does not seem possible to create 00060409 from FFFE0409.

With all of that said, how does one obtain a KLID from an HKL?

Or, is there another way I can go about creating my list of installed keyboards?

//================================================================ 11/25/2020 Addition.

Thank you Rita.

It seems as if GetKeyboardLayoutList() creates a list of 'Loaded' keyboard layouts.

  • System loaded keyboard layouts, 0x0409409,....
  • Keyboard Layouts installed via MKLCS installation.

It seems that any Keyboards defined within the following registry keys will get loaded at boot.

  • HKEY_CURRENT_USER\Keyboard Layout Note the Preload and Substitute value's.

(Note there are many other 'Keyboard Layout' keys spread around within the registry, so I am not sure if HKEY_CURRENT_USER\Keyboard Layout is the actual registry key that defines the PreLoad - Substitutes.

  • HKEY_USERS\.DEFAULT\Keyboard Layout
  • HKEY_USERS\S-1-5-18 (My User Account)
  • HKEY_LOCAL_MACHINE\SYSTEM\Keyboard Layout )

So there is no doubt in my mind that Rita's example works due to the fact that her HKEY_CURRENT_USER\Keyboard Layout contains the following entries: Preload: 1 d0010804

Substitutes: d0010804 a0000804

The entries may have been put there by the MKLCS installer? Or perhaps the action of adding the keyboard via Settings->Time & Language->Click on Preferred Language->Options->Add a Keyboard

From ActivateKeyboardLayout() documentation:

The input locale identifier must have been loaded by a previous call to the LoadKeyboardLayout function.

Since a0000804 (HKL: F0C00804) is actually already loaded ActivateKeyboardLayout() works.

Since my KLID: 00060409 is not referenced within any of the X\Keyboard Layout Preload and Substitutes I must physically call LoadKeyBoardLayout(L"00060409") in order for it to appear within the GetKeyboardList() HKL's.

Thanks again Rita.


回答1:


how does one obtain a KLID from an HKL?

There seems no direct method out of box to achieve it.

A workaround is retrieving a list of HKLs, then active a layout via a HKL, then get its KLID. The following is an example:

int cnt = GetKeyboardLayoutList(sizeof(hklArr)/sizeof(hklArr[0]), hklArr);
if(cnt > 0)
{
    printf("keyboard list: \n");
    for (UINT i = 0; i < cnt; i++)
    {
        printf("%x\n", (LONG_PTR)hklArr[i]);
        if (ActivateKeyboardLayout(hklArr[i], KLF_SETFORPROCESS))
        {
            WCHAR pName[KL_NAMELENGTH];
            if (GetKeyboardLayoutName(pName))
            {
                wprintf(L"layout name (KLID): %s\n", pName);
            }
        }
    }
}

Result like this:

Update:

Update 2: Share my creating and installing steps.

I use Keyboard Layout Creator 1.4.

  1. Load an existing keyboard for testing purpose. (You can modify based on it or create your own completely.)

  1. Valid and test keyboard to make sure it works as you expected. Then build DLL and setup package.

  1. Run setup.exe generated by step 2. After installation complete you will see the related preload keyboard layout item in registry.



来源:https://stackoverflow.com/questions/64995173/how-to-create-a-list-of-keyboards-extract-klid-from-hkl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!