question

AlanSinclair-3422 avatar image
AlanSinclair-3422 asked ·

how to programmatically install a keyboard layout?

I need to package several different keyboard layouts aka "input locale identifiers" together, so I need to write some code to install a layout in Windows, but haven't found any documentation. Can anyone show me example code or point me to documentation? Backgound: Microsoft's MSKLC tool enables creation of Keyboard Layouts. Each single layout is 'contained' in a DLL; for a layout MSKLC creates four DLLs for various flavors of Windows (naming them i386, amd64, ia64, wow64). MSKLC also creates the three appropriate MSI installers for that single layout, but those installers cannot be used in this situation. Just deploying the DLLs doesn't enable them, there is obviously some action needed to add the new locale identifiers to what Windows knows about its keyboards.

(I'm unsure this is the right place for this question, and what tags should be used .. please correct me if necessary)

winapi-general
1 comment
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@AlanSinclair-3422 What kind of project are you using?

0 Votes 0 · ·
AlanSinclair-3422 avatar image
AlanSinclair-3422 answered ·

> What kind of project are you using?

WiX Toolset and Visual Studio 2017 writing C++ code.

Using the WiX Toolset I'm making an MSI install package to deploy an input locale definition file; for reference I'll call that file LOCALE.DLL

LOCALE.DLL is created by MSKLC to define the new keyboard layout. The specific language will already be installed on the target system; this new input locale remaps various keys for our specific needs. Msiexec.exe (the native Windows Installer) will install LOCALE.DLL from my MSI file.

My MSI needs a custom action written in C++ using Visual Studio 2017

As msiexec deploys LOCALE.DLL from my MSI, msiexec will call functions in a custom action binary (for reference I'll call this binary CUSTOM.DLL) which in turn calls WINAPI functions to "activate" the input locale: e.g. to add the keyboard configuration defined in LOCALE.DLL to the Windows Language Bar, etc. (CUSTOM.DLL is not deployed on the target system; it remains embedded in the MSI)

For what it's worth, I'm familiar with writing custom action DLLs for Windows Installer; what I'm missing is how to activate the input locale provided in LOCALE.DLL which my MSI deploys.

I think CUSTOM.DLL will need to use LoadKeyboardLayout and ActivateKeyboardLayout WINAPI functions but I have not found documentation

Any pointers to documentation or example code you can give will be much appreciated!

Thanks

1 comment Share
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@AlanSinclair-3422 Your question about WiX Toolset is not supported in Microsoft Q&A yet now. Microsoft Q&A supports the products listed over here: supported topics (more to be added later on). You could ask this question in the forum about WiX Toolset to ask for help.

0 Votes 0 · ·
AlanSinclair-3422 avatar image
AlanSinclair-3422 answered ·

Sorry, I confused the issue. This is NOT about the Wix Toolset.

I am asking what C++ code do I write to install an input locale (aka keyboard layout).

Please can you give me a pointer to C++ or WINAPI documentation or example code for how to install an input locale?

(The wix tool is just a deployment mechanism and not really relevant to my question. I mentioned it to give the full background, but it's unnecessary. I can use a C++ exe if you tell me where to find example or documentation.)

thanks

Share
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

DrakeWu-MSFT avatar image
DrakeWu-MSFT answered ·

Hi @AlanSinclair-3422 Please check if this Keyboard Layout Samples and the steps in it are what you need.


If the answer is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

Share
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

AlanSinclair-3422 avatar image
AlanSinclair-3422 answered ·

@DrakeWu-MSFT
Thanks DrakeWu .. the link gives samples of how to create new Keyboard Layouts, but what I need is example of how to USE a new layout -- i.e. how to install the new layout in Windows.

Is there any example code to use LoadKeyboardLayout API, and/or ActivateKeyboardLayout API ?

thanks
Alan

1 comment Share
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi, @AlanSinclair-3422 You will need to go through the registry [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts], Add the locale identifier for your layout, and add the corresponding key value according to other layouts, then put your dll in the %windir%\system32 directory, and then use LoadKeyboardLayout and ActivateKeyboardLayout to load and activate it:

     HKL hkl, ret;
     hkl = LoadKeyboardLayout(L"00000409", KLF_ACTIVATE);
     ret = ActivateKeyboardLayout(hkl, KLF_SETFORPROCESS);
0 Votes 0 · ·
RobertSullivan-9551 avatar image
RobertSullivan-9551 answered ·

There has to be more to it than what Drake-WU has described.

What does 'add the corresponding key value according to other layouts' mean?

I created a Keyboard Layout with MKLSC. The install package calls out to an imbedded Custom.dll to perform some registry operations.
The installed keyboard appears within the 'Language Bar'.

I created a Keyboard layout from the Sample Keyboard Layouts (KBDUS.dll), ClientUs.dll.
'Installed' it following your suggestion (I think?)

'add the corresponding key value according to other layouts':
I modeled the registry values under [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00060409]
after the registry values for [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000409].
Is this what you mean?

HKEY_CURRENT_USER\Keyboard Layout\Substitutes has a REG_SZ entry for d0020409 with a value of 00060409
HKEY_CURRENT_USER\Keyboard Layout\Preload has a REG_SZ entry for 3 with a value of d0020409

Note: I picked 00060409 arbitrarily.

My Keyboard Layout shows up in Settings->Time & Language->Language->English->Options->Add a keyboard.
I can add the keyboard.
I can load the layout via LoadKeyBoardLayout("00060409").

My Keyboard Layout does not show in the 'Language Bar'.

Does something additional need to occur for an install to show up in the 'Language Bar'?

Thanks

Share
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

AlanSinclair-3422 avatar image
AlanSinclair-3422 answered ·

> Does something additional need to occur for an install to show up in the 'Language Bar'

The custom.dll used in the MSKLC installer has two functions for installing the layout: 'RegisterKeyboard', and 'AddKeyboardToLangBar' (entry points CA01 and CA03 respectively); it also provides two uninstall functions: 'UnRegisterKeyboard' and 'RemoveKeyboardFromLangBar' (entry points CA02 & CA04).

So I guess you need a function analogous to 'AddKeyboardToLangBar'. Which is probably DrakeWu's example line 3 does:

        ret = ActivateKeyboardLayout(hkl, KLF_SETFORPROCESS);

[I haven't yet had an opportunity to use DrakeWu's example. I only get to revisit this issue occasionally so my apologies if this comment is uselessly out of date]

Btw the custom.dll's CA03 'AddKeyboardToLangBar' adds more registry entries but I haven't experimented with replicating those

@RobertSullivan-9551
If you get this working please share!

thanks

Share
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

RobertSullivan-9551 avatar image
RobertSullivan-9551 answered ·

I am piping in on this due to the fact that I have a Windows 10, C++.
application that needs to use two Custom Keyboard Layouts in conjunction with
a Keyboard Filter Driver.

The real answer here is for Microsoft to simply release the source code for the Custom.dll imbedded within an MSKLC installer package. I am surprised that they have not already done so. I am of course not sure where to post such a request and what tags to attach to it or how to word the topic in order to get the appropriate People's top see it.

I have not visited MSND for quite some time now. I am surprised at the limited 'tags' one can apply to a topic. I believe that winapi-general seems to be the only suitable 'tag' to apply to any sort of Win32 based question. It seems this site has become really azure concentric.

When I am done with this post I will post a request for the source code to Custom.dll titles 'MSKLC / Custom.dll Source Code' tagged with winapi-general so you can find it.

What DrakeWu described will work if one simply wants to load the Keyboard Layout and activate it,
but the Keyboard Layout will NOT appear within the Language Bar.
I have two 'Custom' Keyboard 'Installed':
- A Custom Keyboard Created And Installed Via MSKLC. Named: US-Custom
This Keyboard shows up within the Language Bar.
- A Custom Keyboard I created from the KBDUS Sample Layout and 'Installed' as DrakeWu suggested. Named: 'Client-US'.
This Keyboard DOES NOT show up within the Language Bar.

Here is some output:
Initial ActiveKeyBoard:0x04090409
Initial KeyBoardLayoutName:00000409
GetLayoutFromRegistry():SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000409
Layout Text::US

// This Is 'My' Keyboard Layout.
LoadKeyBoardLayout(00060409,(UINT)0)
LoadedKeyboardLayout:0xFFFE0409
ActivateKeyboardLayout(0xFFFE0409,KLF_SETFORPROCESS)
Last LoadedKeyboardLayout:0x04090409
LoadedKeyboardLayout Now:0xFFFE0409
GetKeyboardLayoutName():00060409
GetLayoutFromRegistry():SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00060409
Layout Text::Client-US
BufferKeyBoard:Client-US

// This Is The Keyboard Created And Installed With MSKLC
LoadKeyBoardLayout(a0000409,(UINT)0)
LoadedKeyboardLayout:0xF0C00409
ActivateKeyboardLayout(0xF0C00409,KLF_SETFORPROCESS)
Last LoadedKeyboardLayout:0xFFFE0409
LoadedKeyboardLayout Now:0xF0C00409
GetKeyboardLayoutName():A0000409
GetLayoutFromRegistry():SYSTEM\CurrentControlSet\Control\Keyboard Layouts\A0000409
Layout Text::US - Custom
BufferKeyBoard:US - Custom

//======================================================================
As a side bar I am annoyed with the fact that is seems impossible to ascertain the appropriate KLID from a HKL:
HKL For MSKLC Keyboard: 0xF0C00409
KLID For MSKLC Keyboard: 0xa0000409

There seems to be no bit manipulation that can produce a0000409 from F0C00409
This makes GetKeyboardLayoutList() useless for my purposes.


Share
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

RobertSullivan-9551 avatar image
RobertSullivan-9551 answered ·

Alan.

See my post over in stackoverflow



Not sure if this relates to your install scenario in the end but it relates to mine.
If you read between the lines one can see that the HKEY_USERS.DEFAULT\Keyboard Layout (I think that is the appropriate key) seems to come into play if you want the system to actually load your keyboard at boot so one does not need to physically load it via LoadKeyboardLayout().

I will give my request for the Custom.dll source a day or two. If I get no response I will start asking questions on Stackoverflow.




Share
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.