-
Notifications
You must be signed in to change notification settings - Fork 6.7k
/
accelerator_map.h
191 lines (164 loc) · 7.15 KB
/
accelerator_map.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_BASE_ACCELERATORS_ACCELERATOR_MAP_H_
#define UI_BASE_ACCELERATORS_ACCELERATOR_MAP_H_
#include <map>
#include <utility>
#include <vector>
#include "base/component_export.h"
#include "ui/base/accelerators/accelerator.h"
#if defined(OS_CHROMEOS)
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
#endif
namespace ui {
// This is a wrapper around an internal std::map of type
// |std::map<Accelerator, V>| where |V| is the mapped value.
//
// Accelerators in Chrome on all platforms are specified with the |key_code|,
// aka VKEY, however certain keys (eg. brackets, comma, period, plus, minus),
// are in different places based on the keyboard layout. In some cases the
// VKEYs don't exist, in some cases they now conflict with other shortcuts.
//
// Chrome OS uses a positional mapping for this subset of keys. Shortcuts
// based on these keys are determined by the position of the key on a US
// keyboard. This was already the case for all non-latin alphabet keyboards
// (Chinese, Japanese, Arabic, Russian, etc.).
//
// To achieve this on Chrome OS for the remaining layouts, an additional
// remapping may happen to the accelerator used for lookup based on the state
// of |use_positional_lookup_|. When false no remapping occurs. When true,
// the |code| aka DomCode (which is by definition fixed position), is used to
// find the US layout VKEY, and that VKEY is used to lookup in the map.
//
// Other non-positional keys, eg. alphanumeric, F-keys, and special keys are
// all not remapped. Alphanumeric keys always continue to follow the
// |code|/VKEY defined by the current layout as is existing behavior.
template <typename V>
class COMPONENT_EXPORT(UI_BASE) AcceleratorMap {
public:
AcceleratorMap() = default;
~AcceleratorMap() = default;
using iterator = typename std::map<Accelerator, V>::iterator;
using const_iterator = typename std::map<Accelerator, V>::const_iterator;
// Lookup an accelerator and return a pointer to the value. If the
// accelerator is not in the map, this returns nullptr.
const V* Find(const Accelerator& accelerator) const {
auto iter = FindImpl(accelerator);
return iter == map_.end() ? nullptr : &iter->second;
}
V* Find(const Accelerator& accelerator) {
// Call the const implementation to avoid duplicating code.
return const_cast<V*>(
const_cast<const AcceleratorMap*>(this)->Find(accelerator));
}
// Lookup an accelerator and return a reference to the value. If the
// accelerator is not present this function will DCHECK.
const V& Get(const Accelerator& accelerator) const {
auto iter = FindImpl(accelerator);
DCHECK(iter != map_.end());
return iter->second;
}
V& Get(const Accelerator& accelerator) {
// Call the const implementation to avoid duplicating code.
return const_cast<V&>(
const_cast<const AcceleratorMap*>(this)->Get(accelerator));
}
V& GetOrInsertDefault(const Accelerator& accelerator) {
#if defined(OS_CHROMEOS)
// Ensure the DomCode is NONE before registering. The DomCode is only
// used during lookup to select the correct VKEY.
if (accelerator.code() != DomCode::NONE) {
Accelerator accelerator_copy = accelerator;
accelerator_copy.reset_code();
return map_[accelerator_copy];
}
#endif
return map_[accelerator];
}
// Erase an accelerator from the map.
bool Erase(const Accelerator& accelerator) {
return map_.erase(accelerator) > 0;
}
// Inserts a new accelerator and value into the map. DCHECKs if the
// accelerator was already in the map.
void InsertNew(const std::pair<const Accelerator, V>& value) {
#if defined(OS_CHROMEOS)
// Ensure the DomCode is NONE before registering. The DomCode is only
// used during lookup to select the correct VKEY.
if (value.first.code() != DomCode::NONE) {
Accelerator accelerator_copy = value.first;
accelerator_copy.reset_code();
auto value_copy = std::make_pair(accelerator_copy, value.second);
auto result = map_.insert(value_copy);
DCHECK(result.second);
return;
}
#endif
auto result = map_.insert(value);
DCHECK(result.second);
}
// Iterators for the internal map.
iterator begin() { return map_.begin(); }
iterator end() { return map_.end(); }
// Returns the number of items in the map.
size_t size() const { return map_.size(); }
// Returns true if the map is empty.
bool empty() const { return map_.empty(); }
#if defined(OS_CHROMEOS)
// When true, lookup operators on the map will remap the |key_code| of
// position-based keys based on the |code|.
void set_use_positional_lookup(bool use_positional_lookup) {
use_positional_lookup_ = use_positional_lookup;
}
#endif
private:
std::map<Accelerator, V> map_;
#if defined(OS_CHROMEOS)
bool use_positional_lookup_ = false;
// For the shortcuts that use positional mapping, the lookup is done based
// on the |key_code| in the US layout. The supplied |code| (DomCode) is used
// to remap the layout specific |key_code| with the US layout equivalent,
// which effectively pins the location of these keys in place regardless of
// the actual key mapping. Note that this only happens for a subset of keys
// and has no overlap with alphanumeric characters or the language equivalent
// keys that map to the alphanumeric set of VKEYS.
//
// One such example is Alt ']'. In the US layout ']' is VKEY_OEM_6, in the
// DE layout it is VKEY_OEM_PLUS. However the key in that position is always
// DomCode::BRACKET_RIGHT regardless of what the key generates when pressed.
// This function uses the DomCode to remap the VKEY back to it's US layout
// equivalent.
//
// See the design doc in crbug.com/1174326 for more information.
Accelerator RemapAcceleratorForLookup(const Accelerator& accelerator) const {
KeyboardCode lookup_key_code = accelerator.key_code();
if (use_positional_lookup_) {
// If there's a valid remapping, use that |KeyboardCode| instead.
KeyboardCode remapped_key_code =
KeycodeConverter::MapPositionalDomCodeToUSShortcutKey(
accelerator.code());
lookup_key_code = remapped_key_code != VKEY_UNKNOWN ? remapped_key_code
: lookup_key_code;
}
return Accelerator(lookup_key_code, DomCode::NONE, accelerator.modifiers(),
accelerator.key_state());
}
#endif // defined(OS_CHROMEOS)
const_iterator FindImpl(const Accelerator& accelerator) const {
#if defined(OS_CHROMEOS)
auto iter = map_.find(RemapAcceleratorForLookup(accelerator));
// Sanity check that a DomCode was never inserted into the map.
DCHECK(iter == map_.end() || iter->first.code() == DomCode::NONE);
return iter;
#endif // defined(OS_CHROMEOS)
return map_.find(accelerator);
}
iterator FindImpl(const Accelerator& accelerator) {
return const_cast<V*>(
const_cast<const AcceleratorMap*>(this)->FindImpl(accelerator));
}
};
} // namespace ui
#endif // UI_BASE_ACCELERATORS_ACCELERATOR_MAP_H_