by Michael S. Kaplan, published on 2007/09/02 04:46 -04:00, original URI: http://blogs.msdn.com/b/michkap/archive/2007/09/02/4701403.aspx
Following up on yet another of those fun issues that spins out of the architecture for custom keyboard layouts based on custom languages that I described in Getting the language (and more!) of an LCID-less keyboard and continued in MSKLC keyboard layout names in your own language....
Every custom locale/culture has an assumed LCID value of 0x00001000, which is also known as LOCALE_CUSTOM_UNSPECIFIED in winnt.h, defined as follows:
#define LOCALE_CUSTOM_UNSPECIFIED \
(MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED), SORT_DEFAULT))
You might not like this, and if you don't then you are not alone; this is a controversial thing that even today some people still think could have and should have been done differently.
But that is not what this post is about, so I'll talk about that another day.
Now there are two other "custom culture" LCID values, defined in that same header file:
#define LOCALE_CUSTOM_DEFAULT \
(MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), SORT_DEFAULT))
#define LOCALE_CUSTOM_UI_DEFAULT \
(MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT), SORT_DEFAULT))
Both of these values: LOCALE_CUSTOM_DEFAULT (a.k.a. 0x00000c000) and LOCALE_CUSTOM_UI_DEFAULT (a.k.a. 0x00001400) are kind of dumb-seeming, as any time they are valid you can get the same data back and the same locale used by asking for LOCALE_USER_DEFAULT or querying for the user default UI language via a call to GetUserDefaultUILanguage.
So why do they exist?
Well that way a call to GetUserDefaultUILanguage or GetUserDefaultLCID has some value to return, a value that can be passed to LCID taking functions and still actually do something useful.
Fair enough.
So now, to get back to keyboards for a moment, all of the above is fine and dandy, but the real question that all of this is able to inspire is simple -- why do custom keyboards with custom language all use 0x0c00 as their LANGID value?
This is after all the value for LOCALE_CUSTOM_DEFAULT, which is not the LCID value of the custom culture that MSKLC lets you pick to work from a custom culture, and it is pretty guaranteed to not return correct data.
The answer is simple enough -- most people take the HKL value they get back from LoadKeyboardLayout or ActivateKeyboardLayout, call the LOWORD macro to extract the LANGID value, and then use it.
But the one advantage that both LOCALE_CUSTOM_DEFAULT and LOCALE_CUSTOM_UI_DEFAULT have over LOCALE_CUSTOM_UNSPECIFIED is that if you do pass them one of those other functions, the other function will likely still be able to work. Even if the value is probably going to be wrong sometimes.
Now this is yet another of those decisions that another group made (in this case the Language Bar/Text Services Framework people), as i kind of oscillate between occasionally thinking this decision was brilliant, occasionally thinking is was awful/terrible, and usually falling somewhere in between.
The real answer is to use names rather than LANGID values, and with the architecture info described in Getting the language (and more!) of an LCID-less keyboard, adding a function to return this info in some future version of Windows would not be too terribly hard to do.
But since some value had to be returned, and ideally it should not be a value that breaks the myriad of LOWORD(GetKeyboardLayout(0)) callers out there. So now we have 0x0c00 as the LANGID that in the NLS world means "custom user default" and in the keyboarding world means "any custom language whatsoever"....
This post brought to you by ∫ (U+222b, a.k.a. INTEGRAL)
Ivan Petrov on 2 Sep 2007 5:29 PM:
Hi Michael,
Did the Language Bar/Text Services Framework people have their own blog or someone working in that group his own blog, like you?
Regards,
Ivan.
Eric C Brown on 3 Oct 2007 2:30 PM:
I have a Text Services Framework related blog (linked), but I don't actually work in that group - I work on speech & dictation, but I spend a lot of time working with Text Services Framework.