ãšã㊠(xswitcher ã¯ãæŠå¿µå®èšŒã段é) ããªãå€ãã®å»ºèšçãªãã£ãŒãããã¯ãåãåããŸãã (ããã¯ããããšã§ã), ç§ã¯èªç±æéãè²»ãããŠãããžã§ã¯ãã®éçºãç¶ããŸããã ä»ãç§ã¯ããªãã®ãéãå°ã䜿ããããšæã£ãŠããŸã... XNUMX çªç®ã®ã¹ãããã¯ãéåžžãšã¯ç°ãªããŸã: æ§æèšèšã®ææ¡/ãã£ã¹ã«ãã·ã§ã³ã§ãã

ã©ãããããããéåžžã®ããã°ã©ããããããã¹ãŠã®ã³ã³ãããŒã«ãèšå®ããã®ã¯ä¿¡ããããªãã»ã©éå±ã§ããããšãããããŸããã
æ ¹æ ã®ãªãããšã®ãªãããã«ãå
éšã§ã¯ç§ãæ±ã£ãŠãããã®ã®äŸã瀺ããŸãã
å
šäœçã«éåžžã«ããèãããã (ãããŠããå®è£
ããã) Apache Kafka ãš ZooKeeper ã§ãã
- æ§æïŒ ã§ãéå±ã ãïŒ ãã XML (ãããã«äœ¿ããããã®ã§ãããã)ã
- ãããACLãæ¬²ããã§ããïŒ ã§ãããã¯ãšãŠãéå±ã§ãïŒ ã¿ããããâŠã¿ãããªã
ããããç§ã®ä»äºã§ã¯å šãéã§ãã å³ ïŒæ®å¿µãªãããåããŠã®ããšã¯ã»ãšãã©ãããŸããïŒ æ§ç¯ãããã¢ãã«ã«ãããç°¡åãã€èªç¶ã«ããã«ç¶ããããšãã§ããŸã ïŒã»ãšãã©ïŒ å³ãçµã¿ç«ãŠãŸãã
æè¿ãããŒã¿ãµã€ãšã³ãã£ã¹ãã®æžåœãªåªåã«ã€ããŠã®ããã¬ã«é¢ããèšäºãèŠã€ããŸãã...
ãã®ç¬éã圌ãã«ãšã£ãŠå®å
šã«å®çŸãããŠããããšãããããŸããã ãããŠãç§ã®ç·Žç¿ã§ã¯ã圌ããèšãããã«ããã©ã€ãããŒãžã§ã³ãã§ãã ãã«ãããªã¥ãŒã ã¢ãã«ãOOP ãåããçç·Žã®ããã°ã©ããŒãªã©ã â ããã¯ãã¹ãŠãåŸã§ãããè»éã«ä¹ã£ããšãã«è¡šç€ºãããŸãã ãããããã¶ã€ããŒã¯ä»ããããå§ããå¿
èŠããããŸãã
æ¬é¡ã«å ¥ããŸãã TOMLãæ§æã®åºç€ãšããŠæ¡çšããŸãã .
ã ã£ãŠåœŒã¯ (TOML) äžæ¹ã§ã人éã«ããç·šéãå¯èœã§ãã äžæ¹ãXMLãJSONãYAML ãªã©ã®ããäžè¬çãªæ§æã®ããããã« 1:1 ã§å€æãããŸãã
ããã«ãç§ããgithub.com/BurntSushi/tomlããã䜿çšããå®è£
ã¯ãæããã¡ãã·ã§ããã«ã§ã¯ãããŸããã (ãŸã 1.4 æ§æã§ã)ãåã (ãçµã¿èŸŒã¿ã) JSON ãšæ§æçã«äºææ§ããããŸãã
ã€ãŸããå¿ èŠã«å¿ããŠããããªãã® TOML ã䜿ã£ãŠæ£®ãæããXXX ãæ¬²ããããšèšãã ãã§ããã£ã XNUMX è¡ã§ã³ãŒãã«ããããããé©çšããããšãã§ããŸãã
ãããã£ãŠãxswitcher ãèšå®ããããã«ããã€ãã®ãŠã£ã³ããŠãäœæãããå Žåã¯ã ïŒããããããªãïŒ ãããªãã®ãã®ããŸããŸããèšå®ã§ã¯ãåé¡ã¯èµ·ãããªããšäºæ³ãããŸãã
ä»ã®ãã¹ãŠã®å Žåãæ§æã¯ãã㌠= å€ãã«åºã¥ããŸãã (ãããŠæåéã = [some, that, array] ã®ãããªããã«è€éãªãªãã·ã§ã³ãããã€ããããŸã) ç§ã¯èããŸã
çŽæçã«äŸ¿å©ã
è峿·±ãã®ã¯ã åãé ïŒ2013幎é ïŒã ãã ãç§ãšéã£ãŠãTOML ã®äœè
ã¯é©åãªèŠæš¡ã§åãçµã¿ãŸããã
ãããã£ãŠãèªåã«åãããŠå®è£ ã調æŽããããšã容æã«ãªãããã®éã¯èµ·ãããŸããã
äžè¬ã«ãTOML (å€ã Windows INI ã«éåžžã«äŒŒãŠããŸã) ãæ¡çšããŸãã ãããŠãããŒããŒãããã®ææ°ã®ã¹ãã£ã³ ã³ãŒãã®ã»ããã«å¿ããŠäžé£ã®ããã¯ãã¢ã¿ããããæ¹æ³ãèšè¿°ããæ§æããããŸãã 以äžã«ããããŸã§ã«èµ·ãã£ãããšãäžã€ãã€ç€ºããŸãã ãããŠããªããã®ããã«æ±ºãããã®èª¬æã
0. åºæ¬çãªæœè±¡å
- ã¹ãã£ã³ã³ãŒãã®æå®ã åçŽã«ããžã¿ã«ã³ãŒãã¯çµ¶å¯Ÿã«äººéãå€èªã§ããªããããããã«ã€ããŠã¯ééããªãäœããããå¿
èŠããããŸãïŒããã¯ç§ã ãã§ãïŒ ).
ç§ã¯ãgolang-evdevããããecodes.goããåé€ããŸããïŒèè ã¯éåžžã«æåçã«ããã瀺ããŠããŸããããç§ã¯å ã®ãœãŒã¹ãèŠãã®ãé¢åã§ããïŒã ããªãæãã£ãç¹ãïŒãšããããïŒå°ãä¿®æ£ããŸããã ãLEFTBRACEãâãL_BRACEãã®ããã«ã - ããã«ã圌ã¯ãç¶æ ããŒãã®æŠå¿µãå°å ¥ããŸããã éåžžã®ææ³ã䜿çšãããŠãããããé·ãæç« ã¯èš±å¯ãããŸããã (ãã ããæå°éã®ãªãŒããŒãããã§ãã§ãã¯ã§ããŸãããçŽæ¥ãèšé²ã®ã¿ã䜿çšããå Žå)ã
- æŒãããå 容ã®ãéè€é€å»æ©èœããçµã¿èŸŒãŸããŸãã ãããã£ãŠãç¶æ "repeat"=2 ãæžã蟌ãŸããŸãã 1 å
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 ã³ãŒãã«ãã£ãããªããµãã©ã€ãºããæ¿å
¥ããŸãã)ã
å
éšã§ã¯ãé
åã«ãäœããããã颿°ãžã®ãªã³ã¯ãåã蟌ãããšã説æããŸããã golangã§ã¯ãã㯠ïŒçªç¶ïŒ ããã¯äŸ¿å©ã§æçœã§ããããšãããããŸããã
- ããã§ã¯ãããããããæå°éã«æããã€ããã§ãã ããæè»ãªåŠçãæ¯æããŸã (以äžã«ç€ºããŸã)ã
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. XNUMX 〠(ãŸãã¯è€æ°) ã®ã¯ãªã㯠ã·ãŒã±ã³ã¹ã«ãããXNUMX ã€ãŸãã¯å¥ã®ããã¯ãããªã¬ãŒãããŸãã
# 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)" ]
ããã¯ã¯XNUMXçš®é¡ã«åãããŸãã ã話ããåå (NewWordãNewSentenceãCompose) ãçµã¿èŸŒãŸããŠãããããã°ã©ã å¯èœã§ãã
ããã°ã©ã å¯èœãªååã¯ãActionãã§å§ãŸããŸãã ãªããªãTOML v1.4ãããããå«ãååã¯åŒçšç¬Šã§å²ãå¿ èŠããããŸãã
åã»ã¯ã·ã§ã³ã«ã€ããŠã¯ä»¥äžã§èª¬æããŸã åãååã§.
ã裞ã®ãåžžé£å®¢ã«äººã ã®å¿ãé©ãããªãããã«ïŒçµéšäžã圌ãã® æžããã¶ãXNUMX人ã«XNUMX人 å°éå®¶)ãããã«è¿œå ã®æ§æãå®è£ ããŸãã
- ããªã:ã(ãŸãã¯ããªã³:ã) regexp (æ£èŠè¡šçŸ) ã®åã«ã次ã®ãã¿ã³ãæŸã (ãŸãã¯æŒã) å¿
èŠããããŸãã
次ã«ãäžå ¬å¹³ããªæ£èŠè¡šçŸãäœæããŸãã ãã€ãã|ãéã®éšåãåå¥ã«ãã§ãã¯ããŸãã "[LR]_SHIFT" ã®ãããªã¬ã³ãŒãã®æ°ãæžãããã (ããã¯æããã«å¿ èŠã§ã¯ãããŸãã)ã - ãé å:ã åã®æ¡ä»¶ãæºãããã (ãŸãã¯æºããããªã) å Žåã¯ããéåžžã®ãæ£èŠè¡šçŸãšç §åããŸãã 詳现ã«ã€ããŠã¯ãããã« ^W ã«ãregexpãã©ã€ãã©ãªãéä¿¡ããŸãã ãªããªããç§ã¯ãŸã ãç§ã®ãæ°ã«å ¥ãã® pcre ãšã®äºææ§ (ãperl äºææ§ã) ã®çšåºŠã調ã¹ãæ°ã«ã¯ãªã£ãŠããªãããã§ãã
- åŒã¯æ¬¡ã®åœ¢åŒã§èšè¿°ãããŸãã ãBUTTON_1: ã³ãŒã 1ãBUTTON_2: ã³ãŒã 2ã ã¹ãã£ã³ã³ãŒããåä¿¡ããé ã«ç¶ããŸãã
- ãã§ãã¯ã¯åžžã«ã·ãŒã±ã³ã¹ã®æåŸã«ããŽã£ãããä»ããããŸãããªã®ã§ãæ«å°Ÿã«ã$ãã远å ããå¿ èŠã¯ãããŸããã
- XNUMX è¡å ã®ãã¹ãŠã®ãã§ãã¯ãé çªã«å®è¡ãããŸã ãšãIããçµã¿åããããã®ã§ãã ãã ããå€ã¯é åãšããŠèšè¿°ããããããã«ã³ãã®åŸã«ä»£æ¿ãã§ãã¯ãèšè¿°ããããšãã§ããŸãã äœããã®çç±ã§ãããå¿ èŠãªå Žåã
- å€ ã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ããšæžããŸããå¥ã®ã»ã¯ã·ã§ã³ãæžãã®ãé¢åã«ãªããªãããã«ããŠãã ãã).
ç¹ã«ãä¿®æ£ãããã¬ã€ã¢ãŠãã§ã®åèªã®åå
¥å㯠XNUMX ã€ã®éšåã«åãããŠããŸãã ãããã«æå®ãããŠããããã«ã¬ã€ã¢ãŠãã倿ŽããŸãã О ãåå
¥åãïŒãRetypeWordãïŒ.
æ®ãã®ãã©ã¡ãŒã¿ã¯ãèŸæžãã«æžã蟌ãŸããŸãã (golangã§ã¯ãå°å³ã) ç¹å®ã®ã¢ã¯ã·ã§ã³ã«ã€ããŠããã®ãªã¹ãã¯ãã¢ã¯ã·ã§ã³ãã«æžãããå 容ã«ãã£ãŠç°ãªããŸãã
è€æ°ã®ç°ãªãã¢ã¯ã·ã§ã³ã XNUMX ã€ã®ããŒãã«èšè¿°ã§ããŸã (ã»ã¯ã·ã§ã³)ã ãããã¯ãåŒãé¢ãããšãã§ããŸãã äžã§ç€ºããããã«ã
ããã«ãExecãã¢ã¯ã·ã§ã³ãèšå®ããŠå€éšã¹ã¯ãªãããå®è¡ããŸãã èšé²ããããããã¡ãæšæºå ¥åã«ããã·ã¥ãããªãã·ã§ã³ä»ãã
- ãWait = 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.
ã©ããå¿ãã/ééããã®ã§ãããã? (ãããªãã§ã¯ç¡ç)ãæ³šææ·±ãèªè ãã錻ãçªãã®ãæ ããªãããšãå¿ããé¡ã£ãŠããŸãã
é 匵ã£ãŠãã ããïŒ
åºæïŒ habr.com
