sobota 19. prosince 2020

Wayland a mapování tlačítek myši

Řekl jsem si, že vyzkouším konečně Gnome Shell na Wayland session, když už jsem nainstaloval Ubuntu 20.04 a tak jsem učinil. Hned jsem samozřejmě narazil s některými svými výtvory, které jsou založené na "průhlednosti" X11 a pod Waylandem nefungují. Tak jen pár poznámek kolem toho a možnosti mapování tlačítek myši. ...

Wayland obecněji a co mi vzal

Wayland je protokol pro komunikaci mezi aplikacemi a zobrazovacím serverem - kompozitorem. Kompozitorů tu máme více, vývoj protokolu začínal s Watsonem, Gnome Shell má Mutter, KDE KWin, pak je tu Sway, ... . Různá prostředí mají různé kompozitory a tím různou implementaci Waylandu, není jen jeden Wayland display server. Okna aplikací fungují jako klienti kompozitoru a díky stejnému protokolu by jejich vzájemná komunikace teoreticky měla být nezávislá na kompozitoru.

Kompozitor zajišťuje i události ze vstupních zařízení jako jsou myši, klávesnice, tablety, apod. Okno přes Wayland dostane pouze ty události, které mu patří, tedy ty z klávesnice pouze pokud má okno fokus, a z myši, pokud je ukazetel přímo nad ním. Oproti X11 serveru s Waylandem není možné, aby si aplikace sama definovala globální klávesovou zkratku, sama určila, že okno bude "Allways on top", nemůže si ani říci, kam na obrazovce si chce umístit nové okno, zjistit, kde se na obrazovce nachází, natož vidět ostatní okna a posílat jim něco na vstupy. Z hlediska uživatele z toho kouká jediná výhoda - vyšší bezpečnost, aplikace jsou od sebe izolované, nemohou se navzájem šmírovat.

Já jsem tak přepnutím na Wayland ztratil například mapování tlačítek myši na globální i lokální klávesové zkratky pomocí xbindkeys s xte, (či xkvbd) a funkce navázané na myšší gesta díky aplikaci Easystroke (gesty ovládám především webové prohlížeče, na což mě kdysi naučila Opera, a nemusel jsem řešit rozšíření u každého z nich). V mém SGTimeru přestalo fungovat zapamatování pozice widgetu, allways on top je mu nutné nastavit ručně a protože nemá dekoraci, musí se přes Alt+Space menu, zničilo to také funkci, která uměla po najetí myši widget schovat, aby se pod ním dalo i klikat a zobrazit jej opět po odjetí kurzoru myši z oblasti, na které se zobrazuje, protože již není schopen hlídat polohu kurzoru, který není nad jeho oknem.

Toto všechno nefunguje pod Wayland protokolem, ale neznamená to, že to nemůže fungovat pod Wayland session. Aplikace, které nejsou schopny, nebo nechtějí, fungovat přímo s Waylandem, mohou využít XWayland, tedy server X11 jako klienta Wayland kompozitoru. Není problém mít jedno GTK3 okno na Waylandu a vedle další GTK3 okno pod X11. Pak například X11 aplikace může vidět i pozici ukazatele myši, ale pouze tehdy, když je ukazatel zrovna nad nějakým X11 oknem.

Ještě je nutné říci, že Wayland nefunguje s proprietárními ovladači grafické karty, takže jsem musel přeinstalovat na otevřený noveau. Nehraji hry a desktop s tímto ovladačem mi funguje nerozeznatelně, jen monitoring grafiky, který jsem si napsal pro Conky, mi nefunguje, takové info noveau neposkytuje. Pro náročnější využití GK je to každopádně mínus, výkon a efektivita je stále dost nízko.

Dále pod Waylandem nefunguje restart Gnome Shellu, vůbec. Když napíšete do okénka pro spuštění (Alt+F2) příkaz r pro restart, tak vám to ještě před Enterem napíše, že to pod Waylandem nejde. To může být problém, zrovna mi pod X11 zlobilo přepínání oken Alt+Tab, tak jsem stiskl Alt+F2 spustil r a bylo opraveno.

Která okna jsou která?

Pod Wayland session tak můžete mít na desktopu fůru oken, u kterých pohledem nerozlišíte, zda běží nativně, nebo pod X11. Například Firefox, i když už Wayland zvládá, se spouští pod X11. Pro představu, jak Wayland funguje a co přináší vývojářům Firefoxu, doporučuji článek na rootu.cz Firefox na Waylandu: proč ho chtít a jaké má výhody?

