Xswitcher-asettelukorjaus linuxille: vaihe kaksi

Kuin edellinen julkaisu (xswitcher konseptitodistusvaiheessa) sai paljon rakentavaa palautetta (mikä on mukavaa)Jatkoin vapaa-aikani käyttämistä projektin kehittämiseen. Nyt haluan käyttää vähän sinun... Toinen vaihe on hieman epätavallinen: kokoonpanosuunnittelun ehdottaminen/keskustelu.

Xswitcher-asettelukorjaus linuxille: vaihe kaksi

Jostain syystä tavallisten ohjelmoijien on uskomattoman tylsää säätää kaikkia näitä nuppeja.

Välttääkseni olemasta perusteeton, tässä on esimerkki siitä, minkä kanssa olen tekemisissä.
Apache Kafka ja ZooKeeper ovat yleisesti ottaen hyvin suunniteltuja (ja hyvin toteutettuja).
— Konfiguraatio? Mutta se on tylsää! Vain huolimatonta XML:ää (koska se on "valmis").
– Ai niin, ja haluatko myös eturistisiteen? Mutta se on niin hankalaa! Läimäytys... Jotain sinne päin.

Ja minun työssäni se on täysin päinvastoin. Aivan oikein. (valitettavasti se ei melkein koskaan tapahdu ensimmäisellä kerralla) rakennettu malli mahdollistaa entistä helpomman ja rennomman (no, melkein) kokoa piiri.

Törmäsin hiljattain Habr-sivustolla artikkeliin datatieteilijöiden vaikeasta työstä…
Kävi ilmi, että he toteuttavat tätä aspektia täysimääräisesti. Kokemukseni mukaan se on, kuten sanotaan, "kevyt versio". Monivolyymiset mallit, kokeneet ohjelmoijat valmiina OOP:iin ja niin edelleen – kaikki tämä tulee myöhemmin, jos/kun se lähtee lentoon. Mutta suunnittelijan on aloitettava jostain juuri tästä ja nyt.

Mennäänpä asiaan. Käytin TOML:ää syntaktisena perustana. tältä kansalaiselta.

Koska hän on (TOML) Toisaalta se on ihmisen muokattavissa. Toisaalta se kääntää sen 1:1 mille tahansa yleisimmistä syntakseista: XML, JSON, YAML.
Lisäksi käyttämäni toteutus sivustolta “github.com/BurntSushi/toml”, vaikkakaan ei kaikkein muodikkain (käyttää edelleen 1.4-syntaksia), on syntaktisesti yhteensopiva saman (“sisäänrakennetun”) JSON:in kanssa.

Eli jos haluat, voit yksinkertaisesti sanoa "painu helvettiin TOML:si kanssa, haluan XXX" ja "korjata" koodin yhdellä rivillä.

Jos siis haluat kirjoittaa ikkunoita xswitcherin konfiguroimiseksi (en todellakaan minä) "tämän pirun kokoonpanosi" kanssa ei odoteta olevan ongelmia.

Kaikkien muiden syntaksi perustuu "avain = arvo". (ja kirjaimellisesti pari monimutkaisempaa vaihtoehtoa, kuten = [jotkut, taulukko]) Oletan
intuitiivisesti kätevä.
Mielenkiintoista on, että hän itse "palanut" Suunnilleen samaan aikaan (noin vuonna 2013). Toisin kuin minä, TOML:n kirjoittaja lähestyi asiaa asianmukaisella laajuudella.

Siksi minun on nyt helpompi räätälöidä sen toteutus itselleni sopivaksi kuin toisinpäin.

Pohjimmiltaan otamme TOML:n (hyvin samankaltainen kuin vanha Windows INI). Ja luomme konfiguraation, jossa kuvaamme, kuinka liitetään sarja hookkeja viimeisimpien näppäimistöltä syötettyjen skannauskoodien perusteella. Alla on palasina tähänastiset tiedot. Ja selitys sille, miksi päädyin tähän mennessä.

0. Perusabstraktiot

  • Skannauskoodien nimitykset. Tälle asialle on ehdottomasti tehtävä jotain, sillä pelkät digitaaliset koodit ovat täysin lukukelvottomia (olen vain sarkastinen). loloswitcher).
    Poimin "ecodes.go"-tiedoston "golang-evdev"-tiedostosta (olin liian laiska perehtymään lähdekoodiin, vaikka kirjoittaja kohteliaasti viittasikin siihen). Korjasin myös hieman (toistaiseksi) jotakin täysin rumaa. Kuten "LEFTBRACE" → "L_BRACE".
  • Esittelin myös "tilallisten avainten" käsitteen, koska käytetty tavallinen kielioppi ei sovellu pitkien kappaleiden kirjoittamiseen. (Mutta se antaa sinun tarkistaa mahdollisimman vähäisin häiriöin, jos käytät vain "suoraa" tallennusta.)
  • Painettuun näppäimeen on sisäänrakennettu "deduplikaattori". Näin ollen "repeat"=2 -tila tallennetaan. yksi aikaa.

