Fórum Ubuntu CZ/SK

Ostatní => Tipy a triky pro Linux => Téma založeno: ramael 14 Srpna 2022, 22:30:16

Název: Jak tak trochu ošidit libinput.
Přispěvatel: ramael 14 Srpna 2022, 22:30:16
Toto vlákno bude časem nabobtnávat s rozšířením vědomostí a dopracováním se k něčemu 100% funkčnímu. Nechci měnit příspěvky podle výsledků, ale chci zachovat kontinuitu jak se k něčemu dopracovat. Občas to vypadá a už jsem si i vyslechl, že pro mě je to jednoduché něco naklikáš a je hotovo. Tak takhle to doopravdy nefunguje. Jen ať je vidět, že cesta se dá najít, jen je trnitá a hlavně zdlouhavá!

V jedné diskuzi se tu ( https://forum.ubuntu.cz/index.php?topic=86030.0 ) narazilo na problém špatně funkčního touchpadu. A díky tomu jsem si vzpomenul na kdysi křížek s dálkovým ovladačem "PHILIPS MCE USB IR Receiver- Spinel plus". Bláhově jsem si myslel, že vývojáři už dávno odstranili problémy se zařízeními s "nestandardními" kódy. No, jenže skutek utek a pravda je bohužel opakem. Nejen, že se na to vykvajzli, ale ještě navíc omezili možnosti si něco normálněji dobastlit. Zkrátka vzhůru k windows logice.
Docela mne takové věci sejří (nejen mne https://www.askwoody.com/forums/topic/why-ive-come-to-dislike-libinput-one-of-the-linux-input-drivers/) a koukl se tomu blíže na zoubek. Myšlenky se míchali a jedna zavrhovala druhou aby ta třetí tu první povytáhla. Stále je ve mne taková doutnající jiskra, zkusit napsat přímo jaderný modul. Bohužel času moc nazbyt nemám. Stačilo několik dní zkoumat a přečíst kde co a jak abych se jen trošku zorientoval v problému input zařízeních v linuxu. Vypínat moduly, zakazovat atd. Začal jsem něco psát v pythonu. Což jsem ale asi po hodině zavrhl, po nedávné zkušenosti malého update a musel jsem si přepsat jedno API. Do překládaného programu se mi moc nechtělo a tak jsem objevoval jak to udělat v bash s maximem základních programů. Což se mi podařilo až po nainstalování balíku:
Kód: [Vybrat]
sudo apt install evemu-tools
Samozřejmě mohu nainstalovat irmodul atd. A problém s tímto DO vyřešen. Ale to neřeší problém jiných nestandardních vstupních zařízení. A v neposlední řadě mne jde o princip. Ukážu jednu z cest jak donacpat nefunkční tlačítka do funkčních eventů klávesnice.

Upozorňuji, že je to velice hrubé řešení. Chce si to doladit pomocí udev. Je to jen návod ukazující cestu. DO plně funguje, jen se to spouští ručně.

Takže tady je několik dní v pár řádcích:

První co je třeba si zjistit, je adresa zmíněného zařízení. Pomocí
Kód: [Vybrat]
sudo dmesg
se po připojení dozvíme bližší info:
Kód: [Vybrat]
usb 1-2: new low-speed USB device number 4 using xhci_hcd
[ 5804.564426] usb 1-2: New USB device found, idVendor=0471, idProduct=20cc, bcdDevice= 1.01
[ 5804.564431] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 5804.564434] usb 1-2: Product: MCE USB IR Receiver- Spinel plus
[ 5804.564435] usb 1-2: Manufacturer: PHILIPS
[ 5804.594082] input: PHILIPS MCE USB IR Receiver- Spinel plus Keyboard as /devices/pci0000:00/0000:00:08.1/0000:03:00.3/usb1/1-2/1-2:1.0/0003:0471:20CC.0003/input/input20
[ 5804.653981] input: PHILIPS MCE USB IR Receiver- Spinel plus System Control as /devices/pci0000:00/0000:00:08.1/0000:03:00.3/usb1/1-2/1-2:1.0/0003:0471:20CC.0003/input/input21
[ 5804.654302] input: PHILIPS MCE USB IR Receiver- Spinel plus Consumer Control as /devices/pci0000:00/0000:00:08.1/0000:03:00.3/usb1/1-2/1-2:1.0/0003:0471:20CC.0003/input/input22
[ 5804.655096] hid-generic 0003:0471:20CC.0003: input,hiddev0,hidraw1: USB HID v1.00 Keyboard [PHILIPS MCE USB IR Receiver- Spinel plus] on usb-0000:03:00.3-2/input0
Pro mne je důležitý údaj hidraw1 Dále Keyboard že je na adrese /0003:0471:20CC.0003/input/input20
Na základě toho mohu napsat:
Kód: [Vybrat]
ls -d /sys/bus/hid/drivers/hid-generic/0003\:0471\:20CC.0003/input/input20/ev*
A vypadne na mne eventX na kterém je namapovaná daná klávesnice DO. U mne event7

Napsal jsem skript kterému tyto hodnoty předáme. Spouští se ve tvaru:
Kód: [Vybrat]
sudo input_injection.sh cislo_eventu cislo_hidraw
U mne:
Kód: [Vybrat]
sudo input_injection.sh 7 1
Skript input_injection.sh:
Kód: [Vybrat]
#! /usr/bin/env bash

event=$1
hid=$2

# červené 304000000 KEY_F1 59
# zelené  308000000 KEY_F2 60
# žluté   300100000 KEY_F3 61
# modré   300200000 KEY_F4 62
# logo    302000000 KEY_HOME 102
# téčko   310000000 KEY_F5 63


function gehtdoch {
  evemu-event /dev/input/event$event --type 1 --code $1 --value 1
  evemu-event /dev/input/event$event --type 1 --code $1 --value 0
}

while :; do
  # načte raw hodnoty z hidraw1
  # později předělat pomocí udevu na něco dynamičtějšího
  vstup=$(hexdump -n8 -e'8/1 "%X"' /dev/hidraw$hid) || break
  # oříznutí první cifry určující skupinu tlačítek
  # díky tomu stačí jen jedna podmínka
  vstup=${vstup:1}
  # podmínka na "puštění" klávesy
  [[ "$vstup" = "0000000" ]] && continue  # || echo $vstup
  case $vstup in
    "04000000") gehtdoch 59;;
    "08000000") gehtdoch 60;;
    "0010000") gehtdoch 61;;
    "0020000") gehtdoch 62;;
    "02000000") gehtdoch 102;;
    "10000000") gehtdoch 63;;
  esac
