Разделение ввода от нескольких клавиатур
Разделение ввода от нескольких клавиатур
В одной из прошлых статей мы научились получать список всех устройств, реальных и виртуальных, которые используются для ввода. А можно ли каким-то образом разделять данные, полученные от разных источников? Например, к компьютеру подключены несколько клавиатур и надо определить, на какой именно клавиатуре была нажата клавиша. Ответ - да, можно. Приложение может подписаться на нужные устройства ввода при помощи функции RegisterRawInputDevices. При получении "сырого" ввода от каждого из устройств выбранного типа, система будет посылать приложению сообщение WM_INPUT, а приложению останется его правильно обработать.
Теперь константы и структуры, про которые не знает FASM, но которые нам понадобятся для работы. Даже немного с избытком, но это на будущее, вдруг когда-нибудь пригодится.
Code (Assembler) : Убрать нумерацию
- struct RAWINPUTDEVICE
- usUsagePage dw ?
- usUsage dw ?
- dwFlags dd ?
- hwndTarget dd ?
- ends
- struct RAWMOUSE
- usFlags dw ?
- union
- ulButtons dd ?
- union
- usButtonFlags dw ?
- usButtonData dw ?
- ends
- ends
- ulRawButtons dd ?
- lLastX dd ?
- lLastY dd ?
- ulExtraInformation dd ?
- ends
- struct RAWKEYBOARD
- MakeCode dw ?
- Flags dw ?
- Reserved dw ?
- VKey dw ?
- Message dd ?
- ExtraInformation dd ?
- ends
- struct RAWHID
- dwSizeHid dd ?
- dwCount dd ?
- bRawData db ?
- ends
- struct RAWINPUTHEADER
- dwType dd ?
- dwSize dd ?
- hDevice dd ?
- wParam dd ?
- ends
- struct RAWINPUT
- header RAWINPUTHEADER
- union
- mouse RAWMOUSE
- keyboard RAWKEYBOARD
- hid RAWHID
- ends
- ends
- HID_USAGE_GENERIC_KEYBOARD = 6
- HID_USAGE_PAGE_GENERIC = 1
- RIDEV_REMOVE = 1
- RIM_TYPEMOUSE = 0
- RIM_TYPEKEYBOARD = 1
- RIM_TYPEHID = 2
- RI_KEY_MAKE = 0
- RI_KEY_BREAK = 1
- RI_KEY_E0 = 2
- RI_KEY_E1 = 4
- RID_INPUT = 0x10000003
- WM_INPUT = 0x00FF
Code (Assembler) : Убрать нумерацию
- ; Зарегистрировать обработку ввода
- mov [dev.usUsagePage],HID_USAGE_PAGE_GENERIC
- mov [dev.usUsage],HID_USAGE_GENERIC_KEYBOARD
- mov [dev.dwFlags],0
- mov eax,[hwnddlg]
- mov [dev.hwndTarget],eax
- invoke RegisterRawInputDevices,dev,1,sizeof.RAWINPUTDEVICE
Code (Assembler) : Убрать нумерацию
- ; Прекратить обработку ввода
- mov [dev.usUsagePage],HID_USAGE_PAGE_GENERIC
- mov [dev.usUsage],HID_USAGE_GENERIC_KEYBOARD
- mov [dev.dwFlags],RIDEV_REMOVE
- mov [dev.hwndTarget],0
- invoke RegisterRawInputDevices,dev,1,sizeof.RAWINPUTDEVICE
Code (Assembler) : Убрать нумерацию
- ; Получено сообщение WM_INPUT?
- cmp [msg],WM_INPUT
- je .wminput
- ...
- ...
- .wminput:
- ; Получить размер необходимых данных
- invoke GetRawInputData,[lparam],RID_INPUT,0,dSize,sizeof.RAWINPUTHEADER
- ; Получить данные
- invoke GetRawInputData,[lparam],RID_INPUT,input,dSize,\
- sizeof.RAWINPUTHEADER
- ; Ввод от клавиатуры?
- cmp [input.header.dwType],RIM_TYPEKEYBOARD
- jne .processed
Я протестировал обычные и мультимедийные клавиатуры с подключениями через USB и PS/2, беспроводную bluetooth-клавиатуру, клавиатуры ноутбуков. Способ везде уверенно работает, устройства определяются корректно, ввод можно разделять.
Что интересно, при тестировании водил кулаком по клавиатуре, в какой-то момент Punto Switcher углядел определенную комбинацию символов и переключил раскладку клавиатуры для последнего введенного "слова". В лог незамедлительно вывалилась целая пачка якобы нажатий и отпусканий кнопок. Получается, что так можно отслеживать программную эмуляцию клавиатурного ввода, в таких случаях значение поля hDevice всегда будет нулевым. Рискну предположить, что на чем-то подобном основана самозащита антивирусных программ от эмуляции действий пользователя.
В приложении пример программы с исходным текстом, которая обрабатывает ввод от нескольких клавиатур.
Просмотров: 1571 | Комментариев: 8
Метки: Assembler, клавиатура
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
FasmTheBest
(23.04.2024 в 23:49):
GetRawInputBuffer позволяет за один вызов получить массив со всеми последними данными, полезно для устройств с очень частой отправкой. Спасибо Вам что обратили внимание на этот важный инструментарий.
ManHunter
(20.05.2021 в 12:00):
Так если подключить клавиатуру или мышь к ноуту, то получится ровно такое же опасное деяние :)
Grey
(20.05.2021 в 08:36):
Так ты опасный человек, на одну машину можешь несколько человек усадить)). Так гляди и занесут в черный список мирового правительства.
qaz
(25.09.2020 в 18:52):
Fn кнопка существует только для контроллера клавы как переключатель
ManHunter
(23.09.2020 в 17:17):
Ну при таких раскладах - да, действительно проблема.
0101
(23.09.2020 в 11:56):
мне до "ближайшего" магазина 100км (правда, почта это дело сильно упрощает) и клаву хочу за 2,5тр с usb-портами и котортким ходом клавиш, которую не сразу и найдёшь.. Может, прежняя потому и сгорела, что постоянно в неё флешку засовывал - удобно!
ManHunter
(23.09.2020 в 08:58):
Так вроде ж не заря компьютерной эры, ипотеку на клавиатуру брать уже не надо :)
Все решение сводится к прогулке до ближайшего магазина электроники и нескольким сотням рублей.
Все решение сводится к прогулке до ближайшего магазина электроники и нескольким сотням рублей.
0101
(23.09.2020 в 08:35):
Хорошая статья, кому-то обязательно пригодится! У меня более насущные потребности: сгорела одна клава, поставил какая была под рукой, а она "ноутбучная". Вместо привычного левого "Win" кнопка "Fn". Как переназначить (Win7_x64) так и не придумал, ни программами, ни правкой реестра не получилось.. Придётся новую клаву покупать.. Или на "Alt+D" повесить "Win+D"..
Добавить комментарий
Заполните форму для добавления комментария