V Gnome desktopu určuje při startu GTK aplikacím použitý okenní protokol systémová proměnná GDK_BACKEND a ta je v shellu Ubuntu 20.04 nastavena i pod Waylandem takto:

$ echo $GDK_BACKEND
x11

Pokud tedy z terminálu spustíte GTK3 aplikaci, spustí se pod X11. Pokud proměnnou přepíšete na "wayland", poběží na Waylandu. Firefox tuto proměnnou také poslouchá, mimoto ale slyší na svou vlastní:

MOZ_ENABLE_WAYLAND=1

Nejjednodušším způsobem, jak rozlišit okna běžících aplikací, je spuštění nějakého X11 nástroje, který pracuje s kurzorem myši pro určení zdroje například:

xprop

Ten, po spuštění v terminálu bez argumentů, změní kurzor myši na křížek a čeká, až kliknete na okno, jehož vlastnosti vám pak vypíše do terminálu. Takto to ale funguje pouze s X11 okny, takže stačí myší přejíždět nad okny a nad kterými se kurzor mění na křížek, ty běží na X11, Wayland okna vůbec nevidí a nemůže zaznamenat ani kliknutí do nich.

Můžete si také vypsat seznam oken, registrovaných pod X11 následovně (wmctrl nutno doinstalovat):

$ wmctrl -l

Waylandí okna nevidí a tak je ani nevypíše. Pozor na to, že wmctrl -l vypisuje to, co mají okna v dekoraci jako záhlaví. X11 aplikace lze vypsat i příkazem xlsclients, který vypisuje jména aplikací, místo oken, ale ten mi například neviděl Wireshark, ačkoli pod X11 bežel, některé procesy nemají okna řádně registrovaná a nelze je tak spojit. Okna běžící po Waylandem si nevylistujete, tak je to navrženo schválně.

Vstupy pod Waylandem 

Úkolem dneška je namapovat extra tlačítka myši na klávesové zkratky. Začneme oťukáváním zařízení.

Výpis vstupních zařízení: 

Získat seznam vstupních zařízení můžete z kernelu:

$ cat /proc/bus/input/devices

Jména a ukazatele na myši lze vyfiltrovat následovně:

$ egrep "Name|Handlers" /proc/bus/input/devices | egrep -B1 'Handlers.*mouse'
    N: Name="Logitech Performance MX"
    H: Handlers=mouse0 event5

Protože nyní vidí X11 vstupy skrz Wayland, vypadá výpis xinput takto:

$ xinput list
WARNING: running xinput against an Xwayland server. See the xinput man page for details.
    ⎡ Virtual core pointer                            id=2    [master pointer  (3)]
    ⎜   ↳ Virtual core XTEST pointer                  id=4    [slave  pointer  (2)]
    ⎜   ↳ xwayland-pointer:17                         id=6    [slave  pointer  (2)]
    ⎜   ↳ xwayland-relative-pointer:17                id=7    [slave  pointer  (2)]
    ⎣ Virtual core keyboard                           id=3    [master keyboard (2)]
        ↳ Virtual core XTEST keyboard                 id=5    [slave  keyboard (3)]
        ↳ xwayland-keyboard:17                        id=8    [slave  keyboard (3)]

Pod X11 session dostanete výpis fyzických zařízení, takže je zřejmé, která konkrétní zařízení mají jaká id. Pod Waylandem je to jinak, X11 nevidí přímo na zařízení, vstupy dostává od Waylandu, který v protokolu nemá popis konkrétních fyzických zařízení, dává pouze virtuální vstup/y a bez intervence sdružuje zařízení stejného typu, takže více myší tu bude jako jeden vstup. Ještě bych měl dodat, že tyto X11 nástroje fungují pouze za předpokladu, že nemáte zakázaný XWayland, což ale není výchozí stav.

Vstupy nám v systému zajišťuje knihovna libinput, která nahradila Xorg evdev, pro Wayland je nezbytná, funguje s ní i přímo X11. Pro další hrátky bude třeba doinstalovat následující balíky:

sudo apt install evtest evemu-tools libinput-tools

Evtest a libinput-tools jsou nástroje pro práci se vstupy, evemu-tools umožňují emulovat vstupní zařízení, tedy posílat třeba stisky kláves.

Přímo k datům vstupních zařízení se dostanete pouze jako root, nebo uživatel patřicí do skupiny input. Následující příkaz vypíše všechna vstupní zařízení a základní vlastnosti:

$ sudo libinput list-devices
     ...
    Device:           Logitech Performance MX
    Kernel:           /dev/input/event5
    Group:            5
    Seat:             seat0, default
    Capabilities:     pointer
    Tap-to-click:     n/a
    Tap-and-drag:     n/a
    Tap drag lock:    n/a
    Left-handed:      disabled
    Nat.scrolling:    disabled
    Middle emulation: disabled
    Calibration:      n/a
    Scroll methods:   button
    Click methods:    none
    Disable-w-typing: n/a
    Accel profiles:   flat *adaptive
    Rotation:         n/a
    ...

Každé zařízení má svůj odstavec, tohle je kus pro mou myš. Dalším filtrováním se dostaneme k cestám pouze zařízení typu pointer, typicky myši:

$ sudo libinput list-devices | grep "  pointer" -B4 | grep -o '/dev/input/event[0-9]*'
/dev/input/event5

V mém případě jsou typu pointer dvě zařízení, jeden generuje čip klávesnice, podporující touchpad, který ovšem chybí. Jeho atribut Capabilities: je ovšem "keyboard pointer", takže stačí odfiltrovat přidánim dvou mezer před "pointer".

nebo takto bez zvýšených práv a o dva řády rychleji (opravdu stovky ms proti nízkým jednotkám):
$ echo /dev/input/$(sed -rn '/Handlers=.*mouse.*/s/.*(event[0-9]).*/\1/p' /proc/bus/input/devices)
/dev/input/event5

Popis vstupních zařízení nabízí i evemu., také je třeba root, nebo input skupina. Následující příkaz je možné spustit přímo s cestou ke konkrétnímu zařízení, nebo bez argumentu a pak dostanete vybrat ze seznamu:

$ sudo evemu-describe
    Available devices:
    /dev/input/event0:     Power Button
    /dev/input/event1:     Power Button
    /dev/input/event2:     SEMICO USB Keyboard
    /dev/input/event3:     SEMICO USB Keyboard Consumer Control
    /dev/input/event4:     SEMICO USB Keyboard System Control
    /dev/input/event5:     Logitech Performance MX
    /dev/input/event6:     FiiO DigiHug USB Audio
    /dev/input/event7:     HDA NVidia HDMI/DP,pcm=3
    /dev/input/event8:     HDA NVidia HDMI/DP,pcm=7
    /dev/input/event9:     HDA NVidia HDMI/DP,pcm=8
    /dev/input/event10:    HDA NVidia HDMI/DP,pcm=9
    /dev/input/event11:    HDA NVidia HDMI/DP,pcm=10
    /dev/input/event12:    HDA NVidia HDMI/DP,pcm=11
    /dev/input/event13:    HDA NVidia HDMI/DP,pcm=12

    Select the device event number [0-13]: 5

    # EVEMU 1.3
    # Kernel: 5.4.0-56-generic
    # DMI: dmi:bvnAmericanMegatrendsInc.:bvrV10.10:bd10/31/2013:svnMSI:pnMS-7758:pvr2.0:rvnMSI:rnB75A-G43(MS-7758):rvr2.0:cvnMSI:ct3:cvr2.0:
    # Input device name: "Logitech Performance MX"
    # Input device ID: bus 0x03 vendor 0x46d product 0x101a version 0x111
    # Supported events:
    #   Event type 0 (EV_SYN)
    #     Event code 0 (SYN_REPORT)
    #     Event code 1 (SYN_CONFIG)
    #     Event code 2 (SYN_MT_REPORT)
    #     Event code 3 (SYN_DROPPED)
    #     Event code 4 ((null))
    #     Event code 5 ((null))
    #     Event code 6 ((null))
    #     Event code 7 ((null))
    #     Event code 8 ((null))
    #     Event code 9 ((null))
    #     Event code 10 ((null))
    #     Event code 11 ((null))
    #     Event code 12 ((null))
    #     Event code 13 ((null))
    #     Event code 14 ((null))
    #     Event code 15 (SYN_MAX)
    #   Event type 1 (EV_KEY)
    #     Event code 272 (BTN_LEFT)
    #     Event code 273 (BTN_RIGHT)
    #     Event code 274 (BTN_MIDDLE)
    #     Event code 275 (BTN_SIDE)
    #     Event code 276 (BTN_EXTRA)
    #     Event code 277 (BTN_FORWARD)
    #     Event code 278 (BTN_BACK)
    #     Event code 279 (BTN_TASK)
    #     Event code 280 ((null))
    #     Event code 281 ((null))
    #     Event code 282 ((null))
    #     Event code 283 ((null))
    #     Event code 284 ((null))
    #     Event code 285 ((null))
    #     Event code 286 ((null))
    #     Event code 287 ((null))
    #   Event type 2 (EV_REL)
    #     Event code 0 (REL_X)
    #     Event code 1 (REL_Y)
    #     Event code 6 (REL_HWHEEL)
    #     Event code 8 (REL_WHEEL)
    #     Event code 11 (REL_WHEEL_HI_RES)
    #     Event code 12 (REL_HWHEEL_HI_RES)
    #     Event type 4 (EV_MSC)
    #     Event code 4 (MSC_SCAN)
    # Properties:
    N: Logitech Performance MX
    I: 0003 046d 101a 0111
    P: 00 00 00 00 00 00 00 00
    B: 00 0b 00 00 00 00 00 00 00
    B: 01 00 00 00 00 00 00 00 00
    ...

Zde je vidět i konkrétní překlady jednotlivých tlačítek myši. Boční tlačítka včetně Vpřed/Vzad jsou popsaná špatně, ta jmenovaná ale v systému fungují správně, zatímco další dvě ve výchozím stavu nemají funkci žádnou a jedno ani nemá přiřazen key code. Evidentně jsou některé key codes špatně pojmenovány, protože jejich číselné reprezentace by měly fungovat bez ohledu na výrobce myši, na ty se mají reálná tlačítka mapovat..

Mapování vstupu pomocí udev - hwdb

Základní možností, jak tlačítko myši namapovat na klávesu klávesnice, nebo i na jiné tlačítko myši, je připsání nějakého toho řádku do hwdb souboru. Po připojení zařízení kernel vygeneruje událost, podle které uvdev spustí předepsané akce, včetně hwdb. Kernel dodá i detailní popis zařízení, takže hwdb může aplikovat konfiguraci s rozlišením na konkrétní modely, i revize. Díky základním regulárním výrazům lze konfigurace cílit i na celé skupiny zařízení, sdílejících stejný základ.

Například nastavení bočního tlačítka mé Logitech Performance MX na levou klávesu Super, pro aktivaci Overlay náhledu v Gnome Shellu, vypadá následovně (toto je mnou vytvořený soubor) a dále popíšu, jak jsem se k tomu dostal:

$ cat /etc/udev/hwdb.d/99-gdh-mouse.hwdb
# Logitech Performance MX
evdev:input:b0003v046Dp101A*
 ID_INPUT_KEY=1
 KEYBOARD_KEY_90009=leftmeta

Systémové hwdb soubory se nacházejí v adresáři:

/usr/lib/udev/hwdb.d/

Uživatelské hwdb soubory by se měly umístit do:

/etc/udev/hwdb.d/

Soubory v /usr/lib/.. needitujte, protože aktualizace by je dříve, či později přepsaly. Soubory jsou čteny z obou adresářů najednou a aplikují se podle abecedy, proto začínají čísly, aby se v tom dobře orientovalo. Dříve se spouští ty s nižšími čísly a pokud oba adresáře obsahují stejně pojmenovaný soubor, má přednost ten v /etc/... a ten z /usr/lib/... se vůbec nebude aplikovat. Na druhou stranu pozor na to, že pokud v různých hwdb souborech bude nastavována stejná vlastnost zařízení, jen s jiným parametrem, bude mít poslední slovo ta později aplikovaná, takže je třeba jméno souboru začít dostatečně vysokým číslem.

Formát identifikace zařízení je následující:

<typ_zařízení>:<sběrnice>:v<VENDOR_ID>p<PRODUCT_ID>:name:<DEVICE_NAME>:

nebo u verzí nad 220:

evdev:input:b<sběrnice>v<VENDOR_ID>p<PRODUCT_ID>e<verze>*

evdev:name:<jméno zařízení>*

Nemusíte zadávat úplně vše, můžete použít i wild card znaky, konkrétně * pro libovolný znak(y) v libovolném množství, včetně žádného, ? pro jakýkoli jeden znak a [znaky]  pro jakýkoliv znak z výčtu mezi závorkami. Viz dokumentace. Nicméně z dokumentace jsem byl také lehce zmaten, protože tam jsem se nedozvěděl, že ten údajně novější zápis (jak jsem se dozvěděl na fórech), musí mít všchna ID  zařízení zapsaná s velkými písmeny, jinak to nefunguje. Takže nakonec mém přípdě fungují na Ubuntu 20.04 všechny následující varianty:

mouse:usb:v046dp101a:name:Logitech Performance MX: evdev:input:b0003v046Dp101Ae0111*
evdev:name:Logitech Performance MX*

Potřebná id zařízení naleznete třeba v /proc/bus/input/devices, v mém případě jako filtr mohu zadat část jména mé myši (MX):

grep MX -B1 /proc/bus/input/devices
I: Bus=0003 Vendor=046d Product=101a Version=0111
N: Name="Logitech Performance MX"

Další možnost:

$ grep "" /sys/class/input/event5/device/id/*
/sys/class/input/event5/device/id/bustype:0003
/sys/class/input/event5/device/id/product:101a
/sys/class/input/event5/device/id/vendor:046d
/sys/class/input/event5/device/id/version:0111

Jak vypadá nastavení vlastností zařízení se můžete podívat do systémových hwdb souborů, pro myši je tam nejčastějí třeba nastavení rozlišení (DPI) snímače. Identifikační řetězec začíná hned zleva, řádky s nastavením vlastností musí začínat právě jednou mezerou.

ID_INPUT_KEY=1 zajistí, že se myš nebude chovat pouze jako myš, ale také jako klávesnice. Pro mapování tlačítek a kláves je formát následující:

KEYBOARD_KEY_<scan_code>=<key_code>

Scan_code je kód tlačítka/klávesy, který leze ze zřízení, key_code je kód klávesy, které rozumí systém a na kterou potřebujete tlačítko namapovat. Můžete použít přímo číselný kód klávesy, nebo jednoduše název klávesy, ten se zapisuje malými písmeny, buď bez prefixu (např. key_, btn_), nebo s ním.

Seznam kódů kláves, tlačítek a dalších vstupních událostí, s jejich názvy, naleznete v souboru:

/usr/include/linux/input-event-codes.h

Přečtení scan code tlačítka myši:

Scan kódy zjistíte pomocí evtestu:

sudo evtest /dev/input/event5 | egrep -v "EV_REL|SYN"
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x46d product 0x101a version 0x111
Input device name: "Logitech Performance MX"
Supported events:
  Event type 1 (EV_KEY)
    Event code 125 (KEY_LEFTMETA)
    Event code 272 (BTN_LEFT)
    Event code 273 (BTN_RIGHT)
    Event code 274 (BTN_MIDDLE)
    Event code 275 (BTN_SIDE)
    Event code 276 (BTN_EXTRA)
    Event code 277 (BTN_FORWARD)
    Event code 278 (BTN_BACK)
    Event code 279 (BTN_TASK)
    Event code 280 (?)
    Event code 281 (?)
    Event code 282 (?)
    Event code 283 (?)
    Event code 284 (?)
    Event code 285 (?)
    Event code 286 (?)
    Event code 287 (?)
    Event code 0 (REL_X)
    Event code 1 (REL_Y)
    Event code 6 (REL_HWHEEL)
    Event code 8 (REL_WHEEL)
    Event code 11 (REL_WHEEL_HI_RES)
    Event code 12 (REL_HWHEEL_HI_RES)
  Event type 4 (EV_MSC)
    Event code 4 (MSC_SCAN)
Properties:
Testing ... (interrupt to exit)
Event: time 1608286945.290995, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90009
Event: time 1608286945.290995, type 1 (EV_KEY), code 280 (?), value 1
Event: time 1608286945.413001, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90009
Event: time 1608286945.413001, type 1 (EV_KEY), code 280 (?), value 0

Pro eliminaci výpisu pohybu myši a dalších zbytečných řádků jsem přidal filtr. Po spuštění vypíše vlastnosti zadaného zařízení a i zde můžete přečíst ID pro identifikaci zařízení v hwdb a aktuální mapování tlačítek. Následně stisknete tlačítko, jehož scan kód hledáte a událost se vypíše do terminálu. Pomocí Ctrl+C příkaz ukončíte. Evtest můžete spustit i bez cesty k zařízení, pak opět dostanete na výběr ze seznamu.

Scan_code je v řádku vedle (MSC_SCAN), v mém případě 90009.

Klávesu, na kterou chcete tlačítko namapovat, můžete zjistit stejným způsobem, jen si musíte vybrat patřičný vstup, tedy klávesnici, zajímat vás bude položka code - buď číselný, nebo jméno za ním v závorce.

Mapování tlačítek za běhu za pomocí skriptu

Předchozím způsobem lze mapovat klávesy a tlačítka jedna ku jedné, což neumožňuje složené klávesové zkratky typu Ctrl+Tab apod. Tady si můžeme pomoci debug výstupem z libinput, který umí plivat všechny vstupní události pěkně přehledně. Trochu to profiltrujeme a když zachytíme kód klávesy, kterou chceme namapovat, nasimulujeme stisk tlačítek klávesnice pomocí evemu.

Našel jsem na githubu hotové řešení jménem wayland-mouse-mapper, který dělá přesně toto. Já jsem si ho z několika důvodů trochu upravil, napíšu proč. Nejprve ale zásadní komponenty skriptu.

Čtení událostí z libinput

$ sudo stdbuf -oL libinput debug-events |grep POINTER_BUTTON
 event5   POINTER_BUTTON   +1.162s    BTN_LEFT (272) pressed, seat count: 1
 event5   POINTER_BUTTON   +1.218s    BTN_LEFT (272) released, seat count: 0
 event5   POINTER_BUTTON   +2.372s    ??? (280) pressed, seat count: 1
 event5   POINTER_BUTTON   +2.460s    ??? (280) released, seat count: 0

Takto můžete číst po řádcích vstupní události ze všech vstupů najednou a pouštět dál pouze ty, které odpovídají stisku tlačítek myši. Přidáte-li libinputu cestu k zařízení ve formátu /dev/bus/input/eventX, kde X je číslo eventu daného zařízení, dostanete stream pouze odtud.

Tím jsem se dostal k první úpravě zmíněného skriptu, který si vyfiltruje pouze vstupy z myší a navěsí libinput debug na každý zvlášť. Problém je v tom, že když zařízení vytáhnete z usb (a třeba jen přepojíte do jiného konektoru), libinput debug zacílený na konkrétní zařízení, nezaznamená chybu a ani nedostanete žádnou zprávu třeba ve streamu, prostě jen přestanou proudit data. Pokud čte libinput debug globální vstup, je ve streamu jak zpráva o odebrání zařízení, tak po opětovném připojení se se zprávou o přidání zařízení vrátí i data. Vzhledem k tomu, že na mém systému nepotřebuji filtrovat konkrétně tuto myš, je pro mě výhodnější použít globální stream.

Zde je ještě jedna důležitá věc a to použití stdbuf, jenž umožňuje změnit vlastnosti bufferování výstupu. Pokud totiž výstup nejde přímo do terminálu, bufferuje se a posílá dál po dávkách, takže by nastávalo zpoždění a při nízké aktivitě značné. Takto funguje v shellu skoro všechno, již jsem tu o tom psal.

Další problém, který je vidět v ukázce výstupu předchozího příkazu, je již zmíněná absence jména přiřazeného ke key_code jednoho mého tlačítka, takže nemohu filtrovat podle jmen bez nějakého předchozího přemapování. Vzhledem k tomu, že další popisky extra tlačítek nesedí, ačkoliv fungují správně, nemá význam se snažit to nějak opravovat. Napsal jsem si seznam kódů potřebných tlačítek a filtruji je podle nich.

Simulace stisku kláves

Posílání stisku kláves pomocí evemu může vypadat takto:

$ sudo evemu-event /dev/input/event2 --sync --type EV_KEY --code KEY_L --value 1

Než to spustíte pozor - je to stisk klávesy, ale ne její uvolnění, takže to funguje stejně, jako byste tu klávesu drželi. evemu umožňuje vytvořit si vlastní virtuální zařízení, nebo využít nějaké existující, jako v tomto příkladu, kdy využívám klávesnici na event2. --type určuje, že se bude jednat o klávesu, --code jakou klávesu budeme posílat a --value zda půjde o stisk (1), nebo uvolnění (0).

Evemu umí události i logovat a následně přehrávat, takže si můžete zaznamenat nějakou aktivitu vstupů a později ji replikovat.

Má verze mousemapper.sh

#!/bin/bash
 
keyboard="/dev/input/$(sed -rn '/Handlers=.*kbd.+leds/s/.*(event[0-9]).*/\1/p' /proc/bus/input/devices)"
# leds handler indikuje, že jde o klasickou klávesnici s diodami pro numlock atd.
if [[ ! -r $keyboard ]]
    then echo "Error: no permissions to read input, or keyboard detected. Exitting..."; exit 1