done
Skript v loopu čeká na jakýkoliv vstup v /dev/hidrawX což je matka /dev/input/eventY a ještě dalších dvou. Čte vstup pomocí hexdump který jsem nastavil na 8bytů. Offset jsem zrušil a výstup nacpal kvůli zpracování na jeden řádek. Výsledné číslo začíná cifrou type události. Při stlačení klávesy se vygeneruje kód a při release ne vždy (podle type) se vygeneruje další kód type události s nulama. To nepotřebuji, tak jsem ho ořízl a tím mohl sjednocený kód release testovat a díky tomu přeskočit zbytek smyčky. Pakliže projde námi upravený kód, je porovnán jen s kódy nefunkčních tlačítek! Nepotřebuji suplovat celý libinput, ale jen těch pár kláves. Z výstupu evtest vím jaké kódy je schopná klávesnice DO obsloužit. A pár těch kódů které není DO schopen "vyslat" se napojí na ta tlačítka. V mém případě červené až modré tlačítko je F1 až F4. Tlačítku title jsem dal kód F5 a tlačítku WinLogo jsem dal Home.
Po spuštění skriptu funguje DO normálně a skript při zmáčknutí náma zadané klávesy injektuje /dev/input/eventX náma zadanou chybějící hodnotou.
Název: Re:Jak tak trochu ošidit libinput.
Přispěvatel: ramael 15 Srpna 2022, 06:28:10
Jsem se vzbudil trochu dřív, tak jsem to vylepšil.
jako root vytvořit soubor /usr/local/sbin/input_injection.sh obsahující
Kód: [Vybrat]
#! /usr/bin/env bash

