6 сентябр 2025

Klaviatura: keydown va keyup

Klaviaturaga o’tishdan oldin, zamonaviy qurilmalarda “biror narsani kiritish” uchun boshqa usullar ham mavjudligini yodda tuting. Masalan, odamlar ovozni tanish texnologiyasidan foydalanadilar (ayniqsa mobil qurilmalarda) yoki sichqoncha bilan nusxa olish/joylashtirish.

Shuning uchun agar biz <input> maydoniga har qanday kirishni kuzatmoqchi bo’lsak, klaviatura hodisalari yetarli emas. <input> maydonining o’zgarishlarini har qanday usul bilan kuzatish uchun input nomli boshqa hodisa mavjud. Va bu bunday vazifa uchun yaxshiroq tanlov bo’lishi mumkin. Buni keyinroq Hodisalar: change, input, cut, copy, paste bobida ko’rib chiqamiz.

Klaviatura hodisalari klaviatura harakatlarini (virtual klaviatura ham hisobga olinadi) qayta ishlashni xohlasak ishlatilishi kerak. Masalan, o’q tugmalari Up va Down yoki tezkor tugmalar (tugmalar kombinatsiyalari) ga javob berish uchun.

Test stendi

Klaviatura hodisalarini yaxshiroq tushunish uchun quyidagi test stendidan foydalanishingiz mumkin.

Matn maydonida turli tugma kombinatsiyalarini sinab ko’ring.

Natija
script.js
style.css
index.html
kinput.onkeydown = kinput.onkeyup = kinput.onkeypress = handle;

let lastTime = Date.now();

function handle(e) {
  if (form.elements[e.type + "Ignore"].checked) return;

  let text =
    e.type +
    " key=" +
    e.key +
    " code=" +
    e.code +
    (e.shiftKey ? " shiftKey" : "") +
    (e.ctrlKey ? " ctrlKey" : "") +
    (e.altKey ? " altKey" : "") +
    (e.metaKey ? " metaKey" : "") +
    (e.repeat ? " (repeat)" : "") +
    "\n";

  if (area.value && Date.now() - lastTime > 250) {
    area.value += new Array(81).join("-") + "\n";
  }
  lastTime = Date.now();

  area.value += text;

  if (form.elements[e.type + "Stop"].checked) {
    e.preventDefault();
  }
}
#kinput {
  font-size: 150%;
  box-sizing: border-box;
  width: 95%;
}

#area {
  width: 95%;
  box-sizing: border-box;
  height: 250px;
  border: 1px solid black;
  display: block;
}

