Resposta parcial : Entendendo a infraestrutura da HID e os dados brutos da HID
(Disclaimer: Eu só fiz tudo isso para USB, mas suponho que será aplicado da mesma forma ou de forma semelhante ao Bluetooth).
Os dispositivos HID podem enviar e receber relatórios em um formato bem definido. O formato para um dispositivo em particular é dado pelo descritor HID , que para USB é muito semelhante aos outros descritores USB (por exemplo, lsusb
pode listá-los se eles não estiverem vinculados). Detalhes (para USB) podem ser encontrados na Definição de classe de dispositivos para dispositivos de interface humana (HID) Documento PDF .
A documentação do kernel para HID pode ser encontrada em Documentation/hid
. Como explica hiddev.txt
, o fluxo de dados para um evento é assim:
usb.c --> hid-core.c --> hid-input.c --> input-subsystem
Em drivers/hid/hid-input.c
, em particular na rotina hidinput_configure_usage
, um relatório é analisado de acordo com o descritor HID.
Então, se você não consegue ver a chave Fn , é aí que as coisas dão errado.
A saída vista em hidraw0
parece suspeitamente como se houvesse vários tipos de relatórios com IDs diferentes (esse relatório tem o ID 1, os relatórios normais do teclado têm o ID 0).
Mas para ter certeza, precisamos do (s) descritor (es) HID. Os descritores HID estão disponíveis por meio de um ioctl no dispositivo hidraw
. Você pode usar, por exemplo, https://github.com/DIGImend/usbhid-dump
para obter o descritor (somente USB) e https://github.com/DIGImend/hidrd
para analisá-lo. Há também o arquivo /samples/hidraw/hid-example.c
na fonte do kernel que mostra como obter o descritor HID via ioctl; Ele pode ser facilmente modificado para produzir um dump hexadecimal similar a usbhid-dump
. Você terá que usar isso para Bluetooth, então eu coloquei em um pastebin . Compile com make
.
(Se você não está acostumado a compilar projetos externos: Faça o download do arquivo zip para ambos, descompacte cada um em um diretório vazio, ./bootstrap
, ./configure
, make
. Agora você pode usar os binários diretamente, adicioná-los $PATH
, etc.)
Agora você pode analisar o descritor usando
sudo ./hid-desc /dev/hidraw0 | tail -n+3 | head -1 | hidrd-convert -ihex -ospec
Além de fornecer esta saída (ou o hexdump, se alguma coisa não funcionar), por favor, teste o que acontece em hidraw
se você pressionar o Fn em combinação com várias outras chaves (alfabético , Setas; flechas). Também teste o que acontece para pressionamentos de tecla normais.
Não tenho certeza sobre a melhor maneira de proceder se não for possível fazer o kernel reconhecer os relatórios especiais. Talvez a maneira mais simples seja escrever um programa em C que analise eventos de hidraw
e produza eventos de entrada adicionais, da mesma forma que input-create .
Atualizar : o descritor HID contém um 00
extra no final. Se você remover isso, ele será analisado em
Usage Page (Desktop), ; Generic desktop controls (01h)
Usage (Keyboard), ; Keyboard (06h, application collection)
Collection (Application),
Report ID (1), ; +00 report id
Usage Page (Keyboard), ; Keyboard/keypad (07h)
Logical Minimum (0),
Logical Maximum (1),
Usage Minimum (KB Leftcontrol), ; Keyboard left control (E0h, dynamic value)
Usage Maximum (KB Right GUI), ; Keyboard right GUI (E7h, dynamic value)
Report Size (1),
Report Count (8),
Input (Variable), ; +01 modifier
Report Count (5),
Report Size (1),
Usage Page (LED), ; LEDs (08h)
Usage Minimum (01h),
Usage Maximum (05h),
Output (Variable),
Report Count (1),
Report Size (3),
Output (Constant, Variable),
Report Count (8),
Report Size (1),
Logical Minimum (0),
Logical Maximum (1),
Usage Page (FF00h), ; FF00h, vendor-defined
Usage (03h),
Input (Constant, Variable), ; +02 vendor
Report Count (6),
Report Size (8),
Logical Minimum (0),
Logical Maximum (101),
Usage Page (Keyboard), ; Keyboard/keypad (07h)
Usage Minimum (None), ; No event (00h, selector)
Usage Maximum (KB Application), ; Keyboard Application (65h, selector)
Input, ; +03 6 keysym bytes
Report Count (1),
Report Size (1),
Logical Minimum (0),
Logical Maximum (1),
Usage Page (Consumer), ; Consumer (0Ch)
Usage (Eject), ; Eject (B8h, one-shot control)
Input (Variable), : +09.0
Report Count (1),
Report Size (1),
Usage Page (FF00h), ; FF00h, vendor-defined
Usage (03h),
Input (Variable), ; +09.1
Report Count (1),
Report Size (6),
Input (Constant, Variable), : +09.2-7
Usage Page (FF02h), ; FF02h, vendor-defined
Usage (55h),
Report ID (85),
Logical Minimum (0),
Logical Maximum (255),
Report Size (8),
Report Count (64),
Feature (Variable, No Preferred, Volatile),
End Collection,
Usage Page (FF00h), ; FF00h, vendor-defined
Usage (14h),
Collection (Application),
Report ID (144),
Usage Page (Power Device), ; Power device (84h, power page)
Report Size (1),
Report Count (3),
Logical Minimum (0),
Logical Maximum (1),
Usage (61h),
Usage Page (Power Batsys), ; Power battery system (85h, power page)
Usage (44h),
Usage (46h),
Input (Variable),
Report Count (5),
Input (Constant),
Report Size (8),
Report Count (1),
Logical Minimum (0),
Logical Maximum (255),
Usage (65h),
Input (Variable),
End Collection
Há um relatório de evento de entrada com o ID hex 01
, um relatório de status da bateria com ID hex 90
, uma saída para definir os LEDs normalmente e um controle de recurso específico do fornecedor.
Marquei os bytes para o relatório de eventos de entrada. Há vários campos definidos pelo fornecedor onde não sabemos o que eles fazem e temos que adivinhar.
O relatório de eventos de entrada consiste em 10 bytes e seus exemplos são decodificados da seguinte forma:
ID MM VA K1 K2 K3 K4 K5 K6 VB
01 00 00 00 00 00 00 00 00 02 ; press? Fn
01 00 00 00 00 00 00 00 00 00 ; release? Fn
01 00 00 3b 00 00 00 00 00 00 ; press F2
01 00 00 00 00 00 00 00 00 00 ; release
01 00 00 00 00 00 00 00 00 00 ;
01 00 00 00 00 00 00 00 00 02 ; press Fn?
01 00 00 3b 00 00 00 00 00 02 ; press F2
01 00 00 00 00 00 00 00 00 02 ; release F2 (but not Fn?)
ID
é o relatório. MM
são os bits modificadores padrão 8, que não têm espaço para a chave Fn
. K1
to K6
são até 6 teclas pressionadas simultaneamente. VA
e VB
são específicos do fornecedor. Assumindo que você segurou Fn e apenas pressionou e liberou F2
no último exemplo, meu palpite é que o bit 1 em VB
representa o modificador para Fn (ou pelo menos algo relacionado a isso).
Use hexdump -e '10/1 "%02X ""\n"'
para obter 9 bytes de saída por linha e teste essa hipótese combinando Fn com várias chaves, incluindo aquelas que você deseja redefinir no final.
Atualização : Para referência futura e completa, embora eu suponha que não seja mais relevante para este caso específico: é possível injetar eventos HID usando o UHID, veja Documentation/hid/uhid.txt
e samples/uhid/uhid-example.c
no kernel .