Xswitcher مصحح تخطيط لينكس: الخطوة الثانية

منذ أن حصل المنشور السابق (xswitcher في مرحلة "إثبات المفهوم") على الكثير من المراجعات البناءة (وهو أمر جيد) ، واصلت قضاء وقت فراغي في تطوير المشروع. الآن أريد أن أنفق القليل من خطوتك ... لن تكون الخطوة الثانية مألوفة تمامًا: اقتراح / مناقشة تصميم التكوين.



بطريقة ما اتضح أن المبرمجين العاديين يشعرون بالملل الشديد لضبط كل هذه التقلبات.

لكي لا تكون بلا أساس ، في الداخل مثال على ما أتعامل معه.
( ) Apache Kafka & ZooKeeper.
— ? ! - xml ( « »).
— , ACL ? ! -… - .

وفي عملي - العكس تمامًا. بشكل صحيح (للأسف ، من أول مرة تقريبًا أبدًا) يسمح لك النموذج المصمم بتجميع الدائرة بسهولة ويسر (جيدًا ، تقريبًا) .

ظهر مقال حديث عن حبري عبر مقال عن العمل الشاق لعلماء البيانات ...
, . , , « ». , .. — , / . - .

أوضح ماذا تقصد. كأساس نحوي ، أخذت TOML من هذا المواطن .

لأنه (TOML) قابل للتحرير من ناحية الإنسان. ومن ناحية أخرى - يُترجم 1: 1 إلى أي من الصيغ الأكثر شيوعًا: XML و JSON و YAML.
علاوة على ذلك ، فإن التطبيق الذي استخدمته من "github.com/BurntSushi/toml" ، على الرغم من أنه ليس الأكثر أناقة (بناء الجملة 1.4) ، فهو متوافق نحويًا مع نفس JSON ("المضمنة").

أي إذا كنت تريد ، يمكنك ببساطة أن تقول "اذهب عبر الغابة مع TOML الخاص بك ، أريد XXX" و "تصحيح" الرمز بخط واحد فقط.

وبالتالي ، إذا كنت تريد كتابة بعض النوافذ (بالتأكيد لست أنا) لتكوين xswitcher ، فلا توجد مشاكل "مع هذا التكوين اللعين".

بالنسبة إلى جميع القواعد الأخرى على أساس "key = value" (وبشكل حرفي ، هناك خياران أكثر تعقيدًا ، مثل = [a ، ثم المصفوفة]) يعتقدون
مريحة بشكل حدسي.
, «» ( 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) وقابلة للبرمجة.

تبدأ الأسماء القابلة للبرمجة بـ "Action". لان 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) لهذا الإجراء ، وتعتمد قائمتها على ما هو مكتوب في "الإجراء".

يمكن وصف العديد من الإجراءات المختلفة في كومة واحدة (قسم) . ويمكنك تفكيكها. كما بينت أعلاه.

على الفور وضع الإجراء "Exec" - تنفيذ برنامج نصي خارجي. مع خيار دفع المخزن المؤقت المكتوب إلى stdin.

  • "انتظر = 1" - انتظر اكتمال عملية التشغيل.
  • ربما ، "إلى كومة الذاكرة المؤقتة" سوف ترغب في وضع إضافي في البيئة. معلومات مثل اسم فئة النافذة التي يتم اعتراضها منها.
    "هل تريد توصيل معالجك؟" إليك هنا ".

Phew (زفير). يبدو أنه لم ينس شيئا.

وجه الفتاة! نعم ، لم أنس ...
? -́? :

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


وحيث نسيت / ارتكبت خطأ (بدون هذا - بأي حال من الأحوال) ، آمل حقًا ألا يكون القراء اليقظون كسالى جدًا لدرجة أن يخدشوا أنوفهم.

حظا طيبا وفقك الله

All Articles