# červené 304000000 KEY_F1 59
# zelené  308000000 KEY_F2 60
# žluté   300100000 KEY_F3 61
# modré   300200000 KEY_F4 62
# logo    302000000 KEY_HOME 102
# téčko   310000000 KEY_F5 63

function gehtdoch {
# stlačení klávesy
  evemu-event /dev/input/my_remote --type 1 --code $1 --value 1
# uvolnění klávesy
  evemu-event /dev/input/my_remote --type 1 --code $1 --value 0
}

while :; do
  # načte raw hodnoty z hidraw1
  vstup=$(hexdump -n8 -e'8/1 "%X"' /dev/remote 2> /dev/null) || break

  # oříznutí první cifry určující skupinu tlačítek
  # díky tomu stačí jen jedna podmínka
  vstup=${vstup:1}
  # podmínka na "puštění" klávesy
  [[ "$vstup" = "0000000" ]] && continue  # || echo $vstup
  case $vstup in
    "04000000") gehtdoch 59;;
    "08000000") gehtdoch 60;;
    "0010000") gehtdoch 61;;
    "0020000") gehtdoch 62;;
    "02000000") gehtdoch 102;;
    "10000000") gehtdoch 63;;
  esac
done
Jako root vytvoření souboru /etc/udev/rules.d/10-my-local.rules s tímto obsahem:
Kód: [Vybrat]
SUBSYSTEM=="hidraw" , ATTRS{idVendor}=="0471", ATTRS{idProduct}=="20cc", ACTION=="add", SYMLINK+="remote", RUN+="/usr/local/sbin/input_injection.sh"
ACTION=="add", ATTRS{name}=="PHILIPS MCE USB IR Receiver- Spinel plus Keyboard", SYMLINK+="input/my_remote"
PC se restartovat nemusí, stačí zadat
Kód: [Vybrat]
udevadm control --reload-rules
udevadm trigger
]
Soubor .rules zajistí první podmínkou aby se vytvořil link s názvem remote na vytvořený hidraw. Protože se může číslo hidrawu měnit, udev to ohlídá a slinkuje vždy ten správný na můj /dev/remote. Další podmínka ohlídá vytvoření "Keyboardu" a slinkuje vytvořený /dev/input/eventX s /dev/input/my_remote. Tím mám dva na tento ovladač pevně nastavené soubory zařízení s kterýma se dá pracovat aniž bych musel do toho dál nějak zasahovat.
A dálkový ovladač funguje naplno bez dalších zásahů.
Název: Re:Jak tak trochu ošidit libinput.
Přispěvatel: ramael 16 Srpna 2022, 11:45:14
Malá úprava scriptu aby generoval události v souladu s evtestem. A zároveň jsem přemapoval klávesy red=KEY_A, green=KEY_B, yellow=KEY_C, blue=KEY_D a "title"=KEY_E. Klávesu s logem win jsem nechal jako KEY_HOME.
/usr/local/sbin/input_injection.sh
Kód: [Vybrat]
#! /usr/bin/env bash

# červené 304000000 KEY_F1 59 13a10
# zelené  308000000 KEY_F2 60 13ba0
# žluté   300100000 KEY_F3 61 1388a
# modré   300200000 KEY_F4 62 13894
# logo    302000000 KEY_HOME 102
# téčko   310000000 KEY_F5 63 13c68

# sleep 1

function gehtdoch {
# nejdřív msc scan s hodnotou
  evemu-event /dev/input/my_remote --type 4 --code 4 --value 8${vstup:0:4}
# pak kód stlačené klávesy se sync
  evemu-event /dev/input/my_remote --sync --type 1 --code $1 --value 1
# opět msc scan
  evemu-event /dev/input/my_remote --type 4 --code 4 --value 8${vstup:0:4}
# kód uvolněné klávesy se sync
  evemu-event /dev/input/my_remote --sync --type 1 --code $1 --value 0
}

