Xswitcher izkÄrtojuma korektors operÄtÄjsistÄmai Linux: otrais solis
KÄ iepriekÅ”ÄjÄ publikÄcija (xswitcher ākoncepcijas pierÄdÄ«jumaā stadijÄ) saÅÄma diezgan daudz konstruktÄ«vu atsauksmju (kas ir jauki), es turpinÄju pavadÄ«t savu brÄ«vo laiku, izstrÄdÄjot projektu. Tagad es vÄlos pavadÄ«t nedaudz no jÅ«su... Otrais solis nebÅ«s gluži parasts: konfigurÄcijas dizaina priekÅ”likums/diskusija.
Kaut kÄ izrÄdÄs, ka parastiem programmÄtÄjiem ir neticami garlaicÄ«gi iestatÄ«t visas Ŕīs vadÄ«bas ierÄ«ces.
Lai nebÅ«tu nepamatoti, iekÅ”Ä ir piemÄrs tam, ar ko man ir darÄ«Å”ana.
KopumÄ lieliski izstrÄdÄts (un labi Ä«stenots) Apache Kafka & ZooKeeper.
- KonfigurÄcija? Bet tas ir garlaicÄ«gi! MÄms xml (jo tas ir āno kastesā).
- Ak, vai jÅ«s arÄ« vÄlaties ACL? Bet tas ir tik garlaicÄ«gi! Tap-blooper... Kaut kas tamlÄ«dzÄ«gs.
Bet manÄ darbÄ tas ir tieÅ”i otrÄdi. Pa labi (diemžÄl gandrÄ«z nekad pirmo reizi) konstruÄtais modelis ļauj viegli un dabiski turpinÄt tÄlÄk (GandrÄ«z) salikt diagrammu.
Nesen uzgÄju rakstu par HabrÄ par datu zinÄtnieku smago darbu...
IzrÄdÄs, ka viÅiem Å”is brÄ«dis ir pilnÄ«bÄ realizÄts. Un manÄ praksÄ, kÄ saka, āvieglÄ versijaā. VairÄku sÄjumu modeļi, pieredzÄjuÅ”i programmÄtÄji ar gatavu OOP utt. ā tas viss parÄdÄ«sies vÄlÄk, kad/ja tas pacelsies. TaÄu dizainerim jÄsÄk kaut kur Å”eit un tagad.
NonÄc pie lietas. Es ÅÄmu TOML kÄ sintaktisko pamatu no Ŕī pilsoÅa.
TapÄc ka viÅÅ” (TOML) no vienas puses, cilvÄka rediÄ£Äjams. No otras puses, tas tiek tulkots 1:1 jebkurÄ no biežÄk sastopamajÄm sintaksÄm: XML, JSON, YAML.
TurklÄt implementÄcija, ko izmantoju no āgithub.com/BurntSushi/tomlā, lai gan tÄ nav vismodernÄkÄ (joprojÄm 1.4 sintakse), ir sintaktiski saderÄ«ga ar to paÅ”u (āiebÅ«vÄtoā) JSON.
Tas ir, ja vÄlaties, varat vienkÄrÅ”i pateikt "ejiet cauri mežam ar savu TOML, es gribu XXX" un "pielÄgot" kodu tikai ar vienu rindiÅu.
TÄdÄjÄdi, ja vÄlaties rakstÄ«t dažus logus, lai konfigurÄtu xswitcher (ES neesmu pÄrliecinÄts) Nav gaidÄmas nekÄdas problÄmas āar Å”o jÅ«su sasodÄ«to konfigurÄcijuā.
Visiem pÄrÄjiem sintakses pamatÄ ir āatslÄga = vÄrtÄ«baā (un burtiski pÄris sarežģītÄkas opcijas, piemÄram, = [daži, tas, masÄ«vs]) man Ŕķiet intuitÄ«vi Ärti.
Interesanti ir tas "sadedzis" aptuveni tajÄ paÅ”Ä laikÄ (ap 2013. gadu). Tikai atŔķirÄ«bÄ no manis TOML autors iegÄja kÄrtÄ«gÄ mÄrogÄ.
TÄpÄc tagad man ir vieglÄk pielÄgot tÄ ievieÅ”anu sev, nevis otrÄdi.
KopumÄ mÄs Åemam TOML (ļoti lÄ«dzÄ«gs vecajam Windows INI). Un mums ir konfigurÄcija, kurÄ mÄs aprakstÄm, kÄ pievienot virkni ÄÄ·u atkarÄ«bÄ no jaunÄko skenÄÅ”anas kodu kopas no tastatÅ«ras. ZemÄk pa gabalu ir lÄ«dz Å”im notikuÅ”ais. Un paskaidrojums, kÄpÄc es tÄ izlÄmu.
0. Pamata abstrakcijas
SkenÄt kodu apzÄ«mÄjumus. Kaut kas noteikti ir jÄdara lietas labÄ, jo vienkÄrÅ”i digitÄlie kodi absolÅ«ti nav cilvÄkiem lasÄmi (tas esmu tikai es loloswitcher).
Es izkratÄ«ju āecodes.goā no āgolang-evdevā (biju slinks, lai paskatÄ«tos oriÄ£inÄlo avotu, lai gan autors to norÄdÄ«ja diezgan kulturÄli). Es nedaudz izlaboju (pagaidÄm) kaut ko, kas bija diezgan bailÄ«gs. PiemÄram, āLEFTBRACEā ā āL_BRACEā.
TurklÄt viÅÅ” ieviesa jÄdzienu āstÄvokļa atslÄgasā. TÄ kÄ lietotÄ parastÄ gramatika nepieļauj garus fragmentus. (Bet tas ļauj pÄrbaudÄ«t ar minimÄlu pieskaitÄmo izdevumu. Ja izmantojat tikai ātieÅ”oā ierakstÄ«Å”anu.)
BÅ«s iebÅ«vÄts nospiestÄ ādedublikatorsā. TÄdÄjÄdi tiks ierakstÄ«ts stÄvoklis "atkÄrtot"=2 viens reizes.
1. VeidÅu sadaļa
[Templates] # "@name@" to simplify expressions
# Words can consist of these chars (regex)
"WORD" = "([0-9A-Z`;']|[LR]_BRACE|COMMA|DOT|SLASH|KP[0-9])"
No kÄ sastÄv cilvÄku valodas vÄrds ar fonÄtisko apzÄ«mÄjumu? (vai nu jautÄjums par grafÄmÄm jeb "hieroglifiem")? Kaut kÄda briesmÄ«ga "palags". TÄpÄc es nekavÄjoties ievieÅ”u jÄdzienu āveidneā.
2. Ko darÄ«t, ja kaut kas tiek noklikŔķinÄts (ir saÅemts cits skenÄÅ”anas kods)
[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"]
KopÄ ir 768 kodi. (Bet ākatram gadÄ«jumamā xswitcher kodÄ ievietoju āpÄrsteigumuā uztverÅ”anu).
IekÅ”pusÄ es aprakstÄ«ju masÄ«va aizpildÄ«Å”anu ar saitÄm uz funkcijÄm āko darÄ«tā. GolangÄ tas ir (pÄkÅ”Åi) Tas izrÄdÄ«jÄs Ärti un acÄ«mredzami.
Es plÄnoju Å”ajÄ vietÄ samazinÄt āDropā lÄ«dz minimumam. Par labu elastÄ«gÄkai apstrÄdei (to parÄdÄ«Å”u zemÄk).
3. Tabula ar logu klasÄm
# 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"
Tabulas rindas ir dubultÄs kvadrÄtiekavÄs ar tÄs nosaukumu. Tas nevarÄja bÅ«t vieglÄk uzreiz. AtkarÄ«bÄ no paÅ”laik aktÄ«vÄ loga varat atlasÄ«t Å”Ädas opcijas:
PÄrslÄgt āMouseClickDropsā ā ko darÄ«t, ja tiek konstatÄts peles klikŔķis. TÄ kÄ vietÄ, kur ir ieslÄgts xswitcher, nav informÄcijas par to, kur viÅi noklikŔķina, mÄs pÄc noklusÄjuma atiestatÄm buferi. Bet terminÄļos (piemÄram) jums tas nav jÄdara (parasti).
4. Viena (vai vairÄkas) klikŔķu secÄ«bas iedarbina vienu vai otru ÄÄ·i
# 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)" ]
ÄÄ·i ir sadalÄ«ti divos veidos. IebÅ«vÄts, ar "runÄjoÅ”iem" nosaukumiem (NewWord, NewSentence, Compose) un programmÄjams.
ProgrammÄjamie nosaukumi sÄkas ar ādarbÄ«baā. Jo TOML v1.4, nosaukumiem ar punktiem jÄbÅ«t pÄdiÅÄs.
Katra sadaļa ir jÄapraksta tÄlÄk ar tÄdu paÅ”u nosaukumu.
Lai nepÅ«stu cilvÄku prÄtus ar āplikiemā pastÄvÄ«gajiem apmeklÄtÄjiem (pÄc pieredzes, viÅu rakstÄ«tvarbÅ«t viens no desmit profesionÄļiem), es nekavÄjoties ievieÅ”u papildu sintaksi.
"OFF:" (vai "ON:") pirms regexp (regulÄrÄ izteiksme) ir jÄatlaiž (vai jÄnospiež) tÄlÄk norÄdÄ«tÄs pogas.
TÄlÄk es izveidoÅ”u ānetaisnÄ«guā regulÄro izteiksmi. Ar atseviŔķu gabalu pÄrbaudi starp caurulÄm "|". Lai samazinÄtu tÄdu ierakstu skaitu kÄ "[LR]_SHIFT" (kur tas noteikti nav nepiecieÅ”ams).
"SEQ:" Ja iepriekÅ”Äjais nosacÄ«jums ir izpildÄ«ts (vai tÄ nav), mÄs pÄrbaudÄm, vai tiek izmantota ānormÄlaā regulÄra izteiksme. Lai iegÅ«tu sÄ«kÄku informÄciju, es nekavÄjoties nosÅ«tu uz ^W āregexpā bibliotÄku. TÄ kÄ es joprojÄm neesmu pacenties noskaidrot saderÄ«bas pakÄpi ar savu iecienÄ«tÄko pcre (āperl saderÄ«gsā).
Izteiciens ir rakstÄ«ts formÄ "BUTTON_1: CODE1, BUTTON_2: CODE2" utt., secÄ«bÄ, kÄdÄ tiek saÅemti skenÄÅ”anas kodi.
Äeks vienmÄr tiek āpievilktsā lÄ«dz secÄ«bas beigÄm, tÄpÄc astei nav jÄpievieno ā$ā.
Visas pÄrbaudes vienÄ rindÄ tiek veiktas viena pÄc otras un tos apvieno ar āesā. Bet, tÄ kÄ vÄrtÄ«ba ir aprakstÄ«ta kÄ masÄ«vs, aiz komata varat ierakstÄ«t alternatÄ«vu pÄrbaudi. Ja kÄda iemesla dÄļ tas ir nepiecieÅ”ams.
VÄrtÄ«ba "SeqLength = 8" ierobežo bufera lielumu, pret kuru tiek veiktas visas pÄrbaudes. Jo Es (lÄ«dz Å”im) savÄ dzÄ«vÄ neesmu saskÄries ar bezgalÄ«giem resursiem.
# 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.
Galvenais Å”eit ir "DarbÄ«ba = [masÄ«vs]". LÄ«dzÄ«gi kÄ iepriekÅ”ÄjÄ sadaļÄ, ir ierobežots iebÅ«vÄto darbÄ«bu kopums. Un dokstacijas iespÄja principÄ nav ierobežota (rakstiet āAction.XXXā un neesiet pÄrÄk slinks, lai uzrakstÄ«tu tam citu sadaļu).
Jo Ä«paÅ”i vÄrda atkÄrtota ievadÄ«Å”ana labotajÄ izkÄrtojumÄ ir sadalÄ«ta divÄs daļÄs: āmainÄ«t izkÄrtojumu, kÄ norÄdÄ«ts turā Šø āpÄrrakstÄ«tā (āRetypeWordā).
PÄrÄjie parametri tiek ierakstÄ«ti "vÄrdnÄ«cÄ" ("karte" golangÄ) konkrÄtai darbÄ«bai to saraksts ir atkarÄ«gs no tÄ, kas rakstÄ«ts sadaÄ¼Ä āDarbÄ«baā.
VienÄ kaudzÄ var aprakstÄ«t vairÄkas dažÄdas darbÄ«bas (sadaļas). Vai arÄ« varat to izjaukt. KÄ es parÄdÄ«ju iepriekÅ”.
Es nekavÄjoties iestatÄ«ju darbÄ«bu āIzpildÄ«tā, lai izpildÄ«tu ÄrÄjo skriptu. Ar iespÄju nospiest ierakstÄ«to buferi stdin.
āPagaidiet = 1ā ā pagaidiet, lÄ«dz tiek pabeigts darbÄ«bas process.
IespÄjams, ālÄ«dz kaudzeiā gribÄsies ielikt vidÄ papildus cilvÄkus. informÄcija, piemÄram, tÄs loga klases nosaukums, no kuras tas tika pÄrtverts. āVai vÄlaties savienot savu apstrÄdÄtÄju? Å eit jums jÄiet."
Fu (izelpots). Å Ä·iet, ka es neko neesmu aizmirsusi.
Hmm! JÄ, es neaizmirsu...
Kur ir palaiÅ”anas konfigurÄcija? CietajÄ kodÄ? TÄds:
[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.
Kur es aizmirsu/kļūdÄ«jos? (bez Ŕī nekÄdÄ gadÄ«jumÄ), ļoti ceru, ka vÄrÄ«giem lasÄ«tÄjiem nebÅ«s slinkums bÄzt degunu.