Since the previous publication (xswitcher at the “proof of concept” stage) received a lot of constructive reviews (which is nice) , I continued to spend my free time on the development of the project. Now I want to spend a little of yours ... The second step will not be quite familiar: suggestion / discussion of configuration design.
Somehow it turns out that normal programmers are wildly bored to tune all these twists.In order not to be unfounded, inside is an example of what I'm dealing with.( ) Apache Kafka & ZooKeeper.
— ? ! - xml ( « »).
— , ACL ? ! -… - .
And in my work - exactly the opposite. Correctly (alas, from the first time almost never) the constructed model allows you to easily and easily (well, almost) assemble the circuit.Recently article on Habré came across an article about hard work of data-scientists ..., . , , « ». , .. — , / . - .
Get to the point. As a syntactic basis, I took TOML from this citizen .Because it (TOML) is on one hand human-editable. And on the other - it translates 1: 1 into any of the more common syntaxes: XML, JSON, YAML.Moreover, the implementation I used from "github.com/BurntSushi/toml", although not the most fashionable (still syntax 1.4), is syntactically compatible with the same ("built-in") JSON.That is, if you want, you can simply say “go through the forest with this your TOML, I want XXX” and “patch” the code with just one line.Thus, if you want to write some windows (certainly not me) to configure xswitcher, there are no problems "with this your fucking config".For all the others, the syntax based on "key = value" (and literally a couple of options is more complicated, type = [some, that, array]) I supposeintuitively convenient.,
«» ( 2013 ). , , TOML .
, .
In general, we take TOML (very similar to the old Windows INI). And we have a configuration in which we describe how to attach a series of hooks depending on the set of the latest scan codes from the keyboard. Below in pieces - what happened at the moment. And the explanation of what I decided so.0. Basic abstractions
- -. - , - ( loloswitcher).
«ecodes.go» «golang-evdev» ( , ). () . «LEFTBRACE» → «L_BRACE». - « ». . ( . «» .)
- «» . , «»=2 .
1.
[Templates]
"WORD" = "([0-9A-Z`;']|[LR]_BRACE|COMMA|DOT|SLASH|KP[0-9])"
What does a human language word with phonetic notation consist of (or is it a grapheme aka “hieroglyphs” case) ? Some kind of terrible "sheet." Therefore, I immediately lay the concept of “template”.2. What to do when something is pressed (the next scan code has arrived)
[ActionKeys]
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 = ["ESC", "-", "TAB", "ENTER", "KPENTER", "LINEFEED..POWER"]
StateKeys = ["L_CTRL", "L_SHIFT", "L_ALT", "L_META", "CAPS", "N_LOCK", "S_LOCK",
"R_CTRL", "R_SHIFT", "R_ALT", "R_META"]
Test = ["F1..F10", "ZENKAKUHANKAKU", "102ND", "F11", "F12",
"RO..KPJPCOMMA", "SYSRQ", "SCALE", "HANGEUL..YEN",
"STOP..SCROLLDOWN", "NEW..MAX"]
A total of 768 codes are provided. (But, just in case, I inserted a catch of "surprises" in the xswitcher code).Inside I painted filling the array with links to the "what to do" functions. On golang, it (suddenly) turned out to be convenient and obvious.- “Drop” in this place I plan to reduce to a minimum. In favor of more flexible processing (I will show below).
3. Window class label
[[WindowClasses]]
Regex = "^VirtualBox"
Actions = ""
[[WindowClasses]]
Regex = "^konsole"
MouseClickDrops = 0
Actions = "Actions"
[[WindowClasses]]
MouseClickDrops = 1
Actions = "Actions"
Table rows are in double square brackets with its name. Easier to go did not work. Depending on the current active window, you can choose the options:- « » «Actions = …». / — .
- «MouseClickDrops» — . xswitcher « », - . () ( ).
4. ( )
[Actions]
SeqLength = 8
NewWord = [ "OFF:(CTRL|ALT|META) SEQ:(((BACK)?SPACE|[LR]_SHIFT):[01],)*(@WORD@:1)",
"SEQ:(@WORD@:2,@WORD@:0)",
"SEQ:((KP)?MINUS|(KP)?ENTER|ESC|TAB)" ]
NewSentence = [ "SEQ:(ENTER:0)" ]
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)" ]
"Action.Respawn" = [ "OFF:(CTRL|ALT|META|SHIFT) SEQ:(S_LOCK:2,S_LOCK:0)" ]
"Action.Layout0" = [ "OFF:(CTRL|ALT|META|R_SHIFT) SEQ:(L_SHIFT:1,L_SHIFT:0)" ]
"Action.Layout1" = [ "OFF:(CTRL|ALT|META|L_SHIFT) SEQ:(R_SHIFT:1,R_SHIFT:0)" ]
"Action.Hook1" = [ "OFF:(CTRL|R_ALT|META|SHIFT) SEQ:(L_ALT:1,L_ALT:0)" ]
Hooks are divided into two types. Built-in, with "talking" names (NewWord, NewSentence, Compose) and programmable.Programmable names begin with "Action." Because TOML v1.4, dotted names must be in quotation marks.A section with the same name should be described below for each .In order not to blow up people's brains with “bare” regulars (from experience, one out of ten professionals can write them ), I immediately introduce an additional syntax.- «OFF:» ( «ON:») regexp ( ) ( ).
«» . "|". "[LR]_SHIFT" ( ). - «SEQ:» ( ), «» .
^W «regexp». pcre («perl compatible»). - «_1: 1, _2: 2» .., -.
- «» , "$" .
- «». , . - .
- «SeqLength = 8» , . .. ( ) .
5. ,
[Action.RetypeWord]
Action = [ "Action.CyclicSwitch", "RetypeWord" ]
[Action.CyclicSwitch]
Action = [ "Switch" ]
Layouts = [0, 1]
[Action.Layout0]
Action = [ "Layout" ]
Layout = 0
[Action.Layout1]
Action = [ "Layout" ]
Layout = 1
[Action.Respawn]
Action = [ "Respawn" ]
[Action.Hook1]
Action = [ "Exec" ]
Exec = "/path/to/exec -a -b --key_x"
Wait = 1
SendBuffer = "Word"
The main thing here is “Action = [Array]” . Similar to the previous section, there is a limited set of built-in actions. And unlimited in principle the possibility of docking (write "Action.XXX" and not be too lazy to paint another section for it) .In particular, the word re-typing in the corrected layout is divided into two parts: “change the layout as it is set there” and “re-type” (“RetypeWord”) .The remaining parameters are written to the "dictionary" ("map" in golang) for this action, their list depends on what is written in "Action".Several different actions can be described in one heap (section) . And you can pull it apart. As I showed above.Immediately lay the “Exec” action - execute an external script. With the option to push the written buffer into stdin.- “Wait = 1” - wait for the completion of the running process.
- Probably, "to the heap" will want to put in the environment extra. information such as the name of the window class from which it is intercepted.
“Want to hook up your handler?” To you here. ”
Phew (exhaled). It seems to have forgotten nothing.Oops! Yeah, I didn’t forget ...? -́? :
[ScanDevices]
Test = "/dev/input/event0"
Respawn = 30
Search = "/dev/input/event*"
Bypass = "(?i)Video|Camera"
And where I forgot / made a mistake (without this - no way) , I really hope that attentive readers are not too lazy to poke their nose.Good luck