Xswitcher layout corrector alang sa Linux: ikaduhang lakang

sukad sa miaging publikasyon (xswitcher sa yugto sa "pamatuod sa konsepto") nakadawat og daghang makaayo nga feedback (nga nindot), nagpadayon ko sa paggahin sa akong libreng panahon sa pagpalambo sa proyekto. Karon gusto kong mogasto og gamay sa imong... Ang ikaduhang lakang dili na kasagaran: proposal/diskusyon sa disenyo sa configuration.

Xswitcher layout corrector alang sa Linux: ikaduhang lakang

Sa usa ka paagi kini nahimo nga ang mga normal nga programmer nakakaplag nga kini dili katuohan nga makalaay sa pag-set up sa tanan niini nga mga kontrol.

Aron dili mahimong walay basehanan, sa sulod mao ang usa ka ehemplo sa unsa ang akong giatubang.
Sa kinatibuk-an maayo kaayo nga gipanamkon (ug maayo nga gipatuman) Apache Kafka & ZooKeeper.
- Pag-configure? Pero boring! Dumb xml (tungod kay "gawas sa kahon").
- Oh, gusto ka ba usab ug ACL? Pero boring kaayo! Tap-blooper... Ingon niana.

Pero sa akong trabaho sukwahi gyud. Husto (alaut, halos dili sa unang higayon) ang gitukod nga modelo nagtugot kanimo sa pagpadayon sa labi ka dali ug natural (Hapit) pagtigom ug diagram.

Bag-o lang akong nakit-an ang usa ka artikulo sa Habré bahin sa kakugi sa mga siyentipiko sa datos...
Kini nahimo nga kini nga higayon hingpit nga naamgohan alang kanila. Ug sa akong praktis, ingon sa ilang giingon, "light version". Multi-volume nga mga modelo, mga batid nga programmer nga adunay OOP nga andam, ug uban pa. — kini tanan makita sa ulahi kung / kung kini mohawa. Apan ang tigdesinyo kinahanglan nga magsugod sa usa ka lugar dinhi ug karon.

Adto sa punto. Gikuha nako ang TOML isip usa ka syntactic nga basehan gikan niini nga lungsoranon.

Kay siya (TOML) sa usa ka bahin, ma-edit sa tawo. Sa laing bahin, gihubad kini nga 1:1 sa bisan unsang mas komon nga mga syntax: XML, JSON, YAML.
Dugang pa, ang pagpatuman nga akong gigamit gikan sa "github.com/BurntSushi/toml", bisan kung dili ang labing uso (sa gihapon 1.4 syntax), syntactically compatible sa parehas nga ("built-in") JSON.

Sa ato pa, kung gusto nimo, mahimo ra nimo isulti nga "pag-agi sa kakahoyan sa imong TOML, gusto ko ang XXX" ug "patch" ang code sa usa lang ka linya.

Sa ingon, kung gusto nimo magsulat pipila ka mga bintana aron ma-configure ang xswitcher (Dili ko sigurado) Wala’y gipaabut nga mga problema "sa imong daotan nga config."

Alang sa uban pa, ang syntax gibase sa "key = value" (ug sa literal usa ka magtiayon nga mas komplikado nga mga kapilian, sama sa = [pipila, kana, laray]) Nagtuo ko
intuitively kombenyente.
Unsa ang makapaikag mao kana "nasunog" sa parehas nga oras (mga 2013). Lamang, dili sama kanako, ang tagsulat sa TOML misulod sa husto nga sukod.

Busa, karon mas sayon ​​alang kanako ang pag-adjust sa pagpatuman niini aron mohaum sa akong kaugalingon, ug dili vice versa.

Sa kinatibuk-an, among gikuha ang TOML (parehas kaayo sa daan nga Windows INI). Ug kami adunay usa ka pagsulud diin among gihulagway kung giunsa ang pag-attach sa usa ka serye sa mga kaw-it depende sa set sa labing bag-ong mga code sa pag-scan gikan sa keyboard. Sa ubos, tipik sa piraso, mao ang nahitabo hangtod karon. Ug usa ka katin-awan kung nganong nakahukom ko niini nga paagi.

