适用于Linux的Xswitcher布局校正器:第二步

由于上一期出版物(处于“概念验证”阶段的xswitcher)收到了很多建设性的评论(很好),所以我继续将空闲时间用于项目的开发。现在,我想花点时间... ...第二步将不太熟悉:配置设计的建议/讨论。



某种程度上,事实证明普通的程序员对调整所有这些曲折感到无聊。

为了没有根据,内部是我正在处理的示例。
( ) Apache Kafka & ZooKeeper.
— ? ! - xml ( « »).
— , ACL ? ! -… - .

而在我的工作中-恰恰相反。正确地(alas,这是第一次,几乎从来没有)构建的模型使您能够轻松,轻松地(很好,几乎)组装电路。

最近关于Habré的文章遇到了一篇有关数据科学家的辛勤工作的文章...
, . , , « ». , .. — , / . - .

讲到重点。作为句法基础,我从这个公民那儿选了TOML

因为一方面(TOML)是人类可编辑的。另一方面-它会将1:1:1转换为任何更常见的语法:XML,JSON,YAML。
而且,尽管不是最流行的(仍然是语法1.4),但我在“ github.com/BurntSushi/toml”中使用的实现与相同的(“内置”)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代码中插入了一个“惊喜”)。
在内部,我绘制了指向“做什么”功能的链接的数组。在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"

表格行在其名称的双方括号中。容易走没用。根据当前的活动窗口,可以选择以下选项:

  • « » «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 compatible»).
  • «_1: 1, _2: 2» .., -.
  • «» , "$" .
  • «». , . - .
  • «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 = [Array]”。与上一节类似,内置动作的数量有限。原则上,对接的可能性是无限的(编写“ Action.XXX”,不要太懒惰以至于不能为它画另一个部分)
特别地,在校正后的布局中的单词重新键入分为两个部分:“在此处设置的布局中更改布局”“重新键入”(“ RetypeWord”)

其余参数将为此操作写入“字典” (golang中的“地图”),其参数取决于“ Action”中写入的内容。

可以在一个堆(部分)中描述几种不同的动作。您可以将其拆开。如上所示。

立即执行“执行”操作-执行外部脚本。可以选择将写入缓冲区推入标准输入。

  • “等待= 1”-等待运行过程完成。
  • 可能,“堆”将要额外放入环境中。信息,例如从其截获的窗口类的名称。
    “想联系您的服务员吗?” 在这里给你。”

ew(呼气)。似乎什么也没忘记。

糟糕!是的,我没有忘记...
? -́? :

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


在我忘记/犯了一个错误的情况下(没有这种情况-绝不行),我真的希望细心的读者不要太懒惰以免nose鼻。

祝好运

All Articles