Могу ли я изменить ввод с клавиатуры пользователя? - PullRequest
8 голосов
/ 14 января 2010

Я нашел этот код перехвата клавиатуры, который я пытаюсь немного изменить для моих целей: http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx

В качестве обзора я хочу, чтобы пользователь нажал клавишу, скажем «E», и чтобы клавиатура возвращала другой символ «Z» для любого приложения, которое находится в фокусе.

Соответствующий метод, который я изменил, теперь выглядит так:

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
        {
            //The truely typed character:
            int vkCode = Marshal.ReadInt32(lParam);
            Console.WriteLine((Keys)vkCode);

            KBDLLHOOKSTRUCT replacementKey = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
            replacementKey.vkCode = 90; // char 'Z'
            Marshal.StructureToPtr(replacementKey, lParam, false);

            //Now changed to my set character
            vkCode = Marshal.ReadInt32(lParam);
            Console.WriteLine((Keys)vkCode);
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }

Консоль правильно выводит это как:

E
Z
T
Z
G
Z
etc.

ОДНАКО, приложение в фокусе все еще печатает 'E' вместо 'Z'. Зачем? Я изменил ввод с клавиатуры на «Z» вместо «E», и строки консоли показывают, что он был изменен правильно!

Насколько я понимаю, вызов return CallNextHookEx(_hookID, nCode, wParam, lParam); - это то, что посылает команду "напечатать это сейчас" в открытое приложение. Разве это не так? Есть ли что-то, что мешает мне печатать нужный символ? Я знаю, что такие приложения, как AutoHotkey, берут клавишу ввода, проверяют ее и возвращают другой символ. Как мне сделать то же самое здесь?

Спасибо!

Ответы [ 2 ]

5 голосов
/ 15 января 2010

Я делал это раньше, но немного по-другому.
Вместо того, чтобы пытаться изменить параметры, отправленные на CallNextHookEx, я «проглотил» нажатие клавиши (вы можете сделать это, возвращая ненулевое значение из процедуры подключения, чтобы предотвратить вызов последующих процедур).

Затем я использовал SendInput , чтобы отправить новый ключ, который я хотел «ввести».

Так что в основном это работает так:

  • Хук-процедура определяет, нажата ли целевая клавиша
  • Позвонить в SendInput с новым ключом
  • Возврат 1 из процедуры подключения, чтобы игнорировать оригинальный ключ

Остерегайтесь циклических перенаправлений, т. Е. 'A', перенаправленный на 'b', перенаправленный на 'a', может легко взорваться;)

0 голосов
/ 15 января 2010

Скорее всего, вы установили крючок «по всей длине», а не «по всей системе», что означает, что перевод ключа будет происходить только для нити, устанавливающей крючок.

Чтобы установить его «в масштабе всей системы», вам понадобятся две части: одна dll с «провайдером хуков» и исполняющий ее управляющий. Вот хороший учебник http://www.codeproject.com/KB/system/hooksys.aspx а вот пример: http://www.codeguru.com/cpp/com-tech/shell/article.php/c4509/

Но: 1. Установка широких системных крючков может серьезно испортить вашу систему (убедитесь, что вы пересылаете ключи, которые вы не переводите). 2. Пожалуйста ... не создавайте другой кейлоггер

...