1

I want to write some code in C++ in combination with windows API in order to change the input method on windows (Keyboard input language).

Here is my first try:

#include <iostream>
#include <windows.h>

int main() {
    int arr_size = GetKeyboardLayoutList(0, NULL);

    HKL hkl_array[arr_size];  // The array to hold input locale identifies found in the system(HKL)

    // Initialize the array to all zeros
    for (int i = 0; i <= arr_size - 1; i++) {
        hkl_array[i] = nullptr;
    }

    int lang_found = GetKeyboardLayoutList(arr_size, hkl_array);  // Get all the HKLs in the array

    for (int i = 0; i <= lang_found - 1; ++i) {
        // Print all the HKLs found
        std::cout << i + 1 << ". " << hkl_array[i] << std::endl;
    }

    std::cout << "Function return: " << ActivateKeyboardLayout(hkl_array[0], KLF_SETFORPROCESS);

    return 0;
}

When running the above code with English as the current language I get:

1. 0x4080408
2. 0x4090409

Function return: 0x4090409

(0x4080408 is Greek and 0x4090409 is English)

According to the documentation for ActivateKeyboardLayout, the return value is of type HKL and If the function succeeds, the return value is the previous input locale identifier. Otherwise, it is zero. In my case, the function clearly runs with no errors since it returns the input locale identifier for English witch was the language before the hypothetical change. The language although does not change. I get similar results if I start from greek and try to change to English.

I have tried different values in the flag parameter with no luck. It is always the same thing. I have also tried using the LoadKeyboardLayoutA as follows:

#include <iostream>
#include <windows.h>

int main(){
    LPCSTR language_select = "00000408";  // Code for greek
    std::cout << LoadKeyboardLayoutA(language_select, KLF_ACTIVATE);

    return 0;
}

When running the above code with English as the current language I get:

0x4080408

According to the documentation for LoadKeyboardLayoutA, If the function succeeds, the return type is HKL and the return value is the input locale identifier corresponding to the name specified in the function's parameter (language_select). So this seems to run ok as well but no luck with language change. I also tried with language_select = "00000809" (UK English) and the result I got was Uk English was just added to the list of languages as I did not have it installed.

Finally, I tried calling the ActivateKeyboardLayout with LoadKeyboardLayoutA ad the HKL parameter as follows

#include <iostream>
#include <windows.h>

int main() {
    LPCSTR language_select = "00000408";  // Code for greek
    std::cout << ActivateKeyboardLayout(LoadKeyboardLayoutA(language_select, KLF_ACTIVATE), KLF_SETFORPROCESS);

    return 0;
}

When running the above code with English as the current language I get:

0x4080408

Which again seems normal but there is no chance in the language. I am running this on Windows 10 20H2 OS Build 19042.685 and I am using CLion as an IDE (I don't think it matters but just in case anyone needs the info). What am I doing wrong?

2
  • Are you trying to change the keyboard layout for the current process or for the system? Commented Jan 9, 2021 at 0:19
  • @namesis I want it to have the same behavior as when I hit Windows key + Space or Shift + Alt. And just to be clear changing the keyboard layout just changes the language that the keyboard types correct? Commented Jan 9, 2021 at 0:23

1 Answer 1

3

The very first sentence of the ActivateKeyboardLayout function documentation states: "Sets the input locale identifier (formerly called the keyboard layout handle) for the calling thread or the current process.". Since you never read input in your program, you don't observe its effect. It does not change the keyboard layout of the system.

On Windows, each thread has its own keyboard layout. To change the keyboard layout for a specific window, you need to send the WM_INPUTLANGCHANGEREQUEST message to it:

SendMessageW(<windowHandle>, WM_INPUTLANGCHANGEREQUEST, 0, LoadKeyboardLayoutW(language_select, KLF_ACTIVATE));
Sign up to request clarification or add additional context in comments.

3 Comments

I managed to get it working for the system by doing this SendMessageW(HWND_BROADCAST, WM_INPUTLANGCHANGEREQUEST, 0, reinterpret_cast<LPARAM>(LoadKeyboardLayoutA(language, KLF_ACTIVATE))); Instead of a specific window handle I pass the HWND_BROADCAST so the input method changes for the system. Also, my compiler needed a cast to LPARAM to get it running.
You may get away without the cast if you change from SendMessageW to SendMessageA. WinAPI is split into functions that finish in A and accept normal strings (made out of 1-byte characters) or W and accept wide strings (made out of 2-byte characters).
@namesis I actually tried that but I got the same error. IntelliSense by Clion actually suggested the cast so I went with it. I don't think it is a problem though since it works without a problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.