Коректор на распоред на Xswitcher за Linux: чекор два

Како претходната публикација (xswitcher во фазата „доказ за концепт“) доби доста конструктивни повратни информации (што е убаво), продолжив да го трошам слободното време развивајќи го проектот. Сега сакам да потрошам малку од вашата... Вториот чекор нема да биде сосема вообичаен: предлог/дискусија за дизајнот на конфигурацијата.

Коректор на распоред на Xswitcher за Linux: чекор два

Некако излегува дека на нормалните програмери им е неверојатно досадно да ги постават сите овие контроли.

За да не бидам неоснована, внатре е пример со што имам работа.
Севкупно одлично замислен (и добро имплементиран) Apache Kafka & ZooKeeper.
- Конфигурација? Но, тоа е досадно! Глупав xml (бидејќи е „надвор од кутијата“).
- О, дали сакаш и ACL? Но, тоа е толку досадно! Tap-blooper... Нешто слично.

Но, во мојата работа е токму спротивното. Во право (за жал, скоро никогаш прв пат) конструираниот модел ви овозможува да продолжите понатаму лесно и природно (За малку) состави дијаграм.

Неодамна наидов на статија на Хабре за напорната работа на научниците за податоци...
Излегува дека овој момент е целосно реализиран за нив. И во мојата пракса, како што велат, „лесна верзија“. Модели со повеќе волумени, искусни програмери со OOP на готовс, итн. — сето ова ќе се појави подоцна кога/ако полета. Но, дизајнерот треба да започне некаде овде и сега.

Дојдете до поентата. Го земав TOML како синтаксичка основа од овој граѓанин.

Затоашто тој (TOML) од една страна, може да се уредува од човек. Од друга страна, тој е преведен 1:1 во која било од повообичаените синтакси: XML, JSON, YAML.
Покрај тоа, имплементацијата што ја користев од „github.com/BurntSushi/toml“, иако не е најмодерна (сеуште 1.4 синтакса), е синтаксички компатибилна со истиот („вграден“) JSON.

Односно, ако сакате, можете едноставно да кажете „оди низ шумата со тој твој TOML, сакам ХХХ“ и „закрпи“ кодот со само една линија.

Така, ако сакате да напишете некои прозорци за да го конфигурирате xswitcher (Не сум сигурен) Не се очекуваат проблеми „со оваа ваша проклета конфигурација“.

За сите други, синтаксата се заснова на „клуч = вредност“ (и буквално неколку покомплицирани опции, како = [некои, тоа, низа]) претпоставувам
интуитивно удобен.
Она што е интересно е тоа "изгорен" приближно во исто време (околу 2013 година). Само, за разлика од мене, авторот на ТОМЛ влезе во соодветна скала.

Затоа, сега ми е полесно да ја прилагодам неговата имплементација за да одговарам на себе, а не обратно.

Во принцип, земаме TOML (многу сличен на стариот Windows INI). И имаме конфигурација во која опишуваме како да прикачите серија куки во зависност од комплетот на најновите кодови за скенирање од тастатурата. Подолу, дел по дел, е она што се случувало досега. И објаснување зошто се решив на овој начин.

0. Основни апстракции

  • Скенирајте ги ознаките на кодот. Дефинитивно треба да се направи нешто во врска со ова, бидејќи едноставно дигиталните кодови апсолутно не се читливи од човек (тоа сум само јас loloswitcher).
    Го исфрлив „ecodes.go“ од „голанг-евдев“ (бев премногу мрзелив да го погледнам изворниот извор, иако авторот доста културно го посочи). Поправив малку (засега) нешто што беше прилично страшно. Како „LEFTBRACE“ → „L_BRACE“.
  • Дополнително, тој го воведе концептот на „државни клучеви“. Бидејќи употребената редовна граматика не дозволува долги пасуси. (Но тоа ви овозможува да проверите со минимални трошоци. Ако користите само „директно“ снимање.)
  • Ќе има вграден „дедупликатор“ на она што е притиснато. Така ќе се запише состојбата „повтори“=2 една пати

1. Дел за шаблони

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

Од што се состои зборот на човечки јазик со фонетска нотација? (или прашање на графеми или „хиероглифи“)? Некаков ужасен „чаршаф“. Затоа, веднаш го воведувам концептот на „шаблон“.

2. Што да направите кога нешто е кликнато (пристигна друг код за скенирање)

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

