Cutting the cord, revisited -- and documenting how to get the job done!

Sorting it all Out
Michael Kaplan's random stuff of dubious value
Be sure to read the disclaimer here first!

Cutting the cord, revisited -- and documenting how to get the job done!

  • Comments 6

Over in the Suggestion Box, John Daintree asks:

Could you please follow up the missing functionality of LoadKeyboardLayout() on Windows Vista? I need to be able to load a specific layout for my application as the app starts.

The missing functionality in question is I believe what I described in Cutting the cord while someone else is shoring it up, which is the ability to load IMEs via a call to LoadKeyboardLayout, partially ameliorated by Office 2007 which adds three of them back:

  • Microsoft Pinyin IME 2007 for Simplified Chinese (KLID E0200804)
  • Microsoft Office IME 2007 for Korean (KLID E0200412)
  • Microsoft Office IME 2007 for Japanese (KLID E0200411)
  • Perhaps "add" is the wrong word since these three values don't exist in any prior version, but they do enable the LoadKeyboardLayout-style bootstrapping technique of loading up the appropriate IME....

    At the time, I suggested:

    (The question itself is one I'll provide some answers for another time -- since it involves for the IME a TSF sample!)

    However, when I looked into creating such a sample, I noticed a topic in MSDN entitled Language Bar, which states:

    An application cannot add items to the language bar; only a text service can add items to the language bar. An application can affect how certain items on the language bar appear.

    This is a clear departure from prior versions, since in the TSF world you have to have the IME "installed" to the Language Bar to make use of it, but the decision to place it in the Language Bar has clearly been moved to be considered a user decision, not an application one (back in the world of doing this via LoadKeyboardLayout it was obviously an easy application decision)....

    With that said, I ma curious about a situation where a user

    • understands how to use an IME, and
    • expects a certain application to use that IME, yet
    • does not have that IME installed to the Language Bar already?

    And interestingly, switching to an installed IME is an easy operation via an ActivateKeyboardLayout call, and the ability to add a keyboard layout or TSF TIP using the same technique as Regional Options does has now been documented, by calling the InstallLayoutOrTip function in input.dll.

    The latter function call provides the way to directly install or uninstall any keyboard layout or TIP from the Language Bar (it is also the same function that is used by MSKLC 1.4 to support the automatic install and uninstall of keyboard layouts in the automatically provided setup!).

    The function takes the same strings as Regional Options unattend does (discussed previously in On building a list of keyboards).

    The technique only works in Vista, Server 2008, and above (the function does not exist downlevel), though this is the only place that the LoadKeyboardLayout method is broken, so it is at least a step in right direction in terms of keeping functionality working....

    And I will be talking about some of the rest of these now-documented functions (now listed here along with previously documented TSF functions!) inupvoming blogs.

     

    This post brought to you by(U+0c8a, aka KANNADA LETTER UU)

    Comment on the blather
    Leave a Comment
    • Please add 1 and 1 and type the answer here:
    • Post
    Blog - Comment List
    • Hi Michael,

      Interesting stuff, thanks for talking through this.  What I'm seeing on Vista is that if I call ActivateKeyboardLayout (or LoadKeyboardLayout), to activate an already installed layout, "at some time later" the keyboard reverts back to the default.

      What seems to happen is that next time I get to the Message Queue something in msctf.dll (Text Services I guess) switches the layout back (C stack is attached).  Do you have any ideas about what could be causing this?

      What I've done here is put a breakpoint on a Window proc when it gets a WM_INPUTLANGCHANGE message.

      The culprit seems to be:

      msctf.dll!PostInputLangRequest()  + 0xc9 bytes

      Thanks for your continued input (pardon the pun),

      /john

      > dyalog.exe!Session_wnd_proc(HWND__ * hWnd=0x002608fc, unsigned int msg=0x00000051, unsigned int wParam=0x00000000, long lParam=0x08090809)  Line 1879 C
      user32.dll!_InternalCallWinProc@20()  + 0x23 bytes
      user32.dll!_UserCallWinProcCheckWow@32()  + 0xb3 bytes
      user32.dll!_CallWindowProcAorW@24()  + 0x51 bytes
      user32.dll!_CallWindowProcW@20()  + 0x1b bytes
      dyalog.exe!OwnerProc(HWND__ * hWnd=0x002608fc, unsigned int msg=0x00000051, unsigned int wParam=0x00000000, long lParam=0x08090809)  Line 456 C
      user32.dll!_InternalCallWinProc@20()  + 0x23 bytes
      user32.dll!_UserCallWinProcCheckWow@32()  + 0xb3 bytes
      user32.dll!_DispatchClientMessage@20()  + 0x4b bytes
      user32.dll!___fnDWORD@4()  + 0x24 bytes
      ntdll.dll!_KiUserCallbackDispatcher@12()  + 0x2e bytes
      user32.dll!_NtUserActivateKeyboardLayout@8()  + 0xc bytes
      msctf.dll!PostInputLangRequest()  + 0xc9 bytes
      msctf.dll!SyncActivateAssemblyByAsm()  + 0x1b914 bytes
      msctf.dll!SyncActivateAssembly()  + 0x76 bytes
      msctf.dll!ActivateAssemblyPostCleanupCallback()  + 0x22 bytes
      msctf.dll!CCleanupShared::~CCleanupShared()  + 0x2a bytes
      msctf.dll!CCleanupShared::`scalar deleting destructor'()  + 0xd bytes
      msctf.dll!CThreadInputMgr::_CleanupContextsWorker()  + 0x69 bytes
      msctf.dll!CThreadInputMgr::_CleanupContexts()  + 0x38 bytes
      msctf.dll!ActivateAssembly()  + 0xa4 bytes
      msctf.dll!SetFocusDIMForAssembly()  + 0x5e bytes
      msctf.dll!CThreadInputMgr::_SetFocus()  + 0x133 bytes
      msctf.dll!SetDIMFocus()  + 0x55 bytes
      msctf.dll!_GetMsgHook()  + 0x4afd bytes
      msctf.dll!_TF_Notify@12()  + 0x91 bytes
      user32.dll!_CtfHookProcWorker@16()  + 0x21 bytes
      user32.dll!_CallHookWithSEH@16()  + 0x21 bytes
      user32.dll!___fnHkINLPMSG@4()  + 0x25 bytes
      ntdll.dll!_KiUserCallbackDispatcher@12()  + 0x2e bytes
      user32.dll!_NtUserGetMessage@16()  + 0xc bytes
      user32.dll!_GetMessageW@16()  + 0x2b bytes
      dyalog.exe!w3_next_message()  Line 848 + 0x10 bytes C
      dyalog.exe!MessageLoop(int (void)* readfn=0x00676ed0)  

    • Okay, that issue goes a little beyond the scope of what I was trying to cover here, so I moved it over to the suggestion box, here....

    • OK, I guessed as much. Thanks.

    • If you are a regular reader, you may recall either Cutting the cord while someone else is shoring it

    • Joost van Doorn asks (via the Contact link): Hello Michael, Since your name appears in a lot of MSDN

    • Michael,

      I'm trying to use InstallLayoutOrTip to install Tips for the current user, but they seem to only go to local machine.  Can you provide a sample of the correct calling convention to have it apply to the current user.  From the above discussion I'm unclear on how you use ActivateKeyboardLayout if it is not proceeded by LoadKeyboardLayout.

      Thanks,

    Page 1 of 1 (6 items)