Xswitcher skipulagsleiðrétting fyrir Linux: skref tvö

Eins og fyrri útgáfu (xswitcher á „proof of concept“ stigi) fékk töluvert af uppbyggilegum endurgjöfum (sem er fínt), Ég hélt áfram að eyða frítíma mínum í að þróa verkefnið. Nú langar mig að eyða smá af þínum... Annað skrefið verður ekki alveg venjulegt: tillaga/umræða um uppsetningarhönnun.

Xswitcher skipulagsleiðrétting fyrir Linux: skref tvö

Einhvern veginn kemur í ljós að venjulegum forriturum finnst ótrúlega leiðinlegt að setja upp allar þessar stýringar.

Til þess að vera ekki ástæðulaus er inni dæmi um það sem ég er að fást við.
Á heildina litið frábærlega hugsuð (og vel útfærð) Apache Kafka & ZooKeeper.
- Stillingar? En það er leiðinlegt! Heimskulegt xml (vegna þess að það er „út úr kassanum“).
- Ó, viltu líka ACL? En það er svo leiðinlegt! Tap-blooper... Eitthvað svoleiðis.

En í starfi mínu er þetta einmitt hið gagnstæða. Rétt (því miður, næstum aldrei í fyrsta skiptið) smíðaða líkanið gerir þér kleift að halda áfram á auðveldan og eðlilegan hátt (Næstum) setja saman skýringarmynd.

Ég rakst nýlega á grein á Habré um mikla vinnu gagnafræðinga...
Það kemur í ljós að þetta augnablik er að fullu að veruleika fyrir þá. Og í starfi mínu, eins og þeir segja, "létt útgáfa". Módel í mörgum bindum, vanir forritarar með OOP viðbúið o.s.frv. — þetta mun allt birtast síðar þegar/ef það fer í loftið. En hönnuðurinn þarf að byrja einhvers staðar hér og nú.

Komdu þér að efninu. Ég tók TOML sem setningafræðilegan grunn frá þessum borgara.

Vegna þess að hann (TOML) annars vegar breytanlegt af mönnum. Aftur á móti er það þýtt 1:1 í einhverja af algengari setningafræði: XML, JSON, YAML.
Þar að auki er útfærslan sem ég notaði frá „github.com/BurntSushi/toml“, þó hún sé ekki sú smartasta (samt 1.4 setningafræði), setningafræðilega samhæfð við sama („innbyggða“) JSON.

Það er, ef þú vilt geturðu einfaldlega sagt „farðu í gegnum skóginn með þessum TOML þínum, ég vil XXX“ og „plástra“ kóðann með aðeins einni línu.

Svona, ef þú vilt skrifa nokkra glugga til að stilla xswitcher (Ég er ekki viss) Ekki er búist við neinum vandræðum "með þessari helvítis stillingu þinni."

Fyrir alla aðra er setningafræðin byggð á „lykill = gildi“ (og bókstaflega nokkrir flóknari valkostir, eins og = [sumir, það, fylki]) ætli það ekki
innsæi þægilegt.
Það sem er athyglisvert er það "brenndur" um svipað leyti (um 2013). Aðeins, ólíkt mér, fór höfundur TOML inn á viðeigandi mælikvarða.

Þess vegna er nú auðveldara fyrir mig að aðlaga útfærslu þess til að henta mér, en ekki öfugt.

Almennt tökum við TOML (mjög líkt gamla Windows INI). Og við erum með uppsetningu þar sem við lýsum því hvernig á að festa röð af krókum eftir setti nýjustu skannakóða frá lyklaborðinu. Hér að neðan, stykki fyrir stykki, er það sem hefur gerst hingað til. Og skýring á því hvers vegna ég ákvað þetta.

0. Grunnabstraktanir

  • Skannaðu merkingar kóða. Það þarf örugglega að gera eitthvað í þessu, þar sem einfaldlega stafrænir kóðar eru alls ekki læsilegir fyrir mönnum (það er bara ég loloswitcher).
    Ég hristi út „ecodes.go“ úr „golang-evdev“ (ég var of latur til að skoða upprunalegu heimildina, þó höfundurinn hafi gefið það til kynna nokkuð menningarlega). Ég leiðrétti smá (í bili) eitthvað sem var frekar óttalegt. Eins og „LEFTBRACE“ → „L_BRACE“.
  • Að auki kynnti hann hugtakið „ríkislyklar“. Þar sem venjuleg málfræði sem notuð er gerir ekki ráð fyrir löngum köflum. (En það gerir þér kleift að athuga með lágmarks kostnaði. Ef þú notar aðeins „beina“ upptöku.)
  • Það verður innbyggður „afritunarvél“ af því sem ýtt er á. Þannig verður ástandið "endurtaka"=2 skrifað einn sinnum.

1. Sniðmátshluti

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

Hvað samanstendur mannamálsorð með hljóðritun? (annaðhvort spurning um grafemes aka "híróglyphs")? Einhvers konar hræðilegt "blað". Þess vegna kynni ég strax hugtakið „sniðmát“.

2. Hvað á að gera þegar smellt er á eitthvað (annar skannakóði er kominn)