while :; do
  # načte raw hodnoty z hidraw1/remote
  vstup=$(hexdump -n8 -e'8/1 "%X"' /dev/remote 2> /dev/null) || break

  # oříznutí první cifry určující skupinu tlačítek
  # díky tomu stačí jen jedna podmínka
  vstup=${vstup:1}
  # podmínka na "puštění" klávesy
  [[ "$vstup" = "0000000" ]] && continue  # || echo $vstup
  case $vstup in
    "04000000") gehtdoch 30;;
    "08000000") gehtdoch 48;;
    "0010000") gehtdoch 46;;
    "0020000") gehtdoch 32;;
    "02000000") gehtdoch 102;;
    "10000000") gehtdoch 18;;
  esac
done
v rules se nic nemění:
/etc/udev/rules.d/10-my-local.rules
Kód: [Vybrat]
SUBSYSTEM=="hidraw" , ATTRS{idVendor}=="0471", ATTRS{idProduct}=="20cc", ACTION=="add", SYMLINK+="remote", RUN+="/usr/local/sbin/input_injection.sh"
ACTION=="add", ATTRS{name}=="PHILIPS MCE USB IR Receiver- Spinel plus Keyboard", SYMLINK+="input/my_remote"
Zkoušel jsem mapovat na klávesy dle /usr/include/linux/input-event-codes.h avšak libinput nepovolí jiné kódy než které zobrazí evtest /dev/input/my_remote
Pak jsem zkoušel přemapování pomocí hwdb, ale to nefunguje. Respetive, udevadm zobrazí změny, ale libinput a ostatní si jich nevšímají. Myslel jsem, že je to problém mého WM, avšak to nešlo ani v čistém terminálu bez WM.
Název: Re:Jak tak trochu ošidit libinput.
Přispěvatel: ramael 21 Srpna 2022, 00:10:10
Jsem si dnes našel trochu času a opět se v tom pošťoural. No vypadá to, že chyba není na straně libinputu, ale už v hidrawu. DO totiž ač vysílá klávesu KEY_2 systém dostane znak ě. Po různých testech jsem dospěl k závěru, že to dělá vrstva mezi hidraw a zbytkem. Ze samotného /dev/hidrawX jde ještě číst raw eventy, avšak ovladač ještě k tomu vysílá znak stisknuté klávesy remapovaný na locale klávesnici. Po vyřazení DO z hidrawu se to přestává dít a dají se číst eventy bez vkládání znaků včetně ovládání hlasitosti ap. Vzhledem k ďábelské specifikaci: https://www.usb.org/sites/default/files/hut1_3_0.pdf se mi to nechce vůbec dekódovat a hledat jak to přiohnout. I když...
Bash je dle mne v tomto už hodně omezen (není na to stavěn). Tak jsem si napsal skript v pythonu
Kód: [Vybrat]
#! /usr/bin/env python3

import usb.core
import usb.util

# vytvoření "instance" zařízení
my_remote = usb.core.find(idVendor=0x0471, idProduct=0x20cc)

try:
    # nastavení do "úvodního" stavu
    my_remote.reset()
except Exception as e:
    print('reset', e)

rozhrani = 0
endpoint = my_remote[0][(0, 0)][0]

# test jestli je aktivní nějaký modul na zařízení
if my_remote.is_kernel_driver_active(rozhrani) is True:
    # odpojení zařízení od jaderných modulů
    my_remote.detach_kernel_driver(rozhrani)
    usb.util.claim_interface(my_remote, rozhrani)

# nekonečná smyčka na načítání dat z usb rozhraní
while True:
    try:
        data = my_remote.read(endpoint.bEndpointAddress,
                              endpoint.wMaxPacketSize)
        if data[0] > 0:
        # nutný filtr ať se výstup neplevelí nulovýma řádkama
            vys = ""
            for i in data:
                # Konverze do bitového zobrazení s pevnou délkou pro lepší
                # vizuální porovnání jednotlivých bitů kláves
                # vys += format(i, "b").zfill(8) + " "
                # takhle je to rychlejší:
                vys += bin(i)[2:].zfill(8) + " "
            print(vys)
    except usb.core.USBError as e:
        data = None
        continue