fi
event_type=EV_KEY
action_type=POINTER_BUTTON
pressed="pressed,"
 
# Kódy tlačítek Logitech Performance MX
# Thumb btn TASK - 277
# Thumb btn ZOOM - 280
# BACK           - 275
# FORWARD        - 276
# MIDDLE         - 274
# Wheel LEFT     - neprodukuje stisky tlačítek
# Wheel RIGHT    - neprodukuje stisky tlačítek

# COMMANDS MAP -  tlačítka, která se mají mapovat a na co
# formát BTN_<key_code>=(<sekvence key_codes tlačítek buď jako čísla, nebo jejich jména)
#BTN_277=(KEY_LEFTMETA KEY_S)
BTN_280=(KEY_LEFTCTRL KEY_TAB)
 
function pressKey(){
    key=$1; value=$2
    #echo "pressing ${key} ${value}"
    evemu-event ${keyboard} --sync --type ${event_type} --code ${key} --value ${value};
}
 
function pressCommand(){
    button=$1; movement=$2
    var=$button[@]
    command=${!var} # ! nahradí jméno proměnné obsahem té proměnné a tu bash následně expanduje jako běžnou proměnnou.
                    # V tomto případě přijde do var např BTN_277 a po expanzi s ! se změní na $BTN_277, což je proměnná, která obsahuje stisky kláves přiřazené výše k tomuto tlačítku, a ta přijde do $command
 
    if [ ${movement} = ${pressed} ]; then
        for key in ${command}; do
            pressKey ${key} 1
        done
    else
        for key in ${command}; do
            pressKey ${key} 0
        done
    fi
}
 
