javascript 事件已弃用的 KeyboardEvent.which 属性的替代方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49278648/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 08:31:06  来源:igfitidea点击:

Alternative for event's deprecated KeyboardEvent.which property

javascripteventskeyboard-events

提问by flen

MDN states that KeyboardEvent.whichis deprecated. How can I substitute it for a non-deprecated version?

MDN 声明KeyboardEvent.which已弃用。如何将其替换为未弃用的版本?

For example, I have the following:

例如,我有以下内容:

window.onkeydown = (event) => { console.log(event.which); }

I thought event.key.charCodeAt()could substitute event.which, but this won't work for keys such as ALT, CTRLor ENTER, and it only works if event.key.length === 1:

我认为event.key.charCodeAt()可以替代event.which,但这不适用于诸如ALT,CTRL或 之类的键ENTER,并且仅在event.key.length === 1以下情况下才有效:

window.onkeydown = (event) => { console.log(event.key.charCodeAt()); }

To recap, event.which != event.codeand event.which != event.key, therefore I am unable to simply use event.key.

总括来说,event.which != event.codeevent.which != event.key,因此我无法简单地使用event.key

Is there a substitute for event.whichwhich detects combination keypresses including ALT, CTRLor ENTER?

是否有event.which检测组合按键的替代品,包括ALT,CTRLENTER

回答by AnilRedshift

TL;DR: These are the rules you should follow:

TL;DR:这些是您应该遵循的规则:

  • When getting text input from the user, use the keypressevent along with e.key
  • For shortcuts and other combinations, the built-in way is to use keydown/keyupand check the various modifier keys. If you need to detect chords, you may need to build a state machine.
  • 从用户获取文本输入时,将keypress事件与e.key
  • 对于快捷键和其他组合,内置的方式是使用keydown/keyup并检查各种修饰键。如果您需要检测和弦,您可能需要构建一个状态机。

Background

背景

Keyboard input is split into two phases - keydown/keyup pairs, which track physical keys being pressed, and composed characters that combines multiple sequences of keys to compute a character.

键盘输入分为两个阶段 - keydown/keyup 对,跟踪被按下的物理键,以及组合多个键序列来计算字符的字符。

Getting "text"

获取“文本”

If you want to know what the operating system thinks the composed sequence is, you should use KeyboardEvent.key

如果你想知道操作系统认为组合序列是什么,你应该使用KeyboardEvent.key

Sample code:

示例代码:

document.getElementById('a').addEventListener('keypress', e => console.log(e.key));
<input id="a" type="text" placeholder="type here">

The reason you want to do this most of the time is because many languages compose characters with several keypresses. The easiest for US-101 keyboards to understand is pressing the shiftkey + ais A, compared to just pressing a. For languages like Russian, with the altgrdead key, this becomes especially important.

大多数时候你想这样做的原因是因为许多语言用几个按键组合字符。最简单的US-101键盘明白的是按下shift键+aA,这一比例仅为紧迫a。对于像俄语这样的语言,使用altgr死键,这变得尤为重要。

The point I am trying to make is that doing all of this work yourself - detecting key sequences and determining the correct text output is a hard problem?. It is the job of the operating system for a reason.

我想说明的一点是,自己完成所有这些工作——检测关键序列并确定正确的文本输出是一个难题?。这是操作系统的工作是有原因的。

Now, for older browsers, you may not want to use e.keyfor lack of older support. Then you can fall back to things like which, or other non-standard approaches.

现在,对于较旧的浏览器,e.key由于缺乏较旧的支持,您可能不想使用。然后你可以退回到诸如which,或其他非标准方法之类的东西。

At some point in the future, keypress may be removed by browsers. The beforeinputevent is supposed to be the replacement. However, that event is only supported in chrome, so I'm omitting in here for brevity's sake.

在未来的某个时候,浏览器可能会删除按键。该beforeinput事件被认为是替代。但是,该事件仅在 chrome 中受支持,因此为简洁起见,我在此处省略。

Getting keystrokes

获取击键

Now then, suppose you are not tracking text, but rather key sequences. This is for things like games, or listening to ctrl-cetc. In this case, the correct thing to do is to listen to keydown/keyupevents. For modifier keys, you can simply listen to the ctrlKey, shiftKey, and metaKeyproperties of the event. See below:

现在,假设您不是在跟踪文本,而是在跟踪键序列。这适用于游戏或收听ctrl-c等。在这种情况下,正确的做法是收听keydown/ keyupevents。对于组合键,你可以简单地听ctrlKeyshiftKey以及metaKey事件的性质。见下文:

