Share via

How to get current IME Chinese/English mode from Windows 11 language bar using C++ ?

yezi lan 65 Reputation points
2026-04-20T17:07:28.21+00:00

I am developing a C++ console application on Windows 11 and I need to detect the current input mode (Chinese / English) shown in the taskbar language bar.

My goal is to track in real time whether the IME is in Chinese input mode or English input mode

What is the recommended way to monitor this state in real time from a native C++ application?

Any guidance or official documentation reference would be greatly appreciated.

Windows development | Windows API - Win32
0 comments No comments

Answer accepted by question author

Taki Ly (WICLOUD CORPORATION) 1,500 Reputation points Microsoft External Staff Moderator
2026-04-21T09:32:33.7366667+00:00

Hello @yezi lan ,

Based on my testing with Microsoft Pinyin, I think the official TSF compartment you are actually looking for is GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION. As you have noticed, when the user presses the Shift key to toggle between Chinese and English, the OPENCLOSE compartment does not change at all. Instead, it seems to toggle the TF_CONVERSIONMODE_NATIVE flag inside the INPUTMODE_CONVERSION compartment. You can find the official definition of these flags in the Predefined Compartments documentation. I think that this is the underlying state that the Language Bar relies on to display "中" or "英".

Regarding the question of why modern IMEs do not seem to expose this state globally through TSF, it seems the issue is not that the IME hides the state, but rather how the TSF architecture handles scope. According to the official Compartments overview documentation, these states are strictly managed on a per-thread basis. So, if you register an ITfCompartmentEventSink in a background C++ Console application, I think it will only receive events for its own isolated console thread. When the user switches to another application (like Chrome or Word) and presses the Shift key, TSF will update the target application's thread compartment, but it does not broadcast this change globally across process boundaries to reach your console application. Because TSF operates this way, building a global monitor purely from an isolated Console process is extremely difficult without injecting DLLs (TSF Text Services) into every running process.

To monitor this state globally without injecting DLLs, there are two alternative methods you can explore. First, you might wonder whether you can use legacy IMM32 APIs as a cross-process workaround. Based on my testing, it seems this legacy method actually still works for classic Win32 applications. You can periodically poll the foreground window, find its default IME window, and send a WM_IME_CONTROL message. Below is a code snippet illustrating the idea:

#include <windows.h>
#pragma comment(lib, "imm32.lib")
// Query the IME state of the active window
void CheckForegroundImeState() {
    HWND hForegroundWnd = GetForegroundWindow();
    if (!hForegroundWnd) return;
    HWND hImeWnd = ImmGetDefaultIMEWnd(hForegroundWnd);
    if (!hImeWnd) return;
    // Send a cross-process message to query the conversion mode
    LRESULT conversionMode = SendMessage(hImeWnd, WM_IME_CONTROL, IMC_GETCONVERSIONMODE, 0);
    if (conversionMode & IME_CMODE_NATIVE) {
        // IME is in Native/Chinese Mode
    } else {
        // IME is in Alphanumeric/English Mode
    }
}

However, when I tested this IMM32 method with modern Windows 11 applications such as the new Notepad app, the messages seemed to be completely ignored. I suspect the reason is that modern Windows applications might have completely bypassed the legacy IMM32 compatibility layer.

Considering the limitations of IMM32 with modern applications, the idea of using UI Automation is likely a robust method on Windows 11. Because the taskbar visibly updates the state of the Language Bar button for the user to see, you can use the Microsoft UI Automation (UIA) API to act as a "screen reader" for the taskbar. By monitoring the accessible name of the Language Bar button. Below is a code snippet illustrating how you can locate and read this state:

