Xswitcher-uitlegkorrigeerder vir Linux: stap twee

As vorige publikasie (xswitcher by die bewys van konsep stadium) het nogal baie konstruktiewe terugvoer ontvang (wat lekker is), Ek het voortgegaan om my vrye tyd te spandeer om die projek te ontwikkel. Nou wil ek van jou... Die tweede stap sal nie heeltemal bekend wees nie: voorstel / bespreking van die ontwerp van die konfigurasie.

Xswitcher-uitlegkorrigeerder vir Linux: stap twee

Op een of ander manier blyk dit dat dit baie vervelig is vir normale programmeerders om al hierdie kinkels op te stel.

Om nie ongegrond te wees nie, is binne 'n voorbeeld van waarmee ek te doen het.
Puik algehele ontwerp (en goed geïmplementeer) Apache Kafka & ZooKeeper.
— Konfigurasie? Maar dis vervelig! Tyap-bloop xml (omdat "buite die boks").
- O, wil jy ook ACL hê? Maar dit is so irriterend! Tik-flater ... So iets.

In my werk is dit presies die teenoorgestelde. Reg (ja, die eerste keer amper nooit) die geboude model laat verder maklik en natuurlik toe (Amper) stel die diagram saam.

Ek het onlangs op 'n artikel op Habré afgekom oor die harde werk van data-wetenskaplikes ...
Dit blyk dat hierdie oomblik is hulle ten volle besef. En in my praktyk, soos hulle sê, "ligte weergawe". Multi-volume modelle, gesoute programmeerders met OOP gereed, ens. - dit alles sal later verskyn wanneer / as dit opstyg. En die ontwerper moet hier en nou met iets begin.

Kom by die punt uit. As 'n sintaktiese basis het ek TOML geneem van hierdie burger.

Want hy (TOML) aan die een kant mens-redigeerbaar. Aan die ander kant word dit 1:1 vertaal in enige van die meer algemene sintaksis: XML, JSON, YAML.
Boonop is die implementering wat ek vanaf “github.com/BurntSushi/toml” gebruik het, hoewel nie die modieusste nie (steeds sintaksis 1.4), sintakties versoenbaar met dieselfde (“ingebedde”) JSON.

Dit wil sê, as jy wil, kan jy eenvoudig sê "gaan bos toe met hierdie TOML van jou, ek wil XXX hê" en die kode met net een reël "patch".

Dus, as jy wil, skryf 'n paar vensters om xswitcher op te stel (Ek is nie seker nie) probleme "met jou fokken config" word nie verwag nie.

Vir alle ander is die sintaksis gebaseer op "sleutel = waarde" (en letterlik 'n paar meer ingewikkelde opsies, soos = [een soort skikking]) Ek skat
intuïtief gerieflik.
Vreemd genoeg, by die einste "verbrand" ongeveer dieselfde tyd (ongeveer 2013). Net, anders as ek, het die skrywer van TOML op groot skaal gegaan.

Daarom is dit nou vir my makliker om die implementering daarvan vir myself aan te pas, en nie andersom nie.

Oor die algemeen neem ons TOML (baie soortgelyk aan die ou Windows INI). En ons het 'n konfigurasie waarin ons beskryf hoe om 'n reeks hake aan te heg, afhangende van die stel van die nuutste velkodes vanaf die sleutelbord. Onder in stukke - wat het op die oomblik gebeur. En 'n verduideliking van hoekom ek so besluit het.

0. Basiese abstraksies

  • Skandeer kode-benamings. Iets moet hiermee gedoen word, want net digitale kodes is absoluut nie mensleesbaar nie (dit is ek in die tuin loloswitter).
    Ek het “ecodes.go” uit “golang-evdev” uitgeskud (ek was te lui om na die bron te gaan, alhoewel die skrywer dit nogal kultureel aangedui het). 'n Bietjie (tot dusver) het 'n baie vreesaanjaende een reggestel. Tik "LEFTBRACE" → "L_BRACE".
  • Daarbenewens het hy die konsep van "sleutels met 'n staat" bekendgestel. Aangesien die gereelde grammatika wat gebruik word nie bevorderlik is vir lang gedeeltes nie. (Maar dit laat jou toe om te kyk met minimale oorhoofse koste. As jy net "direkte" opname gebruik.)
  • Daar sal 'n ingeboude "deduplicator" wees van die een wat geklik is. Dus sou die toestand "herhaal"=2 geskryf word 1 tyd.

1. Sjabloon afdeling

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

Waaruit bestaan ​​'n mensetaalwoord met fonetiese notasie? (Is dit 'n kwessie van grafeme aka "hiërogliewe")? Een of ander verskriklike "blad". Daarom lê ek dadelik die konsep van "sjabloon".