0. Panguna nga abstraction

  • Mga ngalan sa scan code. Adunay kinahanglan nga buhaton bahin niini, tungod kay ang yano nga mga digital code dili gyud mabasa sa tawo (ako ra kana loloswitcher).
    Gitangtang nako ang "ecodes.go" gikan sa "golang-evdev" (Tapolan kaayo ko nga tan-awon ang orihinal nga gigikanan, bisan kung gipasabut kini sa tagsulat nga medyo kultural). Gitul-id nako ang gamay (sa pagkakaron) usa ka butang nga makahadlok kaayo. Sama sa "LEFTBRACE" → "L_BRACE".
  • Dugang pa, gipaila niya ang konsepto sa "mga yawe sa estado". Tungod kay ang regular nga gramatika nga gigamit wala magtugot sa taas nga mga tudling. (Apan kini nagtugot kanimo sa pagsusi nga adunay gamay nga overhead. Kung gigamit nimo ang "direkta" nga pagrekord.)
  • Adunay usa ka built-in nga "deduplicator" sa kung unsa ang gipugos. Busa, ang estado nga "repeat"=2 isulat один mga higayon.

1. Seksyon sa templates

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

Unsa ang gilangkuban sa pulong sa tawo nga adunay phonetic notation? (bisan usa ka butang sa graphemes aka "hieroglyphs")? Usa ka matang sa makalilisang nga "panid". Busa, gipaila dayon nako ang konsepto sa "template".

2. Unsa ang buhaton kung adunay usa ka butang nga gi-klik (laing scan code miabut)

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

Adunay 768 ka kodigo sa kinatibuk-an. (Apan "sa kaso lang" gisulod nako ang pagdakop sa "mga surpresa" sa xswitcher code).
Sa sulod akong gihulagway ang pagpuno sa laray sa mga link sa mga gimbuhaton nga "unsay buhaton". Sa golang kini (kalit) Kini nahimo nga sayon ​​​​ug klaro.

  • Nagplano ko nga pakunhuran ang "Drop" sa labing gamay niining lugara. Pabor sa mas flexible nga pagproseso (akong ipakita kini sa ubos).

3. Lamesa nga adunay mga klase sa bintana

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

Ang mga laray sa lamesa naa sa doble nga square bracket nga adunay ngalan niini. Dili kini mahimong mas sayon ​​gikan sa kabog. Depende sa kasamtangan nga aktibo nga bintana, mahimo nimong pilion ang mosunod nga mga kapilian:

  • Ang imong kaugalingon nga set sa "init nga mga yawe" "Mga Aksyon = ...". Kung wala/walay sulod, ayaw pagbuhata.
  • Pagbalhin sa "MouseClickDrops" - kung unsa ang buhaton kung makit-an ang pag-klik sa mouse. Tungod kay sa punto diin ang xswitcher gi-on wala'y mga detalye mahitungod sa "diin sila nag-klik," among gi-reset ang buffer pinaagi sa default. Apan sa mga terminal (pananglitan) dili nimo kinahanglan buhaton kini (kasagaran).

4. Usa (o ubay-ubay) nga mga han-ay sa mga pag-klik ang magpahinabo sa usa o lain nga kaw-it

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

Ang mga kaw-it gibahin sa duha ka matang. Built-in, nga adunay "pagsulti" nga mga ngalan (NewWord, NewSentence, Compose) ug programmable.

Programmable nga mga ngalan nagsugod sa "Aksyon." Kay TOML v1.4, ang mga ngalan nga adunay mga tulbok kinahanglan naa sa mga kinutlo.

Ang matag seksyon kinahanglang ihulagway sa ubos nga adunay parehas nga ngalan.

