Как получить список устройств ввода
Как получить список устройств ввода
Как узнать, подключена ли к компьютеру клавиатура и/или мышь? Ответить на этот вопрос можно путем перечисления всех подключенных системных устройств ввода при помощи функции GetRawInputDeviceList. Она позволяет получить список идентификаторов и типов устройств ввода, а на основании идентификатора при помощи функции GetRawInputDeviceInfo можно узнать об этом устройстве более детальную информацию.
Начинаем, как водится, с описания необходимых для работы структур и констант. Структура RID_DEVICE_INFO используется для всех типов устройств, просто для каждого типа в ней будет заполнен свой набор полей.
Code (Assembler) : Убрать нумерацию
- struct RAWINPUTDEVICELIST
- hDevice dd ?
- dwType dd ?
- ends
- struct RID_DEVICE_INFO_MOUSE
- dwId dd ?
- dwNumberOfButtons dd ?
- dwSampleRate dd ?
- fHasHorizontalWheel dd ?
- ends
- struct RID_DEVICE_INFO_KEYBOARD
- dwType dd ?
- dwSubType dd ?
- dwKeyboardMode dd ?
- dwNumberOfFunctionKeys dd ?
- dwNumberOfIndicators dd ?
- dwNumberOfKeysTotal dd ?
- ends
- struct RID_DEVICE_INFO_HID
- dwVendorId dd ?
- dwProductId dd ?
- dwVersionNumber dd ?
- usUsagePage dw ?
- usUsage dw ?
- ends
- struct RID_DEVICE_INFO
- cbSize dd ?
- dwType dd ?
- union
- mouse RID_DEVICE_INFO_MOUSE
- keyboard RID_DEVICE_INFO_KEYBOARD
- hid RID_DEVICE_INFO_HID
- ends
- ends
- RIM_TYPEMOUSE = 0
- RIM_TYPEKEYBOARD = 1
- RIM_TYPEHID = 2
- RIDI_DEVICENAME = 0x20000007
- RIDI_DEVICEINFO = 0x2000000b
Code (Assembler) : Убрать нумерацию
- ; Получить количество устройств ввода
- invoke GetRawInputDeviceList,NULL,numDev,sizeof.RAWINPUTDEVICELIST
- or eax,eax
- jnz .no_devices
- ; Получить список устройств ввода
- invoke GetRawInputDeviceList,ridl,numDev,sizeof.RAWINPUTDEVICELIST
- mov esi,ridl
- mov ebx,[numDev]
- .loc_loop:
- ; RAWINPUTDEVICELIST.hDevice
- lodsd
- push eax
- ; Имя устройства
- mov [pcbSize],200h
- invoke GetRawInputDeviceInfo,eax,RIDI_DEVICENAME,devname,pcbSize
- pop eax
- ; Информация об устройстве
- mov [pcbSize],sizeof.RID_DEVICE_INFO
- invoke GetRawInputDeviceInfo,eax,RIDI_DEVICEINFO,riddi,pcbSize
- ; Mouse
- cmp [riddi.dwType],RIM_TYPEMOUSE
- jne @f
- ...
- ...
- jmp .loc_next
- @@:
- ; Keyboard
- cmp [riddi.dwType],RIM_TYPEKEYBOARD
- jne @f
- ...
- ...
- jmp .loc_next
- @@:
- ; HID
- ...
- ...
- .loc_next:
- ; RAWINPUTDEVICELIST.dwType
- lodsd
- ; Следующее устройство
- dec ebx
- jnz .loc_loop
Отлично, список устройств мы получили, но в нем нет человекопонятных названий устройств, только системные имена типа \\?\HID#VID_0D9F&PID_00A6#6&166ed471&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}. Как все-таки получить название устройства, понятное для человека? Сделать это можно, но нам понадобятся дополнительные структуры и константы.
Code (Assembler) : Убрать нумерацию
- struct SP_DEVINFO_DATA
- cbSize dd ?
- ClassGuid rb 16
- DevInst dd ?
- Reserved dd ?
- ends
- DIGCF_PRESENT = 0x00000002
- DIGCF_ALLCLASSES = 0x00000004
- SPDRP_DEVICEDESC = 0x00000000
- SPDRP_FRIENDLYNAME = 0x0000000C
- \\?\ или \??\ (для WinXP) - префикс имени
- HID - класс устройства
- VID_0D9F&PID_00A6 - VID/PID, то есть VendorID и ProductID - это идентификаторы производителя и устройства, для разных классов они могут формироваться и выглядеть по-разному
- 6&166ed471&0&0000 - уникальный идентификатор устройства в системе
- {4d1e55b2-f16f-11cf-88cb-001111000030} - GUID интерфейса устройства
Данные устройства в реестре
Для получения названия устройства можно извлечь данные из реестра, сформировав путь из частей его системного имени, но лучше воспользоваться функциями WinAPI для работы с устройствами.
Code (Assembler) : Убрать нумерацию
- ; Преобразовать строку имени устройства из системного вида
- ; в Instance ID типа HID\VID_0D9F&PID_00A6\6&166ed471&0&0000
- mov esi,devname
- mov edi,instanceID
- @@:
- lodsb
- cmp al,'\'
- je @b
- cmp al,'?'
- je @b
- dec esi
- ; Тут дополнительно формируется юникодная строка класса устройства
- xor ecx,ecx
- xor eax,eax
- @@:
- lodsb
- cmp al,'#'
- je @f
- stosb
- mov word [szClass+ecx],ax
- inc ecx
- inc ecx
- jmp @b
- @@:
- mov word [szClass+ecx],0
- mov al,'\'
- stosb
- @@:
- lodsb
- cmp al,'#'
- je @f
- stosb
- jmp @b
- @@:
- mov al,'\'
- stosb
- @@:
- lodsb
- cmp al,'#'
- je @f
- stosb
- jmp @b
- @@:
- mov al,0
- stosb
- ; Получить хэндл списка устройств этого класса
- invoke SetupDiGetClassDevs,NULL,szClass,\
- NULL,DIGCF_ALLCLASSES+DIGCF_PRESENT
- mov [hDevInfo],eax
- xor ebx,ebx
- .loc_enum_devs:
- ; Получить информацию о следующем устройстве этого класса
- mov [pspDevInfoData.cbSize],sizeof.SP_DEVINFO_DATA
- invoke SetupDiEnumDeviceInfo,[hDevInfo],ebx,pspDevInfoData
- or eax,eax
- jz .no_more_devs
- invoke SetupDiGetDeviceInstanceId,[hDevInfo], pspDevInfoData,\
- DeviceInstanceId, 100h, tmp
- ; InstanceId устройства соответствует нашему устройству?
- invoke lstrcmpi,instanceID,DeviceInstanceId
- or eax,eax
- jnz .loc_next_device
- ; Получить человекопонятное название устройства
- invoke SetupDiGetDeviceRegistryProperty,[hDevInfo],\
- pspDevInfoData,SPDRP_FRIENDLYNAME,NULL,\
- PropertyBuffer,100h,tmp
- or eax,eax
- jnz .no_more_devs
- ; Получить описание устройства
- invoke SetupDiGetDeviceRegistryProperty,[hDevInfo],\
- pspDevInfoData,SPDRP_DEVICEDESC,NULL,\
- PropertyBuffer,100h,tmp
- or eax,eax
- jnz @f
- ; Никакого названия не найдено, записать в строку "Unknown"
- invoke lstrcpy,PropertyBuffer,szUnknown
- @@:
- jmp .no_more_devs
- .loc_next_device:
- ; Следующее устройство
- inc ebx
- jmp .loc_enum_devs
- .no_more_devs:
- ; Прибраться за собой
- invoke SetupDiDestroyDeviceInfoList,[hDevInfo]
Code (Assembler) : Убрать нумерацию
- mov esi,devname
- mov edi,instanceID
- @@:
- lodsw
- cmp ax,'\'
- je @b
- cmp ax,'?'
- je @b
- dec esi
- dec esi
- @@:
- lodsw
- cmp ax,'#'
- je @f
- stosw
- jmp @b
- @@:
- mov word [edi],0
- ; Тут дополнительно формируется юникодная строка класса устройства
- invoke lstrcpy,szClass,instanceID
- mov ax,'\'
- stosw
- @@:
- lodsw
- cmp ax,'#'
- je @f
- stosw
- jmp @b
- @@:
- mov ax,'\'
- stosw
- @@:
- lodsw
- cmp ax,'#'
- je @f
- stosw
- jmp @b
- @@:
- mov ax,0
- stosw
В приложении пример программы с исходным текстом, которая выводит список всех подключенных к компьютеру устройств ввода, их названия или описания, а также некоторые физические характеристики.
Просмотров: 2234 | Комментариев: 10
Метки: Assembler, клавиатура
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(06.12.2021 в 21:04):
Как должно быть охуенно жить на свете вообще без мозга, да? Включил защитник windows или чо там у тебя работает вместо головы, и жизнь прекрасна. Выйди в окно, не засоряй собой планету.
dev
(06.12.2021 в 20:32):
в архиве вирус Trojan:Win32/Ulthar.A!ml
ManHunter
(26.09.2020 в 14:35):
Дополнил статью информацией, как получить человекопонятное название устройства. С удивлением выяснил, что мой бесперебойник тоже является устройством ввода :) Архив обновлен.
ManHunter
(22.09.2020 в 12:56):
Также выяснилось, что буфер ridl должен быть выровнен на границу DWORD, в MSDN про это ни слова. Дополнил статью и исходник.
ManHunter
(09.09.2020 в 08:21):
Что интересно, WinXP имя устройства выдает как
Mouse: \??\Root#RDP_MOU#0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}
а на Win7 как
Mouse: \\?\Root#RDP_MOU#0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}
то есть на WinXP строка начинается с "\??\", а на Win7 с "\\?\"
Это так, на случай необходимости детекта физических устройств ввода.
Mouse: \??\Root#RDP_MOU#0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}
а на Win7 как
Mouse: \\?\Root#RDP_MOU#0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}
то есть на WinXP строка начинается с "\??\", а на Win7 с "\\?\"
Это так, на случай необходимости детекта физических устройств ввода.
ManHunter
(08.09.2020 в 14:36):
Добавил в выхлоп примера RAWINPUTDEVICELIST.hDevice
ManHunter
(03.07.2020 в 21:52):
Два последних девайса, которые рутовые \\?\Root#RDP_xxx. Соответственно, физическая клавиатура и физическая мышь. У меня примерно похожая картина, только виртуальных поменьше, а железные определяются точно так же от рута.
DRON
(03.07.2020 в 21:32):
Вот реальный пример: https://pastebin.com/rjjibR5A
И как тут определить что есть что?
И как тут определить что есть что?
ManHunter
(03.07.2020 в 10:43):
Можно же отсечь ненужное по SampleRate для мыши и всяким NumberOfFunctionKeys для клавы.
DRON
(03.07.2020 в 09:04):
Всё это, к сожалению, не очень надёжно: игровые мышки видятся как клавы, а игровые клавы как мышки. А у меня даже при физически отключенных мышках/клавах находится пара виртуальных.
Добавить комментарий
Заполните форму для добавления комментария