2. Wat om te doen wanneer iets geklik word (nog 'n skanderingskode het opgedaag)

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

Daar is altesaam 768 kodes. (Maar "net vir ingeval" het ek vang "verrassings" in die xswitcher-kode ingevoeg).
Binne het ek geverf om die skikking te vul met skakels na die "wat om te doen" funksies. In golang is dit (skielik) blyk gerieflik en voor die hand liggend te wees.

  • "Drop" in hierdie plek wat ek beplan om tot 'n minimum te verminder. Ten gunste van meer buigsame verwerking (ek sal hieronder wys).

3. Tafel met vensterklasse

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

Die rye van die tabel is tussen dubbele vierkantige hakies met sy naam. Dit het nie makliker uitgewerk nie. Afhangende van die huidige aktiewe venster, kan jy opsies kies:

  • Jou eie stel "hot keys" "Actions = ...". Indien nie/leeg nie, doen niks.
  • MouseClickDrops wissel - wat om te doen wanneer 'n muisklik bespeur word. Aangesien die xswitcher-aanskakelpunt geen besonderhede bevat van "waar dit geklik word nie", stel ons die buffer by verstek terug. Maar in terminale (byvoorbeeld) kan jy dit nie doen nie (gewoonlik).

4. Een (of meer) sekwense van kliks veroorsaak een of ander haak

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

Hakies word in twee tipes verdeel. Ingebou, met "pratende" name (NewWord, NewSentence, Compose) en programmeerbaar.

Programmeerbare name begin met "Aksie." Omdat TOML v1.4, name met kolletjies moet tussen aanhalingstekens wees.

Elke afdeling moet hieronder beskryf word. met dieselfde naam.

Om nie mense se breine met “naakte” gereelde seisoene (volgens ondervinding, hul om te skryfmiskien een uit tien professionele persone), implementeer onmiddellik addisionele sintaksis.

  • "AF:" (of "AAN:") voor regexp (gereelde uitdrukking) vereis dat die volgende knoppies vrygelaat (of gedruk word).
    Volgende gaan ek 'n "oneerlike" gereelde uitdrukking maak. Met aparte nagaan van stukke tussen "|" pype. Om die aantal rekords soos "[LR]_SHIFT" te verminder (waar dit duidelik nie nodig is nie).
  • SEQ: As die vorige voorwaarde nagekom word (of afwesig is), dan kyk ons ​​teen die "gewone" gereelde uitdrukking. Vir besonderhede stuur ek dadelik aan ^W na die "regexp" biblioteek. Want hy het nog nie die moeite gedoen om die mate van versoenbaarheid met my gunsteling pcre ("perl compatible") uit te vind nie.
  • Die uitdrukking word geskryf as "BUTTON_1: CODE1, BUTTON_2: CODE2" ens., in die volgorde van ontvangs van die skanderingskodes.
  • Validasie word altyd "gedruk" tot aan die einde van die reeks, so "$" hoef nie by die stert gevoeg te word nie.
  • Alle kontroles in een reël word een na die ander uitgevoer en word gekombineer deur "ek". Maar aangesien die waarde as 'n skikking beskryf word, kan jy 'n alternatiewe tjek na die komma skryf. As dit vir een of ander rede nodig is.
  • Waarde "SeqLength=8" beperk die grootte van die buffer waarteen alle kontroles uitgevoer word. Omdat Ek het nie (tot dusver) oneindige hulpbronne in my lewe gesien nie.

5. Stel die hake wat in die vorige afdeling beskryf is

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

Die belangrikste ding hier is "Aksie = [Array]". Soortgelyk aan die vorige afdeling, is daar 'n beperkte stel ingeboude aksies. En die moontlikheid van dok, wat nie in beginsel beperk is nie (skryf "Action.XXX" en moenie te lui wees om nog 'n afdeling daarvoor te verf nie).
In die besonder word woordtik in die gekorrigeerde uitleg in twee dele verdeel: "Verander die uitleg soos daar gegee" и "retype" ("RetypeWord").

Die oorblywende parameters word na die "woordeboek" geskryf ("kaart" in golang) vir 'n gegewe aksie hang hul lys af van wat in "Aksie" geskryf staan.

Verskeie verskillende aksies kan in een hoop beskryf word (afdelings). En jy kan dit uitmekaar haal. Soos ek hierbo gewys het.

Lê onmiddellik die aksie "Exec" - voer 'n eksterne skrif uit. Met die opsie om die geskrewe buffer in stdin te druk.

  • "Wag = 1" - wag vir die lopende proses om te voltooi.
  • Waarskynlik, "tot die hoop" sal jy bykomende in die omgewing wil plaas. inligting soos die klasnaam van die venster waaruit dit onderskep is.
    “Wil jy jou hanteerder koppel? Hier is jy."

Pff (uitasem). Lyk my ek het niks vergeet nie.

Op! Ja, nie vergeet nie...
Waar is die bekendstellingkonfigurasie? In hardekode? Soos dit:

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

Waar het ek vergeet/gemis? (geen manier daarsonder nie), Ek hoop regtig dat aandagtige lesers nie te lui sal wees om hul neuse in te steek nie.

Sterkte!

Bron: will.com

Voeg 'n opmerking