Cywirwr cynllun Xswitcher ar gyfer Linux: cam dau

Fel cyhoeddiad blaenorol (xswitcher ar y cam “prawf o gysyniad”) gryn dipyn o adborth adeiladol (sy'n neis), Fe wnes i barhau i dreulio fy amser rhydd yn datblygu'r prosiect. Nawr rydw i eisiau gwario ychydig o'ch... Ni fydd yr ail gam yn hollol arferol: cynnig/trafod dyluniad cyfluniad.

Cywirwr cynllun Xswitcher ar gyfer Linux: cam dau

Rhywsut mae'n troi allan bod rhaglenwyr arferol yn ei chael hi'n hynod ddiflas sefydlu'r holl reolaethau hyn.

Er mwyn peidio â bod yn ddi-sail, mae tu mewn yn enghraifft o'r hyn yr wyf yn delio ag ef.
Ar y cyfan wedi'i gynllunio'n wych (a'i weithredu'n dda) Apache Kafka & ZooKeeper.
- Cyfluniad? Ond mae'n ddiflas! Xml fud (oherwydd ei fod “allan o'r bocs”).
- O, a ydych chi hefyd eisiau ACL? Ond mae mor ddiflas! Tap-blooper... Rhywbeth felly.

Ond yn fy ngwaith mae'n union i'r gwrthwyneb. Iawn (sef, bron byth y tro cyntaf) mae'r model adeiledig yn caniatáu ichi barhau ymhellach yn rhwydd ac yn naturiol (bron) cydosod diagram.

Yn ddiweddar, deuthum ar draws erthygl ar Habré am waith caled gwyddonwyr data...
Mae'n ymddangos bod y foment hon yn cael ei gwireddu'n llawn ar eu cyfer. Ac yn fy arfer, fel maen nhw'n dweud, “fersiwn ysgafn”. Modelau aml-gyfrol, rhaglenwyr profiadol gydag OOP yn barod, ac ati. — bydd hyn i gyd yn ymddangos yn ddiweddarach pan/os bydd yn dechrau. Ond mae angen i'r dylunydd ddechrau rhywle yma ac yn awr.

Cyrraedd y pwynt. Cymerais TOML fel sail gystrawen oddi wrth y dinesydd hwn.

Oherwydd ei fod (TOML) ar y naill law, dynol-olygadwy. Ar y llaw arall, mae'n cael ei gyfieithu 1:1 i unrhyw un o'r cystrawennau mwy cyffredin: XML, JSON, YAML.
Ar ben hynny, mae'r gweithrediad a ddefnyddiais o “github.com/BurntSushi/toml”, er nad yw'r gystrawen fwyaf ffasiynol (1.4 cystrawen o hyd), yn gydnaws yn gystrawen â'r un peth (“built-in”) JSON.

Hynny yw, os dymunwch, gallwch chi ddweud yn syml “ewch trwy'r coed gyda'r TOML hwnnw ohonoch chi, rydw i eisiau XXX” a “chlytia” y cod gydag un llinell yn unig.

Felly, os ydych chi am ysgrifennu rhai ffenestri i ffurfweddu xswitcher (Dydw i ddim yn siŵr) Ni ddisgwylir unrhyw broblemau “gyda'r cyfluniad damn hwn o'ch un chi.”

Ar gyfer pob un arall, mae'r gystrawen yn seiliedig ar “allwedd = gwerth” (ac yn llythrennol cwpl o opsiynau mwy cymhleth, fel = [rhai, hynny, amrywiaeth]) Dyfalaf
yn reddfol gyfleus.
Yr hyn sy'n ddiddorol yw hynny "llosgi" tua'r un amser (tua 2013). Dim ond, yn wahanol i mi, awdur TOML aeth i mewn ar raddfa iawn.

Felly, nawr mae'n haws i mi addasu ei weithrediad i weddu i mi fy hun, ac nid i'r gwrthwyneb.

