Низкоуровневый ввод с клавиатуры из Windows - PullRequest
5 голосов
/ 22 ноября 2008

Какие вызовы win32 можно использовать для глобального обнаружения событий нажатия клавиш (не только для 1 окна, я хочу получать сообщение КАЖДЫЙ раз при нажатии клавиши) из службы Windows?

Ответы [ 5 ]

4 голосов
/ 22 ноября 2008

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

Подробнее об этом можно прочитать здесь

Тип хука, который вам нужен, - WH_KEYBOARD, и вы можете установить его через Win32 API SetWindowsHookEx.

По сути, Windows будет вызывать функцию в DLL, которую вы создаете при каждом нажатии клавиши в любой прикладной системе.

Хук вызовет вашу функцию, которая будет иметь этот интерфейс:

LRESULT CALLBACK KeyboardProc(      
    int code,
    WPARAM wParam,
    LPARAM lParam
);

Больше информации об этом обратном вызове здесь .

С помощью хуков Windows вы можете не только отслеживать общесистемные события во всех процессах, но и фильтровать их и полностью их останавливать.

2 голосов
/ 22 ноября 2008

Посмотрите на хуки, которые вы можете установить с помощью SetWindowHookEx:

http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx

Однако, если вы не используете «интерактивный» сервис, у вас не будет доступа к рабочему столу (и вам не следует запускать интерактивный сервис, потому что он не будет работать правильно в более новых версиях Windows). Чтобы получить доступ к рабочему столу / консоли, вам нужно изучить API управления сеансом и рабочим столом.

1 голос
/ 07 августа 2014

Просто используйте встроенную функцию GetKeyState или GetAsyncKeyState или GetKeyboardState из библиотеки user32.

Вы можете прочитать о каждой функции, о которой я упоминал выше, на сайте msdn:

h ttp: //msdn.microsoft.com/en-us/library/windows/desktop/ms646301 (v = vs.85) .aspx

для GetKeyState и

h ttp: //msdn.microsoft.com/en-us/library/windows/desktop/ms646293 (v = vs.85) .aspx

для GetAsyncKeyState и

h ttp: //msdn.microsoft.com/en-us/library/windows/desktop/ms646299 (v = vs.85) .aspx

для GetKeyboardState .

Если вы программируете на C #, тогда:

Ваш код должен включать следующую строку из любого объявления класса, структуры или перечисления:

using System.Runtime.InteropServices;

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

[DllImport("user32.dll")]
static uint GetKeyState(byte virtualKeyCode);

//or

[DllImport("user32.dll")]
static uint GetAsyncKeyState(byte virtualKeyCode);

//or

[DllImport("user32.dll")]
static uint GetKeyboardState(byte[] virtualKeyCodes);
//NOTE: The length of the byte array parameter must be always 256 bytes!

Если вам не нравится uint в качестве типа возврата, вы также можете изменить его на int .

Если нативные функции всегда возвращают 1 как true или 0 как false, тогда вы можете изменить вместо них тип возврата на bool , но если вы сделаете это, то я думаю, что вам следует добавить еще одну строку кода выше определения нативной функции:

[MarshalAs(UnmanagedType.Bool)]

ИЛИ вы можете добавить следующую строку в середине определения собственной функции (ниже строки, где находится слово DllImport, и выше строки, где находится слово 'extern'):

[return: MarshalAs(UnmanagedType.Bool)]

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

Следующая ссылка ведет к определению GetKeyState в C #:

h ttp: //www.pinvoke.net/default.aspx/user32.getkeystate

Следующая ссылка ведет к определению GetAsyncKeyState в C #

h ttp: //www.pinvoke.net/default.aspx/user32.getasynckeystate

Следующая ссылка ведет к определению GetKeyboardState в C #

h ttp: //www.pinvoke.net/default.aspx/user32.getkeyboardstate

Чтобы определить, какая клавиша удерживается (в любое время и в любом месте), затем вызовите функцию GetKeyState или GetAsyncKeyState, в одном параметре укажите ключ, который вы хотите обнаружить, а затем добавьте: & 0x8000 или & 0x80 после звонка. Если упомянутый ключ удерживается нажатым, то возвращаемое значение выражения не равно нулю, но в противном случае оно равно нулю. В соответствии с возвращенным целым числом выражения вы можете определить, какая клавиша удерживается или нет. Обратите внимание, что если вы поместите код внутри оператора if с этим выражением! = 0 в качестве условия ввода, который находится внутри цикла, код в этом операторе if будет выполняться более одного раза, фактически много раз , когда вы удерживал нажатой эту клавишу. Если вы хотите, чтобы какой-то код выполнялся один раз Когда вы нажимаете клавишу, а затем отпускаете ее, следующий код - это трюк , который достигает этой цели:

while (boolean exression that will return false when you want to quit this loop)
{
    if (boolean expression that will return true when particular key is **held down**) //This boolean expression calls either GetKeyState or GetAsyncKeyState with the & 0x8000 or & 0x80 after the call, and then != 0 to check for **held down** key
       while (true) //It's purpose is to wait for the same key that was held down to be released. After code execution, it will encounter the break keyword that will finish him, even though that his enter condition is true.
           if (boolean expression that will return true when the **same** particular key is **NOT** held down! (NOT held down, means that at that time, that key was released). You can copy the same condition from the first if statement, and just change **!=**, which is next to 0, to **==**, or instead add brackets to the condition '(' and ')', and in left of '(' add '!').
           {
               //Put here the code that you want to execute once, when paticular key was pressed and then released.
               break; //the while (true), which is the only way to get out of it
           }
}
0 голосов
/ 22 января 2013

Если вы реализуете это в приложении .net, я бы порекомендовал GlobalKeyboardHook , в противном случае я бы посмотрел на его источник и взял то, что вам нужно, так как он реализует функции DLLImport, упомянутые выше.

0 голосов
/ 22 ноября 2008

Проверьте API необработанного ввода в MSDN:

http://msdn.microsoft.com/en-us/library/ms645536(VS.85).aspx

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

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

...