AlexXYZ
@AlexXYZ
O Keep Clear O

C#, Как определить раскладку клавиатуры консольного приложения в другом потоке (по handle окна) в Windows 10?

Всем привет.

Требуется определить раскладку клавиатуры (rus/en) консольного приложения для Windows 10 (хотя бы тот же cmd.exe, который сама windows определяет легко):

bb38f7622f404a819ebe68769803ed4b.png

Для windows 7/8/8.1 определял с помощью кода:
[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);
}

На выходе hKL в windows 7/8 выдаёт правильный результат для консоли (например, 00000419 - русская раскладка), но в Windows 10 недокументированная функция GetConsoleKeyboardLayoutName возвращает false и язык не определяет, hKL-"00000000". Информации по GetConsoleKeyboardLayoutName очень мало и она очень скудная. Для консольного приложения GetKeyboardLayout() выдаёт ноль. Хотелось бы всё-таки получить язык раскладки, а не нули. ???
  • Вопрос задан
  • 1806 просмотров
Пригласить эксперта
Ответы на вопрос 2
15432
@15432
Системный программист ^_^
Зачем консоль аттачить? Есть же GetKeyboardLayout, которая получает раскладку по ID треда
https://msdn.microsoft.com/en-us/library/windows/d...

она вернет вам Handle на раскладку. Ставите её же на свой процесс (ActivateKeyboardLayout) и смотрите имя уже своей раскладки (GetKeyboardLayoutName)
Ответ написан
@ajka454
с Windows 7 под консоль запускается процесс CONHOST, в котором есть поток с окном класс="IME"
владелей этого окна=GetAncestor(hwnd, GA_ROOTOWNER) - окно консоли.
окно IME чутко реагирует на смену раскладки, котокую можно получить через GetKeyboardLayout
быстрый способ найти ЭТО окно через EnumWindows, перебор процессов -> потоков -> окон в разы дольше

HWND hWnd=hWndCon; //окно консоли
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") ) //сравнение в lowercase
if(*(HWND*)lParam==::GetAncestor(hwnd, GA_ROOTOWNER)) //владелец тукущая консоль
*(HWND*)lParam = hwnd;
return FALSE; //стоп перебор
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы