ืžืชืงืŸ ืคืจื™ืกืช Xswitcher ืขื‘ื•ืจ ืœื™ื ื•ืงืก: ืฉืœื‘ ืฉื ื™

ื›ืžื• ืคืจืกื•ื ืงื•ื“ื (xswitcher ื‘ืฉืœื‘ "ื”ื•ื›ื—ืช ื”ืจืขื™ื•ืŸ") ืงื™ื‘ืœ ื“ื™ ื”ืจื‘ื” ืžืฉื•ื‘ ื‘ื•ื ื” (ื–ื” ื ื—ืžื“), ื”ืžืฉื›ืชื™ ืœื”ืฉืงื™ืข ืืช ื–ืžื ื™ ื”ืคื ื•ื™ ื‘ืคื™ืชื•ื— ื”ืคืจื•ื™ืงื˜. ืขื›ืฉื™ื• ืื ื™ ืจื•ืฆื” ืœื‘ืœื•ืช ืงืฆืช ืžืžืš... ื”ืฉืœื‘ ื”ืฉื ื™ ืœื ื™ื”ื™ื” ื“ื™ ืจื’ื™ืœ: ื”ืฆืขื”/ื“ื™ื•ืŸ ื‘ืขื™ืฆื•ื‘ ืชืฆื•ืจื”.

ืžืชืงืŸ ืคืจื™ืกืช Xswitcher ืขื‘ื•ืจ ืœื™ื ื•ืงืก: ืฉืœื‘ ืฉื ื™

ืื™ื›ืฉื”ื• ืžืชื‘ืจืจ ืฉืœืžืชื›ื ืชื™ื ืจื’ื™ืœื™ื ื–ื” ืžืฉืขืžื ืœื”ืคืœื™ื ืœื”ื’ื“ื™ืจ ืืช ื›ืœ ื”ืคืงื“ื™ื ื”ืืœื”.

ื›ื“ื™ ืœื ืœื”ื™ื•ืช ืžื•ืคืจืš, ื‘ืคื ื™ื ื™ืฉ ื“ื•ื’ืžื” ืœืžื” ืฉืื ื™ ืžืชืžื•ื“ื“ ืื™ืชื•.
ื‘ืื•ืคืŸ ื›ืœืœื™, ืืคืืฆ'ื™ ืงืคืงื ื•-ZooKeeper ืžืชื•ื›ื ื ื™ื ืžืฆื•ื™ืŸ (ื•ืžื™ื•ืฉืžื™ื ื”ื™ื˜ื‘).
- ืชืฆื•ืจื”? ืื‘ืœ ื–ื” ืžืฉืขืžื! xml ืžื˜ื•ืžื˜ื (ื›ื™ ื–ื” "ืžื—ื•ืฅ ืœืงื•ืคืกื”").
- ืื”, ื’ื ืืชื” ืจื•ืฆื” ACL? ืื‘ืœ ื–ื” ื›ืœ ื›ืš ืžืฉืขืžื! ื˜ืคื•-ื‘ืœื•ืคืจ... ืžืฉื”ื• ื›ื–ื”.

ืื‘ืœ ื‘ืขื‘ื•ื“ื” ืฉืœื™ ื–ื” ื‘ื“ื™ื•ืง ื”ืคื•ืš. ื™ืžื™ืŸ (ืื‘ื•ื™, ื›ืžืขื˜ ืืฃ ืคืขื ืœื ื‘ืคืขื ื”ืจืืฉื•ื ื”) ื”ื“ื’ื ื”ื‘ื ื•ื™ ืžืืคืฉืจ ืœืš ืœื”ืžืฉื™ืš ื”ืœืื” ื‘ืงืœื•ืช ื•ื‘ื˜ื‘ืขื™ื•ืช (ื›ึผึดืžืขึทื˜) ืœื”ืจื›ื™ื‘ ืชืจืฉื™ื.

ืœืื—ืจื•ื ื” ื ืชืงืœืชื™ ื‘ืžืืžืจ ืขืœ Habrรฉ ืขืœ ื”ืขื‘ื•ื“ื” ื”ืงืฉื” ืฉืœ ืžื“ืขื ื™ ื ืชื•ื ื™ื...
ืžืกืชื‘ืจ ืฉื”ืจื’ืข ื”ื–ื” ืžื•ืžืฉ ืขื‘ื•ืจื ื‘ืžืœื•ืื•. ื•ื‘ืชืจื’ื•ืœ ืฉืœื™, ื›ืžื• ืฉืื•ืžืจื™ื, "ื’ืจืกื” ืงืœื”". ื“ื’ืžื™ื ืžืจื•ื‘ื™ื, ืžืชื›ื ืชื™ื ื•ืชื™ืงื™ื ืขื OOP ืžื•ื›ืŸ ื•ื›ื•'. - ื›ืœ ื–ื” ื™ื•ืคื™ืข ืžืื•ื—ืจ ื™ื•ืชืจ ื›ืืฉืจ/ืื ื–ื” ื™ืžืจื™ื. ืื‘ืœ ื”ืžืขืฆื‘ ืฆืจื™ืš ืœื”ืชื—ื™ืœ ืื™ืคืฉื”ื• ื›ืืŸ ื•ืขื›ืฉื™ื•.

ืชื’ื™ืข ืœื ืงื•ื“ื”. ืœืงื—ืชื™ ืืช TOML ื›ื‘ืกื™ืก ืชื—ื‘ื™ืจื™ ืžื”ืื–ืจื— ื”ื–ื”.

ื‘ื’ืœืœ ืฉื”ื•ื (TOML) ืžืฆื“ ืื—ื“, ื ื™ืชืŸ ืœืขืจื™ื›ื” ืื ื•ืฉื™ืช. ืžืฆื“ ืฉื ื™, ื”ื•ื ืžืชื•ืจื’ื 1:1 ืœื›ืœ ืื—ื“ ืžื”ืชื—ื‘ื™ืจ ื”ื ืคื•ืฆื™ื ื™ื•ืชืจ: XML, JSON, YAML.
ื™ืชืจื” ืžื›ืš, ื”ืžื™ืžื•ืฉ ืฉื‘ื• ื”ืฉืชืžืฉืชื™ ืž-"github.com/BurntSushi/toml", ืื ื›ื™ ืœื ื”ื›ื™ ืื•ืคื ืชื™ (ืขื“ื™ื™ืŸ ืชื—ื‘ื™ืจ 1.4), ืชื•ืื ืชื—ื‘ื™ืจื™ืช ืœืื•ืชื• ("ืžื•ื‘ื ื”") JSON.

ื›ืœื•ืžืจ, ืื ืชืจืฆื”, ืืชื” ื™ื›ื•ืœ ืคืฉื•ื˜ ืœื•ืžืจ "ืขื‘ื•ืจ ื“ืจืš ื”ื™ืขืจ ืขื ื”-TOML ื”ื–ื” ืฉืœืš, ืื ื™ ืจื•ืฆื” XXX" ื•"ืชืชืงืŸ" ืืช ื”ืงื•ื“ ื‘ืฉื•ืจื” ืื—ืช ื‘ืœื‘ื“.

ืœืคื™ื›ืš, ืื ืืชื” ืจื•ืฆื” ืœื›ืชื•ื‘ ื›ืžื” ื—ืœื•ื ื•ืช ื›ื“ื™ ืœื”ื’ื“ื™ืจ ืืช xswitcher (ืื ื™ ืœื ื‘ื˜ื•ื—) ืœื ืฆืคื•ื™ื•ืช ื‘ืขื™ื•ืช "ืขื ื”ืชืฆื•ืจื” ื”ืืจื•ืจื” ื”ื–ื• ืฉืœืš."

ืขื‘ื•ืจ ื›ืœ ื”ืฉืืจ, ื”ืชื—ื‘ื™ืจ ืžื‘ื•ืกืก ืขืœ "ืžืคืชื— = ืขืจืš" (ื•ืžืžืฉ ื›ืžื” ืืคืฉืจื•ื™ื•ืช ืžืกื•ื‘ื›ื•ืช ื™ื•ืชืจ, ื›ืžื• = [ื›ืžื”, ื–ื”, ืžืขืจืš]) ืื ื™ ืžื ื™ื—
ื ื•ื— ืื™ื ื˜ื•ืื™ื˜ื™ื‘ื™ืช.
ืžื” ืฉืžืขื ื™ื™ืŸ ื–ื” "ืฉื‚ึทืจื•ึผืฃ" ื‘ืขืจืš ื‘ืื•ืชื• ื–ืžืŸ (ื‘ืกื‘ื™ื‘ื•ืช 2013). ืจืง ืฉื‘ื ื™ื’ื•ื“ ืืœื™, ืžื—ื‘ืจ TOML ื ื›ื ืก ื‘ืงื ื” ืžื™ื“ื” ืจืื•ื™.

ืœื›ืŸ, ืขื›ืฉื™ื• ืงืœ ืœื™ ื™ื•ืชืจ ืœื”ืชืื™ื ืืช ื”ื™ื™ืฉื•ื ืฉืœื• ื›ืš ืฉื™ืชืื™ื ืœืขืฆืžื™, ื•ืœื ืœื”ื™ืคืš.

ื‘ืื•ืคืŸ ื›ืœืœื™, ืื ื• ืœื•ืงื—ื™ื TOML (ื“ื•ืžื” ืžืื•ื“ ืœ-Windows INI ื”ื™ืฉืŸ). ื•ื™ืฉ ืœื ื• ืชืฆื•ืจื” ืฉื‘ื” ืื ื• ืžืชืืจื™ื ื›ื™ืฆื“ ืœื—ื‘ืจ ืกื“ืจื” ืฉืœ ื•ื•ื™ื ื‘ื”ืชืื ืœืกื˜ ืฉืœ ืงื•ื“ื™ ื”ืกืจื™ืงื” ื”ืขื“ื›ื ื™ื™ื ื‘ื™ื•ืชืจ ืžื”ืžืงืœื“ืช. ืœื”ืœืŸ, ื—ืœืง ืื—ืจ ื—ืœืง, ืžื” ืฉืงืจื” ืขื“ ื›ื”. ื•ื”ืกื‘ืจ ืœืžื” ื”ื—ืœื˜ืชื™ ื›ื›ื”.

0. ื”ืคืฉื˜ื•ืช ื‘ืกื™ืกื™ื•ืช

  • ืกืจื•ืง ื™ื™ืขื•ื“ื™ ืงื•ื“. ื‘ื”ื—ืœื˜ ืฆืจื™ืš ืœืขืฉื•ืช ืžืฉื”ื• ื‘ืงืฉืจ ืœื–ื”, ืžื›ื™ื•ื•ืŸ ืฉืคืฉื•ื˜ ืงื•ื“ื™ื ื“ื™ื’ื™ื˜ืœื™ื™ื ืื™ื ื ื ื™ืชื ื™ื ืœืงืจื™ืื” ืื ื•ืฉื™ืช (ื–ื” ืจืง ืื ื™ loloswitcher).
    ื”ื•ืฆืืชื™ ืืช "ecodes.go" ืž-"golang-evdev" (ื”ื™ื™ืชื™ ืขืฆืœืŸ ืžื›ื“ื™ ืœื”ืกืชื›ืœ ืขืœ ื”ืžืงื•ืจ ื”ืžืงื•ืจื™, ืื ื›ื™ ื”ืžื—ื‘ืจ ืฆื™ื™ืŸ ื–ืืช ื‘ืื•ืคืŸ ืชืจื‘ื•ืชื™ ืœืžื“ื™). ืชื™ืงื ืชื™ ืžืฉื”ื• ืงื˜ืŸ (ื‘ื™ื ืชื™ื™ื) ืฉื”ื™ื” ื“ื™ ืžืคื—ื™ื“. ื›ืžื• "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).
ื‘ืคื ื™ื ืชื™ืืจืชื™ ืืช ืžื™ืœื•ื™ ื”ืžืขืจืš ื‘ืงื™ืฉื•ืจื™ื ืœืคื•ื ืงืฆื™ื•ืช "ืžื” ืœืขืฉื•ืช". ื‘ื’ื•ืœื ื’ ื–ื” (ืคึผึดืชึฐืื•ึนื) ื”ืชื‘ืจืจ ืฉื–ื” ื ื•ื— ื•ืžื•ื‘ืŸ ืžืืœื™ื•.

  • ืื ื™ ืžืชื›ื ืŸ ืœืฆืžืฆื ืืช "ื“ืจื•ืค" ืœืžื™ื ื™ืžื•ื ื‘ืžืงื•ื ื”ื–ื”. ืœื˜ื•ื‘ืช ืขื™ื‘ื•ื“ ื’ืžื™ืฉ ื™ื•ืชืจ (ืืจืื” ื–ืืช ื‘ื”ืžืฉืš).

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, ืฉืžื•ืช ืขื ื ืงื•ื“ื•ืช ื—ื™ื™ื‘ื™ื ืœื”ื™ื•ืช ื‘ืžื™ืจื›ืื•ืช.

ื›ืœ ืกืขื™ืฃ ืฆืจื™ืš ืœื”ื™ื•ืช ืžืชื•ืืจ ืœื”ืœืŸ ืขื ืื•ืชื• ืฉื.

ื›ื“ื™ ืœื ืœืคื•ืฆืฅ ืืช ื“ืขืชื ืฉืœ ืื ืฉื™ื ืขื ืื ืฉื™ื ืงื‘ื•ืขื™ื "ืขื™ืจื•ืžื™ื" (ืžื ื™ืกื™ื•ืŸ, ืฉืœื”ื ืœื›ืชื•ื‘ืื•ืœื™ ืื—ื“ ืžื›ืœ ืขืฉืจื” ืžืงืฆื•ืข), ืื ื™ ืžื™ื™ืฉื ืžื™ื“ ืชื—ื‘ื™ืจ ื ื•ืกืฃ.

  • "OFF:" (ืื• "ON:") ืœืคื ื™ regexp (ื‘ื™ื˜ื•ื™ ืจื’ื•ืœืจื™) ื™ืฉ ืœืฉื—ืจืจ (ืื• ืœืœื—ื•ืฅ) ืืช ื”ื›ืคืชื•ืจื™ื ื”ื‘ืื™ื.
    ื”ื‘ื ืื ื™ ื”ื•ืœืš ืœืขืฉื•ืช ื‘ื™ื˜ื•ื™ ืจื’ื•ืœืจื™ "ืœื ื”ื•ื’ืŸ". ืขื ื‘ื“ื™ืงื” ื ืคืจื“ืช ืฉืœ ื—ืชื™ื›ื•ืช ื‘ื™ืŸ ืฆื™ื ื•ืจื•ืช "|". ืขืœ ืžื ืช ืœืฆืžืฆื ืืช ืžืกืคืจ ื”ืจืฉื•ืžื•ืช ื›ืžื• "[LR]_SHIFT" (ื›ืืฉืจ ื–ื” ื‘ืจื•ืจ ืฉืื™ืŸ ืฆื•ืจืš).
  • "SEQ:" ืื ื”ืชื ืื™ ื”ืงื•ื“ื ืžืชืงื™ื™ื (ืื• ื ืขื“ืจ), ืื– ื ื‘ื“ื•ืง ืžื•ืœ ื‘ื™ื˜ื•ื™ ืจื’ื•ืœืจื™ "ืจื’ื™ืœ". ืœืคืจื˜ื™ื, ืื ื™ ืฉื•ืœื— ืžื™ื“ ืืœ ^W ืืช ืกืคืจื™ื™ืช "regexp". ื›ื™ ืขื“ื™ื™ืŸ ืœื ื˜ืจื—ืชื™ ืœื‘ืจืจ ืืช ืžื™ื“ืช ื”ืชืื™ืžื•ืช ืขื pcre ื”ืื”ื•ื‘ ืขืœื™ื™ ("ืชื•ืื perl").
  • ื”ื‘ื™ื˜ื•ื™ ื›ืชื•ื‘ ื‘ืฆื•ืจื” "BUTTON_1: CODE1, BUTTON_2: CODE2" ื•ื›ื•', ืœืคื™ ืกื“ืจ ืงื‘ืœืช ืงื•ื“ื™ ื”ืกืจื™ืงื”.
  • ื”ืฆ'ืง ืชืžื™ื“ "ืžื•ืฆืžื“" ืœืกื•ืฃ ื”ืจืฆืฃ, ื›ืš ืฉืื™ืŸ ืฆื•ืจืš ืœื”ื•ืกื™ืฃ "$" ืœื–ื ื‘.
  • ื›ืœ ื”ื‘ื“ื™ืงื•ืช ื‘ืฉื•ืจื” ืื—ืช ืžื‘ื•ืฆืขื•ืช ื‘ื–ื• ืื—ืจ ื–ื• ื•ืžืฉื•ืœื‘ื™ื ืขืœ ื™ื“ื™ "ืื ื™". ืื‘ืœ ืžื›ื™ื•ื•ืŸ ืฉื”ืขืจืš ืžืชื•ืืจ ื›ืžืขืจืš, ืืชื” ื™ื›ื•ืœ ืœื›ืชื•ื‘ ืฆ'ืง ื—ืœื•ืคื™ ืื—ืจื™ ื”ืคืกื™ืง. ืื ื–ื” ื ื—ื•ืฅ ืžืกื™ื‘ื” ื›ืœืฉื”ื™.
  • ืขืจืš "SeqLength = 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" ื•ืืœ ืชืชืขืฆืœ ืœื›ืชื•ื‘ ืขื‘ื•ืจื• ืงื˜ืข ื ื•ืกืฃ).
ื‘ืคืจื˜, ื”ืงืœื“ื” ื—ื•ื–ืจืช ืฉืœ ืžื™ืœื” ื‘ืคืจื™ืกื” ื”ืžืชื•ืงื ืช ืžื—ื•ืœืงืช ืœืฉื ื™ ื—ืœืงื™ื: "ืฉื ื” ืืช ื”ืคืจื™ืกื” ื›ืคื™ ืฉืฆื•ื™ืŸ ืฉื" ะธ "retype" ("RetypeWord").

ืฉืืจ ื”ืคืจืžื˜ืจื™ื ื ื›ืชื‘ื™ื ืœ"ืžื™ืœื•ืŸ" ("ืžืคื”" ื‘ื’ื•ืœืื ื’) ืขื‘ื•ืจ ืคืขื•ืœื” ื ืชื•ื ื”, ื”ืจืฉื™ืžื” ืฉืœื”ื ืชืœื•ื™ื” ื‘ืžื” ืฉื›ืชื•ื‘ ื‘"ืคืขื•ืœื”".

ื ื™ืชืŸ ืœืชืืจ ื›ืžื” ืคืขื•ืœื•ืช ืฉื•ื ื•ืช ื‘ืขืจื™ืžื” ืื—ืช (ืžืงื˜ืขื™ื). ืื• ืฉืืชื” ื™ื›ื•ืœ ืœืคืจืง ืื•ืชื•. ื›ืคื™ ืฉื”ืจืื™ืชื™ ืœืžืขืœื”.

ื”ื’ื“ืจืชื™ ืžื™ื“ ืืช ืคืขื•ืœืช ื”-"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

ื”ื•ืกืคืช ืชื’ื•ื‘ื”