Hatena::Groupjavascript

JavaScriptで遊ぶよ

 | 

2009-11-14

DOM3 Eventsのキーイベント

08:33

この前ちょこっと疑問点を書きましたが、そのあたりも全部 Web Applications Working Group Teleconference にて話されていました。

気になるところをいくつか書いていきます。


1

キーイベントの key プロパティ (key value と呼びます) は、原則としてそのキーの文字そのものが入ります。

event.key === 'a'

など。


2

Shift が押されている場合はちょっと自信がないですが、例を見る感じだと if (event.key == 'a' && event.shiftKey) と判断するのではなくて、直接 if (event.key == 'A') と判断するようです。

  1. keydown: 'Shift', shiftKey
  2. keydown: 'Q' ('\u0051', Latin Capital Letter Q key), shiftKey
  3. textInput: 'Q'
  4. keyup: 'Q' ('\u0051', Latin Capital Letter Q key), shiftKey
  5. keyup: 'Shift'
Document Object Model (DOM) Level 3 Events Specification

keyIdentifier とは違いますよね、たぶん。

参考 (にはならないけど) → SafariとChromeではkeyIdentifierが使えるので素晴らしすぎます - JavaScriptで遊ぶよ - g:javascript


3

対応する Unicode 文字のないキーの場合は、keyIdentifier と同じようにキーの名前が入ります。

event.key === 'Enter'

など。


4

制御キー等の場合は Unicode エスケープで書かないといけないので注意が必要です。

if (event.key == '\u0008') { // 'Backspace'
  //
} else if (event.key == '\u001B') { // 'Esc'
  //
} else if ('\u0009') { // 'Tab'
  //
}

など。


5

サロゲートペアの問題ですが、それも「文字そのもの」を返すということになったので心配はなくなりました。

event.key == '𣧂'  // == '\uD84E\uDDC2'

実際にこの文字を入力するキーボードは存在するそうです。

DS: maciej wasn't sure that there are keys that result in a non BMP character

... however there appears there are

... characters "tree stub" and "untidy" are such characters

http://www.w3.org/2009/11/02-webapps-minutes.html#item08

サロゲートペアの文字は JS では長さ2ということになるので、押されたキーが Unicode かどうかを判断するのに if (event.key.length == 1) としてはいけません。

それでも if (event.key.length <= 2) と書く人がいるかもしれないので、今 F1 などとなっているファンクションキーの名前を Function1 などにしてはどうかと Hixie さんが言ってましたが、まだどうなるかわかりません。(たぶんならない。Unicode がサロゲート「ペア」の範囲で収まる保証もないし、無意味だと思う)


6

↓ここらへんで話されていましたが、ウムラウトやアクセント記号などの入力補助のための dead key (それ単体では文字を入力しないが、次に押されるキーと組み合わせて1文字になるキー) はどうなるのかよくわかりません。

たぶん制御キー等と同じように

if (event.key == '\u0300') { // 'DeadGrave'
  //
} else if (event.key == '\u0301') { // 'DeadEacute'
  //
}

などと判断することになるのかな。


7

IME を使っている場合は composition イベントが出るようになるので、Google のトップページのようにそのために毎秒100回入力欄をチェックする必要はなくなるかもしれません。

  1. keydown: 's' ('\u0073', Latin Small Letter S key)
  2. compositionstart: ''
  3. keyup: 's' ('\u0073', Latin Small Letter S key)
  4. keydown: 'i' ('\u0069', Latin Small Letter I key)
  5. keyup: 'i' ('\u0069', Latin Small Letter I key)
  6. keydown: 'Convert'
  7. compositionupdate: '詩'
  8. keyup: 'Convert'
  9. keydown: 'Convert'
  10. compositionupdate: '市'
  11. keyup: 'Convert'
  12. keydown: 'Accept'
  13. compositionend: '市'
  14. textInput: '市' ("inputMode": 'DOM_INPUT_METHOD_IME')
http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#keyset-unicode

8

key value では、キーボード上でのキーの位置までは感知しません。Google の坊野さんの質問に対する Doug Schepers さんの回答に詳しいです。

つまり、例えばロシア語のキー配列の場合は q のキーを押したとしても event.key は "й" になるので、event.key == 'q' だけで判断した場合はロシア語配列の人はショートカットが使えないことになります。ページ側は、キーボードショートカットとして使用するキー配列を選んでもらうようにするのが安全だとのことです。


9

最後に、この仕様では JavaScript の正規表現に構文を追加することを求めています。↓一番最後の一節。

With key values and regular expressions, however, authors can support selective and intuitive ranges for key-based input, in a cross-platform manner with advanced internationalization support, such as the following pseudocode:

  if ( event.key == "-" || 
       event.key.match("\p{Sc}") || 
       event.key.match("\p{N}") ) {
    // minus sign, any currency symbol, and numeric characters (regardless of key location)
    ... 
  }
  else if ( event.key.match("\p{L}") ) {
    // alphabetic characters from any language, upper and lower case
    ... 
  }
  else {
    ... 
  } 

In addition, because Unicode categorizes each assigned code point into a group of code points used by a particular human writing system, even more advanced capabilities are possible. For example, an author can match characters from a particular human script (e.g. Tibetan) using a regular expression such as \p{Tibetan}, to filter out other characters, or discover if a code point is in a certain code block (range of code points), using a regular expression like \p{InCyrillic}.

To facilitate this, implementations should support Unicode range detection using regular expressions, in a manner such as the Perl Compatible Regular Expressions (PCRE) [PCRE].

http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#keyset-unicode

例えば \p{L} はラテン文字の意味。


感想

ちょっと納得いかないところもありますが、今までよりはかなりキーイベントが扱いやすくなるんじゃないでしょうか。

key value が返すのは「文字そのもの」なので、仕様書から '\uXXXX' のような表現は無くしてほしいなあ。そもそも '\uXXXX' は ECMAScript では定義されているけど他の言語では定義されていない場合もあるわけだし。(他の言語ではその言語に対応する表現で「文字そのもの」を返すことになる)


KeyboardEvent クラス

仕様を読んでたらまだおもしろそうなのがあった。

  // Introduced in DOM Level 3:
  interface KeyboardEvent : UIEvent {

  // KeyLocationCode
  const unsigned long       DOM_KEY_LOCATION_STANDARD      = 0x00;
  const unsigned long       DOM_KEY_LOCATION_LEFT          = 0x01;
  const unsigned long       DOM_KEY_LOCATION_RIGHT         = 0x02;
  const unsigned long       DOM_KEY_LOCATION_NUMPAD        = 0x03;
  const unsigned long       DOM_KEY_LOCATION_MOBILE        = 0x04;
  const unsigned long       DOM_KEY_LOCATION_JOYSTICK      = 0x05;

  readonly attribute DOMString       key;                   
  readonly attribute unsigned long   location;
  readonly attribute boolean         ctrlKey;
  readonly attribute boolean         shiftKey;
  readonly attribute boolean         altKey;
  readonly attribute boolean         metaKey;
  readonly attribute boolean         repeat;
  boolean            getModifierState(in DOMString keyArg);
  void               initKeyboardEvent(in DOMString typeArg, 
                                     in boolean canBubbleArg, 
                                     in boolean cancelableArg, 
                                     in views::AbstractView viewArg, 
                                     in DOMString keyArg, 
                                     in DOMString characterArg, 
                                     in DOMString nameArg, 
                                     in DOMString unicodeArg, 
                                     in unsigned long locationArg, 
                                     in DOMString modifiersListArg,
                                     in boolean repeat);
  };

10

event.location でキーのおおまかな位置が取得できる。一部のブラウザでは既に keyLocation として使えていたものから名称変更。

Shift と左 Shift を区別したい時とか、テンキーの数字と通常キーボードの数字を区別したい時などに使う。


11

keydown 時などで、「キーを押したまま」だった場合は event.repeated が true となる。押したままなんだったら keydown じゃないだろ、と思うところだけど、互換性的な理由 (?) からそういう場合は keydown → keypress が何度も出るブラウザが多い (Opera 以外はそうだったと思う)。


12

event.getModifierState('Alt') // true or false など。

A modifier key value. Common modifier keys are 'Alt', 'AltGraph', 'CapsLock', 'Control', 'Meta', 'NumLock', 'Scroll', or 'Shift'.

shiftKey みたいなのだど、一般的ではないモディファイアキーに対応できないため。


13

keypress について。

Note: the keypress event is traditionally associated with detecting a character value rather than a physical key, and may not be available on all keys in some configurations.

Warning: the keypress event type is defined in this specification for reference and completeness, but this specification deprecates the use of this event type.

http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#events-keyboard-event-order

keypress は互換性のために残してあるけど、deprecated となったので使うべきではない。

 |