document.getElementById('a').addEventListener('keydown', (e) => {
  const states = {
    alt: e.altKey,
    ctrl: e.ctrlKey,
    meta: e.metaKey,
    shift: e.shiftKey,
  };
  const key = e.key;
  const code = e.code;
  console.log(`keydown key: ${key}, code: ${code}`, states);
});
<input id="a" type="text" placeholder="press ctrl">

As an example, when pressing shift-o on my keyboard, I get the following:

例如,在我的键盘上按 shift-o 时,我得到以下信息:

keydown key: Shift, code: ShiftLeft {
  "alt": false,
  "ctrl": false,
  "meta": false,
  "shift": true
}
keydown key: O, code: KeyS {
  "alt": false,
  "ctrl": false,
  "meta": false,
  "shift": true
}

Hopefully the statespart is pretty self-evident. They say whether that modifier key was pressed while the other key is down.

希望这states部分是不言而喻的。他们说在另一个键按下时是否按下了修改键。

The difference between keyand codehas to do with keyboard layouts. I am using the software dvorak layout. Thus when I type the skey, the scan code that goes to the operating system says s, but then the OS converts that to obecause it's dvorak. Code in this case always refers to the scan code (physical key being pressed), while the key corresponds to the operating system's best-effort to figure out what the "text" will be. This isn't always possible, especially with other languages. Again, this is why using the key for the keypressis the right way to go about it.

之间的差异key,并code与键盘布局做。我正在使用软件 dvorak 布局。因此,当我键入s密钥时,进入操作系统的扫描代码显示为s,但随后操作系统将其转换为odvorak。在这种情况下,代码总是指扫描代码(被按下的物理键),而键对应于操作系统为弄清楚“文本”将是什么而做出的最大努力。这并不总是可能的,尤其是对于其他语言。同样,这就是为什么使用密钥keypress是正确的方法。

3rd party libraries

第三方库

If this doesn't sound particularly easy, that's because it's not. The last time I was looking at this, I came across the mousetraplibrary, although I'm not sure I would recommend it, given some of the issues I found. It does, however, show an example of building a state machine to track key chords.

如果这听起来不是特别容易,那是因为它不是。上次我看到这个时,我遇到了捕鼠器库,尽管我不确定我会推荐它,因为我发现了一些问题。但是,它确实显示了构建状态机以跟踪关键和弦的示例。

Addendum

附录

This is also why you need to track keydown/keyupif you want to eat keystrokes. Since there is no "text" for ctrl+c, you won't get a proper keypress, and thus the browser will natively handle it. If you want to run your own behavior, you need to e.preventDefault()on the keydown itself. (Some of the followup events like copycan also be cancelled, but that's not universally true)

这也是为什么你需要跟踪keydown/keyup如果你想吃按键。由于 ctrl+c 没有“文本”,您将无法获得正确的按键,因此浏览器将在本机处理它。如果你想运行你自己的行为,你需要e.preventDefault()在 keydown 本身上。(一些后续事件copy也可以取消,但并非普遍如此)

If you also just need to track keys inserted after-the-fact into an input field (or contenteditable div), see the inputevent.

如果您还只需要跟踪事后插入输入字段(或 contenteditable div)的键,请参阅输入事件。

History: Updated 8/2019 to change keypress->beforeinput

历史:更新 8/2019 以更改 keypress->beforeinput

回答by EECOLOR

From the specification:

从规范:

whichof type unsigned long, readonly

which holds a system- and implementation-dependent numerical code signifying the unmodified identifier associated with the key pressed. In most cases, the value is identical to keyCode

keyCodeof type unsigned long, readonly

keyCode holds a system- and implementation-dependent numerical code signifying the unmodified identifier associated with the key pressed. Unlike the KeyboardEvent.key attribute, the set of possible values are not normatively defined in this specification. Typically, these value of the keyCode should represent the decimal codepoint in ASCII [RFC20][US-ASCII] or Windows 1252 [WIN1252], but may be drawn from a different appropriate character set. Implementations that are unable to identify a key use the key value '0'.

See Legacy key models for more details on how to determine the values for keyCode.

哪些类型的 unsigned long 是只读的

它包含一个系统和实现相关的数字代码,表示与按下的键相关联的未修改标识符。在大多数情况下,该值与 keyCode 相同

unsigned long 类型的keyCode,只读

keyCode 包含一个系统和实现相关的数字代码,表示与按下的键相关联的未修改标识符。与 KeyboardEvent.key 属性不同,本规范中没有规范地定义可能值的集合。通常,keyCode 的这些值应代表 ASCII [RFC20][US-ASCII] 或 Windows 1252 [WIN1252] 中的十进制代码点,但可能来自不同的适当字符集。无法识别键的实现使用键值“0”。

