<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fa"><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://zmim.ir/feed.xml" rel="self" type="application/atom+xml" /><link href="https://zmim.ir/" rel="alternate" type="text/html" hreflang="fa" /><updated>2026-05-09T11:36:52+03:30</updated><id>https://zmim.ir/feed.xml</id><title type="html">محمد زینلی</title><subtitle>یادداشت‌های محمد زینلی   &lt;a href=&quot;https://github.com/piharpi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@github&lt;/a&gt;.</subtitle><author><name>محمد زینلی</name><email>m@zmim.ir</email></author><entry xml:lang="fa"><title type="html">جنگ نوشته</title><link href="https://zmim.ir/reflections-on-war/" rel="alternate" type="text/html" title="جنگ نوشته" /><published>2026-04-05T15:50:00+03:30</published><updated>2026-04-05T15:50:00+03:30</updated><id>https://zmim.ir/reflections-on-war</id><content type="html" xml:base="https://zmim.ir/reflections-on-war/"><![CDATA[<p>این یادداشت کوتاه را برای یک استوری در اینستاگرام نوشتم و به تشویق یکی از دوستان اینجا هم می‌گذارمش.</p>

<p>من به شخصه آینده روشنی در پس این جنگ برای ایران نمی‌بینم. نه چشم‌انداز روشنی برای اصلاح رفتار و ساختار حکومت می‌بینم، نه افقی روشن برای یک تغییر اساسی در نظام حکمرانی کشور. به همین دلیل، خیلی صریح و بدون واهمه از قضاوت یا کوبیده شدن توسط موافقان جنگ می‌گویم که من با مداخله نظامی به این شکل موافق نبودم.
اما حالا که این اتفاق رخ داده، پرسش اصلی برای من دیگر این نیست که چه موضعی درست‌تر بوده، بلکه این است که در دل این جنگ و در فردای آن، چه باید کرد.</p>

<p>برای من، مهم‌ترین مساله در این لحظه نه اثبات حقانیت یک موضع، بلکه تلاش برای فهمیدن پیچیدگی موقعیتی است که در آن قرار گرفته‌ایم.</p>

<p>برای خیلی‌ها دفاع از مداخله نظامی به این معنا نیست که جنگ هیچ هزینه‌ای برای مردم ندارد و حتی به این معنا نیست که حتما در صورت مداخله اوضاع بهتر می‌شود. بسیاری از کسانی که موافق این مداخله هستند، کاملا می‌پذیرند که ممکن است اوضاع حتی بدتر هم بشود. بحث بر سر این نیست که «هر چه بشود بهتر است»، بلکه دقیقا بر سر انتخاب میان چند سناریوی بد است.</p>

<p>یک سناریو، تداوم وضعیت موجود است؛ با هزینه‌های انباشته سرکوب، فرسایش اقتصادی، مهاجرت گسترده، انسداد سیاسی و اجتماعی، و روندی که در بلندمدت می‌تواند به فروپاشی‌های کنترل‌نشده منجر شود.</p>

<p>سناریوی دیگر، مداخله نظامی است؛ با همه ریسک‌های جدی آن: بی‌ثباتی، خشونت، تلفات انسانی، و حتی احتمال تکرار تجربه‌هایی شبیه عراق، سوریه یا لیبی.</p>

<p>استدلال موافقان مداخله این نیست که این ریسک‌ها وجود ندارد، بلکه این است که هزینه‌های سناریوی اول برای آن‌ها قطعی، مستمر و رو به افزایش است، در حالی که سناریوی دوم، با وجود ریسک بالا، یک امکان گسست و تغییر واقعی را باز می‌کند.</p>

<p>در واقع، برای این گروه، مساله انتخاب میان «زوال تدریجی تقریبا قطعی» و «ریسک یک جهش پرهزینه با احتمال تغییر» است.</p>

<p>ممکن است کسی این قمار را نپذیرد، و این موضع کاملا قابل احترام و قابل دفاع است. اما اگر کسی آن را بپذیرد، موضعش لزوما از جنس توهم یا بی‌توجهی به رنج مردم نیست؛ بلکه از جنس ترجیح دادن یک ریسک بزرگ به یک بن‌بست فرساینده است.</p>

<p>در عین حال، به همان اندازه باید گفت که نظر مخالفان جنگ هم کاملا قابل درک است.</p>

<p>مخالفت با جنگ به معنای دفاع از وضعیت موجود نیست. بسیاری از مخالفان، بیش از هر چیز نگران ویرانی اجتماعی، فروپاشی نهادها، گسترش خشونت و رنجی هستند که ممکن است نسل‌ها ادامه پیدا کند. تجربه تاریخی منطقه این ترس را برایشان کاملا واقعی کرده است.</p>

<p>اما شاید تصویر جامعه ایران را هم نتوان تنها در قالب این دو نگرانی توضیح داد. در کنار کسانی که تغییرات بنیادین را، با همه ریسک‌هایش، تنها راه گریز از فرسایش می‌بینند، و در کنار کسانی که از فروپاشی و بی‌ثباتی هراس دارند، بخش قابل توجهی از جامعه نیز همچنان به جمهوری اسلامی و ایده سیاسی و تاریخی پشت آن باور دارد. برای این گروه، جمهوری اسلامی صرفا یک حکومت مستقر نیست، بلکه بخشی از هویت سیاسی، دینی یا تاریخی آن‌هاست؛ چیزی که بقایش را با استقلال، ثبات یا حتی معنای ایران معاصر گره‌خورده می‌بینند. به همین دلیل، افق آینده را نه در فروپاشی کامل این نظم، بلکه در تداوم، بازسازی یا اصلاح آن جست‌وجو می‌کنند.</p>

<p>به‌نظرم بخش مهمی از تفاوت این دیدگاه‌ها، نه از ناآگاهی یا بی‌اخلاقی یک طرف، بلکه از تفاوت در تجربه زیسته و زاویه نگاه آن‌ها می‌آید.</p>

<p>کسی که سال‌ها فرسایش تدریجی زندگی، سرکوب، ناامیدی و انسداد را به‌عنوان خطر اصلی تجربه کرده، ممکن است ریسک یک گسست بزرگ را قابل تحمل‌تر ببیند.</p>

<p>در مقابل، کسی که فروپاشی اجتماعی، جنگ داخلی، آوارگی و ویرانی منطقه را خطر نزدیک‌تر می‌بیند، طبیعی است که با هر نوع مداخله نظامی مخالفت کند.</p>

<p>و در سوی دیگر، کسانی هم هستند که با وجود همه بحران‌ها، ناکارآمدی‌ها و نارضایتی‌ها، همچنان از جمهوری اسلامی دفاع می‌کنند و حاضرند برای حفظ آن هزینه بدهند؛ نه لزوما چون همه وضعیت موجود را مطلوب می‌دانند، بلکه چون فروپاشی این نظم را مساوی با فروپاشی نوعی هویت سیاسی، تاریخی یا حتی امنیت جمعی می‌بینند. نادیده گرفتن این بخش از جامعه، حتی اگر کسی با آن همدل نباشد، فهم ما از نیروهای واقعی و مسیرهای ممکن آینده ایران را ناقص می‌کند.</p>

<p>این اختلاف، بیش از آنکه نزاعی ساده میان درست و غلط باشد، اختلاف بر سر این است که هر گروه کدام نوع خطر را واقعی‌تر، فوری‌تر و تحمل‌ناپذیرتر می‌بیند.</p>

<p>اشکال اصلی جایی شروع می‌شود که هر دو طرف، موضع طرف مقابل را به یک کاریکاتور تقلیل می‌دهند.</p>

<p>اینکه نظر موافقان مداخله نظامی به «بدتر از این نمی‌شود» یا «جنگ هیچ هزینه‌ای ندارد» فروکاسته شود، همان‌قدر نادرست است که نظر مخالفان جنگ به «دفاع از جمهوری اسلامی» یا «رضایت از وضعیت موجود» تقلیل داده شود.</p>

<p>وقتی پیچیدگی و گوناگونی آدم‌های موافق و مخالف حذف می‌شود، نقد کردن موضع آن‌ها راحت‌تر می‌شود، اما دیگر نقدِ نسخه واقعی آن موضع نیست؛ نقد یک تصویر ساده‌شده و ناقص است.</p>

<p>شاید یکی از مهم‌ترین کارهایی که باید همین امروز، در دل این بحران و در اوج شکاف‌ها و خشم‌ها انجام شود، ساختن یک گفتار مشترک برای باهم‌زیستن باشد.</p>

<p>گفتاری که از ضرورت تاریخی برپایی دوباره ایران بر محور ایده باهم‌زیستن دفاع کند؛
اینکه با وجود همه اختلاف‌های عمیق، خشم‌ها، زخم‌ها و تجربه‌های متفاوت، آینده‌ای برای این سرزمین بدون پذیرش تکثر دیدگاه‌ها و بدون امکان زندگی در کنار یکدیگر ساخته نمی‌شود.</p>

<p>اگر قرار است از این وضعیت عبور کنیم، این عبور فقط سیاسی نیست؛
باید دوباره یاد بگیریم که همدیگر را بفهمیم، پیش از آنکه یکدیگر را حذف کنیم.</p>

<p>شاید مهم‌ترین وظیفه امروز ما همین باشد:
حفظ امکان باهم‌ماندن، حتی در اوج اختلاف.</p>

<p>چون ایرانِ پس از جنگ، هر شکلی که به خود بگیرد، ناگزیر خانه مشترک همه ما خواهد بود؛
و اگر زبان گفت‌وگو و امکان باهم‌زیستن را از همین امروز نسازیم، هیچ تغییر سیاسی به‌تنهایی آینده‌ای روشن برای این سرزمین نخواهد ساخت.</p>

<p>آینده ایران نه فقط در میدان سیاست، که در توان ما برای باهم‌ماندن، باهم‌شنیدن و باهم‌ساختن رقم می‌خورد.</p>]]></content><author><name>محمد زینلی</name><email>m@zmim.ir</email></author><summary type="html"><![CDATA[یادداشتی کوتاه درباره جنگ]]></summary></entry><entry xml:lang="fa"><title type="html">چرا پیام از داخل ایران راحت‌تر به خارج می‌رسد؟</title><link href="https://zmim.ir/inbound-outbound/" rel="alternate" type="text/html" title="چرا پیام از داخل ایران راحت‌تر به خارج می‌رسد؟" /><published>2026-01-24T12:10:00+03:30</published><updated>2026-01-24T12:10:00+03:30</updated><id>https://zmim.ir/inbound-outbound</id><content type="html" xml:base="https://zmim.ir/inbound-outbound/"><![CDATA[<p>متاسفانه حدود دو هفته است که ارتباط اینترنت ایران قطع شده و خبرهای ناگواری باعث شده هیچ کدام ما حال و روز خوبی نداشته باشیم. دسترسی آزاد به اینترنت از حقوق اولیه و اساسی همه انسان‌هاست. به امید روزهای بهتر.</p>

<p>اینجا قصد دارم توضیح بدهم که چرا پس از برقراری محدود و مختصر ارتباط پیامهای ارسالی از داخل ایران راحت‌تر در خارج از کشور دریافت می‌شوند و معمولا مسیر برگشت یعنی پیام‌هایی که از خارج از ایران ارسال می‌شوند سخت‌تر به مقصد می‌رسند.</p>

<h1 id="نامتقارن-شدن-مسیرهای-اینترنت-asymmetric-routing">نامتقارن شدن مسیرهای اینترنت (Asymmetric Routing)</h1>

<p>در شرایط بحران یا محدودسازی، مسیرهای اینترنت معمولاً نامتقارن می‌شوند. یعنی مسیر خروجی از ایران (ارسال داده به خارج) کمتر محدود می‌شود، اما مسیر ورودی به ایران (دریافت داده از خارج) شدیدتر فیلتر یا مسدود می‌شود. دلیلش این است که کنترل اطلاعات ورودی برای سیستم‌های نظارتی اهمیت بیشتری دارد.</p>

<p>به زبان ساده، «فرستادن» راحت‌تر از «دریافت کردن» می‌شود. نتیجه این نامتقارن بودن این است که درخواست از داخل کشور می‌رود، اما پاسخ از خارج ممکن است هرگز برنگردد.</p>

<p>مسیرهای اینترنت در زمان قطعی نامتقارن (Asymmetric Routing) می‌شوند. مسیر خروجی از ایران معمولاً بازتر است ولی مسیر ورودی بیشتر محدود می‌شود. از طرف دیگر فیلترشکن‌ها و VPNها در اینترنت ناپایدار سخت‌تر می‌توانند ارتباط ورودی را دوباره برقرار کنند، مخصوصاً اگر UDP باشند یا keep-alive ضعیفی داشته باشند. البته DNS و سرورهای خارجی هم گاهی جواب را از مسیری می‌فرستند که راه برگشتش به ایران بسته است.</p>

<h1 id="فایروال-stateless-بدون-وضعیت">فایروال stateless (بدون وضعیت)</h1>

<p>فایروال stateless هر بسته اینترنت را کاملاً مستقل بررسی می‌کند. یعنی برایش مهم نیست قبل از این بسته چه چیزی رد و بدل شده است. فقط نگاه می‌کند این بسته با قوانین تعریف‌ شده هم‌خوانی دارد یا نه.</p>

<h2 id="مزایا">مزایا</h2>

<p>سادگی مهم‌ترین مزیت این نوع فایروال است. پیاده‌سازی آن راحت است، مصرف منابع کمی دارد و سرعت پردازش بالاست. به همین دلیل برای روترهای ساده یا شبکه‌هایی که حجم ترافیک بسیار بالایی دارند مناسب است.</p>

<h2 id="معایب">معایب</h2>

<p>مشکل اصلی این فایروال این است که «کانتکست» ندارد. نمی‌فهمد یک بسته ادامه چه ارتباطی است. به همین دلیل قوانینش یا باید خیلی باز باشند (که امنیت را کم می‌کند) یا خیلی سخت‌گیرانه (که باعث قطع ارتباط‌های سالم می‌شود) و برای کنترل دقیق ترافیک ورودی چندان مناسب نیست.</p>

<h1 id="فایروال-stateful-دارای-وضعیت">فایروال stateful (دارای وضعیت)</h1>

<p>فایروال stateful برخلاف stateless، حافظه دارد. وقتی یک ارتباط از داخل شبکه شروع می‌شود، فایروال آن را در جدولی به نام state table ثبت می‌کند. از آن به بعد فقط بسته‌هایی اجازه عبور دارند که ادامه همان ارتباط ثبت‌شده باشند.</p>

<p>اگر بسته‌ای از خارج وارد شود که هیچ ارتباط قبلی برایش وجود نداشته باشد، فایروال آن را مشکوک تلقی می‌کند و معمولاً مسدود می‌کند.</p>

<h2 id="مزایا-1">مزایا</h2>

<p>امنیت بالاتر مهم‌ترین مزیت فایروال stateful است. چون فقط اجازه ادامه ارتباط‌هایی را می‌دهد که «قانونی» شروع شده‌اند. کنترل ترافیک ورودی بسیار دقیق‌تر است و احتمال سوءاستفاده کمتر می‌شود.</p>

<h2 id="معایب-1">معایب</h2>

<p>این نوع فایروال پیچیده‌تر است و منابع بیشتری مصرف می‌کند. علاوه بر این، به ناپایداری شبکه حساس است. اگر ارتباط قطع و وصل شود یا بسته‌ای گم شود، ممکن است state پاک شود و بسته‌های بعدی به‌اشتباه مسدود شوند.</p>

<h1 id="مقایسه-خلاصه-stateless-و-stateful">مقایسه خلاصه stateless و stateful</h1>

<p>به طور خلاصه، stateless ساده و سریع است ولی دیدی نسبت به ارتباط ندارد. stateful هوشمندتر و امن‌تر است اما در اینترنت ناپایدار می‌تواند باعث قطع ارتباط‌های سالم شود. در محدودیت‌های اینترنت ایران بیشتر از فایروال‌های stateful استفاده می‌شود، چون کنترل ترافیک ورودی برایشان اولویت دارد.</p>

<p>در محدودیت‌های اینترنت ایران احتمالا بیشتر از فایروال stateful استفاده می‌شود، یعنی اگر ارتباط از داخل کشور شروع بشود، جوابش از خارج راحت‌تر برمی‌گرده، اما اگر کسی از خارج بخواهد بدون شروع قبلی به داخل پیام بفرستد، معمولاً فایروال مسدودش می‌کند.</p>

<p>برای همین پیام‌هایی که از داخل به خارج فرستاده می‌شوند، شانس رسیدن بیشتری دارند تا پیام‌هایی که از خارج به داخل ارسال می‌شوند.</p>

<h1 id="tcp-و-پیام‌های-اصلی-آن">TCP و پیام‌های اصلی آن</h1>

<p>بیشتر ارتباط‌های اینترنتی (وب، پیام‌رسان‌ها، ایمیل) روی پروتکلی به نام TCP انجام می‌شوند. TCP قبل از ارسال داده یک فرایند مشخص برای برقراری ارتباط دارد.</p>

<p>ابتدا بسته‌ای به نام SYN ارسال می‌شود که یعنی «می‌خواهم ارتباط برقرار کنم». طرف مقابل با SYN-ACK جواب می‌دهد، یعنی «درخواستت را گرفتم و آماده‌ام». سپس فرستنده با ACK تأیید می‌کند و ارتباط برقرار می‌شود. بعد از آن داده‌های واقعی یا DATA رد و بدل می‌شوند. در پایان، یکی از دو طرف با FIN اعلام می‌کند که ارتباط تمام شده و اتصال بسته می‌شود.</p>

<p>این ساختار مشخص باعث می‌شود فایروال‌های stateful بتوانند تشخیص دهند کدام ارتباط معتبر است.</p>

<div style="text-align: center;">
    <img src="udp-tcp.jpg" style="max-width: 80%; margin: 10px;" alt="مقایسه UDP و TCP" />
</div>

<h1 id="udp-و-مفهوم-pseudo-state">UDP و مفهوم pseudo-state</h1>

<p>UDP برخلاف TCP هیچ‌کدام از این مراحل را ندارد. نه شروع مشخصی دارد، نه تأیید، نه پایان. هر بسته UDP مستقل ارسال می‌شود، بدون اینکه طرف مقابل حتماً پاسخی بدهد.</p>

<p>برای اینکه UDP به‌طور کامل مسدود نشود، فایروال‌های stateful چیزی به نام pseudo-state می‌سازند. یعنی اگر از داخل شبکه یک بسته UDP به مقصدی خاص ارسال شود، فایروال برای مدت کوتاهی اجازه می‌دهد پاسخ از همان مقصد برگردد. اگر این زمان تمام شود یا اینترنت ناپایدار باشد، بسته‌های بعدی که از خارج می‌آیند دیگر معتبر شناخته نمی‌شوند و drop می‌شوند.</p>

<p>به همین دلیل ارتباط‌های مبتنی بر UDP، مثل بعضی VPNها، تماس‌های صوتی و تصویری، در شرایط قطع و وصل اینترنت خیلی زود ناپایدار می‌شوند.</p>

<h1 id="جمع‌بندی">جمع‌بندی</h1>

<p>اینکه پیام از داخل ایران به خارج راحت‌تر می‌رسد اما از خارج به داخل نه، نتیجه ترکیب چند عامل است: نامتقارن شدن مسیرهای اینترنت، استفاده گسترده از فایروال‌های stateful، حساسیت این فایروال‌ها به ناپایداری شبکه، و تفاوت ذاتی TCP و UDP. این رفتار نه باگ است و نه تصادفی، بلکه حاصل طراحی و سیاست‌گذاری در سطح زیرساخت شبکه است.</p>]]></content><author><name>محمد زینلی</name><email>m@zmim.ir</email></author><category term="network" /><category term="internet" /><category term="freedom" /><summary type="html"><![CDATA[در زمان قطعی یا محدودیت شدید اینترنت در ایران، خیلی‌ها تجربه می‌کنند که پیام‌هایی که از داخل کشور به خارج ارسال می‌شوند معمولاً راحت‌تر می‌رسند، اما پیام‌هایی که از خارج به داخل می‌آیند یا دیر می‌رسند یا اصلاً نمی‌رسند. این رفتار اتفاقی یا تصادفی نیست و ریشه در نحوه طراحی شبکه، نوع فیلترینگ، و تفاوت پروتکل‌های اینترنت دارد.]]></summary></entry><entry xml:lang="fa"><title type="html">مدیریت فایل‌های تنظیمات با استفاده از Git bare</title><link href="https://zmim.ir/dotfiles-git/" rel="alternate" type="text/html" title="مدیریت فایل‌های تنظیمات با استفاده از Git bare" /><published>2023-07-01T21:10:00+03:30</published><updated>2023-07-01T21:10:00+03:30</updated><id>https://zmim.ir/How-to-manage-dotfiles-with-git-bare-repo</id><content type="html" xml:base="https://zmim.ir/dotfiles-git/"><![CDATA[<h1 id="دات‌فایل‌ها">دات‌فایل‌ها</h1>

<p>یکی از بزرگترین مزایای استفاده از گنو/لینوکس قابلیت شخصی سازی آن است. بسیاری از کاربران شخصی سازی را با تغییر فایل‌های تنظیمات انجام می‌دهند.
 به مرور که از سیستم استفاده می‌کنیم، این فایل‌ها پیوسته تغییر می‌کنند و وقتی تعداد آنها زیاد شود و شما روی سیستم‌های مختلف از آنها استفاده کنید، مدیریت این فایل‌ها دشوارتر می‌شود.
 یکی از بهترین روش‌ها برای مدیریت این فایل‌ها استفاده از <code class="language-plaintext highlighter-rouge">Git</code> است.</p>

<h1 id="ویندو-منیجرها-و-بزرگترین-مزیتشان-قابلیت-شخصی-سازی">ویندو منیجرها و بزرگترین مزیتشان: قابلیت شخصی سازی</h1>

<p>من مدت‌هاست که از گنو/لینوکس روی سیستم‌های شخصی استفاده می‌کنم و سال‌هاست که استفاده از ویندو منیجر‌ّهای مینیمال را به محیط‌های دسکتاپ بزرگ مثل گنوم و کی‌دی‌ای ترجیح می‌دهم.
استفاده از ویندو منیجرها سبب شده که سیستم من سبک‌تر باشد و برای استفاده من کاملا شخصی سازی شده باشد.</p>

<p>هنگامی که شما به جای دسکتاپ‌های بزرگ از ویندو منیجرها استفاده می‌کنید، بسیاری از تنظیمات سیستم و ابزارها را خودتان باید انجام دهید.</p>

<p>این کار سبب می‌شود که شما سیستمی که از آن استفاده می‌کنید را بهتر بشناسید و بسته به نیازتان آن را تغییر بدهید.</p>

<p>مدیریت فایل‌های تنظیمات برای استفاده از آنها روی سیستم‌های مختلف با سخت‌افزار و سیستم عامل‌های متفاوت ممکن است دشوار به نظر برسد. استفاده از <code class="language-plaintext highlighter-rouge">Git bare repository</code> یکی از بهترین و هوشمندانه‌ترین راه‌ها برای این کار است. از آنجا که بیشتر ما برای مدیریت پروژه‌هامان از <code class="language-plaintext highlighter-rouge">Git</code> استفاده می‌کنیم، این کار نیاز به نصب ابزار تازه و یاد گرفتن آن ندارد.</p>

<h1 id="سایر-ابزارها">سایر ابزارها</h1>

<p>ابزارهای بسیاری برای مدیریت دات‌فایل‌ها وجود دارد. معروفترین آنها شاید <a href="https://www.gnu.org/software/stow/" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">GNU Stow</code></a> باشد. لیستی از این ابزارها را می‌توانید <a href="https://dotfiles.github.io/utilities" target="_blank" rel="noopener noreferrer">اینجا</a> یا در <a href="https://wiki.archlinux.org/title/Dotfiles#Tools" target="_blank" rel="noopener noreferrer">ویکی آرچ</a> ببینید.</p>

<h1 id="روش-git-bare-repo">روش <code class="language-plaintext highlighter-rouge">Git bare repo</code></h1>

<p>اولین جایی که من این روش بسیار هوشمندانه را پیدا کردم در <a href="https://news.ycombinator.com/item?id=11070797">این گفتگوی هکر نیوز</a> بود. پس از آن جاهای مختلفی درباره آن خواندم و تصمیم گرفتم از این روش برای مدیریت دات‌فایل‌ها استفاده کنم.</p>

<h2 id="مزایا">مزایا</h2>

<ul>
  <li>بدون نیاز به نصب ابزار اضافی</li>
  <li>از symlink استفاده نمی‌کنید.</li>
  <li>فایل‌ها در یک ریپوزیتوری <code class="language-plaintext highlighter-rouge">Git</code> مدیریت می‌شوند.</li>
  <li>می‌توانید از شاخه‌های مختلف برای سیستم‌های‌ مختلف استفاده کنید.</li>
  <li>می‌توانید پیکربندی خود را به راحتی هنگام نصب سیستم جدید تکرار کنید.</li>
</ul>

<h2 id="چطور-کار-می‌کند">چطور کار می‌کند؟</h2>

<p>در این روش مخزن <code class="language-plaintext highlighter-rouge">Git bare</code> در یک پوشه جانبی (مانند ‪$HOME/.cfg‬ یا ‪$HOME/.myconfig‬) ذخیره می‌شود. با استفاده از یک <code class="language-plaintext highlighter-rouge">alias</code> ویژه دستورهای <code class="language-plaintext highlighter-rouge">Git</code> روی این پوشه جانبی اجرا می‌شوند و تداخلی با دات‌فایل‌ها و بقیه مخزن‌های <code class="language-plaintext highlighter-rouge">Git</code> نخواهند داشت.</p>

<h2 id="آغاز-از-صفر">آغاز از صفر</h2>

<p>اگر پیش از این پیکربندی‌های خود را در یک مخزن <code class="language-plaintext highlighter-rouge">Git</code> ردیابی نکرده‌اید، می‌توانید با این فرمان‌ها به راحتی از این روش استفاده کنید:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">git init <span class="nt">--bare</span> <span class="nv">$HOME</span>/.cfg
<span class="nb">alias </span><span class="nv">config</span><span class="o">=</span><span class="s1">'/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'</span>
config config <span class="nt">--local</span> status.showUntrackedFiles no
<span class="nb">echo</span> <span class="s2">"alias config='/usr/bin/git --git-dir=</span><span class="nv">$HOME</span><span class="s2">/.cfg/ --work-tree=</span><span class="nv">$HOME</span><span class="s2">'"</span> <span class="o">&gt;&gt;</span> <span class="nv">$HOME</span>/.config/shell/.aliasrc</code></pre></figure>

</div>

<p>فرمان نخست یک پوشه در مسیر <code class="language-plaintext highlighter-rouge">‪~/.cfg‬</code> ایجاد می کند که یک مخزن <a href="http://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/"><code class="language-plaintext highlighter-rouge">Git bare</code></a> است که فایل‌های ما را ردیابی می‌کند.</p>

<p>سپس یک <code class="language-plaintext highlighter-rouge">alias</code> می‌سازیم تا هر گاه می‌خواهیم با مخزن دات‌فایل‌ها تعامل داشته باشیم به جای <code class="language-plaintext highlighter-rouge">git</code> معمولی از آن استفاده کنیم.</p>

<p>ما یک فلگ محلی برای مخفی کردن فایل‌هایی که هنوز آنها را ردیابی نمی‌کنیم تنظیم می‌کنیم. چون پس از این وقتی وضعیت پیکربندی و سایر فرمان‌ها را تایپ می‌کنید، فایل‌هایی که علاقه‌ای به ردیابی آنها ندارید به‌عنوان ردیابی نشده نشان داده نشوند.
من ترجیح می‌دهم به جای این کار از فرمان <code class="language-plaintext highlighter-rouge">echo "*" &gt; ~/.gitignore</code> استفاده کنم. در این صورت برای اضافه کردن فایل‌ها باید از فلگ <code class="language-plaintext highlighter-rouge">‪-f‬</code> در فرمان‌های <code class="language-plaintext highlighter-rouge">config</code> استفاده کنیم مثلا: <code class="language-plaintext highlighter-rouge">config add -f .dotfile</code>. این کمک می‌کند که ناخواسته با فرمان <code class="language-plaintext highlighter-rouge">‪config add .‬</code> فایل‌های اضافی افزوده و کامیت نشوند.</p>

<p>من از <code class="language-plaintext highlighter-rouge">zsh</code> استفاده می‌کنم و فایل <code class="language-plaintext highlighter-rouge">‪~/.config/shell/aliasrc‬</code> را در <code class="language-plaintext highlighter-rouge">‪.zshrc‬</code> سورس کرده‌ام. دقت کنید که اگر شما از شل دیگری استفاده می‌کنید در خط چهارم <code class="language-plaintext highlighter-rouge">alias</code> را برای آن شل اضافه کنید:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="c"># for bash</span>
<span class="nb">echo</span> <span class="s2">"alias config='/usr/bin/git --git-dir=</span><span class="nv">$HOME</span><span class="s2">/.cfg/ --work-tree=</span><span class="nv">$HOME</span><span class="s2">'"</span> <span class="o">&gt;&gt;</span> <span class="nv">$HOME</span>/.bashrc

<span class="c"># for zsh </span>
<span class="nb">echo</span> <span class="s2">"alias config='/usr/bin/git --git-dir=</span><span class="nv">$HOME</span><span class="s2">/.cfg/ --work-tree=</span><span class="nv">$HOME</span><span class="s2">'"</span> <span class="o">&gt;&gt;</span> <span class="nv">$HOME</span>/.config/zsh/.zshrc</code></pre></figure>

</div>

<p>برای <code class="language-plaintext highlighter-rouge">fish</code> می‌توانید از این تابع استفاده کنید:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="k">function </span>config <span class="nt">-w</span> git <span class="nt">-d</span> <span class="s2">"Manages dotfiles"</span>
    git <span class="nt">--git-dir</span><span class="o">=</span><span class="nv">$HOME</span>/.dot <span class="nt">--work-tree</span><span class="o">=</span><span class="nv">$HOME</span> <span class="nv">$argv</span>
end</code></pre></figure>

</div>

<h2 id="نصب-فایل‌ها-روی-سیستم-جدید-و-یا-استفاده-از-این-روش-برای-فایل‌های-فعلی">نصب فایل‌ها روی سیستم جدید و یا استفاده از این روش برای فایل‌های فعلی</h2>

<p>اگر پیش از این پیکربندی‌های خود را در یک مخزن <code class="language-plaintext highlighter-rouge">Git</code> ذخیره کرده‌اید، در یک سیستم جدید می‌توانید با مراحل زیر به این روش مهاجرت کنید:</p>

<p>پیش از نصب مطمئن شوید که <code class="language-plaintext highlighter-rouge">alias</code> را در ریپوزیتوریتان به <code class="language-plaintext highlighter-rouge">‪.bashrc‬</code> یا <code class="language-plaintext highlighter-rouge">‪.zshrc‬</code> اضافه کردید.</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">echo</span> <span class="s2">"alias config='/usr/bin/git --git-dir=</span><span class="nv">$HOME</span><span class="s2">/.cfg/ --work-tree=</span><span class="nv">$HOME</span><span class="s2">'"</span> <span class="o">&gt;&gt;</span> <span class="nv">$HOME</span>/.config/shell/.aliasrc</code></pre></figure>

</div>

<p>و اینکه مخزن منبع شما پوشه‌ای را که به عنوان <code class="language-plaintext highlighter-rouge">git bare</code>  استفاده می‌کنید نادیده می‌گیرد تا مشکلات عجیب و غریب برایتان پیش نیاید: <code class="language-plaintext highlighter-rouge">echo ".cfg" &gt;&gt; ~/.gitignore</code> یا آنطور که در بالا اشاره کردم: <code class="language-plaintext highlighter-rouge">echo "*" &gt;&gt; ~/.gitignore</code></p>

<p>اکنون ریپوزیتوری پیکربندی‌هایتان را در یک مخزن <code class="language-plaintext highlighter-rouge">bare</code> در پوشه‌ای مخفی در مسیر <code class="language-plaintext highlighter-rouge">‪$HOME/.cfg‬</code> کلون کنید:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">git clone <span class="nt">--bare</span> &lt;git-repo-url&gt; <span class="nv">$HOME</span>/.cfg</code></pre></figure>

</div>

<p>حال <code class="language-plaintext highlighter-rouge">alias</code> را در شلی که باز کرده‌این تعریف کنید تا بتوانید از آن استفاده کنید:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">alias </span><span class="nv">config</span><span class="o">=</span><span class="s1">'/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'</span></code></pre></figure>

</div>

<p>فایل‌های اصلی را با استفاده از فرمان <code class="language-plaintext highlighter-rouge">config checkout</code> جایگذاری کنید. من از شاخه <code class="language-plaintext highlighter-rouge">home</code> در <a href="https://github.com/mhdzli/dotfiles/tree/home" target="_blank" rel="noopener noreferrer">ریپوزیتوری خودم</a> برای ذخیره این فایل‌ها استفاده می‌کنم بنابر این برای من این فرمان به این شکل خواهد بود: <code class="language-plaintext highlighter-rouge">config checkout home</code>. اگر شما برای سیستم‌های مختلف از شاخه‌های مختلف استفاده می‌کنید دقت کنید که فایل‌های درست را جایگذاری کنید.</p>

<p>در صورتی که پیشتر فایل‌های پیکربندی مشابه در پوشه خانه سیستم داشته باشید دستور بالا اجرا نشده و خطا می‌دهد.
باید این فایل‌ها را از پوشه خانه پاک یا جابجا کنید. لیست کل فایل‌هایی که در ریپوزیتوری دارید را می‌توانید با این دستور ببینید:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">config ls-tree <span class="nt">--full-tree</span> <span class="nt">--name-only</span> <span class="nt">-r</span> &lt;YOUR BRANCH&gt; 

<span class="c">#for me</span>
config ls-tree <span class="nt">--full-tree</span> <span class="nt">--name-only</span> <span class="nt">-r</span> home</code></pre></figure>

</div>

<p>سپس برای دیده نشدن فایل‌های ردیابی نشده این تنظیم را انجام دهید: <code class="language-plaintext highlighter-rouge">config config --local status.showUntrackedFiles no</code></p>

<p>تبریک می‌گم. پس از این می‌توانید فایل‌هایتان را این گونه مدیریت کنید:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">config status
config add .vimrc
config commit <span class="nt">-m</span> <span class="s2">"Add vimrc"</span>
config add .bashrc
config commit <span class="nt">-m</span> <span class="s2">"Add bashrc"</span>
config push</code></pre></figure>

</div>

<p>اگر به جای تنظیم <code class="language-plaintext highlighter-rouge">status.showUntrackedFiles</code> از <code class="language-plaintext highlighter-rouge">*</code> در <code class="language-plaintext highlighter-rouge">‪.gitignore‬</code> استفاده کردید این فرمان‌ها به این صورت خواهند بود:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">config status
config add <span class="nt">-f</span> .vimrc
config commit <span class="nt">-m</span> <span class="s2">"Add vimrc"</span>
config add <span class="nt">-f</span> .bashrc
config commit <span class="nt">-m</span> <span class="s2">"Add bashrc"</span>
config push</code></pre></figure>

</div>

<h1 id="منابع">منابع:</h1>

<ul>
  <li><a href="https://news.ycombinator.com/item?id=11070797" target="_blank" rel="noopener noreferrer">Hacker News</a></li>
  <li><a href="https://www.atlassian.com/git/tutorials/dotfiles" target="_blank" rel="noopener noreferrer">Atlassian’s Blog</a></li>
  <li><a href="https://coffeeaddict.dev/how-to-manage-dotfiles-with-git-bare-repo" target="_blank" rel="noopener noreferrer">Coffee Addict</a></li>
</ul>

<h1 id="دات‌فایل‌های-من"><a href="https://github.com/mhdzli/dotfiles" target="_blank" rel="noopener noreferrer">دات‌فایل‌های من</a></h1>]]></content><author><name>محمد زینلی</name><email>m@zmim.ir</email></author><category term="git" /><category term="dotfiles" /><category term="linux" /><summary type="html"><![CDATA[یکی از بزرگترین مزایای استفاده از گنو/لینوکس قابلیت شخصی سازی آن است. بسیاری از کاربران شخصی سازی را با تغییر فایل‌های تنظیمات انجام می‌دهند. یکی از بهترین روش‌ها برای مدیریت این فایل‌ها استفاده از `Git` است.]]></summary></entry><entry xml:lang="fa"><title type="html">تنظیمات صفحه کلید در گنو/لینوکس</title><link href="https://zmim.ir/keyboard-configurations/" rel="alternate" type="text/html" title="تنظیمات صفحه کلید در گنو/لینوکس" /><published>2022-04-22T10:42:36+04:30</published><updated>2022-04-22T10:42:36+04:30</updated><id>https://zmim.ir/keyboard-configurations</id><content type="html" xml:base="https://zmim.ir/keyboard-configurations/"><![CDATA[<p>استفاده از دو زبان فارسی و انگلیسی برای کاربران فارسی رایانه ضروری است. پشتیبانی از زبان فارسی در گنو/لینوکس مدت‌هاست که افزوده شده و همواره استانداردهای بهتری به نسبت ویندوز داشته است. با این حال شخصی سازی بیشتر، همواره تجربه خوشایندتری در کار با رایانه برای ما خواهد داشت. استفاده از دو زبان همزمان و نبود استاندارد یکسان برای فارسی نویسی، موجب می‌شود کاربران فارسی زبان گاه با مشکلاتی مواجه شوند، که هرگز برای کاربران انگلیسی زبان پیش نمی‌آید. چندی پیش یکی از دوستان دنبال راهی برای افزودن یک نویسه خاص به صفحه کلید بود. اینکه نتوانسته بود راهنمای مناسبی برای این کار پیدا کند، موجب شد به فکر نوشتن یک مطلب در این زمینه بیفتم.</p>

<p>اینجا تلاش می‌کنم درباره تنظیمات صفحه کلید در محیط کنسول <code class="language-plaintext highlighter-rouge">tty</code> و محیط‌های گرافیکی <code class="language-plaintext highlighter-rouge">X11</code> و مدیر پنجره <code class="language-plaintext highlighter-rouge">Sway</code> روی ویلند بنویسم. تنظیمات صفحه کلید روی ویلند وابسته به کامپوزیتوری است که از آن استفاده می‌کنید. اما عمده آنچه اینجا به آن اشاره می‌شود، بر روی محیط‌های کاربری دیگر ویلند، به ویژه آنها که بر اساس <code class="language-plaintext highlighter-rouge">wlroots</code> هستند نیز فابل انجام است.</p>

<h1 id="تفاوت-صفحه-کلیدها-و-layoutهای-مختلف">تفاوت صفحه کلیدها و <code class="language-plaintext highlighter-rouge">layout</code>های مختلف</h1>

<p>بیشتر ما از <code class="language-plaintext highlighter-rouge">layout</code> انگلیسی و فارسی <code class="language-plaintext highlighter-rouge">QWERTY</code> روی صفحه کلید استفاده می‌کنیم. که نمونه آن را در عکس زیر می‌توانید ببینید.</p>

<div style="text-align: center;">
    <img src="600px-KB_United_States.png" style="max-width: 80%; margin: 10px;" alt="صفحه کلید qwerty انگلیسی" />
</div>

<p>اما چیدمان‌های دیگری نیز برای صفحه کلیدهای <code class="language-plaintext highlighter-rouge">QWERTY</code> بسته به زبان صفحه کلید وجود دارد. به عنوان نمونه صفحه کلید فرانسوی <code class="language-plaintext highlighter-rouge">AZERTY</code> که تغییراتی را در صفحه کلید انگلیسی <code class="language-plaintext highlighter-rouge">QWERTY</code> برای سازگاری بیشتر با زبان فرانسوی داده است:</p>

<div style="text-align: center;">
    <img src="KB_France.png" style="max-width: 80%; margin: 10px;" alt="صفحه کلید azerty فرانسوی" />
</div>

<p>برای اطلاعات بیشتر در این زمینه می‌توانید صفحه مربوط به آن را در <a href="https://en.wikipedia.org/wiki/Keyboard_layout" target="_blank" rel="noopener noreferrer">ویکی‌پدیا</a> بخوانید.</p>

<p>همچنین چیدمان‌های دیگری نیز از صفحه کلید انگلیسی وجود دارد که <a href="https://en.wikipedia.org/wiki/Dvorak_keyboard_layout" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">DVORAK</code></a> و <a href="https://en.wikipedia.org/wiki/Colemak" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">COLEMAK</code></a> شناخته شده‌تر هستند.</p>

<p>نمونه صفحه کلید <code class="language-plaintext highlighter-rouge">DVORAK</code>:</p>

<div style="text-align: center;">
    <img src="KB_United_States_Dvorak.png" style="max-width: 80%; margin: 10px;" alt="صفحه کلید dvorak" />
</div>

<p>نمونه صفحه کلید <code class="language-plaintext highlighter-rouge">COLEMAK</code>:</p>

<div style="text-align: center;">
    <img src="600px-KB_US-Colemak.png" style="max-width: 80%; margin: 10px;" alt="صفحه کلید colemak" />
</div>

<p><a href="https://kbdlayout.info/kbdfar" target="_blank" rel="noopener noreferrer">صفحه کلید فارسی استاندارد</a> نیز نمونه‌ای از صفحه کلیدهای <code class="language-plaintext highlighter-rouge">QWERTY</code> دسته‌بندی می‌شود. که چیدمان کلید‌ها در آن به این صورت است:</p>

<div style="text-align: center;">
    <img src="KB_Persian.png" style="max-width: 80%; margin: 10px;" alt="صفحه کلید فارسی استاندارد" />
</div>

<h1 id="تنظیمات-صفحه-کلید-در-tty">تنظیمات صفحه کلید در <code class="language-plaintext highlighter-rouge">tty</code></h1>

<p>شاید کمتر برای شما پیش آمده باشد که بخواهید تنظیمات صفحه کلید را در کنسول یا همان محیط <code class="language-plaintext highlighter-rouge">tty</code> تغییر دهید بیشتر ما از صفحه کلید انگلیسی <code class="language-plaintext highlighter-rouge">QWERTY</code> که بیشتر جاها پیش گزیده است، استفاده می‌کنیم. اما همانطور که اشاره شد، چیدمان‌های دیگری هم از حروف انگلیسی وجود دارد. این یکی از دلایلی است که ممکن است بخواهیم در محیط کنسول از یک <code class="language-plaintext highlighter-rouge">layout</code> متفاوت استفاده کنیم.</p>

<p>چنانچه از <code class="language-plaintext highlighter-rouge">Systemd</code> به عنوان راه‌انداز استفاده می‌کنید می‌توانید با فرمان <code class="language-plaintext highlighter-rouge">localectl list-keymaps</code> لیستی از چیدمان‌های موجود را ببینید. برای من خروجی این دستور ۲۳۲ صفحه کلید متفاوت را نمایش می‌دهد.</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>localectl list-keymaps | <span class="nb">wc</span> <span class="nt">-l</span>
232</code></pre></figure>

</div>

<p>همچنین می‌توانید با استفاده از <code class="language-plaintext highlighter-rouge">grep</code> صفحه کلید مورد نظرتان را بیابید:</p>

<div style="text-align: center;">
    <img src="localectl.png" style="max-width: 80%; margin: 10px;" alt="دستور localectl" />
</div>

<p>در صورتی که از <code class="language-plaintext highlighter-rouge">Systemd</code> استفاده نمی‌کنید، دستور <code class="language-plaintext highlighter-rouge">find</code> می‌تواند لیستی از صفحه کلیدهای موجود را به شما بدهد. خروجی آن برای من به این صورت است:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>find /usr/share/kbd/keymaps/ <span class="nt">-type</span> f <span class="nt">-name</span> <span class="s2">"*"</span>
/usr/share/kbd/keymaps/amiga/amiga-de.map.gz
/usr/share/kbd/keymaps/amiga/amiga-us.map.gz
/usr/share/kbd/keymaps/atari/atari-de.map.gz
/usr/share/kbd/keymaps/atari/atari-se.map.gz
/usr/share/kbd/keymaps/atari/atari-uk-falcon.map.gz
/usr/share/kbd/keymaps/atari/atari-us.map.gz
/usr/share/kbd/keymaps/i386/azerty/azerty.map.gz
/usr/share/kbd/keymaps/i386/azerty/be-latin1.map.gz
/usr/share/kbd/keymaps/i386/azerty/fr-latin1.map.gz
/usr/share/kbd/keymaps/i386/azerty/fr-latin9.map.gz
/usr/share/kbd/keymaps/i386/azerty/fr-pc.map.gz
/usr/share/kbd/keymaps/i386/azerty/fr.map.gz
/usr/share/kbd/keymaps/i386/azerty/wangbe.map.gz
/usr/share/kbd/keymaps/i386/azerty/wangbe2.map.gz
/usr/share/kbd/keymaps/i386/bepo/fr-bepo-latin9.map.gz
/usr/share/kbd/keymaps/i386/bepo/fr-bepo.map.gz
/usr/share/kbd/keymaps/i386/carpalx/carpalx-full.map.gz
/usr/share/kbd/keymaps/i386/carpalx/carpalx.map.gz
/usr/share/kbd/keymaps/i386/colemak/colemak.map.gz
/usr/share/kbd/keymaps/i386/dvorak/ANSI-dvorak.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-ca-fr.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-es.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-fr.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-l.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-la.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-no.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-programmer.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-r.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-ru.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-sv-a1.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-sv-a5.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-uk.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-ukp.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak.map.gz
/usr/share/kbd/keymaps/i386/fgGIod/tr_f-latin5.map.gz
/usr/share/kbd/keymaps/i386/fgGIod/trf-fgGIod.map.gz
/usr/share/kbd/keymaps/i386/include/applkey.map.gz
/usr/share/kbd/keymaps/i386/include/azerty-layout.inc
/usr/share/kbd/keymaps/i386/include/backspace.map.gz
/usr/share/kbd/keymaps/i386/include/compose.inc
/usr/share/kbd/keymaps/i386/include/ctrl.map.gz
/usr/share/kbd/keymaps/i386/include/euro.map.gz
/usr/share/kbd/keymaps/i386/include/euro1.inc
/usr/share/kbd/keymaps/i386/include/euro1.map.gz
/usr/share/kbd/keymaps/i386/include/euro2.map.gz
/usr/share/kbd/keymaps/i386/include/keypad.map.gz
/usr/share/kbd/keymaps/i386/include/linux-keys-bare.inc
/usr/share/kbd/keymaps/i386/include/linux-keys-extd.inc
/usr/share/kbd/keymaps/i386/include/linux-with-alt-and-altgr.inc
/usr/share/kbd/keymaps/i386/include/linux-with-modeshift-altgr.inc
/usr/share/kbd/keymaps/i386/include/linux-with-two-alt-keys.inc
/usr/share/kbd/keymaps/i386/include/qwerty-layout.inc
/usr/share/kbd/keymaps/i386/include/qwertz-layout.inc
/usr/share/kbd/keymaps/i386/include/unicode.map.gz
/usr/share/kbd/keymaps/i386/include/windowkeys.map.gz
/usr/share/kbd/keymaps/i386/neo/README.md
/usr/share/kbd/keymaps/i386/neo/adnw.map.gz
/usr/share/kbd/keymaps/i386/neo/bone.map.gz
/usr/share/kbd/keymaps/i386/neo/koy.map.gz
/usr/share/kbd/keymaps/i386/neo/neo.map.gz
/usr/share/kbd/keymaps/i386/neo/neoqwertz.map.gz
/usr/share/kbd/keymaps/i386/olpc/es-olpc.map.gz
/usr/share/kbd/keymaps/i386/olpc/pt-olpc.map.gz
/usr/share/kbd/keymaps/i386/qwerty/bashkir.map.gz
/usr/share/kbd/keymaps/i386/qwerty/bg-cp1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/bg-cp855.map.gz
/usr/share/kbd/keymaps/i386/qwerty/bg_bds-cp1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/bg_bds-utf8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/bg_pho-cp1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/bg_pho-utf8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/br-abnt.map.gz
/usr/share/kbd/keymaps/i386/qwerty/br-abnt2.map.gz
/usr/share/kbd/keymaps/i386/qwerty/br-latin1-abnt2.map.gz
/usr/share/kbd/keymaps/i386/qwerty/br-latin1-us.map.gz
/usr/share/kbd/keymaps/i386/qwerty/by-cp1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/by.map.gz
/usr/share/kbd/keymaps/i386/qwerty/bywin-cp1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ca.map.gz
/usr/share/kbd/keymaps/i386/qwerty/cf.map.gz
/usr/share/kbd/keymaps/i386/qwerty/cz-cp1250.map.gz
/usr/share/kbd/keymaps/i386/qwerty/cz-lat2-prog.map.gz
/usr/share/kbd/keymaps/i386/qwerty/cz-lat2.map.gz
/usr/share/kbd/keymaps/i386/qwerty/cz.map.gz
/usr/share/kbd/keymaps/i386/qwerty/defkeymap.map.gz
/usr/share/kbd/keymaps/i386/qwerty/defkeymap_V1.0.map.gz
/usr/share/kbd/keymaps/i386/qwerty/dk-latin1.map.gz
/usr/share/kbd/keymaps/i386/qwerty/dk.map.gz
/usr/share/kbd/keymaps/i386/qwerty/emacs.map.gz
/usr/share/kbd/keymaps/i386/qwerty/emacs2.map.gz
/usr/share/kbd/keymaps/i386/qwerty/es-cp850.map.gz
/usr/share/kbd/keymaps/i386/qwerty/es.map.gz
/usr/share/kbd/keymaps/i386/qwerty/et-nodeadkeys.map.gz
/usr/share/kbd/keymaps/i386/qwerty/et.map.gz
/usr/share/kbd/keymaps/i386/qwerty/fa.map.gz
/usr/share/kbd/keymaps/i386/qwerty/fi.map.gz
/usr/share/kbd/keymaps/i386/qwerty/gr-pc.map.gz
/usr/share/kbd/keymaps/i386/qwerty/gr.map.gz
/usr/share/kbd/keymaps/i386/qwerty/hu101.map.gz
/usr/share/kbd/keymaps/i386/qwerty/hypermap.m4
/usr/share/kbd/keymaps/i386/qwerty/il-heb.map.gz
/usr/share/kbd/keymaps/i386/qwerty/il-phonetic.map.gz
/usr/share/kbd/keymaps/i386/qwerty/il.map.gz
/usr/share/kbd/keymaps/i386/qwerty/is-latin1-us.map.gz
/usr/share/kbd/keymaps/i386/qwerty/is-latin1.map.gz
/usr/share/kbd/keymaps/i386/qwerty/it-ibm.map.gz
/usr/share/kbd/keymaps/i386/qwerty/it.map.gz
/usr/share/kbd/keymaps/i386/qwerty/it2.map.gz
/usr/share/kbd/keymaps/i386/qwerty/jp106.map.gz
/usr/share/kbd/keymaps/i386/qwerty/kazakh.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ky_alt_sh-UTF-8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/kyrgyz.map.gz
/usr/share/kbd/keymaps/i386/qwerty/la-latin1.map.gz
/usr/share/kbd/keymaps/i386/qwerty/lt.baltic.map.gz
/usr/share/kbd/keymaps/i386/qwerty/lt.l4.map.gz
/usr/share/kbd/keymaps/i386/qwerty/lt.map.gz
/usr/share/kbd/keymaps/i386/qwerty/lv-tilde.map.gz
/usr/share/kbd/keymaps/i386/qwerty/lv.map.gz
/usr/share/kbd/keymaps/i386/qwerty/mk-cp1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/mk-utf.map.gz
/usr/share/kbd/keymaps/i386/qwerty/mk.map.gz
/usr/share/kbd/keymaps/i386/qwerty/mk0.map.gz
/usr/share/kbd/keymaps/i386/qwerty/nl.map.gz
/usr/share/kbd/keymaps/i386/qwerty/nl2.map.gz
/usr/share/kbd/keymaps/i386/qwerty/no-latin1.doc
/usr/share/kbd/keymaps/i386/qwerty/no-latin1.map.gz
/usr/share/kbd/keymaps/i386/qwerty/no.map.gz
/usr/share/kbd/keymaps/i386/qwerty/pc110.map.gz
/usr/share/kbd/keymaps/i386/qwerty/pl.map.gz
/usr/share/kbd/keymaps/i386/qwerty/pl1.map.gz
/usr/share/kbd/keymaps/i386/qwerty/pl2.map.gz
/usr/share/kbd/keymaps/i386/qwerty/pl3.map.gz
/usr/share/kbd/keymaps/i386/qwerty/pl4.map.gz
/usr/share/kbd/keymaps/i386/qwerty/pt-latin1.map.gz
/usr/share/kbd/keymaps/i386/qwerty/pt-latin9.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ro.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ro_std.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ro_win.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ru-cp1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ru-ms.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ru-yawerty.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ru.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ru1.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ru2.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ru3.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ru4.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ru_win.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_alt-CP1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_alt-KOI8-R.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_alt-UTF-8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_alt_sh-UTF-8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_cplk-CP1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_cplk-KOI8-R.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_cplk-UTF-8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_ct_sh-CP1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_ct_sh-KOI8-R.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_ct_sh-UTF-8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_ctrl-CP1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_ctrl-KOI8-R.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ruwin_ctrl-UTF-8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/se-fi-ir209.map.gz
/usr/share/kbd/keymaps/i386/qwerty/se-fi-lat6.map.gz
/usr/share/kbd/keymaps/i386/qwerty/se-ir209.map.gz
/usr/share/kbd/keymaps/i386/qwerty/se-lat6.map.gz
/usr/share/kbd/keymaps/i386/qwerty/sk-prog-qwerty.map.gz
/usr/share/kbd/keymaps/i386/qwerty/sk-qwerty.map.gz
/usr/share/kbd/keymaps/i386/qwerty/sr-cy.map.gz
/usr/share/kbd/keymaps/i386/qwerty/sv-latin1.map.gz
/usr/share/kbd/keymaps/i386/qwerty/tj_alt-UTF8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/tr_q-latin5.map.gz
/usr/share/kbd/keymaps/i386/qwerty/tralt.map.gz
/usr/share/kbd/keymaps/i386/qwerty/trf.map.gz
/usr/share/kbd/keymaps/i386/qwerty/trq.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ttwin_alt-UTF-8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ttwin_cplk-UTF-8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ttwin_ct_sh-UTF-8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ttwin_ctrl-UTF-8.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ua-cp1251.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ua-utf-ws.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ua-utf.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ua-ws.map.gz
/usr/share/kbd/keymaps/i386/qwerty/ua.map.gz
/usr/share/kbd/keymaps/i386/qwerty/uk.map.gz
/usr/share/kbd/keymaps/i386/qwerty/us-acentos.map.gz
/usr/share/kbd/keymaps/i386/qwerty/us.map.gz
/usr/share/kbd/keymaps/i386/qwerty/us1.map.gz
/usr/share/kbd/keymaps/i386/qwertz/croat.map.gz
/usr/share/kbd/keymaps/i386/qwertz/cz-qwertz.map.gz
/usr/share/kbd/keymaps/i386/qwertz/cz-us-qwertz.map.gz
/usr/share/kbd/keymaps/i386/qwertz/de-latin1-nodeadkeys.map.gz
/usr/share/kbd/keymaps/i386/qwertz/de-latin1.map.gz
/usr/share/kbd/keymaps/i386/qwertz/de-mobii.map.gz
/usr/share/kbd/keymaps/i386/qwertz/de.map.gz
/usr/share/kbd/keymaps/i386/qwertz/de_CH-latin1.map.gz
/usr/share/kbd/keymaps/i386/qwertz/de_alt_UTF-8.map.gz
/usr/share/kbd/keymaps/i386/qwertz/fr_CH-latin1.map.gz
/usr/share/kbd/keymaps/i386/qwertz/fr_CH.map.gz
/usr/share/kbd/keymaps/i386/qwertz/hu.map.gz
/usr/share/kbd/keymaps/i386/qwertz/sg-latin1-lk450.map.gz
/usr/share/kbd/keymaps/i386/qwertz/sg-latin1.map.gz
/usr/share/kbd/keymaps/i386/qwertz/sg.map.gz
/usr/share/kbd/keymaps/i386/qwertz/sk-prog-qwertz.map.gz
/usr/share/kbd/keymaps/i386/qwertz/sk-qwertz.map.gz
/usr/share/kbd/keymaps/i386/qwertz/slovene.map.gz
/usr/share/kbd/keymaps/i386/qwertz/sr-latin.map.gz
/usr/share/kbd/keymaps/include/compose.8859_7
/usr/share/kbd/keymaps/include/compose.8859_8
/usr/share/kbd/keymaps/include/compose.latin
/usr/share/kbd/keymaps/include/compose.latin1
/usr/share/kbd/keymaps/include/compose.latin2
/usr/share/kbd/keymaps/include/compose.latin3
/usr/share/kbd/keymaps/include/compose.latin4
/usr/share/kbd/keymaps/include/vim-compose.latin1
/usr/share/kbd/keymaps/mac/all/apple-a1048-sv.map.gz
/usr/share/kbd/keymaps/mac/all/apple-a1243-sv-fn-reverse.map.gz
/usr/share/kbd/keymaps/mac/all/apple-a1243-sv.map.gz
/usr/share/kbd/keymaps/mac/all/apple-internal-0x0253-sv-fn-reverse.map.gz
/usr/share/kbd/keymaps/mac/all/apple-internal-0x0253-sv.map.gz
/usr/share/kbd/keymaps/mac/all/mac-be.map.gz
/usr/share/kbd/keymaps/mac/all/mac-de-latin1-nodeadkeys.map.gz
/usr/share/kbd/keymaps/mac/all/mac-de-latin1.map.gz
/usr/share/kbd/keymaps/mac/all/mac-de_CH.map.gz
/usr/share/kbd/keymaps/mac/all/mac-dk-latin1.map.gz
/usr/share/kbd/keymaps/mac/all/mac-dvorak.map.gz
/usr/share/kbd/keymaps/mac/all/mac-es.map.gz
/usr/share/kbd/keymaps/mac/all/mac-fi-latin1.map.gz
/usr/share/kbd/keymaps/mac/all/mac-fr.map.gz
/usr/share/kbd/keymaps/mac/all/mac-fr_CH-latin1.map.gz
/usr/share/kbd/keymaps/mac/all/mac-it.map.gz
/usr/share/kbd/keymaps/mac/all/mac-no-latin1.map.gz
/usr/share/kbd/keymaps/mac/all/mac-pl.map.gz
/usr/share/kbd/keymaps/mac/all/mac-pt-latin1.map.gz
/usr/share/kbd/keymaps/mac/all/mac-se.map.gz
/usr/share/kbd/keymaps/mac/all/mac-template.map.gz
/usr/share/kbd/keymaps/mac/all/mac-uk.map.gz
/usr/share/kbd/keymaps/mac/all/mac-us.map.gz
/usr/share/kbd/keymaps/mac/include/apple-a1048-base.inc
/usr/share/kbd/keymaps/mac/include/apple-a1243-fn-reverse.inc
/usr/share/kbd/keymaps/mac/include/apple-a1243-fn.inc
/usr/share/kbd/keymaps/mac/include/mac-azerty-layout.inc
/usr/share/kbd/keymaps/mac/include/mac-euro.map.gz
/usr/share/kbd/keymaps/mac/include/mac-euro2.map.gz
/usr/share/kbd/keymaps/mac/include/mac-linux-keys-bare.inc
/usr/share/kbd/keymaps/mac/include/mac-qwerty-layout.inc
/usr/share/kbd/keymaps/mac/include/mac-qwertz-layout.inc
/usr/share/kbd/keymaps/sun/sun-pl-altgraph.map.gz
/usr/share/kbd/keymaps/sun/sun-pl.map.gz
/usr/share/kbd/keymaps/sun/sundvorak.map.gz
/usr/share/kbd/keymaps/sun/sunkeymap.map.gz
/usr/share/kbd/keymaps/sun/sunt4-es.map.gz
/usr/share/kbd/keymaps/sun/sunt4-fi-latin1.map.gz
/usr/share/kbd/keymaps/sun/sunt4-no-latin1.map.gz
/usr/share/kbd/keymaps/sun/sunt5-cz-us.map.gz
/usr/share/kbd/keymaps/sun/sunt5-de-latin1.map.gz
/usr/share/kbd/keymaps/sun/sunt5-es.map.gz
/usr/share/kbd/keymaps/sun/sunt5-fi-latin1.map.gz
/usr/share/kbd/keymaps/sun/sunt5-fr-latin1.map.gz
/usr/share/kbd/keymaps/sun/sunt5-ru.map.gz
/usr/share/kbd/keymaps/sun/sunt5-uk.map.gz
/usr/share/kbd/keymaps/sun/sunt5-us-cz.map.gz
/usr/share/kbd/keymaps/sun/sunt6-uk.map.gz</code></pre></figure>

</div>

<p>و برای یافتن صفحه کلید مورد نظرتان به جای <code class="language-plaintext highlighter-rouge">*</code> عبارتی که می‌خواهید پیدا کنید را بین دو علامت <code class="language-plaintext highlighter-rouge">*</code> قرار دهید:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>find /usr/share/kbd/keymaps/ <span class="nt">-type</span> f <span class="nt">-name</span> <span class="s2">"*uk*"</span>
/usr/share/kbd/keymaps/atari/atari-uk-falcon.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-uk.map.gz
/usr/share/kbd/keymaps/i386/dvorak/dvorak-ukp.map.gz
/usr/share/kbd/keymaps/i386/qwerty/uk.map.gz
/usr/share/kbd/keymaps/mac/all/mac-uk.map.gz
/usr/share/kbd/keymaps/sun/sunt5-uk.map.gz
/usr/share/kbd/keymaps/sun/sunt6-uk.map.gz</code></pre></figure>

</div>

<p>برای تنظیم کردن صفحه کلید مورد نظرتان باید از فرمان <code class="language-plaintext highlighter-rouge">loadkeys</code> استفاده کنید. توجه کنید که اجرای این فرمان نیاز به دسترسی روت دارد:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span><span class="nb">sudo </span>loadkeys fr
<span class="nv">$ </span><span class="nb">sudo </span>loadkeys i386/azerty/fr.map.gz</code></pre></figure>

</div>

<p>برای این کار هم از نام صفحه کلید و هم از مسیر فایل <code class="language-plaintext highlighter-rouge">keymap</code> می‌توانید استفاده کنید. صفحه کلیدی را که انتخاب می‌کنید باید مناست کنسول بوده و کاراکترهای آن پشتیبانی شوند. چنانچه صفحه کلید فارسی را بخواهید برای کنسول تنظیم کنید با خطا مواجه خواهید شد:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span><span class="nb">sudo </span>loadkeys fa
unicode keysym out of range: U+FDFC
syntax error, unexpected ERROR, expecting NUMBER or LITERAL or PLUS or UNUMBER</code></pre></figure>

</div>

<p>برای اینکه این تنظیمات به صورت همیشگی انجام شود می‌توانید با کلید واژه <code class="language-plaintext highlighter-rouge">KEYMAP</code> و در فایل ‪<code class="language-plaintext highlighter-rouge">/etc/vconsole.conf</code>‬ این کار را انجام دهید.</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span><span class="nb">cat</span> /etc/vconsole.conf
<span class="nv">FONT</span><span class="o">=</span>ter-224b
<span class="nv">KEYMAP</span><span class="o">=</span>us</code></pre></figure>

</div>

<h1 id="تنظیمات-صفحه-کلید-در-x11">تنظیمات صفحه کلید در <code class="language-plaintext highlighter-rouge">X11</code></h1>

<h2 id="setxkbmap"><code class="language-plaintext highlighter-rouge">setxkbmap</code></h2>

<p>برای تنظیم صفحه کلید در محیط‌های کاربری که از <code class="language-plaintext highlighter-rouge">X11</code> سرور استفاده می‌کنند، هر یک از آنها مانند گنوم یا کی‌دی‌ای برنامه خاص خودشان را دارند. یک راه عمومی‌تر و ساده‌تر استفاده از فرمان <code class="language-plaintext highlighter-rouge">setxkbmap</code> است.</p>

<p>من این فرمان را به این صورت استفاده می‌کنم:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>setxkbmap <span class="nt">-model</span> thinkpad us,ir <span class="nt">-option</span> <span class="s2">"grp:shifts_toggle,caps:escape_shifted_capslock,altwin:prtsc_rwin,lv3:ralt_switch"</span></code></pre></figure>

</div>

<p>تنظیمات صفحه کلید با فرمان <code class="language-plaintext highlighter-rouge">setxkbmap</code> سه بخش دارد:</p>

<ul>
  <li>مدل صفحه کلید: می‌توانید مدل صفحه کلیدتان را با ‪<code class="language-plaintext highlighter-rouge">-model &lt;YOUR-KEYBOARD-MODEL&gt;</code>‬ مشخص کنید.</li>
  <li>layout[s]: هر تعداد از <code class="language-plaintext highlighter-rouge">layout</code>‌های موجود را می‌توانید برای استفاده با صفحه کلید تنظیم کنید. دقت کنید که باید از <code class="language-plaintext highlighter-rouge">,</code> برای جدا کردن اسم آنها استفاده کنید.</li>
  <li>تنظیمات ویژه: می‌توانید تنظیمات ویژه صفحه کلیدتان را با ‪<code class="language-plaintext highlighter-rouge">-options &lt;YOUR-KEYBOARD-OPTIONS&gt;</code>‬ مشخص کنید.</li>
</ul>

<p>در فرمانی که من استفاده می‌کنم، مدل صفحه کلید را <code class="language-plaintext highlighter-rouge">thinkpad</code> و دو زبان انگلیسی و فارسی را برای آن تنظیم کرده‌ام.</p>

<p>در بخش تنظیمات ویژه با استفاده از <code class="language-plaintext highlighter-rouge">grp:shifts_toggle</code> مشخص کرده‌ام که جابجایی بین زبان ‌های صفحه کلید با فشار دادن همزمان دو کلید <code class="language-plaintext highlighter-rouge">Shift</code> انجام شود.</p>

<p>شاید برای شما عجیب باشد اما برای من که تقریبا همیشه دستم روی صفحه کلید است، کار راحت‌تری است به نسبت استفاده از <code class="language-plaintext highlighter-rouge">Alt+Shift</code>. البته من کلیدهای دیگری نیز برای تغییر زبان صفحه کلید دارم که چنانچه نیاز باشد با یک دست زبان صفحه کلید را بتوانم عوض کنم.</p>

<p>سپس با <code class="language-plaintext highlighter-rouge">caps:escape_shifted_capslock</code> مشخص کرده‌ام که کلید <code class="language-plaintext highlighter-rouge">CapsLock</code> به عنوان کلید <code class="language-plaintext highlighter-rouge">Escape</code> عمل کند.</p>

<p>من از ادیتور ویم (<code class="language-plaintext highlighter-rouge">Vim</code>) برای ویرایش فایل‌های متنی استفاده می‌کنم و برای خارج شدن از مودهای مختلف این ادیتور از کلید <code class="language-plaintext highlighter-rouge">Escape</code> زیاد استفاده می‌کنم. محل استاندارد این کلید روی صفحه کلید گوشه بالا و سمت چپ است، که دور از دسترس است. تنظیم کلید <code class="language-plaintext highlighter-rouge">CapsLock</code> به عنوان <code class="language-plaintext highlighter-rouge">Escape</code> استفاده از آن را برای من راحت‌تر می‌کند.</p>

<p>گزینه بعدی در تنظیمات ویژه <code class="language-plaintext highlighter-rouge">altwin:prtsc_rwin</code> است که مشخص می‌کند کلید <code class="language-plaintext highlighter-rouge">PrinttScreen (PrtSc)</code> که روی صفحه کلید لپ‌تاپ من کنار <code class="language-plaintext highlighter-rouge">Alt</code> سمت راست قرار دارد به عنوان یک کلید <code class="language-plaintext highlighter-rouge">Meta</code> یا <code class="language-plaintext highlighter-rouge">Mod</code> (همان کلید لوگو <code class="language-plaintext highlighter-rouge">Win</code>) دوم عمل کند.</p>

<p>سال‌هاست که من از محیط‌های دسکتاپ روی لرایانه خودم استفاده نکرده‌ام و به جای آنها از مدیر پنجره‌ها استفاده می‌کنم، که سبک‌تر هستند و قابلیت شخصی سازی بیشتری دارند‌. بیشتر کلیدهای میانبر من به صورت ‪<code class="language-plaintext highlighter-rouge">Mod+&lt;SOME-KEY&gt;</code>‬ هستند،که تعدادشان هم زیاد است. داشتن کلید <code class="language-plaintext highlighter-rouge">Mod</code> در دو سمت صفحه کلید استفاده از این میانبرها را برای من راحت‌تر می‌کند.</p>

<p>در نهایت هم <code class="language-plaintext highlighter-rouge">lv3:ralt_switch</code> مشخص می‌کند که بتوان به لایه سوم صفحه کلید با استفاده از کلید <code class="language-plaintext highlighter-rouge">Alt</code> سمت راست، دسترسی داشت. همانطور که می‌دانید هر زبان روی صفحه کلید بیش از یک لایه از کاراکترها را دارد. تقریبا همه جا می‌توان با استفاده از کلید <code class="language-plaintext highlighter-rouge">Shift</code> کاراکترهای لایه دوم صفحه کلید را تایپ کرد. این کاراکترها برای زبان انگلیسی حروف بزرگ و برخی کاراکترهای پر کاربرد دیگر هستند. برای فارسی هم در صفحه کلید استاندارد نویسه <code class="language-plaintext highlighter-rouge">ژ</code> روی لایه دوم نویسه <code class="language-plaintext highlighter-rouge">ز</code> قرار دارد. برخی کاراکترهای پر کاربرد دیگر هم در این لایه قرار گرفته‌اند. <code class="language-plaintext highlighter-rouge">ZWNJ</code> یا نیم‌فاصله یکی از آنهاست. جالب است بدانید که تعدادی از کاراکترهای کم کاربردتر هم روی لایه‌های سوم و پایین‌تر صفحه کلید قرار دارند. <code class="language-plaintext highlighter-rouge">NBSP</code> یا فاصله نشکن یکی از آنهاست که روی لایه سوم کلید اسپیس قرار دارد. برای دسترسی به این لایه من از کلید <code class="language-plaintext highlighter-rouge">ALt</code> سمت راست استفاده می‌کنم.</p>

<p>سوال مهمی که پیش می‌آید این است که کجا می‌توان لیستی از مدل‌ها، <code class="language-plaintext highlighter-rouge">layout</code>‌ها و تنظیمات ویژه را یافت. کافیست در ترمینال با استفاده از <code class="language-plaintext highlighter-rouge">man xkeyboard-config</code> داکیومنت مربوط به آن را باز کنید و بخوانید. لیست مفصلی از تمامی گزینه‌ها به همراه توضیحی گویا برای هر یک را خواهید یافت. در مرورگرتان هم چنانچه عبارت ‪<code class="language-plaintext highlighter-rouge">man xkeyboard-config &lt;YOUR-DESTRIBUTION&gt;</code>‬ را جست‌وجو کنید، داکیومنت مربوط به توزیعتان را خواهید یافت. برای نمونه توزیع <a href="https://man.archlinux.org/man/xkeyboard-config.7.en" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">Arch Linux</code></a></p>

<p>البته برای یافتن <code class="language-plaintext highlighter-rouge">layout</code>‌ها می‌توانید مسیر ‪<code class="language-plaintext highlighter-rouge">/usr/share/X11/xkb/symbols</code>‬ را ببینید.</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span><span class="nb">ls</span> /usr/share/X11/xkb/symbols</code></pre></figure>

</div>

<p>نکته بعدی این است که چطور این تنظیمات را همیشگی کنیم. من برای راه‌اندازی محیط گرافیکی <code class="language-plaintext highlighter-rouge">X11</code> از بسته <code class="language-plaintext highlighter-rouge">xorg-xinit</code> استفاده می‌کنم و فرمان <code class="language-plaintext highlighter-rouge">startx</code> را مستقیم از کنسول اجرا می‌کنم و از <code class="language-plaintext highlighter-rouge">Display Manager</code> استفاده نمی‌کنم. وقتی این فرمان را اجرا می‌کنم تنظیمات مربوط به محیط گرافیکی را از فایل‌های متنی می‌خواند. یکی از این فایل‌ها ‪<code class="language-plaintext highlighter-rouge">.xinitrc</code>‬ است که در دایرکتوری ‪‪<code class="language-plaintext highlighter-rouge">$HOME</code>‬‬ قرار دارد. کافیست من هر فرمانی که برای تنظیم محیط گرافیکی خودم نیاز دارم را در یک فایل قرار دهم و آن را از داخل ‪<code class="language-plaintext highlighter-rouge">.xinitrc</code>‬ فراخوانی کنم. من این فرمان‌ها را در فایل <code class="language-plaintext highlighter-rouge">.xprofile</code> در دایرکتوری ‪<code class="language-plaintext highlighter-rouge">$HOME</code>‬ قرار داده‌ام.</p>
<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span><span class="nb">cat</span> ~/.xinitrc
<span class="c">#!/bin/sh</span>

<span class="c"># xinitrc runs automatically when you run startx.</span>

<span class="c"># There are some small but important commands that need to be run when we start</span>
<span class="c"># the graphical environment. I keep those commands in ~/.xprofile because that</span>
<span class="c"># file is run automatically if someone uses a display manager (login screen)</span>
<span class="c"># and so they are needed there. To prevent doubling up commands, I source them</span>
<span class="c"># here with the line below.</span>

<span class="o">[</span> <span class="nt">-f</span> ~/.xprofile <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">.</span> ~/.xprofile

<span class="c"># Fix Gnome Apps Slow  Start due to failing services</span>
<span class="c"># Add this when you include flatpak in your system</span>
dbus-update-activation-environment <span class="nt">--systemd</span> DBUS_SESSION_BUS_ADDRESS DISPLAY XAUTHORITY

<span class="c"># Here we start dwm.</span>
<span class="c"># The loop is just to enable dwm's "restart" feature (mod+F2).</span>
<span class="c">#exec dwm</span>
ssh-agent dwm

<span class="nv">$ </span><span class="nb">cat</span> ~/.xprofile
<span class="c">#!/usr/bin/sh</span>

xset r rate 300 50 &amp;    <span class="c"># Speed xrate up</span>
unclutter &amp;     <span class="c"># Remove mouse when idle</span>
<span class="c">#xcompmgr &amp;     # xcompmgr for transparency</span>
picom <span class="nt">--config</span> ~/.config/picom/picom.conf &amp;
dunst &amp;                 <span class="c"># dunst for notifications</span>
<span class="c">#keymap &amp;       # some keyboard remap</span>
mpd &amp;
xrdb ~/.Xdefaults &amp;
setbg &amp;
setxkbmap <span class="nt">-model</span> thinkpad us,ir <span class="nt">-option</span> <span class="s2">"grp:shifts_toggle,caps:escape_shifted_capslock,altwin:prtsc_rwin,lv3:ralt_switch"</span> &amp;</code></pre></figure>

</div>

<p>همانطور که می‌بینید تنظیمات صفحه کلید در خط آخر فایل مشخص شده است. هر <code class="language-plaintext highlighter-rouge">Display Manager</code> فایل‌های تنظیماتی دارد که پیش از بالا آمدن محیط گرافیکی آنها را فراخوانی می‌کند. می‌توانید مسیر این فایل‌ها را با جست‌وجو در اینترنت بیابید و تنظیمات مربوط به صفحه کلید را در آنها قرار دهید تا به صورت خودکار انجام شوند.</p>

<h2 id="xmodmap"><code class="language-plaintext highlighter-rouge">xmodmap</code></h2>

<p><code class="language-plaintext highlighter-rouge">xmodmap</code> ابزاری برای ویرایش چیدمان کلیدها روی صفحه کلید در <code class="language-plaintext highlighter-rouge">X11</code> است. ممکن است شما نیاز داشته باشید جای دو تا از کلیدها را روی صفحه عوض کنید و این گزینه در بین انتخاب‌های <code class="language-plaintext highlighter-rouge">setxkbmap</code> وجود نداشته باشد، برای اینکار می‌توانید از <code class="language-plaintext highlighter-rouge">xmodmap</code> استفاده کنید:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>xmodmap <span class="nt">-e</span> <span class="s1">'keycode 135 = Super_R'</span></code></pre></figure>

</div>

<p>فرمان بالا کلید <code class="language-plaintext highlighter-rouge">Menu</code> را به کلید <code class="language-plaintext highlighter-rouge">Super</code> تبدیل می‌کند. با مشابه آنچه <code class="language-plaintext highlighter-rouge">setxkbmap -option altwin:menu_win</code> انجام می‌دهد. برای یافتن کد مربوط به هر کلید فیزیکی روی صفحه کلید می‌توانید لیست چیدمان فعلی صفحه کلید را با استفاده از <code class="language-plaintext highlighter-rouge">xmodmap -pk</code> ببینید.</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>xmodmap <span class="nt">-pk</span>
There are 10 KeySyms per KeyCode<span class="p">;</span> KeyCodes range from 8 to 255.

    KeyCode Keysym <span class="o">(</span>Keysym<span class="o">)</span> ...
    Value   Value   <span class="o">(</span>Name<span class="o">)</span>  ...

      8
      9     0xff1b <span class="o">(</span>Escape<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff1b <span class="o">(</span>Escape<span class="o">)</span>
     10     0x0031 <span class="o">(</span>1<span class="o">)</span>  0x0021 <span class="o">(</span>exclam<span class="o">)</span> 0x10006f1 <span class="o">(</span>Farsi_1<span class="o">)</span> 0x0021 <span class="o">(</span>exclam<span class="o">)</span> 0x0060 <span class="o">(</span>grave<span class="o">)</span>  0x0031 <span class="o">(</span>1<span class="o">)</span>
     11     0x0032 <span class="o">(</span>2<span class="o">)</span>  0x0040 <span class="o">(</span>at<span class="o">)</span> 0x10006f2 <span class="o">(</span>Farsi_2<span class="o">)</span> 0x100066c <span class="o">(</span>U066C<span class="o">)</span>   0x0040 <span class="o">(</span>at<span class="o">)</span> 0x0032 <span class="o">(</span>2<span class="o">)</span>
     12     0x0033 <span class="o">(</span>3<span class="o">)</span>  0x0023 <span class="o">(</span>numbersign<span class="o">)</span> 0x10006f3 <span class="o">(</span>Farsi_3<span class="o">)</span> 0x100066b <span class="o">(</span>U066B<span class="o">)</span>   0x0023 <span class="o">(</span>numbersign<span class="o">)</span> 0x0033 <span class="o">(</span>3<span class="o">)</span>
     13     0x0034 <span class="o">(</span>4<span class="o">)</span>  0x0024 <span class="o">(</span>dollar<span class="o">)</span> 0x10006f4 <span class="o">(</span>Farsi_4<span class="o">)</span> 0x100fdfc <span class="o">(</span>UFDFC<span class="o">)</span>   0x0024 <span class="o">(</span>dollar<span class="o">)</span> 0x0034 <span class="o">(</span>4<span class="o">)</span>
     14     0x0035 <span class="o">(</span>5<span class="o">)</span>  0x0025 <span class="o">(</span>percent<span class="o">)</span>    0x10006f5 <span class="o">(</span>Farsi_5<span class="o">)</span> 0x100066a <span class="o">(</span>Arabic_percent<span class="o">)</span>  0x0025 <span class="o">(</span>percent<span class="o">)</span>    0x0035 <span class="o">(</span>5<span class="o">)</span>
     15     0x0036 <span class="o">(</span>6<span class="o">)</span>  0x005e <span class="o">(</span>asciicircum<span class="o">)</span>    0x10006f6 <span class="o">(</span>Farsi_6<span class="o">)</span> 0x00d7 <span class="o">(</span>multiply<span class="o">)</span>   0x005e <span class="o">(</span>asciicircum<span class="o">)</span>    0x0036 <span class="o">(</span>6<span class="o">)</span>
     16     0x0037 <span class="o">(</span>7<span class="o">)</span>  0x0026 <span class="o">(</span>ampersand<span class="o">)</span>  0x10006f7 <span class="o">(</span>Farsi_7<span class="o">)</span> 0x05ac <span class="o">(</span>Arabic_comma<span class="o">)</span>   0x0026 <span class="o">(</span>ampersand<span class="o">)</span>  0x0037 <span class="o">(</span>7<span class="o">)</span>
     17     0x0038 <span class="o">(</span>8<span class="o">)</span>  0x002a <span class="o">(</span>asterisk<span class="o">)</span>   0x10006f8 <span class="o">(</span>Farsi_8<span class="o">)</span> 0x002a <span class="o">(</span>asterisk<span class="o">)</span>   0x0ae6 <span class="o">(</span>enfilledcircbullet<span class="o">)</span> 0x0038 <span class="o">(</span>8<span class="o">)</span>
     18     0x0039 <span class="o">(</span>9<span class="o">)</span>  0x0028 <span class="o">(</span>parenleft<span class="o">)</span>  0x10006f9 <span class="o">(</span>Farsi_9<span class="o">)</span> 0x0029 <span class="o">(</span>parenright<span class="o">)</span> 0x100200e <span class="o">(</span>U200E<span class="o">)</span>   0x0039 <span class="o">(</span>9<span class="o">)</span>
     19     0x0030 <span class="o">(</span>0<span class="o">)</span>  0x0029 <span class="o">(</span>parenright<span class="o">)</span> 0x10006f0 <span class="o">(</span>Farsi_0<span class="o">)</span> 0x0028 <span class="o">(</span>parenleft<span class="o">)</span>  0x100200f <span class="o">(</span>U200F<span class="o">)</span>   0x0030 <span class="o">(</span>0<span class="o">)</span>
     20     0x002d <span class="o">(</span>minus<span class="o">)</span>  0x005f <span class="o">(</span>underscore<span class="o">)</span> 0x002d <span class="o">(</span>minus<span class="o">)</span>  0x05e0 <span class="o">(</span>Arabic_tatweel<span class="o">)</span> 0x005f <span class="o">(</span>underscore<span class="o">)</span>
     21     0x003d <span class="o">(</span>equal<span class="o">)</span>  0x002b <span class="o">(</span>plus<span class="o">)</span>   0x003d <span class="o">(</span>equal<span class="o">)</span>  0x002b <span class="o">(</span>plus<span class="o">)</span>   0x1002212 <span class="o">(</span>U2212<span class="o">)</span>
     22     0xff08 <span class="o">(</span>BackSpace<span class="o">)</span>  0xff08 <span class="o">(</span>BackSpace<span class="o">)</span>  0xff08 <span class="o">(</span>BackSpace<span class="o">)</span>  0xff08 <span class="o">(</span>BackSpace<span class="o">)</span>
     23     0xff09 <span class="o">(</span>Tab<span class="o">)</span>    0xfe20 <span class="o">(</span>ISO_Left_Tab<span class="o">)</span>   0xff09 <span class="o">(</span>Tab<span class="o">)</span>    0xfe20 <span class="o">(</span>ISO_Left_Tab<span class="o">)</span>
     24     0x0071 <span class="o">(</span>q<span class="o">)</span>  0x0051 <span class="o">(</span>Q<span class="o">)</span>  0x05d6 <span class="o">(</span>Arabic_dad<span class="o">)</span> 0x05f2 <span class="o">(</span>Arabic_sukun<span class="o">)</span>   0x00b0 <span class="o">(</span>degree<span class="o">)</span>
     25     0x0077 <span class="o">(</span>w<span class="o">)</span>  0x0057 <span class="o">(</span>W<span class="o">)</span>  0x05d5 <span class="o">(</span>Arabic_sad<span class="o">)</span> 0x05ec <span class="o">(</span>Arabic_dammatan<span class="o">)</span>    0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     26     0x0065 <span class="o">(</span>e<span class="o">)</span>  0x0045 <span class="o">(</span>E<span class="o">)</span>  0x05cb <span class="o">(</span>Arabic_theh<span class="o">)</span>    0x05ed <span class="o">(</span>Arabic_kasratan<span class="o">)</span>    0x13a4 <span class="o">(</span>no name<span class="o">)</span>
     27     0x0072 <span class="o">(</span>r<span class="o">)</span>  0x0052 <span class="o">(</span>R<span class="o">)</span>  0x05e2 <span class="o">(</span>Arabic_qaf<span class="o">)</span> 0x05eb <span class="o">(</span>Arabic_fathatan<span class="o">)</span>    0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     28     0x0074 <span class="o">(</span>t<span class="o">)</span>  0x0054 <span class="o">(</span>T<span class="o">)</span>  0x05e1 <span class="o">(</span>Arabic_feh<span class="o">)</span> 0x05ef <span class="o">(</span>Arabic_damma<span class="o">)</span>   0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     29     0x0079 <span class="o">(</span>y<span class="o">)</span>  0x0059 <span class="o">(</span>Y<span class="o">)</span>  0x05da <span class="o">(</span>Arabic_ghain<span class="o">)</span>   0x05f0 <span class="o">(</span>Arabic_kasra<span class="o">)</span>   0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     30     0x0075 <span class="o">(</span>u<span class="o">)</span>  0x0055 <span class="o">(</span>U<span class="o">)</span>  0x05d9 <span class="o">(</span>Arabic_ain<span class="o">)</span> 0x05ee <span class="o">(</span>Arabic_fatha<span class="o">)</span>   0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     31     0x0069 <span class="o">(</span>i<span class="o">)</span>  0x0049 <span class="o">(</span>I<span class="o">)</span>  0x05e7 <span class="o">(</span>Arabic_ha<span class="o">)</span>  0x05f1 <span class="o">(</span>Arabic_shadda<span class="o">)</span>  0x100202d <span class="o">(</span>U202D<span class="o">)</span>
     32     0x006f <span class="o">(</span>o<span class="o">)</span>  0x004f <span class="o">(</span>O<span class="o">)</span>  0x05ce <span class="o">(</span>Arabic_khah<span class="o">)</span>    0x005d <span class="o">(</span>bracketright<span class="o">)</span>   0x100202e <span class="o">(</span>U202E<span class="o">)</span>
     33     0x0070 <span class="o">(</span>p<span class="o">)</span>  0x0050 <span class="o">(</span>P<span class="o">)</span>  0x05cd <span class="o">(</span>Arabic_hah<span class="o">)</span> 0x005b <span class="o">(</span>bracketleft<span class="o">)</span>    0x100202c <span class="o">(</span>U202C<span class="o">)</span>
     34     0x005b <span class="o">(</span>bracketleft<span class="o">)</span>    0x007b <span class="o">(</span>braceleft<span class="o">)</span>  0x05cc <span class="o">(</span>Arabic_jeem<span class="o">)</span>    0x007d <span class="o">(</span>braceright<span class="o">)</span> 0x100202a <span class="o">(</span>U202A<span class="o">)</span>
     35     0x005d <span class="o">(</span>bracketright<span class="o">)</span>   0x007d <span class="o">(</span>braceright<span class="o">)</span> 0x1000686 <span class="o">(</span>Arabic_tcheh<span class="o">)</span>    0x007b <span class="o">(</span>braceleft<span class="o">)</span>  0x100202b <span class="o">(</span>U202B<span class="o">)</span>
     36     0xff0d <span class="o">(</span>Return<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff0d <span class="o">(</span>Return<span class="o">)</span>
     37     0xffe3 <span class="o">(</span>Control_L<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffe3 <span class="o">(</span>Control_L<span class="o">)</span>
     38     0x0061 <span class="o">(</span>a<span class="o">)</span>  0x0041 <span class="o">(</span>A<span class="o">)</span>  0x05d4 <span class="o">(</span>Arabic_sheen<span class="o">)</span>   0x05c4 <span class="o">(</span>Arabic_hamzaonwaw<span class="o">)</span>  0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     39     0x0073 <span class="o">(</span>s<span class="o">)</span>  0x0053 <span class="o">(</span>S<span class="o">)</span>  0x05d3 <span class="o">(</span>Arabic_seen<span class="o">)</span>    0x05c6 <span class="o">(</span>Arabic_hamzaonyeh<span class="o">)</span>  0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     40     0x0064 <span class="o">(</span>d<span class="o">)</span>  0x0044 <span class="o">(</span>D<span class="o">)</span>  0x10006cc <span class="o">(</span>Farsi_yeh<span class="o">)</span>   0x05ea <span class="o">(</span>Arabic_yeh<span class="o">)</span> 0x05e9 <span class="o">(</span>Arabic_alefmaksura<span class="o">)</span>
     41     0x0066 <span class="o">(</span>f<span class="o">)</span>  0x0046 <span class="o">(</span>F<span class="o">)</span>  0x05c8 <span class="o">(</span>Arabic_beh<span class="o">)</span> 0x05c5 <span class="o">(</span>Arabic_hamzaunderalef<span class="o">)</span>  0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     42     0x0067 <span class="o">(</span>g<span class="o">)</span>  0x0047 <span class="o">(</span>G<span class="o">)</span>  0x05e4 <span class="o">(</span>Arabic_lam<span class="o">)</span> 0x05c3 <span class="o">(</span>Arabic_hamzaonalef<span class="o">)</span> 0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     43     0x0068 <span class="o">(</span>h<span class="o">)</span>  0x0048 <span class="o">(</span>H<span class="o">)</span>  0x05c7 <span class="o">(</span>Arabic_alef<span class="o">)</span>    0x05c2 <span class="o">(</span>Arabic_maddaonalef<span class="o">)</span> 0x1000671 <span class="o">(</span>U0671<span class="o">)</span>
     44     0x006a <span class="o">(</span>j<span class="o">)</span>  0x004a <span class="o">(</span>J<span class="o">)</span>  0x05ca <span class="o">(</span>Arabic_teh<span class="o">)</span> 0x05c9 <span class="o">(</span>Arabic_tehmarbuta<span class="o">)</span>  0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     45     0x006b <span class="o">(</span>k<span class="o">)</span>  0x004b <span class="o">(</span>K<span class="o">)</span>  0x05e6 <span class="o">(</span>Arabic_noon<span class="o">)</span>    0x00bb <span class="o">(</span>guillemotright<span class="o">)</span> 0x100fd3e <span class="o">(</span>UFD3E<span class="o">)</span>
     46     0x006c <span class="o">(</span>l<span class="o">)</span>  0x004c <span class="o">(</span>L<span class="o">)</span>  0x05e5 <span class="o">(</span>Arabic_meem<span class="o">)</span>    0x00ab <span class="o">(</span>guillemotleft<span class="o">)</span>  0x100fd3f <span class="o">(</span>UFD3F<span class="o">)</span>
     47     0x003b <span class="o">(</span>semicolon<span class="o">)</span>  0x003a <span class="o">(</span>colon<span class="o">)</span>  0x10006a9 <span class="o">(</span>Arabic_keheh<span class="o">)</span>    0x003a <span class="o">(</span>colon<span class="o">)</span>  0x003b <span class="o">(</span>semicolon<span class="o">)</span>
     48     0x0027 <span class="o">(</span>apostrophe<span class="o">)</span> 0x0022 <span class="o">(</span>quotedbl<span class="o">)</span>   0x10006af <span class="o">(</span>Arabic_gaf<span class="o">)</span>  0x05bb <span class="o">(</span>Arabic_semicolon<span class="o">)</span>   0x0022 <span class="o">(</span>quotedbl<span class="o">)</span>
     49     0x0060 <span class="o">(</span>grave<span class="o">)</span>  0x007e <span class="o">(</span>asciitilde<span class="o">)</span> 0x100200d <span class="o">(</span>U200D<span class="o">)</span>   0x00f7 <span class="o">(</span>division<span class="o">)</span>   0x007e <span class="o">(</span>asciitilde<span class="o">)</span>
     50     0xffe1 <span class="o">(</span>Shift_L<span class="o">)</span>    0xfe0a <span class="o">(</span>ISO_Prev_Group<span class="o">)</span> 0xffe1 <span class="o">(</span>Shift_L<span class="o">)</span>    0xfe0a <span class="o">(</span>ISO_Prev_Group<span class="o">)</span>
     51     0x005c <span class="o">(</span>backslash<span class="o">)</span>  0x007c <span class="o">(</span>bar<span class="o">)</span>    0x005c <span class="o">(</span>backslash<span class="o">)</span>  0x007c <span class="o">(</span>bar<span class="o">)</span>    0x1002010 <span class="o">(</span>U2010<span class="o">)</span>
     52     0x007a <span class="o">(</span>z<span class="o">)</span>  0x005a <span class="o">(</span>Z<span class="o">)</span>  0x05d8 <span class="o">(</span>Arabic_zah<span class="o">)</span> 0x05e3 <span class="o">(</span>Arabic_kaf<span class="o">)</span> 0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     53     0x0078 <span class="o">(</span>x<span class="o">)</span>  0x0058 <span class="o">(</span>X<span class="o">)</span>  0x05d7 <span class="o">(</span>Arabic_tah<span class="o">)</span> 0x1000653 <span class="o">(</span>Arabic_madda_above<span class="o">)</span>  0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     54     0x0063 <span class="o">(</span>c<span class="o">)</span>  0x0043 <span class="o">(</span>C<span class="o">)</span>  0x05d2 <span class="o">(</span>Arabic_zain<span class="o">)</span>    0x1000698 <span class="o">(</span>Arabic_jeh<span class="o">)</span>  0xffffff <span class="o">(</span>VoidSymbol<span class="o">)</span>
     55     0x0076 <span class="o">(</span>v<span class="o">)</span>  0x0056 <span class="o">(</span>V<span class="o">)</span>  0x05d1 <span class="o">(</span>Arabic_ra<span class="o">)</span>  0x1000670 <span class="o">(</span>Arabic_superscript_alef<span class="o">)</span> 0x1000656 <span class="o">(</span>U0656<span class="o">)</span>
     56     0x0062 <span class="o">(</span>b<span class="o">)</span>  0x0042 <span class="o">(</span>B<span class="o">)</span>  0x05d0 <span class="o">(</span>Arabic_thal<span class="o">)</span>    0x100200c <span class="o">(</span>U200C<span class="o">)</span>   0x100200d <span class="o">(</span>U200D<span class="o">)</span>
     57     0x006e <span class="o">(</span>n<span class="o">)</span>  0x004e <span class="o">(</span>N<span class="o">)</span>  0x05cf <span class="o">(</span>Arabic_dal<span class="o">)</span> 0x1000654 <span class="o">(</span>Arabic_hamza_above<span class="o">)</span>  0x1000655 <span class="o">(</span>Arabic_hamza_below<span class="o">)</span>
     58     0x006d <span class="o">(</span>m<span class="o">)</span>  0x004d <span class="o">(</span>M<span class="o">)</span>  0x100067e <span class="o">(</span>Arabic_peh<span class="o">)</span>  0x05c1 <span class="o">(</span>Arabic_hamza<span class="o">)</span>   0x0aae <span class="o">(</span>ellipsis<span class="o">)</span>
     59     0x002c <span class="o">(</span>comma<span class="o">)</span>  0x003c <span class="o">(</span>less<span class="o">)</span>   0x05e8 <span class="o">(</span>Arabic_waw<span class="o">)</span> 0x003e <span class="o">(</span>greater<span class="o">)</span>    0x002c <span class="o">(</span>comma<span class="o">)</span>
     60     0x002e <span class="o">(</span>period<span class="o">)</span> 0x003e <span class="o">(</span>greater<span class="o">)</span>    0x002e <span class="o">(</span>period<span class="o">)</span> 0x003c <span class="o">(</span>less<span class="o">)</span>   0x0027 <span class="o">(</span>apostrophe<span class="o">)</span>
     61     0x002f <span class="o">(</span>slash<span class="o">)</span>  0x003f <span class="o">(</span>question<span class="o">)</span>   0x002f <span class="o">(</span>slash<span class="o">)</span>  0x05bf <span class="o">(</span>Arabic_question_mark<span class="o">)</span>   0x003f <span class="o">(</span>question<span class="o">)</span>
     62     0xffe2 <span class="o">(</span>Shift_R<span class="o">)</span>    0xfe08 <span class="o">(</span>ISO_Next_Group<span class="o">)</span> 0xffe2 <span class="o">(</span>Shift_R<span class="o">)</span>    0xfe08 <span class="o">(</span>ISO_Next_Group<span class="o">)</span>
     63     0xffaa <span class="o">(</span>KP_Multiply<span class="o">)</span>    0xffaa <span class="o">(</span>KP_Multiply<span class="o">)</span>    0xffaa <span class="o">(</span>KP_Multiply<span class="o">)</span>    0xffaa <span class="o">(</span>KP_Multiply<span class="o">)</span>    0xffaa <span class="o">(</span>KP_Multiply<span class="o">)</span>    0xffaa <span class="o">(</span>KP_Multiply<span class="o">)</span>    0x1008fe21 <span class="o">(</span>XF86ClearGrab<span class="o">)</span>  0xffaa <span class="o">(</span>KP_Multiply<span class="o">)</span>    0xffaa <span class="o">(</span>KP_Multiply<span class="o">)</span>    0x1008fe21 <span class="o">(</span>XF86ClearGrab<span class="o">)</span>
     64     0xffe9 <span class="o">(</span>Alt_L<span class="o">)</span>  0xffe7 <span class="o">(</span>Meta_L<span class="o">)</span> 0xffe9 <span class="o">(</span>Alt_L<span class="o">)</span>  0xffe7 <span class="o">(</span>Meta_L<span class="o">)</span>
     65     0x0020 <span class="o">(</span>space<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x0020 <span class="o">(</span>space<span class="o">)</span>  0x100200c <span class="o">(</span>U200C<span class="o">)</span>   0x00a0 <span class="o">(</span>nobreakspace<span class="o">)</span>   0x100202f <span class="o">(</span>U202F<span class="o">)</span>
     66     0xff1b <span class="o">(</span>Escape<span class="o">)</span> 0xffe5 <span class="o">(</span>Caps_Lock<span class="o">)</span>  0xff1b <span class="o">(</span>Escape<span class="o">)</span> 0xffe5 <span class="o">(</span>Caps_Lock<span class="o">)</span>
     67     0xffbe <span class="o">(</span>F1<span class="o">)</span> 0xffbe <span class="o">(</span>F1<span class="o">)</span> 0xffbe <span class="o">(</span>F1<span class="o">)</span> 0xffbe <span class="o">(</span>F1<span class="o">)</span> 0xffbe <span class="o">(</span>F1<span class="o">)</span> 0xffbe <span class="o">(</span>F1<span class="o">)</span> 0x1008fe01 <span class="o">(</span>XF86Switch_VT_1<span class="o">)</span>    0xffbe <span class="o">(</span>F1<span class="o">)</span> 0xffbe <span class="o">(</span>F1<span class="o">)</span> 0x1008fe01 <span class="o">(</span>XF86Switch_VT_1<span class="o">)</span>
     68     0xffbf <span class="o">(</span>F2<span class="o">)</span> 0xffbf <span class="o">(</span>F2<span class="o">)</span> 0xffbf <span class="o">(</span>F2<span class="o">)</span> 0xffbf <span class="o">(</span>F2<span class="o">)</span> 0xffbf <span class="o">(</span>F2<span class="o">)</span> 0xffbf <span class="o">(</span>F2<span class="o">)</span> 0x1008fe02 <span class="o">(</span>XF86Switch_VT_2<span class="o">)</span>    0xffbf <span class="o">(</span>F2<span class="o">)</span> 0xffbf <span class="o">(</span>F2<span class="o">)</span> 0x1008fe02 <span class="o">(</span>XF86Switch_VT_2<span class="o">)</span>
     69     0xffc0 <span class="o">(</span>F3<span class="o">)</span> 0xffc0 <span class="o">(</span>F3<span class="o">)</span> 0xffc0 <span class="o">(</span>F3<span class="o">)</span> 0xffc0 <span class="o">(</span>F3<span class="o">)</span> 0xffc0 <span class="o">(</span>F3<span class="o">)</span> 0xffc0 <span class="o">(</span>F3<span class="o">)</span> 0x1008fe03 <span class="o">(</span>XF86Switch_VT_3<span class="o">)</span>    0xffc0 <span class="o">(</span>F3<span class="o">)</span> 0xffc0 <span class="o">(</span>F3<span class="o">)</span> 0x1008fe03 <span class="o">(</span>XF86Switch_VT_3<span class="o">)</span>
     70     0xffc1 <span class="o">(</span>F4<span class="o">)</span> 0xffc1 <span class="o">(</span>F4<span class="o">)</span> 0xffc1 <span class="o">(</span>F4<span class="o">)</span> 0xffc1 <span class="o">(</span>F4<span class="o">)</span> 0xffc1 <span class="o">(</span>F4<span class="o">)</span> 0xffc1 <span class="o">(</span>F4<span class="o">)</span> 0x1008fe04 <span class="o">(</span>XF86Switch_VT_4<span class="o">)</span>    0xffc1 <span class="o">(</span>F4<span class="o">)</span> 0xffc1 <span class="o">(</span>F4<span class="o">)</span> 0x1008fe04 <span class="o">(</span>XF86Switch_VT_4<span class="o">)</span>
     71     0xffc2 <span class="o">(</span>F5<span class="o">)</span> 0xffc2 <span class="o">(</span>F5<span class="o">)</span> 0xffc2 <span class="o">(</span>F5<span class="o">)</span> 0xffc2 <span class="o">(</span>F5<span class="o">)</span> 0xffc2 <span class="o">(</span>F5<span class="o">)</span> 0xffc2 <span class="o">(</span>F5<span class="o">)</span> 0x1008fe05 <span class="o">(</span>XF86Switch_VT_5<span class="o">)</span>    0xffc2 <span class="o">(</span>F5<span class="o">)</span> 0xffc2 <span class="o">(</span>F5<span class="o">)</span> 0x1008fe05 <span class="o">(</span>XF86Switch_VT_5<span class="o">)</span>
     72     0xffc3 <span class="o">(</span>F6<span class="o">)</span> 0xffc3 <span class="o">(</span>F6<span class="o">)</span> 0xffc3 <span class="o">(</span>F6<span class="o">)</span> 0xffc3 <span class="o">(</span>F6<span class="o">)</span> 0xffc3 <span class="o">(</span>F6<span class="o">)</span> 0xffc3 <span class="o">(</span>F6<span class="o">)</span> 0x1008fe06 <span class="o">(</span>XF86Switch_VT_6<span class="o">)</span>    0xffc3 <span class="o">(</span>F6<span class="o">)</span> 0xffc3 <span class="o">(</span>F6<span class="o">)</span> 0x1008fe06 <span class="o">(</span>XF86Switch_VT_6<span class="o">)</span>
     73     0xffc4 <span class="o">(</span>F7<span class="o">)</span> 0xffc4 <span class="o">(</span>F7<span class="o">)</span> 0xffc4 <span class="o">(</span>F7<span class="o">)</span> 0xffc4 <span class="o">(</span>F7<span class="o">)</span> 0xffc4 <span class="o">(</span>F7<span class="o">)</span> 0xffc4 <span class="o">(</span>F7<span class="o">)</span> 0x1008fe07 <span class="o">(</span>XF86Switch_VT_7<span class="o">)</span>    0xffc4 <span class="o">(</span>F7<span class="o">)</span> 0xffc4 <span class="o">(</span>F7<span class="o">)</span> 0x1008fe07 <span class="o">(</span>XF86Switch_VT_7<span class="o">)</span>
     74     0xffc5 <span class="o">(</span>F8<span class="o">)</span> 0xffc5 <span class="o">(</span>F8<span class="o">)</span> 0xffc5 <span class="o">(</span>F8<span class="o">)</span> 0xffc5 <span class="o">(</span>F8<span class="o">)</span> 0xffc5 <span class="o">(</span>F8<span class="o">)</span> 0xffc5 <span class="o">(</span>F8<span class="o">)</span> 0x1008fe08 <span class="o">(</span>XF86Switch_VT_8<span class="o">)</span>    0xffc5 <span class="o">(</span>F8<span class="o">)</span> 0xffc5 <span class="o">(</span>F8<span class="o">)</span> 0x1008fe08 <span class="o">(</span>XF86Switch_VT_8<span class="o">)</span>
     75     0xffc6 <span class="o">(</span>F9<span class="o">)</span> 0xffc6 <span class="o">(</span>F9<span class="o">)</span> 0xffc6 <span class="o">(</span>F9<span class="o">)</span> 0xffc6 <span class="o">(</span>F9<span class="o">)</span> 0xffc6 <span class="o">(</span>F9<span class="o">)</span> 0xffc6 <span class="o">(</span>F9<span class="o">)</span> 0x1008fe09 <span class="o">(</span>XF86Switch_VT_9<span class="o">)</span>    0xffc6 <span class="o">(</span>F9<span class="o">)</span> 0xffc6 <span class="o">(</span>F9<span class="o">)</span> 0x1008fe09 <span class="o">(</span>XF86Switch_VT_9<span class="o">)</span>
     76     0xffc7 <span class="o">(</span>F10<span class="o">)</span>    0xffc7 <span class="o">(</span>F10<span class="o">)</span>    0xffc7 <span class="o">(</span>F10<span class="o">)</span>    0xffc7 <span class="o">(</span>F10<span class="o">)</span>    0xffc7 <span class="o">(</span>F10<span class="o">)</span>    0xffc7 <span class="o">(</span>F10<span class="o">)</span>    0x1008fe0a <span class="o">(</span>XF86Switch_VT_10<span class="o">)</span>   0xffc7 <span class="o">(</span>F10<span class="o">)</span>    0xffc7 <span class="o">(</span>F10<span class="o">)</span>    0x1008fe0a <span class="o">(</span>XF86Switch_VT_10<span class="o">)</span>
     77     0xff7f <span class="o">(</span>Num_Lock<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff7f <span class="o">(</span>Num_Lock<span class="o">)</span>
     78     0xff14 <span class="o">(</span>Scroll_Lock<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff14 <span class="o">(</span>Scroll_Lock<span class="o">)</span>
     79     0xff95 <span class="o">(</span>KP_Home<span class="o">)</span>    0xffb7 <span class="o">(</span>KP_7<span class="o">)</span>   0xff95 <span class="o">(</span>KP_Home<span class="o">)</span>    0xffb7 <span class="o">(</span>KP_7<span class="o">)</span>
     80     0xff97 <span class="o">(</span>KP_Up<span class="o">)</span>  0xffb8 <span class="o">(</span>KP_8<span class="o">)</span>   0xff97 <span class="o">(</span>KP_Up<span class="o">)</span>  0xffb8 <span class="o">(</span>KP_8<span class="o">)</span>
     81     0xff9a <span class="o">(</span>KP_Prior<span class="o">)</span>   0xffb9 <span class="o">(</span>KP_9<span class="o">)</span>   0xff9a <span class="o">(</span>KP_Prior<span class="o">)</span>   0xffb9 <span class="o">(</span>KP_9<span class="o">)</span>
     82     0xffad <span class="o">(</span>KP_Subtract<span class="o">)</span>    0xffad <span class="o">(</span>KP_Subtract<span class="o">)</span>    0xffad <span class="o">(</span>KP_Subtract<span class="o">)</span>    0xffad <span class="o">(</span>KP_Subtract<span class="o">)</span>    0xffad <span class="o">(</span>KP_Subtract<span class="o">)</span>    0xffad <span class="o">(</span>KP_Subtract<span class="o">)</span>    0x1008fe23 <span class="o">(</span>XF86Prev_VMode<span class="o">)</span> 0xffad <span class="o">(</span>KP_Subtract<span class="o">)</span>    0xffad <span class="o">(</span>KP_Subtract<span class="o">)</span>    0x1008fe23 <span class="o">(</span>XF86Prev_VMode<span class="o">)</span>
     83     0xff96 <span class="o">(</span>KP_Left<span class="o">)</span>    0xffb4 <span class="o">(</span>KP_4<span class="o">)</span>   0xff96 <span class="o">(</span>KP_Left<span class="o">)</span>    0xffb4 <span class="o">(</span>KP_4<span class="o">)</span>
     84     0xff9d <span class="o">(</span>KP_Begin<span class="o">)</span>   0xffb5 <span class="o">(</span>KP_5<span class="o">)</span>   0xff9d <span class="o">(</span>KP_Begin<span class="o">)</span>   0xffb5 <span class="o">(</span>KP_5<span class="o">)</span>
     85     0xff98 <span class="o">(</span>KP_Right<span class="o">)</span>   0xffb6 <span class="o">(</span>KP_6<span class="o">)</span>   0xff98 <span class="o">(</span>KP_Right<span class="o">)</span>   0xffb6 <span class="o">(</span>KP_6<span class="o">)</span>
     86     0xffab <span class="o">(</span>KP_Add<span class="o">)</span> 0xffab <span class="o">(</span>KP_Add<span class="o">)</span> 0xffab <span class="o">(</span>KP_Add<span class="o">)</span> 0xffab <span class="o">(</span>KP_Add<span class="o">)</span> 0xffab <span class="o">(</span>KP_Add<span class="o">)</span> 0xffab <span class="o">(</span>KP_Add<span class="o">)</span> 0x1008fe22 <span class="o">(</span>XF86Next_VMode<span class="o">)</span> 0xffab <span class="o">(</span>KP_Add<span class="o">)</span> 0xffab <span class="o">(</span>KP_Add<span class="o">)</span> 0x1008fe22 <span class="o">(</span>XF86Next_VMode<span class="o">)</span>
     87     0xff9c <span class="o">(</span>KP_End<span class="o">)</span> 0xffb1 <span class="o">(</span>KP_1<span class="o">)</span>   0xff9c <span class="o">(</span>KP_End<span class="o">)</span> 0xffb1 <span class="o">(</span>KP_1<span class="o">)</span>
     88     0xff99 <span class="o">(</span>KP_Down<span class="o">)</span>    0xffb2 <span class="o">(</span>KP_2<span class="o">)</span>   0xff99 <span class="o">(</span>KP_Down<span class="o">)</span>    0xffb2 <span class="o">(</span>KP_2<span class="o">)</span>
     89     0xff9b <span class="o">(</span>KP_Next<span class="o">)</span>    0xffb3 <span class="o">(</span>KP_3<span class="o">)</span>   0xff9b <span class="o">(</span>KP_Next<span class="o">)</span>    0xffb3 <span class="o">(</span>KP_3<span class="o">)</span>
     90     0xff9e <span class="o">(</span>KP_Insert<span class="o">)</span>  0xffb0 <span class="o">(</span>KP_0<span class="o">)</span>   0xff9e <span class="o">(</span>KP_Insert<span class="o">)</span>  0xffb0 <span class="o">(</span>KP_0<span class="o">)</span>
     91     0xff9f <span class="o">(</span>KP_Delete<span class="o">)</span>  0xffae <span class="o">(</span>KP_Decimal<span class="o">)</span> 0xff9f <span class="o">(</span>KP_Delete<span class="o">)</span>  0xffae <span class="o">(</span>KP_Decimal<span class="o">)</span>
     92     0xfe03 <span class="o">(</span>ISO_Level3_Shift<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xfe03 <span class="o">(</span>ISO_Level3_Shift<span class="o">)</span>
     93
     94     0x003c <span class="o">(</span>less<span class="o">)</span>   0x003e <span class="o">(</span>greater<span class="o">)</span>    0x003c <span class="o">(</span>less<span class="o">)</span>   0x003e <span class="o">(</span>greater<span class="o">)</span>    0x007c <span class="o">(</span>bar<span class="o">)</span>    0x00a6 <span class="o">(</span>brokenbar<span class="o">)</span>  0x007c <span class="o">(</span>bar<span class="o">)</span>    0x00a6 <span class="o">(</span>brokenbar<span class="o">)</span>
     95     0xffc8 <span class="o">(</span>F11<span class="o">)</span>    0xffc8 <span class="o">(</span>F11<span class="o">)</span>    0xffc8 <span class="o">(</span>F11<span class="o">)</span>    0xffc8 <span class="o">(</span>F11<span class="o">)</span>    0xffc8 <span class="o">(</span>F11<span class="o">)</span>    0xffc8 <span class="o">(</span>F11<span class="o">)</span>    0x1008fe0b <span class="o">(</span>XF86Switch_VT_11<span class="o">)</span>   0xffc8 <span class="o">(</span>F11<span class="o">)</span>    0xffc8 <span class="o">(</span>F11<span class="o">)</span>    0x1008fe0b <span class="o">(</span>XF86Switch_VT_11<span class="o">)</span>
     96     0xffc9 <span class="o">(</span>F12<span class="o">)</span>    0xffc9 <span class="o">(</span>F12<span class="o">)</span>    0xffc9 <span class="o">(</span>F12<span class="o">)</span>    0xffc9 <span class="o">(</span>F12<span class="o">)</span>    0xffc9 <span class="o">(</span>F12<span class="o">)</span>    0xffc9 <span class="o">(</span>F12<span class="o">)</span>    0x1008fe0c <span class="o">(</span>XF86Switch_VT_12<span class="o">)</span>   0xffc9 <span class="o">(</span>F12<span class="o">)</span>    0xffc9 <span class="o">(</span>F12<span class="o">)</span>    0x1008fe0c <span class="o">(</span>XF86Switch_VT_12<span class="o">)</span>
     97
     98     0xff26 <span class="o">(</span>Katakana<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff26 <span class="o">(</span>Katakana<span class="o">)</span>
     99     0xff25 <span class="o">(</span>Hiragana<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff25 <span class="o">(</span>Hiragana<span class="o">)</span>
    100     0xff23 <span class="o">(</span>Henkan_Mode<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff23 <span class="o">(</span>Henkan_Mode<span class="o">)</span>
    101     0xff27 <span class="o">(</span>Hiragana_Katakana<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff27 <span class="o">(</span>Hiragana_Katakana<span class="o">)</span>
    102     0xff22 <span class="o">(</span>Muhenkan<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff22 <span class="o">(</span>Muhenkan<span class="o">)</span>
    103
    104     0xff8d <span class="o">(</span>KP_Enter<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff8d <span class="o">(</span>KP_Enter<span class="o">)</span>
    105     0xffe4 <span class="o">(</span>Control_R<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffe4 <span class="o">(</span>Control_R<span class="o">)</span>
    106     0xffaf <span class="o">(</span>KP_Divide<span class="o">)</span>  0xffaf <span class="o">(</span>KP_Divide<span class="o">)</span>  0xffaf <span class="o">(</span>KP_Divide<span class="o">)</span>  0xffaf <span class="o">(</span>KP_Divide<span class="o">)</span>  0xffaf <span class="o">(</span>KP_Divide<span class="o">)</span>  0xffaf <span class="o">(</span>KP_Divide<span class="o">)</span>  0x1008fe20 <span class="o">(</span>XF86Ungrab<span class="o">)</span> 0xffaf <span class="o">(</span>KP_Divide<span class="o">)</span>  0xffaf <span class="o">(</span>KP_Divide<span class="o">)</span>  0x1008fe20 <span class="o">(</span>XF86Ungrab<span class="o">)</span>
    107     0xffec <span class="o">(</span>Super_R<span class="o">)</span>    0xffec <span class="o">(</span>Super_R<span class="o">)</span>    0xffec <span class="o">(</span>Super_R<span class="o">)</span>    0xffec <span class="o">(</span>Super_R<span class="o">)</span>
    108     0xfe03 <span class="o">(</span>ISO_Level3_Shift<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xfe03 <span class="o">(</span>ISO_Level3_Shift<span class="o">)</span>
    109     0xff0a <span class="o">(</span>Linefeed<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff0a <span class="o">(</span>Linefeed<span class="o">)</span>
    110     0xff50 <span class="o">(</span>Home<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff50 <span class="o">(</span>Home<span class="o">)</span>
    111     0xff52 <span class="o">(</span>Up<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff52 <span class="o">(</span>Up<span class="o">)</span>
    112     0xff55 <span class="o">(</span>Prior<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff55 <span class="o">(</span>Prior<span class="o">)</span>
    113     0xff51 <span class="o">(</span>Left<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff51 <span class="o">(</span>Left<span class="o">)</span>
    114     0xff53 <span class="o">(</span>Right<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff53 <span class="o">(</span>Right<span class="o">)</span>
    115     0xff57 <span class="o">(</span>End<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff57 <span class="o">(</span>End<span class="o">)</span>
    116     0xff54 <span class="o">(</span>Down<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff54 <span class="o">(</span>Down<span class="o">)</span>
    117     0xff56 <span class="o">(</span>Next<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff56 <span class="o">(</span>Next<span class="o">)</span>
    118     0xff63 <span class="o">(</span>Insert<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff63 <span class="o">(</span>Insert<span class="o">)</span>
    119     0xffff <span class="o">(</span>Delete<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffff <span class="o">(</span>Delete<span class="o">)</span>
    120
    121     0x1008ff12 <span class="o">(</span>XF86AudioMute<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff12 <span class="o">(</span>XF86AudioMute<span class="o">)</span>
    122     0x1008ff11 <span class="o">(</span>XF86AudioLowerVolume<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff11 <span class="o">(</span>XF86AudioLowerVolume<span class="o">)</span>
    123     0x1008ff13 <span class="o">(</span>XF86AudioRaiseVolume<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff13 <span class="o">(</span>XF86AudioRaiseVolume<span class="o">)</span>
    124     0x1008ff2a <span class="o">(</span>XF86PowerOff<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff2a <span class="o">(</span>XF86PowerOff<span class="o">)</span>
    125     0xffbd <span class="o">(</span>KP_Equal<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffbd <span class="o">(</span>KP_Equal<span class="o">)</span>
    126     0x00b1 <span class="o">(</span>plusminus<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x00b1 <span class="o">(</span>plusminus<span class="o">)</span>
    127     0xff13 <span class="o">(</span>Pause<span class="o">)</span>  0xff6b <span class="o">(</span>Break<span class="o">)</span>  0xff13 <span class="o">(</span>Pause<span class="o">)</span>  0xff6b <span class="o">(</span>Break<span class="o">)</span>
    128     0x1008ff4a <span class="o">(</span>XF86LaunchA<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff4a <span class="o">(</span>XF86LaunchA<span class="o">)</span>
    129     0xffae <span class="o">(</span>KP_Decimal<span class="o">)</span> 0xffae <span class="o">(</span>KP_Decimal<span class="o">)</span> 0xffae <span class="o">(</span>KP_Decimal<span class="o">)</span> 0xffae <span class="o">(</span>KP_Decimal<span class="o">)</span>
    130     0xff31 <span class="o">(</span>Hangul<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff31 <span class="o">(</span>Hangul<span class="o">)</span>
    131     0xff34 <span class="o">(</span>Hangul_Hanja<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff34 <span class="o">(</span>Hangul_Hanja<span class="o">)</span>
    132
    133     0xffeb <span class="o">(</span>Super_L<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffeb <span class="o">(</span>Super_L<span class="o">)</span>
    134     0xffec <span class="o">(</span>Super_R<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffec <span class="o">(</span>Super_R<span class="o">)</span>
    135     0xff67 <span class="o">(</span>Menu<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff67 <span class="o">(</span>Menu<span class="o">)</span>
    136     0xff69 <span class="o">(</span>Cancel<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff69 <span class="o">(</span>Cancel<span class="o">)</span>
    137     0xff66 <span class="o">(</span>Redo<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff66 <span class="o">(</span>Redo<span class="o">)</span>
    138     0x1005ff70 <span class="o">(</span>SunProps<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1005ff70 <span class="o">(</span>SunProps<span class="o">)</span>
    139     0xff65 <span class="o">(</span>Undo<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff65 <span class="o">(</span>Undo<span class="o">)</span>
    140     0x1005ff71 <span class="o">(</span>SunFront<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1005ff71 <span class="o">(</span>SunFront<span class="o">)</span>
    141     0x1008ff57 <span class="o">(</span>XF86Copy<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff57 <span class="o">(</span>XF86Copy<span class="o">)</span>
    142     0x1008ff6b <span class="o">(</span>XF86Open<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff6b <span class="o">(</span>XF86Open<span class="o">)</span>
    143     0x1008ff6d <span class="o">(</span>XF86Paste<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff6d <span class="o">(</span>XF86Paste<span class="o">)</span>
    144     0xff68 <span class="o">(</span>Find<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff68 <span class="o">(</span>Find<span class="o">)</span>
    145     0x1008ff58 <span class="o">(</span>XF86Cut<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff58 <span class="o">(</span>XF86Cut<span class="o">)</span>
    146     0xff6a <span class="o">(</span>Help<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff6a <span class="o">(</span>Help<span class="o">)</span>
    147     0x1008ff65 <span class="o">(</span>XF86MenuKB<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff65 <span class="o">(</span>XF86MenuKB<span class="o">)</span>
    148     0x1008ff1d <span class="o">(</span>XF86Calculator<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff1d <span class="o">(</span>XF86Calculator<span class="o">)</span>
    149
    150     0x1008ff2f <span class="o">(</span>XF86Sleep<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff2f <span class="o">(</span>XF86Sleep<span class="o">)</span>
    151     0x1008ff2b <span class="o">(</span>XF86WakeUp<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff2b <span class="o">(</span>XF86WakeUp<span class="o">)</span>
    152     0x1008ff5d <span class="o">(</span>XF86Explorer<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff5d <span class="o">(</span>XF86Explorer<span class="o">)</span>
    153     0x1008ff7b <span class="o">(</span>XF86Send<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff7b <span class="o">(</span>XF86Send<span class="o">)</span>
    154
    155     0x1008ff8a <span class="o">(</span>XF86Xfer<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff8a <span class="o">(</span>XF86Xfer<span class="o">)</span>
    156     0x1008ff41 <span class="o">(</span>XF86Launch1<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff41 <span class="o">(</span>XF86Launch1<span class="o">)</span>
    157     0x1008ff42 <span class="o">(</span>XF86Launch2<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff42 <span class="o">(</span>XF86Launch2<span class="o">)</span>
    158     0x1008ff2e <span class="o">(</span>XF86WWW<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff2e <span class="o">(</span>XF86WWW<span class="o">)</span>
    159     0x1008ff5a <span class="o">(</span>XF86DOS<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff5a <span class="o">(</span>XF86DOS<span class="o">)</span>
    160     0x1008ff2d <span class="o">(</span>XF86ScreenSaver<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff2d <span class="o">(</span>XF86ScreenSaver<span class="o">)</span>
    161     0x1008ff74 <span class="o">(</span>XF86RotateWindows<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff74 <span class="o">(</span>XF86RotateWindows<span class="o">)</span>
    162     0x1008ff7f <span class="o">(</span>XF86TaskPane<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff7f <span class="o">(</span>XF86TaskPane<span class="o">)</span>
    163     0x1008ff19 <span class="o">(</span>XF86Mail<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff19 <span class="o">(</span>XF86Mail<span class="o">)</span>
    164     0x1008ff30 <span class="o">(</span>XF86Favorites<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff30 <span class="o">(</span>XF86Favorites<span class="o">)</span>
    165     0x1008ff33 <span class="o">(</span>XF86MyComputer<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff33 <span class="o">(</span>XF86MyComputer<span class="o">)</span>
    166     0x1008ff26 <span class="o">(</span>XF86Back<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff26 <span class="o">(</span>XF86Back<span class="o">)</span>
    167     0x1008ff27 <span class="o">(</span>XF86Forward<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff27 <span class="o">(</span>XF86Forward<span class="o">)</span>
    168
    169     0x1008ff2c <span class="o">(</span>XF86Eject<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff2c <span class="o">(</span>XF86Eject<span class="o">)</span>
    170     0x1008ff2c <span class="o">(</span>XF86Eject<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff2c <span class="o">(</span>XF86Eject<span class="o">)</span>
    171     0x1008ff17 <span class="o">(</span>XF86AudioNext<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff17 <span class="o">(</span>XF86AudioNext<span class="o">)</span>
    172     0x1008ff14 <span class="o">(</span>XF86AudioPlay<span class="o">)</span>  0x1008ff31 <span class="o">(</span>XF86AudioPause<span class="o">)</span> 0x1008ff14 <span class="o">(</span>XF86AudioPlay<span class="o">)</span>  0x1008ff31 <span class="o">(</span>XF86AudioPause<span class="o">)</span>
    173     0x1008ff16 <span class="o">(</span>XF86AudioPrev<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff16 <span class="o">(</span>XF86AudioPrev<span class="o">)</span>
    174     0x1008ff15 <span class="o">(</span>XF86AudioStop<span class="o">)</span>  0x1008ff2c <span class="o">(</span>XF86Eject<span class="o">)</span>  0x1008ff15 <span class="o">(</span>XF86AudioStop<span class="o">)</span>  0x1008ff2c <span class="o">(</span>XF86Eject<span class="o">)</span>
    175     0x1008ff1c <span class="o">(</span>XF86AudioRecord<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff1c <span class="o">(</span>XF86AudioRecord<span class="o">)</span>
    176     0x1008ff3e <span class="o">(</span>XF86AudioRewind<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff3e <span class="o">(</span>XF86AudioRewind<span class="o">)</span>
    177     0x1008ff6e <span class="o">(</span>XF86Phone<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff6e <span class="o">(</span>XF86Phone<span class="o">)</span>
    178
    179     0x1008ff81 <span class="o">(</span>XF86Tools<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff81 <span class="o">(</span>XF86Tools<span class="o">)</span>
    180     0x1008ff18 <span class="o">(</span>XF86HomePage<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff18 <span class="o">(</span>XF86HomePage<span class="o">)</span>
    181     0x1008ff73 <span class="o">(</span>XF86Reload<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff73 <span class="o">(</span>XF86Reload<span class="o">)</span>
    182     0x1008ff56 <span class="o">(</span>XF86Close<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff56 <span class="o">(</span>XF86Close<span class="o">)</span>
    183
    184
    185     0x1008ff78 <span class="o">(</span>XF86ScrollUp<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff78 <span class="o">(</span>XF86ScrollUp<span class="o">)</span>
    186     0x1008ff79 <span class="o">(</span>XF86ScrollDown<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff79 <span class="o">(</span>XF86ScrollDown<span class="o">)</span>
    187     0x0028 <span class="o">(</span>parenleft<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x0028 <span class="o">(</span>parenleft<span class="o">)</span>
    188     0x0029 <span class="o">(</span>parenright<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x0029 <span class="o">(</span>parenright<span class="o">)</span>
    189     0x1008ff68 <span class="o">(</span>XF86New<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff68 <span class="o">(</span>XF86New<span class="o">)</span>
    190     0xff66 <span class="o">(</span>Redo<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff66 <span class="o">(</span>Redo<span class="o">)</span>
    191     0x1008ff81 <span class="o">(</span>XF86Tools<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff81 <span class="o">(</span>XF86Tools<span class="o">)</span>
    192     0x1008ff45 <span class="o">(</span>XF86Launch5<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff45 <span class="o">(</span>XF86Launch5<span class="o">)</span>
    193     0x1008ff46 <span class="o">(</span>XF86Launch6<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff46 <span class="o">(</span>XF86Launch6<span class="o">)</span>
    194     0x1008ff47 <span class="o">(</span>XF86Launch7<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff47 <span class="o">(</span>XF86Launch7<span class="o">)</span>
    195     0x1008ff48 <span class="o">(</span>XF86Launch8<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff48 <span class="o">(</span>XF86Launch8<span class="o">)</span>
    196     0x1008ff49 <span class="o">(</span>XF86Launch9<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff49 <span class="o">(</span>XF86Launch9<span class="o">)</span>
    197
    198     0x1008ffb2 <span class="o">(</span>XF86AudioMicMute<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ffb2 <span class="o">(</span>XF86AudioMicMute<span class="o">)</span>
    199     0x1008ffa9 <span class="o">(</span>XF86TouchpadToggle<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ffa9 <span class="o">(</span>XF86TouchpadToggle<span class="o">)</span>
    200     0x1008ffb0 <span class="o">(</span>XF86TouchpadOn<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ffb0 <span class="o">(</span>XF86TouchpadOn<span class="o">)</span>
    201     0x1008ffb1 <span class="o">(</span>XF86TouchpadOff<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ffb1 <span class="o">(</span>XF86TouchpadOff<span class="o">)</span>
    202
    203     0xff7e <span class="o">(</span>Mode_switch<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff7e <span class="o">(</span>Mode_switch<span class="o">)</span>
    204     0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffe9 <span class="o">(</span>Alt_L<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffe9 <span class="o">(</span>Alt_L<span class="o">)</span>
    205     0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffe7 <span class="o">(</span>Meta_L<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffe7 <span class="o">(</span>Meta_L<span class="o">)</span>
    206     0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffeb <span class="o">(</span>Super_L<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffeb <span class="o">(</span>Super_L<span class="o">)</span>
    207     0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffed <span class="o">(</span>Hyper_L<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xffed <span class="o">(</span>Hyper_L<span class="o">)</span>
    208     0x1008ff14 <span class="o">(</span>XF86AudioPlay<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff14 <span class="o">(</span>XF86AudioPlay<span class="o">)</span>
    209     0x1008ff31 <span class="o">(</span>XF86AudioPause<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff31 <span class="o">(</span>XF86AudioPause<span class="o">)</span>
    210     0x1008ff43 <span class="o">(</span>XF86Launch3<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff43 <span class="o">(</span>XF86Launch3<span class="o">)</span>
    211     0x1008ff44 <span class="o">(</span>XF86Launch4<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff44 <span class="o">(</span>XF86Launch4<span class="o">)</span>
    212     0x1008ff4b <span class="o">(</span>XF86LaunchB<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff4b <span class="o">(</span>XF86LaunchB<span class="o">)</span>
    213     0x1008ffa7 <span class="o">(</span>XF86Suspend<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ffa7 <span class="o">(</span>XF86Suspend<span class="o">)</span>
    214     0x1008ff56 <span class="o">(</span>XF86Close<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff56 <span class="o">(</span>XF86Close<span class="o">)</span>
    215     0x1008ff14 <span class="o">(</span>XF86AudioPlay<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff14 <span class="o">(</span>XF86AudioPlay<span class="o">)</span>
    216     0x1008ff97 <span class="o">(</span>XF86AudioForward<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff97 <span class="o">(</span>XF86AudioForward<span class="o">)</span>
    217
    218     0xff61 <span class="o">(</span>Print<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff61 <span class="o">(</span>Print<span class="o">)</span>
    219
    220     0x1008ff8f <span class="o">(</span>XF86WebCam<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff8f <span class="o">(</span>XF86WebCam<span class="o">)</span>
    221     0x1008ffb6 <span class="o">(</span>XF86AudioPreset<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ffb6 <span class="o">(</span>XF86AudioPreset<span class="o">)</span>
    222
    223     0x1008ff19 <span class="o">(</span>XF86Mail<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff19 <span class="o">(</span>XF86Mail<span class="o">)</span>
    224     0x1008ff8e <span class="o">(</span>XF86Messenger<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff8e <span class="o">(</span>XF86Messenger<span class="o">)</span>
    225     0x1008ff1b <span class="o">(</span>XF86Search<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff1b <span class="o">(</span>XF86Search<span class="o">)</span>
    226     0x1008ff5f <span class="o">(</span>XF86Go<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff5f <span class="o">(</span>XF86Go<span class="o">)</span>
    227     0x1008ff3c <span class="o">(</span>XF86Finance<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff3c <span class="o">(</span>XF86Finance<span class="o">)</span>
    228     0x1008ff5e <span class="o">(</span>XF86Game<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff5e <span class="o">(</span>XF86Game<span class="o">)</span>
    229     0x1008ff36 <span class="o">(</span>XF86Shop<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff36 <span class="o">(</span>XF86Shop<span class="o">)</span>
    230
    231     0xff69 <span class="o">(</span>Cancel<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0xff69 <span class="o">(</span>Cancel<span class="o">)</span>
    232     0x1008ff03 <span class="o">(</span>XF86MonBrightnessDown<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff03 <span class="o">(</span>XF86MonBrightnessDown<span class="o">)</span>
    233     0x1008ff02 <span class="o">(</span>XF86MonBrightnessUp<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff02 <span class="o">(</span>XF86MonBrightnessUp<span class="o">)</span>
    234     0x1008ff32 <span class="o">(</span>XF86AudioMedia<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff32 <span class="o">(</span>XF86AudioMedia<span class="o">)</span>
    235     0x1008ff59 <span class="o">(</span>XF86Display<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff59 <span class="o">(</span>XF86Display<span class="o">)</span>
    236     0x1008ff04 <span class="o">(</span>XF86KbdLightOnOff<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff04 <span class="o">(</span>XF86KbdLightOnOff<span class="o">)</span>
    237     0x1008ff06 <span class="o">(</span>XF86KbdBrightnessDown<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff06 <span class="o">(</span>XF86KbdBrightnessDown<span class="o">)</span>
    238     0x1008ff05 <span class="o">(</span>XF86KbdBrightnessUp<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff05 <span class="o">(</span>XF86KbdBrightnessUp<span class="o">)</span>
    239     0x1008ff7b <span class="o">(</span>XF86Send<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff7b <span class="o">(</span>XF86Send<span class="o">)</span>
    240     0x1008ff72 <span class="o">(</span>XF86Reply<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff72 <span class="o">(</span>XF86Reply<span class="o">)</span>
    241     0x1008ff90 <span class="o">(</span>XF86MailForward<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff90 <span class="o">(</span>XF86MailForward<span class="o">)</span>
    242     0x1008ff77 <span class="o">(</span>XF86Save<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff77 <span class="o">(</span>XF86Save<span class="o">)</span>
    243     0x1008ff5b <span class="o">(</span>XF86Documents<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff5b <span class="o">(</span>XF86Documents<span class="o">)</span>
    244     0x1008ff93 <span class="o">(</span>XF86Battery<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff93 <span class="o">(</span>XF86Battery<span class="o">)</span>
    245     0x1008ff94 <span class="o">(</span>XF86Bluetooth<span class="o">)</span>  0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff94 <span class="o">(</span>XF86Bluetooth<span class="o">)</span>
    246     0x1008ff95 <span class="o">(</span>XF86WLAN<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff95 <span class="o">(</span>XF86WLAN<span class="o">)</span>
    247     0x1008ff96 <span class="o">(</span>XF86UWB<span class="o">)</span>    0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff96 <span class="o">(</span>XF86UWB<span class="o">)</span>
    248
    249     0x1008fe22 <span class="o">(</span>XF86Next_VMode<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008fe22 <span class="o">(</span>XF86Next_VMode<span class="o">)</span>
    250     0x1008fe23 <span class="o">(</span>XF86Prev_VMode<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008fe23 <span class="o">(</span>XF86Prev_VMode<span class="o">)</span>
    251     0x1008ff07 <span class="o">(</span>XF86MonBrightnessCycle<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ff07 <span class="o">(</span>XF86MonBrightnessCycle<span class="o">)</span>
    252     0x100810f4 <span class="o">(</span>XF86BrightnessAuto<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x100810f4 <span class="o">(</span>XF86BrightnessAuto<span class="o">)</span>
    253     0x100810f5 <span class="o">(</span>XF86DisplayOff<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x100810f5 <span class="o">(</span>XF86DisplayOff<span class="o">)</span>
    254     0x1008ffb4 <span class="o">(</span>XF86WWAN<span class="o">)</span>   0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ffb4 <span class="o">(</span>XF86WWAN<span class="o">)</span>
    255     0x1008ffb5 <span class="o">(</span>XF86RFKill<span class="o">)</span> 0x0000 <span class="o">(</span>NoSymbol<span class="o">)</span>   0x1008ffb5 <span class="o">(</span>XF86RFKill<span class="o">)</span></code></pre></figure>

</div>

<p>فرمان <code class="language-plaintext highlighter-rouge">xmodmap -pke</code> این لیست را به صورتی که برای <code class="language-plaintext highlighter-rouge">xmodmap</code> قابل استفاده باشد در اختیار شما قرار می‌دهد.</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>xmodmap <span class="nt">-pke</span>
keycode   8 <span class="o">=</span>
keycode   9 <span class="o">=</span> Escape NoSymbol Escape
keycode  10 <span class="o">=</span> 1 exclam Farsi_1 exclam grave 1
keycode  11 <span class="o">=</span> 2 at Farsi_2 U066C at 2
keycode  12 <span class="o">=</span> 3 numbersign Farsi_3 U066B numbersign 3
keycode  13 <span class="o">=</span> 4 dollar Farsi_4 UFDFC dollar 4
keycode  14 <span class="o">=</span> 5 percent Farsi_5 Arabic_percent percent 5
keycode  15 <span class="o">=</span> 6 asciicircum Farsi_6 multiply asciicircum 6
keycode  16 <span class="o">=</span> 7 ampersand Farsi_7 Arabic_comma ampersand 7
keycode  17 <span class="o">=</span> 8 asterisk Farsi_8 asterisk enfilledcircbullet 8
keycode  18 <span class="o">=</span> 9 parenleft Farsi_9 parenright U200E 9
keycode  19 <span class="o">=</span> 0 parenright Farsi_0 parenleft U200F 0
keycode  20 <span class="o">=</span> minus underscore minus Arabic_tatweel underscore
keycode  21 <span class="o">=</span> equal plus equal plus U2212
keycode  22 <span class="o">=</span> BackSpace BackSpace BackSpace BackSpace
keycode  23 <span class="o">=</span> Tab ISO_Left_Tab Tab ISO_Left_Tab
keycode  24 <span class="o">=</span> q Q Arabic_dad Arabic_sukun degree
keycode  25 <span class="o">=</span> w W Arabic_sad Arabic_dammatan VoidSymbol
keycode  26 <span class="o">=</span> e E Arabic_theh Arabic_kasratan 0x13a4
keycode  27 <span class="o">=</span> r R Arabic_qaf Arabic_fathatan VoidSymbol
keycode  28 <span class="o">=</span> t T Arabic_feh Arabic_damma VoidSymbol
keycode  29 <span class="o">=</span> y Y Arabic_ghain Arabic_kasra VoidSymbol
keycode  30 <span class="o">=</span> u U Arabic_ain Arabic_fatha VoidSymbol
keycode  31 <span class="o">=</span> i I Arabic_ha Arabic_shadda U202D
keycode  32 <span class="o">=</span> o O Arabic_khah bracketright U202E
keycode  33 <span class="o">=</span> p P Arabic_hah bracketleft U202C
keycode  34 <span class="o">=</span> bracketleft braceleft Arabic_jeem braceright U202A
keycode  35 <span class="o">=</span> bracketright braceright Arabic_tcheh braceleft U202B
keycode  36 <span class="o">=</span> Return NoSymbol Return
keycode  37 <span class="o">=</span> Control_L NoSymbol Control_L
keycode  38 <span class="o">=</span> a A Arabic_sheen Arabic_hamzaonwaw VoidSymbol
keycode  39 <span class="o">=</span> s S Arabic_seen Arabic_hamzaonyeh VoidSymbol
keycode  40 <span class="o">=</span> d D Farsi_yeh Arabic_yeh Arabic_alefmaksura
keycode  41 <span class="o">=</span> f F Arabic_beh Arabic_hamzaunderalef VoidSymbol
keycode  42 <span class="o">=</span> g G Arabic_lam Arabic_hamzaonalef VoidSymbol
keycode  43 <span class="o">=</span> h H Arabic_alef Arabic_maddaonalef U0671
keycode  44 <span class="o">=</span> j J Arabic_teh Arabic_tehmarbuta VoidSymbol
keycode  45 <span class="o">=</span> k K Arabic_noon guillemotright UFD3E
keycode  46 <span class="o">=</span> l L Arabic_meem guillemotleft UFD3F
keycode  47 <span class="o">=</span> semicolon colon Arabic_keheh colon semicolon
keycode  48 <span class="o">=</span> apostrophe quotedbl Arabic_gaf Arabic_semicolon quotedbl
keycode  49 <span class="o">=</span> grave asciitilde U200D division asciitilde
keycode  50 <span class="o">=</span> Shift_L ISO_Prev_Group Shift_L ISO_Prev_Group
keycode  51 <span class="o">=</span> backslash bar backslash bar U2010
keycode  52 <span class="o">=</span> z Z Arabic_zah Arabic_kaf VoidSymbol
keycode  53 <span class="o">=</span> x X Arabic_tah Arabic_madda_above VoidSymbol
keycode  54 <span class="o">=</span> c C Arabic_zain Arabic_jeh VoidSymbol
keycode  55 <span class="o">=</span> v V Arabic_ra Arabic_superscript_alef U0656
keycode  56 <span class="o">=</span> b B Arabic_thal U200C U200D
keycode  57 <span class="o">=</span> n N Arabic_dal Arabic_hamza_above Arabic_hamza_below
keycode  58 <span class="o">=</span> m M Arabic_peh Arabic_hamza ellipsis
keycode  59 <span class="o">=</span> comma less Arabic_waw greater comma
keycode  60 <span class="o">=</span> period greater period less apostrophe
keycode  61 <span class="o">=</span> slash question slash Arabic_question_mark question
keycode  62 <span class="o">=</span> Shift_R ISO_Next_Group Shift_R ISO_Next_Group
keycode  63 <span class="o">=</span> KP_Multiply KP_Multiply KP_Multiply KP_Multiply KP_Multiply KP_Multiply XF86ClearGrab KP_Multiply KP_Multiply XF86ClearGrab
keycode  64 <span class="o">=</span> Alt_L Meta_L Alt_L Meta_L
keycode  65 <span class="o">=</span> space NoSymbol space U200C nobreakspace U202F
keycode  66 <span class="o">=</span> Escape Caps_Lock Escape Caps_Lock
keycode  67 <span class="o">=</span> F1 F1 F1 F1 F1 F1 XF86Switch_VT_1 F1 F1 XF86Switch_VT_1
keycode  68 <span class="o">=</span> F2 F2 F2 F2 F2 F2 XF86Switch_VT_2 F2 F2 XF86Switch_VT_2
keycode  69 <span class="o">=</span> F3 F3 F3 F3 F3 F3 XF86Switch_VT_3 F3 F3 XF86Switch_VT_3
keycode  70 <span class="o">=</span> F4 F4 F4 F4 F4 F4 XF86Switch_VT_4 F4 F4 XF86Switch_VT_4
keycode  71 <span class="o">=</span> F5 F5 F5 F5 F5 F5 XF86Switch_VT_5 F5 F5 XF86Switch_VT_5
keycode  72 <span class="o">=</span> F6 F6 F6 F6 F6 F6 XF86Switch_VT_6 F6 F6 XF86Switch_VT_6
keycode  73 <span class="o">=</span> F7 F7 F7 F7 F7 F7 XF86Switch_VT_7 F7 F7 XF86Switch_VT_7
keycode  74 <span class="o">=</span> F8 F8 F8 F8 F8 F8 XF86Switch_VT_8 F8 F8 XF86Switch_VT_8
keycode  75 <span class="o">=</span> F9 F9 F9 F9 F9 F9 XF86Switch_VT_9 F9 F9 XF86Switch_VT_9
keycode  76 <span class="o">=</span> F10 F10 F10 F10 F10 F10 XF86Switch_VT_10 F10 F10 XF86Switch_VT_10
keycode  77 <span class="o">=</span> Num_Lock NoSymbol Num_Lock
keycode  78 <span class="o">=</span> Scroll_Lock NoSymbol Scroll_Lock
keycode  79 <span class="o">=</span> KP_Home KP_7 KP_Home KP_7
keycode  80 <span class="o">=</span> KP_Up KP_8 KP_Up KP_8
keycode  81 <span class="o">=</span> KP_Prior KP_9 KP_Prior KP_9
keycode  82 <span class="o">=</span> KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract XF86Prev_VMode KP_Subtract KP_Subtract XF86Prev_VMode
keycode  83 <span class="o">=</span> KP_Left KP_4 KP_Left KP_4
keycode  84 <span class="o">=</span> KP_Begin KP_5 KP_Begin KP_5
keycode  85 <span class="o">=</span> KP_Right KP_6 KP_Right KP_6
keycode  86 <span class="o">=</span> KP_Add KP_Add KP_Add KP_Add KP_Add KP_Add XF86Next_VMode KP_Add KP_Add XF86Next_VMode
keycode  87 <span class="o">=</span> KP_End KP_1 KP_End KP_1
keycode  88 <span class="o">=</span> KP_Down KP_2 KP_Down KP_2
keycode  89 <span class="o">=</span> KP_Next KP_3 KP_Next KP_3
keycode  90 <span class="o">=</span> KP_Insert KP_0 KP_Insert KP_0
keycode  91 <span class="o">=</span> KP_Delete KP_Decimal KP_Delete KP_Decimal
keycode  92 <span class="o">=</span> ISO_Level3_Shift NoSymbol ISO_Level3_Shift
keycode  93 <span class="o">=</span>
keycode  94 <span class="o">=</span> less greater less greater bar brokenbar bar brokenbar
keycode  95 <span class="o">=</span> F11 F11 F11 F11 F11 F11 XF86Switch_VT_11 F11 F11 XF86Switch_VT_11
keycode  96 <span class="o">=</span> F12 F12 F12 F12 F12 F12 XF86Switch_VT_12 F12 F12 XF86Switch_VT_12
keycode  97 <span class="o">=</span>
keycode  98 <span class="o">=</span> Katakana NoSymbol Katakana
keycode  99 <span class="o">=</span> Hiragana NoSymbol Hiragana
keycode 100 <span class="o">=</span> Henkan_Mode NoSymbol Henkan_Mode
keycode 101 <span class="o">=</span> Hiragana_Katakana NoSymbol Hiragana_Katakana
keycode 102 <span class="o">=</span> Muhenkan NoSymbol Muhenkan
keycode 103 <span class="o">=</span>
keycode 104 <span class="o">=</span> KP_Enter NoSymbol KP_Enter
keycode 105 <span class="o">=</span> Control_R NoSymbol Control_R
keycode 106 <span class="o">=</span> KP_Divide KP_Divide KP_Divide KP_Divide KP_Divide KP_Divide XF86Ungrab KP_Divide KP_Divide XF86Ungrab
keycode 107 <span class="o">=</span> Super_R Super_R Super_R Super_R
keycode 108 <span class="o">=</span> ISO_Level3_Shift NoSymbol ISO_Level3_Shift
keycode 109 <span class="o">=</span> Linefeed NoSymbol Linefeed
keycode 110 <span class="o">=</span> Home NoSymbol Home
keycode 111 <span class="o">=</span> Up NoSymbol Up
keycode 112 <span class="o">=</span> Prior NoSymbol Prior
keycode 113 <span class="o">=</span> Left NoSymbol Left
keycode 114 <span class="o">=</span> Right NoSymbol Right
keycode 115 <span class="o">=</span> End NoSymbol End
keycode 116 <span class="o">=</span> Down NoSymbol Down
keycode 117 <span class="o">=</span> Next NoSymbol Next
keycode 118 <span class="o">=</span> Insert NoSymbol Insert
keycode 119 <span class="o">=</span> Delete NoSymbol Delete
keycode 120 <span class="o">=</span>
keycode 121 <span class="o">=</span> XF86AudioMute NoSymbol XF86AudioMute
keycode 122 <span class="o">=</span> XF86AudioLowerVolume NoSymbol XF86AudioLowerVolume
keycode 123 <span class="o">=</span> XF86AudioRaiseVolume NoSymbol XF86AudioRaiseVolume
keycode 124 <span class="o">=</span> XF86PowerOff NoSymbol XF86PowerOff
keycode 125 <span class="o">=</span> KP_Equal NoSymbol KP_Equal
keycode 126 <span class="o">=</span> plusminus NoSymbol plusminus
keycode 127 <span class="o">=</span> Pause Break Pause Break
keycode 128 <span class="o">=</span> XF86LaunchA NoSymbol XF86LaunchA
keycode 129 <span class="o">=</span> KP_Decimal KP_Decimal KP_Decimal KP_Decimal
keycode 130 <span class="o">=</span> Hangul NoSymbol Hangul
keycode 131 <span class="o">=</span> Hangul_Hanja NoSymbol Hangul_Hanja
keycode 132 <span class="o">=</span>
keycode 133 <span class="o">=</span> Super_L NoSymbol Super_L
keycode 134 <span class="o">=</span> Super_R NoSymbol Super_R
keycode 135 <span class="o">=</span> Menu NoSymbol Menu
keycode 136 <span class="o">=</span> Cancel NoSymbol Cancel
keycode 137 <span class="o">=</span> Redo NoSymbol Redo
keycode 138 <span class="o">=</span> SunProps NoSymbol SunProps
keycode 139 <span class="o">=</span> Undo NoSymbol Undo
keycode 140 <span class="o">=</span> SunFront NoSymbol SunFront
keycode 141 <span class="o">=</span> XF86Copy NoSymbol XF86Copy
keycode 142 <span class="o">=</span> XF86Open NoSymbol XF86Open
keycode 143 <span class="o">=</span> XF86Paste NoSymbol XF86Paste
keycode 144 <span class="o">=</span> Find NoSymbol Find
keycode 145 <span class="o">=</span> XF86Cut NoSymbol XF86Cut
keycode 146 <span class="o">=</span> Help NoSymbol Help
keycode 147 <span class="o">=</span> XF86MenuKB NoSymbol XF86MenuKB
keycode 148 <span class="o">=</span> XF86Calculator NoSymbol XF86Calculator
keycode 149 <span class="o">=</span>
keycode 150 <span class="o">=</span> XF86Sleep NoSymbol XF86Sleep
keycode 151 <span class="o">=</span> XF86WakeUp NoSymbol XF86WakeUp
keycode 152 <span class="o">=</span> XF86Explorer NoSymbol XF86Explorer
keycode 153 <span class="o">=</span> XF86Send NoSymbol XF86Send
keycode 154 <span class="o">=</span>
keycode 155 <span class="o">=</span> XF86Xfer NoSymbol XF86Xfer
keycode 156 <span class="o">=</span> XF86Launch1 NoSymbol XF86Launch1
keycode 157 <span class="o">=</span> XF86Launch2 NoSymbol XF86Launch2
keycode 158 <span class="o">=</span> XF86WWW NoSymbol XF86WWW
keycode 159 <span class="o">=</span> XF86DOS NoSymbol XF86DOS
keycode 160 <span class="o">=</span> XF86ScreenSaver NoSymbol XF86ScreenSaver
keycode 161 <span class="o">=</span> XF86RotateWindows NoSymbol XF86RotateWindows
keycode 162 <span class="o">=</span> XF86TaskPane NoSymbol XF86TaskPane
keycode 163 <span class="o">=</span> XF86Mail NoSymbol XF86Mail
keycode 164 <span class="o">=</span> XF86Favorites NoSymbol XF86Favorites
keycode 165 <span class="o">=</span> XF86MyComputer NoSymbol XF86MyComputer
keycode 166 <span class="o">=</span> XF86Back NoSymbol XF86Back
keycode 167 <span class="o">=</span> XF86Forward NoSymbol XF86Forward
keycode 168 <span class="o">=</span>
keycode 169 <span class="o">=</span> XF86Eject NoSymbol XF86Eject
keycode 170 <span class="o">=</span> XF86Eject NoSymbol XF86Eject
keycode 171 <span class="o">=</span> XF86AudioNext NoSymbol XF86AudioNext
keycode 172 <span class="o">=</span> XF86AudioPlay XF86AudioPause XF86AudioPlay XF86AudioPause
keycode 173 <span class="o">=</span> XF86AudioPrev NoSymbol XF86AudioPrev
keycode 174 <span class="o">=</span> XF86AudioStop XF86Eject XF86AudioStop XF86Eject
keycode 175 <span class="o">=</span> XF86AudioRecord NoSymbol XF86AudioRecord
keycode 176 <span class="o">=</span> XF86AudioRewind NoSymbol XF86AudioRewind
keycode 177 <span class="o">=</span> XF86Phone NoSymbol XF86Phone
keycode 178 <span class="o">=</span>
keycode 179 <span class="o">=</span> XF86Tools NoSymbol XF86Tools
keycode 180 <span class="o">=</span> XF86HomePage NoSymbol XF86HomePage
keycode 181 <span class="o">=</span> XF86Reload NoSymbol XF86Reload
keycode 182 <span class="o">=</span> XF86Close NoSymbol XF86Close
keycode 183 <span class="o">=</span>
keycode 184 <span class="o">=</span>
keycode 185 <span class="o">=</span> XF86ScrollUp NoSymbol XF86ScrollUp
keycode 186 <span class="o">=</span> XF86ScrollDown NoSymbol XF86ScrollDown
keycode 187 <span class="o">=</span> parenleft NoSymbol parenleft
keycode 188 <span class="o">=</span> parenright NoSymbol parenright
keycode 189 <span class="o">=</span> XF86New NoSymbol XF86New
keycode 190 <span class="o">=</span> Redo NoSymbol Redo
keycode 191 <span class="o">=</span> XF86Tools NoSymbol XF86Tools
keycode 192 <span class="o">=</span> XF86Launch5 NoSymbol XF86Launch5
keycode 193 <span class="o">=</span> XF86Launch6 NoSymbol XF86Launch6
keycode 194 <span class="o">=</span> XF86Launch7 NoSymbol XF86Launch7
keycode 195 <span class="o">=</span> XF86Launch8 NoSymbol XF86Launch8
keycode 196 <span class="o">=</span> XF86Launch9 NoSymbol XF86Launch9
keycode 197 <span class="o">=</span>
keycode 198 <span class="o">=</span> XF86AudioMicMute NoSymbol XF86AudioMicMute
keycode 199 <span class="o">=</span> XF86TouchpadToggle NoSymbol XF86TouchpadToggle
keycode 200 <span class="o">=</span> XF86TouchpadOn NoSymbol XF86TouchpadOn
keycode 201 <span class="o">=</span> XF86TouchpadOff NoSymbol XF86TouchpadOff
keycode 202 <span class="o">=</span>
keycode 203 <span class="o">=</span> Mode_switch NoSymbol Mode_switch
keycode 204 <span class="o">=</span> NoSymbol Alt_L NoSymbol Alt_L
keycode 205 <span class="o">=</span> NoSymbol Meta_L NoSymbol Meta_L
keycode 206 <span class="o">=</span> NoSymbol Super_L NoSymbol Super_L
keycode 207 <span class="o">=</span> NoSymbol Hyper_L NoSymbol Hyper_L
keycode 208 <span class="o">=</span> XF86AudioPlay NoSymbol XF86AudioPlay
keycode 209 <span class="o">=</span> XF86AudioPause NoSymbol XF86AudioPause
keycode 210 <span class="o">=</span> XF86Launch3 NoSymbol XF86Launch3
keycode 211 <span class="o">=</span> XF86Launch4 NoSymbol XF86Launch4
keycode 212 <span class="o">=</span> XF86LaunchB NoSymbol XF86LaunchB
keycode 213 <span class="o">=</span> XF86Suspend NoSymbol XF86Suspend
keycode 214 <span class="o">=</span> XF86Close NoSymbol XF86Close
keycode 215 <span class="o">=</span> XF86AudioPlay NoSymbol XF86AudioPlay
keycode 216 <span class="o">=</span> XF86AudioForward NoSymbol XF86AudioForward
keycode 217 <span class="o">=</span>
keycode 218 <span class="o">=</span> Print NoSymbol Print
keycode 219 <span class="o">=</span>
keycode 220 <span class="o">=</span> XF86WebCam NoSymbol XF86WebCam
keycode 221 <span class="o">=</span> XF86AudioPreset NoSymbol XF86AudioPreset
keycode 222 <span class="o">=</span>
keycode 223 <span class="o">=</span> XF86Mail NoSymbol XF86Mail
keycode 224 <span class="o">=</span> XF86Messenger NoSymbol XF86Messenger
keycode 225 <span class="o">=</span> XF86Search NoSymbol XF86Search
keycode 226 <span class="o">=</span> XF86Go NoSymbol XF86Go
keycode 227 <span class="o">=</span> XF86Finance NoSymbol XF86Finance
keycode 228 <span class="o">=</span> XF86Game NoSymbol XF86Game
keycode 229 <span class="o">=</span> XF86Shop NoSymbol XF86Shop
keycode 230 <span class="o">=</span>
keycode 231 <span class="o">=</span> Cancel NoSymbol Cancel
keycode 232 <span class="o">=</span> XF86MonBrightnessDown NoSymbol XF86MonBrightnessDown
keycode 233 <span class="o">=</span> XF86MonBrightnessUp NoSymbol XF86MonBrightnessUp
keycode 234 <span class="o">=</span> XF86AudioMedia NoSymbol XF86AudioMedia
keycode 235 <span class="o">=</span> XF86Display NoSymbol XF86Display
keycode 236 <span class="o">=</span> XF86KbdLightOnOff NoSymbol XF86KbdLightOnOff
keycode 237 <span class="o">=</span> XF86KbdBrightnessDown NoSymbol XF86KbdBrightnessDown
keycode 238 <span class="o">=</span> XF86KbdBrightnessUp NoSymbol XF86KbdBrightnessUp
keycode 239 <span class="o">=</span> XF86Send NoSymbol XF86Send
keycode 240 <span class="o">=</span> XF86Reply NoSymbol XF86Reply
keycode 241 <span class="o">=</span> XF86MailForward NoSymbol XF86MailForward
keycode 242 <span class="o">=</span> XF86Save NoSymbol XF86Save
keycode 243 <span class="o">=</span> XF86Documents NoSymbol XF86Documents
keycode 244 <span class="o">=</span> XF86Battery NoSymbol XF86Battery
keycode 245 <span class="o">=</span> XF86Bluetooth NoSymbol XF86Bluetooth
keycode 246 <span class="o">=</span> XF86WLAN NoSymbol XF86WLAN
keycode 247 <span class="o">=</span> XF86UWB NoSymbol XF86UWB
keycode 248 <span class="o">=</span>
keycode 249 <span class="o">=</span> XF86Next_VMode NoSymbol XF86Next_VMode
keycode 250 <span class="o">=</span> XF86Prev_VMode NoSymbol XF86Prev_VMode
keycode 251 <span class="o">=</span> XF86MonBrightnessCycle NoSymbol XF86MonBrightnessCycle
keycode 252 <span class="o">=</span> XF86BrightnessAuto NoSymbol XF86BrightnessAuto
keycode 253 <span class="o">=</span> XF86DisplayOff NoSymbol XF86DisplayOff
keycode 254 <span class="o">=</span> XF86WWAN NoSymbol XF86WWAN
keycode 255 <span class="o">=</span> XF86RFKill NoSymbol XF86RFKill</code></pre></figure>

</div>

<p>لیستی از نام کلیدها که برای <code class="language-plaintext highlighter-rouge">xmodmap</code> قابل استفاده است را می‌توانید در <a href="https://wiki.linuxquestions.org/wiki/List_of_Keysyms_Recognised_by_Xmodmap" target="_blank" rel="noopener noreferrer">این صفحه</a> ببینید.</p>

<p>برای یافتن کد یک کلید خاص می‌توانید از <code class="language-plaintext highlighter-rouge">xev</code> استفاده کنید. کافیست <code class="language-plaintext highlighter-rouge">xev</code> را در ترمینال اجرا کنید و کلید مورد نظر را فشار دهید و داده‌های مربوط به آن را ببینید.</p>

<p>این داده‌ها برای کلیدهای <code class="language-plaintext highlighter-rouge">j</code>، <code class="language-plaintext highlighter-rouge">k</code> و کلید لوگوی روی صفحه کلید من به این صورت هستند:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>xev

KeyPress event, serial 34, synthetic NO, window 0x400001,
    root 0x496, subw 0x0, <span class="nb">time </span>23841206, <span class="o">(</span>995,155<span class="o">)</span>, root:<span class="o">(</span>999,715<span class="o">)</span>,
    state 0x0, keycode 44 <span class="o">(</span>keysym 0x6a, j<span class="o">)</span>, same_screen YES,
    XLookupString gives 1 bytes: <span class="o">(</span>6a<span class="o">)</span> <span class="s2">"j"</span>
    XmbLookupString gives 1 bytes: <span class="o">(</span>6a<span class="o">)</span> <span class="s2">"j"</span>
    XFilterEvent returns: False

KeyRelease event, serial 34, synthetic NO, window 0x400001,
    root 0x496, subw 0x0, <span class="nb">time </span>23841286, <span class="o">(</span>995,155<span class="o">)</span>, root:<span class="o">(</span>999,715<span class="o">)</span>,
    state 0x0, keycode 44 <span class="o">(</span>keysym 0x6a, j<span class="o">)</span>, same_screen YES,
    XLookupString gives 1 bytes: <span class="o">(</span>6a<span class="o">)</span> <span class="s2">"j"</span>
    XFilterEvent returns: False

KeyPress event, serial 34, synthetic NO, window 0x400001,
    root 0x496, subw 0x0, <span class="nb">time </span>23853546, <span class="o">(</span>995,155<span class="o">)</span>, root:<span class="o">(</span>999,715<span class="o">)</span>,
    state 0x0, keycode 45 <span class="o">(</span>keysym 0x6b, k<span class="o">)</span>, same_screen YES,
    XLookupString gives 1 bytes: <span class="o">(</span>6b<span class="o">)</span> <span class="s2">"k"</span>
    XmbLookupString gives 1 bytes: <span class="o">(</span>6b<span class="o">)</span> <span class="s2">"k"</span>
    XFilterEvent returns: False

KeyRelease event, serial 34, synthetic NO, window 0x400001,
    root 0x496, subw 0x0, <span class="nb">time </span>23853633, <span class="o">(</span>995,155<span class="o">)</span>, root:<span class="o">(</span>999,715<span class="o">)</span>,
    state 0x0, keycode 45 <span class="o">(</span>keysym 0x6b, k<span class="o">)</span>, same_screen YES,
    XLookupString gives 1 bytes: <span class="o">(</span>6b<span class="o">)</span> <span class="s2">"k"</span>
    XFilterEvent returns: False

KeyPress event, serial 34, synthetic NO, window 0x400001,
    root 0x496, subw 0x0, <span class="nb">time </span>23859678, <span class="o">(</span>995,155<span class="o">)</span>, root:<span class="o">(</span>999,715<span class="o">)</span>,
    state 0x0, keycode 133 <span class="o">(</span>keysym 0xffeb, Super_L<span class="o">)</span>, same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False

KeyRelease event, serial 34, synthetic NO, window 0x400001,
    root 0x496, subw 0x0, <span class="nb">time </span>23859789, <span class="o">(</span>995,155<span class="o">)</span>, root:<span class="o">(</span>999,715<span class="o">)</span>,
    state 0x40, keycode 133 <span class="o">(</span>keysym 0xffeb, Super_L<span class="o">)</span>, same_screen YES,
    XLookupString gives 0 bytes:
    XFilterEvent returns: False</code></pre></figure>

</div>

<p>همانطور که مشاهده می‌کنید حجم داده‌های خروجی <code class="language-plaintext highlighter-rouge">xev</code> زیاد است. این برنامه تمام <code class="language-plaintext highlighter-rouge">event</code>های مربوط به ماوس را هم نمایش می‌دهد که ممکن است کار یافتن کد را دشوار کند. چنانچه فقط کد عددی کلید را می‌خواهید، می‌توانید آن را به این صورت استفاده کنید:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>xev | <span class="nb">awk</span> <span class="nt">-F</span><span class="s1">'[ )]+'</span> <span class="s1">'/^KeyPress/ { a[NR+2] } NR in a { printf "%-3s %s\n", $5, $8 }'</span>
44  j
45  k
133 Super_L

<span class="nv">$ </span>xev | <span class="nb">awk</span> <span class="nt">-F</span><span class="s1">'[ )]+'</span> <span class="s1">'/^KeyPress/ {n=NR+2} NR==n { printf "%-3s %s\n", $5, $8}'</span>
44  j
45  k
133 Super_L</code></pre></figure>

</div>

<p>همانطور که می‌بینید خروجی را فیلتر کرده‌ایم که تنها داده‌های مورد نیاز ما را نمایش دهد.</p>

<p>ابزارهای زیادی برای کار با صفحه کلید در <code class="language-plaintext highlighter-rouge">X11</code> سرور وجود دارد به عنوان نمونه <code class="language-plaintext highlighter-rouge">xset -q</code> اطلاعاتی از وضعیت موجود تنطیمات به شما می‌دهد:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>xset <span class="nt">-q</span>
Keyboard Control:
  auto repeat:  on    key click percent:  0    LED mask:  00000000
  XKB indicators:
    00: Caps Lock:   off    01: Num Lock:    off    02: Scroll Lock: off
    03: Compose:     off    04: Kana:        off    05: Sleep:       off
    06: Suspend:     off    07: Mute:        off    08: Misc:        off
    09: Mail:        off    10: Charging:    off    11: Shift Lock:  off
    12: Group 2:     off    13: Mouse Keys:  off
  auto repeat delay:  300    repeat rate:  50
  auto repeating keys:  00ffffffdffffbbf
                        fadfffefffedffff
                        9fffffffffffffff
                        fff7ffffffffffff
  bell percent:  50    bell pitch:  400    bell duration:  100
Pointer Control:
  acceleration:  2/1    threshold:  4
Screen Saver:
  prefer blanking:  <span class="nb">yes    </span>allow exposures:  <span class="nb">yes
  timeout</span>:  600    cycle:  600
Colors:
  default colormap:  0x20    BlackPixel:  0x0    WhitePixel:  0xffffff
Font Path:
  /usr/share/fonts/misc,/usr/share/fonts/TTF,built-ins
DPMS <span class="o">(</span>Energy Star<span class="o">)</span>:
  Standby: 600    Suspend: 600    Off: 600
  DPMS is Enabled
  Monitor is On</code></pre></figure>

</div>

<p>و بعد از فعال کردن <code class="language-plaintext highlighter-rouge">CapsLock</code>:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>xset <span class="nt">-q</span>
Keyboard Control:
  auto repeat:  on    key click percent:  0    LED mask:  00000001
  XKB indicators:
    00: Caps Lock:   on     01: Num Lock:    off    02: Scroll Lock: off
    03: Compose:     off    04: Kana:        off    05: Sleep:       off
    06: Suspend:     off    07: Mute:        off    08: Misc:        off
    09: Mail:        off    10: Charging:    off    11: Shift Lock:  off
    12: Group 2:     off    13: Mouse Keys:  off
  auto repeat delay:  300    repeat rate:  50
  auto repeating keys:  00ffffffdffffbbf
                        fadfffefffedffff
                        9fffffffffffffff
                        fff7ffffffffffff
  bell percent:  50    bell pitch:  400    bell duration:  100
Pointer Control:
  acceleration:  2/1    threshold:  4
Screen Saver:
  prefer blanking:  <span class="nb">yes    </span>allow exposures:  <span class="nb">yes
  timeout</span>:  600    cycle:  600
Colors:
  default colormap:  0x20    BlackPixel:  0x0    WhitePixel:  0xffffff
Font Path:
  /usr/share/fonts/misc,/usr/share/fonts/TTF,built-ins
DPMS <span class="o">(</span>Energy Star<span class="o">)</span>:
  Standby: 600    Suspend: 600    Off: 600
  DPMS is Enabled
  Monitor is On</code></pre></figure>

</div>

<p>می‌توان از آن برای بررسی کردن وضعیت کلید‌ها در اسکریپت‌ها و تنظیمات استفاده کرد. همچنین می‌توان با استفاده از <code class="language-plaintext highlighter-rouge">xdotool</code> وضعیت کلیدهای صفحه کلید و ماوس  و محل نشانگر ماوس را تنظیم کرد. <code class="language-plaintext highlighter-rouge">xdotool</code> ابزاری برای شبیه‌سازی <code class="language-plaintext highlighter-rouge">event</code>های ورودی‌ها در محیط <code class="language-plaintext highlighter-rouge">X11</code> سرور است.</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>xset <span class="nt">-q</span> | <span class="nb">grep</span> <span class="s2">"Caps Lock:</span><span class="se">\s</span><span class="s2">*on"</span> <span class="o">&amp;&amp;</span> xdotool key Caps_Lock</code></pre></figure>

</div>

<p>فرمان بالا وضعیت کلید <code class="language-plaintext highlighter-rouge">CapsLock</code> را بررسی کرده و در صورت فعال بودن آن را غیرفعال می‌کند.</p>

<h1 id="swaywm-روی-wayland"><code class="language-plaintext highlighter-rouge">Swaywm</code> روی <code class="language-plaintext highlighter-rouge">Wayland</code></h1>

<p>تنظیمات صفحه کلید در محیط ویلند بر عهده کامپوزیتور است و ابزار یکتایی و روش یکسانی برای انجام ان وجود ندارد. کامپوزیتوزها روی ویلند برای دریافت ورودی‌ها بدون واسط و از واسطی استفاده نمی‌کنند و داده‌ها را در لایه پایین‌تری از <code class="language-plaintext highlighter-rouge">API</code>های کرنل دریافت می‌کنند.</p>

<p>تنظیمات صفحه کلید در <code class="language-plaintext highlighter-rouge">Swaywm</code> در فایل تنظیمات این مدیر پنجره انجام می‌شود. این فایل در حالت پیش گزیده در مسیر ‪<code class="language-plaintext highlighter-rouge">/etc/sway/config</code>‬ قرار دارد. چنانچه فایل تنظیمات در مسیر ‪<code class="language-plaintext highlighter-rouge">~/.config/sway/config</code>‬ وجود داشته باشد این فایل اولویت بالاتری خواهد داشت.</p>

<p>تنظیمات صفحه کلید من برای <code class="language-plaintext highlighter-rouge">Swaywm</code> در این فایل و به این صورت است:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-plaintext" data-lang="plaintext"># Use `man xkeyboard-config` to view the options and `setxkbmap -query|print` to check the model
input {
    type:keyboard {
        xkb_layout "us,ir"
        xkb_model "thinkpad"
        xkb_options "caps:escape_shifted_capslock,grp:shifts_toggle,altwin:prtsc_rwin,lv3:ralt_switch"
    }

    type:touchpad {
        # no click needed
        tap enabled
        # disable touchpad while typing
        dwt enabled
        # natural_scroll enabled
        middle_emulation enabled
    }
}</code></pre></figure>

</div>

<p>که همان تنظیماتی است که برای <code class="language-plaintext highlighter-rouge">X11</code> سرور داشتم.</p>

<p>ابزارهایی مثل <code class="language-plaintext highlighter-rouge">xmodmap</code>، <code class="language-plaintext highlighter-rouge">setxkbmap</code>، <code class="language-plaintext highlighter-rouge">xset</code>، <code class="language-plaintext highlighter-rouge">xev</code> و <code class="language-plaintext highlighter-rouge">xdotool</code> روی ویلند قابل استفاده نیستند. در <a href="https://github.com/swaywm/sway/wiki/i3-Migration-Guide">ویکی <code class="language-plaintext highlighter-rouge">Swaywm</code></a> صفحه‌ای مربوط به معرفی جایگزین برای ابزارهای معمول مورد استفاده و در <code class="language-plaintext highlighter-rouge">X11</code> وجود دارد که راهنمای مناسبی است. همچنین می‌توانید به <a href="https://github.com/natpen/awesome-wayland">این صفحه در گیتهاب</a> برای یافتن ابزارهای بیشتر روی ویلند سر بزنید.</p>

<p>به جای <code class="language-plaintext highlighter-rouge">xev</code> می‌توانید از <code class="language-plaintext highlighter-rouge">wev</code> و به جای <code class="language-plaintext highlighter-rouge">xdotool</code> از  <code class="language-plaintext highlighter-rouge">wtype</code>، <code class="language-plaintext highlighter-rouge">wlrctl</code>، <code class="language-plaintext highlighter-rouge">swaymsg seat &lt;seat&gt; cursor …</code> یا <code class="language-plaintext highlighter-rouge">ydotool</code> استفاده کنید. اما ابزاری برای جایگزینی <code class="language-plaintext highlighter-rouge">xmodmap</code> معرفی نشده است که به جای آن یک <code class="language-plaintext highlighter-rouge">layout</code> شخصی سازی شده را می‌شود استفاده کرد.</p>

<h1 id="ساخت-keymap-شخصی">ساخت <code class="language-plaintext highlighter-rouge">keymap</code> شخصی</h1>

<p>اعمال تنظیمات صفحه کلید حتی در محیط <code class="language-plaintext highlighter-rouge">x11</code> به صورت دایمی با استفاده از ابزارهایی که معرفی کردیم هم ممکن است تمامی نیازهای شما را برآورده نکند. ساختن یک <code class="language-plaintext highlighter-rouge">keymap</code> با توجه به نیاز شخصی شما امکان هر گونه تغییری در چیدمان حروف را برای شما فراهم می‌کند.</p>

<p>پیش از توضیح بیشتر بگذارید مساله‌ای که شروع شکل گرفتن این نوشته شد را شرح دهم. یکی از دوستان در ماستودون دنبال راهی برای جایگزینی <code class="language-plaintext highlighter-rouge">/</code> با نویسه <code class="language-plaintext highlighter-rouge">ۀ</code> روی <code class="language-plaintext highlighter-rouge">layout</code> فارسی بود. این نویسه روی صفحه کلید فارسی استاندارد وجود ندارد و یک نویسه عربی است. شکل درست آن در فارسی با ترکیب دو نویسهٔ <code class="language-plaintext highlighter-rouge">ه</code> و نویسهٔ <code class="language-plaintext highlighter-rouge">_ٔ</code> نوشته می‌شود. اما با توجه به محدودیت‌هایی که برای چاپ وجود داشت، مجبور بودند از این نویسه استفاده کنند.</p>

<p>بهترین راه برای ساخت <code class="language-plaintext highlighter-rouge">keymap</code> شخصی استفاده از یکی از فایل‌های موجود در مسیر ‪<code class="language-plaintext highlighter-rouge">/usr/share/X11/xkb/symbols</code>‬ و ویرایش آن است.</p>

<p>به عنوان نمونه فایل مربوط به <code class="language-plaintext highlighter-rouge">keymap</code> فارسی چنین الگویی دارد:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-plaintext" data-lang="plaintext">$ cat /usr/share/X11/xkb/symbols/ir
// Iranian keyboard layout

////////////////////////////////////////
// Persian layout,
// based on
// Information Technology – Layout of Persian Letters and Symbols on Computer Keyboards
// ISIRI 9147 – 1st Edition
// Institute of Standards and Industrial Research of Iran
// http://www.isiri.org/UserStd/DownloadStd.aspx?id=9147
// http://behnam.esfahbod.info/standards/isiri-keyboard-9147.pdf
//
// Author: Behnam Esfahbod &lt;behnam@esfahbod.info&gt;
//

default partial alphanumeric_keys
xkb_symbols "pes" {
    name[Group1]= "Persian";

    include "ir(pes_part_basic)"
    include "ir(pes_part_ext)"

    include "nbsp(zwnj2nb3nnb4)"
    include "level3(ralt_switch)"
};


partial alphanumeric_keys
xkb_symbols "pes_keypad" {
    name[Group1]= "Persian (with Persian keypad)";

    include "ir(pes_part_basic)"
    include "ir(pes_part_ext)"
    include "ir(pes_part_keypad)"

    include "nbsp(zwnj2nb3nnb4)"
    include "level3(ralt_switch)"
};

hidden partial alphanumeric_keys
xkb_symbols "pes_part_basic" {

    // Persian digits
    key &lt;AE01&gt; { [ Farsi_1, exclam,     grave           ] };
    key &lt;AE02&gt; { [ Farsi_2, 0x100066c,  at          ] };
    key &lt;AE03&gt; { [ Farsi_3, 0x100066b,  numbersign      ] };
    key &lt;AE04&gt; { [ Farsi_4, 0x100fdfc,  dollar          ] };
    key &lt;AE05&gt; { [ Farsi_5, 0x100066a,  percent         ] };
    key &lt;AE06&gt; { [ Farsi_6, multiply,   asciicircum     ] };
    key &lt;AE07&gt; { [ Farsi_7, Arabic_comma,   ampersand       ] };
    key &lt;AE08&gt; { [ Farsi_8, asterisk,   enfilledcircbullet  ] };
    key &lt;AE09&gt; { [ Farsi_9, parenright, 0x100200e       ] };
    key &lt;AE10&gt; { [ Farsi_0, parenleft,  0x100200f       ] };

    // Persian letters and symbols
    key &lt;AD01&gt; { [ Arabic_dad,      Arabic_sukun,       degree      ] };
    key &lt;AD02&gt; { [ Arabic_sad,      Arabic_dammatan,    VoidSymbol  ] };
    key &lt;AD03&gt; { [ Arabic_theh,     Arabic_kasratan,    0x13a4      ] };
    key &lt;AD04&gt; { [ Arabic_qaf,      Arabic_fathatan,    VoidSymbol  ] };
    key &lt;AD05&gt; { [ Arabic_feh,      Arabic_damma,       VoidSymbol  ] };
    key &lt;AD06&gt; { [ Arabic_ghain,    Arabic_kasra,       VoidSymbol  ] };
    key &lt;AD07&gt; { [ Arabic_ain,      Arabic_fatha,       VoidSymbol  ] };
    key &lt;AD08&gt; { [ Arabic_heh,      Arabic_shadda,      0x100202d   ] };
    key &lt;AD09&gt; { [ Arabic_khah,     bracketright,       0x100202e   ] };
    key &lt;AD10&gt; { [ Arabic_hah,      bracketleft,        0x100202c   ] };
    key &lt;AD11&gt; { [ Arabic_jeem,     braceright,     0x100202a   ] };
    key &lt;AD12&gt; { [ Arabic_tcheh,    braceleft,      0x100202b   ] };

    key &lt;AC01&gt; { [ Arabic_sheen,    Arabic_hamzaonwaw,  VoidSymbol  ] };
    key &lt;AC02&gt; { [ Arabic_seen,     Arabic_hamzaonyeh,  VoidSymbol  ] };
    key &lt;AC03&gt; { [ Farsi_yeh,       Arabic_yeh,     Arabic_alefmaksura ] };
    key &lt;AC04&gt; { [ Arabic_beh,      Arabic_hamzaunderalef,  VoidSymbol  ] };
    key &lt;AC05&gt; { [ Arabic_lam,      Arabic_hamzaonalef, VoidSymbol  ] };
    key &lt;AC06&gt; { [ Arabic_alef,     Arabic_maddaonalef, 0x1000671   ] };
    key &lt;AC07&gt; { [ Arabic_teh,      Arabic_tehmarbuta,  VoidSymbol  ] };
    key &lt;AC08&gt; { [ Arabic_noon,     guillemotright,     0x100fd3e   ] };
    key &lt;AC09&gt; { [ Arabic_meem,     guillemotleft,      0x100fd3f   ] };
    key &lt;AC10&gt; { [ Arabic_keheh,    colon,          semicolon   ] };
    key &lt;AC11&gt; { [ Arabic_gaf,      Arabic_semicolon,   quotedbl    ] };

    key &lt;AB01&gt; { [ Arabic_zah,      Arabic_kaf,     VoidSymbol  ] };
    key &lt;AB02&gt; { [ Arabic_tah,      0x1000653,      VoidSymbol  ] };
    key &lt;AB03&gt; { [ Arabic_zain,     Arabic_jeh,     VoidSymbol  ] };
    key &lt;AB04&gt; { [ Arabic_ra,       Arabic_superscript_alef,0x1000656   ] };
    key &lt;AB05&gt; { [ Arabic_thal,     0x100200c,      0x100200d   ] };
    key &lt;AB06&gt; { [ Arabic_dal,      Arabic_hamza_above, Arabic_hamza_below  ] };
    key &lt;AB07&gt; { [ Arabic_peh,      Arabic_hamza,       ellipsis    ] };
    key &lt;AB08&gt; { [ Arabic_waw,      greater,        comma       ] };
    key &lt;AB09&gt; { [ period,      less,           apostrophe  ] };
    key &lt;AB10&gt; { [ slash,       Arabic_question_mark,   question    ] };

    key &lt;TLDE&gt; { [ 0x100200d,       division,       asciitilde  ] };
    key &lt;AE11&gt; { [ minus,       Arabic_tatweel,     underscore  ] };
    key &lt;AE12&gt; { [ equal,       plus,           0x1002212   ] };
    key &lt;BKSL&gt; { [ backslash,       bar,            0x1002010   ] };
};

hidden partial alphanumeric_keys
xkb_symbols "pes_part_ext" {

    // Persian and ASCII digits
    key &lt;AE01&gt; { [ Farsi_1, exclam,     grave,          1   ] };
    key &lt;AE02&gt; { [ Farsi_2, 0x100066c,  at,         2   ] };
    key &lt;AE03&gt; { [ Farsi_3, 0x100066b,  numbersign,     3   ] };
    key &lt;AE04&gt; { [ Farsi_4, 0x100fdfc,  dollar,         4   ] };
    key &lt;AE05&gt; { [ Farsi_5, 0x100066a,  percent,        5   ] };
    key &lt;AE06&gt; { [ Farsi_6, multiply,   asciicircum,        6   ] };
    key &lt;AE07&gt; { [ Farsi_7, Arabic_comma,   ampersand,      7   ] };
    key &lt;AE08&gt; { [ Farsi_8, asterisk,   enfilledcircbullet, 8   ] };
    key &lt;AE09&gt; { [ Farsi_9, parenright, 0x100200e,      9   ] };
    key &lt;AE10&gt; { [ Farsi_0, parenleft,  0x100200f,      0   ] };
};

hidden partial alphanumeric_keys
xkb_symbols "pes_part_keypad" {

    // Persian digits and Mathematical operators
    key &lt;KPDV&gt; { [ division,    XF86_Ungrab ] };
    key &lt;KPMU&gt; { [ multiply,    XF86_ClearGrab  ] };
    key &lt;KPSU&gt; { [ 0x1002212,   XF86_Prev_VMode ] };
    key &lt;KPAD&gt; { [ plus,    XF86_Next_VMode ] };

    key &lt;KPEN&gt; { [ KP_Enter ] };
    key &lt;KPEQ&gt; { [ equal    ] };

    key &lt;KP7&gt;  { [ KP_Home, Farsi_7 ] };
    key &lt;KP8&gt;  { [ KP_Up,   Farsi_8 ] };
    key &lt;KP9&gt;  { [ KP_Prior,    Farsi_9 ] };

    key &lt;KP4&gt;  { [ KP_Left, Farsi_4 ] };
    key &lt;KP5&gt;  { [ KP_Begin,    Farsi_5 ] };
    key &lt;KP6&gt;  { [ KP_Right,    Farsi_6 ] };

    key &lt;KP1&gt;  { [ KP_End,  Farsi_1 ] };
    key &lt;KP2&gt;  { [ KP_Down, Farsi_2 ] };
    key &lt;KP3&gt;  { [ KP_Next, Farsi_3 ] };

    key &lt;KP0&gt;  { [ KP_Insert,   Farsi_0 ] };
    key &lt;KPDL&gt; { [ KP_Delete,   0x100066b   ] };
};


////////////////////////////////////////
// Kurdish Layout

partial alphanumeric_keys
xkb_symbols "ku" {
    include "tr(ku)"
    name[Group1]= "Kurdish (Iran, Latin Q)";
};

partial alphanumeric_keys
xkb_symbols "ku_f" {
    include "tr(ku_f)"
    name[Group1]= "Kurdish (Iran, F)";
};

partial alphanumeric_keys
xkb_symbols "ku_alt" {
    include "tr(ku_alt)"
    name[Group1]= "Kurdish (Iran, Latin Alt-Q)";
};

////////////////////////////////////////
// Kurdish Soranî Bahdînî (Arabic) keyboard layout,
// based on the Kurdî Soranî Bahdînî keyboard from KurdITGroup
// which is based on National Iranian Keyboard Standard (ISIRI 2901:1994),
// with additions.
//
// Copyright (C) 2006 Erdal Ronahî, published under the GPL v2
//
// Special copyright note: author explicitly permitted to license this
// layout under MIT/X11 license, for details see
// https://bugs.freedesktop.org/show_bug.cgi?id=9541
//
// Author: Erdal Ronahî  &lt;erdal.ronahi@gmail.com&gt;
//
// Kurdish Arabic-Latin Layout for Soranî

partial alphanumeric_keys
xkb_symbols "ku_ara" {
    name[Group1]= "Kurdish (Iran, Arabic-Latin)";

    // Other 3-Level symbols
    key &lt;TLDE&gt; { [ 0x100200d,       division,       asciitilde  ] };
    key &lt;BKSL&gt; { [ backslash,       bar,            ccedilla, Ccedilla  ] };

    // Digits
    key &lt;AE01&gt; { [ 0x1000661,   exclam,     1,  grave       ] };
    key &lt;AE02&gt; { [ 0x1000662,   at,         2,  at      ] };
    key &lt;AE03&gt; { [ 0x1000663,   numbersign, 3,  0x100066b   ] };
    key &lt;AE04&gt; { [ 0x1000664,   dollar,     4,  0x100fdfc   ] };
    key &lt;AE05&gt; { [ 0x1000665,   percent,    5,  0x100066a   ] };
    key &lt;AE06&gt; { [ 0x1000666,   asciicircum,    6,  multiply    ] };
    key &lt;AE07&gt; { [ 0x1000667,   ampersand,  7,  Arabic_comma    ] };
    key &lt;AE08&gt; { [ 0x1000668,   asterisk,   8,  enfilledcircbullet  ] };
    key &lt;AE09&gt; { [ 0x1000669,   parenright, 9,  0x100200e   ] };
    key &lt;AE10&gt; { [ 0x1000660,   parenleft,  0,  0x100200f   ] };
    key &lt;AE11&gt; { [ minus,       Arabic_tatweel,     underscore  ] };
    key &lt;AE12&gt; { [ equal,       plus,           0x1002212   ] };

    key &lt;AD01&gt; { [         Arabic_qaf,            X,  q,  Q ] };
    key &lt;AD02&gt; { [         Arabic_waw,            X,  w,  W ] };
    key &lt;AD03&gt; { [          0x10006d5,   Arabic_heh,  e,  E ] };
    key &lt;AD04&gt; { [         Arabic_ra ,    0x1000695,  r,  R ] };
    key &lt;AD05&gt; { [         Arabic_teh,   Arabic_tah,  t,  T ] };
    key &lt;AD06&gt; { [          0x10006cc,    0x10006ce,  y,  Y ] };
    key &lt;AD07&gt; { [  Arabic_hamzaonyeh, Arabic_hamza,  u,  U ] };
    key &lt;AD08&gt; { [         Arabic_hah,   Arabic_ain,  i,  I ] };
    key &lt;AD09&gt; { [          0x10006c6, Arabic_hamzaonwaw,  o,  O ] };
    key &lt;AD10&gt; { [          0x100067e,  Arabic_theh,  p,  P ] };
    key &lt;AD11&gt; { [ bracketright,    braceright, ucircumflex, Ucircumflex    ] };
    key &lt;AD12&gt; { [ bracketleft,     braceleft,  scedilla, Scedilla  ] };

    key &lt;AC01&gt; { [ Arabic_alef, Arabic_maddaonalef, a, A    ] };
    key &lt;AC02&gt; { [ Arabic_seen,     Arabic_sheen,   s, S    ] };
    key &lt;AC03&gt; { [  Arabic_dal,     Arabic_thal,    d, D    ] };
    key &lt;AC04&gt; { [  Arabic_feh, Arabic_hamzaunderalef,  f, F    ] };
    key &lt;AC05&gt; { [   0x10006af,     Arabic_ghain,   g, G    ] };
    key &lt;AC06&gt; { [  Arabic_heh,     0x100200c,  h, H    ] };
    key &lt;AC07&gt; { [   0x1000698, Arabic_hamzaonalef, j, J    ] };
    key &lt;AC08&gt; { [   0x10006a9,     Arabic_kaf, k, K    ] };
    key &lt;AC09&gt; { [  Arabic_lam,     0x10006b5,  l, L    ] };
    key &lt;AC10&gt; { [  Arabic_semicolon,   colon,      ecircumflex, Ecircumflex    ] };
    key &lt;AC11&gt; { [  apostrophe,     quotedbl,   icircumflex, Icircumflex    ] };

    key &lt;AB01&gt; { [ Arabic_zain,     Arabic_dad, z, Z    ] };
    key &lt;AB02&gt; { [ Arabic_khah,     Arabic_sad, x, X    ] };
    key &lt;AB03&gt; { [ Arabic_jeem,     0x1000686,  c, C    ] };
    key &lt;AB04&gt; { [   0x10006a4,     Arabic_zah, v, V    ] };
    key &lt;AB05&gt; { [ Arabic_beh,      0x1000649,  b, B    ] };
    key &lt;AB06&gt; { [ Arabic_noon, Arabic_tehmarbuta,  n, N    ] };
    key &lt;AB07&gt; { [ Arabic_meem, Arabic_tatweel,     m, M    ] };
    key &lt;AB08&gt; { [ Arabic_comma,    greater,    comma       ] };
    key &lt;AB09&gt; { [ period,      less,       apostrophe  ] };
    key &lt;AB10&gt; { [ slash,       Arabic_question_mark,   question    ] };

    include "nbsp(zwnj2nb3)"
    include "level3(ralt_switch)"
};

// EXTRAS:

/////////////////////////////////////////////////////////////////////////////////
//
// Generated keyboard layout file with the Keyboard Layout Editor.
// For more about the software, see http://code.google.com/p/keyboardlayouteditor
//
// Version 0.2, fixed AD09.
//
// Layout by Ernst Tremel, http://ubuntuforums.org/showpost.php?p=9365469&amp;postcount=32
// Creation of this file by Simos Xenitellis.

partial alphanumeric_keys
xkb_symbols "ave"
{
    name[Group1] = "Avestan";

    key &lt;AB01&gt; { [ U10B30,         U10B32 ] }; // 𐬰 𐬲
    key &lt;AB02&gt; { [ U10B11,         U10B12 ] }; // 𐬑 𐬒
    key &lt;AB03&gt; { [ U10B17,          UE102 ] }; // 𐬗 
    key &lt;AB04&gt; { [ U10B2C,         U10B13 ] }; // 𐬬 𐬓
    key &lt;AB05&gt; { [ U10B20,         U10B21 ] }; // 𐬠 𐬡
    key &lt;AB06&gt; { [ U10B25,         U10B27 ] }; // 𐬥 𐬧
    key &lt;AB07&gt; { [ U10B28,         U10B29 ] }; // 𐬨 𐬩
    key &lt;AB08&gt; { [ U10B3C,         U10B39 ] }; // 𐬼 𐬹
    key &lt;AB09&gt; { [ U10B3E,         U10B3D ] }; // 𐬾 𐬽
    key &lt;AB10&gt; { [ U10B3F, periodcentered ] }; // 𐬿 ·

    key &lt;AC01&gt; { [ U10B00,         U10B01 ] }; // 𐬀 𐬁
    key &lt;AC02&gt; { [ U10B2F,         U10B31 ] }; // 𐬯 𐬱
    key &lt;AC03&gt; { [ U10B1B,         U10B1C ] }; // 𐬛 𐬜
    key &lt;AC04&gt; { [ U10B1F,         U10B16 ] }; // 𐬟 𐬖
    key &lt;AC05&gt; { [ U10B14,         U10B15 ] }; // 𐬔 𐬕
    key &lt;AC06&gt; { [ U10B35,          UE100 ] }; // 𐬵 
    key &lt;AC07&gt; { [ U10B18,         U10B24 ] }; // 𐬘 𐬤
    key &lt;AC08&gt; { [ U10B10,          UE101 ] }; // 𐬐 
    key &lt;AC09&gt; { [ U10B2E,          UE103 ] }; // 𐬮 
    key &lt;AC10&gt; { [ U10B3B,         U10B3A ] }; // 𐬻 𐬺
    key &lt;AC11&gt; { [ U10B1D                 ] }; // 𐬝

    key &lt;AD01&gt; { [ U10B22,         U10B23 ] }; // 𐬢 𐬣
    key &lt;AD02&gt; { [ U10B33,         U10B34 ] }; // 𐬳 𐬴
    key &lt;AD03&gt; { [ U10B08,         U10B09 ] }; // 𐬈 𐬉
    key &lt;AD04&gt; { [ U10B2D,         U10B26 ] }; // 𐬭 𐬦
    key &lt;AD05&gt; { [ U10B19,         U10B1A ] }; // 𐬙 𐬚
    key &lt;AD06&gt; { [ U10B2B,         U10B2A ] }; // 𐬫 𐬪
    key &lt;AD07&gt; { [ U10B0E,         U10B0F ] }; // 𐬎 𐬏
    key &lt;AD08&gt; { [ U10B0C,         U10B0D ] }; // 𐬌 𐬍
    key &lt;AD09&gt; { [ U10B0A,         U10B0B ] }; // 𐬊 𐬋
    key &lt;AD10&gt; { [ U10B1E                 ] }; // 𐬞
    key &lt;AD11&gt; { [ U10B06,         U10B07 ] }; // 𐬆 𐬇
    key &lt;AD12&gt; { [ U10B02,         U10B03 ] }; // 𐬂 𐬃

    key &lt;AE01&gt; { [ U10B78                 ] }; // 𐭸
    key &lt;AE02&gt; { [ U10B79                 ] }; // 𐭹
    key &lt;AE03&gt; { [ U10B7A                 ] }; // 𐭺
    key &lt;AE04&gt; { [ U10B7B                 ] }; // 𐭻
    key &lt;AE05&gt; { [ U10B7C                 ] }; // 𐭼
    key &lt;AE06&gt; { [ U10B7D                 ] }; // 𐭽
    key &lt;AE07&gt; { [ U10B7E                 ] }; // 𐭾
    key &lt;AE08&gt; { [ U10B7F                 ] }; // 𐭿

    key &lt;BKSL&gt; { [ U10B04,         U10B05 ] }; // 𐬄 𐬅
    key &lt;LSGT&gt; { [ U10B04,         U10B05 ] }; // 𐬄 𐬅
};</code></pre></figure>

</div>

<p>در این فایل کاراکترهای مربوط به هر کلید در یک آرایه مشخص شده‌اند که مربوط به لایه‌های مختلف آن کلید هستند. ردیف مورد نظر ما `    key <AB10> { [ slash,        Arabic_question_mark,   question    ] };` است. که ابتدا در آن نام کلید و بعد از آن به ترتیب `/`، `؟` و `?` در سه لایه مختلف این کلید قرار داده شده‌اند. به این معنی که با فشار دادن کلید `AB10` یا همان `/` روی صفحه کلید نویسه `/` تایپ خواهد شد. در صورتی که این کلید به همراه `Shift` فشار داده شود نویسه `؟` و در لایه سوم (روی صفحه کلید من با تنظیماتی که انجام دادیم به همراه کلید `Alt` سمت راست صفحه کلید.) نویسه `?` تایپ خواهد شد.</AB10></p>

<p>برای اعمال تغییر و ساخت <code class="language-plaintext highlighter-rouge">keymap</code> شخصی خودمان یک کپی از این فایل تهیه می‌کنیم و تغییرات را روی آن اعمال می‌کنیم. پس از آن می‌توانیم از این <code class="language-plaintext highlighter-rouge">layout</code> استفاده کنیم.</p>

<p>کد یونیکد مربوط به نویسه <code class="language-plaintext highlighter-rouge">ۀ</code> برابر با ‪<code class="language-plaintext highlighter-rouge">U+06C0</code>‬ است، که در این فایل باید مشابه سایر کاراکترهای یونیکد به صورت ‪<code class="language-plaintext highlighter-rouge">0x10006c0</code>‬ نوشته شود:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span><span class="nb">sudo cp</span> /usr/share/X11/xkb/symbols/<span class="o">{</span>ir,ir.bak<span class="o">}</span>

<span class="nv">$ </span><span class="nb">cat</span> /usr/share/X11/xkb/symbols/ir | <span class="nb">grep</span> <span class="nt">-n</span> slash
89:    key &lt;AB10&gt; <span class="o">{</span> <span class="o">[</span> slash,        Arabic_question_mark,   question    <span class="o">]</span> <span class="o">}</span><span class="p">;</span>
94:    key &lt;BKSL&gt; <span class="o">{</span> <span class="o">[</span> backslash,        bar,            0x1002010   <span class="o">]</span> <span class="o">}</span><span class="p">;</span>
185:    key &lt;BKSL&gt; <span class="o">{</span> <span class="o">[</span> backslash,       bar,            ccedilla, Ccedilla  <span class="o">]</span> <span class="o">}</span><span class="p">;</span>
235:    key &lt;AB10&gt; <span class="o">{</span> <span class="o">[</span> slash,       Arabic_question_mark,   question    <span class="o">]</span> <span class="o">}</span><span class="p">;</span>

<span class="nv">$ </span><span class="nb">sudo sed</span> <span class="nt">-i</span> <span class="s1">'s/\[ slash,/\[ 0x10006c0,/'</span> /usr/share/X11/xkb/symbols/my-ir

<span class="nv">$ </span><span class="nb">cat</span> /usr/share/X11/xkb/symbols/ir | <span class="nb">grep</span> <span class="nt">-n</span> slash
94:    key &lt;BKSL&gt; <span class="o">{</span> <span class="o">[</span> backslash,        bar,            0x1002010   <span class="o">]</span> <span class="o">}</span><span class="p">;</span>
185:    key &lt;BKSL&gt; <span class="o">{</span> <span class="o">[</span> backslash,       bar,            ccedilla, Ccedilla  <span class="o">]</span> <span class="o">}</span><span class="p">;</span>

<span class="nv">$ </span><span class="nb">cat</span> /usr/share/X11/xkb/symbols/ir | <span class="nb">grep</span> <span class="nt">-n</span> 0x10006c0
89:    key &lt;AB10&gt; <span class="o">{</span> <span class="o">[</span> 0x10006c0,        Arabic_question_mark,   question    <span class="o">]</span> <span class="o">}</span><span class="p">;</span>
235:    key &lt;AB10&gt; <span class="o">{</span> <span class="o">[</span> 0x10006c0,       Arabic_question_mark,   question    <span class="o">]</span> <span class="o">}</span><span class="p">;</span></code></pre></figure>

</div>

<p>برای یافتن نام یا کد کاراکترهای یونیکد می‌توانید به <a href="https://unicode-table.com/en/" target="_blank" rel="noopener noreferrer">این وبسایت</a> مراجعه کنید.</p>

<p>گر چه ویرایش فایل‌ها در مسیر ‪<code class="language-plaintext highlighter-rouge">/usr/share/X11/xkb/symbols</code>‬ امکان شخصی سازی <code class="language-plaintext highlighter-rouge">keymap</code> را به شما می‌دهد اما از نسخه <code class="language-plaintext highlighter-rouge">libxkbcommon 0.10.0</code> امکان ایجاد فایل‌های تنظیمات شخصی در ‪‪<code class="language-plaintext highlighter-rouge">$XDG_CONFIG_HOME/xkb</code>‬‬ و در پوشه‌های ‪‪<code class="language-plaintext highlighter-rouge">$XDG_CONFIG_HOME/xkb/rules/</code>‬‬ و ‪‪<code class="language-plaintext highlighter-rouge">$XDG_CONFIG_HOME/xkb/symbols</code>‬‬ فراهم شده است و فایل‌های موجود در این مسیر پیش از فایل‌های پیش‌گزیده‌اش فراخوانی می‌شوند.</p>

<p>به عنوان نمونه برای افزودن یک آپشن برای جایگزینی کلید <code class="language-plaintext highlighter-rouge">PtrSc</code> با کلید <code class="language-plaintext highlighter-rouge">Menu</code> فایل‌های ‪‪<code class="language-plaintext highlighter-rouge">$XDG_CONFIG_HOME/xkb/rules/envdev</code>‬‬ و ‪‪<code class="language-plaintext highlighter-rouge">$XDG_CONFIG_HOME/xkb/symbols/custom</code>‬‬ را به صورت زیر ایجاد و تنظیم می‌کنیم:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span><span class="nb">mkdir</span> <span class="nt">-p</span> ~/.config/xkb/<span class="o">{</span>symbols,rules<span class="o">}</span>
<span class="nv">$ </span><span class="nb">cd</span> ~/.config/xkb
<span class="nv">$ </span><span class="nb">cat</span> <span class="o">&gt;</span> rules/evdev <span class="o">&lt;&lt;</span> <span class="no">EOF</span><span class="sh">
! option = symbols
  custom:prtscmenu = +custom(prtscmenu)

! include %S/evdev
</span><span class="no">EOF
</span><span class="nv">$ </span><span class="nb">cat</span> <span class="o">&gt;</span> symbols/custom <span class="o">&lt;&lt;</span> <span class="no">EOF</span><span class="sh">
partial modifier_keys
xkb_symbols "prtscmenu" {
  key &lt;PRSC&gt; { [ Menu ] };
};
EOF</span></code></pre></figure>

</div>

<p>و بعد باید این گزینه را فعال/غیرفعال کنیم. برای محیط گنوم:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="c"># apply custom layout:</span>
<span class="nv">$ </span>gsettings <span class="nb">set </span>org.gnome.desktop.input-sources xkb-options <span class="s2">"['custom:prtscmenu']"</span>
<span class="c"># disable custom layout:</span>
<span class="nv">$ </span>gsettings <span class="nb">set </span>org.gnome.desktop.input-sources xkb-options <span class="s2">"[]"</span></code></pre></figure>

</div>

<p>یا برای ایجاد <code class="language-plaintext highlighter-rouge">layout</code> شخصی که پیش از این ایجاد کردیم:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span><span class="nb">cat</span> <span class="o">&gt;</span> ~/.config/xkb/symbols/ir-mz <span class="o">&lt;&lt;</span> <span class="no">EOF</span><span class="sh">
default partial alphanumeric_keys
xkb_symbols "basic" {
    include "ir(pes)"
    include "level3(caps_switch)"
    name[Group1] = "Persian (IR, my custom)";
    key &lt;AB10&gt; { [ 0x10006c0, Arabic_question_mark, question ] };
};
EOF</span></code></pre></figure>

</div>

<p>من از فایل زیر برای جابجایی حرف <code class="language-plaintext highlighter-rouge">چ</code> در کیبورد استاندارد فارسی با <code class="language-plaintext highlighter-rouge">/</code> که کاربرد کمتری دارد استفاده می‌کنم:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span><span class="nb">cat</span> ~/.config/xkb/symbols/ir-mz
default partial alphanumeric_keys
xkb_symbols <span class="s2">"basic"</span> <span class="o">{</span>
    include <span class="s2">"ir(pes)"</span>
    name[Group1]<span class="o">=</span> <span class="s2">"Persian (IR, my custom layout)"</span><span class="p">;</span>
    key &lt;AB10&gt; <span class="o">{</span> <span class="o">[</span> Arabic_tcheh,		Arabic_question_mark,	question	<span class="o">]</span> <span class="o">}</span><span class="p">;</span>
    key &lt;AD12&gt; <span class="o">{</span> <span class="o">[</span> slash,	braceleft,		0x100202b	<span class="o">]</span> <span class="o">}</span><span class="p">;</span>
<span class="o">}</span><span class="p">;</span></code></pre></figure>

</div>

<p>برای استفاده از این <code class="language-plaintext highlighter-rouge">layout</code> در محیط <code class="language-plaintext highlighter-rouge">Swaywm</code> در فایل تنظیمات مربوط به آن <code class="language-plaintext highlighter-rouge">input type:keyboard xkb_layout ir-mz</code> را می‌افزاییم یا از این دستور استفاده می‌کنیم:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">swaymsg input <span class="s2">"</span><span class="si">$(</span>swaymsg <span class="nt">-t</span> get_inputs | <span class="nb">grep</span> <span class="s1">'identifier.*keyboard'</span> | <span class="nb">cut</span> <span class="nt">-d</span><span class="s1">'"'</span> <span class="nt">-f4</span><span class="si">)</span><span class="s2">"</span> xkb_layout ir-mz</code></pre></figure>

</div>

<p>همانطور که گفتم این تنظیمات پیش از مسیرهای پیش‌گزیده فراخوانی و اعمال می‌شوند. برای اطلاعات بیشتر می‌توانید <a href="https://who-t.blogspot.com/2020/02/user-specific-xkb-configuration-part-1.html?m=1" target="_blank" rel="noopener noreferrer">این صفحه</a> را بخوانید.</p>]]></content><author><name>محمد زینلی</name><email>m@zmim.ir</email></author><category term="foss" /><category term="swaywm" /><category term="wayland" /><category term="xorg" /><category term="linux" /><summary type="html"><![CDATA[تنظیمات صفحه کلید در گنو/لینوکس و شخصی‌سازی لایه‌های صفحه کلید.]]></summary></entry><entry xml:lang="fa"><title type="html">افزودن terminfo به سرور</title><link href="https://zmim.ir/terminfo/" rel="alternate" type="text/html" title="افزودن terminfo به سرور" /><published>2022-03-24T20:42:36+04:30</published><updated>2022-03-24T20:42:36+04:30</updated><id>https://zmim.ir/Adding-terminfo-entries-to-a-remote-machine</id><content type="html" xml:base="https://zmim.ir/terminfo/"><![CDATA[<h1 id="جابجایی-فایل-بین-گوشی-اندروید-و-سیستم-گنولینوکس-و-مشکل-terminfo-برای-ترمینال-foot">جابجایی فایل بین گوشی اندروید و سیستم گنو/لینوکس و مشکل <code class="language-plaintext highlighter-rouge">terminfo</code> برای ترمینال <code class="language-plaintext highlighter-rouge">foot</code></h1>

<p>من روی سیستم از تریمینال امولاتور <a href="https://codeberg.org/dnkl/foot" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">foot</code></a> استقاده می‌کنم که روی <code class="language-plaintext highlighter-rouge">wayland</code> به درستی اجرا می‌شود و بسیار ساده، سریع و مینیمال است.
برای جابجایی فایل‌ها بین گوشی اندروید و سیستم گنو/لینوکس هم از <code class="language-plaintext highlighter-rouge">scp</code> یا <code class="language-plaintext highlighter-rouge">rsync</code> روی <code class="language-plaintext highlighter-rouge">ssh</code> استفاده می‌کنم. اگر دوست دارید، می‌توانید ویدیوی آموزشی که در این باره ساختم را ببینید.</p>

<div class="video">
<iframe id="odysee-iframe" src="https://odysee.com/$/embed/ssh-on-termux/2c1fb60299e057dad14d1ffdd70f5bdbee16df88?r=CTpZDCJuEb8cZyCyCCpUEdw5D4LFZTkn" allowfullscreen=""></iframe>
</div>

<p>هنگامی که برای اولین بار از ترمینال <code class="language-plaintext highlighter-rouge">foot</code> به گوشی اندرویدم <code class="language-plaintext highlighter-rouge">ssh</code> کردم، رنگ‌های ترمینال به درستی نمایش داده نمی‌شد و هر کاراکتری که تایپ می‌کردم دو بار نوشته می‌شد.
پس از کمی جستجو فهمیدم که مشکل مربوط به داده‌های <code class="language-plaintext highlighter-rouge">terminfo</code> و نبود آنها روی <code class="language-plaintext highlighter-rouge">termux</code> است. اینجا می‌توانید نبود رنگ‌ها و همچنین تکرار چند باره داده‌های <code class="language-plaintext highlighter-rouge">zsh prompt</code> را روی ترماکس بعد از <code class="language-plaintext highlighter-rouge">ssh</code> ببینید و آن را با گوشی مقایسه کنید:</p>

<div style="text-align: center;">
    <img src="no-terminfo.png" style="max-width: 80%; margin: 10px;" alt="نبود `terminfo`" />
</div>

<h1 id="نبود-داده‌های-terminfo-روی-سرور">نبود داده‌های <code class="language-plaintext highlighter-rouge">terminfo</code> روی سرور</h1>

<p>ممکن است برای شما هم بارها پیش آمده باشد که هنگام اجرای یک برنامه تحت ترمینال روی سروری که به آن <code class="language-plaintext highlighter-rouge">ssh</code> کرده‌اید این خطاها را دریافت کرده باشید:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">Error opening terminal: xterm-kitty.
<span class="c"># OR</span>
WARNING: terminal is not fully functional
/etc/hosts  <span class="o">(</span>press RETURN<span class="o">)</span></code></pre></figure>

</div>

<p>این مشکلات به همان دلیلی که گفتم پیش می‌آیند.</p>

<h1 id="چه-باید-کرد">چه باید کرد؟</h1>

<ul>
  <li>روی سرور با <code class="language-plaintext highlighter-rouge">export TERM=xterm</code>  متغیر محیطی ‪<code class="language-plaintext highlighter-rouge">$TERM</code>‬ را تغییر دهید و آزمایش کنید که آیا مشکل برطرف می‌شود یا خیر.</li>
  <li>ترمینال امولاتوری را که استفاده می‌کنید روی سرور هم نصب کنید. (برای من این کار نشدنی بود چرا که روی ترماکس می‌خواستم <code class="language-plaintext highlighter-rouge">ssh</code> بزنم.)</li>
  <li>داده‌های <code class="language-plaintext highlighter-rouge">terminfo</code> را به سرور بیافزایید.</li>
</ul>

<h2 id="افزودن-داده‌های-terminfo-به-سرور">افزودن داده‌های <code class="language-plaintext highlighter-rouge">terminfo</code> به سرور</h2>

<ul>
  <li>اگر داده‌های <code class="language-plaintext highlighter-rouge">terminfo</code> را در یک فایل دارید می‌توانید آنها را به سرور منتقل کرده و با استفاده از <code class="language-plaintext highlighter-rouge">tic</code> آنها را نصب کنید.</li>
</ul>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">rsync &lt;PATH-TO-YOUR.TERMINFO&gt; &lt;REMOTE-MACHINE&gt;:/tmp
ssh &lt;REMOTE-MACHINE&gt;
<span class="nb">sudo </span>tic /tmp/emu.terminfo</code></pre></figure>

</div>

<p>اگر این داده‌ها را ندارید می‌توانید با استفاده از ‪<code class="language-plaintext highlighter-rouge">infocmp &gt; foot.terminfo</code>‬ آنها را ببینید و در یک فایل ذخیره کنید.
برای <code class="language-plaintext highlighter-rouge">foot</code> این داده‌ها به این صورت هستند:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">infocmp
<span class="c">#	Reconstructed via infocmp from file: /usr/share/terminfo/f/foot</span>
foot|foot terminal emulator,
	am, bce, bw, ccc, hs, mir, msgr, npc, xenl,
	colors#0x100, cols#80, it#8, lines#24, pairs#0x10000,
	<span class="nv">acsc</span><span class="o">=</span><span class="sb">``</span>aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz<span class="o">{{||}}</span>~~,
	<span class="nv">bel</span><span class="o">=</span>^G, <span class="nv">blink</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>5m, <span class="nv">bold</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1m, <span class="nv">cbt</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>Z, <span class="nv">civis</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>?25l,
	<span class="nv">clear</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>H<span class="se">\E</span><span class="o">[</span>2J, <span class="nv">cnorm</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>?12l<span class="se">\E</span><span class="o">[</span>?25h, <span class="nv">cr</span><span class="o">=</span><span class="se">\r</span>,
	<span class="nv">csr</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%i%p1%d<span class="p">;</span>%p2%dr, <span class="nv">cub</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%p1%dD, <span class="nv">cub1</span><span class="o">=</span>^H,
	<span class="nv">cud</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%p1%dB, <span class="nv">cud1</span><span class="o">=</span><span class="se">\n</span>, <span class="nv">cuf</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%p1%dC, <span class="nv">cuf1</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>C,
	<span class="nv">cup</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%i%p1%d<span class="p">;</span>%p2%dH, <span class="nv">cuu</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%p1%dA, <span class="nv">cuu1</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>A,
	<span class="nv">cvvis</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>?12<span class="p">;</span>25h, <span class="nv">dch</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%p1%dP, <span class="nv">dch1</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>P, <span class="nv">dim</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>2m,
	<span class="nv">dl</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%p1%dM, <span class="nv">dl1</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>M, <span class="nv">ech</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%p1%dX, <span class="nv">ed</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>J, <span class="nv">el</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>K,
	<span class="nv">el1</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1K, <span class="nv">flash</span><span class="o">=</span><span class="se">\E</span><span class="o">]</span>555<span class="se">\E\\</span>, <span class="nv">home</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>H, <span class="nv">hpa</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%i%p1%dG,
	<span class="nv">ht</span><span class="o">=</span>^I, <span class="nv">hts</span><span class="o">=</span><span class="se">\E</span>H, <span class="nv">ich</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%p1%d@, <span class="nv">ich1</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>@, <span class="nv">il</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%p1%dL,
	<span class="nv">il1</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>L, <span class="nv">ind</span><span class="o">=</span><span class="se">\n</span>, <span class="nv">indn</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%p1%dS,
	<span class="nv">initc</span><span class="o">=</span><span class="se">\E</span><span class="o">]</span>4<span class="p">;</span>%p1%d<span class="p">;</span>rgb:%p2%<span class="o">{</span>255<span class="o">}</span>%<span class="k">*</span>%<span class="o">{</span>1000<span class="o">}</span>%/%2.2X/%p3%<span class="o">{</span>255<span class="o">}</span>%<span class="k">*</span>%<span class="o">{</span>1000<span class="o">}</span>%/%2.2X/%p4%<span class="o">{</span>255<span class="o">}</span>%<span class="k">*</span>%<span class="o">{</span>1000<span class="o">}</span>%/%2.2X<span class="se">\E\\</span>,
	<span class="nv">invis</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>8m, <span class="nv">is2</span><span class="o">=</span><span class="se">\E</span><span class="o">[!</span>p<span class="se">\E</span><span class="o">[</span>?3<span class="p">;</span>4l<span class="se">\E</span><span class="o">[</span>4l<span class="se">\E</span><span class="o">&gt;</span>, <span class="nv">kDC</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>3<span class="p">;</span>2~,
	<span class="nv">kEND</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>2F, <span class="nv">kHOM</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>2H, <span class="nv">kIC</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>2<span class="p">;</span>2~, <span class="nv">kLFT</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>2D,
	<span class="nv">kNXT</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>6<span class="p">;</span>2~, <span class="nv">kPRV</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>5<span class="p">;</span>2~, <span class="nv">kRIT</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>2C, <span class="nv">kbs</span><span class="o">=</span>^?,
	<span class="nv">kcbt</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>Z, <span class="nv">kcub1</span><span class="o">=</span><span class="se">\E</span>OD, <span class="nv">kcud1</span><span class="o">=</span><span class="se">\E</span>OB, <span class="nv">kcuf1</span><span class="o">=</span><span class="se">\E</span>OC, <span class="nv">kcuu1</span><span class="o">=</span><span class="se">\E</span>OA,
	<span class="nv">kdch1</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>3~, <span class="nv">kend</span><span class="o">=</span><span class="se">\E</span>OF, <span class="nv">kf1</span><span class="o">=</span><span class="se">\E</span>OP, <span class="nv">kf10</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>21~, <span class="nv">kf11</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>23~,
	<span class="nv">kf12</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>24~, <span class="nv">kf13</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>2P, <span class="nv">kf14</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>2Q, <span class="nv">kf15</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>2R,
	<span class="nv">kf16</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>2S, <span class="nv">kf17</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>15<span class="p">;</span>2~, <span class="nv">kf18</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>17<span class="p">;</span>2~,
	<span class="nv">kf19</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>18<span class="p">;</span>2~, <span class="nv">kf2</span><span class="o">=</span><span class="se">\E</span>OQ, <span class="nv">kf20</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>19<span class="p">;</span>2~, <span class="nv">kf21</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>20<span class="p">;</span>2~,
	<span class="nv">kf22</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>21<span class="p">;</span>2~, <span class="nv">kf23</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>23<span class="p">;</span>2~, <span class="nv">kf24</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>24<span class="p">;</span>2~,
	<span class="nv">kf25</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>5P, <span class="nv">kf26</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>5Q, <span class="nv">kf27</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>5R, <span class="nv">kf28</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>5S,
	<span class="nv">kf29</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>15<span class="p">;</span>5~, <span class="nv">kf3</span><span class="o">=</span><span class="se">\E</span>OR, <span class="nv">kf30</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>17<span class="p">;</span>5~, <span class="nv">kf31</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>18<span class="p">;</span>5~,
	<span class="nv">kf32</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>19<span class="p">;</span>5~, <span class="nv">kf33</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>20<span class="p">;</span>5~, <span class="nv">kf34</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>21<span class="p">;</span>5~,
	<span class="nv">kf35</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>23<span class="p">;</span>5~, <span class="nv">kf36</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>24<span class="p">;</span>5~, <span class="nv">kf37</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>6P, <span class="nv">kf38</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>6Q,
	<span class="nv">kf39</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>6R, <span class="nv">kf4</span><span class="o">=</span><span class="se">\E</span>OS, <span class="nv">kf40</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>6S, <span class="nv">kf41</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>15<span class="p">;</span>6~,
	<span class="nv">kf42</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>17<span class="p">;</span>6~, <span class="nv">kf43</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>18<span class="p">;</span>6~, <span class="nv">kf44</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>19<span class="p">;</span>6~,
	<span class="nv">kf45</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>20<span class="p">;</span>6~, <span class="nv">kf46</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>21<span class="p">;</span>6~, <span class="nv">kf47</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>23<span class="p">;</span>6~,
	<span class="nv">kf48</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>24<span class="p">;</span>6~, <span class="nv">kf49</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>3P, <span class="nv">kf5</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>15~, <span class="nv">kf50</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>3Q,
	<span class="nv">kf51</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>3R, <span class="nv">kf52</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>3S, <span class="nv">kf53</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>15<span class="p">;</span>3~, <span class="nv">kf54</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>17<span class="p">;</span>3~,
	<span class="nv">kf55</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>18<span class="p">;</span>3~, <span class="nv">kf56</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>19<span class="p">;</span>3~, <span class="nv">kf57</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>20<span class="p">;</span>3~,
	<span class="nv">kf58</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>21<span class="p">;</span>3~, <span class="nv">kf59</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>23<span class="p">;</span>3~, <span class="nv">kf6</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>17~, <span class="nv">kf60</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>24<span class="p">;</span>3~,
	<span class="nv">kf61</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>4P, <span class="nv">kf62</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>4Q, <span class="nv">kf63</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>4R, <span class="nv">kf7</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>18~,
	<span class="nv">kf8</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>19~, <span class="nv">kf9</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>20~, <span class="nv">khome</span><span class="o">=</span><span class="se">\E</span>OH, <span class="nv">kich1</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>2~,
	<span class="nv">kind</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>2B, <span class="nv">kmous</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>&lt;, <span class="nv">knp</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>6~, <span class="nv">kpp</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>5~,
	<span class="nv">kri</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>1<span class="p">;</span>2A, <span class="nv">oc</span><span class="o">=</span><span class="se">\E</span><span class="o">]</span>104<span class="se">\E\\</span>, <span class="nv">op</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>39<span class="p">;</span>49m, <span class="nv">rc</span><span class="o">=</span><span class="se">\E</span>8,
	<span class="nv">rep</span><span class="o">=</span>%p1%c<span class="se">\E</span><span class="o">[</span>%p2%<span class="o">{</span>1<span class="o">}</span>%-%db, <span class="nv">rev</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>7m, <span class="nv">ri</span><span class="o">=</span><span class="se">\E</span>M,
	<span class="nv">rin</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%p1%dT, <span class="nv">ritm</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>23m, <span class="nv">rmacs</span><span class="o">=</span><span class="se">\E</span><span class="o">(</span>B, <span class="nv">rmam</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>?7l,
	<span class="nv">rmcup</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>?1049l<span class="se">\E</span><span class="o">[</span>23<span class="p">;</span>0<span class="p">;</span>0t, <span class="nv">rmir</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>4l, <span class="nv">rmkx</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>?1l<span class="se">\E</span><span class="o">&gt;</span>,
	<span class="nv">rmso</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>27m, <span class="nv">rmul</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>24m, <span class="nv">rs1</span><span class="o">=</span><span class="se">\E</span>c,
	<span class="nv">rs2</span><span class="o">=</span><span class="se">\E</span><span class="o">[!</span>p<span class="se">\E</span><span class="o">[</span>?3<span class="p">;</span>4l<span class="se">\E</span><span class="o">[</span>4l<span class="se">\E</span><span class="o">&gt;</span>, <span class="nv">sc</span><span class="o">=</span><span class="se">\E</span>7,
	<span class="nv">setab</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%?%p1%<span class="o">{</span>8<span class="o">}</span>%&lt;%t4%p1%d%e%p1%<span class="o">{</span>16<span class="o">}</span>%&lt;%t10%p1%<span class="o">{</span>8<span class="o">}</span>%-%d%e48:5:%p1%d%<span class="p">;</span>m,
	<span class="nv">setaf</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%?%p1%<span class="o">{</span>8<span class="o">}</span>%&lt;%t3%p1%d%e%p1%<span class="o">{</span>16<span class="o">}</span>%&lt;%t9%p1%<span class="o">{</span>8<span class="o">}</span>%-%d%e38:5:%p1%d%<span class="p">;</span>m,
	<span class="nv">sgr</span><span class="o">=</span>%?%p9%t<span class="se">\E</span><span class="o">(</span>0%e<span class="se">\E</span><span class="o">(</span>B%<span class="p">;</span><span class="se">\E</span><span class="o">[</span>0%?%p6%t<span class="p">;</span>1%<span class="p">;</span>%?%p5%t<span class="p">;</span>2%<span class="p">;</span>%?%p2%t<span class="p">;</span>4%<span class="p">;</span>%?%p1%p3%|%t<span class="p">;</span>7%<span class="p">;</span>%?%p4%t<span class="p">;</span>5%<span class="p">;</span>%?%p7%t<span class="p">;</span>8%<span class="p">;</span>m,
	<span class="nv">sgr0</span><span class="o">=</span><span class="se">\E</span><span class="o">(</span>B<span class="se">\E</span><span class="o">[</span>m, <span class="nv">sitm</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>3m, <span class="nv">smacs</span><span class="o">=</span><span class="se">\E</span><span class="o">(</span>0, <span class="nv">smam</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>?7h,
	<span class="nv">smcup</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>?1049h<span class="se">\E</span><span class="o">[</span>22<span class="p">;</span>0<span class="p">;</span>0t, <span class="nv">smir</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>4h, <span class="nv">smkx</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>?1h<span class="se">\E</span><span class="o">=</span>,
	<span class="nv">smso</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>7m, <span class="nv">smul</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>4m, <span class="nv">tbc</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>3g, <span class="nv">u6</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%i%d<span class="p">;</span>%dR,
	<span class="nv">u7</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>6n, <span class="nv">u8</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>?%[<span class="p">;</span>0123456789]c, <span class="nv">u9</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>c,
	<span class="nv">vpa</span><span class="o">=</span><span class="se">\E</span><span class="o">[</span>%i%p1%dd,</code></pre></figure>

</div>

<ul>
  <li>راه ساده‌تر این است که پس از تولید این داده‌ها مستقیم آنها را به سرور فرستاده و نصب کنید:</li>
</ul>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">infocmp | ssh &lt;REMOTE-MACHINE&gt; <span class="s2">"tic -x /dev/stdin"</span></code></pre></figure>

</div>

<ul>
  <li>اما اگر سرور شما قدیمی است و یا به هر دلیلی <code class="language-plaintext highlighter-rouge">tic</code> امکان دسترسی به <code class="language-plaintext highlighter-rouge">/dev/stdin</code> را ندارد، می‌توانید داده‌ها را مستقیم روی فایلی در سرور بریزید و بعد نصب کنید:</li>
</ul>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">infocmp | ssh &lt;REMOTE-MACHINE&gt; <span class="s2">"cat &gt; /tmp/terminfo &amp;&amp; tic -x /tmp/terminfo; rm /tmp/terminfo"</span></code></pre></figure>

</div>

<p>پس از افزودن داده‌های <code class="language-plaintext highlighter-rouge">foot</code> به <code class="language-plaintext highlighter-rouge">termux</code> مشکل من حل شد.</p>

<div style="text-align: center;">
    <img src="with-terminfo.png" style="max-width: 80%; margin: 10px;" alt="نمایش درست رنگ‌ها پس از افزودن داده‌های `terminfo`" />
</div>

<h1 id="منابع">منابع:</h1>

<ul>
  <li><a href="https://sw.kovidgoyal.net/kitty/faq/#i-get-errors-about-the-terminal-being-unknown-or-opening-the-terminal-failing-when-sshing-into-a-different-computer" target="_blank" rel="noopener noreferrer">kitty FAQ</a></li>
  <li><a href="https://codeberg.org/dnkl/foot" target="_blank" rel="noopener noreferrer">foot repository</a></li>
</ul>]]></content><author><name>محمد زینلی</name><email>m@zmim.ir</email></author><category term="foss" /><category term="termux" /><category term="ssh" /><category term="linux" /><summary type="html"><![CDATA[گاهی بسته به ترمینالی که استفاده می‌کنید، برخی برنامه‌های تحت ترمینال روی سروری که به آن `ssh` کرده‌اید به درستی اجرا نمی‌شوند و نیاز است که `terminfo` را به سرور بیافزایید.]]></summary></entry><entry xml:lang="fa"><title type="html">نصب Ubuntu 20.04 روی تبلت Lenovo Thinkpad 10</title><link href="https://zmim.ir/ubuntu-on-tablet/" rel="alternate" type="text/html" title="نصب Ubuntu 20.04 روی تبلت Lenovo Thinkpad 10" /><published>2021-02-13T10:20:00+03:30</published><updated>2021-02-13T10:20:00+03:30</updated><id>https://zmim.ir/Installing-Ubuntu-20.04-on-a-32-bit-uefi-device</id><content type="html" xml:base="https://zmim.ir/ubuntu-on-tablet/"><![CDATA[<h1 id="آنچه-گذشت">آنچه گذشت</h1>

<p>یکی از دوستان من یک تبلت Lenovo Thinkpad 10 دارد و چون دوست داشت روی آن گنو/لینوکس نصب کند، از من خواست تا کمکش کنم. من هم برایم جالب بود که ببینم محیط‌های دسکتاپ مختلف چقدر برای استفاده با صفحه‌های لمسی سازگار هستند.</p>

<p>برای اینکه هر بار که می‌خواهید یک فایل ISO را بوت کنید، مجبور نباشید یک USB drive را فرمت کنید می‌توانید از <a href="https://github.com/ventoy/Ventoy" target="_blank" rel="noopener noreferrer">ventoy</a> استفاده کنید.</p>

<p>بعد از اینکه گزینه‌های مختلف را تست کردیم، تصمیم گرفتیم که Ubuntu را نصب کنیم. از آنجا که برای اولین بار بود که دوست من می‌خواست از گنو/لینوکس استفاده کند، قرار شد که پله پله جلو برویم و در هر بخش من روال کار را توضیح بدهم. اما در همان آغاز، کار گره خورد. چند باری با استفاده از <code class="language-plaintext highlighter-rouge">Rufus</code>  از فایل <code class="language-plaintext highlighter-rouge">ISO</code> یک USB drive ساختم که بتوانم با بوت کردن سیستم از روی آن مراحل نصب را پی بگیرم. هر چند که در تنظیمات <code class="language-plaintext highlighter-rouge">BIOS</code> (با گرفتن همزمان دکمه خاموش و روشن کردن دستگاه و افزایش صدا می‌توانید به تنظیمات <code class="language-plaintext highlighter-rouge">BIOS</code> دسترسی پیدا کنید و تنظیمات بوت را تغییر دهید.) اولویت را به <code class="language-plaintext highlighter-rouge">USB</code> داده بودم و <code class="language-plaintext highlighter-rouge">Secure Boot</code> و <code class="language-plaintext highlighter-rouge">Fast Boot</code> را غیر فعال کرده بودم اما سیستم باز هم از روی هارد بوت می‌شد و <code class="language-plaintext highlighter-rouge">USB drive</code>  را به عنوان <code class="language-plaintext highlighter-rouge">bootable</code> نمی‌شناخت.</p>

<p>یک بار هم به شیوه آشنا، با استفاده از <code class="language-plaintext highlighter-rouge">dd</code> فایل <code class="language-plaintext highlighter-rouge">ISO</code> را روی <code class="language-plaintext highlighter-rouge">USB</code> ریختم ولی باز هم با اینکه به راحتی روی لپ‌تاپ بوت می‌شد اما روی تبلت مشکل داشت.</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">dd </span><span class="k">if</span><span class="o">=</span>&lt;PATH-TO-A-LIVE-ISO&gt; <span class="nv">of</span><span class="o">=</span>/dev/sdx <span class="nv">status</span><span class="o">=</span><span class="s2">"progress"</span></code></pre></figure>

</div>

<p>که در اینجا <code class="language-plaintext highlighter-rouge">sdx</code>، بلاک مربوط به <code class="language-plaintext highlighter-rouge">USB drive</code> شماست که می‌توانید با استفاده از <code class="language-plaintext highlighter-rouge">lsblk</code> آن را بیابید.</p>

<p>با کمی جستجو و دیدن مشخصات تبلت متوجه شدم که این سیستم از ‪<code class="language-plaintext highlighter-rouge">UEFI</code>‬ سی و دو بیتی استفاده می‌کند و دلیل بوت نشدن <code class="language-plaintext highlighter-rouge">USB</code> هم همین است.</p>

<h1 id="چه-باید-کرد">چه باید کرد؟</h1>

<p>پاسخ ساده است</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">USB drive</code> را <code class="language-plaintext highlighter-rouge">fat32</code> فرمت کنید.</li>
  <li>محتوای فایل <code class="language-plaintext highlighter-rouge">ISO</code> را روی آن به صورت دستی کپی کنید.</li>
</ul>

<p>برای <code class="language-plaintext highlighter-rouge">mount</code> کردن یک فایل <code class="language-plaintext highlighter-rouge">ISO</code> در گنو/لینوکس می‌توانید از دستور زیر استفاده کنید:</p>
<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">sudo </span>mount <span class="nt">-o</span> loop &lt;PATH-TO-A-LIVE-ISO&gt; &lt;PATH-TO-THE-FOLDER-YOU-WANT-TO-MOUNT-THE-ISO</code></pre></figure>

</div>

<ul>
  <li>فایل <a href="https://github.com/hirotakaster/baytail-bootia32.efi" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">bootia32.efi</code></a> را از ریپوزیتوری گیتهاب یا از <a href="bootia32.efi">اینجا</a> دانلود کنید و در پوشه <code class="language-plaintext highlighter-rouge">/EFI/BOOT</code> کپی کنید.</li>
  <li>فایل <code class="language-plaintext highlighter-rouge">grub.cfg</code> را از پوشه <code class="language-plaintext highlighter-rouge">/boot/grub</code> کپی کنید و در پوشه ریشه <code class="language-plaintext highlighter-rouge">USB</code> بریزید(<code class="language-plaintext highlighter-rouge">/</code>).</li>
  <li><code class="language-plaintext highlighter-rouge">Fast Boot</code> و <code class="language-plaintext highlighter-rouge">Secure Boot</code> را غیرفعال کنید و سیستم را از <code class="language-plaintext highlighter-rouge">USB</code> بوت کنید.</li>
</ul>]]></content><author><name>محمد زینلی</name><email>m@zmim.ir</email></author><category term="foss" /><category term="ubuntu" /><category term="touch" /><summary type="html"><![CDATA[بوت کردن یک دستگاه با UEFI ۳۲ بیتی از USB]]></summary></entry><entry xml:lang="fa"><title type="html">ارثیه</title><link href="https://zmim.ir/heritage/" rel="alternate" type="text/html" title="ارثیه" /><published>2021-01-25T14:20:00+03:30</published><updated>2021-01-25T14:20:00+03:30</updated><id>https://zmim.ir/heritage</id><content type="html" xml:base="https://zmim.ir/heritage/"><![CDATA[<p>خداداد</p>

<p>انگار می توانست همه آنچه را که ته باغ بالای چاه کنار اتاقک در کله پیرمرد گذشته بود بخواند. به خاطرش آمد نوه‌اش هم همانطور خیره نگاهش کرده بود. معلوم بود پسرش همان وقت تصمیم نگرفته بود. خوب که نگاه کرد مطمئن شد پسرش همان چشم‌ها را داشت. همان‌ها که پرهیز می‌کرد از دیدنشان در آینه. همان چشم‌های مریم که هر بار به آینه نگاه می‌کرد، با غضب نگاهش می‌کردند. مریم مادرش بود انگار همه این اتفاق‌ها را او سال‌ها پیش رقم زده بود با یک نفرین. همان موقع که روی تخت افتاده بود و بعد از بیست سال به هوای اینکه می‌خواست توی ده بمیرد پسرش را کشانده بود آنجا. زن سوم علیخان بود بعد از دو تا زن که هیچ کدام بچه نیاورده بودند. همه می‌گفتند اجاق علیخان کور است و بی وارث می‌ماند. علیخان چهل و پنج سالی داشت که مریم را گرفته بود. همان‌جا توی ده آبستن شده بود و تنها پسر علیخان را آورده بود.</p>

<p>مریم</p>

<p>آسمان ابر گرفته و هوا نمدار بود. مردها همگی رفته بودند دنبال گرگ‌ها، که آن سال بد جوری جری شده بودند و تا پای آغل‌ها هم آمده بودند. نه پیش از آن سال دیده بودش و نه بعد از آن. حالا بعد از بیست سال روی تخت افتاده بود و می‌دانست که امشب را به صبح نمی‌رساند. صدای جیرجیرک‌ها را می‌شنید و بوی نم باغچه را، که باد همراه عطرچوب‌های تازه و گل‌هایی که نمی‌شناخت می‌آورد. تنها چیزی که می‌خواست این بود که یک بار دیگر قیافه سلیمان را ببیند و بی هیچ بهانه آوردنی همه چیز را برای خداداد گفته بود.</p>

<p>خداداد</p>

<p>خداداد آشفته پالتویش را برداشت و از در جلوی باغچه زد بیرون. تا میدانگاهی هیچ کس نبود. بی معطلی راه افتاد. می‌خواست تا از خانه اربابی و همه آنچه شنیده بود بگریزد. باد بوته چرخه ای را توی کوچه خالی می‌غلتاند. پایش توی گل کنار جو رفت و سر خورد. بلند شد و لباسش را نگاه کرد، تا زیر سینه‌اش گل شده بود. دور میدانگاهی یک قهوه خانه بود و خوار و بار فروشی که همه احتیاحات ابتدایی اهالی را رفع می‌کرد، نانوایی و عطاری که قیافه‌اش را توی شیشه آن نگاه کرد. لب‌های باریک و کشیده، چانه تیز، موهای بورش و با خودش فکر کرد: «غیر از چشم‌هام». یاد سلیمان افتاد و لرزش گرفت. راهش را ادامه داد. جلوی قهوه خانه داشتند خون‌های گوسفند را می‌شستند. سگ سیاهی با گوش‌های بریده شده آشغال‌های لاشه را به دندان می‌کشید. پسر بچه‌ای هم با لباس قرمز آستین پاره و کله از ته تراشیده چمباتمه زده بود. صورتی کثیف و آفتاب سوخته داشت. چشم‌هایش با نگاهی حریص سگ را می پایید. همه اینها را خوب به یاد داشت. و اینکه بعد از آن پیچید توی یک کوچه خلوت و کنار چنار خشکی به دیوار تکیه داد. پوستش رفته بود و تنه‌اش پوک شده بود. با این حال با سماجت سر پا مانده بود. آتش سیگار که به انگشت‌هاش رسید و سوزاندش، باعث شد به خودش بیاید. هیچ جوری توی کتش نمی‌رفت. او پسر علیخان بود و البته وارثش و حالا همه کاره ملک اربابی. با قدم‌های تند راه برگشت را پیش گرفت. به خانه که رسید دسته بیل بلندی را برداشت و راهش را به طرف اتاقک ته باغ کج کرد.</p>

<p>سلیمان</p>

<p>آتش ذغال‌هایش توی ایوان از بالای کاهدان انبار معلوم بود. علیخان نشسته بود و مثل هر شب وافور را گذاشته بود گوشه لبش. گویی عزمش را جزم کرده بود قبل از مرگ هر چه را که داشت دود کند. بغل ملا نشسته بود و آتش ذغال را فوت می‌کرد. گر می‌گرفت و تا جرقه میزد، شروع می‌کرد به فحش دادن که: «قرمساق‌ها مگر نگفتم خوب بگردانیدش.» اهل نماز و روزه بود، ولی حتی ماه رمضان هم نوبت‌های تریاکش ترک نمی‌شد. مجوزش را هم از ملا گرفته بود. البته سهم ملا هم از همنشینی پای بساط می‌رسید، که هیچ وقت از تو نمی‌انداخت. حتی آن شب هم که همه رفته بودند دنبال گرگ‌ها. اول از همه او دیده بودشان، چشم‌هایشان را که برق می‌زد. تیر انداخته بود از همان بالای آغل که نشسته بود. خیالش آمده بود سگند، قبل از اینکه خوب نزدیک شوند. به همین خاطر تیرش نشسته بود روی پشت یکیشان. سگ‌ها هم معلوم نبود صدایشان چرا در نیامده بود. حالا هم که رفته بودند رد بزنند، سلیمان مانده بود بالای کاهدان بپا. صدا که از پایین آمد خشکش زد. فقط او می‌دانست چون خودش آنجا بود. اما بقیه می‌گفتند بعد از اینکه پدرش داده بودش به علیخان نفرین کرده بود و پدرش از سر همان نفرین مرده بود. سلیمان اما می‌دانست مریم کار را فقط به نفرین نسپرده بود. هر شب می‌دیدش که تا کنار جو می‌رفت و پاهایش را توی آب می‌گذاشت. اما امشب فرق می‌کرد و تا در انبار را باز نکرد، متوجه‌اش نشد. موهای بلندش از پشت روسری گلدار قرمزی که مثل دستمال بسته بود بالای سرش بیرون ریخته بود. یک طره مو بر پیشانی خیسش افتاده بود و روی شقیقه از کنار چشم راستش تا روی گوشش کشیده شده بود. چند تار مو هم بر گونه‌های تبدارش خزیده بود و افشان شده بود. چشم و ابروی مشکی داشت. در چشم‌های درشتش رگ‌های سرخ دویده بود، لبریز از شرری مفتون کننده. لب‌هایش گلگون نبود ولی او دوست داشت. صورتی رنگ پریده بود و شیارهایشان از خشکی نبود. یک جوری انگار انار رسیده که ترک می‌خورد. قطره‌ای عرق از زیر چانه بر گردن برهنه کنار رگ نزدیک گلویش لغزید. خرده‌های ریز کاه بر گودی استخوان‌های ترقوه‌اش برق می‌زد، زیر نور مرده مهتاب که به زحمت از شکاف‌های سقف بر بدنش می‌نشست. شال سفیدی روی دوشش انداخته بود و زیر پستان‌هایش گره زده بود. لباسش تر شده بود و نفس نفس که می‌زد پستان‌هایش بالا و پایین می‌شد، بی‌فاصله چسبیده به پیرهنی که دور کمر باریکش چین خورده بود. بر ساق و مچ سفیدش هیچ النگویی نبود. لبه پایین دامنش را بالا گرفته بود و پاهایش تا زانو پیدا بود. پاشنه پایش را بالا گرفته بود. ماهیچه‌های پشت ساق‌های باریک و ورزیده‌اش منقبض و منبسط می‌شد. بر کف خاکی انبار که قدم میزد پاشنه و گودی پشت زانویش پر و خالی می‌شد و انحنای روی رانش از زیر دامن بالا می‌آمد و برجسته می‌شد. نگاهی به دور و برش انداخت و آرام سلیمان را صدا زد. سلیمان نفسش را که حبس شده بود بیرون داد و از روی کاهدان پایین آمد. خیره به ذرات غبار که در ستون‌های نور ملایم اطراف او می‌چرخید نگاه کرد. دستهایش را گرفت گونه‌اش را بوسید و او را به بغل گرفت. کنار هم روی علف‌های تازه دراز کشیدند. نمی‌دانست چقدر از این‌ها را مریم برای خداداد گفته بود. توی بغل سلیمان که دراز کشیده بود، لختی اندام‌هاش رنگ پریده می‌نمود. به جز گونه‌ها و خیرگی چشم‌هاش که هراسی بی حیا ته آنها موج می‌زد. اصلا مگر هیچ کس غیر از سلیمان که این تصویر را تا آن لحظه مثل یک راز با خودش حمل کرده بود، می‌توانست این معجزه را تعریف کند. چشم‌های خداداد چقدر شبیه چشم‌های مریم بود، وقتی که پدرش را برای آخرین بار نگاه می‌کرد.</p>

<p>خداداد</p>

<p>مریم برایشان فقط چشم‌هایش را به ارث نگذاشته بود. اینها را حالا خداداد می‌دید که با سری شکافته به چشم‌های پسرش خیره شده یود. به خاطرش آمد نوه‌اش هم با آن لباس قرمز آستین پاره و کله کچلش همان‌طور خیره نگاهش کرده بود.</p>]]></content><author><name>محمد زینلی</name><email>m@zmim.ir</email></author><category term="داستان کوتاه" /><summary type="html"><![CDATA[یک داستان کوتاه قدیمی]]></summary></entry><entry xml:lang="fa"><title type="html">افزودن بخش دیدگاه‌ها با ماستودون</title><link href="https://zmim.ir/mastodon-comments/" rel="alternate" type="text/html" title="افزودن بخش دیدگاه‌ها با ماستودون" /><published>2021-01-19T14:20:00+03:30</published><updated>2021-01-19T14:20:00+03:30</updated><id>https://zmim.ir/mastodon-comments</id><content type="html" xml:base="https://zmim.ir/mastodon-comments/"><![CDATA[<h1 id="ماستودون">ماستودون</h1>

<p><a href="https://fa.wikipedia.org/wiki/%D9%85%D8%A7%D8%B3%D8%AA%D9%88%D8%AF%D9%88%D9%86_(%D9%86%D8%B1%D9%85%E2%80%8C%D8%A7%D9%81%D8%B2%D8%A7%D8%B1)" target="_blank" rel="noopener noreferrer">از ویکی‌پدیا، دانشنامه آزاد</a></p>

<p><a href="https://joinmastodon.org/" target="_blank" rel="noopener noreferrer">ماستودون (به انگلیسی: Mastodon)</a> یک نرم‌افزار آزاد و متن‌باز خودمیزبان (خدمات وب) برای ساخت شبکهٔ اجتماعی است که این امکان را به هر شخص می‌دهد تا گره سرور خود را در شبکه میزبانی کند و پایگاه‌های مختلف از کاربران آن در میان سروهای متفاوتی پخش هستند.</p>

<p>این سرورها به صورت شبکه اجتماعی فدرال به هم متصل هستند، که به کاربران خود اجازه می‌دهد با یکدیگر به شکل یکپارچه تعامل داشته باشند. ماستودون عضوی از یک <a href="https://fediverse.party/" target="_blank" rel="noopener noreferrer">فدراسیون بزرگ‌تر</a> است که به کاربران امکان می‌دهد با دیگر سکوهای آزاد مانند <a href="https://joinpeertube.org/" target="_blank" rel="noopener noreferrer">پیرتیوب</a> و <a href="https://friendi.ca/" target="_blank" rel="noopener noreferrer">فرندیکا</a> که قوانین یکسانی را پشتیبانی می‌کنند تعامل داشته باشند.</p>

<h1 id="افزودن-بخش-دیدگاه‌ها-با-ماستودون">افزودن بخش دیدگاه‌ها با ماستودون</h1>

<p>یکی از دشواری‌های وبسایت‌ها استاتیک افزودن بخش دیدگاه‌هاست. گزینه‌های گوناگونی برای انجام این کار وجود دارد. یک راهکار ساده استفاده از Disqus است. چون Disqus  سنگین است و مقدار زیادی اسکریپت غیرضروری در صفحات بارگزاری می‌کند و مهم‌تر از همه آزاد نیست هرگز گزینه مطلوبی برای من نبود. برای دیدن راهکارهای بیشتر می‌توانید <a href="https://mehdix.ir/static-comments.html" target="_blank" rel="noopener noreferrer">این پست</a> مهدی صادقی را ببینید.</p>

<p>با سپاس از <a href="https://linuxrocks.online/@carl" target="_blank" rel="noopener noreferrer">‪@carl‬</a> برای نوشتن کد و گزارشی که در <a href="https://carlschwan.eu/2020/12/29/adding-comments-to-your-static-blog-with-mastodon/" target="_blank" rel="noopener noreferrer">این پست</a> نوشته است، از این پس شما می‌توانید با داشتن یک اکانت ماستودون دیدگاه‌های خودتان را برای من بفرستید، و آنچه دیگران نوشته‌اند را هم ببینید.</p>

<h2 id="کد-جاوا-اسکریپت">کد جاوا اسکریپت</h2>

<p>چون کد اصلی برای <a href="https://gohugo.io/" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">#HUGO</code></a> نوشته شده بود، من تغییرات اندکی در آن دادم تا با <a href="https://jekyllrb.com/" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">#JEKYLL</code></a> سازگار شود و آن را در فایل <a href="https://raw.githubusercontent.com/mhdzli/zmim.ir/master/src/_includes/mastodon.html" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">mastodon.html</code></a> در پوشه <a href="https://github.com/mhdzli/zmim.ir/tree/master/src/_includes" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">_includes</code></a> قراد دادم:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"page-content"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;h2&gt;</span>دیدگاه‌ها<span class="nt">&lt;/h2&gt;</span>
  <span class="nt">&lt;p&gt;</span>می‌توانید دیدگاه‌های این پست را در ماستودون و<span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"link"</span> <span class="na">href=</span><span class="s">"https://{{ page.mastodon.host }}/@{{ page.mastodon.username }}/{{ page.mastodon.id }}"</span> <span class="na">target=</span><span class="s">"_blank"</span> <span class="na">rel=</span><span class="s">"noopener noreferrer"</span><span class="nt">&gt;</span> اینجا <span class="nt">&lt;/a&gt;</span>ببینید. برای نوشتن دیدگاه خود روی لینک زیر کلیک کنید.<span class="nt">&lt;/p&gt;</span>
  <span class="nt">&lt;p&gt;&lt;a</span> <span class="na">class=</span><span class="s">"button"</span> <span class="na">href=</span><span class="s">"https://{{ page.mastodon.host }}/@{{ page.mastodon.username }}/{{ page.mastodon.id }}"</span> <span class="na">target=</span><span class="s">"_blank"</span> <span class="na">rel=</span><span class="s">"noopener noreferrer"</span><span class="nt">&gt;</span>نوشتن دیدگاه‌<span class="nt">&lt;/a&gt;&lt;/p&gt;</span>
  <span class="nt">&lt;p&gt;&lt;/p&gt;</span>
  <span class="nt">&lt;p</span> <span class="na">id=</span><span class="s">"mastodon-comments-list"</span><span class="nt">&gt;&lt;a</span> <span class="na">id=</span><span class="s">"load-comment"</span> <span class="na">class=</span><span class="s">"button"</span><span class="nt">&gt;</span>دیدن دیدگاه‌ها<span class="nt">&lt;/a&gt;&lt;/p&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"comments-wrapper"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;noscript&gt;&lt;p&gt;</span>برای این بخش می‌باید جاوا اسکریپت را فعال کنید، یا <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"https://{{ page.mastodon.host }}/@{{ page.mastodon.username }}/{{ page.mastodon.id }}"</span> <span class="na">target=</span><span class="s">"_blank"</span> <span class="na">rel=</span><span class="s">"noopener noreferrer"</span><span class="nt">&gt;</span>پست اصلی<span class="nt">&lt;/a&gt;</span> را در ماستودون ببینید<span class="nt">&lt;/p&gt;&lt;/noscript&gt;</span>
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"/assets/js/purify.min.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
  <span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">&gt;</span>
    <span class="kd">function</span> <span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">unsafe</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="nx">unsafe</span>
        <span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/&amp;/g</span><span class="p">,</span> <span class="dl">"</span><span class="s2">&amp;amp;</span><span class="dl">"</span><span class="p">)</span>
        <span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/&lt;/g</span><span class="p">,</span> <span class="dl">"</span><span class="s2">&amp;lt;</span><span class="dl">"</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/&gt;/g</span><span class="p">,</span> <span class="dl">"</span><span class="s2">&amp;gt;</span><span class="dl">"</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/"/g</span><span class="p">,</span> <span class="dl">"</span><span class="s2">&amp;quot;</span><span class="dl">"</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/'/g</span><span class="p">,</span> <span class="dl">"</span><span class="s2">&amp;#039;</span><span class="dl">"</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kd">function</span> <span class="nf">emojify</span><span class="p">(</span><span class="nx">input</span><span class="p">,</span> <span class="nx">emojis</span><span class="p">)</span> <span class="p">{</span>
      <span class="kd">let</span> <span class="nx">output</span> <span class="o">=</span> <span class="nx">input</span><span class="p">;</span>

      <span class="nx">emojis</span><span class="p">.</span><span class="nf">forEach</span><span class="p">(</span><span class="nx">emoji</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="kd">let</span> <span class="nx">picture</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">"</span><span class="s2">picture</span><span class="dl">"</span><span class="p">);</span>

        <span class="kd">let</span> <span class="nx">source</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">"</span><span class="s2">source</span><span class="dl">"</span><span class="p">);</span>
        <span class="nx">source</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">srcset</span><span class="dl">"</span><span class="p">,</span> <span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">emoji</span><span class="p">.</span><span class="nx">url</span><span class="p">));</span>
        <span class="nx">source</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">media</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">(prefers-reduced-motion: no-preference)</span><span class="dl">"</span><span class="p">);</span>

        <span class="kd">let</span> <span class="nx">img</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nf">createElement</span><span class="p">(</span><span class="dl">"</span><span class="s2">img</span><span class="dl">"</span><span class="p">);</span>
        <span class="nx">img</span><span class="p">.</span><span class="nx">className</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">emoji</span><span class="dl">"</span><span class="p">;</span>
        <span class="nx">img</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">src</span><span class="dl">"</span><span class="p">,</span> <span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">emoji</span><span class="p">.</span><span class="nx">static_url</span><span class="p">));</span>
        <span class="nx">img</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">alt</span><span class="dl">"</span><span class="p">,</span> <span class="s2">`:</span><span class="p">${</span> <span class="nx">emoji</span><span class="p">.</span><span class="nx">shortcode</span> <span class="p">}</span><span class="s2">:`</span><span class="p">);</span>
        <span class="nx">img</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">title</span><span class="dl">"</span><span class="p">,</span> <span class="s2">`:</span><span class="p">${</span> <span class="nx">emoji</span><span class="p">.</span><span class="nx">shortcode</span> <span class="p">}</span><span class="s2">:`</span><span class="p">);</span>
        <span class="nx">img</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">width</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">20</span><span class="dl">"</span><span class="p">);</span>
        <span class="nx">img</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">height</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">20</span><span class="dl">"</span><span class="p">);</span>

        <span class="nx">picture</span><span class="p">.</span><span class="nf">appendChild</span><span class="p">(</span><span class="nx">source</span><span class="p">);</span>
        <span class="nx">picture</span><span class="p">.</span><span class="nf">appendChild</span><span class="p">(</span><span class="nx">img</span><span class="p">);</span>

        <span class="nx">output</span> <span class="o">=</span> <span class="nx">output</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="s2">`:</span><span class="p">${</span> <span class="nx">emoji</span><span class="p">.</span><span class="nx">shortcode</span> <span class="p">}</span><span class="s2">:`</span><span class="p">,</span> <span class="nx">picture</span><span class="p">.</span><span class="nx">outerHTML</span><span class="p">);</span>
      <span class="p">});</span>

      <span class="k">return</span> <span class="nx">output</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kd">function</span> <span class="nf">loadcomments</span><span class="p">()</span> <span class="p">{</span>
      <span class="nb">document</span><span class="p">.</span><span class="nf">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">load-comment</span><span class="dl">"</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">دریافت دیدگاه‌ها</span><span class="dl">"</span><span class="p">;</span>
      <span class="nf">fetch</span><span class="p">(</span><span class="dl">'</span><span class="s1">https://{{ page.mastodon.host }}/api/v1/statuses/{{ page.mastodon.id }}/context</span><span class="dl">'</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">then</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">return</span> <span class="nx">response</span><span class="p">.</span><span class="nf">json</span><span class="p">();</span>
        <span class="p">})</span>
        <span class="p">.</span><span class="nf">then</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
          <span class="kd">let</span> <span class="nx">descendants</span> <span class="o">=</span> <span class="nx">data</span><span class="p">[</span><span class="dl">'</span><span class="s1">descendants</span><span class="dl">'</span><span class="p">];</span>
          <span class="k">if</span><span class="p">(</span>
            <span class="nx">descendants</span> <span class="o">&amp;&amp;</span>
            <span class="nb">Array</span><span class="p">.</span><span class="nf">isArray</span><span class="p">(</span><span class="nx">descendants</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
            <span class="nx">descendants</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span>
          <span class="p">)</span> <span class="p">{</span>
            <span class="nb">document</span><span class="p">.</span><span class="nf">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">mastodon-comments-list</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="dl">""</span><span class="p">;</span>
            <span class="nx">descendants</span><span class="p">.</span><span class="nf">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">reply</span><span class="p">)</span> <span class="p">{</span>
              <span class="k">if</span><span class="p">(</span> <span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="p">)</span> <span class="p">{</span>
                <span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span> <span class="o">=</span> <span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span><span class="p">);</span>
                <span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span> <span class="o">=</span> <span class="nf">emojify</span><span class="p">(</span><span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span><span class="p">,</span> <span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">emojis</span><span class="p">);</span>
              <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span> <span class="o">=</span> <span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">username</span><span class="p">;</span>
              <span class="p">};</span>

              <span class="nx">reply</span><span class="p">.</span><span class="nx">content</span> <span class="o">=</span> <span class="nf">emojify</span><span class="p">(</span><span class="nx">reply</span><span class="p">.</span><span class="nx">content</span><span class="p">,</span> <span class="nx">reply</span><span class="p">.</span><span class="nx">emojis</span><span class="p">);</span>

              <span class="nx">reply</span><span class="p">.</span><span class="nx">created_at</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Date</span><span class="p">(</span> <span class="nx">reply</span><span class="p">.</span><span class="nx">created_at</span> <span class="p">).</span><span class="nf">toLocaleString</span><span class="p">(</span><span class="dl">'</span><span class="s1">fa-IR</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span>
                <span class="na">dateStyle</span><span class="p">:</span> <span class="dl">"</span><span class="s2">long</span><span class="dl">"</span><span class="p">,</span>
                <span class="na">timeStyle</span><span class="p">:</span> <span class="dl">"</span><span class="s2">short</span><span class="dl">"</span><span class="p">,</span>
              <span class="p">});</span>

              <span class="kd">let</span> <span class="nx">instance</span> <span class="o">=</span> <span class="dl">""</span><span class="p">;</span>
              <span class="k">if</span><span class="p">(</span> <span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">acct</span><span class="p">.</span><span class="nf">includes</span><span class="p">(</span><span class="dl">"</span><span class="s2">@</span><span class="dl">"</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span>
                <span class="nx">instance</span> <span class="o">=</span> <span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">acct</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="dl">"</span><span class="s2">@</span><span class="dl">"</span><span class="p">)[</span><span class="mi">1</span><span class="p">];</span>
              <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="nx">instance</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">{{ page.mastodon.host }}</span><span class="dl">"</span><span class="p">;</span>
              <span class="p">}</span>

              <span class="nx">mastodonComment</span> <span class="o">=</span>
                <span class="s2">`&lt;div class="mastodon-comment"&gt;
                &lt;div class="avatar"&gt;
                &lt;img src="</span><span class="p">${</span><span class="nf">escapeHtml</span><span class="p">(</span><span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">avatar_static</span><span class="p">)}</span><span class="s2">" height=60 width=60 alt=""&gt;
                &lt;/div&gt;
                &lt;div class="content"&gt;
                &lt;div class="author" title="profile: @</span><span class="p">${</span> <span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">username</span> <span class="p">}</span><span class="s2">@</span><span class="p">${</span> <span class="nx">instance</span> <span class="p">}</span><span class="s2">"&gt;
                &lt;a href="</span><span class="p">${</span><span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">url</span><span class="p">}</span><span class="s2">" target="_blank" rel="external nofollow"&gt;
                &lt;span&gt;</span><span class="p">${</span><span class="nx">reply</span><span class="p">.</span><span class="nx">account</span><span class="p">.</span><span class="nx">display_name</span><span class="p">}</span><span class="s2">&lt;/span&gt;
                &lt;span class="instance"&gt;</span><span class="p">${</span><span class="nx">instance</span><span class="p">}</span><span class="s2">&lt;/span&gt;
                &lt;/a&gt;
                &lt;/div&gt;
                &lt;div title="دیدن دیدگاه در </span><span class="p">${</span> <span class="nx">instance</span> <span class="p">}</span><span class="s2">"&gt;
                &lt;a class="date" href="</span><span class="p">${</span><span class="nx">reply</span><span class="p">.</span><span class="nx">uri</span><span class="p">}</span><span class="s2">" target="_blank" rel="external nofollow"&gt;
                </span><span class="p">${</span><span class="nx">reply</span><span class="p">.</span><span class="nx">created_at</span><span class="p">}</span><span class="s2">
                &lt;/a&gt;
                &lt;/div&gt;
                &lt;div class="mastodon-comment-content"&gt;</span><span class="p">${</span><span class="nx">reply</span><span class="p">.</span><span class="nx">content</span><span class="p">}</span><span class="s2">&lt;/div&gt; 
                &lt;/div&gt;
                &lt;/div&gt;`</span><span class="p">;</span>
              <span class="nb">document</span><span class="p">.</span><span class="nf">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">mastodon-comments-list</span><span class="dl">'</span><span class="p">).</span><span class="nf">appendChild</span><span class="p">(</span><span class="nx">DOMPurify</span><span class="p">.</span><span class="nf">sanitize</span><span class="p">(</span><span class="nx">mastodonComment</span><span class="p">,</span> <span class="p">{</span><span class="dl">'</span><span class="s1">RETURN_DOM_FRAGMENT</span><span class="dl">'</span><span class="p">:</span> <span class="kc">true</span><span class="p">}));</span>
            <span class="p">});</span>
          <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="nb">document</span><span class="p">.</span><span class="nf">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">mastodon-comments-list</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">&lt;p&gt;بدون دیدگاه&lt;/p&gt;</span><span class="dl">"</span><span class="p">;</span>
          <span class="p">}</span>
        <span class="p">});</span>
    <span class="p">}</span>
    <span class="nb">document</span><span class="p">.</span><span class="nf">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">load-comment</span><span class="dl">"</span><span class="p">).</span><span class="nf">addEventListener</span><span class="p">(</span><span class="dl">"</span><span class="s2">click</span><span class="dl">"</span><span class="p">,</span> <span class="nx">loadcomments</span><span class="p">);</span>
  <span class="nt">&lt;/script&gt;</span>
<span class="nt">&lt;/div&gt;</span></code></pre></figure>

</div>

<p>سپس در <a href="https://raw.githubusercontent.com/mhdzli/zmim.ir/master/src/_layouts/post.html" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">layout</code> مربوط به پست‌ها</a> یک شرط افزودم تا هر زمان که در <a href="https://jekyllrb.com/docs/front-matter/" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">frontmatter</code></a> پست ‍<code class="language-plaintext highlighter-rouge">mastodon</code> وجود داشت، بخش دیدگاه‌ها افزوده شود:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-liquid" data-lang="liquid"><span class="cp">{%</span><span class="w"> </span><span class="nt">if</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">mastodon</span><span class="w"> </span><span class="cp">%}</span>
  <span class="cp">{%</span><span class="w"> </span><span class="nt">include</span><span class="w"> </span>mastodon.html<span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">endif</span><span class="w"> </span><span class="cp">%}</span></code></pre></figure>

</div>

<p>و در <code class="language-plaintext highlighter-rouge">frontmatter</code> باید <code class="language-plaintext highlighter-rouge">mastodon</code> با این ساختار افزوده شود:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">mastodon</span><span class="pi">:</span>
  <span class="na">host</span><span class="pi">:</span> <span class="s">mas.to</span>
  <span class="na">username</span><span class="pi">:</span> <span class="s">mz</span>
  <span class="na">id</span><span class="pi">:</span> <span class="s">105582586560918183</span></code></pre></figure>

</div>

<p>که باید این موارد در آن مشخص گردد:</p>

<ul>
  <li>host: آدرس سرور ماستودون</li>
  <li>username: نام کاربری در ماستودون</li>
  <li>id: شماره یکتای بوق مربوط به پست</li>
</ul>

<p>در پایان هم برای نمایش بهتر دیدگاه‌ها از <a href="https://github.com/mhdzli/zmim.ir/commit/78e351e5f809ead9eb4a77021026c5364c6e2081" target="_blank" rel="noopener noreferrer">این چند خط <code class="language-plaintext highlighter-rouge">CSS</code></a> استفاده کردم.</p>

<p>اینجا می‌توانید نتیجه نهایی را آزمایش کنید:</p>]]></content><author><name>محمد زینلی</name><email>m@zmim.ir</email></author><category term="foss" /><category term="mastodon" /><category term="fediverse" /><summary type="html"><![CDATA[افزودن بخش دیدگاه‌ها با مسنادون (یک شبکه اجتماعی آزاد و گسترده).]]></summary></entry><entry xml:lang="fa"><title type="html">کاهش نویز با استفاده از sox</title><link href="https://zmim.ir/sox/" rel="alternate" type="text/html" title="کاهش نویز با استفاده از sox" /><published>2020-12-28T12:20:00+03:30</published><updated>2020-12-28T12:20:00+03:30</updated><id>https://zmim.ir/sox</id><content type="html" xml:base="https://zmim.ir/sox/"><![CDATA[<h1 id="sox">SoX</h1>

<p><a href="http://sox.sourceforge.net/" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">SoX</code></a> ابزاری برای ویرایش فایل‌های صوتی است که روی گنو/لینوکس، مک و ویندوز در دسترس است. روی اندروید هم می‌توانید در  محیط <a href="https://termux.com/" target="_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">termux</code></a> از آن استفاده کنید.</p>

<p>در این پست نخست با استفاده از <code class="language-plaintext highlighter-rouge">SoX</code> نویز یک فایل صوتی را کاهش می‌دهیم و سپس یک اسکریپت برای کاهش نویز فایل‌های صوتی و تصویری، با استفاده از <code class="language-plaintext highlighter-rouge">Sox</code> و <code class="language-plaintext highlighter-rouge">FFmpeg</code> را بررسی می‌کنیم.</p>

<h1 id="کاهش-نویز-با-استفاده-از-sox">کاهش نویز با استفاده از <code class="language-plaintext highlighter-rouge">SoX</code></h1>

<p>اگر یک فایل صدا به نام <code class="language-plaintext highlighter-rouge">audio.wav</code> داشته باشیم که در ابتدای آن بخش کوچکی سکوت یا درست‌تر بنویسم «صدای محیط» ضبط شده باشد، میتوانیم آن بخش را با استفاده از <code class="language-plaintext highlighter-rouge">SoX</code> جدا کنیم:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="c"># sox in.ext out.ext trim {start: s.ms} {duration: s.ms}</span>
sox audio.wav noise.wav trim 0 0.900</code></pre></figure>

</div>

<p>در اینجا <code class="language-plaintext highlighter-rouge">SoX</code> فایل <code class="language-plaintext highlighter-rouge">audio.wav</code> را به عنوان ورودی دریافت و تا ثانیه <code class="language-plaintext highlighter-rouge">0.9</code> آن را جدا کرده و با نام <code class="language-plaintext highlighter-rouge">noise.wave</code> ذخیره می‌کند.</p>

<p>اکنون با استفاده از این بخش یک فایل از ویژگی‌های نویز محیط به نام <code class="language-plaintext highlighter-rouge">noise.prof</code> می‌سازیم:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">sox noise.wav <span class="nt">-n</span> noiseprof noise.prof</code></pre></figure>

</div>

<p>در پایان کاهش نویز را بر اساس پروفایل ساخته شده انجام می‌دهیم. برای تنظیم اندازه کاهش نویز از یک ضریب استفاده می شود که بر اساس <a href="http://www.zoharbabin.com/how-to-do-noise-reduction-using-ffmpeg-and-sox/" target="_blank" rel="noopener noreferrer">این منبع</a> عددی بین <code class="language-plaintext highlighter-rouge">0.2</code> تا <code class="language-plaintext highlighter-rouge">0.3</code> بهترین خروجی‌ها را خواهد داشت:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">sox audio.wav audio-clean.wav noisered noise.prof 0.21</code></pre></figure>

</div>

<h1 id="اسکریپتی-برای-کاهش-نویز-فایل‌های-صوتی-و-تصویری-با-ffmpeg-و-sox">اسکریپتی برای کاهش نویز فایل‌های صوتی و تصویری با <code class="language-plaintext highlighter-rouge">FFmpeg</code> و <code class="language-plaintext highlighter-rouge">SoX</code></h1>

<p>این اسکریپت دو مسیر، -نخست فایل ورودی و سپس فایل خروجی- را می‌گیرد (<code class="language-plaintext highlighter-rouge">$1</code> و <code class="language-plaintext highlighter-rouge">$2</code>). در صورتی که فایل ورودی تصویری باشد با استفاده از <code class="language-plaintext highlighter-rouge">FFmpeg</code> صدای آن را جدا می‌کند. سپس مشابه آنچه که در بخش پیش دیدیم نویز فایل صوتی را کاهش می‌دهد و در  پایان اگر ورودی فایل تصویری باشد دوباره با استفاده از <code class="language-plaintext highlighter-rouge">FFmpeg</code> صدا و تصویر را به هم می‌چسباند.</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="c">#!/usr/bin/sh</span>

usage <span class="o">()</span>
<span class="o">{</span>
    <span class="nb">printf</span> <span class="s2">"Usage : noisereduce &lt;input video file&gt; &lt;output video file&gt;</span><span class="se">\n</span><span class="s2">"</span>
    <span class="nb">exit</span>
<span class="o">}</span>

<span class="c"># Tests for requirements</span>
ffmpeg <span class="nt">-version</span> <span class="o">&gt;</span>/dev/null <span class="o">||</span> <span class="o">{</span> <span class="nb">echo</span> <span class="o">&gt;</span>&amp;2 <span class="s2">"We require 'ffmpeg' but it's not installed. Install it by 'sudo apt-get install ffmpeg' Aborting."</span><span class="p">;</span> <span class="nb">exit </span>1<span class="p">;</span> <span class="o">}</span>
sox <span class="nt">--version</span> <span class="o">&gt;</span>/dev/null <span class="o">||</span> <span class="o">{</span> <span class="nb">echo</span> <span class="o">&gt;</span>&amp;2 <span class="s2">"We require 'sox' but it's not installed. Install it by 'sudo apt-get install sox' Aborting."</span><span class="p">;</span> <span class="nb">exit </span>1<span class="p">;</span> <span class="o">}</span>

<span class="k">if</span> <span class="o">[</span> <span class="s2">"$#"</span> <span class="nt">-ne</span> 2 <span class="o">]</span>
<span class="k">then
  </span>usage
<span class="k">fi

if</span> <span class="o">[</span> <span class="o">!</span> <span class="nt">-e</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="o">]</span>
<span class="k">then
    </span><span class="nb">printf</span> <span class="s2">"File not found: %s</span><span class="se">\n</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>
    <span class="nb">exit
</span><span class="k">fi

if</span> <span class="o">[</span> <span class="nt">-e</span> <span class="s2">"</span><span class="nv">$2</span><span class="s2">"</span> <span class="o">]</span>
<span class="k">then
    </span><span class="nb">printf</span> <span class="s2">"File %s already exists, overwrite? [y/N]</span><span class="se">\n</span><span class="s2">: "</span> <span class="s2">"</span><span class="nv">$2</span><span class="s2">"</span>
    <span class="nb">read</span> <span class="nt">-r</span> yn
    <span class="k">case</span> <span class="nv">$yn</span> <span class="k">in</span>
        <span class="o">[</span>Yy]<span class="k">*</span> <span class="p">)</span> <span class="p">;;</span>
        <span class="k">*</span> <span class="p">)</span> <span class="nb">exit</span><span class="p">;;</span>
    <span class="k">esac</span>
<span class="k">fi

</span><span class="nv">inBasename</span><span class="o">=</span><span class="si">$(</span><span class="nb">basename</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span><span class="si">)</span>
<span class="nv">inExt</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">inBasename</span><span class="p">##*.</span><span class="k">}</span><span class="s2">"</span>

<span class="nv">isVideoStr</span><span class="o">=</span><span class="si">$(</span>ffprobe <span class="nt">-v</span> warning <span class="nt">-show_streams</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> | <span class="nb">grep </span><span class="nv">codec_type</span><span class="o">=</span>video<span class="si">)</span>
<span class="k">if</span> <span class="o">[</span> <span class="nt">-n</span> <span class="s2">"</span><span class="nv">$isVideoStr</span><span class="s2">"</span> <span class="o">]</span>
<span class="k">then
    </span><span class="nv">isVideo</span><span class="o">=</span>1
    <span class="nb">printf</span> <span class="s2">"Detected %s as a video file</span><span class="se">\n</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$inBasename</span><span class="s2">"</span>
<span class="k">else
    </span><span class="nv">isVideo</span><span class="o">=</span>0
    <span class="nb">printf</span> <span class="s2">"Detected %s as an audio file</span><span class="se">\n</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$inBasename</span><span class="s2">"</span>
<span class="k">fi

</span><span class="nb">printf</span> <span class="s2">"Sample noise start time [00:00:00]: "</span>
<span class="nb">read</span> <span class="nt">-r</span> sampleStart
<span class="k">if</span> <span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$sampleStart</span><span class="s2">"</span> <span class="o">]</span> <span class="p">;</span> <span class="k">then </span><span class="nv">sampleStart</span><span class="o">=</span><span class="s2">"00:00:00"</span><span class="p">;</span> <span class="k">fi
</span><span class="nb">printf</span> <span class="s2">"Sample noise end time [00:00:00.900]: "</span>
<span class="nb">read</span> <span class="nt">-r</span> sampleEnd
<span class="k">if</span> <span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$sampleEnd</span><span class="s2">"</span> <span class="o">]</span> <span class="p">;</span> <span class="k">then </span><span class="nv">sampleEnd</span><span class="o">=</span><span class="s2">"00:00:00.900"</span><span class="p">;</span> <span class="k">fi
</span><span class="nb">printf</span> <span class="s2">"Noise reduction amount [0.21]: "</span> 
<span class="nb">read</span> <span class="nt">-r</span> sensitivity
<span class="k">if</span> <span class="o">[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$sensitivity</span><span class="s2">"</span> <span class="o">]</span> <span class="p">;</span> <span class="k">then </span><span class="nv">sensitivity</span><span class="o">=</span><span class="s2">"0.21"</span><span class="p">;</span> <span class="k">fi


</span><span class="nv">tmpVidFile</span><span class="o">=</span><span class="s2">"/tmp/noiseclean_tmpvid.</span><span class="nv">$inExt</span><span class="s2">"</span>
<span class="nv">tmpAudFile</span><span class="o">=</span><span class="s2">"/tmp/noiseclean_tmpaud.wav"</span>
<span class="nv">noiseAudFile</span><span class="o">=</span><span class="s2">"/tmp/noiseclean_noiseaud.wav"</span>
<span class="nv">noiseProfFile</span><span class="o">=</span><span class="s2">"/tmp/noiseclean_noise.prof"</span>
<span class="nv">tmpAudCleanFile</span><span class="o">=</span><span class="s2">"/tmp/noiseclean_tmpaud-clean.wav"</span>

<span class="nb">printf</span> <span class="s2">"Cleaning noise on %s...</span><span class="se">\n</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>

<span class="k">if</span> <span class="o">[</span> <span class="nv">$isVideo</span> <span class="nt">-eq</span> <span class="s2">"1"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span>ffmpeg <span class="nt">-v</span> warning <span class="nt">-y</span> <span class="nt">-i</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="nt">-qscale</span>:v 0 <span class="nt">-vcodec</span> copy <span class="nt">-an</span> <span class="s2">"</span><span class="nv">$tmpVidFile</span><span class="s2">"</span>
    ffmpeg <span class="nt">-v</span> warning <span class="nt">-y</span> <span class="nt">-i</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="nt">-qscale</span>:a 0 <span class="s2">"</span><span class="nv">$tmpAudFile</span><span class="s2">"</span>
<span class="k">else
    </span><span class="nb">cp</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$tmpAudFile</span><span class="s2">"</span>
<span class="k">fi
</span>ffmpeg <span class="nt">-v</span> warning <span class="nt">-y</span> <span class="nt">-i</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="nt">-vn</span> <span class="nt">-ss</span> <span class="s2">"</span><span class="nv">$sampleStart</span><span class="s2">"</span> <span class="nt">-t</span> <span class="s2">"</span><span class="nv">$sampleEnd</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$noiseAudFile</span><span class="s2">"</span>
sox <span class="s2">"</span><span class="nv">$noiseAudFile</span><span class="s2">"</span> <span class="nt">-n</span> noiseprof <span class="s2">"</span><span class="nv">$noiseProfFile</span><span class="s2">"</span>
sox <span class="s2">"</span><span class="nv">$tmpAudFile</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$tmpAudCleanFile</span><span class="s2">"</span> noisered <span class="s2">"</span><span class="nv">$noiseProfFile</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$sensitivity</span><span class="s2">"</span>
<span class="k">if</span> <span class="o">[</span> <span class="nv">$isVideo</span> <span class="nt">-eq</span> <span class="s2">"1"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span>ffmpeg <span class="nt">-v</span> warning <span class="nt">-y</span> <span class="nt">-i</span> <span class="s2">"</span><span class="nv">$tmpAudCleanFile</span><span class="s2">"</span> <span class="nt">-i</span> <span class="s2">"</span><span class="nv">$tmpVidFile</span><span class="s2">"</span> <span class="nt">-vcodec</span> copy <span class="nt">-qscale</span>:v 0 <span class="nt">-qscale</span>:a 0 <span class="s2">"</span><span class="nv">$2</span><span class="s2">"</span>
<span class="k">else
    </span><span class="nb">cp</span> <span class="s2">"</span><span class="nv">$tmpAudCleanFile</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$2</span><span class="s2">"</span>
<span class="k">fi

</span><span class="nb">printf</span> <span class="s2">"Done"</span></code></pre></figure>

</div>

<h1 id="لینک‌های-بیشتر">لینک‌های بیشتر</h1>

<ul>
  <li><a href="https://sourceforge.net/p/sox/code/ci/master/tree/scripts/" target="_blank" rel="noopener noreferrer">چند مثال در ریپوزیتوری اصلی</a></li>
  <li><a href="https://github.com/madskjeldgaard/sox-tricks" target="_blank" rel="noopener noreferrer">SoX tricks</a></li>
  <li><a href="https://github.com/HiSunzhenliang/SoX" target="_blank" rel="noopener noreferrer">یک فورک روی گیتهاب</a></li>
  <li><a href="http://sox.sourceforge.net/Docs/Features" target="_blank" rel="noopener noreferrer">امکاناب و فرمت‌هایی که پشتیبانی می‌شوند</a></li>
  <li><a href="https://github.com/daizyu/sox-normalize-noise-reduction" target="_blank" rel="noopener noreferrer">نمونه یک کد ‪C#‬</a></li>
</ul>

<p>اگر هم که دیدن ویدیوی آموزشی برایتان آسانتر است یا می‌خواهید تفاوت فایل خروجی و ورودی را ببینید:</p>

<div class="video">
  <iframe sandbox="allow-same-origin allow-scripts allow-popups" src="https://peertube.linuxrocks.online/videos/embed/de166e78-c3c8-440f-8557-bea6e26d1f9f" frameborder="0" allowfullscreen=""></iframe>
</div>]]></content><author><name>محمد زینلی</name><email>m@zmim.ir</email></author><category term="unix/linux" /><category term="CLI" /><summary type="html"><![CDATA[SoX (Swiss Army knife of sound processing) ابزاری برای ویرایش صدا]]></summary></entry><entry xml:lang="fa"><title type="html">به روز رسانی افزونه ماهور.</title><link href="https://zmim.ir/mahoor-update/" rel="alternate" type="text/html" title="به روز رسانی افزونه ماهور." /><published>2020-11-03T08:10:47+03:30</published><updated>2020-11-03T08:10:47+03:30</updated><id>https://zmim.ir/mahoor-update</id><content type="html" xml:base="https://zmim.ir/mahoor-update/"><![CDATA[<p>در این پست تلاش می‌کنم به بهانه به روزرسانی افزونه <a href="https://addons.thunderbird.net/en-us/thunderbird/addon/mahour-iranian-date/" target="\_blank" rel="noopener noreferrer">ماهور</a> کمی درباره افزونه‌های فایرفاکس و چگونگی ساخت یک افزونه برای فایرفاکس بنویسم.</p>

<h1 id="افزونه‌های-فایرفاکس">افزونه‌های فایرفاکس</h1>

<p>تا پیش از نوامبر ۲۰۱۷ ابزارهای مختلفی برای ساخت یک افزونه فایرفاکس وجود داشت اما در نسخه‌های به روزتر برخی از آنها مانند ‫<code class="language-plaintext highlighter-rouge">overlay add-ons</code>‬، ‫<code class="language-plaintext highlighter-rouge">bootstrapped add-ons</code>‬، ‫<code class="language-plaintext highlighter-rouge">Add-on SDK</code>‬ و … دیگر پشتیبانی نمی‌شوند. افزونه‌های جدید باید با استفاده از <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions" target="\_blank" rel="noopener noreferrer">WebExtensions API</a>ها ساخته شوند. اگر یک افزونه <code class="language-plaintext highlighter-rouge">Legacy</code> دارید برای سازگاری آن با نسخه های به روز فایرفاکس و ساخت <code class="language-plaintext highlighter-rouge">WebExtension</code> می‌توانید از <a href="https://extensionworkshop.com/documentation/develop/porting-a-legacy-firefox-extension/" target="\_blank" rel="noopener noreferrer">این راهنمای موزیلا</a> استفاده کنید.</p>

<h2 id="ساختار-webextensionها">ساختار <code class="language-plaintext highlighter-rouge">WebExtension</code>ها</h2>

<p>هر <code class="language-plaintext highlighter-rouge">WebExtension</code> یک فایل <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">manifest.json</code></a> دارد که ساختار، منابع و ویژگی‌های آن را مشخص می‌کند. عکس زیر ساختار کلی فایل <code class="language-plaintext highlighter-rouge">manifest.jason</code> را در یک <code class="language-plaintext highlighter-rouge">WebExtension</code> نشان می دهد.</p>

<div style="text-align: center;">
    <img src="webextension-anatomy.png" style="max-width: 80%; margin: 10px;" alt="ساختار webextensionها" />
</div>

<p>نمونه فایل <code class="language-plaintext highlighter-rouge">manifest.json</code> افزونه ماهور:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-json" data-lang="json"><span class="p">{</span><span class="w">
  </span><span class="nl">"manifest_version"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w">
  </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Mahour"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Adds a new Iranian(Persian/Jalali/Khorshidi) date column to ThunderBird."</span><span class="p">,</span><span class="w">
  </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.1.2"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"homepage_url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://github.com/mhdzli/mahour"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"author"</span><span class="p">:</span><span class="w"> </span><span class="s2">"M.Zeinali"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"applications"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"gecko"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"mahour@zmim.ir"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"strict_min_version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"68.0a1"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"[experiment_apis](experiment_apis)"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"MahourDate"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"schema"</span><span class="p">:</span><span class="w"> </span><span class="s2">"api/schema.json"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"parent"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"scopes"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"addon_parent"</span><span class="p">],</span><span class="w">
        </span><span class="nl">"paths"</span><span class="p">:</span><span class="w"> </span><span class="p">[[</span><span class="s2">"MahourDate"</span><span class="p">]],</span><span class="w">
        </span><span class="nl">"script"</span><span class="p">:</span><span class="w"> </span><span class="s2">"api/experiments.js"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"background"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"background/background.js"</span><span class="p">]</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"browser_action"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"default_title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ماهور"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"default_popup"</span><span class="p">:</span><span class="w"> </span><span class="s2">"popup/popup.html"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"default_icon"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"48"</span><span class="p">:</span><span class="w"> </span><span class="s2">"assets/icons/icon48.png"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"options_ui"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"page"</span><span class="p">:</span><span class="w"> </span><span class="s2">"options/options.html"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"open_in_tab"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"icons"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"32"</span><span class="p">:</span><span class="w"> </span><span class="s2">"assets/icons/icon32.png"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"48"</span><span class="p">:</span><span class="w"> </span><span class="s2">"assets/icons/icon48.png"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"64"</span><span class="p">:</span><span class="w"> </span><span class="s2">"assets/icons/icon64.png"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"128"</span><span class="p">:</span><span class="w"> </span><span class="s2">"assets/icons/icon128.png"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"permissions"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"storage"</span><span class="p">]</span><span class="w">
</span><span class="p">}</span></code></pre></figure>

</div>

<p>این فایل دربردارنده کلیدهای زیر است:</p>

<ul>
  <li>کلیدهای اساسی که بایست حتما تعریف شوند:
    <ul>
      <li>ورژن مانیفست (<a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/manifest_version" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">manifest_version</code></a>)</li>
      <li>نام افزونه (<a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/name" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">name</code></a>)</li>
      <li>ورژن افزونه (<a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/version" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">version</code></a>)</li>
    </ul>
  </li>
  <li>کلیدهای انتخابی:
    <ul>
      <li>توضیحات برنامه (<a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/description" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">description</code></a>)</li>
      <li>آیکون‌ها (<a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/icons" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">icons</code></a>)</li>
      <li>وبگاه یا مخزن افزونه (<a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/homepage_url" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">homepage_url</code></a>)</li>
      <li>سازنده (<a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/author" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">author</code></a>)</li>
    </ul>
  </li>
  <li>تنظیمات ویژه مرورگر (<a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">browser_specific_settings</code></a> یا در اینجا <code class="language-plaintext highlighter-rouge">applications</code>). ویژگی‌های مرورگر برای اجرای افزونه <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/WebExtensions_and_the_Add-on_ID#When_do_you_need_an_add-on_ID" target="\_blank" rel="noopener noreferrer">چنانچه نیاز باشد</a> در این کلید مشخص می‌شوند:
    <ul>
      <li>حداقل ورژن موتور ساخت محتوای مرورگر (<code class="language-plaintext highlighter-rouge">gecko</code>: content rendering engine)</li>
      <li>شناسه افزونه برای موتور تولید محتوا (<code class="language-plaintext highlighter-rouge">gecko.id</code>)</li>
    </ul>
  </li>
  <li>اسکریپت پس زمینه (<a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#Background_scripts" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">Background scripts</code></a>): این اسکریپت در قالب یک صفحه ویژه به نام <code class="language-plaintext highlighter-rouge">background page</code> در پس زمینه اجرا می‌شود.</li>
  <li>اسکریپت‌های ساخت محتوا (<a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">Content scripts</code></a>) که کار اصلی را بر عهده دارند و خوراک بخش‌های گوناگون افزونه را تولید می‌کنند. افزونه ماهور به جای این کلید از <a href="https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/basics.html#webextensions-experiments" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">experiment_apis</code></a> بهره برده است. اسکریپت تولید محتوا درون <code class="language-plaintext highlighter-rouge">API</code> بارگذاری می‌شود.</li>
  <li>رابط برنامه‌نویسی آزمایشی نرم‌افزار (<a href="https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/basics.html?highlight=experiment_apis#webextensions-experiments" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">experiment_apis</code></a>): با این کلید می‌توان یک رابط برنامه نویسی تازه برای استفاده در افزونه ساخت.</li>
  <li>صفحه‌های پیش فرض که مانند یک صفحه وب معمولی می‌توانند از فایلهای <code class="language-plaintext highlighter-rouge">css</code> و <code class="language-plaintext highlighter-rouge">js</code> استفاده کنند:
    <ul>
      <li>نوار کناری (<a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/sidebar_action" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">Sidebars</code></a>)</li>
      <li>پنجره‌های بازشو (<code class="language-plaintext highlighter-rouge">popups</code>) ویژگی‌های مربوط به آن در کلید <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/page_action" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">browser_action || page_action</code></a> تعریف می‌شود.</li>
      <li>سامان‌دهی (<code class="language-plaintext highlighter-rouge">options</code>): ویژگی‌های مربوط به آن در کلید <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/options_ui" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">options_ui</code></a> تعریف می‌شود. این کلید در صفحه <code class="language-plaintext highlighter-rouge">Add-ons Manager</code> گزینه <code class="language-plaintext highlighter-rouge">Preferences</code> را برای افزونه نمایان می‌کند. با کلیک کردن روی آن، صفحه ساماندهی در این بخش بارگذاری شده و امکان تغییر ویژگی‌های افزونه را فراهم می‌کند. (ست کردن ویژگی <code class="language-plaintext highlighter-rouge">open_in_tab</code> صفحه جدیدی برای بارگذاری باز خواهد کرد.)</li>
    </ul>
  </li>
  <li>صفحه‌های افزونه (<a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/user_interface/Extension_pages" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">Extension pages</code></a>): هر افزونه می‌تواند جدا از صفحه‌های پیش فرض، دربردارنده صفحه‌های ویژه خودش نیز باشد که اینجا تعریف می‌شوند.</li>
  <li>منابع مورد نیاز تولید محتوا (<a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/web_accessible_resources" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">Web accessible resources</code></a>): چنانچه بخواهیم از فایل‌های ‫<code class="language-plaintext highlighter-rouge">HTML</code>‬، ‫<code class="language-plaintext highlighter-rouge">CSS</code>‬، ‫<code class="language-plaintext highlighter-rouge">JavaScript</code>‬ و … در تولید محتوای افزونه استفاده کنیم آنها را در اینجا مشخص می‌کنیم. (نمونه: چنانچه افزونه نیاز دارد که عکس‌هایی را در صفحه‌های وب نمایش دهد، آنها را در اینجا مسیردهی می‌کنیم تا به آنها دسترسی داشته باشیم.)</li>
  <li>مجوزها (<a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">permissions</code></a>): مجوزهای مورد نیاز برنامه با این کلید مشخص می‌شوند. برای مجوزهای اختیاری که نداشتن آنها جلوی اجرای برنامه را نمی‌گیرد از کلید <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">optional_permissions</code></a> استفاده می‌شود.</li>
</ul>

<h3 id="رابط-برنامه-نویسی-افزونه‌ها">رابط برنامه نویسی افزونه‌ها</h3>

<p>برای درک بهتر <code class="language-plaintext highlighter-rouge">API</code>های موزیلا و چگونگی استفاده از آنها <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions" target="\_blank" rel="noopener noreferrer">این راهنما</a> را بخوانید.</p>

<p>در زیر نمونه یک <code class="language-plaintext highlighter-rouge">API</code> تعریف شده در فایل <code class="language-plaintext highlighter-rouge">manifest.json</code> را مشاهده می‌کنید.</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-json" data-lang="json"><span class="p">{</span><span class="w">
  </span><span class="nl">"manifest_version"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w">
  </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Extension containing an experimental API"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"experiment_apis"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"apiname"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"schema"</span><span class="p">:</span><span class="w"> </span><span class="s2">"schema.json"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"parent"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"scopes"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"addon_parent"</span><span class="p">],</span><span class="w">
        </span><span class="nl">"paths"</span><span class="p">:</span><span class="w"> </span><span class="p">[[</span><span class="s2">"myapi"</span><span class="p">]],</span><span class="w">
        </span><span class="nl">"script"</span><span class="p">:</span><span class="w"> </span><span class="s2">"implementation.js"</span><span class="w">
      </span><span class="p">},</span><span class="w">

      </span><span class="nl">"child"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"scopes"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"addon_child"</span><span class="p">],</span><span class="w">
        </span><span class="nl">"paths"</span><span class="p">:</span><span class="w"> </span><span class="p">[[</span><span class="s2">"myapi"</span><span class="p">]],</span><span class="w">
        </span><span class="nl">"script"</span><span class="p">:</span><span class="w"> </span><span class="s2">"child-implementation.js"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">

</span><span class="p">}</span><span class="w">
</span><span class="p">}</span></code></pre></figure>


</div>

<p>در هر <code class="language-plaintext highlighter-rouge">API</code> یک یا چند فضای نام تعریف می‌شود، که اشیا آن را می‌توان در اسکریپت‌های افزونه فراخوانی کرد. برای هر <code class="language-plaintext highlighter-rouge">API</code> باید یک <code class="language-plaintext highlighter-rouge">schema</code> تعریف شود که ویژگی‌های <code class="language-plaintext highlighter-rouge">API</code> را مشخص می‌کند. کلید <code class="language-plaintext highlighter-rouge">schema</code> در فایل <code class="language-plaintext highlighter-rouge">manifest.json</code> درون مسیر اصلی افزونه یک مسیر نسبی برای فایل <code class="language-plaintext highlighter-rouge">schema</code> مشخص می‌کند.</p>

<p>ویژگی‌های اصلی پردازش سرپرست (<code class="language-plaintext highlighter-rouge">parent process</code>) و پردازشهای فرزند (<code class="language-plaintext highlighter-rouge">child processes</code>) با کلیدهای <code class="language-plaintext highlighter-rouge">parent</code> و <code class="language-plaintext highlighter-rouge">child</code> در <code class="language-plaintext highlighter-rouge">script </code>مسیردهی می‌شوند.</p>

<p>در حال حاضر تنها گزینه‌های مجاز کلید <code class="language-plaintext highlighter-rouge">scops</code> برای مشخص کردن محدوده دسترسی هر فضای نام <code class="language-plaintext highlighter-rouge">addon-child</code> و <code class="language-plaintext highlighter-rouge">addon-parent</code> هستند.</p>

<p>فایل <code class="language-plaintext highlighter-rouge">schema</code> برای افزونه ماهور:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-json" data-lang="json"><span class="p">[</span><span class="w">
  </span><span class="p">{</span><span class="w">
    </span><span class="nl">"namespace"</span><span class="p">:</span><span class="w"> </span><span class="s2">"MahourDate"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"functions"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
      </span><span class="p">{</span><span class="w">
        </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"addWindowListener"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"function"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Adds a listener 3pane windows"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"async"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
        </span><span class="nl">"parameters"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
          </span><span class="p">{</span><span class="w">
            </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hich"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"string"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hich"</span><span class="w">
          </span><span class="p">}</span><span class="w">
        </span><span class="p">]</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="p">{</span><span class="w">
        </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"changeSettings"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"function"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Handle Prefrences"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"async"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
        </span><span class="nl">"parameters"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
          </span><span class="p">{</span><span class="w">
            </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"newSettings"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"object"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"properties"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
              </span><span class="nl">"longMonth"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"boolean"</span><span class="w"> </span><span class="p">},</span><span class="w">
              </span><span class="nl">"showTime"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"boolean"</span><span class="w"> </span><span class="p">},</span><span class="w">
              </span><span class="nl">"weekDay"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"boolean"</span><span class="w"> </span><span class="p">},</span><span class="w">
              </span><span class="nl">"englishNumbers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"boolean"</span><span class="w"> </span><span class="p">}</span><span class="w">
            </span><span class="p">}</span><span class="w">
          </span><span class="p">}</span><span class="w">
        </span><span class="p">]</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">]</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">]</span></code></pre></figure>

</div>

<p>در این فایل برای فضای نام <code class="language-plaintext highlighter-rouge">MahourDate</code> دو تابع <code class="language-plaintext highlighter-rouge">addWindowListener</code> و <code class="language-plaintext highlighter-rouge">changeSettings</code> تعریف شده است. تابع نخست در زمان شروع برنامه یک <code class="language-plaintext highlighter-rouge">windowListener</code> برای کنترل نمایش ستون <code class="language-plaintext highlighter-rouge">تاریخ</code> به برنامه اضافه می‌کند. تابع دوم با عوض کردن تنظیمات برنامه ستون <code class="language-plaintext highlighter-rouge">تاریخ</code> را دوباره می‌سازد و نمایش می‌دهد.</p>

<blockquote>
  <p>توجه: فراخوانی این توابع در <code class="language-plaintext highlighter-rouge">background script</code> باید با یک متغیر همراه باشد. بنابراین هر چند <code class="language-plaintext highlighter-rouge">addWindowListener</code> نیازی به ورودی ندارد، برای آن یک متغیر به نام <code class="language-plaintext highlighter-rouge">hich</code> (هیچ😂) تعریف شده است.</p>
</blockquote>

<p>این توابع درون اسکریپت <code class="language-plaintext highlighter-rouge">api/experiments.js</code> تعریف شده‌اند، که در ویژگی <code class="language-plaintext highlighter-rouge">parent</code> رابط برنامه نویسی <code class="language-plaintext highlighter-rouge">MahourDate</code> در فایل <code class="language-plaintext highlighter-rouge">manifest.json</code> افزونه مسیردهی شده است.</p>

<p>فایل <code class="language-plaintext highlighter-rouge">experiment.js</code>:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// This Source Code Form is subject to the terms of the</span>
<span class="c1">// GNU General Public License, version 3.0.</span>

<span class="dl">"</span><span class="s2">use strict</span><span class="dl">"</span><span class="p">;</span>

<span class="kd">var</span> <span class="p">{</span> <span class="nx">Services</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">ChromeUtils</span><span class="p">.</span><span class="k">import</span><span class="p">(</span><span class="dl">"</span><span class="s2">resource://gre/modules/Services.jsm</span><span class="dl">"</span><span class="p">);</span>
<span class="kd">var</span> <span class="p">{</span> <span class="nx">ExtensionSupport</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">ChromeUtils</span><span class="p">.</span><span class="k">import</span><span class="p">(</span>
<span class="dl">"</span><span class="s2">resource:///modules/ExtensionSupport.jsm</span><span class="dl">"</span>
<span class="p">);</span>
<span class="kd">var</span> <span class="p">{</span> <span class="nx">ExtensionParent</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">ChromeUtils</span><span class="p">.</span><span class="k">import</span><span class="p">(</span>
<span class="dl">"</span><span class="s2">resource://gre/modules/ExtensionParent.jsm</span><span class="dl">"</span>
<span class="p">);</span>

<span class="kd">const</span> <span class="nx">EXTENSION_NAME</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">mahour@zmim.ir</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">extension</span> <span class="o">=</span> <span class="nx">ExtensionParent</span><span class="p">.</span><span class="nx">GlobalManager</span><span class="p">.</span><span class="nf">getExtension</span><span class="p">(</span><span class="nx">EXTENSION_NAME</span><span class="p">);</span>

<span class="c1">//customizeable options</span>
<span class="kd">var</span> <span class="nx">monthStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">long</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">timeStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">2-digit</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">weekDayStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">hidden</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">numbersStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">arabext</span><span class="dl">"</span><span class="p">;</span>

<span class="c1">// Implements the functions defined in the experiments section of schema.json.</span>
<span class="kd">var</span> <span class="nx">MahourDate</span> <span class="o">=</span> <span class="kd">class</span> <span class="nc">extends</span> <span class="nx">ExtensionCommon</span><span class="p">.</span><span class="nx">ExtensionAPI</span> <span class="p">{</span>
<span class="nf">onStartup</span><span class="p">()</span> <span class="p">{}</span>

<span class="nf">onShutdown</span><span class="p">(</span><span class="nx">isAppShutdown</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="nx">isAppShutdown</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="c1">// Looks like we got uninstalled. Maybe a new version will be installed now.</span>
<span class="c1">// Due to new versions not taking effect (https://bugzilla.mozilla.org/show_bug.cgi?id=1634348)</span>
<span class="c1">// we invalidate the startup cache. That's the same effect as starting with -purgecaches</span>
<span class="c1">// (or deleting the startupCache directory from the profile).</span>
<span class="nx">Services</span><span class="p">.</span><span class="nx">obs</span><span class="p">.</span><span class="nf">notifyObservers</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="dl">"</span><span class="s2">startupcache-invalidate</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>

<span class="nf">getAPI</span><span class="p">(</span><span class="nx">context</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">context</span><span class="p">.</span><span class="nf">callOnClose</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="k">return</span> <span class="p">{</span>
<span class="na">MahourDate</span><span class="p">:</span> <span class="p">{</span>
<span class="nf">addWindowListener</span><span class="p">(</span><span class="nx">hich</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Adds a listener to detect new windows.</span>
<span class="nx">ExtensionSupport</span><span class="p">.</span><span class="nf">registerWindowListener</span><span class="p">(</span><span class="nx">EXTENSION_NAME</span><span class="p">,</span> <span class="p">{</span>
<span class="na">chromeURLs</span><span class="p">:</span> <span class="p">[</span>
<span class="dl">"</span><span class="s2">chrome://messenger/content/messenger.xul</span><span class="dl">"</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">chrome://messenger/content/messenger.xhtml</span><span class="dl">"</span><span class="p">,</span>
<span class="p">],</span>
<span class="na">onLoadWindow</span><span class="p">:</span> <span class="nx">paint</span><span class="p">,</span>
<span class="na">onUnloadWindow</span><span class="p">:</span> <span class="nx">unpaint</span><span class="p">,</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="nf">changeSettings</span><span class="p">(</span><span class="nx">newSettings</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="nx">newSettings</span><span class="p">.</span><span class="nx">longMonth</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">monthStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">long</span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">monthStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">2-digit</span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if </span><span class="p">(</span><span class="nx">newSettings</span><span class="p">.</span><span class="nx">showTime</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">timeStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">2-digit</span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">timeStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">hidden</span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if </span><span class="p">(</span><span class="nx">newSettings</span><span class="p">.</span><span class="nx">weekDay</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">weekDayStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">long</span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">weekDayStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">hidden</span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if </span><span class="p">(</span><span class="nx">newSettings</span><span class="p">.</span><span class="nx">englishNumbers</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">numbersStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">latn</span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">numbersStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">arabext</span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">win</span> <span class="k">of</span> <span class="nx">Services</span><span class="p">.</span><span class="nx">wm</span><span class="p">.</span><span class="nf">getEnumerator</span><span class="p">(</span><span class="dl">"</span><span class="s2">mail:3pane</span><span class="dl">"</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">win</span><span class="p">.</span><span class="nx">MahourDate</span><span class="p">.</span><span class="nx">MahourDateHeaderView</span><span class="p">.</span><span class="nf">destroy</span><span class="p">();</span>
<span class="nx">win</span><span class="p">.</span><span class="nx">MahourDate</span><span class="p">.</span><span class="nx">MahourDateHeaderView</span><span class="p">.</span><span class="nf">init</span><span class="p">(</span><span class="nx">win</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="p">},</span>
<span class="p">};</span>
<span class="p">}</span>

<span class="nf">close</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">ExtensionSupport</span><span class="p">.</span><span class="nf">unregisterWindowListener</span><span class="p">(</span><span class="nx">EXTENSION_NAME</span><span class="p">);</span>
<span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">win</span> <span class="k">of</span> <span class="nx">Services</span><span class="p">.</span><span class="nx">wm</span><span class="p">.</span><span class="nf">getEnumerator</span><span class="p">(</span><span class="dl">"</span><span class="s2">mail:3pane</span><span class="dl">"</span><span class="p">))</span> <span class="p">{</span>
<span class="nf">unpaint</span><span class="p">(</span><span class="nx">win</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">};</span>

<span class="kd">function</span> <span class="nf">paint</span><span class="p">(</span><span class="nx">win</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">win</span><span class="p">.</span><span class="nx">MahourDate</span> <span class="o">=</span> <span class="p">{};</span>
<span class="nx">Services</span><span class="p">.</span><span class="nx">scriptloader</span><span class="p">.</span><span class="nf">loadSubScript</span><span class="p">(</span>
<span class="nx">extension</span><span class="p">.</span><span class="nf">getURL</span><span class="p">(</span><span class="dl">"</span><span class="s2">content/customcol.js</span><span class="dl">"</span><span class="p">),</span>
<span class="nx">win</span><span class="p">.</span><span class="nx">MahourDate</span>
<span class="p">);</span>
<span class="nx">win</span><span class="p">.</span><span class="nx">MahourDate</span><span class="p">.</span><span class="nx">MahourDateHeaderView</span><span class="p">.</span><span class="nf">init</span><span class="p">(</span><span class="nx">win</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nf">unpaint</span><span class="p">(</span><span class="nx">win</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">win</span><span class="p">.</span><span class="nx">MahourDate</span><span class="p">.</span><span class="nx">MahourDateHeaderView</span><span class="p">.</span><span class="nf">destroy</span><span class="p">();</span>
<span class="k">delete</span> <span class="nx">win</span><span class="p">.</span><span class="nx">MahourDate</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>


</div>

<p>برای اینکه امکان فراخوانی توابع <code class="language-plaintext highlighter-rouge">addWindowListener</code> و <code class="language-plaintext highlighter-rouge">changeSettings</code> وجود داشته باشد، آنها را با الگوی مشخص شده در <a href="https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/functions.html" target="\_blank" rel="noopener noreferrer">راهنمای موزیلا</a> و درون <code class="language-plaintext highlighter-rouge">getAPI(context)</code> تعریف کرده‌ایم.</p>

<p>تابع <code class="language-plaintext highlighter-rouge">addWindowListener</code> با eventهای <code class="language-plaintext highlighter-rouge">onLoadWindow</code> و <code class="language-plaintext highlighter-rouge">onUnloadWindow</code> به ترتیب توابع <code class="language-plaintext highlighter-rouge">paint</code> و <code class="language-plaintext highlighter-rouge">unpaint</code> را فراخوانی می‌کند. تابع <code class="language-plaintext highlighter-rouge">paint</code> با فراخوانی اسکریپت <code class="language-plaintext highlighter-rouge">content/customcol.js</code> محتوای ستون را تولید کرده و آن را نمایش می‌دهد. تابع <code class="language-plaintext highlighter-rouge">unpaint</code> نمایش ستون را متوقف و محتوای آن را پاک می‌کند.</p>

<p>مقدار پیش فرض متغیرهای قابل تنظیم برنامه در اینجا تعریف شده‌اند. در صورت تغییر آنها در صفحه ساماندهی افزونه تابع <code class="language-plaintext highlighter-rouge">changeSetting</code> با واسطه <code class="language-plaintext highlighter-rouge">background.js</code> فراخوانی شده و ستون تاریخ را دوباره می‌سازد و نمایش می‌دهد.</p>

<p>فایل <code class="language-plaintext highlighter-rouge">content/customcol.js</code>:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// This Source Code Form is subject to the terms of the</span>
<span class="c1">// GNU General Public License, version 3.0.</span>
<span class="kd">var</span> <span class="p">{</span> <span class="nx">AppConstants</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">ChromeUtils</span><span class="p">.</span><span class="k">import</span><span class="p">(</span>
  <span class="dl">"</span><span class="s2">resource://gre/modules/AppConstants.jsm</span><span class="dl">"</span>
<span class="p">);</span>
<span class="kd">var</span> <span class="p">{</span> <span class="nx">Services</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">ChromeUtils</span><span class="p">.</span><span class="k">import</span><span class="p">(</span><span class="dl">"</span><span class="s2">resource://gre/modules/Services.jsm</span><span class="dl">"</span><span class="p">);</span>

<span class="kd">const</span> <span class="nx">jalaliDateColumnHandler</span> <span class="o">=</span> <span class="p">{</span>
<span class="nf">init</span><span class="p">(</span><span class="nx">win</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">win</span> <span class="o">=</span> <span class="nx">win</span><span class="p">;</span>
<span class="p">},</span>
<span class="nf">getCellText</span><span class="p">(</span><span class="nx">row</span><span class="p">,</span> <span class="nx">col</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">date</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Date</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nf">getJalaliDate</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">win</span><span class="p">.</span><span class="nx">gDBView</span><span class="p">.</span><span class="nf">getMsgHdrAt</span><span class="p">(</span><span class="nx">row</span><span class="p">)));</span>
<span class="kd">var</span> <span class="nx">currentDate</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Date</span><span class="p">();</span>

    <span class="c1">//fixed options</span>
    <span class="kd">var</span> <span class="nx">yearStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">2-digit</span><span class="dl">"</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">dayStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">2-digit</span><span class="dl">"</span><span class="p">;</span>

    <span class="kd">var</span> <span class="nx">locale</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">fa-IR-u-nu-</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">numbersStyle</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">-ca-persian</span><span class="dl">"</span><span class="p">;</span>

    <span class="kd">var</span> <span class="nx">year</span> <span class="o">=</span> <span class="nx">date</span><span class="p">.</span><span class="nf">toLocaleString</span><span class="p">(</span><span class="nx">locale</span><span class="p">,</span> <span class="p">{</span> <span class="na">year</span><span class="p">:</span> <span class="nx">yearStyle</span> <span class="p">});</span>
    <span class="kd">var</span> <span class="nx">month</span> <span class="o">=</span> <span class="nx">date</span><span class="p">.</span><span class="nf">toLocaleString</span><span class="p">(</span><span class="nx">locale</span><span class="p">,</span> <span class="p">{</span> <span class="na">month</span><span class="p">:</span> <span class="nx">monthStyle</span> <span class="p">});</span>
    <span class="kd">var</span> <span class="nx">day</span> <span class="o">=</span> <span class="nx">date</span><span class="p">.</span><span class="nf">toLocaleString</span><span class="p">(</span><span class="nx">locale</span><span class="p">,</span> <span class="p">{</span> <span class="na">day</span><span class="p">:</span> <span class="nx">dayStyle</span> <span class="p">});</span>
    <span class="kd">var</span> <span class="nx">weekDay</span> <span class="o">=</span>
      <span class="nx">weekDayStyle</span> <span class="o">!=</span> <span class="dl">"</span><span class="s2">hidden</span><span class="dl">"</span>
        <span class="p">?</span> <span class="nx">date</span><span class="p">.</span><span class="nf">toLocaleString</span><span class="p">(</span><span class="nx">locale</span><span class="p">,</span> <span class="p">{</span> <span class="na">weekday</span><span class="p">:</span> <span class="nx">weekDayStyle</span> <span class="p">})</span>
        <span class="p">:</span> <span class="dl">""</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">time</span> <span class="o">=</span>
      <span class="nx">timeStyle</span> <span class="o">!=</span> <span class="dl">"</span><span class="s2">hidden</span><span class="dl">"</span>
        <span class="p">?</span> <span class="nx">date</span><span class="p">.</span><span class="nf">toLocaleString</span><span class="p">(</span><span class="nx">locale</span><span class="p">,</span> <span class="p">{</span>
            <span class="na">hour</span><span class="p">:</span> <span class="nx">timeStyle</span><span class="p">,</span>
            <span class="na">minute</span><span class="p">:</span> <span class="nx">timeStyle</span><span class="p">,</span>
            <span class="na">hour12</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
          <span class="p">})</span> <span class="o">+</span> <span class="dl">"</span><span class="s2"> ،</span><span class="dl">"</span>
        <span class="p">:</span> <span class="dl">""</span><span class="p">;</span>

    <span class="c1">//fix for bug that doesn't prepend zero to farsei</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">length</span> <span class="o">!=</span> <span class="mi">7</span> <span class="o">&amp;&amp;</span> <span class="nx">timeStyle</span> <span class="o">!=</span> <span class="dl">"</span><span class="s2">hidden</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
      <span class="kd">var</span> <span class="nx">zero</span> <span class="o">=</span> <span class="nx">numbersStyle</span> <span class="o">===</span> <span class="dl">"</span><span class="s2">arabext</span><span class="dl">"</span> <span class="p">?</span> <span class="dl">"</span><span class="s2">۰</span><span class="dl">"</span> <span class="p">:</span> <span class="dl">"</span><span class="s2">0</span><span class="dl">"</span><span class="p">;</span>
      <span class="nx">time</span> <span class="o">=</span> <span class="nx">zero</span> <span class="o">+</span> <span class="nx">time</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="kd">var</span> <span class="nx">isCurrentYear</span><span class="p">;</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">currentDate</span><span class="p">.</span><span class="nf">toLocaleString</span><span class="p">(</span><span class="nx">locale</span><span class="p">,</span> <span class="p">{</span> <span class="na">year</span><span class="p">:</span> <span class="nx">yearStyle</span> <span class="p">})</span> <span class="o">==</span> <span class="nx">year</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">isCurrentYear</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="nx">isCurrentYear</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="kd">var</span> <span class="nx">isCurrentDay</span><span class="p">;</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">date</span><span class="p">.</span><span class="nf">toDateString</span><span class="p">()</span> <span class="o">===</span> <span class="nx">currentDate</span><span class="p">.</span><span class="nf">toDateString</span><span class="p">())</span> <span class="p">{</span>
      <span class="nx">isCurrentDay</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="nx">isCurrentDay</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="kd">var</span> <span class="nx">isYesterday</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">yesterdayDate</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Date</span><span class="p">();</span>
    <span class="nx">yesterdayDate</span><span class="p">.</span><span class="nf">setDate</span><span class="p">(</span><span class="nx">currentDate</span><span class="p">.</span><span class="nf">getDate</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">date</span><span class="p">.</span><span class="nf">toDateString</span><span class="p">()</span> <span class="o">===</span> <span class="nx">yesterdayDate</span><span class="p">.</span><span class="nf">toDateString</span><span class="p">())</span> <span class="p">{</span>
      <span class="nx">isYesterday</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="nx">isYesterday</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kd">var</span> <span class="nx">placehodler</span><span class="p">;</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">monthStyle</span> <span class="o">===</span> <span class="dl">"</span><span class="s2">long</span><span class="dl">"</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">placeholder</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">TT </span><span class="se">\</span><span class="s2">u202BWD DD MM YY</span><span class="se">\</span><span class="s2">u202C</span><span class="dl">"</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="nx">placeholder</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">TT YY/MM/DD WD</span><span class="dl">"</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">//remove year if it's current year</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">isCurrentYear</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">placeholder</span> <span class="o">=</span> <span class="nx">placeholder</span><span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="sr">/YY./</span><span class="p">,</span> <span class="dl">""</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="c1">//only show time if it's current day or yesterday</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">isCurrentDay</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">placeholder</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">TT امروز</span><span class="dl">"</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="k">if </span><span class="p">(</span><span class="nx">isYesterday</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">placeholder</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">TT دیروز</span><span class="dl">"</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="nx">dateString</span> <span class="o">=</span> <span class="nx">placeholder</span>
      <span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="dl">"</span><span class="s2">YY</span><span class="dl">"</span><span class="p">,</span> <span class="nx">year</span><span class="p">)</span>
      <span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="dl">"</span><span class="s2">MM</span><span class="dl">"</span><span class="p">,</span> <span class="nx">month</span><span class="p">)</span>
      <span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="dl">"</span><span class="s2">DD</span><span class="dl">"</span><span class="p">,</span> <span class="nx">day</span><span class="p">)</span>
      <span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="dl">"</span><span class="s2">WD</span><span class="dl">"</span><span class="p">,</span> <span class="nx">weekDay</span><span class="p">)</span>
      <span class="p">.</span><span class="nf">replace</span><span class="p">(</span><span class="dl">"</span><span class="s2">TT</span><span class="dl">"</span><span class="p">,</span> <span class="nx">time</span><span class="p">);</span>

    <span class="k">return</span> <span class="nx">dateString</span><span class="p">;</span>

<span class="p">},</span>
<span class="nf">getSortStringForRow</span><span class="p">(</span><span class="nx">hdr</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nf">getJalaliDate</span><span class="p">(</span><span class="nx">hdr</span><span class="p">);</span>
<span class="p">},</span>
<span class="nf">isString</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">},</span>
<span class="nf">getCellProperties</span><span class="p">(</span><span class="nx">row</span><span class="p">,</span> <span class="nx">col</span><span class="p">,</span> <span class="nx">props</span><span class="p">)</span> <span class="p">{},</span>
<span class="nf">getRowProperties</span><span class="p">(</span><span class="nx">row</span><span class="p">,</span> <span class="nx">props</span><span class="p">)</span> <span class="p">{},</span>
<span class="nf">getImageSrc</span><span class="p">(</span><span class="nx">row</span><span class="p">,</span> <span class="nx">col</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">},</span>
<span class="nf">getSortLongForRow</span><span class="p">(</span><span class="nx">hdr</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">},</span>
<span class="nf">getJalaliDate</span><span class="p">(</span><span class="nx">aHeader</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">aHeader</span><span class="p">.</span><span class="nx">date</span> <span class="o">/</span> <span class="mi">1000</span><span class="p">;</span>
<span class="p">},</span>
<span class="p">};</span>

<span class="kd">const</span> <span class="nx">columnOverlay</span> <span class="o">=</span> <span class="p">{</span>
<span class="nf">init</span><span class="p">(</span><span class="nx">win</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">win</span> <span class="o">=</span> <span class="nx">win</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nf">addColumns</span><span class="p">(</span><span class="nx">win</span><span class="p">);</span>
<span class="p">},</span>

<span class="nf">destroy</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">destroyColumns</span><span class="p">();</span>
<span class="p">},</span>

<span class="nf">observe</span><span class="p">(</span><span class="nx">aMsgFolder</span><span class="p">,</span> <span class="nx">aTopic</span><span class="p">,</span> <span class="nx">aData</span><span class="p">)</span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="nx">jalaliDateColumnHandler</span><span class="p">.</span><span class="nf">init</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">win</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">win</span><span class="p">.</span><span class="nx">gDBView</span><span class="p">.</span><span class="nf">addColumnHandler</span><span class="p">(</span>
<span class="dl">"</span><span class="s2">jalaliDateColumn</span><span class="dl">"</span><span class="p">,</span>
<span class="nx">jalaliDateColumnHandler</span>
<span class="p">);</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">ex</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="nx">ex</span><span class="p">);</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Cannot add column handler</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">},</span>

<span class="nf">addColumn</span><span class="p">(</span><span class="nx">win</span><span class="p">,</span> <span class="nx">columnId</span><span class="p">,</span> <span class="nx">columnLabel</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="nx">win</span><span class="p">.</span><span class="nb">document</span><span class="p">.</span><span class="nf">getElementById</span><span class="p">(</span><span class="nx">columnId</span><span class="p">))</span> <span class="k">return</span><span class="p">;</span>

    <span class="kd">const</span> <span class="nx">treeCol</span> <span class="o">=</span> <span class="nx">win</span><span class="p">.</span><span class="nb">document</span><span class="p">.</span><span class="nf">createXULElement</span><span class="p">(</span><span class="dl">"</span><span class="s2">treecol</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">treeCol</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">id</span><span class="dl">"</span><span class="p">,</span> <span class="nx">columnId</span><span class="p">);</span>
    <span class="nx">treeCol</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">persist</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">hidden ordinal sortDirection width</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">treeCol</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">flex</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">2</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">treeCol</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">closemenu</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">none</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">treeCol</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">label</span><span class="dl">"</span><span class="p">,</span> <span class="nx">columnLabel</span><span class="p">);</span>
    <span class="nx">treeCol</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">tooltiptext</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">تاریخ خورشیدی</span><span class="dl">"</span><span class="p">);</span>

    <span class="kd">const</span> <span class="nx">threadCols</span> <span class="o">=</span> <span class="nx">win</span><span class="p">.</span><span class="nb">document</span><span class="p">.</span><span class="nf">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">threadCols</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">threadCols</span><span class="p">.</span><span class="nf">appendChild</span><span class="p">(</span><span class="nx">treeCol</span><span class="p">);</span>

    <span class="c1">// Restore persisted attributes.</span>
    <span class="kd">let</span> <span class="nx">attributes</span> <span class="o">=</span> <span class="nx">Services</span><span class="p">.</span><span class="nx">xulStore</span><span class="p">.</span><span class="nf">getAttributeEnumerator</span><span class="p">(</span>
      <span class="k">this</span><span class="p">.</span><span class="nx">win</span><span class="p">.</span><span class="nb">document</span><span class="p">.</span><span class="nx">URL</span><span class="p">,</span>
      <span class="nx">columnId</span>
    <span class="p">);</span>
    <span class="k">for </span><span class="p">(</span><span class="kd">let</span> <span class="nx">attribute</span> <span class="k">of</span> <span class="nx">attributes</span><span class="p">)</span> <span class="p">{</span>
      <span class="kd">let</span> <span class="nx">value</span> <span class="o">=</span> <span class="nx">Services</span><span class="p">.</span><span class="nx">xulStore</span><span class="p">.</span><span class="nf">getValue</span><span class="p">(</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">win</span><span class="p">.</span><span class="nb">document</span><span class="p">.</span><span class="nx">URL</span><span class="p">,</span>
        <span class="nx">columnId</span><span class="p">,</span>
        <span class="nx">attribute</span>
      <span class="p">);</span>
      <span class="c1">// See Thunderbird bug 1607575 and bug 1612055.</span>
      <span class="k">if </span><span class="p">(</span>
        <span class="nx">attribute</span> <span class="o">!=</span> <span class="dl">"</span><span class="s2">ordinal</span><span class="dl">"</span> <span class="o">||</span>
        <span class="nf">parseInt</span><span class="p">(</span><span class="nx">AppConstants</span><span class="p">.</span><span class="nx">MOZ_APP_VERSION</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">74</span>
      <span class="p">)</span> <span class="p">{</span>
        <span class="nx">treeCol</span><span class="p">.</span><span class="nf">setAttribute</span><span class="p">(</span><span class="nx">attribute</span><span class="p">,</span> <span class="nx">value</span><span class="p">);</span>
      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="nx">treeCol</span><span class="p">.</span><span class="nx">ordinal</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
      <span class="p">}</span>
    <span class="p">}</span>

    <span class="nx">Services</span><span class="p">.</span><span class="nx">obs</span><span class="p">.</span><span class="nf">addObserver</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="dl">"</span><span class="s2">MsgCreateDBView</span><span class="dl">"</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>

<span class="p">},</span>

<span class="nf">addColumns</span><span class="p">(</span><span class="nx">win</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">addColumn</span><span class="p">(</span><span class="nx">win</span><span class="p">,</span> <span class="dl">"</span><span class="s2">jalaliDateColumn</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">تاریخ</span><span class="dl">"</span><span class="p">);</span>
<span class="p">},</span>

<span class="nf">destroyColumn</span><span class="p">(</span><span class="nx">columnId</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">treeCol</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">win</span><span class="p">.</span><span class="nb">document</span><span class="p">.</span><span class="nf">getElementById</span><span class="p">(</span><span class="nx">columnId</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">treeCol</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="nx">treeCol</span><span class="p">.</span><span class="nf">remove</span><span class="p">();</span>
<span class="p">},</span>

<span class="nf">destroyColumns</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">destroyColumn</span><span class="p">(</span><span class="dl">"</span><span class="s2">jalaliDateColumn</span><span class="dl">"</span><span class="p">);</span>
<span class="nx">Services</span><span class="p">.</span><span class="nx">obs</span><span class="p">.</span><span class="nf">removeObserver</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="dl">"</span><span class="s2">MsgCreateDBView</span><span class="dl">"</span><span class="p">);</span>
<span class="p">},</span>
<span class="p">};</span>

<span class="kd">var</span> <span class="nx">MahourDateHeaderView</span> <span class="o">=</span> <span class="p">{</span>
<span class="nf">init</span><span class="p">(</span><span class="nx">win</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">win</span> <span class="o">=</span> <span class="nx">win</span><span class="p">;</span>
<span class="nx">columnOverlay</span><span class="p">.</span><span class="nf">init</span><span class="p">(</span><span class="nx">win</span><span class="p">);</span>

    <span class="c1">// Usually the column handler is added when the window loads.</span>
    <span class="c1">// In our setup it's added later and we may miss the first notification.</span>
    <span class="c1">// So we fire one ourserves.</span>
    <span class="k">if </span><span class="p">(</span>
      <span class="nx">win</span><span class="p">.</span><span class="nx">gDBView</span> <span class="o">&amp;&amp;</span>
      <span class="nx">win</span><span class="p">.</span><span class="nb">document</span><span class="p">.</span><span class="nx">documentElement</span><span class="p">.</span><span class="nf">getAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">windowtype</span><span class="dl">"</span><span class="p">)</span> <span class="o">==</span> <span class="dl">"</span><span class="s2">mail:3pane</span><span class="dl">"</span>
    <span class="p">)</span> <span class="p">{</span>
      <span class="nx">Services</span><span class="p">.</span><span class="nx">obs</span><span class="p">.</span><span class="nf">notifyObservers</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="dl">"</span><span class="s2">MsgCreateDBView</span><span class="dl">"</span><span class="p">);</span>
    <span class="p">}</span>

<span class="p">},</span>

<span class="nf">destroy</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">columnOverlay</span><span class="p">.</span><span class="nf">destroy</span><span class="p">();</span>
<span class="p">},</span>
<span class="p">};</span></code></pre></figure>


</div>

<p>محتوای اصلی ستون اینجا ساخته می‌شود و ستون جدید ایجاد می‌شود.</p>

<h3 id="اسکریپت-پس-زمینه">اسکریپت پس زمینه</h3>

<p>اسکریپت‌های پس زمینه به عنوان صفحه‌های ویژه مشخصه <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">window</code></a> را با ویژگی <a href="https://developer.mozilla.org/en-US/docs/Glossary/DOM" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">Document Object Model</code></a> دارند.</p>

<p>ویژگی‌های صفحه پس زمینه:</p>

<p>صفحه پس زمینه زمانی که افزونه مجوزهای لازم را داشته باشد، می‌تواند به <code class="language-plaintext highlighter-rouge">WebExtension API</code>ها دسترسی داشته باشد. همچنین با توجه به دسترسی به میزبان (<a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">host permissions</code></a>) امکان فرستادن درخواست‌های <code class="language-plaintext highlighter-rouge">XHR</code> را دارد. برای آگاهی بیشتر در این زمینه کلید واژه <code class="language-plaintext highlighter-rouge">Cross-origin access</code> را جستجو کنید.</p>

<p>اسکریپت پس زمینه دسترسی مستقیم به صفحه‌های وب ندارد، اما می‌تواند اسکریپت‌های تولید محتوا (<a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">content scripts</code></a>) را در آنها بارگذاری کند و با استفاده از <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#Communicating_with_background_scripts" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">message-passing API</code></a> با آنها ارتباط برقرار کند. از این شیوه در افزونه ماهور استفاده شده است.</p>

<blockquote>
  <p>نکته: اسکریپت‌های پس زمینه برای جلوگیری از دسترسی به کنش‌های نابجا محدودیت‌هایی نیز دارند. نداشتن توان فراخوانی <code class="language-plaintext highlighter-rouge">eval()</code> نمون‌ای از این محدودیت‌ها است.
برای آگاهی بیشتر <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy" target="\_blank" rel="noopener noreferrer"><code class="language-plaintext highlighter-rouge">Content Security Policy</code></a> را بخوانید.
همچنین امکان فراخوانی <code class="language-plaintext highlighter-rouge">alert()</code>، <code class="language-plaintext highlighter-rouge">confirm()</code>، یا <code class="language-plaintext highlighter-rouge">prompt()</code> نیز در این صفحه وجود ندارد.</p>
</blockquote>

<p>کد اسکریپت پس زمینه ماهور:</p>

<div class="code-block">

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="dl">"</span><span class="s2">use strict</span><span class="dl">"</span><span class="p">;</span>

<span class="sr">/</span><span class="err">_
</span><span class="nx">Default</span> <span class="nx">settings</span><span class="p">.</span> <span class="nx">Initialize</span> <span class="nx">storage</span> <span class="nx">to</span> <span class="nx">these</span> <span class="nx">values</span><span class="p">.</span>
<span class="nx">_</span><span class="o">/</span>
<span class="kd">var</span> <span class="nx">datePrefrences</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">longMonth</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">showTime</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">weekDay</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="na">englishNumbers</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="p">};</span>

<span class="sr">/</span><span class="err">_
</span><span class="nx">Generic</span> <span class="nx">error</span> <span class="nx">logger</span><span class="p">.</span>
<span class="nx">_</span><span class="o">/</span>
<span class="kd">function</span> <span class="nf">onError</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
<span class="p">}</span>

<span class="sr">/</span><span class="err">_
</span><span class="nx">On</span> <span class="nx">startup</span><span class="p">,</span> <span class="nx">check</span> <span class="nx">whether</span> <span class="nx">we</span> <span class="nx">have</span> <span class="nx">stored</span> <span class="nx">settings</span><span class="p">.</span>
<span class="nx">If</span> <span class="nx">we</span> <span class="nx">don</span><span class="dl">'</span><span class="s1">t, then store the default settings.
_/
function checkStoredSettings(storedSettings) {
if (!storedSettings.datePrefrences) {
browser.storage.local.set({ datePrefrences });
}
}

function repaint(newSettings) {
browser.MahourDate.changeSettings(newSettings);
}

const gettingStoredSettings = browser.storage.local.get();
gettingStoredSettings.then(checkStoredSettings, onError);

/_ globals browser _/
var init = async () =&gt; {
browser.MahourDate.addWindowListener("hich");
};

init();</span></code></pre></figure>


</div>

<p>برای استفاده از ‪<code class="language-plaintext highlighter-rouge">browser.storage.local.get()</code>‬ و ‪<code class="language-plaintext highlighter-rouge">browser.storage.local.set()</code>‬ در فایل <code class="language-plaintext highlighter-rouge">manifest.jason</code> مجوز <code class="language-plaintext highlighter-rouge">storage</code> گرفته شده است. <code class="language-plaintext highlighter-rouge">MahourDate</code> شناسه <code class="language-plaintext highlighter-rouge">API</code> تازه این افزونه است. با استفاده از <code class="language-plaintext highlighter-rouge">browser.MahourDate.changeSettings(newSettings)</code> یکی از توابع آن برای اعمال تنظیمات فراخوانی می‌شود.</p>

<h1 id="به-روز-رسانی-برای-thunderbird-نسخه-۱۱۵-به-بعد">به روز رسانی برای <code class="language-plaintext highlighter-rouge">Thunderbird</code> نسخه ۱۱۵ به بعد</h1>

<p>در نسخه ۱۱۰ <code class="language-plaintext highlighter-rouge">Thunderbird</code> پشتیبانی از <code class="language-plaintext highlighter-rouge">Custom Culomn</code> متوقف شد و افزونه ماهور روی این نسخه از کار افتاد. با اضافه شدن <code class="language-plaintext highlighter-rouge">API</code> جدید در نسخه ۱۱۵ امکان به روز کردن کد و پشتیبانی از این نسخه‌ها فراهم شد. اگر دوست دارید بیشتر بدونید <a href="https://github.com/mhdzli/mahoor/issues/8">اینجا</a> درباره‌اش گفتگو کردیم.</p>

<p>چون وقت کافی برای به روز کردن کدها نداشتم، کمی طول کشید، اما سرانجام ماهور نسخه‌های تازه‌تر تا ۱۲۸ را پشتیبانی می‌کند.</p>

<h1 id="منابع-مفید">منابع مفید:</h1>

<p>اگر با ساخت افزونه‌ها آشنایی ندارید و تازه می‌خواهید شروع کنید این ویدیوی آقای شجاعی را ببینید:</p>

<div class="video">
  <iframe sandbox="allow-same-origin allow-scripts allow-popups" src="https://peertube.linuxrocks.online/videos/embed/d70182ca-9ea9-4411-bd24-86dcbff95ceb" frameborder="0" allowfullscreen=""></iframe>
</div>
<p>برای تست افزونه‌ها روی Thunderbird در صفحه <code class="language-plaintext highlighter-rouge">Add-ons Manager</code>  روی <code class="language-plaintext highlighter-rouge">Tools for all add-ons</code> (<i class="fa fa-cog"></i> <i class="fa  fa-chevron-down"></i>) کلیک کنید. با انتخاب گزینه <code class="language-plaintext highlighter-rouge">Debug Add-ons</code> یک تب جدید باز می‌شود که در آن افزونه ها را می‌توانید موقتا نصب و امتحان کنید. کافی است روی <code class="language-plaintext highlighter-rouge">Load Temporary Add-on</code> کلیک کنید و فایل <code class="language-plaintext highlighter-rouge">manifest.json</code> افزونه را انتخاب کنید.</p>

<ul>
  <li><a href="https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/index.html" target="\_blank" rel="noopener noreferrer">راهنمای توسعه رابط برنامه نویسی برای افزونه‌ها</a></li>
  <li><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions" target="\_blank" rel="noopener noreferrer">افزونه‌های مرورگر</a></li>
  <li><a href="https://github.com/mdn/webextensions-examples" target="\_blank" rel="noopener noreferrer">نمونه‌های ساده</a></li>
</ul>]]></content><author><name>محمد زینلی</name><email>m@zmim.ir</email></author><category term="unix/linux" /><category term="foss" /><category term="پروژه‌های من" /><summary type="html"><![CDATA[ماهور یک افزونه برای افزودن ستون تاریخ خورشیدی به برنامه مدیریت ایمیل محبوب Thunderbird است.]]></summary></entry></feed>