#include <windows.h>
#include <uiautomation.h>
#include <iostream>
#include <string>
// Assuming COM is initialized and pAutomation is your IUIAutomation instance
void CheckTaskbarImeIndicator(IUIAutomation* pAutomation) {
    IUIAutomationElement* pRoot = nullptr;
    pAutomation->GetRootElement(&pRoot);
    // 1. Find the Taskbar based on the class name
    IUIAutomationCondition* pTaskbarCond = nullptr;
    // ... (Create condition for UIA_ClassNamePropertyId == "Shell_TrayWnd")
    IUIAutomationElement* pTaskbar = nullptr;
    pRoot->FindFirst(TreeScope_Children, pTaskbarCond, &pTaskbar);
    // 2. Find the System Tray Icon for the Input Indicator
    // On Win11, the AutomationId is usually "SystemTrayIcon" and its name contains "Input Indicator"
    // ... (Use FindAll with TreeScope_Descendants to locate the exact element)
    // 3. Read the CurrentName property
    BSTR bstrName = nullptr;
    if (SUCCEEDED(pIndicatorElement->get_CurrentName(&bstrName)) && bstrName) {
        std::wstring indicatorName(bstrName);
        // The accessible name will dynamically change when the user presses Shift
        if (indicatorName.find(L"Chinese Mode") != std::wstring::npos) {
             std::wcout << L"Global state: Chinese Mode" << std::endl;
        } else if (indicatorName.find(L"English Mode") != std::wstring::npos) {
             std::wcout << L"Global state: English Mode" << std::endl;
        }
        SysFreeString(bstrName);
    }
}

I hope these observations from testing, sample code snippets, and documentation links will provide a clear direction for your project. If you found my response helpful, I would greatly appreciate it if you could provide feedback by following this guide.

Thank you.

Was this answer helpful?


2 additional answers

Sort by: Most helpful
  1. Castorix31 91,871 Reputation points
    2026-04-21T07:36:50.5833333+00:00

    ITfLanguageProfileNotifySink

    or

    ITfInputProcessorProfileActivationSink

    work on Windows 10 22H2, and should work on Windows 11 too...

    Was this answer helpful?

    0 comments No comments

  2. AI answer

    2026-04-20T17:07:39.9033333+00:00

    The provided documentation and Q&A context do not describe any TSF compartment, Win32, or other public API that exposes the “Chinese/English mode” (e.g., 中 / 英) of modern IMEs such as Microsoft Pinyin on Windows 11.

    From the context:

    • Custom IMEs are required to use TSF; IMM32-based IMEs are blocked in modern Windows apps. TSF acts as the intermediary between apps and IMEs and enforces app-container restrictions, but the documentation only mentions:
      • Loading IME DLLs via TSF
      • Using ITfThreadMgrEx::GetActiveFlags to distinguish immersive (Windows app) vs desktop mode
      • General IME compatibility and security constraints
    • There is no mention of a TSF compartment or API that represents the IME’s internal “Chinese vs English” mode.
    • For games and full-screen apps, the IME-related guidance is limited to handling messages like WM_INPUTLANGCHANGE and using GetKeyboardLayout to know which input locale/IME is active. This only identifies the active input locale/IME, not the internal mode of that IME.

    Based on this context, only the following are documented and supported:

    • Detecting the active input locale / IME (e.g., which keyboard layout or IME is selected) using GetKeyboardLayout and WM_INPUTLANGCHANGE.
    • Distinguishing immersive vs desktop context for an IME using ITfThreadMgrEx::GetActiveFlags.

    There is no documented, supported way in this context to:

    • Read the Microsoft Pinyin (or other modern IME) “Chinese/English” toggle state via TSF compartments.
    • Access that state via ITfInputProcessorProfiles, ITfLangBarItem, ITfLangBarMgr, or any other TSF interface.
    • Monitor that state globally from a console/native application.

    Therefore, within the scope of the provided documentation, the “Chinese/English input mode” shown in the Windows 11 language bar is not exposed as a public TSF or Win32 API surface, and no supported alternative mechanism (including UI Automation) is documented here for that purpose.


    References:

    AI-generated content may be incorrect. Read our transparency notes for more information.

    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.