Xswitcher korektè layout pou Linux: etap de

Kòm piblikasyon anvan (xswitcher nan etap "prèv konsèp") te resevwa anpil fidbak konstriktif (ki bèl), Mwen te kontinye pase tan lib mwen devlope pwojè a. Koulye a, mwen vle pase yon ti kras nan ou ... Dezyèm etap la pa pral byen nòmal: pwopozisyon / diskisyon sou konsepsyon konfigirasyon.

Xswitcher korektè layout pou Linux: etap de

Yon jan kanmenm li vire soti ke pwogramasyon nòmal yo jwenn li ekstrèmman raz yo mete kanpe tout kontwòl sa yo.

Pou pa san fondman, anndan se yon egzanp de sa m ap fè fas ak.
An jeneral trè byen vin ansent (ak byen aplike) Apache Kafka & ZooKeeper.
- Konfigirasyon? Men li raz! Xml bèbè (paske li "soti nan bwat la").
- Oh, ou vle tou yon ACL? Men, li tèlman raz! Tap-blooper... Yon bagay konsa.

Men, nan travay mwen se egzakteman opoze a. Dwa (Ay, prèske pa janm premye fwa) modèl la konstwi pèmèt ou kontinye pi fasil ak natirèlman (Prèske) rasanble yon dyagram.

Dènyèman, mwen te rankontre yon atik sou Habré sou travay di syantifik done yo...
Li sanble ke moman sa a konplètman reyalize pou yo. Ak nan pratik mwen an, jan yo di, "vèsyon limyè". Modèl milti-volim, pwogramasyon expérimentés ak OOP nan pare, elatriye. — tout bagay sa yo pral parèt pita lè/si li dekole. Men, designer a bezwen kòmanse yon kote isit la e kounye a.

Ale nan pwen an. Mwen te pran TOML kòm yon baz sentaktik soti nan sitwayen sa a.

Paske li (TOML) sou yon bò, moun-editable. Nan lòt men an, li tradui 1:1 nan nenpòt nan sentaks yo ki pi komen: XML, JSON, YAML.
Anplis, aplikasyon mwen te itilize nan "github.com/BurntSushi/toml", byenke se pa ki pi alamòd (toujou 1.4 sentaks), se sentaktik konpatib ak menm ("bati nan") JSON.

Sa vle di, si ou vle, ou ka tou senpleman di "ale nan Woods yo ak sa a TOML ou a, mwen vle XXX" ak "patch" kòd la ak yon sèl liy.

Kidonk, si ou vle ekri kèk fenèt pou configure xswitcher (Mwen pa sèten) Pa gen pwoblèm yo espere "ak modi sa a konfigirasyon ou."

Pou tout lòt, sentaks la baze sou "kle = valè" (ak literalman yon koup nan opsyon ki pi konplike, tankou = [kèk, sa, etalaj]) Mwen devine
entwitif pratik.
Sa ki enteresan se sa "boule" anviwon menm tan an (anviwon 2013). Se sèlman, kontrèman ak mwen, otè a nan TOML te antre nan yon echèl apwopriye.

Se poutèt sa, kounye a li pi fasil pou mwen ajiste aplikasyon li nan kostim tèt mwen, epi yo pa vis vèrsa.

An jeneral, nou pran TOML (trè menm jan ak ansyen Windows INI). Epi nou gen yon konfigirasyon nan ki nou dekri ki jan yo tache yon seri kwòk depann sou seri a nan dènye kòd eskanè soti nan klavye a. Anba, moso pa moso, se sa ki rive jiskaprezan. Ak yon eksplikasyon sou poukisa mwen deside fason sa a.

0. Abstraksyon debaz yo

  • Eskane deziyasyon kòd. Yon bagay definitivman bezwen fè sou sa a, paske tou senpleman kòd dijital yo absoliman pa moun lizib (sa se jis mwen. loloswitcher).
    Mwen te souke "ecodes.go" soti nan "golang-evdev" (mwen te twò parese gade sous orijinal la, byenke otè a endike li byen kiltirèl). Mwen korije yon ti kras (pou kounye a) yon bagay ki te byen pè. Tankou "LEFTBRACE" → "L_BRACE".
  • Anplis de sa, li te prezante konsèp "kle eta". Piske gramè regilye yo itilize pa pèmèt pasaj long. (Men, li pèmèt ou tcheke avèk minimòm sou tèt yo. Si ou itilize sèlman "dirèk" anrejistreman.)
  • Pral gen yon bati-an "deduplicator" nan sa ki bourade. Kidonk, eta "repete"=2 pral ekri yon sèl fwa.

1. Modèl seksyon

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

Ki sa yon mo lang moun ak notasyon fonetik konpoze? (swa yon kesyon de grafèm aka "jeroglif")? Gen kèk kalite terib "fèy". Se poutèt sa, mwen imedyatman prezante konsèp nan "modèl".

2. Kisa pou w fè lè yo klike sou yon bagay (yon lòt kòd eskanè rive)

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

Gen 768 kòd nan total. (Men, "jis nan ka" mwen mete pwan "supriz" nan kòd la xswitcher).
Anndan mwen te dekri ranpli etalaj la ak lyen ki mennen nan fonksyon "sa pou fè". Nan golang sa a se (toudenkou) Li te tounen pratik ak evidan.

  • Mwen planifye pou redwi "Drop" nan yon minimòm nan kote sa a. An favè pwosesis pi fleksib (mwen pral montre li anba a).

3. Tablo ak klas fenèt yo

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

Ranje yo nan tab la nan parantèz kare doub ak non li yo. Li pa t 'kapab te pi fasil imedyatman nan baton an. Tou depan de fenèt ki aktif kounye a, ou ka chwazi opsyon sa yo:

  • Pwòp seri "kle cho" "Aksyon = ...". Si ou pa / vid, pa fè anyen.
  • Chanje "MouseClickDrops" - sa pou w fè lè yo detekte yon klik sourit. Depi nan pwen kote xswitcher vire sou pa gen okenn detay sou "kote yo klike sou," nou reset tanpon an pa default. Men, nan tèminal (pa egzanp) ou pa oblije fè sa (anjeneral).

4. Youn (oswa plizyè) sekans klik deklanche youn oswa yon lòt zen

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

Kwòk yo divize an de kalite. Entègre, ak non "pale" (NewWord, NewSentence, Compose) ak pwogramasyon.

Non pwogramasyon kòmanse ak "Aksyon". Paske TOML v1.4, non ak pwen yo dwe nan guillemets.

Chak seksyon ta dwe dekri anba a ak menm non an.

Yo nan lòd yo pa soufle lespri moun ak regilye "toutouni" (ki soti nan eksperyans, yo ekripetèt youn sou dis pwofesyonèl), Mwen imedyatman aplike sentaks adisyonèl.

  • "OFF:" (oswa "ON:") anvan regexp (ekspresyon regilye) mande pou bouton sa yo dwe lage (oswa peze).
    Apre sa, mwen pral fè yon ekspresyon regilye "enjis". Avèk tcheke separe nan moso ant tiyo "|". Yo nan lòd yo redwi kantite dosye tankou "[LR]_SHIFT" (kote sa a klèman pa nesesè).
  • "SEQ:" Si kondisyon anvan an satisfè (oswa absan), Lè sa a, nou tcheke kont yon "nòmal" ekspresyon regilye. Pou plis detay, mwen voye imedyatman bay ^W bibliyotèk "regexp". Paske mwen toujou pa te deranje pou chèche konnen degre konpatibilite ak pcre pi renmen mwen ("perl konpatib").
  • Ekspresyon an ekri nan fòm lan "BUTTON_1: CODE1, BUTTON_2: CODE2" elatriye, nan lòd yo resevwa kòd eskanè yo.
  • Chèk la toujou "snugged" nan fen sekans lan, kidonk pa gen okenn nesesite pou ajoute "$" nan ke a.
  • Tout chèk nan yon liy yo fèt youn apre lòt epi yo konbine pa "mwen". Men, depi valè a dekri kòm yon etalaj, ou ka ekri yon chèk altènatif apre vigil la. Si sa nesesè pou kèk rezon.
  • Valè "SeqLength = 8" limite gwosè tanpon an kont tout chèk yo fèt. Paske Mwen te (jiska kounye a) pa janm rankontre resous kontinuèl nan lavi mwen.

5. Mete kwòk ki dekri nan seksyon anvan an

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

Bagay pwensipal lan isit la se "Aksyon = [Array]". Menm jan ak seksyon anvan an, gen yon seri limite nan aksyon entegre. Ak posiblite pou debakadè pa limite nan prensip (ekri "Action.XXX" epi pa twò parese pou w ekri yon lòt seksyon pou li).
An patikilye, retape yon mo nan layout korije a divize an de pati: "chanje layout la jan sa espesifye la" и "Retype" ("RetypeWord").

Paramèt ki rete yo ekri nan "diksyonè" ("kat jeyografik" nan golang) pou yon aksyon bay, lis yo depann de sa ki ekri nan "Aksyon".

Plizyè aksyon diferan ka dekri nan yon sèl pil (seksyon). Oswa ou ka rale li apa. Jan mwen te montre pi wo a.

Mwen imedyatman mete aksyon "Exec" pou egzekite script ekstèn lan. Avèk opsyon pou pouse tanpon ki anrejistre a nan stdin.

  • "Tann = 1" - tann pou pwosesis la kouri fini.
  • Pwobableman, "nan pil la" ou pral vle mete lòt moun nan anviwònman an. enfòmasyon tankou non klas fenèt kote yo te entèsepte l.
    "Èske ou vle konekte moun kap okipe w la? Sa a se kote ou bezwen ale."

Phew (ekspire). Sanble mwen pa bliye anyen.

Oups! Wi, mwen pa bliye...
Ki kote konfigirasyon lansman an ye? Nan kòd difisil? Konsa:

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

Ki kote mwen te bliye/fè yon erè? (pa gen okenn fason san sa a), Mwen reyèlman espere ke lektè atantif pa pral twò parese pou pike nen yo.

Bon chans!

Sous: www.habr.com

Add nouvo kòmantè