1. Mallit-osio

[Templates] # "@name@" to simplify expressions
 # Words can consist of these chars (regex)
 "WORD" = "([0-9A-Z`;']|[LR]_BRACE|COMMA|DOT|SLASH|KP[0-9])"

Mistä ihmiskielen sana koostuu foneettisesti merkityssä muodossa? (grafeemit eli hieroglyfit ovat eri asia)Mikä kamala "taulukko". Joten esittelen heti "mallin" käsitteen.

2. Mitä tehdä, kun jotakin painetaan (toinen skannauskoodi vastaanotetaan)

[ActionKeys]
 # Collect key and do the test for command sequence
 # !!! Repeat codes (code=2) must be collected once per key!
 Add = ["1..0", "=", "BS", "Q..]", "L_CTRL..CAPS", "N_LOCK", "S_LOCK",
        "KP7..KPDOT", "R_CTRL", "KPSLASH", "R_ALT", "KPEQUAL..PAUSE",
        "KPCOMMA", "L_META..COMPOSE", "KPLEFTPAREN", "KPRIGHTPAREN"]

 # Drop all collected keys, including this.  This is default action.
 Drop = ["ESC", "-", "TAB", "ENTER", "KPENTER", "LINEFEED..POWER"]
 # Store extra map for these keys, when any is in "down" state.
 # State is checked via "OFF:"|"ON:" conditions in action.
 # (Also, state of these keys must persist between buffer drops.)
 # ??? How to deal with CAPS and "LOCK"-keys ???
 StateKeys = ["L_CTRL", "L_SHIFT", "L_ALT", "L_META", "CAPS", "N_LOCK", "S_LOCK",
              "R_CTRL", "R_SHIFT", "R_ALT", "R_META"]

 # Test only, but don't collect.
 # E.g., I use F12 instead of BREAK on dumb laptops whith shitty keyboards (new ThinkPads)
 Test = ["F1..F10", "ZENKAKUHANKAKU", "102ND", "F11", "F12",
          "RO..KPJPCOMMA", "SYSRQ", "SCALE", "HANGEUL..YEN",
          "STOP..SCROLLDOWN", "NEW..MAX"]

Koodeja on yhteensä 768. (Mutta "varmuuden vuoksi" lisäsin xswitcher-koodiin "yllätyssiepparin".)
Sisällä kuvailin, miten taulukko täytetään viittauksilla "mitä tehdä"-funktioihin. Go:ssa tämä on (yhtäkkiä) Se osoittautui käteväksi ja itsestään selväksi.

  • Aion minimoida tämän alueen "pudotuksen" joustavamman käsittelyn hyväksi (näytän sen alla).

3. Ikkunaluokkakilpi

# Some behaviour can depend on application currently doing the input.
[[WindowClasses]]
 # VNC, VirtualBox, qemu etc. emulates there input independently, so never intercept.
 # With the exception of some stupid VNC clients, which does high-level (layout-based) keyboard input.
 Regex = "^VirtualBox"
 Actions = "" # Do nothing while focus stays in VirtualBox

[[WindowClasses]]
 Regex = "^konsole"
 # In general, mouse clicks leads to unpredictable (at the low-level where xswitcher resides) cursor jumps.
 # So, it's good choise to drop all buffers after click.
 # But some windows, e.g. terminals, can stay out of this problem.
 MouseClickDrops = 0
 Actions = "Actions"

[[WindowClasses]] # Default behaviour: no Regex (or wildcard like ".")
 MouseClickDrops = 1
 Actions = "Actions"

Taulukon rivit ovat hakasulkeissa sen nimen kanssa. Ei se voisi heti olla yksinkertaisempaa. Aktiivisen ikkunan mukaan voit valita asetuksia:

  • Mukautettu pikanäppäinsarja "Toiminnot = ...". Jos ei mitään/tyhjä, ei tehdä mitään.
  • "MouseClickDrops"-kytkin – mitä tehdä, kun hiiren napsautus havaitaan. Koska xswitcherin käyttöönottopiste ei määritä mitään tiettyjä napsautussijainteja, oletusarvoinen toimintatapa on puskurin tyhjentäminen. Esimerkiksi päätteissä tämä ei kuitenkaan ole välttämätöntä. (yleensä).