有关如何确定 keyCode 值的更多详细信息,请参阅旧密钥模型。

(I have omitted the links)

(我省略了链接)

So it is quite easy to create a version that is compatible with the specification. The easiest version just returns 0for each key.

因此,创建与规范兼容的版本非常容易。最简单的版本只是0为每个键返回。

A slightly more involved version takes event.keyand grabs it's ASCII number. You can do the same for the control keys (altKey, ctrlKey, shiftKey).

稍微复杂一点的版本获取event.key并获取它的 ASCII 数字。您可以对控制键 ( altKey, ctrlKey, shiftKey)执行相同操作。

In short, as it stands the behavior of whichis different between systems and browsers. Using the non-deprecated event information you can create a more robust version that removes these differences and will be more future proof.

简而言之,就which目前而言,系统和浏览器之间的行为是不同的。使用未弃用的事件信息,您可以创建一个更强大的版本,以消除这些差异,并且更适合未来证明。

You can check the behavior of your version with the implementation of whichin major browsers. If you are not using any edge cases your version will be both simple and compatible.

您可以通过which在主要浏览器中的实现来检查您的版本的行为。如果您不使用任何边缘情况,您的版本将既简单又兼容。

回答by flen

As the other answers pointed out, event.whichhas one main problem: it does not return the same number for different browsers or computers (maybe this is why it is deprecated). Therefore, there is no perfect substitute for it, since it will output different numbers for different users.

正如其他答案所指出的,event.which有一个主要问题:它不会为不同的浏览器或计算机返回相同的数字(也许这就是它被弃用的原因)。因此,没有完美的替代品,因为它会为不同的用户输出不同的数字。

So the main problem in trying to create a substitute for it (let's name it: function whichSubstitute(event)) is that the Metaand Shiftkeys, for example, don't have a unique number that whichSubstituteshould get when one of them is pressed, it varies according to OS.

因此,尝试为其创建替代品的主要问题(让我们将其命名function whichSubstitute(event)为:)是MetaShift键,例如,没有在whichSubstitute按下其中一个键时应该获得的唯一编号,它因操作系统而异

With that in mind, there are two approaches for getting the unicode code point for the user's input.

考虑到这一点,有两种方法可以获取用户输入的 unicode 代码点。

  1. Getting the unicode value for the character that the user inputted (e.g., ü, which would be 'ü'.codePointAt(0)).
  2. Getting a numeric value for the character that corresponds to the physical key pressed in the keyboard, which might be different from what was inputted to the text field. As AnilRedShift mentioned, the keyboard layout might change the "natural" output from that key in the keyboard, in such a way that the key smight output o. In this case, we'd get 's'.codePointAt(0), instead of getting the value for 'o'(that is, what was actually outputted), like we would get using the first approach. More on this from MDN:
  1. 获取用户输入的字符的 unicode 值(例如,ü将是'ü'.codePointAt(0))。
  2. 获取与键盘中按下的物理键对应的字符的数值,该数值可能与输入到文本字段的内容不同。正如 AnilRedShift 所提到的,键盘布局可能会改变键盘中该键的“自然”输出,这样该键s可能会输出o. 在这种情况下,我们将获取's'.codePointAt(0),而不是获取'o'(即实际输出的内容)的值,就像我们使用第一种方法一样。更多来自 MDN 的内容

For example, the code returned is "KeyQ" is for the "q" key on a QWERTY layout keyboard, but the same code value also represents the "'" key on Dvorak keyboards and the "a" key on AZERTY keyboards. That makes it impossible to use the value of code to determine name of the key is to users if they're not using an anticipated keyboard layout.

例如,返回的代码“ KeyQ”用于qQWERTY 布局键盘上的“ ”键,但相同的代码值也表示'Dvorak 键盘上的“ a”键和 AZERTY 键盘上的“ ”键。如果用户不使用预期的键盘布局,则无法使用代码的值来确定用户的键名。

In short: approach number 1 gets the unicode code point for ü, whereas approach number 2 gets the code points for SHIFT, 6and U(since SHIFT+6+U== ü).

简而言之:方法 1 获取 的 unicode 代码点ü,而方法 2 获取SHIFT,6U(因为SHIFT+ 6+ U== ü)的代码点。

In this answer, we'll use String.prototype.codePointAt()instead of String.prototype.charCodeAt(). The differences are well explained here. The reason is that we can get the whole unicode number with .codePointAt(0), whereas the .charCodeAt(0)would lack .codePointAt(1)to complete the UTF-16 encoded code point.

在这个答案中,我们将使用String.prototype.codePointAt()代替String.prototype.charCodeAt()这些差异在这里得到了很好的解释。原因是我们可以使用 获得整个 unicode 编号.codePointAt(0),而 则.charCodeAt(0)无法.codePointAt(1)完成 UTF-16 编码的代码点。

For approach number 1, we can use the following code:

对于方法1,我们可以使用以下代码:

function whichSubstitute(event) {
  const theKey = event.key;
  if (theKey.length === 1) {
    return theKey.codePointAt(0);
  }
  switch (theKey) {
    case "Backspace":
      return 8;
    case "Tab":
      return 9;
    case "Enter":
      return 13;
    case "Alt":
      return 18;
    case "Escape":
      return 27;
    case "Delete":
      return 127;

    case "Dead": //As of july 2018, Firefox has no support for "Dead" keys https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
      {}
      break;
    case "Unidentified":
      alert("handle the 'Unidentified' if you want to!");
  }

  /*** there are many other possible key values https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
        but, AFAIK, there are no unicode code points for them, such as:

  switch (theKey) {
    case "AltGraph":
    case "CapsLock":
    case "Control":
    case "Fn":
    case "FnLock":
    ...

       event.which may output some number for them, but it is not consistent across
       browsers/machines and they may overlap with other code points. For example:

  case "ArrowUp":
    return 38; //this overlaps with "&"
  case "ArrowLeft":
    return 37; //this overlaps with "%"
  case "ArrowDown":
    return 40; //this overlaps with "("
  case "ArrowRight":
    return 39; //this overlaps with "'"

  ***/

  return 0;
}

//test
document.onkeydown = (event) => {
  console.log('whichSubstitute: ' + whichSubstitute(event) + '; event.which: ' + event.which);
  //note that whichSubstitute gets the ASCII number of 'a', while event.which only gets the ASCII number of 'A' (upper case, always)
}

This, of course, does not solve the problem of getting only one uniqueconsistent number for a pressed key when there is no unicode code point for it(as in the case of Meta). Such keys need to be handled by the programmer according to her/his needs.

当然,这并不能解决在没有 unicode 代码点的情况下(如 的情况)为按下的键获取唯一一致数字的问题。这些键需要由程序员根据她/他的需要来处理。Meta

For approach number 2, we can use the following code:

对于方法2,我们可以使用以下代码:

function whichSubstitute(event) {
  const theChar = event.code;
  if (theChar.startsWith('Key')) {
    return theChar.codePointAt(3);
  }
  if (theChar.startsWith('Digit')) {
    return theChar.codePointAt(5);
  }

  switch (theChar) {
    case "Backspace":
      return 8;
    case "Tab":
      return 9;
    case "Enter":
      return 13;
    case "Alt":
      return 18;
    case "Escape":
      return 27;
    case "Delete":
      return 127;
    case "Minus":
      return 45;
    case "Plus":
      return 43;
    case "Equal":
      return 61;
    case "Delete":
      return 127;
    case "BracketRight":
      return 93;
    case "BracketLeft":
      return 91;
    case "Backslash":
      return 92;
    case "Slash":
      return 47;
    case "Semicolon":
      return 59;
    case "Colon":
      return 58;
    case "Comma":
      return 44;
    case "Period":
      return 46;
    case "Space":
      return 32;
    case "Quote":
      return 34;
    case "Backquote":
      return 39;

    //there are also "Numpad....." variants

    case "Unidentified":
      alert("handle the 'Unidentified' if you want to!");
  }

  /*** there are many other possible character values https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
        but, AFAIK, there are no unicode code points for them, such as:

  switch (theKey) {
    case "AltLeft":
    case "CapsLock":
    case "ControlRight":
    case "Fn":
    case "NumpadDecimal":
    ...

       event.which may output some number for them, but it is not consistent across
       browsers/machines and they may overlap with other code points.

  ***/

  return 0;
}

//test
document.onkeydown = (event) => {
  console.log('whichSubstitute: ' + whichSubstitute(event) + '; event.which: ' + event.which);
}

This second approach might be useless, since the same physical key might output different unicode characters according to different keyboard layouts. The users might have no idea of which key they should press.

第二种方法可能没用,因为相同的物理键可能会根据不同的键盘布局输出不同的 unicode 字符。用户可能不知道他们应该按下哪个键。

Related: https://www.w3.org/TR/uievents/#keys

相关:https: //www.w3.org/TR/uievents/#keys