function parseEventLine(){
    button=BTN_$1   # protože nesedí jména tlačítek a jedno nemá označení žádné, používám číselné kódy, které zbavuji závorek
    movement=$2     # pressed/released
 
    pressCommand ${button} ${movement}
}
 
while read line; do
    grep -q $action_type <<< "$line" && \
    parseEventLine $(awk '{gsub (/\(|\)/, "", $5); print $5, " ", $6}' <<< "$line")
done < <(stdbuf -oL libinput debug-events || exit 1 &) #--device ${device} & )   # bez určení konkrétního vstupu nehraje roli odpojení a připojení myši na usb port, při určení konkrétního vstupu se proud přeruší, i když se myš namapuje na stejnou cestu a přitom to nevyhodí žádnou chybu.
    # využívá se debug streamu z libinput a rovnou se filtrují podle $action_type stisky tlačítek
    # stdbuf se stará o to, aby z libinput padaly jednotlivé řádky okamžitě, jinak by to lezlo po větších blocích, po naplnění výstupního bufferu
  
wait

Skript musí běžet pod rootem, nebo lépe pod uživatelem patřícím do skupiny input, bez dalších speciálních práv. Můžete si podle vzoru na GitHubu projektu wayland-mouse-mapper vytvořit ze skriptu službu, která se bude spouštět automaticky po startu a bude ovladatelná pomocí systemctl příkazů.

 

Závěrem

Má pro mě vlastně vůbec smysl používat Wayland a snášet ta omezení? Z praktického hlediska a na domácím počítači na interní síti mě nic nenapadá, ale ze studijních důvodů byl ten výlet zajímavý a nakonec výsledek mapování tlačítek je použitelný nejen pod Wayland session, ale i pod X11, tudíž si to mohu sjednotit.

Na druhou stranu jsem si s Waylandem zatím nevšiml nějakých bugů, i Firefox se choval normálně. Pouze Dock se mi při některých konfiguracích rozšíření zdvojoval v overlay náhledu a velmi pomalu po přihlášení do systému nabíhal, byl do té doby prázdný.


Žádné komentáře:

Okomentovat

Zkuste prosím při komentováni používat místo volby Anonymní volbu Název/adresa URL, kde vyplníte nějakou přezdívku, adresu zadávat nemusíte. Vědět, které příspěvky jsou od jednoho člověka, je fajn. Díky.

Pokud by se vám náhodou odeslaný komentář na stránce nezobrazil, vytáhnu ho z koše hned jak si toho všimnu. I Google spam filter se občas sekne.