لینکس کے لیے Xswitcher لے آؤٹ درست کرنے والا: دوسرا مرحلہ

جیسا کہ پچھلی اشاعت ("تصور کے ثبوت" مرحلے پر xswitcher) کو کافی تعمیری تاثرات موصول ہوئے۔ (جو اچھا ہے)میں نے اپنا فارغ وقت اس پروجیکٹ کو تیار کرنے میں گزارنا جاری رکھا۔ اب میں آپ کا تھوڑا سا خرچ کرنا چاہتا ہوں... دوسرا مرحلہ بالکل عام نہیں ہوگا: کنفیگریشن ڈیزائن کی تجویز/بات چیت۔

لینکس کے لیے Xswitcher لے آؤٹ درست کرنے والا: دوسرا مرحلہ

کسی نہ کسی طرح یہ پتہ چلتا ہے کہ عام پروگرامرز کو ان تمام کنٹرولز کو ترتیب دینا ناقابل یقین حد تک بورنگ لگتا ہے۔

بے بنیاد نہ ہونے کے لیے، اندر اس کی ایک مثال ہے جس کے ساتھ میں معاملہ کر رہا ہوں۔
اپاچی کافکا اور زو کیپر مجموعی طور پر بہترین تصور کیا گیا (اور اچھی طرح سے لاگو کیا گیا)۔
- ترتیب؟ لیکن یہ بورنگ ہے! گونگا ایکس ایم ایل (کیونکہ یہ "باکس سے باہر" ہے)۔
- اوہ، کیا آپ بھی ACL چاہتے ہیں؟ لیکن یہ بہت بورنگ ہے! ٹیپ بلوپر... کچھ ایسا ہی۔

لیکن میرے کام میں اس کے بالکل برعکس ہے۔ ٹھیک ہے۔ (افسوس، پہلی بار تقریبا کبھی نہیں) تعمیر شدہ ماڈل آپ کو مزید آسانی اور قدرتی طور پر جاری رکھنے کی اجازت دیتا ہے۔ (تقریبا) ایک خاکہ جمع کریں.

میں نے حال ہی میں Habré پر ڈیٹا سائنسدانوں کی محنت کے بارے میں ایک مضمون دیکھا۔
معلوم ہوا کہ یہ لمحہ ان کے لیے مکمل طور پر محسوس ہوا ہے۔ اور میری مشق میں، جیسا کہ وہ کہتے ہیں، "لائٹ ورژن"۔ ملٹی والیوم ماڈلز، تیار ہونے والے OOP کے ساتھ تجربہ کار پروگرامر وغیرہ۔ - یہ سب کچھ بعد میں ظاہر ہوگا جب/اگر یہ شروع ہوتا ہے۔ لیکن ڈیزائنر کو یہاں اور اب کہیں شروع کرنے کی ضرورت ہے۔

بات تک پہنچ جاؤ۔ میں نے TOML کو ایک نحوی بنیاد کے طور پر لیا۔ اس شہری سے.

کیونکہ وہ (TOML) ایک طرف، انسانی قابل تدوین۔ دوسری طرف، اس کا ترجمہ 1:1 سے زیادہ عام نحو میں کیا جاتا ہے: XML، JSON، YAML۔
مزید برآں، میں نے "github.com/BurntSushi/toml" سے استعمال کیا عمل، اگرچہ سب سے زیادہ فیشن نہیں ہے (اب بھی 1.4 نحو)، اسی ("بلٹ ان") JSON کے ساتھ مصنوعی طور پر مطابقت رکھتا ہے۔

یعنی، اگر آپ چاہیں تو، آپ صرف یہ کہہ سکتے ہیں کہ "آپ کے اس TOML کے ساتھ جنگل میں جائیں، مجھے XXX چاہیے" اور صرف ایک لائن کے ساتھ کوڈ کو "پیچ" کریں۔

اس طرح، اگر آپ xswitcher کو ترتیب دینے کے لیے کچھ ونڈوز لکھنا چاہتے ہیں۔ (مجھے یقین نہیں ہے) "آپ کی اس لات کی ترتیب کے ساتھ" کسی پریشانی کی توقع نہیں ہے۔

باقی سب کے لیے، نحو کی بنیاد "key = قدر" پر ہوتی ہے۔ (اور لفظی طور پر کچھ اور پیچیدہ اختیارات، جیسے = [کچھ، وہ، صف]) مجھے لگتا ہے
بدیہی طور پر آسان.
دلچسپ بات یہ ہے کہ "جلا ہوا" اسی وقت (2013 کے آس پاس)۔ صرف، میرے برعکس، TOML کا مصنف ایک مناسب پیمانے پر آیا۔

اس لیے، اب میرے لیے اس کے نفاذ کو اپنے موافق کرنا آسان ہے، نہ کہ اس کے برعکس۔

