Z
Z
Zakharov Alexander2017-06-25 10:23:29
C++ / C#
Zakharov Alexander, 2017-06-25 10:23:29

C#, How to determine the keyboard layout of a console application on another thread (by window handle) in Windows 10?

Hello.
It is required to determine the keyboard layout (rus / en) of the console application for Windows 10 (at least the same cmd.exe, which windows itself determines easily): For windows 7/8/8.1, it was determined using the code:
bb38f7622f404a819ebe68769803ed4b.png

[DllImport("kernel32.dll")]
static extern bool FreeConsole();
[DllImport("kernel32.dll")]
static extern bool AttachConsole(int pid);
// http://forum.script-coding.com/viewtopic.php?id=5650
[DllImport("kernel32.dll")]
static extern bool GetConsoleKeyboardLayoutName(byte[] name);

uint pid = 0;
IntPtr tpid = GetWindowThreadProcessId(fore_ptr, out pid);
IntPtr hKL = IntPtr.Zero;
if (AttachConsole((int)pid) == true) {
    // За идею взят код https://github.com/Maximus5/ConEmu/blob/master/src/ConEmuCD/ConsoleMain.cpp
    byte[] byte_name = new byte[8];
    StringBuilder sb = new StringBuilder();
    // GetConsoleKeyboardLayoutName - недокументированная функция
    if (GetConsoleKeyboardLayoutName(byte_name) == true) {
        for (int i = 0; i <= byte_name.Length - 1; i++) {
            byte_name[i] -= 48;
            sb.Append(byte_name[i].ToString());
        }
        hKL = new IntPtr(Convert.ToInt32(sb.ToString(), 16));
        //string name = sb.ToString();
        //Console.WriteLine("name:" + name);
    }
    FreeConsole();
    // Последняя попытка:
    if(IntPtr.Zero.Equals(hKL) == true) {
        hKL = GetKeyboardLayout(tpid);
    }
}
else {
    hKL = GetKeyboardLayout(tpid);
}

On output, hKL in windows 7/8 produces the correct result for the console (for example, 00000419 - Russian layout), but in Windows 10, the undocumented function GetConsoleKeyboardLayoutName returns false and the language does not determine hKL-"00000000". There is very little information on GetConsoleKeyboardLayoutName and it is very scarce. For a console application, GetKeyboardLayout() returns zero. I would still like to get the layout language, and not zeros. ???

Answer the question

In order to leave comments, you need to log in

2 answer(s)
1
15432, 2017-06-25
@15432

Why attach a console? There is also GetKeyboardLayout, which gets the layout by the thread ID
https://msdn.microsoft.com/en-us/library/windows/d...
it will return you the Handle to the layout. Put it on your process (ActivateKeyboardLayout) and see the name of your layout already (GetKeyboardLayoutName)

A
ajka454, 2019-12-21
@ajka454

With Windows 7, a CONHOST process is launched under the console, in which there is a thread with a window class="IME"
owner of this window=GetAncestor(hwnd, GA_ROOTOWNER) - the console window.
the IME window reacts sensitively to layout changes, which can be obtained via GetKeyboardLayout
quick way to find THIS window via EnumWindows, enumeration of processes -> threads -> windows many times longer
HWND hWnd=hWndCon; //console window
EnumWindows(CallBackEnumWnd, (LPARAM)&hWnd);
if(hWnd!=hWndCon && ::IsWindow(hWnd))
DWORD tid = ::GetWindowThreadProcessId(hWnd, 0);
hkl = ::GetKeyboardLayout(tid); //1033(0x409)-en 1049(0x419)-ru
BOOL CALLBACK CallBackEnumWnd(HWND hwnd, LPARAM lParam)
char sClassName[256];
int ns = GetClassName(hwnd, sClassName, 256);
if(ns>2 && 0==_stricmp(sClassName, "IME") ) // compare to lowercase
if(*(HWND*)lParam==::GetAncestor(hwnd, GA_ROOTOWNER)) // current console owner
*(HWND *)lParam = hwnd;
return FALSE; // stop search

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question