Xswitcher layout corrector rau Linux: kauj ruam ob

txij li thaum yav dhau los tshaj tawm (xswitcher ntawm "cov ntaub ntawv pov thawj ntawm lub tswv yim" theem) tau txais cov lus pom zoo heev (uas yog qhov zoo), Kuv txuas ntxiv siv kuv lub sijhawm dawb los tsim qhov project. Tam sim no kuv xav siv me ntsis ntawm koj ... Cov kauj ruam thib ob yuav tsis zoo li ib txwm: daim ntawv thov / kev sib tham txog kev tsim qauv.

Xswitcher layout corrector rau Linux: kauj ruam ob

Yuav ua li cas nws hloov tawm hais tias ib txwm programmers pom nws incredibly tho txawv los teeb tsa tag nrho cov kev tswj.

Txhawm rau kom tsis txhob muaj qhov tsis muaj tseeb, sab hauv yog ib qho piv txwv ntawm qhov kuv tab tom cuam tshuam nrog.
Zuag qhia tag nrho zoo heev xeeb (thiab ua tau zoo) Apache Kafka & ZooKeeper.
- Kev teeb tsa? Tab sis nws yog boring! Dumb xml (vim nws yog "tawm ntawm lub thawv").
- Auj, koj puas xav tau ACL? Tab sis nws dhuav heev! Tap-blooper... Ib yam li ntawd.

Tab sis hauv kuv txoj haujlwm nws yog qhov tsis sib xws. Txoj cai (Alas, yuav luag tsis yog thawj zaug) tus qauv tsim tso cai rau koj mus txuas ntxiv yooj yim thiab ib txwm (Yuav luag) sib sau ua ib daim duab.

Tsis ntev los no kuv tau hla ib tsab xov xwm ntawm Habre hais txog kev ua haujlwm hnyav ntawm cov kws tshawb fawb cov ntaub ntawv ...
Nws hloov tawm hais tias lub sij hawm no yog tag nrho paub rau lawv. Thiab nyob rau hauv kuv xyaum, raws li lawv hais, "light version". Multi-volume qauv, seasoned programmers nrog OOP ntawm npaj txhij, thiab lwm yam. - qhov no yuav tshwm sim tom qab thaum / yog tias nws tawm mus. Tab sis tus tsim qauv yuav tsum pib qhov chaw ntawm no thiab tam sim no.

Tau mus rau qhov taw tes. Kuv coj TOML ua ib lub hauv paus syntactic los ntawm pej xeem no.

Vim nws (TOML) ntawm ib sab, human-editable. Ntawm qhov tod tes, nws tau txhais 1: 1 rau hauv ib qho ntawm ntau cov syntaxes: XML, JSON, YAML.
Ntxiv mus, qhov kev siv kuv siv los ntawm "github.com/BurntSushi/toml", txawm hais tias tsis yog qhov fashionable tshaj plaws (tseem 1.4 syntax), yog syntactically sib xws nrog tib ("built-in") JSON.

Ntawd yog, yog tias koj xav tau, koj tuaj yeem hais yooj yim "mus hla hav zoov nrog TOML ntawm koj li, Kuv xav tau XXX" thiab "patch" cov cai nrog ib kab xwb.

Yog li, yog tias koj xav sau qee qhov rais los teeb tsa xswitcher (Kuv tsis paub meej) Tsis muaj teeb meem xav tau "nrog rau qhov damn config ntawm koj li."

Rau tag nrho lwm tus, cov syntax yog raws li "key = tus nqi" (thiab cia li ob peb qhov kev xaiv nyuaj ntxiv, xws li = [qee, uas, array]) kuv twv
yooj yim intuitively.
Qhov nthuav yog qhov ntawd "hluav taws" nyob rau tib lub sijhawm (kwv yees 2013). Tsuas yog, tsis zoo li kuv, tus sau TOML tau nkag mus rau qhov ntsuas kom raug.

Yog li ntawd, tam sim no nws yooj yim dua rau kuv los kho nws qhov kev siv kom haum rau kuv tus kheej, thiab tsis ua rau lwm tus.

Feem ntau, peb siv TOML (zoo ib yam li Windows INI qub). Thiab peb muaj ib tug configuration nyob rau hauv uas peb piav qhia txog yuav ua li cas muab ib tug series ntawm hooks nyob ntawm seb cov txheej txheem scan codes tshiab los ntawm cov keyboard. Hauv qab no, ib feem ntawm daim, yog dab tsi tau tshwm sim txog tam sim no. Thiab piav qhia tias vim li cas kuv thiaj txiav txim siab li no.