عام طور پر، ہم TOML (بہت پرانے ونڈوز INI سے ملتا جلتا) لیتے ہیں۔ اور ہمارے پاس ایک کنفیگریشن ہے جس میں ہم یہ بیان کرتے ہیں کہ کی بورڈ سے تازہ ترین اسکین کوڈز کے سیٹ کے لحاظ سے ہکس کی ایک سیریز کو کیسے جوڑنا ہے۔ ذیل میں، ٹکڑے ٹکڑے کر کے، اب تک کیا ہوا ہے. اور میں نے اس طرح کا فیصلہ کیوں کیا اس کی وضاحت۔

0. بنیادی تجریدات

  • اسکین کوڈ عہدہ۔ اس کے بارے میں یقینی طور پر کچھ کرنے کی ضرورت ہے، کیونکہ صرف ڈیجیٹل کوڈز انسانی پڑھنے کے قابل نہیں ہیں (یہ صرف میں ہوں loloswitcher).
    میں نے "golang-evdev" سے "ecodes.go" نکالا (میں اصل ماخذ کو دیکھنے میں بہت سست تھا، حالانکہ مصنف نے ثقافتی طور پر اس کی نشاندہی کی تھی)۔ میں نے (ابھی کے لیے) کچھ درست کیا جو کافی خوفناک تھا۔ جیسے "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)" ]

ہکس کو دو اقسام میں تقسیم کیا گیا ہے۔ بلٹ ان، "اسپیکنگ" ناموں کے ساتھ (نیو ورڈ، نیو سنٹینس، کمپوز) اور قابل پروگرام۔

قابل پروگرام نام "ایکشن" سے شروع ہوتے ہیں۔ کیونکہ TOML v1.4، نقطوں والے نام کوٹس میں ہونے چاہئیں۔

ہر سیکشن کو ذیل میں بیان کیا جانا چاہئے۔ اسی نام کے ساتھ.

تاکہ لوگوں کے ذہنوں کو "ننگے" ریگولروں سے نہ اڑا دیا جائے (تجربے سے، ان کے لکھناشاید دس میں سے ایک پیشہ ور افراد) میں فوری طور پر اضافی نحو نافذ کرتا ہوں۔

  • "آف:" (یا "آن:") regexp سے پہلے (باقاعدہ اظہار) کا تقاضا ہے کہ درج ذیل بٹن جاری کیے جائیں (یا دبائے جائیں)۔
    اگلا میں ایک "غیر منصفانہ" باقاعدہ اظہار کرنے جا رہا ہوں۔ پائپوں کے درمیان ٹکڑوں کی علیحدہ چیکنگ کے ساتھ "|"۔ ریکارڈز کی تعداد کو کم کرنے کے لیے جیسے کہ "[LR]_SHIFT" (جہاں یہ واضح طور پر ضروری نہیں ہے)۔
  • "SEQ:" اگر پچھلی شرط پوری ہو جاتی ہے (یا غیر حاضر)، تو ہم "نارمل" ریگولر ایکسپریشن کے خلاف چیک کرتے ہیں۔ تفصیلات کے لیے، میں فوری طور پر ^W "regexp" لائبریری کو بھیجتا ہوں۔ کیونکہ میں نے ابھی تک اپنے پسندیدہ pcre ("perl compatible") کے ساتھ مطابقت کی ڈگری معلوم کرنے کی زحمت نہیں کی۔
  • اظہار شکل میں لکھا جاتا ہے۔ "BUTTON_1: CODE1، BUTTON_2: CODE2" وغیرہ، اس ترتیب میں جس میں اسکین کوڈ موصول ہوتے ہیں۔
  • چیک ہمیشہ تسلسل کے آخر تک "snugged" ہوتا ہے۔، لہذا دم میں "$" شامل کرنے کی ضرورت نہیں ہے۔
  • ایک لائن میں تمام چیک ایک کے بعد ایک کئے جاتے ہیں۔ اور "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" لکھیں اور اس کے لیے دوسرا سیکشن لکھنے میں سستی نہ کریں).
خاص طور پر، درست ترتیب میں کسی لفظ کی دوبارہ ٹائپنگ کو دو حصوں میں تقسیم کیا گیا ہے: "لے آؤٹ کو تبدیل کریں جیسا کہ وہاں بیان کیا گیا ہے" и "دوبارہ ٹائپ" ("دوبارہ ٹائپ ورڈ").

باقی پیرامیٹرز "لغت" میں لکھے گئے ہیں ("نقشہ" گولانگ میں) دی گئی کارروائی کے لیے، ان کی فہرست اس بات پر منحصر ہے کہ "ایکشن" میں کیا لکھا ہے۔

ایک ہی ڈھیر میں کئی مختلف اعمال بیان کیے جا سکتے ہیں۔ (حصے). یا آپ اسے الگ کر سکتے ہیں۔ جیسا کہ میں نے اوپر دکھایا۔

میں نے فوری طور پر بیرونی اسکرپٹ کو انجام دینے کے لیے "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

نیا تبصرہ شامل کریں