kterým se vypisují v binární podobě jednotlivé eventy DO přímo z usb. Snažil jsem se tím přijít na topologii klávesnice. Avšak, žádnou zákonitost jsem neobjevil, vyjma inkrementace code na číselných tlačítkách. Teoreticky bych si ještě mohl pohrát s https://cs.wikipedia.org/wiki/Endianita jestli to třeba nebude zobrazovat něco "logičtějšího". Tak i tak je to docela pěkný pokrok za dnešní 3 hodiny. Od tud už je jen krůček k napsání si vlastního ovladače.
Název: Re:Jak tak trochu ošidit libinput.
Přispěvatel: ramael 22 Srpna 2022, 23:14:44
Dnešní hrátky se omezili na testování výpisu big endianu a úpravu skriptu. S tím BE to nebyl dobrý/funkční nápad. Výstupy byli ještě více "ošklivé"/nic neříkající. Avšak úprava skriptu se mi docela povedla. Jsem ho udělal trochu univerzálnější:
Kód: [Vybrat]
#! /usr/bin/env python3

import argparse
import usb.core
import usb.util

arr = argparse.ArgumentParser(description="Program na výpis raw událostí"
                              "z usb zařízení.\n"
                              "Program nemá ošetřené vstupy!!!\n"
                              "Spouštět jako obyčejný uživatel.",
                              formatter_class=argparse.RawTextHelpFormatter)
arr.add_argument("vendor", help="idVendor zařízení")
arr.add_argument("product", help="idProduct zařízení")
arr.add_argument("-o", "--output", default="dec",
                 help=("povolené hodnoty:\n"
                       "\tbin: binární\n"
                       "\tdec: desítkový\n"
                       "\thex: šestnáctkový\n"
                       "\toct: osmičkový"))

argumenty = arr.parse_args()


# my_remote = usb.core.find(idVendor=0x0471, idProduct=0x20cc)
my_remote = usb.core.find(idVendor=int(argumenty.vendor, 16),
                          idProduct=int(argumenty.product, 16))

try:
    # nastavení do "úvodního" stavu
    my_remote.reset()
except Exception:
    print('Zařízení není připojené, nebo není typu usb')
    exit(1)

rozhrani = 0
endpoint = my_remote[0][(0, 0)][0]

# odpojení zařízení od jaderných modulů
if my_remote.is_kernel_driver_active(rozhrani) is True:
    my_remote.detach_kernel_driver(rozhrani)
    usb.util.claim_interface(my_remote, rozhrani)


def raw_input_from_device(vst):
    print("Pro ukončení zmáčkni ctr+c")
    while True:
        try:
            data = my_remote.read(endpoint.bEndpointAddress,
                                  endpoint.wMaxPacketSize)
            print(kostra_fce(data, argumenty.output))
        except usb.core.USBError as e:
            data = None
            print(e)
            continue
        except KeyboardInterrupt:
            usb.util.release_interface(my_remote, rozhrani)
            my_remote.attach_kernel_driver(rozhrani)
            exit(0)
        except Exception:
            print("Něco se pos...")
            exit(1)


def kostra_fce(a, b):
    k_tisku = b + ": "
    i = 0
    vst: dict = {"bin": (bin, 2, 8),
                 "hex": (hex, 2, 2),
                 "dec": (str, 0, 0),
                 "oct": (oct, 2, 3)}
    for i in a:
        fce, zacatek, kolik = vst[b]
        k_tisku += fce(i)[zacatek:].zfill(kolik) + " | "
    return k_tisku


# spuštění hlavní fce
raw_input_from_device(argumenty.output)
Skript má povinné dva argumenty a to IDVendor a IDProduct USB INPUT zařízení z kterého chcete dostat informace. Třetí argument je -o nebo --output s volbou [bin|dec|hex|oct]. Asi není třeba popisovat co udělá jaký výpis. Vím, že pomocí wireshark to jde také. Ale ten mne několikrát spadnul. Tak jsem to napsal takto. On ten hexdump je také fajn, ale dopracovat se k nějakému kýženému výstupu trvá a trvá a ... Navíc cesta kterou jsem zvolil je plná sladkého poznávání.