Aron dili mohuyop sa hunahuna sa mga tawo nga adunay "hubo" nga mga regular (gikan sa kasinatian, ilang sa pagsulattingali usa sa napulo mga propesyonal), Gipatuman dayon nako ang dugang nga syntax.

  • "OFF:" (o "ON:") sa wala pa ang regexp (regular nga ekspresyon) nagkinahanglan nga ang mosunod nga mga buton ipagawas (o i-press).
    Sunod maghimo ako usa ka "dili patas" nga regular nga ekspresyon. Uban sa bulag nga pagsusi sa mga piraso tali sa mga tubo "|". Aron makunhuran ang gidaghanon sa mga rekord sama sa "[LR]_SHIFT" (diin klaro nga dili kini kinahanglan).
  • "SEQ:" Kung ang miaging kondisyon natuman (o wala), nan atong susihon ang usa ka "normal" nga regular nga ekspresyon. Para sa mga detalye, ipadala dayon nako sa ^W ang “regexp” library. Tungod kay wala pa ko maghago sa pagpangita sa lebel sa pagkaangay sa akong paborito nga pcre (“perl compatible”).
  • Ang ekspresyon gisulat sa porma "BUTTON_1: CODE1, BUTTON_2: CODE2" ug uban pa, sa han-ay diin ang mga scan code nadawat.
  • Ang tseke kanunay nga "snugged" sa katapusan sa han-ay, busa dili kinahanglan nga idugang ang "$" sa ikog.
  • Ang tanan nga mga pagsusi sa usa ka linya gihimo sa usag usa ug gihiusa sa "Ako". Apan tungod kay ang kantidad gihulagway nga usa ka laray, mahimo kang magsulat og alternatibong tseke human sa comma. Kung gikinahanglan kini sa pipila ka rason.
  • bili "SeqLength = 8" gilimitahan ang gidak-on sa buffer batok diin ang tanan nga mga pagsusi gihimo. Kay Wala pa ako (hangtod karon) nakasugat og walay katapusan nga mga kapanguhaan sa akong kinabuhi.

5. Pagbutang sa mga kaw-it nga gihulagway sa miaging seksyon

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

Ang nag-unang butang dinhi mao "Aksyon = [Array]". Sama sa miaging seksyon, adunay limitado nga hugpong sa mga built-in nga aksyon. Ug ang posibilidad sa pagdunggo dili limitado sa prinsipyo (isulat ang "Action.XXX" ug ayaw pagtinapulan sa pagsulat og laing seksyon alang niini).
Sa partikular, ang pag-type pag-usab sa usa ka pulong sa gitul-id nga layout gibahin sa duha ka bahin: "bag-o ang layout ingon nga gitakda didto" и “i-type pag-usab” (“RetypeWord”).

Ang nahabilin nga mga parameter gisulat sa "diksyonaryo" ("mapa" sa golang) alang sa gihatag nga aksyon, ang ilang lista nagdepende sa kung unsa ang nahisulat sa "Aksyon".

Daghang lainlaing mga aksyon ang mahulagway sa usa ka tapok (mga seksyon). O mahimo nimo kini ibira. Sama sa akong gipakita sa ibabaw.

Gibutang dayon nako ang aksyon nga "Exec" aron ipatuman ang eksternal nga script. Uban ang kapilian nga iduso ang natala nga buffer sa stdin.

  • "Paghulat = 1" - paghulat sa proseso sa pagdagan aron makompleto.
  • Tingali, "ngadto sa tambak" gusto nimong ibutang ang dugang nga mga tawo sa palibot. impormasyon sama sa ngalan sa klase sa bintana diin kini nasakpan.
    “Gusto ba nimong ikonektar ang imong handler? Dinhi ka kinahanglan moadto."

Phew (giginhawa). Murag wala koy nalimtan.

Oops! Oo nga di ko nakalimutan...
Diin ang paglansad sa pag-configure? Sa lisud nga code? Ingon niana:

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

Asa ko nakalimot/nasayop? (wala’y paagi kung wala kini), Manghinaut gyud ko nga ang mga matinagdanon nga magbabasa dili tapolan sa pagduslak sa ilang mga ilong.

Good luck!

Source: www.habr.com

Idugang sa usa ka comment