Крючок клавиатуры меняет поведение клавиш - PullRequest
4 голосов
/ 23 августа 2010

Я создаю программу, которая устанавливает хук клавиатуры для захвата всех клавиш и отображения текста, связанного с ними.

Однако я наткнулся на препятствие, и некоторые клавиши меняют поведение, когдахук установлен.

Я расскажу о публикации небольшой, но полной тестовой программы, но сейчас я просто опишу проблему.

Проблема проявляется в Windows 764-битная, в .NET 4.0, программа на C #.Я предполагаю, что ничего из этого не имеет значения.

Мой хук устанавливает себя через SetWindowsHookEx, а затем обрабатывает все ключи, обработанные в системе.

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

Однако, если я вызову эту функцию, ToAscii из User32.dll, чтобы выяснить, какая клавишана моей клавиатуре OemTilde или подобный действительно есть, тогда любая клавиша, которая «перекрывает следующую клавишу», перестает функционировать.Я не знаю правильного имени для таких ключей, но два типа апострофа, `` и ´ , as well as ~ and ¨`, перестают функционировать.

Например, если я нажму ~ и затем N, он отображается следующим образом:

  • Без установленного крючка клавиатуры: -
  • С установленным крюком клавиатуры: n (примечание № ~ выше)

Кто-нибудь знает, почему это происходит и как я могу решить эту проблему?

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

Дополнительная информация:

Если я вызываю функцию ToAscii как часть метода ловушки, возникает другая проблема.Ключи типа ¨ обрабатываются дважды, т.е.если я нажму ¨ один раз, Блокнот получит два ¨¨ символа, а нажатие N теперь просто добавляет N.

Однако, если я использую BeginInvoke для обработки ключа наВ отдельном потоке после возврата из метода перехвата клавиатуры возникает первая проблема.


Моя программа, вероятно, немного особенная в этом:

  • Я не использую клавиатурусостояние (т. е. 256-байтовый массив «Состояние ключа», который я передаю, просто полон 0)
  • Мне не нужны мертвые ключи (в том смысле, что моя программа не будет их обрабатывать, ядостаточно заботиться о них, чтобы я не хотел, чтобы моя программа делала их бесполезными для остальной системы)

Таким образом, мой код в итоге выглядел следующим образом:

private bool IsDeadKey(uint key)
{
    return ((Hook.Interop.MapVirtualKey(key, 2) & 2147483648) == 2147483648);
}

void _Hook_KeyDown_Async(KeyDownEventArgs e)
{
    var inBuffer = new byte[2];
    char key = '\0';
    if (!IsDeadKey((uint)e.KeyCode))
    {
        int ascii = Hook.Interop.ToAscii((int) e.KeyCode,
                                            e.ScanCode,
                                            _KeyState,
                                            inBuffer,
                                            e.Flags);
        if (ascii == 1)
        {
            key = Char.ToUpper((char) inBuffer[0]);
        }
    }

    BeginInvoke(
        new Action<Keys, Boolean, Boolean, Boolean, Char>(ProcessKeyboardEvent),
        e.KeyCode, e.Control, e.Shift, e.Alt, key);
}

Ответы [ 4 ]

2 голосов
/ 23 августа 2010

В вашем вопросе отсутствует критическая информация, какие из двух клавиатурных хуков вы используете?Самый простой, WH_KEYBOARD_LL не может работать.В конечном итоге вы будете использовать состояние клавиатуры вашей программы, а не программу, которая фактически получает нажатие клавиши.Мертвые ключи действительно имеют значение.

Сложный, WH_KEYBOARD требует хука, который вы не можете написать в управляемом коде.Вам понадобится неуправляемая DLL, которая может быть вставлена ​​в каждый процесс.Как только вы это получите, я бы не стал беспокоиться о подключении клавиатуры, а также мог бы регистрировать сообщения WM_CHAR с WH_CALLWNDPROC.

Пример библиотеки DLL доступен здесь .

2 голосов
/ 23 августа 2010

Эти ключи называются мертвые клавиши , и вы можете решить проблему, убрав вызов ToAscii. Смотрите также следующую связанную тему:

ToAscii / ToUnicode в хуке клавиатуры уничтожает мертвые клавиши.

Обновление: я не видел ваш код, но при обработке параметров функции обратного вызова KeyboardProc вы можете проверить, что вы передаете сообщение клавиатуры, когда параметр code меньше чем 0? В документации сказано:

код [in] int

Код, используемый процедурой подключения, чтобы определить, как обрабатывать сообщение. Если код меньше нуля, подключаемая процедура должна передать сообщение функции CallNextHookEx без дальнейшей обработки и вернуть значение, возвращаемое CallNextHookEx.

Существует пример для настройки управляемого перехвата в MSDN:

if (nCode < 0)
{
    return CallNextHookEx(hHook, nCode, wParam, lParam);
}
else
{
    // process message here

    return CallNextHookEx(hHook, nCode, wParam, lParam); 
}
1 голос
/ 23 августа 2010

То, что вы, вероятно, видите здесь, это эффект попытки сопоставить ключ, когда задействован мертвый ключ. Отображение клавиатуры - довольно сложный процесс, в котором есть много подводных камней вокруг определенных типов клавиш, которые вызывают такое поведение.

Я рекомендую вам прочитать следующую серию блогов Майкла Каплана на эту тему. Это помогло мне разобраться с рядом ошибок.

0 голосов
/ 23 августа 2010

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

Пример кодовых страниц страны

  • США, Великобритания 437
  • Многоязычный 850
  • Славянский 852
  • Португальский 860
  • Исландский 861
  • канадский, французский 863
  • Скандинавский / скандинавский 865

Подробнее

MSDN Info

Интернационализация для приложений Windows

...