0. Basic abstractions

  • Luam theej duab kos npe. Ib yam dab tsi yuav tsum tau ua tiav txog qhov no, vim tsuas yog cov lej digital tsis yog tib neeg nyeem tau (uas tsuas yog kuv loloswitcher).
    Kuv tshee tawm "ecodes.go" los ntawm "golang-evdev" (Kuv tub nkees heev los saib qhov qub, txawm hais tias tus sau qhia nws zoo heev). Kuv kho me ntsis (rau tam sim no) ib yam dab tsi uas txaus ntshai heev. Zoo li β€œLEFTBRACE” β†’ β€œL_BRACE”.
  • Tsis tas li ntawd, nws tau qhia txog lub tswvyim ntawm "lub xeev cov yuam sij". Txij li cov qauv sau ntawv tsis tu ncua tsis tso cai rau cov lus ntev. (Tab sis nws tso cai rau koj mus xyuas nrog tsawg kawg nkaus nyiaj siv ua haujlwm. Yog tias koj tsuas yog siv cov ntaub ntawv "direct" xwb.)
  • Yuav muaj ib tug built-in "deuplicator" ntawm dab tsi yog nias. Yog li, lub xeev "repeat" = 2 yuav raug sau ΠΎΠ΄ΠΈΠ½ ib zaug.

1. Cov qauv ntu

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

Dab tsi yog ib lo lus tib neeg nrog lub suab lus suav nrog? (txawm yog teeb meem ntawm graphemes aka "hieroglyphs")? Qee yam txaus ntshai "daim ntawv". Yog li ntawd, kuv tam sim qhia lub tswvyim ntawm "template".

2. Yuav ua li cas thaum ib yam dab tsi raug nyem (lwm tus lej scan tau tuaj txog)

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

Tag nrho muaj 768 codes. (Tab sis "tsuas yog nyob rau hauv rooj plaub" Kuv tso ntes "xws li" rau hauv xswitcher code).
Hauv kuv tau piav qhia txog kev sau cov array nrog kev txuas mus rau cov haujlwm "yuav ua li cas". Nyob rau hauv golang no (dam ntawd) Nws muab tawm kom yooj yim thiab pom tseeb.

  • Kuv npaj yuav txo "Tshaj" mus rau qhov tsawg kawg nkaus hauv qhov chaw no. Hauv kev pom zoo ntawm kev hloov pauv ntau dua (Kuv yuav qhia nws hauv qab).

3. Rooj nrog qhov rais chav kawm

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

Cov kab ntawm lub rooj yog nyob rau hauv ob chav square brackets nrog nws lub npe. Nws tsis tuaj yeem yooj yim tawm ntawm tus puav. Nyob ntawm lub qhov rais tam sim no, koj tuaj yeem xaiv cov kev xaiv hauv qab no:

  • Koj tus kheej txheej ntawm "cov yuam sij kub" "Kev Ua = ...". Yog tias tsis yog / khoob, tsis ua dab tsi.
  • Hloov "MouseClickDrops" - yuav ua li cas thaum pom tus nas nyem. Txij li thaum lub sijhawm uas xswitcher tau qhib tsis muaj cov ntsiab lus hais txog "qhov twg lawv nyem," peb rov pib qhov tsis yog los ntawm lub neej ntawd. Tab sis hauv terminals (piv txwv li) koj tsis tas yuav ua qhov no (feem ntau).

4. Ib qho (lossis ob peb) ntu ​​ntawm kev nias ua rau ib qho lossis lwm qhov sib txuas

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

Hooks muab faib ua ob hom. Built-in, nrog rau tus kheej piav npe (NewWord, NewSentence, Compose) thiab programmable.

Programmable npe pib nrog "Action." Vim TOML v1.4, cov npe nrog cov dots yuav tsum muaj nyob rau hauv nqe lus.

Txhua ntu yuav tsum tau piav qhia hauv qab no nrog tib lub npe.