Yn gyffredinol, rydym yn cymryd TOML (tebyg iawn i'r hen Windows INI). Ac mae gennym ni gyfluniad lle rydyn ni'n disgrifio sut i atodi cyfres o fachau yn dibynnu ar set y codau sgan diweddaraf o'r bysellfwrdd. Isod, fesul darn, mae'r hyn sydd wedi digwydd hyd yn hyn. Ac esboniad pam y penderfynais fel hyn.

0. Tyniadau sylfaenol

  • Sganio dynodiadau cod. Yn bendant mae angen gwneud rhywbeth am hyn, oherwydd yn syml iawn nid yw codau digidol yn ddarllenadwy gan bobl (dim ond fi yw hynny loloswitcher).
    Ysgwydais “ecodes.go” o “golang-evdev” (roeddwn yn rhy ddiog i edrych ar y ffynhonnell wreiddiol, er bod yr awdur wedi nodi hynny yn eithaf diwylliannol). Cywirais ychydig (am y tro) rhywbeth a oedd yn eithaf ofnus. Fel “LEFTBRACE” → “L_BRACE”.
  • Yn ogystal, cyflwynodd y cysyniad o “allweddi cyflwr”. Gan nad yw'r gramadeg rheolaidd a ddefnyddir yn caniatáu ar gyfer darnau hir. (Ond mae'n caniatáu ichi wirio gydag ychydig iawn o orbenion. Os ydych chi'n defnyddio recordiad “uniongyrchol” yn unig.)
  • Bydd “dad-ddyblygwr” adeiledig o'r hyn sy'n cael ei wasgu. Felly, bydd y cyflwr "ailadrodd" = 2 yn cael ei ysgrifennu 1 amser

1. Templedi adran

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

Beth mae gair iaith ddynol gyda nodiant ffonetig yn ei gynnwys? (naill ai mater o graffemau neu “hieroglyffau”)? Rhyw fath o “daflen” ofnadwy. Felly, rwy'n cyflwyno'r cysyniad o “templed” ar unwaith.

2. Beth i'w wneud pan fydd rhywbeth yn cael ei glicio (cod sgan arall wedi cyrraedd)

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

Mae cyfanswm o 768 o godau. (Ond “rhag ofn” fe wnes i fewnosod dal “syrpreis” yn y cod xswitcher).
Y tu mewn disgrifiais lenwi'r arae gyda dolenni i swyddogaethau “beth i'w wneud”. Yn golang mae hyn (yn sydyn) Trodd allan i fod yn gyfleus ac yn amlwg.

  • Rwy'n bwriadu lleihau “Gollwng” i'r lleiafswm yn y lle hwn. O blaid prosesu mwy hyblyg (byddaf yn ei ddangos isod).

3. Tabl gyda dosbarthiadau ffenestr

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

Mae rhesi'r tabl mewn cromfachau sgwâr dwbl gyda'i enw. Ni allai fod wedi bod yn haws yn syth o'r bat. Yn dibynnu ar y ffenestr sy'n weithredol ar hyn o bryd, gallwch ddewis yr opsiynau canlynol:

  • Eich set eich hun o “allweddi poeth” “Camau Gweithredu = …”. Os nad yw/yn wag, peidiwch â gwneud dim.
  • Newid "MouseClickDrops" - beth i'w wneud pan ganfyddir clic llygoden. Gan ar y pwynt lle mae xswitcher yn cael ei droi ymlaen nid oes unrhyw fanylion am “ble maen nhw'n clicio,” rydyn ni'n ailosod y byffer yn ddiofyn. Ond mewn terfynellau (er enghraifft) nid oes rhaid i chi wneud hyn (fel arfer).

4. Mae un (neu sawl) dilyniant o gliciau yn sbarduno un bachyn neu'r llall

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

Rhennir bachau yn ddau fath. Yn gynwysedig, gydag enwau “siarad” (NewWord, NewSentence, Compose) ac yn rhaglenadwy.

Mae enwau rhaglenadwy yn dechrau gyda “Gweithredu.” Achos TOML v1.4, rhaid i enwau gyda dotiau fod mewn dyfyniadau.

Dylid disgrifio pob adran isod gyda'r un enw.

Er mwyn peidio â chwythu meddyliau pobl â rheoleiddwyr “noeth” (o brofiad, eu i ysgrifennuefallai un o bob deg gweithwyr proffesiynol), Rwy'n gweithredu cystrawen ychwanegol ar unwaith.

  • "I FFWRDD:" (neu "YMLAEN:") cyn i regexp (mynegiant rheolaidd) fynnu bod y botymau canlynol yn cael eu rhyddhau (neu eu pwyso).
    Nesaf rydw i'n mynd i wneud mynegiant rheolaidd “annheg”. Gyda gwirio darnau ar wahân rhwng pibellau "|". Er mwyn lleihau nifer y cofnodion fel "[LR]_SHIFT" (lle mae'n amlwg nad yw hyn yn angenrheidiol).
  • "SEQ:" Os yw'r amod blaenorol yn cael ei fodloni (neu'n absennol), yna rydym yn gwirio yn erbyn mynegiant rheolaidd "normal". Am fanylion, byddaf yn anfon y llyfrgell “regexp” at ^W ar unwaith. Oherwydd nid wyf wedi trafferthu o hyd i ddarganfod i ba raddau y maent yn gydnaws â fy hoff pcre (“cydnaws perl”).
  • Mae'r mynegiant wedi'i ysgrifennu yn y ffurf "BUTTON_1: CODE1, BUTTON_2: CODE2" ac ati, yn y drefn y derbynnir y codau sgan.
  • Mae'r siec bob amser yn “snugged” hyd at ddiwedd y dilyniant, felly nid oes angen ychwanegu "$" i'r gynffon.
  • Mae pob gwiriad mewn un llinell yn cael ei berfformio un ar ôl y llall ac yn cael eu cyfuno gan “I”. Ond gan fod y gwerth yn cael ei ddisgrifio fel arae, gallwch chi ysgrifennu siec arall ar ôl y coma. Os oes angen hyn am ryw reswm.
  • Gwerth "SeqLength = 8" cyfyngu ar faint y byffer y cyflawnir yr holl wiriadau yn ei erbyn. Achos Nid wyf (hyd yn hyn) erioed wedi dod ar draws adnoddau diddiwedd yn fy mywyd.

