diff --git "a/text/0000-\330\254\330\263\330\261-\331\204\331\210\330\255\330\251-\330\247\331\204\331\205\331\201\330\247\330\252\331\212\330\255-\331\204\330\252\330\267\330\250\331\212\331\202\330\247\330\252-\331\206\330\265\331\221\331\212\331\221\330\251-\330\252\331\201\330\247\330\271\331\204\331\212\331\221\330\251.md" "b/text/0000-\330\254\330\263\330\261-\331\204\331\210\330\255\330\251-\330\247\331\204\331\205\331\201\330\247\330\252\331\212\330\255-\331\204\330\252\330\267\330\250\331\212\331\202\330\247\330\252-\331\206\330\265\331\221\331\212\331\221\330\251-\330\252\331\201\330\247\330\271\331\204\331\212\331\221\330\251.md" new file mode 100644 index 0000000..199422c --- /dev/null +++ "b/text/0000-\330\254\330\263\330\261-\331\204\331\210\330\255\330\251-\330\247\331\204\331\205\331\201\330\247\330\252\331\212\330\255-\331\204\330\252\330\267\330\250\331\212\331\202\330\247\330\252-\331\206\330\265\331\221\331\212\331\221\330\251-\330\252\331\201\330\247\330\271\331\204\331\212\331\221\330\251.md" @@ -0,0 +1,82 @@ +- **عنوان المقترح:** جسر لوحة المفاتيح لتطبيقات ص النصّيّة التفاعليّة (التقط_مفتاح) +- **النطاق:** لغة `text/` +- **تاريخ البدء:** 2026-07-26 +- **رقم الـ RFC:** (يُترك فارغاً حتى الدمج) +- **الحالة:** مقترَح (PR مفتوح) +- **Issue التتبُّع:** (يُترك فارغاً حتى القبول) + +# ملخّص + +مُدمَج جديد `التقط_مفتاح()` يعيد رمز آخر ضغطة لوحة مفاتيح منتظِرة (UnifiedKeyCode كعدد) ويستهلكها، أو 0 إن لا شيء. يمكّن هذا برامج ص من بناء واجهاتٍ نصّيّة تفاعليّة (طرفيّة، حقول إدخال، محرّرات) بلغة ص خالصة على الواجهة الحرّة — أوّل جسر إدخالٍ نصّيّ من لوحة المفاتيح إلى كود ص. + +# الدافع (Motivation) + +قبل هذا المقترح، كانت الواجهة الحرّة تلتقط ضغطات المفاتيح داخليًّا (evdev) لكن لا تُوصِّلها إلى كود ص — تُستعمَل حصرًا للخروج (F2/Escape). فتعذّر بناء أيّ برنامج نصّيّ تفاعليّ (طرفيّة، حقل بحث) بلغة ص. حالة الاستخدام المباشرة: **أوّل برنامج حقيقيّ تفاعليّ في سطح مكتب ص — طرفيّة تكتب فيها أوامر وتُنفَّذ**. + +# الشرح التوجيهي (Guide-level explanation) + +يستنزف البرنامج المفاتيح المنتظِرة كلّ إعادة بناءٍ في لولب، ويحدّث حالته: + +```sad +استورد رسومات +متغير أحرف = ["a"، "b"، "c"، "..."] # جدول رمز→حرف بفهرسة مصفوفة +متغير المدخَل = [""] + +دالة عالِج_المفاتيح() + متغير ك = التقط_مفتاح() + بينما (ك != 0) + إذا (ك == 40) # Enter (HID) + نفّذ(نص_المدخَل()) + المدخَل = [""] + نهاية + إذا (ك >= 4) # حرف a..z (HID 4..29) + إذا (ك <= 29) + المدخَل = المدخَل + [أحرف[ك - 4]] + نهاية + نهاية + ك = التقط_مفتاح() # المفتاح التالي + نهاية +نهاية +``` + +الرموز موحّدة (UnifiedKeyCode = HID usage): `a=4..z=29`، `1=30..9=38`، `0=39`، `Enter=40`، `Escape=41`، `Backspace=42`، `Space=44`. يخطّط كود ص الرمز إلى حرفٍ بفهرسة مصفوفة (لا يحتاج تحويل رمز→حرف مضمَّنًا). + +**اتّفاقيّة الخروج**: صار `F2` وحده يخرج من التطبيق الحرّ؛ `Escape` لم يعد يخرج (صار متاحًا للتطبيقات التي تحتاجه — طرفيّة/حقل). + +# الشرح المرجعي (Reference-level explanation) + +- **مصدر الحقيقة**: مدخل `NEXT_KEY` في `ui_widgets.yaml` (namespace `UICore`، `MODULE_FUNCTION`، `require_import: true`، بلا معاملات، يعيد عددًا). +- **المفسّر**: يعيد 0 (لا مصدر إدخالٍ حرّ headless) — متماثلٌ مع المصرّف المستضاف. +- **المترجم (sadc)**: أوپكود `BUILTIN_UI_NEXT_KEY` ⇒ نداء رنتايم `sad_next_key()` (i32 → مدّ إشارةٍ إلى i64). مُصنَّف ذا-أثرٍ في CSE (يستنزف حالة ⇒ لا يُدمَج). لا أوپكود إدخالٍ معقّد. +- **الرنتايم الحرّ**: طابور مفاتيح `deque` أحاديّ الخيط؛ `cfg.onKey` يُلحِق رمز كلّ مفتاح (عدا F2) ويوسّخ العرض؛ `sad_next_key()` يستنزفه. الحلقة الحرّة تعيد بناء البانِي فيستنزفه. +- **نظام الأخطاء**: لا رموز جديدة. +- **الأدوات**: لا أثر. +- **التوافق الخلفي**: مُدمَج جديد (إضافة). **تغيير سلوك وحيد**: `Escape` لم يعد يخرج من التطبيقات الحرّة (F2 يبقى) — لا تطبيق داخل المستودع يعتمده. + +# السلبيات (Drawbacks) + +- تغيير اتّفاقيّة الخروج (Escape) قد يفاجئ مستخدمي sad-os الحاليّين. +- الهدف المستضاف (SDL2) لا يوصِّل المفاتيح للطابور بعد ⇒ تطوير تطبيقات لوحة المفاتيح حرًّا فقط حاليًّا. +- نموذج الاستنزاف (مفتاحٌ لكلّ بناء) يعتمد على أن يلفّ كاتبُ التطبيق `التقط_مفتاح` حتّى 0. + +# المبرّرات والبدائل (Rationale and alternatives) + +- **البديل: ردّ نداء مفتاح `عند_مفتاح(دالّة)`**: يتطلّب تمرير إغلاقٍ بوسيطٍ عبر thunk (أعقد codegen). نموذج «استنزاف طابور» أبسط: مُدمَج واحد zero-arg بلا إغلاق. +- **البديل: توجيه المفاتيح لحقل نصّ مُركَّز**: يتطلّب تتبّع تركيزٍ وربطًا لكلّ ودجت — أثقل، ويقيّد المنطق في المحرّك بدل ص. +- **عدم الفعل**: يستحيل بناء أيّ برنامج نصّيّ تفاعليّ بلغة ص. + +# أعمال سابقة (Prior art) + +- طرفيّات النصّ (curses/termbox): حلقة أحداثٍ تقرأ المفاتيح وتُحدّث مخزَن الشاشة. +- لعبة/واجهة immediate-mode (Dear ImGui): استنزاف طابور أحداثٍ كلّ إطار — نظير مباشر لنموذجنا. + +# أسئلة غير محسومة (Unresolved questions) + +- توصيل الهدف المستضاف (SDL2) بالطابور لتطوير/اختبار تطبيقات لوحة المفاتيح على سطح المكتب المستضاف. +- هل نضيف مُدمَجات مساعدة (رمز→حرف، حالة Shift/Ctrl) لاحقًا؟ + +# إمكانات مستقبلية (Future possibilities) + +- حقل نصّ مُركَّز يستهلك المفاتيح تلقائيًّا (بناءً على هذا الجسر). +- محرِّر نصوص/صدَفة رسوميّة كاملة بلغة ص. +- توصيل مِفصال Shift/Ctrl/Alt عبر مُدمَجٍ لحالة المُعدِّلات.