Txhawm rau kom tsis txhob cuam tshuam tib neeg lub siab nrog "liab qab" tsis tu ncua (los ntawm kev paub, lawv sau ntawvtej zaum ib tug ntawm kaum cov kws tshaj lij), Kuv tam sim siv cov syntax ntxiv.

  • "OFF:" (los yog "ON:") ua ntej regexp (kev qhia tsis tu ncua) xav kom cov nyees khawm hauv qab no raug tso tawm (los yog nias).
    Tom ntej no kuv yuav ua qhov "tsis ncaj ncees" tsis tu ncua. Nrog cais cov khoom ntawm cov kav dej "|". Txhawm rau txo cov ntaub ntawv xws li "[LR]_SHIFT" (qhov no yog qhov tsis tsim nyog).
  • "SEQ:" Yog tias qhov xwm txheej dhau los tau ua tiav (lossis tsis tuaj), ces peb kuaj xyuas qhov "ib txwm" qhia tsis tu ncua. Yog xav paub ntxiv, kuv xa mus rau ^W lub tsev qiv ntawv "regexp". Vim kuv tseem tsis tau thab mus nrhiav cov degree ntawm compatibility nrog kuv nyiam pcre ("perl compatible").
  • Cov lus qhia yog sau rau hauv daim ntawv "BUTTON_1: CODE1, BUTTON_2: CODE2" thiab lwm yam, nyob rau hauv qhov kev txiav txim uas tau txais cov lej scan.
  • Daim tshev yeej ib txwm "snuged" mus rau qhov kawg ntawm qhov sib lawv liag, yog li tsis tas yuav ntxiv "$" rau tus Tsov tus tw.
  • Tag nrho cov tshev hauv ib kab yog ua ib qho tom qab lwm qhov thiab ua ke los ntawm "Kuv". Tab sis txij li tus nqi tau piav qhia tias yog ib qho array, koj tuaj yeem sau ib qho kev kuaj xyuas tom qab lub comma. Yog tias qhov no xav tau rau qee yam.
  • nqi "Luas = 8" txwv qhov loj ntawm qhov tsis tawm tsam uas txhua qhov kev kuaj xyuas tau ua. Vim Kuv muaj (txog tam sim no) yeej tsis tau ntsib kev txom nyem hauv kuv lub neej.

5. Kev teeb tsa cov hooks tau piav qhia hauv ntu dhau los

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

Qhov tseem ceeb ntawm no yog "Action = [Array]". Zoo ib yam li cov seem dhau los, muaj kev txwv tsis pub ua hauv kev ua haujlwm. Thiab qhov muaj peev xwm ntawm docking tsis txwv hauv txoj cai (sau "Action.XXX" thiab tsis txhob tub nkeeg dhau los sau lwm ntu rau nws).
Tshwj xeeb tshaj yog, retyping ntawm ib lo lus nyob rau hauv kho layout yog muab faib ua ob ntu: β€œhloov lub layout raws li tau teev tseg rau ntawd” ΠΈ "retype" ("RetypeWord").

Qhov seem tsis yog sau rau "dictionary" ("map" in golang) rau ib qho kev nqis tes ua, lawv cov npe nyob ntawm qhov tau sau hauv "Action".

Ob peb yam sib txawv tuaj yeem piav qhia hauv ib heap (seem). Los yog koj tuaj yeem rub nws sib nrug. Raws li kuv tau qhia saum toj no.

Kuv tau teeb tsa "Exec" tam sim ntawd los ua cov ntawv sau sab nraud. Nrog rau kev xaiv thawb lub kaw tsis rau hauv stdin.

  • "Tos = 1" β€” tos kom cov txheej txheem khiav kom tiav.
  • Tej zaum, "mus rau heap" koj yuav xav tso cov neeg ntxiv rau hauv ib puag ncig. cov ntaub ntawv xws li lub npe ntawm lub qhov rais chav kawm uas nws tau cuam tshuam.
    β€œKoj puas xav txuas koj tus tuav? Nov yog qhov chaw koj yuav tsum mus. "

Pheej (exhaled). Zoo li kuv tsis nco qab dab tsi.

Oops! Yog, kuv tsis tau hnov ​​qab ...
Qhov kev tso tawm nyob qhov twg? Nyob rau hauv hard code? Zoo li ntawd:

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

Kuv tsis nco qab / ua yuam kev qhov twg? (tsis muaj txoj hauv kev no), Kuv vam tias cov neeg nyeem nyeem yuav tsis ua tub nkeeg dhau los ua rau lawv lub qhov ntswg.

Hmoov zoo!

Tau qhov twg los: www.hab.com

Ntxiv ib saib