5. Gosod y bachau a ddisgrifir yn yr adran flaenorol

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

Y prif beth yma "Gweithredu = [Array]". Yn debyg i'r adran flaenorol, mae set gyfyngedig o gamau gweithredu adeiledig. Ac nid yw'r posibilrwydd o docio yn gyfyngedig mewn egwyddor (ysgrifennwch “Action.XXX” a pheidiwch â bod yn rhy ddiog i ysgrifennu adran arall ar ei gyfer).
Yn benodol, mae aildeipio gair yn y gosodiad wedi'i gywiro wedi'i rannu'n ddwy ran: “newid y gosodiad fel y nodir yno” и “retype” (“RetypeWord”).

Ysgrifennir y paramedrau sy'n weddill i'r “geiriadur” ("map" yn golang) ar gyfer gweithred benodol, mae eu rhestr yn dibynnu ar yr hyn sydd wedi'i ysgrifennu yn “Gweithredu”.

Gellir disgrifio sawl gweithred wahanol mewn un domen (adrannau). Neu gallwch ei dynnu ar wahân. Fel y dangosais uchod.

Gosodais y weithred “Exec” ar unwaith i weithredu'r sgript allanol. Gyda'r opsiwn i wthio'r byffer a gofnodwyd i mewn i stdin.

  • “Arhoswch = 1” - arhoswch i'r broses redeg gael ei chwblhau.
  • Mae'n debyg, “i'r domen” byddwch chi eisiau rhoi pobl ychwanegol yn yr amgylchedd. gwybodaeth megis enw'r dosbarth ffenestr y cafodd ei rhyng-gipio ohono.
    “Ydych chi am gysylltu eich triniwr? Dyma lle mae angen i chi fynd.”

Phew (exhaled). Mae'n ymddangos nad wyf wedi anghofio unrhyw beth.

Wps! Ie, wnes i ddim anghofio...
Ble mae cyfluniad y lansiad? Mewn cod caled? Fel yna:

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

Ble wnes i anghofio/gwneud camgymeriad? (dim ffordd heb hyn), Dwi wir yn gobeithio na fydd darllenwyr astud yn rhy ddiog i brocio eu trwynau.

Pob lwc!

Ffynhonnell: hab.com

Ychwanegu sylw