Alternative for event's deprecated KeyboardEvent.which property

后端 未结 3 651
抹茶落季
抹茶落季 2021-02-04 03:25

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

For example, I have the following:

3条回答
  •  忘了有多久
    2021-02-04 03:55

    As the other answers pointed out, event.which has 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.

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

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

    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 s might 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:

    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.

    In short: approach number 1 gets the unicode code point for ü, whereas approach number 2 gets the code points for SHIFT, 6 and U (since 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.

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

    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 unique consistent 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.

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

    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.

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

提交回复
热议问题