4. Yksi (tai useampi) klikkaussarja laukaisee tietyn koukun

# action = [ regex1, regex2, ... ]
# "CLEAN" state: all keys are released
[Actions]
# Inverse regex is hard to understand, so extract negation to external condition.
# Expresions will be checked in direct order, one-by-one. Condition succceds when ALL results are True.
 # Maximum key sequence length, extra keys will be dropped. More length - more CPU.
 SeqLength = 8
 # Drop word buffer and start collecting new one
 NewWord = [ "OFF:(CTRL|ALT|META)  SEQ:(((BACK)?SPACE|[LR]_SHIFT):[01],)*(@WORD@:1)", # "@WORD@:0" then collects the char
             "SEQ:(@WORD@:2,@WORD@:0)", # Drop repeated char at all: unlikely it needs correction
             "SEQ:((KP)?MINUS|(KP)?ENTER|ESC|TAB)" ] # Be more flexible: chars line "-" can start new word, but must not completelly invalidate buffer!
 # Drop all buffers
 NewSentence = [ "SEQ:(ENTER:0)" ]

 # Single char must be deleted by single BS, so there is need in compose sequence detector.
 Compose = [ "OFF:(CTRL|L_ALT|META|SHIFT)  SEQ:(R_ALT:1,(R_ALT:2,)?(,@WORD@:1,@WORD@:0){2},R_ALT:0)" ]

 "Action.RetypeWord" = [ "OFF:(CTRL|ALT|META|SHIFT)  SEQ:(PAUSE:0)" ]
 "Action.CyclicSwitch" = [ "OFF:(R_CTRL|ALT|META|SHIFT)  SEQ:(L_CTRL:1,L_CTRL:0)" ] # Single short LEFT CONTROL
 "Action.Respawn" = [ "OFF:(CTRL|ALT|META|SHIFT)  SEQ:(S_LOCK:2,S_LOCK:0)" ] # Long-pressed SCROLL LOCK

 "Action.Layout0" = [ "OFF:(CTRL|ALT|META|R_SHIFT)  SEQ:(L_SHIFT:1,L_SHIFT:0)" ] # Single short LEFT SHIFT
 "Action.Layout1" = [ "OFF:(CTRL|ALT|META|L_SHIFT)  SEQ:(R_SHIFT:1,R_SHIFT:0)" ] # Single short RIGHT SHIFT

 "Action.Hook1" = [ "OFF:(CTRL|R_ALT|META|SHIFT)  SEQ:(L_ALT:1,L_ALT:0)" ]

Jaoin koukut kahteen tyyppiin: sisäänrakennettuihin koukkuihin, joilla on itsestään selittävät nimet (NewWord, NewSentence, Compose), ja ohjelmoitaviin koukkuihin.

Ohjelmoitavat nimet alkavat sanalla "Toiminto". TOML v1.4:stä lähtien pisteelliset nimet on kirjoitettava lainausmerkkeihin.

Jokaisen osion alla tulisi olla kuvaus samalla nimellä.

Jotta ihmiset eivät hämmästyisi "alastomat" vakioasiakkaat (kokemuksesta he kirjoittaa- ehkä yksi kymmenestä ammattilaisille), toteutan välittömästi lisäsyntaksin.

  • "POIS:" (tai "PÄÄLLÄ:") ennen regexpia (säännöllistä lauseketta) vaaditaan seuraavien painikkeiden vapauttamista (tai painamista).
    Seuraavaksi aion luoda "epärehellisen" säännöllisen lausekkeen. Tarkistuksilla erillisillä osioilla "|"-pystyviivojen välissä. Tämä vähentää "[LR]_SHIFT"-merkintöjen määrää (joissa ne ovat selvästi tarpeettomia).
  • "SARJANUMERO:" Jos edellinen ehto täyttyy (tai puuttuu), tarkistamme sen seuraavaksi "säännöllistä" säännöllistä lauseketta vasten. Lisätietoja saat suoraan "regexp"-kirjastosta. Koska en ole vieläkään vaivautunut selvittämään yhteensopivuusastetta suosikki-pcreni ("perl-yhteensopiva") kanssa.
  • Lauseke kirjoitetaan muodossa "PAINIKE_1: KOODI1, PAINIKE_2: KOODI2" jne., siinä järjestyksessä kuin skannauskoodit vastaanotetaan.
  • Tarkistus "painataan" aina sekvenssin loppuun, joten häntään ei tarvitse lisätä merkkiä "$".
  • Kaikki yhden rivin tarkistukset suoritetaan peräkkäin ja yhdistetään käyttämällä "JA"-operaattoria. Mutta koska arvo on kuvattu taulukkona, pilkun jälkeen voidaan kirjoittaa vaihtoehtoinen tarkistus. Jos se on jostain syystä välttämätöntä.
  • Arvo "SarjanPituus = 8" rajoittaa puskurin kokoa, jota vasten kaikki tarkistukset suoritetaan. Koska elämässäni (tähän mennessä) en ole koskaan kohdannut loputtomia resursseja.