Poznámka ke kódu skriptu. Pokud by někdo hledal podmínky if určující jaký výpis se má provést, tak takhle to v pythonu nefunguje. Respektive funguje, ale je to náročnější na prostředky PC. Python má lepší řešení ve formě volání funkcí ze slovníku:
Kód: [Vybrat]
vst: dict = {"bin": (bin, 2, 8),
                 "hex": (hex, 2, 2),
                 "dec": (str, 0, 0),
                 "oct": (oct, 2, 3)}
vst je zvolený název slovníku obsahující klíč: hodnota/y. Hodnoty jsem zvolil jako ntici kde prví položka je volaná funkce a další jsou dodatečné parametry.
Řádkem
Kód: [Vybrat]
fce, zacatek, kolik = vst[b]
se přiřadí záznam slovníku s klíčem v proměnné b do proměnných fce, zacatek a kolik
Kód: [Vybrat]
fce(i)[zacatek:].zfill(kolik)už jen promění díky kulatým závorkám proměnnou na volání funkce s parametrem i. Protože všechny zvolené funkce mají řetězcový výstup, dají se oříznout což zabezpečí údaje v hranatých závorkách. Proměnná zacatek určí kolik bude od počátku řetězce uříznuto. Poslední proměnná kolik určí kolik nul má příkaz zfill vyplnit do výsledku. Pokud se zadá neplatný klíč, je to odchyceno pomocí konstrukce try a skipt je ukončen.
Suma sumárum není třeba na každou požadovanou formu výpisu vytvářet extra funkce. Funkce lišící se jen v jednom řádku! A ty funkce volat podle série podmínek if. Přitom si stačí jen osvojit takovýto konstrukt formy volání.
Název: Re:Jak tak trochu ošidit libinput.
Přispěvatel: ramael 28 Srpna 2022, 20:31:05
Dnes jsem měl, díky počasí, po několika dnech čas trochu zapokračovat. Napravil jsem jeden nedostatek při práci se vstupníma usb zařízeníma. Ve zkratce. Každé vstupní usb zařízení má ještě několik rozhraní. Skript jsem poopravil aby se korektně odpojili (od jaderných modulů) a pak opět zpět připojili všechna rozhraní testovaného zařízení. Přidal jsem parametr kterým se určuje z jakého rozhraní chceme události zachytávat. Vyhrabal jsem myš Logitech M705+ a otestoval. Nejprve se spustí grep jako root. Který vypíše všechna připojená usb zařízení s jejich id vendor, produkt a počtem rozhraní. To abych věděl kolik rozhraní mohu testovat.
Kód: [Vybrat]
sudo grep -i 'vendor\|manufacturer\|product\|#ifs' /sys/kernel/debug/usb/devices
Výstup u mne vypadá takto:
Kód: [Vybrat]
P:  Vendor=1d6b ProdID=0002 Rev= 5.07
S:  Manufacturer=Linux 5.7.8-050708-generic xhci-hcd
S:  Product=xHCI Host Controller
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=  0mA
P:  Vendor=046d ProdID=c52b Rev=12.11
S:  Manufacturer=Logitech
S:  Product=USB Receiver
C:* #Ifs= 3 Cfg#= 1 Atr=a0 MxPwr= 98mA
P:  Vendor=04f2 ProdID=b6c2 Rev=27.14
S:  Manufacturer=Chicony Electronics Co.,Ltd.
S:  Product=Integrated Camera
C:* #Ifs= 2 Cfg#= 1 Atr=80 MxPwr=500mA
P:  Vendor=1d6b ProdID=0003 Rev= 5.07
S:  Manufacturer=Linux 5.7.8-050708-generic xhci-hcd
S:  Product=xHCI Host Controller
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=  0mA
P:  Vendor=1d6b ProdID=0002 Rev= 5.07
S:  Manufacturer=Linux 5.7.8-050708-generic xhci-hcd
S:  Product=xHCI Host Controller
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=  0mA
P:  Vendor=0bda ProdID=c123 Rev= 0.00
S:  Manufacturer=Realtek
S:  Product=Bluetooth Radio
C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
P:  Vendor=1d6b ProdID=0003 Rev= 5.07
S:  Manufacturer=Linux 5.7.8-050708-generic xhci-hcd
S:  Product=xHCI Host Controller
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=  0mA
Pro mne důležité toto:
Kód: [Vybrat]
P:  Vendor=046d ProdID=c52b Rev=12.11
S:  Manufacturer=Logitech
S:  Product=USB Receiver
C:* #Ifs= 3 Cfg#= 1 Atr=a0 MxPwr= 98mA
Písmeno S: říká s kým mám tu čest. Písmeno P: říká idVendor a idProduct. A pod písmenem C: je položka #Ifs= (interfaces) která oznamuje kolik má dané zařízení rozhraní. Hvězdička * ukazuje že je to momentálně připojené.
Pak už jen stačilo testovat.

