قبل أن نأتي إلى لوحة المفاتيح، يُرجى التنبّه إلى أنّ للأجهزة الحديثة سُبلًا أخرى إلى "إدخال شيء ما". فقد يستخدم الناس مثلا تقنيّة التعرّف على الكلام (خاصّة على اﻷجهزة المحمولة) أو النسخ/اللصق بواسطة الفأرة.
ولذلك، إذا أردنا تتبّع جميع المُدخلات في الحقل <input>
، فإنّ أحداث لوحة المفاتيح لا تفي بالغرض. يوجد هناك حدث آخر اسمه input
لتتبّع التغيّرات التي تحصل في الحقل <input>
، مهما كانت الوسيلة. وقد يكون الخيار اﻷفضل لهذه المهمّة. سنتناول هذا الحدث لاحقا في مقال يشرح اﻷحداث change وinput وcut وcopy وpaste.
ينبغي استخدام أحداث لوحة المفاتيح عند التعامل مع اﻷفعال التي تحصل بواسطة لوحة المفاتيح (يدخل في ذلك لوحة المفاتيح الافتراضيّة)، كالاستجابة للضغط على المفاتيح السهميّة Up
وDown
أو مفاتيح الاختصارات (بما في ذلك الجمع بين المفاتيح).
منصة الاختبار
لفهم أحداث لوحة المفاتيح بشكل أفضل، يمكنك استخدام منصّة الاختبار الموجودة هنا أو المثال الحي الآتي. جرّب تجميعات مختلفة من المفاتيح في المساحة النصيّة.
Keydown وkeyup
يقع حدث keydown
عندما يُضغط مفتاح ما، ثمّ يقع keyup
عندما يُحرّر.
event.code وevent.key
تسمح الخاصّيّة key
لكائن الحدث بالحصول على المحرف، بينما تُمكّنه الخاصّيّة code
من الحصول على "كود المفتاح الملموس". على سبيل المثال، يمكن أن يُضغط نفس المفتاح Z
مع أو بدون المفتاح Shift
. سيعطينا ذلك محرفان مختلفان: z
الصغير وZ
الكبير.
تعبّر الخاصّيّة event.key
عن المحرف، وقد تختلف. لكنّ event.code
تبقى نفسها:
Key |
event.key
|
event.code
|
---|---|---|
Z
|
z (الصغير)
|
KeyZ
|
Shift+Z
|
Z (الكبير)
|
KeyZ
|
إذا كان المستخدم يستعمل لغات مختلفة، فإنّ تغييره للغة أخرى سيعطي محرفا مختلفا تماما بدل "Z"
. وسيصبح ذلك هو قيمة event.key
، بينما تبقى event.code
هي نفسها دائما: "KeyZ".
ملاحظة: "KeyZ" وغيرها من أكواد المفاتيح
لكلّ مفتاحٍ كود يتعلّق بمكانه على لوحة المفاتيح. أكواد المفاتيح موضّحة في مواصفة أكواد أحداث واجهة المستخدم.
على سبيل المثال:
-
مفاتيح الأحرف لها أكواد من الشكل
"Key<letter>"
:"KeyA"
و"KeyB"
وهكذا. -
مفاتيح اﻷرقام لها أكواد من الشكل
"Digit<number>"
: "Digit0"
و"Digit1"
وهكذا. -
المفاتيح الخاصّة مكوّدة بأسمائها
"Enter"
و"Backspace"
و"Tab"
وهكذا.
هناك عدّة تخطيطات (layouts) شائعة للوحات المفاتيح، وتعطي المواصفة أكواد مفاتيح لكلّ منها؛ طالع قسم الحروف اﻷبجديّة واﻷرقام في المواصفة لمزيد من اﻷكواد، أو اضغط فقط على المفتاح في منصّة الاختبار الموجودة هنا.
تنبيه: حجم الأحرف مهمّ: "KeyZ"
وليس "keyZ"
يبدو ذلك واضحا، لكن لا يزال النّاس يخطئون في ذلك. يُرجى تجنّب الأخطاء عند الكتابة: إنّه KeyZ
وليس keyZ
. لن ينجح التحقّق event.code=="keyZ"
مثلا، إذ يجب أن يكون أوّل حرف من "Key"
كبيرا.
لكن ماذا لو لم يكن المفتاح يعطي أيّ محرف؟ مثل Shift
أو F1
أو غير ذلك. بالنسبة لتلك المفاتيح، event.key
هي في الغالب نفس event.code
:
Key |
event.key
|
event.code
|
---|---|---|
F1
|
F1
|
F1
|
Backspace
|
Backspace
|
Backspace
|
Shift
|
Shift
|
ShiftRight أو ShiftLeft
|
يُرجى التنبّه أنّ event.code
يبيّن المفتاح قد ضُعط بالضبط. فعلى سبيل المثال، تملك أغلب لوحات المفاتيح مفتاحي Shift
، على اليمين وعلى اليسار. يخبرنا event.code
أيّ واحد قد ضُغط بالضبط، أمّا event.key
فهو مسؤول عن "معنى" المفتاح: ما هو (إنّه "تبديل").
لنفترض أنّنا نريد معالجة أحد مفاتيح الاختصارات: Ctrl+Z
(أو Cmd+Z
في ماك). تربط معظم محرّرات النّصوص فعل "التراجع" بها. يمكننا وضع منصت إلى keydown
وتفحّص المفتاح الذي ضُغط.
لكنّ هناك معضلة هنا: في مثل هذه المنصتات، هل يجب علينا تفحّص قيمة event.key
أو event.code
؟
من جهة، قيمة event.key
هي المحرف، وتتغيّر حسب اللغة. فإذا كان للزائر عدّة لغات في نظام التشغيل وينتقل بينها، فإنّ نفس المفتاح يعطي محرفات مختلفة. لذا فمن المنطقيّ تفحّص event.code
، لأنّ لها نفس القيمة دائما. هكذا:
document.addEventListener('keydown', function(event) { if (event.code == 'KeyZ' && (event.ctrlKey || event.metaKey)) { alert('Undo!') } });
في الجهة المقابلة، هناك مشكلة مع event.code
. مع اختلاف تخطيطات لوحة المفاتيح، قد يكون لنفس المفتاح محرفات مختلفة. على سبيل المثال، إليك التخطيط اﻷمريكيّ ("QWERTY") والتخطيط الألمانيّ ("QWERTZ") تحته (من ويكيبيديا):
عند نفس المفتاح، نجد في التخطيط اﻷمريكيّ "Z"، بينما في التخطيط اﻷلمانيّ "Y" (اﻷحرف منعكسة).
حرفيًّا، تكون قيمة event.code
هي KeyZ
بالنسبة للذين عندهم التخطيط اﻷلماني عند الضغط على المفتاح Y
.
لو أجرينا التحقّق event.code == 'KeyZ'
في شيفرتنا، فإنّ الناس الذين عندهم التخطيط اﻷلمانيّ سينجح معهم هذا التحقّق إذا ضغطوا على المفتاح "Y".
يبدو هذا غريبا حقّا، لكنّه كذلك. تذكر المواصفة هذا السلوك صراحة.
من الممكن إذًا أن يوافق event.code
المحرفَ الخطأ في التخطيط غير المتوقّع. فقد تقابل نفس اﻷحرف مفاتيح ملموسة مختلفة باختلاف التخطيطات، مما يؤدّي إلى أكواد مختلفة. لحسن الحظّ، يحدث هذا مع بعض اﻷكواد فقط مثل keyA
وkeyQ
وkeyZ
(كما رأينا)، ولا يحدث مع المفاتيح الخاصّة مثل Shift
. يمكن أن تجد القائمة في المواصفة.
لتتبّع المحرفات التي تتعلّق بالتخطيط بشكل موثوق، قد يكون event.key
هو الطريقة اﻷفضل.
في المقابل، يمتاز event.code
بأنّه يكون هو نفسه على الدوام، ومرتبطا بمكان المفتاح الملموس، حتى لو غيّر الزائر اللغة. وبذلك، ستعمل مفاتيح الاختصارات التي تعتمد عليه حتى في حال تغيير اللغة.
إذا كنّا نودّ معالجة المفاتيح التي تتعلّق بالتخطيط، فإنّ event.key
هو الحلّ. وإذا كنّا نريد لمفاتيح الاختصارات أن تعمل ولو عند تغيير اللغة، فقد يكون event.code
هو اﻷفضل.
التكرار التلقائي
إذا استغرق الضغط على مفتاح ما مدّة طويلة بما يكفي، فإنّه يبتدئ "التكرار التلقائيّ": يقع الحدث keydown
مرار وتكرار، إلى أن يُحرّر المفتاح فنحصل عندها على keyup
. لذلك قد يكون من الطبيعيّ أن نحصل على العديد من keydown
بالإضافة إلى keyup
وحيد.
إذا وقعت الأحداث بواسطة التكرار التلقائيّ، فإنّ قيمة الخاصّية event.repeat
لكائن الحدث تكون true
.
اﻷفعال الافتراضيّة
تتنوّع الأفعال الافتراضيّة، إذ هناك العديد من اﻷمور التي قد تحصل بواسطة لوحة المفاتيح. على سبيل المثال:
- يظهر محرف على الشاشة (النتيجة اﻷظهر).
-
يُحذف محرف (مفتاح
Delete
). -
تُمرَّر الصفحة (مفتاح
PageDown
). -
يفتح المتصفّح حوار "حفظ الصفحة" (
Ctrl+S
). - …وهكذا.
قد يؤدّي منع الفعل الافتراضيّ عند keydown
إلى إلغاء معظمها، باستثناء المفاتيح الخاصّة المضمّنة في نظام التشغيل. على سبيل المثال، يعمل Alt+F4
في ويندوز على إغلاق نافذة المتصفّح الحاليّة. ولا سبيل إلى إيقاف ذلك بواسطة منع الفعل الافتراضيّ في جافاسكربت.
مثلا، يتوقّع المُدخل <input>
أدناه رقم هاتف، فلا يقبل المفاتيح التي بخلاف اﻷرقام أو +
أو ()
أو -
:
<script> function checkPhoneKey(key) { return (key >= '0' && key <= '9') || key == '+' || key == '(' || key == ')' || key == '-'; } </script> <input onkeydown="return checkPhoneKey(event.key)" placeholder="Phone, please" type="tel">
يُرجى التنبّه أنّ المفاتيح الخاصّة، مثل Backspace
وLeft
وRight
وCtrl+V
، لا تعمل في المُدخل. هذا أثر جانبيّ للمرشّح checkPhoneKey
الصارم. لنقم بإرخائه بعض الشيء:
<script> function checkPhoneKey(key) { return (key >= '0' && key <= '9') || key == '+' || key == '(' || key == ')' || key == '-' || key == 'ArrowLeft' || key == 'ArrowRight' || key == 'Delete' || key == 'Backspace'; } </script> <input onkeydown="return checkPhoneKey(event.key)" placeholder="Phone, please" type="tel">
تعمل كلّ من مفاتيح اﻷسهم والحذف جيّدا الآن.
لكن لايزال بإمكاننا إدخال أيّ شيء باستخدام الفأرة عن طريق النقر باليمين ثمّ اللصق. فالمرشّح إذًا ليس موثوقا مئة بالمئة. يمكننا تركه كذلك، لأنّه يعمل في غالب الأحيان. أو بدلا من ذلك، يمكننا تتبّع حدث input
الذي يقع عند كلّ تغيير، ونتفحّصه عندئذ و نبرزه/نعدّله إذا لم يكن صالحًا.
الأحداث والخاصيات القديمة
في القديم، كان هناك الحدث keypress
، بالإضافة إلى خاصّيّات كائن الحدث keyCode
وcharCode
و which
. كان هناك الكثير من حالات عدم توافق المتصفّح عند العمل بها، مما أجبر العاملين على المواصفة على التخلّي عنها جميعا وإنشاء أحداث جديدة (كما بُيّنت في أعلى هذا المقال). لا تزال الشيفرات القديمة تعمل، إذ بقيت المتصفّحات تدعمها، لكن ليس هناك سبب إطلاقا لاستخدامها الآن.
الملخص
يؤدّي الضغط على مفتاح ما إلى توليد حدث من أحداث لوحة المفاتيح، سواءً كان مفتاح رمز أو مفتاحا خاصّا مثل Shift
أو Ctrl
أو غيرها. الاستثناء الوحيد هو المفتاح Fn
الذي يكون أحيانا في الحواسيب المحمولة. ليس هناك حدث لوحة مفاتيح له، لأنّه يكون في الغالب في مستوى أقلّ انخفاضا من مستوى نظام التشغيل.
أحداث لوحة المفاتيح:
-
keydown
-- عند الضغط على المفتاح (يتكرّر تلقائيّا إذا ضُغط المفتاح طويلا)، -
keyup
-- عند تحرير المفتاح.
خاصّيات أحداث لوحة المفاتيح اﻷساسيّة:
-
code
-- "كود المفتاح" ("KeyA"
و"ArrowLeft"
وهكذا)، متعلّق بالمكان الملموس للمفتاح على لوحة المفاتيح. -
key
-- المحرف ("A"
و"a"
وهكذا). لمفاتيح غير المحارف، مثلEsc
، تكون له نفس قيمةcode
عادة.
في السابق، كانت أحداث لوحة المفاتيح تُستعمل أحيانا لتتبّع مُدخلات المستخدم في حقول النماذج. هذا غير موثوق، لأنّ المُدخلات قد تأتي من مصادر متنوّعة. لذلك، لدينا الأحداث input
وchange
التي تمكّننا من معالجة أيّ مدخل كان (سنتطرّق لها لاحقا في مقال اﻷحداث change وinput وcut وcopy وpaste). تقع تلك اﻷحداث عند إدخال أيّ نوع من المدخلات، بما في ذلك النسخ واللصق والتعرّف على الكلام.
التمارين
مفاتيح الاختصارات الموسعة
الأهميّة: 5
أنشئ الدالّة runOnKeys(func, code1, code2, ... code_n)
التي تعمل على بتنفيذ func
عند الضغط في نفس الوقت على المفاتيح التي لها اﻷكواد code1
, code2
, …, code_n
.
على سبيل المثال، تظهر الشيفرة أدناه alert
عندما تُضغط المفاتيح "Q"
و"W"
معا (في أيّ لغة، مع أو بدون تفعيل الأحرف الكبيرة).
runOnKeys( () => alert("Hello!"), "KeyQ", "KeyW" );
يمكن مشاهدة المثال يعمل من هنا.
الحل
لابدّ أن نستخدم اثنين من المعالجات: document.onkeydown
وdocument.onkeyup
.
لننشئ المجموعة pressed = new Set()
لحفظ المفاتيح المضغوطة حاليّا. يعمل المعالج اﻷوّل على الإضافة إليها، بينما يعمل المعالج الثاني على النزع منها. وكلّما وقع الحدث keydown
نتحقّق إن كان لدينا ما يكفي من المفاتيح المضغوطة، وننفّذ الدالّة إذا كان الحال كذلك.
افتح الحلّ في البيئة التجريبيّة
ترجمة -وبتصرف- للمقال Keyboard: keydown and keyup من سلسلة Browser: Document, Events, Interfaces لصاحبها Ilya Kantor
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.