form label {
  display: inline;
  white-space: nowrap;
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="style.css" />
  </head>

  <body>
    <form id="form" onsubmit="return false">
      Prevent default for:
      <label>
        <input type="checkbox" name="keydownStop" value="1" />keydown</label
      >&nbsp;&nbsp;&nbsp;
      <label> <input type="checkbox" name="keyupStop" value="1" />keyup</label>

      <p>
        Ignore:
        <label>
          <input type="checkbox" name="keydownIgnore" value="1" />
          keydown</label
        >&nbsp;&nbsp;&nbsp;
        <label>
          <input type="checkbox" name="keyupIgnore" value="1" /> keyup</label
        >
      </p>

      <p>Kirish maydoniga e'tibor qarating va tugmani bosing.</p>

      <input
        type="text"
        placeholder="Bu yerdagi tugmachalarni bosing"
        id="kinput"
      />

      <textarea id="area"></textarea>
      <input type="button" value="Tozalash" onclick="area.value = ''" />
    </form>
    <script src="script.js"></script>
  </body>
</html>

Keydown va keyup

Tugma bosilganda keydown hodisasi sodir bo’ladi, keyin uni qo’yib yuborilganda keyup.

event.code va event.key

Hodisa obyektining key xossasi belgilarni olish imkonini beradi, code xossasi esa "jismoniy tugma kodi"ni olish imkonini beradi.

Masalan, bir xil Z tugmasi Shift bilan yoki usiz bosilishi mumkin. Bu bizga ikkita turli belgi beradi: kichik z va katta Z.

event.key aynan belgi bo’lib, u har xil bo’ladi. Lekin event.code bir xil:

Tugma event.key event.code
Z z (kichik harf) KeyZ
Shift+Z Z (katta harf) KeyZ

Agar foydalanuvchi turli tillarda ishlasa, boshqa tilga o’tish "Z" o’rniga butunlay boshqa belgi hosil qiladi. Bu event.key ning qiymati bo’ladi, event.code esa doim bir xil: "KeyZ".

“KeyZ” va boshqa tugma kodlari

Har bir tugma klaviaturadagi joylashuviga qarab kodga ega. Tugma kodlari UI Events code spetsifikatsiyasi da tasvirlangan.

Masalan:

  • Harf tugmalari "Key<harf>" kodlariga ega: "KeyA", "KeyB" va h.k.
  • Raqam tugmalari kodlarga ega: "Digit<raqam>": "Digit0", "Digit1" va h.k.
  • Maxsus tugmalar o’z nomlari bilan kodlanadi: "Enter", "Backspace", "Tab" va h.k.

Bir nechta keng tarqalgan klaviatura joylashuvlari mavjud va spetsifikatsiya har biri uchun tugma kodlarini beradi.

Ko’proq kodlar uchun spetsifikatsiyaning alfanumerik bo’limini o’qing yoki yuqoridagi test stendida tugmani bosing.

Katta-kichik harf muhim: "KeyZ", "keyZ" emas

Aniq ko’rinadi, lekin odamlar hali ham xatolarga yo’l qo’yadilar.

Iltimos, xatolardan saqlaning: KeyZ, keyZ emas. event.code=="keyZ" kabi tekshiruv ishlamaydi: "Key"ning birinchi harfi katta bo’lishi kerak.

Agar tugma hech qanday belgi bermasa-chi? Masalan, Shift yoki F1 yoki boshqalar. Bunday tugmalar uchun event.key taxminan event.code bilan bir xil:

Tugma event.key event.code
F1 F1 F1
Backspace Backspace Backspace
Shift Shift ShiftRight yoki ShiftLeft

Diqqat qiling, event.code aynan qaysi tugma bosilganini ko’rsatadi. Masalan, ko’pgina klaviaturalarda ikkita Shift tugmasi bor: chap va o’ng tomonda. event.code bizga aynan qaysi biri bosilganini aytadi, event.key esa tugmaning “ma’nosi” uchun javobgar: u nima (“Shift”).

Aytaylik, biz tezkor tugmani qayta ishlashni xohlaymiz: Ctrl+Z (yoki Mac uchun Cmd+Z). Ko’pgina matn muharrirlari unga “Bekor qilish” amalini bog’laydi. Biz keydown ga tinglovchi o’rnatishimiz va qaysi tugma bosilganini tekshirishimiz mumkin.

Bu yerda dilemma bor: bunday tinglovchida biz event.key yoki event.code qiymatini tekshirishimiz kerakmi?

Bir tomondan, event.key qiymati belgi bo’lib, u tilga qarab o’zgaradi. Agar tashrif buyuruvchi OS da bir nechta tilga ega bo’lib, ular o’rtasida almashsa, bir xil tugma turli belgilarni beradi. Shuning uchun event.code ni tekshirish mantiqiy, u doim bir xil.

Bunday:

document.addEventListener('keydown', function(event) {
  if (event.code == 'KeyZ' && (event.ctrlKey || event.metaKey)) {
    alert('Bekor qilish!')
  }
});

Boshqa tomondan, event.code bilan muammo bor. Turli klaviatura joylashuvlari uchun bir xil tugmada turli belgilar bo’lishi mumkin.

Masalan, bu yerda AQSh joylashuvi (“QWERTY”) va uning ostida Nemis joylashuvi (“QWERTZ”) (Vikipediyadan):

Bir xil tugma uchun AQSh joylashuvida “Z” bor, Nemis joylashuvida esa “Y” (harflar almashtirilgan).

Tom ma’noda, Nemis joylashuviga ega odamlar Y ni bosganda event.code KeyZ ga teng bo’ladi.

Agar biz kodimizdagi event.code == 'KeyZ' ni tekshirsak, Nemis joylashuviga ega odamlar uchun bunday test Y ni bosganda o’tadi.

Bu haqiqatan ham g’alati eshitiladi, lekin shunday. Spetsifikatsiya bunday xatti-harakatni aniq eslatadi.

Shunday qilib, event.code kutilmagan joylashuv uchun noto’g’ri belgiga mos kelishi mumkin. Turli joylashuvlardagi bir xil harflar turli jismoniy tugmalarga mos kelishi mumkin, bu esa turli kodlarga olib keladi. Yaxshiyamki, bu faqat bir nechta kod bilan sodir bo’ladi, masalan keyA, keyQ, keyZ (ko’rganimizdek), va Shift kabi maxsus tugmalar bilan sodir bo’lmaydi. Ro’yxatni spetsifikatsiyada topishingiz mumkin.

Joylashuvga bog’liq belgilarni ishonchli kuzatish uchun event.key yaxshiroq usul bo’lishi mumkin.

Boshqa tomondan, event.code har doim bir xil bo’lib, jismoniy tugma joylashuviga bog’langanligining afzalligi bor, hatto tashrif buyuruvchi tillarni o’zgartirsa ham. Shuning uchun unga tayanadigan tezkor tugmalar til almashtirilgan holatda ham yaxshi ishlaydi.

Biz joylashuvga bog’liq tugmalarni qayta ishlamoqchimizmi? U holda event.key yo’li.

Yoki tezkor tugma til almashtirilgandan keyin ham ishlashini xohlaymizmi? U holda event.code yaxshiroq bo’lishi mumkin.

Avtomatik takrorlash

Agar tugma etarlicha uzoq vaqt bosilsa, u "avtomatik takrorlash"ni boshlaydi: keydown qayta-qayta ishga tushadi, keyin qo’yib yuborilganda nihoyat keyup ni olamiz. Shuning uchun ko’plab keydown va bitta keyup bo’lishi odatiy holdir.

Avtomatik takrorlash tomonidan ishga tushirilgan hodisalar uchun hodisa obyekti event.repeat xossasini true ga o’rnatilgan.

Standart harakatlar

Standart harakatlar turli xil, chunki klaviatura tomonidan boshlanishi mumkin bo’lgan ko’plab mumkin bo’lgan narsalar mavjud.

Masalan:

  • Belgi ekranda paydo bo’ladi (eng aniq natija).
  • Belgi o’chiriladi (Delete tugmasi).
  • Sahifa aylantiriladi (PageDown tugmasi).
  • Brauzer “Sahifani saqlash” dialogini ochadi (Ctrl+S)
  • …va hokazo.

keydown da standart harakatning oldini olish ularning ko’pchiligini bekor qilishi mumkin, OS ga asoslangan maxsus tugmalar bundan mustasno. Masalan, Windows da Alt+F4 joriy brauzer oynasini yopadi. Va JavaScript da standart harakatning oldini olish orqali buni to’xtatishning yo’li yo’q.

Masalan, quyidagi <input> telefon raqamini kutadi, shuning uchun raqamlar, +, () yoki - dan tashqari tugmalarni qabul qilmaydi:

<script>
function checkPhoneKey(key) {
  return (key >= '0' && key <= '9') || key == '+' || key == '(' || key == ')' || key == '-';
}
</script>
<input onkeydown="return checkPhoneKey(event.key)" placeholder="Telefon, iltimos" type="tel">

Diqqat qiling, Backspace, Left, Right, Ctrl+V kabi maxsus tugmalar kirishda ishlamaydi. Bu qat’iy filtr checkPhoneKey ning yon ta’siri.

Uni biroz yumshatamiz:

<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="Telefon, iltimos" type="tel">

Endi o’qlar va o’chirish yaxshi ishlaydi.

…Lekin biz hali ham sichqonchani ishlatib va o’ng bosish + Joylashtirish orqali har qanday narsani kiritishimiz mumkin. Shuning uchun filtr 100% ishonchli emas. Biz uni shunday qoldirishimiz mumkin, chunki ko’p hollarda ishlaydi. Yoki muqobil yondashuv input hodisasini kuzatish bo’ladi – u har qanday o’zgarishdan keyin ishga tushadi. U yerda biz yangi qiymatni tekshirishimiz va noto’g’ri bo’lganda uni ajratib ko’rsatish/o’zgartirishimiz mumkin.

Meros

O’tmishda keypress hodisasi va shuningdek hodisa obyektining keyCode, charCode, which xossalari mavjud edi.

Ular bilan ishlashda juda ko’p brauzer nomosliklari bo’lgan, spetsifikatsiya ishlab chiquvchilari ularning barchasini eskirgan deb e’lon qilish va yangi, zamonaviy hodisalar (ushbu bobda yuqorida tasvirlangan) yaratishdan boshqa yo’li yo’q edi. Eski kod hali ham ishlaydi, chunki brauzerlar ularni qo’llab-quvvatlashda davom etadilar, lekin ularni ishlatishning hojati yo’q.

Mobil klaviaturalar

Virtual/mobil klaviaturalardan foydalanganda, rasmiy ravishda IME (Input-Method Editor) deb nomlanadi, W3C standarti KeyboardEvent ning e.keyCode 229 bo’lishi va e.key "Unidentified" bo’lishi kerakligini bildiradi.

Bu klaviaturalarning ba’zilari hali ham o’qlar yoki backspace kabi ma’lum tugmalarni bosganda e.key, e.code, e.keyCode uchun to’g’ri qiymatlarni ishlatishi mumkin bo’lsa-da, kafolat yo’q, shuning uchun klaviatura mantiqingiz mobil qurilmalarda har doim ham ishlamasligi mumkin.

Xulosa

Tugmani bosish har doim klaviatura hodisasini hosil qiladi, xoh u belgi tugmalari bo’lsin yoki Shift yoki Ctrl kabi maxsus tugmalar. Yagona istisno ba’zan noutbuk klaviaturasida mavjud bo’lgan Fn tugmasi. Uning uchun klaviatura hodisasi yo’q, chunki u ko’pincha OS dan pastroq darajada amalga oshiriladi.

Klaviatura hodisalari:

  • keydown – tugmani bosganda (tugma uzoq vaqt bosilsa avtomatik takrorlanadi),
  • keyup – tugmani qo’yib yuborishda.

Asosiy klaviatura hodisa xossalari:

  • code – “tugma kodi” ("KeyA", "ArrowLeft" va h.k.), klaviaturadagi tugmaning jismoniy joylashuviga xos.
  • key – belgi ("A", "a" va h.k.), belgi bo’lmagan tugmalar uchun, masalan Esc, odatda code bilan bir xil qiymatga ega.

O’tmishda klaviatura hodisalari ba’zan forma maydonlaridagi foydalanuvchi kirishini kuzatish uchun ishlatilgan. Bu ishonchli emas, chunki kirish turli manbalardan kelishi mumkin. Bizda har qanday kirishni qayta ishlash uchun input va change hodisalari mavjud (keyinroq Hodisalar: change, input, cut, copy, paste bobida ko’rib chiqiladi). Ular nusxa olish-joylashtirish yoki nutqni tanish kabi har qanday kirish turidan keyin ishga tushadi.

Haqiqatan ham klaviaturani xohlasak klaviatura hodisalarini ishlatishimiz kerak. Masalan, tezkor tugmalar yoki maxsus tugmalarga javob berish uchun.

Vazifalar

code1, code2, …, code_n kodlari bilan tugmalarni bir vaqtda bosish bilan func ishlaydigan runOnKeys(func, code1, code2, ... code_n) funksiyasini yarating.

Misol uchun, quyidagi kodda "Q" va "W" birga bosilganda alert ko’rsatiladi (har qanday tilda, CapsLock bilan yoki bo’lmasdan)

runOnKeys(() => alert("Salom!"), "KeyQ", "KeyW");

Yangi oynada namoyish

Biz ikkita ishlov beruvchidan foydalanishimiz kerak: document.onkeydown va document.onkeyup.

Hozir bosilgan tugmachalarni ushlab turish uchun pressed = new Set() to’plamini yarataylik.

Birinchi ishlov beruvchi unga qo’shadi, ikkinchisi esa undan olib tashlaydi. Har safar keydown da bizda yetarlicha tugmalar bosilganligini tekshiramiz va agar shunday bo’lsa, funktsiyani ishga tushiramiz.

Yechimni sandbox-da oching.

O'quv qo'llanma xaritasi

Izohlar

izoh berishdan oldin buni o'qing…
  • Agar sizda nimani yaxshilash kerakligi haqida takliflaringiz bo'lsa - iltimos, GitHub muammosini yuboring yoki izoh berish o'rniga so'rov yuboring.
  • Agar siz maqolada biror narsani tushunolmasangiz - iltimos, batafsilroq ma'lumot bering.
  • Bir nechta so'z so'zlarini kiritish uchun <code> yorlig'ini ishlating, bir nechta satrlar uchun - ularni <pre> yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepen…)