Изменение раскладки клавиатуры внутри клавиатуры 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 ответ

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

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

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

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

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

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

Другие вопросы по тегам