Изменение компоновки клавиатуры внутри клавишной панели CallBack

63
6

У меня проблема с изменением раскладки клавиатуры внутри клавиатуры. В этом простом коде при нажатии клавиши "A" требуется много времени, чтобы изменить язык, в более сложных случаях приложение делает неправильные вещи.

Приложение работает в лотке, поэтому я использовал крючки. Что не так с моим кодом? )) Или, может быть, есть другой способ изменить раскладку клавиатуры, которая хорошо работает с крючками? Спасибо за ваши ответы.

private static bool nextKey = false;

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
uint tpid = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
ushort currentLayout = GetKeyboardLayout(tpid);

if (nCode >= 0 && wParam == (IntPtr) WM_KEYDOWN) {
if (nextKey) {
Console.WriteLine("changing to english...");
PostMessage(GetForegroundWindow(), 0x0050, 0, (int) LoadKeyboardLayout("00000409", 0x00000001));
nextKey = false;
}

int vkCode = Marshal.ReadInt32(lParam);

if (vkCode == 0x41 && currentLayout == 0x409) { // if language is rus and 'A' pressed
Console.WriteLine("changing to russian...");
PostMessage(GetForegroundWindow(), 0x0050, 0, (int) LoadKeyboardLayout("00000419", 0x00000001));
nextKey = true;
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}

спросил(а) 2021-01-25T18:54:21+03:00 4 месяца, 4 недели назад
1
Решение
133

Прежде чем пытаться исправить этот код, я должен задать пару глупых вопросов:

Зачем вам нужно делать это внутри крючка? Зачем вам это нужно? Вы можете указать горячую клавишу для выбора языка ввода на панели управления клавиатуры ("Регион" и "Язык" → "Клавиатура и языки" → "Изменить клавиатуру" → "Дополнительные параметры ключа"). И всякий раз, когда вы включаете несколько языков ввода, значок уже помещается на панель задач. Вам не нужно писать собственное приложение, чтобы выполнить одно из этих действий.

Теперь, глядя конкретно на ваш код, то, что вы делаете, отправляет сообщение WM_INPUTLANGCHANGEREQUEST в окно переднего плана. Но это сообщение является уведомлением. Он информирует программу о том, что пользователь попросил изменить язык ввода. Он не предназначен для того, чтобы программы могли запрашивать другие программы для изменения языка ввода.

Если программа хочет изменить собственную раскладку клавиатуры, она вызывает функцию ActivateKeyboardLayout. Но не нужно p/вызывать эту функцию из приложения.NET. Структура уже обертывает все это в классе InputLanguage - настоятельно рекомендуется.

Кроме того, другие проблемы неизбежно существуют в коде, который вы не показываете, который принадлежит другим приложениям. В окне переднего плана, на которое вы отправляете сообщение WM_INPUTLANGCHANGEREQUEST есть возможность либо принять изменение, передав сообщение в DefWindowProc, либо отклонить изменение, вернув 0 в ответ. Если сломанное приложение просто возвращает 0 для всех тех сообщений, которые он явно не обрабатывает, это не будет сделано правильно. Или если приложение было написано для явного отклонения запросов WM_INPUTLANGCHANGEREQUEST, оно не будет делать то, что вы ожидаете. И так далее. Вы не контролируете эти вещи. Помните, что WM_INPUTLANGCHANGEREQUEST - это просто запрос.

Что касается скорости ("требуется много времени, чтобы изменить язык"), загрузка языка ввода в первый раз не гарантируется как бы молниеносная операция. Я вижу примерно половину задержки на моей машине, используя обычный механизм. Обычно это не большое узкое место; большинство людей не переключаются туда и обратно много раз. Если вам действительно нужно ускорить это, подумайте о кэшировании возвращаемого значения функции LoadKeyboardLayout.

ответил(а) 2021-01-25T18:54:21+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема