DUAL-FUNCTION-KEYS(1) User Manuals DUAL-FUNCTION-KEYS(1) نام (NAME) interception - کلیدهای دوکاره (dual function keys) توضیحات (DESCRIPTION) ضربه زدن برای یک کلید، نگه داشتن برای کلیدی دیگر. بسیار کاربردی برای کلیدهای تبدیل‌گر (modifier) مانند: نگه داشتن برای ctrl، ضربه زدن برای delete. نجات‌دهنده‌ی دست برای افرادی با محدودیت حرکتی انگشتان. پلاگینی برای ابزارهای interception (). شروع سریع (QUICK START) 1. چند نگاشت در /etc/interception/dual-function-keys/my-mappings.yaml ایجاد کنید. نمونه‌های زیادی در () وجود دارد. 2. پیکربندی udevmon مربوط به ابزارهای interception () خود را بسازید: /etc/interception/udevmon.d/my-keyboards.yaml. برای شروع می‌توانید از پیکربندی من استفاده کنید. 3. فعال‌سازی udevmon: sudo systemctl enable udevmon 4. راه‌اندازی (مجدد) udevmon: sudo systemctl restart udevmon 5. بررسی مشکلات: journalctl -u udevmon. بی‌خبری خوش‌خبری است (عدم نمایش پیام نشان‌دهنده عملکرد صحیح است). می‌توانید با خیال راحت از پیام‌های ignoring /etc/interception/udevmon.yaml, reason: bad file: /etc/interception/udevmon.yaml صرف‌نظر کنید. عملکرد (FUNCTIONALITY) در این مثال‌ها از کلید شیفت چپ (LS) استفاده خواهیم کرد. این کلید به‌گونه‌ای پیکربندی شده است که ضربه زدن به آن عمل delete (DE) و نگه داشتن آن عمل LS را انجام می‌دهد. - KEY: KEY_LEFTSHIFT TAP: KEY_DELETE HOLD: KEY_LEFTSHIFT ضربه زدن (Tap) فشردن و رها کردن کلید LS در بازه زمانی TAP_MILLIS (پیش‌فرض ۲۰۰ میلی‌ثانیه) برای عمل DE. به‌طور پیش‌فرض، تا زمان کامل شدن ضربه، LS دریافت می‌شود. برای مشاهده سایر گزینه‌ها به بخش‌های زیر مراجعه کنید. <---------200ms---------> <---------200ms---------> keyboard: LS↓ LS↑ LS↓ LS↑ computer sees: LS↓ LS↑ DE↓ DE↑ LS↓ LS↑ دو بار ضربه زدن (Double Tap) ضربه بزنید و سپس مجدداً در بازه DOUBLE_TAP_MILLIS (پیش‌فرض ۱۵۰ میلی‌ثانیه) فشار دهید تا DE نگه داشته شود. <-------150ms-------> <---------200ms---------> keyboard: LS↓ LS↑ LS↓ LS↑ computer sees: LS↓ LS↑ DE↓ DE↑ DE↓ ..(repeats).. DE↑ تا زمانی که در بازه زمانی DOUBLE_TAP_MILLIS باشید، می‌توانید به زدن ضربه‌های دوتایی ادامه دهید. مصرف شدن (Consumption) اگر کلید دیگری را در بازه زمانی TAP_MILLIS فشار داده یا رها کنید، عمل ضربه زدن (tap) انجام نخواهد شد. این قابلیت به‌ویژه برای کلیدهای تبدیل‌گر بسیار مفید است، برای مثال اجرای سریع ctrl-C. در این مثال، کلید a را در طول این بازه زمانی فشار می‌دهیم. ضربه دوتایی پس از مصرف شدن عمل نمی‌کند؛ ابتدا باید یک ضربه ساده بزنید. رویدادهای ماوس و تاچ‌پد (EV_REL و EV_ABS) نیز می‌توانند ضربه‌ها را مصرف کنند، با این حال باید از یک پیکربندی چنددستگاهی (Multiple Devices) استفاده کنید. <-------150ms-------> <---------200ms---------> <-------150ms-------> <---------200ms---------> keyboard: LS↓ a↓ a↑ LS↑ LS↓ LS↑ LS↓ computer sees: LS↓ a↓ a↑ LS↑ LS↓ LS↑ DE↓ DE↑ DE↓ ..(repeats).. نصب (INSTALLATION) مدیر بسته (Package Manager) [تصویر: وضعیت بسته‌بندی ()] () از کد منبع (From Source) وابستگی‌های زمان اجرا را ببینید (). ابتدا ابزارهای Interception Tools () را نصب کنید. git clone https://gitlab.com/interception/linux/plugins/dual-function-keys.git cd dual-function-keys make && sudo make install پیشوند نصب به‌طور پیش‌فرض /usr/local است. این مقدار را می‌توان در config.mk بازنویسی کرد..SH "پیکربندی (CONFIGURATION)" دو بخش برای پیکربندی وجود دارد: dual-function-keys و udevmon، که dual- function-keys را اجرا می‌کند. به مثال‌ها (https://gitlab.com/interception/linux/plugins/dual-function- keys/-/tree/master/doc/examples.md) که شامل پیکربندی‌های dual-function- keys و udevmon.yaml است مراجعه کنید. dual-function-keys این فایل yaml به طور معمول در /etc/interception/dual-function-keys قرار دارد. می‌توانید از کدهای کلید خام (عدد صحیح) استفاده کنید، با این حال استفاده از رشته‌های #define شده از input-event-codes.h (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h) آسان‌تر است. # optional TIMING: TAP_MILLISEC: DOUBLE_TAP_MILLISEC: SYNTHETIC_KEYS_PAUSE_MILLISEC: # necessary MAPPINGS: - KEY: TAP: [ , ... ] HOLD: [ , ... ] # optional HOLD_START: [ AFTER_PRESS | AFTER_RELEASE | BEFORE_CONSUME | BEFORE_CONSUME_OR_RELEASE ] - KEY: ... مثال ما از بخش پیشین به این صورت است: TIMING: TAP_MILLISEC: 200 DOUBLE_TAP_MILLISEC: 150 MAPPINGS: - KEY: KEY_LEFTSHIFT TAP: KEY_DELETE HOLD: KEY_LEFTSHIFT کلیدهای ترکیبی (Combo Keys) می‌توانید TAP را به عنوان یک “ترکیب (combo)” پیکربندی کنید، که چندین کلید را به ترتیب فشرده و سپس رها می‌کند، برای نمونه space cadet (: MAPPINGS: - KEY: KEY_LEFTSHIFT TAP: [ KEY_LEFTSHIFT, KEY_9, ] HOLD: KEY_LEFTSHIFT می‌توانید HOLD را به عنوان یک “ترکیب (combo)” پیکربندی کنید، که چندین کلید را به ترتیب فشرده و سپس رها می‌کند، برای نمونه کلید تبدیل‌کننده هایپر (hyper modifier): MAPPINGS: - KEY: KEY_TAB TAP: KEY_TAB HOLD: [ KEY_LEFTCTRL, KEY_LEFTMETA, KEY_LEFTALT, ] به‌طور پیش‌فرض، یک مکث ۲۰ میلی‌ثانیه‌ای بین کلیدها در “ترکیب” وجود خواهد داشت. این مقدار قابل تغییر است: TIMING: SYNTHETIC_KEYS_PAUSE_MILLISEC: 10 تغییر رفتار کلیدهای HOLD می‌توانید به صورت اختیاری از HOLD_START برای پیکربندی رفتار کلیدهای HOLD استفاده کنید. HOLD_START: AFTER_PRESS اگر HOLD_START مشخص نشده باشد، برابر AFTER_PRESS یا یک مقدار ناشناخته باشد، رفتار پیش‌فرض اعمال خواهد شد. HOLD_START: BEFORE_CONSUME کلیدهای HOLD پیش از مصرف شدن KEY فشرده می‌شوند، و هنگامی که KEY رها شود، رها می‌شوند. بنابراین هنگامی که روی KEY ضربه زده (tap) می‌شود، هیچ کلید اضافه‌ای به جز کلیدهای TAP ارسال نمی‌شود، در حالی که کلیدهای HOLD همچنان می‌توانند به عنوان کلیدهای تبدیل‌کننده (modifiers) استفاده شوند. MAPPINGS: - KEY: KEY_LEFTSHIFT TAP: KEY_DELETE HOLD: KEY_LEFTSHIFT HOLD_START: BEFORE_CONSUME <---------200ms---------> <---------200ms---------> keyboard: LS↓ LS↑ LS↓ LS↑ computer sees: DE↓ DE↑ <-------150ms-------> <---------200ms---------> <-------150ms-------> <---------200ms---------> keyboard: LS↓ a↓ a↑ LS↑ LS↓ LS↑ LS↓ computer sees: LS↓ a↓ a↑ LS↑ DE↓ DE↑ DE↓ ..(repeats).. HOLD_START: BEFORE_CONSUME_OR_RELEASE رفتار مشابه BEFORE_CONSUME است، با این تفاوت که وقتی KEY رها می‌شود و پیش از آن نه ضربه خورده و نه مصرف شده است، کلیدهای HOLD به ترتیب فشرده شده و سپس به ترتیب رها می‌شوند. MAPPINGS: - KEY: KEY_LEFTSHIFT TAP: KEY_DELETE HOLD: KEY_LEFTSHIFT HOLD_START: BEFORE_CONSUME_OR_RELEASE <---------200ms---------> <---------200ms---------> keyboard: LS↓ LS↑ LS↓ LS↑ computer sees: DE↓ DE↑ LS↓ LS↑ حالت نگه‌داشتن (Hold) تنها پس از رها شدن کلید آغاز می‌شود، به شرطی که زمان TAP_MILLISEC سپری شده باشد. این نوع شروع نگه‌داشتن تحت تأثیر هیچ نوع مصرف‌شدنی (consumption) قرار نمی‌گیرد. MAPPINGS: - KEY: KEY_A TAP: KEY_A HOLD: [KEY_LEFTSHIFT, KEY_A] HOLD_START: AFTER_RELEASE <---------200ms---------> <---------200ms---------> keyboard: a↓ a↑ a↓ a↑ computer sees: a↓ a↑ A↓ A↑ هشدار (Warning) یک کلید تبدیل‌گر (modifier) یکسان را به دو کلیدی که قصد دارید هم‌زمان فشار دهید اختصاص ندهید، چرا که با یکدیگر تداخل خواهند داشت. از نسخه‌های چپ و راست تبدیل‌گرها استفاده کنید؛ به عنوان مثال alt-tab با space-caps: MAPPINGS: - KEY: KEY_CAPSLOCK TAP: KEY_TAB HOLD: KEY_LEFTALT - KEY: KEY_SPACE TAP: KEY_SPACE HOLD: KEY_RIGHTALT در غیر این صورت، می‌توانید از HOLD_START: BEFORE_CONSUME یا HOLD_START: BEFORE_CONSUME_OR_RELEASE استفاده کنید و سپس اختصاص تبدیل‌گر یکسان بلامانع خواهد بود: MAPPINGS: - KEY: KEY_CAPSLOCK TAP: KEY_TAB HOLD: KEY_LEFTALT HOLD_START: BEFORE_CONSUME_OR_RELEASE - KEY: KEY_SPACE TAP: KEY_SPACE HOLD: KEY_LEFTALT HOLD_START: BEFORE_CONSUME_OR_RELEASE udevmon باید به udevmon اطلاع داده شود که می‌خواهیم از کلیدهای دوکاره (Dual Function Keys) استفاده کنیم. برای شرح کامل، بخش نحوه کار (https://gitlab.com/interception/linux/tools#how-it-works) را ببینید. - JOB: "intercept -g $DEVNODE | dual-function-keys -c | uinput -d $DEVNODE" DEVICE: NAME: نام دستگاه را می‌توان با اجرای دستور زیر مشخص کرد: sudo uinput -p -d /dev/input/by-id/X که در آن X دستگاهی است که نامی شبیه به صفحه‌کلید شما دارد. اطمینان حاصل کنید که تمام EV_KEYها در زیر بخش EVENTS وجود داشته باشند. اگر نمی‌توانید صفحه‌کلید خود را در /dev/input/by-id بیابید، دستگاه‌های موجود در /dev/input را مستقیماً بررسی کنید. برای اطلاعات بیشتر دربارهٔ uinput -p، به Interception Tools: How It Works (https://gitlab.com/interception/linux/tools#how-it-works) مراجعه کنید. معمولاً این نام برای شناسایی یکتای صفحه‌کلید کافی است، با این حال برخی صفحه‌کلیدها چندین دستگاه مانند یک ماوس مجازی را ثبت می‌کنند. می‌توانید dual-function-keys را برای همهٔ دستگاه‌ها اجرا کنید، اما ترجیح من اجرای آن صرفاً برای صفحه‌کلید واقعی است. فایل /etc/interception/udevmon.d/my-keyboards.yaml من: - JOB: "intercept -g $DEVNODE | dual-function-keys -c /etc/interception/dual-function-keys/home-row-modifiers.yaml | uinput -d $DEVNODE" DEVICE: NAME: "Minimalist Keyboard ABC" EVENTS: EV_KEY: [ KEY_LEFTSHIFT ] - JOB: "intercept -g $DEVNODE | dual-function-keys -c /etc/interception/dual-function-keys/thumb-cluster.yaml | uinput -d $DEVNODE" DEVICE: NAME: "Split Keyboard XYZ" EVENTS: EV_KEY: [ KEY_LEFTSHIFT ] چندین دستگاه (Multiple Devices) هنگام استفاده از ورودی‌های چند دستگاه مختلف، مثلاً ctrl-scroll، ممکن است برای اینکه dual-function-keys بین این دستگاه‌ها کار کند (مثلاً اسکرول، ctrl را مصرف کند)، تسهیم کردن (mux) دستگاه‌ها با یکدیگر (https://gitlab.com/interception/linux/tools#mux) لازم باشد. پیکربندی نمونه udevmon برای ماوس و صفحه‌کلید: - CMD: mux -c dfk -c my-keyboard -c my-mouse - JOB: - mux -i dfk | dual-function-keys -c /etc/interception/dual-function-keys/my-cfg.yaml | mux -o my-keyboard -o my-mouse - mux -i my-keyboard | uinput -c /etc/interception/udevmon.d/my-keyboard.yaml - mux -i my-mouse | uinput -c /etc/interception/udevmon.d/my-mouse.yaml - JOB: intercept -g $DEVNODE | mux -o dfk DEVICE: NAME: AT Translated Set 2 keyboard EVENTS: EV_KEY: [ KEY_LEFTCTRL ] - JOB: intercept -g $DEVNODE | mux -o dfk DEVICE: NAME: Razer Razer Naga Trinity EVENTS: EV_REL: [REL_WHEEL] EV_KEY: [BTN_LEFT] در مثال بالا، my-keyboard.yaml و my-mouse.yaml نمایانگر دستگاه‌های مجازی هستند که udevmon برای خروجی دادن رویدادها ایجاد خواهد کرد. آن‌ها یک‌بار از خود دستگاه تولید می‌شوند؛ به عنوان مثال: sudo uinput -p -d /dev/input/by-id/usb-my-keyboard-kbd > my-keyboard.yaml یک راهکار جایگزین، در صورتی که ریسک آن را می‌پذیرید (https://gitlab.com/interception/linux/plugins/dual-function- keys/-/issues/31#note_725722450)، این است که پیکربندی دستگاه مجازی را بی‌درنگ و در حین کار (on the fly) تولید کنید؛ به عنوان مثال: - CMD: mux -c dfk -c my-keyboard -c my-mouse - JOB: - mux -i dfk | dual-function-keys -c /etc/interception/dual-function-keys/my-cfg.yaml | mux -o my-keyboard -o my-mouse - mux -i my-keyboard | uinput -d /dev/input/by-path/my-keyboard-event-kbd - mux -i my-mouse | uinput -d /dev/input/by-id/usb-my-mouse-event-mouse - JOB: intercept -g $DEVNODE | mux -o dfk DEVICE: LINK: /dev/input/by-path/my-keyboard-event-kbd - JOB: intercept -g $DEVNODE | mux -o dfk DEVICE: LINK: /dev/input/by-id/usb-my-mouse-event-mouse همانند همیشه یک نکته وجود دارد: dual-function-keys بر روی keycodes خام عمل می‌کند، نه keysyms، آن‌گونه که توسط X11 یا Wayland دیده می‌شوند. اگر هر چیزی دارید که نگاشت keycode->keysym را دستکاری می‌کند، مانند XKB (https://www.x.org/wiki/XKB) یا xmodmap (https://wiki.archlinux.org/index.php/Xmodmap)، توجه داشته باشید که dual-function-keys پیش از آن‌ها اعمال می‌شود. برخی از کاربردهای رایج XKB که ممکن است در پیکربندی X11 شما یافت شوند: Option "XkbModel" "pc105" Option "XKbLayout" "us" Option "XkbVariant" "dvp" Option "XkbOptions" "caps:escape" پرسش‌های متداول (FAQ) موردی جدید برای استفاده دارم. آیا می‌توانید از آن پشتیبانی کنید؟ لطفاً یک issue ثبت کنید. dual-function-keys برای برطرف‌کردن نیازهای من ساخته شده است. بسیار علاقه‌مندم ایده‌های شما را بشنوم و به عملی‌شدن آن‌ها کمک کنم. مثل همیشه، از ارسال PR به‌گرمی استقبال می‌شود. می‌بینم که در udevmon خود از صفحه‌کلید اصلاح‌شدهٔ q.m.k HHKB استفاده می‌کنید. این صفحه‌کلید از QMK Firmware (https://qmk.fm) بهره می‌برد. چرا مستقیماً از Tap-Hold (https://docs.qmk.fm/#/tap_hold) استفاده نمی‌کنید؟ نکته‌سنجی خوبی بود! آن قابلیت در واقع عملکرد مشابهی با dual-function- keys ارائه می‌دهد. متأسفانه معایبی وجود دارد: 1. صفحه‌کلیدهای اندکی از QMK Firmware استفاده می‌کنند. 2. مشکلاتی در آن قابلیت وجود دارد، همان‌طور که در مستندات Tap-Hold (https://docs.qmk.fm) ذکر شده است. 3. این قابلیت نیازمند پردازنده‌ای سریع در صفحه‌کلید است. آزمایش‌های غیرعلمی من با یک Ergodox (~800 اسکن در ثانیه) و HHKB (~140) نشان داد که صفحه‌کلید کندتر، اسفنجی شده و دقت آن تا حد بلااستفاده بودن کاهش می‌یابد. چرا از xcape (https://github.com/alols/xcape) استفاده نمی‌کنید؟ برنامه xcape تنها قابلیت ساده tap/hold را ارائه می‌دهد. به نظر می‌رسد افزودن باقی قابلیت‌ها با استفاده از سازوکارهای XTestFakeKeyEvent آن بسیار دشوار (شاید غیرممکن؟) باشد. ترکیب کلیدهای من کار نمی‌کند اطمینان حاصل کنید که مدیر پنجره (window manager) شما این ترکیب کلید را رهگیری و مسدود نمی‌کند. من قابلیت دو بار فشردن (Double Tap) را نمی‌خواهم مقدار DOUBLE_TAP_MILLISEC را برابر با 0 قرار دهید. بخش Key Combinations, No Double Tap (https://gitlab.com/interception/linux/plugins/dual-function- keys/-/blob/master/doc/examples.md#key-combinations-no-double-tap) را ببینید. مشارکت‌کنندگان (CONTRIBUTORS) لطفاً این مخزن را فورک کرده و یک PR ارسال کنید. اگر در حال ایجاد تغییرات در مستندات هستید، لطفاً فایل pandoc با نام dual-function-keys.md را ویرایش کرده و دستور make doc را اجرا کنید. لطفاً مطمئن شوید که این README.md و صفحه راهنما dual-function-keys.1 دارای تغییرات شما هستند و هر سه را کامیت کنید. می‌توانید صفحه راهنمای تولیدشده را با دستور man -l dual-function-keys.1 آزمایش کنید. همانند همیشه، لطفاً قواعد .editorconfig را رعایت فرمایید. مجوز (LICENSE) کپی‌رایت © 2020 Alexander Courtis نویسندگان (AUTHORS) Alexander Courtis. Dual Function Keys 2020/12/25 DUAL-FUNCTION-KEYS(1)