test1:
Kód: [Vybrat]
sudo ./der.py 046d c52b -i 0 -o binžádný výstup.

test2:
Kód: [Vybrat]
sudo ./der.py 046d c52b -i 1 -o bina tady už je to zajímavé:
Kód: [Vybrat]
Pro ukončení zmáčkni ctr+c
bin: 00000010 | 00000001 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 |
bin: 00000010 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 |
bin: 00000010 | 00000010 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 |
bin: 00000010 | 00000010 | 00000000 | 00000000 | 11110000 | 11111111 | 00000000 | 00000000 |
bin: 00000010 | 00000010 | 00000000 | 00000000 | 00010000 | 00000000 | 00000000 | 00000000 |
bin: 00000010 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 |
bin: 00000010 | 00000000 | 00000000 | 00000001 | 00000000 | 00000000 | 00000000 | 00000000 |
bin: 00000010 | 00000000 | 00000000 | 00000001 | 11110000 | 11111111 | 00000000 | 00000000 |
bin: 00000010 | 00000000 | 00000000 | 00000010 | 00000000 | 00000000 | 00000000 | 00000000 |
bin: 00000010 | 00000000 | 00000000 | 00000101 | 11110000 | 11111111 | 00000000 | 00000000 |
bin: 00000010 | 00000000 | 00000000 | 00000100 | 11110000 | 11111111 | 00000000 | 00000000 |
bin: 00000010 | 00000000 | 00000000 | 00000100 | 11110000 | 11111111 | 00000000 | 00000000 |
bin: 00000010 | 00000000 | 00000000 | 00000011 | 11110000 | 11111111 | 00000000 | 00000000 |
bin: 00000010 | 00000000 | 00000000 | 00000010 | 00000000 | 00000000 | 00000000 | 00000000 |
Druhý byte ukazuje bitové hodnoty tlačítek vyjma pohybu kolečka. Sedmý byte ukazuje jakým směrem se kolečko otáčí a osmý jakým směrem se kolečko naklání. Čtyřka až šestka určují směr (a nejspíš i rychlost) pohybu myši. Na to jsem to testoval moc krátce.

Pak je tu jedno překvapení a to test3 na rozhraní číslo 2:
Kód: [Vybrat]
sudo ./der.py 046d c52b -i 2 -o binkdo by to byl řekl, že i to mechanické tlačítko na jemnost pohybu kolečka má svoje události:
Kód: [Vybrat]
Pro ukončení zmáčkni ctr+c
bin: 00010001 | 00000001 | 00011010 | 00010000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 |
bin: 00010001 | 00000001 | 00011010 | 00010000 | 00000001 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 | 00000000 |
Fíha, 20 byte na jeden spínač. Fakt to není tlačítko, ale spínač. Z toho jen pátý byte určuje jestli je zapnutý nebo ne.

Ještě okomentovaný zdrojový kód skriptu:
Kód: [Vybrat]
#! /usr/bin/env python3

import argparse
import usb.core
import usb.util

arr = argparse.ArgumentParser(description="Program na výpis raw událostí"
                              "z usb zařízení.\n"
                              "Program nemá ošetřené vstupy!!!",
                              formatter_class=argparse.RawTextHelpFormatter)
