OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef UI_EVENTS_KEYCODES_DOM3_DOM_KEY_H_ | 5 #ifndef UI_EVENTS_KEYCODES_DOM3_DOM_KEY_H_ |
6 #define UI_EVENTS_KEYCODES_DOM3_DOM_KEY_H_ | 6 #define UI_EVENTS_KEYCODES_DOM3_DOM_KEY_H_ |
7 | 7 |
| 8 #include <stdint.h> |
| 9 |
| 10 #include "base/logging.h" |
| 11 |
8 namespace ui { | 12 namespace ui { |
9 | 13 |
| 14 // Integer representation of UI Events KeyboardEvent.key value. |
| 15 // |
| 16 // The semantics follow the web string form[1]: the value is either a |
| 17 // Unicode character or one of a defined set of additional values[2]. |
| 18 // There is one notable difference from the UI Events string key: for |
| 19 // the 'Dead' key, this type provides a whole range of values that also |
| 20 // encode the associated combining character. (They are not quite the |
| 21 // same thing: a dead key is a non-printing operator that modifies a |
| 22 // subsequent printing character, whereas a Unicode combining character |
| 23 // is a printable character in its own right that attaches to a preceding |
| 24 // character in a string.) This allows the interpretation of any keystroke |
| 25 // to be carried as a single integer value. |
| 26 // |
| 27 // DomKey::NONE is a sentinel used to indicate an error or undefined value. |
| 28 // It is not the same as Unicode code point 0 (ASCII NUL) or the valid DOM |
| 29 // key 'Unidentified'. |
| 30 // |
| 31 // References: |
| 32 // [1] http://www.w3.org/TR/uievents/#widl-KeyboardEvent-key |
| 33 // [2] http://www.w3.org/TR/DOM-Level-3-Events-key/ |
| 34 // |
| 35 class DomKey { |
| 36 public: |
| 37 using Base = int32_t; |
| 38 |
| 39 private: |
| 40 // Integer representation of DomKey. This is arranged so that DomKey encoded |
| 41 // values are distinct from Unicode code points, so that we can dynamically |
| 42 // verify that they are not accidentally conflated. |
| 43 // |
| 44 // 31 24 16 8 0 |
| 45 // | | | | | | | | | |
| 46 // | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
| 47 // | z |c|s| v | |
| 48 // |
| 49 // From low to high: |
| 50 // - |v| is a value whose interpretation depends on the kind of key: |
| 51 // - for a Unicode value, it is the code point (0 <= v <= 0x10FFFF); |
| 52 // - for a dead key, the code point of the associated combining character; |
| 53 // - for others, an arbitrary distinct value. |
| 54 // - |s| is set for a valid symbolic key (i.e. not a Unicode character). |
| 55 // - |c| is set if |v| holds a code point (for either a Unicode character |
| 56 // directly, or a dead-key combining character). |
| 57 // - |z| is reserved and always zero. |
| 58 // |
| 59 // As consequences of this representation, |
| 60 // - all valid DomKey encodings have at least one of |c| or |s| set, so |
| 61 // they can't be confused with raw Unicode characters (where both are 0). |
| 62 // - integer 0 is not a valid encoding, and can be used for DomKey::NONE. |
| 63 // |
| 64 enum { VALUE_BITS = 21 }; |
| 65 enum Type : Base { |
| 66 VALUE_MASK = (1L << VALUE_BITS) - 1, |
| 67 TF_SYMBOLIC = (1L << VALUE_BITS), |
| 68 TF_CODEPOINT = (1L << (VALUE_BITS + 1)), |
| 69 TYPE_MASK = TF_CODEPOINT | TF_SYMBOLIC, |
| 70 TYPE_UNICODE = TF_CODEPOINT, |
| 71 TYPE_NON_UNICODE = TF_SYMBOLIC, |
| 72 TYPE_DEAD = TF_CODEPOINT | TF_SYMBOLIC, |
| 73 }; |
| 74 static_assert(TYPE_UNICODE != 0 && TYPE_NON_UNICODE != 0 && TYPE_DEAD != 0, |
| 75 "suspicious representation change"); |
| 76 |
| 77 public: |
| 78 enum InvalidKey : Base { NONE = 0 }; |
| 79 // |dom_key_data.inc| describes the non-printable DomKey values, and is |
| 80 // included here to create constants for them in the DomKey:: scope. |
| 81 #define DOM_KEY_MAP_DECLARATION enum Key : Base |
| 82 #define DOM_KEY_UNI(key, id, value) id = (TYPE_UNICODE | (value)) |
| 83 #define DOM_KEY_MAP_BEGIN FIRST_NON_UNICODE = TYPE_NON_UNICODE, |
10 #define DOM_KEY_MAP(key, id) id | 84 #define DOM_KEY_MAP(key, id) id |
11 #define DOM_KEY_MAP_DECLARATION enum class DomKey | 85 #define DOM_KEY_MAP_END LAST_NON_UNICODE |
12 #include "ui/events/keycodes/dom/dom_key_data.inc" | 86 #include "ui/events/keycodes/dom/dom_key_data.inc" |
| 87 #undef DOM_KEY_MAP_DECLARATION |
| 88 #undef DOM_KEY_MAP_BEGIN |
13 #undef DOM_KEY_MAP | 89 #undef DOM_KEY_MAP |
14 #undef DOM_KEY_MAP_DECLARATION | 90 #undef DOM_KEY_MAP_END |
| 91 #undef DOM_KEY_UNI |
| 92 |
| 93 // Create a DomKey, with the undefined-value sentinel DomKey::NONE. |
| 94 DomKey() : value_(NONE) {} |
| 95 |
| 96 // Create a DomKey from an encoded integer value. This is implicit so |
| 97 // that DomKey::NAME constants don't need to be explicitly converted |
| 98 // to DomKey. |
| 99 DomKey(Base value) : value_(value) { |
| 100 DCHECK(value == 0 || IsValid()) << value; |
| 101 } |
| 102 |
| 103 // Obtain the encoded integer representation of the DomKey. |
| 104 operator Base() const { return value_; } |
| 105 |
| 106 // True if the value is a valid DomKey (which excludes DomKey::NONE and |
| 107 // integers not following the DomKey format). |
| 108 bool IsValid() const { return (value_ & TYPE_MASK) != 0; } |
| 109 |
| 110 // True if the value is a Unicode code point. |
| 111 bool IsCharacter() const { return (value_ & TYPE_MASK) == TYPE_UNICODE; } |
| 112 |
| 113 // True if the value is a dead key. |
| 114 bool IsDeadKey() const { return (value_ & TYPE_MASK) == TYPE_DEAD; } |
| 115 |
| 116 // Returns the Unicode code point for a Unicode key. |
| 117 // It is incorrect to call this for other kinds of key. |
| 118 int32_t ToCharacter() const { |
| 119 DCHECK(IsCharacter()) << value_; |
| 120 return value_ & VALUE_MASK; |
| 121 } |
| 122 |
| 123 // Returns the associated combining code point for a dead key. |
| 124 // It is incorrect to call this for other kinds of key. |
| 125 int32_t ToDeadKeyCombiningCharacter() const { |
| 126 DCHECK(IsDeadKey()) << value_; |
| 127 return value_ & VALUE_MASK; |
| 128 } |
| 129 |
| 130 // Returns a DomKey for the given Unicode character. |
| 131 static DomKey FromCharacter(int32_t character) { |
| 132 DCHECK(character >= 0 && character <= 0x10FFFF); |
| 133 return DomKey(TYPE_UNICODE | character); |
| 134 } |
| 135 |
| 136 // Returns a dead-key DomKey for the given combining character. |
| 137 static DomKey DeadKeyFromCombiningCharacter(int32_t combining_character) { |
| 138 DCHECK(combining_character >= 0 && combining_character <= 0x10FFFF); |
| 139 return DomKey(TYPE_DEAD | combining_character); |
| 140 } |
| 141 |
| 142 // Provide means to generate constant DomKey::Base values, primarily to |
| 143 // allow conversion tables to be constant, without startup construction. |
| 144 // In the future (cue the theremin) this can be replaced with constexpr |
| 145 // functions. |
| 146 template<Base C> struct Constant { |
| 147 enum : Base { |
| 148 Character = TYPE_UNICODE | C, |
| 149 Dead = TYPE_DEAD | C, |
| 150 }; |
| 151 }; |
| 152 |
| 153 private: |
| 154 Base value_; |
| 155 }; |
15 | 156 |
16 } // namespace ui | 157 } // namespace ui |
17 | 158 |
18 #endif // UI_EVENTS_KEYCODES_DOM3_DOM_KEY_H_ | 159 #endif // UI_EVENTS_KEYCODES_DOM3_DOM_KEY_H_ |
OLD | NEW |