Има вкупно 768 кодови. (Но „за секој случај“ вметнав фаќање „изненадувања“ во кодот на xswitcher).
Внатре опишав пополнување на низата со врски до функциите „што да правам“. Во голанг ова е (одеднаш) Се покажа дека е погодно и очигледно.

  • Планирам да го намалам „Drop“ на минимум на ова место. Во корист на пофлексибилна обработка (ќе го покажам подолу).

3. Табела со класи на прозорци

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

Редовите на табелата се во двојни квадратни загради со неговото име. Не можеше да биде полесно веднаш. Во зависност од моментално активниот прозорец, можете да ги изберете следниве опции:

  • Ваш сопствен сет на „жешки копчиња“ „Акции =…“. Ако не/празна, не правете ништо.
  • Префрлете го „MouseClickDrops“ - што да направите кога ќе се открие кликнување на глувчето. Бидејќи на местото каде што е вклучен xswitcher, нема детали за „каде кликнуваат“, стандардно го ресетираме баферот. Но, во терминалите (на пример) не мора да го правите ова (обично).

4. Една (или неколку) секвенци на кликања активираат една или друга кука

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

Куките се поделени на два вида. Вграден, со „говорни“ имиња (NewWord, NewSentence, Compose) и може да се програмира.

Програмабилните имиња започнуваат со „Акција“. Бидејќи TOML v1.4, имињата со точки мора да бидат во наводници.

Секој дел треба да биде опишан подолу со истото име.

За да не им се разбуди умот на луѓето со „голи“ редовни (од искуство, нивни да пишувамможеби еден од десет професионалци), веднаш имплементирам дополнителна синтакса.

  • „ИСКЛУЧЕНО:“ (или „ВКЛУЧЕНО:“) пред regexp (редовен израз) да бара да се отпуштат (или притиснат) следните копчиња.
    Следно, ќе направам „нефер“ регуларен израз. Со посебна проверка на парчиња помеѓу цевките "|". Со цел да се намали бројот на записи како „[LR]_SHIFT“ (каде што ова очигледно не е потребно).
  • "SEQ:" Ако претходниот услов е исполнет (или отсутен), тогаш проверуваме со „нормален“ регуларен израз. За детали, веднаш ја испраќам до ^W библиотеката „regexp“. Затоа што сè уште не сум се потрудил да го дознаам степенот на компатибилност со мојот омилен pcre („perl compatible“).
  • Изразот е напишан во форма „BUTTON_1: CODE1, BUTTON_2: CODE2“ итн., по редоследот по кој се примаат шифрите за скенирање.
  • Проверката е секогаш „притисната“ до крајот на низата, така што нема потреба да додавате „$“ на опашката.
  • Сите проверки во една линија се вршат една по друга и се комбинирани со „јас“. Но, бидејќи вредноста е опишана како низа, можете да напишете алтернативна проверка по запирката. Ако ова е потребно поради некоја причина.
  • Вредност „Последна должина = 8“ ја ограничува големината на баферот против кој се вршат сите проверки. Бидејќи Никогаш (до сега) не сум сретнал бескрајни ресурси во мојот живот.

5. Поставување на куките опишани во претходниот дел

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

Главната работа тука е „Акција = [Низа]“. Слично на претходниот дел, има ограничен сет на вградени дејства. И можноста за докинг не е ограничена во принцип (напишете „Action.XXX“ и немојте да бидете премногу мрзливи да напишете друг дел за него).
Конкретно, повторното пишување на збор во коригираниот распоред е поделено на два дела: „променете го распоредот како што е наведено таму“ и „повторно пишување“ („Повторно пишување збор“).

Останатите параметри се запишани во „речник“ („карта“ на голанг) за дадена акција, нивниот список зависи од тоа што е напишано во „Дејство“.

Во еден куп може да се опишат неколку различни дејства (делови). Или можете да го расклопите. Како што покажав погоре.

Веднаш го поставив дејството „Exec“ за извршување на надворешната скрипта. Со опција за туркање на снимениот бафер во stdin.

  • „Чекај = 1“ - почекајте да заврши процесот на работа.
  • Веројатно, „до куп“ ќе сакате да ставите дополнителни луѓе во околината. информации како што е името на класата на прозорец од која е пресретнат.
    „Дали сакате да го поврзете вашиот управувач? Ова е местото каде што треба да одите“.

Пју (издишан). Изгледа ништо не сум заборавил.

Упс! Да, не заборавив...
Каде е конфигурацијата за лансирање? Во хард код? Како тоа:

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

Каде заборавив/згрешив? (во никој случај без ова), навистина се надевам дека внимателните читатели нема да бидат премногу мрзливи да го пикаат носот.

Со среќа!

Извор: www.habr.com

Додадете коментар