arr.add_argument("vendor", help="idVendor zařízení")
arr.add_argument("product", help="idProduct zařízení")
arr.add_argument("-i", "--interf", default=0,
                 help="které rozhraní skenovat")
arr.add_argument("-o", "--output", default="dec",
                 help=("povolené hodnoty:\n"
                       "\tbin: binární\n"
                       "\tdec: desítkový\n"
                       "\toct: osmičkový\n"))

argumenty = arr.parse_args()


# vytvoření instance našeho vstupního zařízení
# my_remote = usb.core.find(idVendor=0x0471, idProduct=0x20cc)
my_remote = usb.core.find(idVendor=int(argumenty.vendor, 16),
                          idProduct=int(argumenty.product, 16))

try:
    # nastavení do "úvodního" stavu
    my_remote.reset()
except Exception:
    # cosi se po....hnojilo. Chybové ukončení
    print('Zařízení není připojené, nebo není typu usb')
    exit(1)

# endpoint rozhraní které se bude testovat
endpoint = my_remote[0][(int(argumenty.interf, 10), 0)][0]

# odpojení zařízení od jaderných modulů
# nejdřív načte kolik rozhraních má dané zařízení
rozhrani = my_remote[0].bNumInterfaces
# rozhraní se budou postupně procházet a odpojovat od kernel modulů
for i in range(rozhrani):
    if my_remote.is_kernel_driver_active(i) is True:
        my_remote.detach_kernel_driver(i)
        usb.util.claim_interface(my_remote, i)


# hlavní funkce "capo di capo"
# není ideálně napsaná, ale nepředpokládám že bude mít jiné využití
# fce přijímá jediný parametr a to požadovaný formát výpisu
def raw_input_from_device(vst):
    print("Pro ukončení zmáčkni ctr+c")
    while True:
        try:
            # načte údaje z vyhrazené paměti
            data = my_remote.read(endpoint.bEndpointAddress,
                                  endpoint.wMaxPacketSize)
            # vytiskne co je třeba
            print(kostra_fce(data, argumenty.output))
        except usb.core.USBError as e:
            data = None
            # prevence proti výpisu timeoutu. Jinak vypiš všechny chyby a
            # pokračuj
            if e.errno == 110:
                continue
            print(e)
            continue
        except KeyboardInterrupt:
            # Zachycení události ctrl+c
            # Jde se uklidit do původního stavu
            # Opětovné připojení k jaderným modulům
            for i in range(rozhrani):
                usb.util.release_interface(my_remote, i)
                my_remote.attach_kernel_driver(i)
            # normální ukončení
            exit(0)
        except Exception:
            # Zachycení všeho ostatního nechtěného špatného
            print("Něco se pos...")
            # Jde se uklidit do původního stavu
            # Opětovné připojení k jaderným modulům
            for i in range(rozhrani):
                usb.util.release_interface(my_remote, i)
                my_remote.attach_kernel_driver(i)
            # chybové ukončení
            exit(1)


# řídící funkce na formát výpisu
# přijímá vygenerovaná data události a klíč na formát výpisu
def kostra_fce(a, b):
    k_tisku = b + ": "  # inicializace řetězce výpisu
    i = 0
    # řídící slovník ve formátu:
    # "klíč": (příkaz,
    #          kolik počátečních znaků oříznout,
    #          ciferné zarovnání/kolik cifer bude vytisknuto)
    vst: dict = {"bin": (bin, 2, 8),
                 "hex": (hex, 2, 2),
                 "dec": (str, 0, 0),
                 "oct": (oct, 2, 3)}
    # procházení prvků dat události
    for i in a:
        # přiřazení hodnot dle řídícího slovníku
        fce, zacatek, kolik = vst[b]
        # řetězení výstupního řádku
        k_tisku += fce(i)[zacatek:].zfill(kolik) + " | "
    return k_tisku


# spuštění hlavní fce
raw_input_from_device(argumenty.output)

Až budu mít zase jednou čas, popojdu kousek dál.
Hlavní je, že se dá cesta jak něco udělat/zprovoznit, vždy najít!