5. Edellisessä osiossa kuvattujen koukkujen asettaminen

# Action is the array, so actions could be chained (m.b., infinitely... Have I to check this?).
# For each action type, extra named parameters could be collected. Invalid parameters will be ignored(?).
[Action.RetypeWord] # Switch layout, drop last word and type it again
 Action = [ "Action.CyclicSwitch", "RetypeWord" ] # Call Switch() between layouts tuned below, then RetypeWord()

[Action.CyclicSwitch] # Cyclic layout switching
 Action = [ "Switch" ] # Internal layout switcher func
 Layouts = [0, 1]

[Action.Layout0] # Direct layout selection
 Action = [ "Layout" ] # Internal layout selection func
 Layout = 0

[Action.Layout1] # Direct layout selection
 Action = [ "Layout" ] # Internal layout selection func
 Layout = 1

[Action.Respawn] # Completely respawn xswitcher. Reload config as well
 Action = [ "Respawn" ]

[Action.Hook1] # Run external commands
  Action = [ "Exec" ]
  Exec = "/path/to/exec -a -b --key_x"
  Wait = 1
  SendBuffer = "Word" # External hook can process collected buffer by it's own means.

Tärkeintä tässä on - "Toiminto = [Matriisi]"Kuten edellisessä osiossa, sisäänrakennettuja toimintoja on rajoitettu määrä. Ja telakointimahdollisuudet ovat käytännössä rajattomat. (kirjoita "Action.XXX" äläkä ole laiska ja kirjoita sille oma osio).
Erityisesti sanan uudelleenkirjoittaminen korjatussa asettelussa on jaettu kahteen osaan: "Muuta näppäimistöasettelu tuolla määritetyn mukaisesti." и ”kirjoita uudelleen” (”Tyypitä uudelleenSana”).

Loput parametrit kirjoitetaan "sanakirjaan" (kartta golangiksi) Tietyn toiminnon osalta niiden luettelo riippuu siitä, mitä kohdassa ”Toiminto” on kirjoitettu.

Useita eri toimintoja voidaan kuvata yhdessä keossa (osiot)Tai voit purkaa sen osiin. Kuten yllä näytin.

Asetin heti "Exec"-toiminnon suorittamaan ulkoisen skriptin. Mahdollisuudella siirtää tallennettu puskuri sen stdin-muistiin.

  • "Odota = 1" - odota, kunnes käynnissä oleva prosessi on valmis.
  • Todennäköisesti haluat myös lisätä ympäristöön joitakin lisätietoja, kuten sen ikkunan luokan nimen, josta se siepattiin.
    "Haluatko liittää prosessorisi? Löydät sen täältä."

Huh (uloshengitettyään). Näyttää siltä, ​​etten unohtanut mitään.

Hupsista! Ahaa, en unohtanut...
Missä on käynnistysasetukset? Koodissa? Jotain tällaista:

[ScanDevices]
 # Must exist on start. Self-respawn in case it is younger then 30s
 Test = "/dev/input/event0"
 Respawn = 30
 # Search mask
 Search = "/dev/input/event*"
 # In my thinkPads there are such a pseudo-keyboards whith tons of unnecessary events
 Bypass = "(?i)Video|Camera" # "(?i)" obviously differs from "classic" pcre's.

Missä teit virheen/unohtuiko? (ei ole muuta keinoa)Toivon todella, että tarkkaavaiset lukijat eivät ole liian laiskoja huomauttamaan tästä.

Onnea!

Lähde: will.com

Osta luotettava isännöinti sivustoille, joissa on DDoS-suojaus, VPS VDS -palvelimet 🔥 Osta luotettavaa verkkosivustojen hostingia DDoS-suojauksella, VPS VDS -palvelimilla | ProHoster