event.key, event.code hay keyCode cho phím tắt

Nên dùng thuộc tính nào của KeyboardEvent cho phím tắt, trò chơi và nhập liệu, bố cục AZERTY hay QWERTZ thay đổi câu trả lời thế nào, cùng các bẫy IME và AltGr.

Trong bài này

Mỗi sự kiện bàn phím trong trình duyệt mang ba cách nói phím nào được nhấn: event.key, event.code và event.keyCode đời cũ. Chọn sai, phím tắt của bạn chạy trên bàn phím của bạn nhưng hỏng với người dùng ở Pháp, Đức hay Việt Nam, hoặc bị kích hoạt giữa chừng khi họ đang gõ một từ bằng bộ gõ. Bài này giải thích ý nghĩa từng thuộc tính, đưa ra giá trị thật trên các bố cục khác nhau, và kết thúc bằng một đoạn xử lý phím tắt chạy tốt ở mọi nơi. Bạn có thể kiểm tra mọi giá trị trong công cụ xem mã phím bằng cách tự nhấn phím.

Ba câu trả lời cho "phím nào?"

Nhấn phím ở vị trí chữ cái trên cùng bên trái, phím mang nhãn Q trên bàn phím Mỹ:

Bố cụckeycodekeyCode
QWERTY Mỹ"q""KeyQ"81
AZERTY Pháp"a""KeyQ"65
QWERTZ Đức"q""KeyQ"81
  • `key` là kết quả: ký tự phím gõ ra với bố cục và phím bổ trợ hiện tại, hoặc một tên như "Enter", "ArrowLeft", "Escape", "Shift". Có Shift thì nó đổi ("Q"), còn với phím dấu đang chờ chữ tiếp theo thì nó là "Dead".
  • `code` là vị trí: phím vật lý, đặt tên theo vị trí của nó trên bàn phím Mỹ. Nó không đổi theo bố cục, Shift hay Caps Lock. Phím trái, phải được phân biệt: "ShiftLeft", "ShiftRight", "NumpadEnter".
  • `keyCode` (và which) là con số đời cũ có từ trước cả hai thuộc tính trên, đã bị đặc tả UI Events đánh dấu lỗi thời. Với chữ cái, nó là mã ASCII viết hoa của chữ theo bố cục (65 cho "a" trên AZERTY), nhưng với dấu câu thì mỗi trình duyệt một khác (phím dấu chấm phẩy từng là 186 trên Chrome và 59 trên Firefox), và khi dùng bộ gõ IME nó luôn là 229.

Phím tắt: thường dùng key

Phím tắt thường được gọi theo chữ cái: Ctrl+Z nghĩa là "Z", dù Z nằm ở đâu. Trên bàn phím QWERTZ của Đức, Z nằm ở chỗ của Y trên bàn phím Mỹ, nên người dùng nhấn phím có code là "KeyY" và key là "z". Mã kiểm tra code === "KeyZ" sẽ bắt người Đức nhấn Ctrl+Y để hoàn tác. Hãy kiểm tra key, và so chữ cái không phân biệt hoa thường, vì Shift biến "z" thành "Z":

document.addEventListener("keydown", (event) => {
  if (event.isComposing || event.repeat) return;
  if (event.key.toLowerCase() === "z" && (event.ctrlKey || event.metaKey) && !event.altKey) {
    event.preventDefault();
    event.shiftKey ? redo() : undo();
  }
});

Với phím tắt là ký hiệu như "?" để mở trợ giúp, hãy so key === "?" và đừng kiểm tra Shift: trên bàn phím Mỹ "?" cần Shift, trên bàn phím khác thì có thể không.

Trò chơi và vị trí: dùng code

Với di chuyển bằng WASD, vị trí mới là điều quan trọng: trên AZERTY bốn phím đó mang nhãn Z, Q, S, D, và người chơi muốn chúng chạy mà không phải gán lại. Hãy so code: "KeyW", "KeyA", "KeyS", "KeyD". Tương tự với phím tắt định nghĩa theo vị trí ("phím bên trái số 1", code === "Backquote"), và với phím tắt Alt hay Option trên macOS, nơi Option đổi ký tự: Option+S gõ ra "ß", nên key là "ß" chứ không phải "s".

Để hiển thị đúng nhãn cho một code, trình duyệt nhân Chromium có navigator.keyboard.getLayoutMap(); ở nơi khác, hãy hiển thị tên theo bố cục Mỹ hoặc cho người dùng tự nhấn phím họ muốn.

Bẫy bộ gõ (IME)

Gõ tiếng Việt kiểu Telex, pinyin tiếng Trung, tiếng Nhật và tiếng Hàn đều dùng bộ gõ ghép ký tự từ nhiều lần nhấn phím. Trong lúc soạn, trình duyệt vẫn phát keydown, với isComposing bằng true (và thường key là "Process", keyCode là 229). Nếu có mã xử lý Enter để gửi biểu mẫu, nhấn Enter để chốt một từ tiếng Nhật cũng gửi luôn biểu mẫu. Hãy luôn mở đầu mã xử lý bàn phím bằng:

if (event.isComposing || event.keyCode === 229) return;

Điều kiện keyCode === 229 bắt được các bản Safari cũ phát keydown cuối cùng sau khi việc soạn chữ đã kết thúc. Trong công cụ xem mã phím, hãy tắt chặn rồi gõ bằng bộ gõ để thấy compositionstart, compositionupdate và compositionend xen giữa các keydown.

Bẫy AltGr

Trên Windows, phím AltGr dùng để gõ các ký tự như "ą" (tiếng Ba Lan) hay "@" (bàn phím Đức) được báo là Ctrl và Alt cùng nhấn. Một phím tắt Ctrl+Alt+A sẽ chạy khi người Ba Lan gõ "ą". Hãy tránh tổ hợp Ctrl+Alt cho phím tắt, hoặc kiểm tra event.getModifierState("AltGraph") và bỏ qua sự kiện khi nó là true.

Những lỗi hay gặp

  • Dùng `keyCode` trong mã mới. Nó đã lỗi thời, phụ thuộc bố cục với dấu câu và bằng 229 khi dùng bộ gõ.
  • So `key === "s"` khi đang giữ Shift. Lúc đó nó là "S". Hãy chuyển về chữ thường hoặc so code.
  • Quên macOS. Ctrl+S trên Windows là Cmd+S trên Mac; hãy kiểm tra (event.ctrlKey || event.metaKey).
  • Không kiểm tra các phím bổ trợ khác. Thiếu !event.altKey thì Ctrl+Alt+Z cũng kích hoạt hoàn tác.
  • Xử lý phím tắt khi người dùng đang gõ. Hãy bỏ qua sự kiện có đích là input, textarea hay phần tử contenteditable, trừ khi phím tắt dành cho việc soạn thảo.
  • Cố bắt phím tắt của hệ điều hành. Alt+Tab, Cmd+Tab và Ctrl+Alt+Delete không bao giờ tới trang web; Ctrl+W và Ctrl+T thường cũng không.

Thử ngay

Mở công cụ xem mã phím, đổi bố cục bàn phím của hệ điều hành rồi nhấn cùng một phím vật lý để thấy key thay đổi trong khi code giữ nguyên. Công cụ viết sẵn đoạn xử lý tương ứng cho bạn, theo key hoặc theo code. Để tra một ký tự mà phím gõ ra, dùng công cụ tra cứu Unicode và emoji.

Công cụ được nhắc trong bài

Về trang blog