Изменение раскладки клавиатуры внутри клавиатуры KeyBack CallBack
У меня проблема с изменением раскладки клавиатуры внутри крючка клавиатуры. В этом простом коде при нажатии клавиши "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);
}
1 ответ
Прежде чем пытаться исправить этот код, я должен задать пару глупых вопросов:
- Зачем вам нужно сделать это внутри крючка?
- Зачем тебе это вообще нужно? Вы можете указать горячую клавишу для выбора языка ввода на панели управления клавиатуры ("Регион и язык" → "Клавиатура и языки" → "Изменить клавиатуру" → "Дополнительные настройки клавиш"). И всякий раз, когда вы включаете несколько языков ввода, значок уже размещен на панели задач. Вам не нужно писать свое собственное приложение, чтобы сделать что-то из этого.
Теперь, глядя конкретно на ваш код, вы публикуете WM_INPUTLANGCHANGEREQUEST
сообщение в окно переднего плана. Но это сообщение является уведомлением. Он сообщает программе, что пользователь запросил изменение языка ввода. Он не предназначен для того, чтобы программы могли запрашивать у других программ язык ввода.
Если программа хочет изменить свою раскладку клавиатуры, она вызывает ActivateKeyboardLayout
функция. Но нет необходимости п / вызывать эту функцию из приложения.NET. Фреймворк уже оборачивает все это в InputLanguage
класс - очень рекомендуется.
Кроме того, в коде, который вы не показываете, неизбежно существуют другие проблемы, код, принадлежащий другим приложениям. Окно переднего плана, в которое вы отправляете WM_INPUTLANGCHANGEREQUEST
сообщение имеет возможность принять изменение, передав сообщение на DefWindowProc
или отклонить изменение, вернув 0 в ответ. Если сломанное приложение просто возвращает 0 для всех тех сообщений, которые оно явно не обрабатывает, оно не будет работать правильно. Или, если заявка была написана, чтобы явно отклонить WM_INPUTLANGCHANGEREQUEST
запросы, он не будет делать то, что вы ожидаете. И так далее. Вы не можете контролировать эти вещи. Помните, WM_INPUTLANGCHANGEREQUEST
это просто запрос.
Что касается проблемы скорости ("для смены языка требуется много времени"), загрузка языка ввода в первый раз не гарантирует молниеносную операцию. Я вижу задержку примерно на полсекунды на моей машине с использованием обычного механизма. Обычно не большое узкое место; большинство людей не переключаются туда-сюда столько раз. Если вам действительно нужно ускорить это, рассмотрите возможность кэширования возвращаемого значения LoadKeyboardLayout
функция.