[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"]

Það eru alls 768 kóðar. (En „bara ef ske kynni að“ setti ég grípandi „óvart“ inn í xswitcher kóðann).
Inni lýsti ég því að fylla fylkið með tenglum á aðgerðir „hvað á að gera“. Í golang er þetta (skyndilega) Það reyndist þægilegt og augljóst.

  • Ég ætla að minnka „Drop“ í lágmarki á þessum stað. Í þágu sveigjanlegri vinnslu (ég mun sýna það hér að neðan).

3. Tafla með gluggaflokkum

# 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"

Raðir töflunnar eru í tvöföldum hornklofum með nafni þess. Það hefði ekki getað verið auðveldara strax. Það fer eftir því hvaða glugga er nú virkur, þú getur valið eftirfarandi valkosti:

  • Þitt eigið sett af „hraðlykla“ „Aðgerðir = …“. Ef ekki/tómt, gerðu ekkert.
  • Skiptu um „MouseClickDrops“ - hvað á að gera þegar músarsmellur greinist. Þar sem kveikt er á xswitcher eru engar upplýsingar um „hvar þeir smella,“ endurstillum við sjálfgefið biðminni. En í skautunum (til dæmis) þarftu ekki að gera þetta (venjulega).

4. Ein (eða fleiri) smelliröð kallar á einn eða annan krók

# 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)" ]

Krókar skiptast í tvær tegundir. Innbyggt, með „talandi“ nöfnum (NewWord, NewSentence, Compose) og forritanlegt.

Forritanleg nöfn byrja á „Aðgerð“. Vegna þess að TOML v1.4, nöfn með punktum verða að vera innan gæsalappa.

Lýsa skal hverjum hluta hér að neðan með sama nafni.

Til þess að blása ekki huga fólks með „nöktum“ fastagestur (af reynslu, þeirra að skrifakannski einn af hverjum tíu fagfólk), Ég innleiða strax viðbótar setningafræði.

  • "OFF:" (eða "ON:") áður en regexp (venjuleg tjáning) þarf að sleppa (eða ýta á) eftirfarandi hnappa.
    Næst ætla ég að gera „ósanngjörn“ reglubundna tjáningu. Með sérstakri athugun á bitum á milli röra "|". Til að fækka færslum eins og "[LR]_SHIFT" (þar sem þetta er greinilega ekki nauðsynlegt).
  • "SEQ:" Ef fyrra skilyrðið er uppfyllt (eða fjarverandi), þá tökum við upp á móti „venjulegri“ reglulegri tjáningu. Fyrir frekari upplýsingar sendi ég strax til ^W „regexp“ bókasafnið. Vegna þess að ég hef enn ekki nennt að finna út hversu samhæfni við uppáhalds pcre minn ("perl samhæft").
  • Tjáningin er skrifuð í formi "BUTTON_1: CODE1, BUTTON_2: CODE2" o.s.frv., í þeirri röð sem skannakóðar berast.
  • Ávísunin er alltaf „snugged“ í lok röðarinnar, svo það er engin þörf á að bæta „$“ við skottið.
  • Allar athuganir í einni línu eru framkvæmdar hver á eftir annarri og eru sameinuð með „ég“. En þar sem gildinu er lýst sem fylki geturðu skrifað aðra ávísun á eftir kommu. Ef þess er þörf af einhverjum ástæðum.
  • Gildi "SeqLength = 8" takmarkar stærð biðminni sem allar athuganir eru gerðar á. Vegna þess að Ég hef (þar til núna) aldrei kynnst endalausum úrræðum á ævinni.

5. Stilling krókanna sem lýst er í fyrri hlutanum

# 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.

Aðalatriðið hér er "Aðgerð = [Array]". Svipað og í fyrri hlutanum er takmarkað sett af innbyggðum aðgerðum. Og möguleikinn á bryggju er ekki takmarkaður í grundvallaratriðum (skrifaðu „Action.XXX“ og ekki vera of latur að skrifa annan hluta fyrir það).
Einkum er endurritun orðs í leiðréttu skipulagi skipt í tvo hluta: „breyttu skipulaginu eins og tilgreint er þar“ и „retype“ („RetypeWord“).

Eftirstöðvarnar eru skrifaðar í „orðabókina“ ("kort" í golang) fyrir tiltekna aðgerð fer listi þeirra eftir því sem er skrifað í „Aðgerð“.

Hægt er að lýsa nokkrum mismunandi aðgerðum í einni hrúgu (kaflar). Eða þú getur dregið það í sundur. Eins og ég sýndi hér að ofan.

Ég stillti strax „Exec“ aðgerðina til að keyra ytri handritið. Með möguleika á að ýta skráða biðminni inn í stdin.

  • „Bíddu = 1“ — bíddu eftir að keyrsluferlinu lýkur.
  • Sennilega, „í hauginn“, viltu setja fleiri fólk í umhverfið. upplýsingar eins og nafn gluggaklasans sem það var hlerað úr.
    „Viltu tengja stjórnandann þinn? Þetta er þangað sem þú þarft að fara."

Púff (útöndun). Það virðist sem ég hafi engu gleymt.

Úps! Já, ég gleymdi ekki...
Hvar er ræsingarstillingin? Í hörðum kóða? Svona:

[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.

Hvar gleymdi ég/gerði mistök? (ekkert án þessa), Ég vona svo sannarlega að athugulir lesendur verði ekki of latir við að reka í nefið.

Gangi þér vel!

Heimild: www.habr.com

Bæta við athugasemd