Detecting the IME status of other windows

명훈 이 0 Reputation points
2025-11-07T09:30:35.84+00:00

The following code works correctly on Windows 10.

        HWND forehwnd = GetForegroundWindow();

        HWND ime = ImmGetDefaultIMEWnd(forehwnd);

        LRESULT ret = SendMessageA(ime, WM_IME_CONTROL, 0x05, 0);

I checked using ret, but it always returns 0 on Windows 11 OS. What could be the reason?

Windows development | Windows API - Win32

2 answers

Sort by: Most helpful
  1. zdn 0 Reputation points
    2026-09-05T09:24:32.98+00:00

    I recently ran into the same issue as well.

    To avoid the situation you mentioned, I tested this on Windows 10. This version still uses the IME-related implementation. I also found an input method based on TSF, which is Rime. Its repository is here:

    https://github.com/rime

    I also wrote a small test program to print out the message types:

    auto msg = MSG{};
    while (GetMessageW(&msg, nullptr, 0, 0)) {
      if (msg.hwnd == nullptr) {
        std::cout << msg.message << "\n";
      } else {
        DispatchMessageW(&msg);
      }
    }
    

    I found that when using the Windows 10 IME-related implementation, the corresponding IME notification event does have a message value. The hexadecimal value starts from 0xC000, and the decimal value is 49255. This value is different every time I restart the computer.

    This also indicates that the IME notification event has a NULL hwnd.

    However, when I switched to Rime, which is based on TSF, I found that there were no corresponding IME notification messages at all. In other words, GetMessage cannot retrieve the event messages related to TSF.

    When I changed the code to this:

    auto msg = MSG{};
    while (GetMessageW(&msg, nullptr, 0, 0)) {
      DispatchMessageW(&msg);
    }
    

    and simply dispatched all events, the IME switching worked correctly when I pressed the Shift key.

    As far as I know, many Windows applications often have two threads, and they use msg.hwnd == NULL to filter out custom messages used internally by the application.

    As I mentioned above, IME notification events have a NULL hwnd, so they won't be dispatched by this logic.

    If Notepad doesn't work for testing, you could try writing a simple Win32 window with a button that toggles the IME state when clicked. In that case, it won't check msg.hwnd == NULL.

    I'm not sure if this helps, but hopefully it gives you another clue about the issue.

    Was this answer helpful?

    0 comments No comments

  2. Danny Nguyen (WICLOUD CORPORATION) 8,725 Reputation points Microsoft External Staff Moderator
    2025-11-07T11:21:09.7+00:00

    Hi,

    Thank you for posting on Microsoft Learn Q&A.

    I recreated this on my Windows 11 setup (version 24H2), and it works as expected: SendMessageA returns 1 (non-zero) when the IME is open and active for composition, and 0 when it's closed. I used the same code snippet, with a Japanese IME installed and switched to hiragana mode while typing in Notepad to trigger the open state.

    That said, if it's consistently returning 0 for you even when it should be open, here are some speculations on what might be going wrong or what you could be missing:

    • IME Not Truly "Open" or Active: The status only flips to non-zero when the IME is in composition mode (e.g., candidate window visible during input like pinyin or kana conversion). If you're just switched to the IME language but typing in alphanumeric/half-width mode (no composition), it'll report as closed. Maybe test by explicitly starting input that triggers suggestions.
    • Modern vs. Legacy IME Mismatch: Windows 11's default "new" IME (post-22H2 updates) has known compatibility quirks with legacy APIs like WM_IME_CONTROL. It might not respond correctly to IMC_GETOPENSTATUS, even if the UI shows it's active, due to shifts toward Text Services Framework (TSF). If you're on the modern IME, that could explain the discrepancy—apps using old Imm32 calls sometimes get defaults or fails.
    • No Valid IME Association or Context: If the foreground window doesn't have an proper IME context (e.g., in a console app, custom control, or if IME isn't enabled for that thread/process), ImmGetDefaultIMEWnd might grab a handle, but the message fails silently. Win11's process isolation or security features could amplify this compared to Win10.
    • System Configuration Differences: Things like missing language packs, corrupted IME settings, or even regional builds (e.g., non-East Asian editions) might not fully support the default IME window. Also, if no complex-input language is installed/prioritized, it defaults to inactive.

    To troubleshoot, here's what I'd check/step through:

    1. Confirm IME Setup: Go to Settings > Time & language > Language & region. Ensure a language like Japanese, Chinese (Simplified), or Korean is added with its IME keyboard. Switch to it via Win + Space, and verify the taskbar icon changes.
    2. Toggle Legacy IME: Right-click the IME taskbar icon > Settings > General > Compatibility > Turn on "Use previous version of Microsoft IME". This reverts to Win10-like behavior and often fixes legacy API issues. Restart apps and retest.
    3. Check for Errors/Handles: Add logging to your code: Print if ImmGetDefaultIMEWnd returns NULL (invalid), and after SendMessageA, use GetLastError() to see any Win32 errors (e.g., via Marshal.GetLastWin32Error() in C#). Non-zero errors could point to access denials or missing DLLs.
    4. Update and Environment: Run Windows Update to grab any IME fixes (there were patches for 22H2/23H2 bugs). Test in a simple GUI app like Notepad vs. your target app, as consoles sometimes don't associate IME well.

    If none of that clicks or you share more details (like your exact Win11 build, IME language, or full output with handles), I can dig deeper. Hope this helps narrow it down.

    Was this answer helpful?


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.