Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(570)

Side by Side Diff: chrome/browser/chromeos/events/event_rewriter.cc

Issue 248343002: Convert chromeos::EventRewriter to a ui::EventRewriter (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@x354034-kder
Patch Set: Restore XI2 monitoring for device IDs. Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 #include "chrome/browser/chromeos/events/event_rewriter.h" 5 #include "chrome/browser/chromeos/events/event_rewriter.h"
6 6
7 #if defined(USE_X11)
7 #include <X11/extensions/XInput2.h> 8 #include <X11/extensions/XInput2.h>
8 #include <X11/keysym.h>
9 #include <X11/XF86keysym.h>
10 #include <X11/Xlib.h> 9 #include <X11/Xlib.h>
11 // Get rid of macros from Xlib.h that conflicts with other parts of the code. 10 // Get rid of macros from Xlib.h that conflicts with other parts of the code.
12 #undef RootWindow 11 #undef RootWindow
13 #undef Status 12 #undef Status
13 #endif
sadrul 2014/04/25 13:53:27 Conditional includes usually go at the end of the
14 14
15 #include <vector> 15 #include <vector>
16 16
17 #include "ash/wm/window_state.h" 17 #include "ash/wm/window_state.h"
18 #include "ash/wm/window_util.h" 18 #include "ash/wm/window_util.h"
19 #include "base/command_line.h" 19 #include "base/command_line.h"
20 #include "base/logging.h" 20 #include "base/logging.h"
21 #include "base/prefs/pref_service.h" 21 #include "base/prefs/pref_service.h"
22 #include "base/strings/string_util.h" 22 #include "base/strings/string_util.h"
23 #include "base/sys_info.h" 23 #include "base/sys_info.h"
24 #include "chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener .h"
25 #include "chrome/browser/chromeos/login/login_display_host_impl.h" 24 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
26 #include "chrome/browser/chromeos/login/user_manager.h" 25 #include "chrome/browser/chromeos/login/user_manager.h"
27 #include "chrome/browser/profiles/profile_manager.h" 26 #include "chrome/browser/profiles/profile_manager.h"
28 #include "chrome/common/pref_names.h" 27 #include "chrome/common/pref_names.h"
29 #include "chromeos/chromeos_switches.h" 28 #include "chromeos/chromeos_switches.h"
30 #include "chromeos/ime/ime_keyboard.h" 29 #include "chromeos/ime/ime_keyboard.h"
31 #include "chromeos/ime/input_method_manager.h" 30 #include "chromeos/ime/input_method_manager.h"
32 #include "ui/base/x/x11_util.h"
33 #include "ui/events/event.h" 31 #include "ui/events/event.h"
34 #include "ui/events/event_utils.h" 32 #include "ui/events/event_utils.h"
35 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
36 #include "ui/events/platform/platform_event_source.h" 33 #include "ui/events/platform/platform_event_source.h"
37 #include "ui/wm/core/window_util.h" 34 #include "ui/wm/core/window_util.h"
38 35
36 #if defined(USE_X11)
37 #include "chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener .h"
38 #include "ui/base/x/x11_util.h"
39 #endif
40
41 namespace chromeos {
42
39 namespace { 43 namespace {
40 44
41 const int kBadDeviceId = -1; 45 const int kBadDeviceId = -1;
42 46
43 // A key code and a flag we should use when a key is remapped to |remap_to|. 47 // Table of key properties of remappable keys and/or remapping targets.
48 // This is searched in two distinct ways:
49 // - |remap_to| is an |input_method::ModifierKey|, which is the form
50 // held in user preferences. |GetRemappedKey()| maps this to the
51 // corresponding |key_code| and characterstic event |flag|.
52 // - |flag| is a |ui::EventFlags|. |GetRemappedModifierMasks()| maps this
53 // to the corresponding user preference |pref_name| for that flag's
54 // key, so that it can then be remapped as above.
55 // In addition |kModifierRemappingCtrl| is a direct reference to the
56 // Control key entry in the table, used in handling Chromebook Diamond
57 // and Apple Command keys.
44 const struct ModifierRemapping { 58 const struct ModifierRemapping {
45 int remap_to; 59 int remap_to;
46 int flag; 60 int flag;
47 unsigned int native_modifier; 61 ui::KeyboardCode key_code;
48 ui::KeyboardCode keycode; 62 const char* pref_name;
49 KeySym native_keysyms[4]; // left, right, shift+left, shift+right.
50 } kModifierRemappings[] = { 63 } kModifierRemappings[] = {
51 { chromeos::input_method::kSearchKey, 0, Mod4Mask, ui::VKEY_LWIN, 64 { input_method::kSearchKey,
52 { XK_Super_L, XK_Super_L, XK_Super_L, XK_Super_L }}, 65 ui::EF_COMMAND_DOWN, ui::VKEY_LWIN,
53 { chromeos::input_method::kControlKey, ui::EF_CONTROL_DOWN, ControlMask, 66 prefs::kLanguageRemapSearchKeyTo },
54 ui::VKEY_CONTROL, 67 { input_method::kControlKey,
55 { XK_Control_L, XK_Control_R, XK_Control_L, XK_Control_R }}, 68 ui::EF_CONTROL_DOWN, ui::VKEY_CONTROL,
56 { chromeos::input_method::kAltKey, ui::EF_ALT_DOWN, Mod1Mask, 69 prefs::kLanguageRemapControlKeyTo },
57 ui::VKEY_MENU, { XK_Alt_L, XK_Alt_R, XK_Meta_L, XK_Meta_R }}, 70 { input_method::kAltKey,
58 { chromeos::input_method::kVoidKey, 0, 0U, ui::VKEY_UNKNOWN, 71 ui::EF_ALT_DOWN, ui::VKEY_MENU,
59 { XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol }}, 72 prefs::kLanguageRemapAltKeyTo },
60 { chromeos::input_method::kCapsLockKey, 0, 0U, ui::VKEY_CAPITAL, 73 { input_method::kVoidKey,
61 { XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock }}, 74 0, ui::VKEY_UNKNOWN,
62 { chromeos::input_method::kEscapeKey, 0, 0U, ui::VKEY_ESCAPE, 75 NULL },
63 { XK_Escape, XK_Escape, XK_Escape, XK_Escape }}, 76 { input_method::kCapsLockKey,
77 ui::EF_CAPS_LOCK_DOWN, ui::VKEY_CAPITAL,
78 prefs::kLanguageRemapCapsLockKeyTo },
79 { input_method::kEscapeKey,
80 0, ui::VKEY_ESCAPE,
81 NULL },
82 { 0,
83 0, ui::VKEY_F15,
84 prefs::kLanguageRemapDiamondKeyTo },
64 }; 85 };
65 86
66 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1]; 87 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1];
67 88
68 // A structure for converting |native_modifier| to a pair of |flag| and
69 // |pref_name|.
70 const struct ModifierFlagToPrefName {
71 unsigned int native_modifier;
72 int flag;
73 const char* pref_name;
74 } kModifierFlagToPrefName[] = {
75 // TODO(yusukes): When the device has a Chrome keyboard (i.e. the one without
76 // Caps Lock), we should not check kLanguageRemapCapsLockKeyTo.
77 { Mod3Mask, 0, prefs::kLanguageRemapCapsLockKeyTo },
78 { Mod4Mask, 0, prefs::kLanguageRemapSearchKeyTo },
79 { ControlMask, ui::EF_CONTROL_DOWN, prefs::kLanguageRemapControlKeyTo },
80 { Mod1Mask, ui::EF_ALT_DOWN, prefs::kLanguageRemapAltKeyTo },
81 { Mod2Mask, 0, prefs::kLanguageRemapDiamondKeyTo },
82 };
83
84 // Gets a remapped key for |pref_name| key. For example, to find out which 89 // Gets a remapped key for |pref_name| key. For example, to find out which
85 // key Search is currently remapped to, call the function with 90 // key Search is currently remapped to, call the function with
86 // prefs::kLanguageRemapSearchKeyTo. 91 // prefs::kLanguageRemapSearchKeyTo.
87 const ModifierRemapping* GetRemappedKey(const std::string& pref_name, 92 const ModifierRemapping* GetRemappedKey(const std::string& pref_name,
88 const PrefService& pref_service) { 93 const PrefService& pref_service) {
89 if (!pref_service.FindPreference(pref_name.c_str())) 94 if (!pref_service.FindPreference(pref_name.c_str()))
90 return NULL; // The |pref_name| hasn't been registered. On login screen? 95 return NULL; // The |pref_name| hasn't been registered. On login screen?
91 const int value = pref_service.GetInteger(pref_name.c_str()); 96 const int value = pref_service.GetInteger(pref_name.c_str());
92 for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) { 97 for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
93 if (value == kModifierRemappings[i].remap_to) 98 if (value == kModifierRemappings[i].remap_to)
94 return &kModifierRemappings[i]; 99 return &kModifierRemappings[i];
95 } 100 }
96 return NULL; 101 return NULL;
97 } 102 }
98 103
99 bool IsRight(KeySym native_keysym) {
100 switch (native_keysym) {
101 case XK_Alt_R:
102 case XK_Control_R:
103 case XK_Hyper_R:
104 case XK_Meta_R:
105 case XK_Shift_R:
106 case XK_Super_R:
107 return true;
108 default:
109 break;
110 }
111 return false;
112 }
113
114 bool HasDiamondKey() {
115 return CommandLine::ForCurrentProcess()->HasSwitch(
116 chromeos::switches::kHasChromeOSDiamondKey);
117 }
118
119 bool IsISOLevel5ShiftUsedByCurrentInputMethod() { 104 bool IsISOLevel5ShiftUsedByCurrentInputMethod() {
120 // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask, 105 // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask,
121 // it's not possible to make both features work. For now, we don't remap 106 // it's not possible to make both features work. For now, we don't remap
122 // Mod3Mask when Neo2 is in use. 107 // Mod3Mask when Neo2 is in use.
123 // TODO(yusukes): Remove the restriction. 108 // TODO(yusukes): Remove the restriction.
124 chromeos::input_method::InputMethodManager* manager = 109 input_method::InputMethodManager* manager =
125 chromeos::input_method::InputMethodManager::Get(); 110 input_method::InputMethodManager::Get();
126 return manager->IsISOLevel5ShiftUsedByCurrentInputMethod(); 111 return manager->IsISOLevel5ShiftUsedByCurrentInputMethod();
127 } 112 }
128 113
114 EventRewriter::DeviceType GetDeviceType(
115 const std::string& device_name) {
116 std::vector<std::string> tokens;
117 Tokenize(device_name, " .", &tokens);
118
119 // If the |device_name| contains the two words, "apple" and "keyboard", treat
120 // it as an Apple keyboard.
121 bool found_apple = false;
122 bool found_keyboard = false;
123 for (size_t i = 0; i < tokens.size(); ++i) {
124 if (!found_apple && LowerCaseEqualsASCII(tokens[i], "apple"))
125 found_apple = true;
126 if (!found_keyboard && LowerCaseEqualsASCII(tokens[i], "keyboard"))
127 found_keyboard = true;
128 if (found_apple && found_keyboard)
129 return EventRewriter::kDeviceAppleKeyboard;
130 }
131
132 return EventRewriter::kDeviceUnknown;
133 }
134
129 } // namespace 135 } // namespace
130 136
131 namespace chromeos {
132
133 EventRewriter::EventRewriter() 137 EventRewriter::EventRewriter()
134 : last_device_id_(kBadDeviceId), 138 : last_device_id_(kBadDeviceId),
135 keyboard_for_testing_(NULL), 139 ime_keyboard_for_testing_(NULL),
136 pref_service_for_testing_(NULL) { 140 pref_service_for_testing_(NULL) {
141 #if defined(USE_X11)
137 ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this); 142 ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
138 if (base::SysInfo::IsRunningOnChromeOS()) { 143 if (base::SysInfo::IsRunningOnChromeOS()) {
139 XInputHierarchyChangedEventListener::GetInstance()->AddObserver(this); 144 XInputHierarchyChangedEventListener::GetInstance()->AddObserver(this);
140 } 145 }
141 RefreshKeycodes(); 146 #endif
142 } 147 }
143 148
144 EventRewriter::~EventRewriter() { 149 EventRewriter::~EventRewriter() {
150 #if defined(USE_X11)
145 ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this); 151 ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
146 if (base::SysInfo::IsRunningOnChromeOS()) { 152 if (base::SysInfo::IsRunningOnChromeOS()) {
147 XInputHierarchyChangedEventListener::GetInstance()->RemoveObserver(this); 153 XInputHierarchyChangedEventListener::GetInstance()->RemoveObserver(this);
148 } 154 }
155 #endif
149 } 156 }
150 157
151 EventRewriter::DeviceType EventRewriter::DeviceAddedForTesting( 158 EventRewriter::DeviceType EventRewriter::DeviceAddedForTesting(
152 int device_id, 159 int device_id,
153 const std::string& device_name) { 160 const std::string& device_name) {
154 return DeviceAddedInternal(device_id, device_name); 161 return DeviceAddedInternal(device_id, device_name);
155 } 162 }
156 163
157 // static 164 void EventRewriter::RewriteLocatedEventForTesting(
158 EventRewriter::DeviceType EventRewriter::GetDeviceType( 165 const ui::Event& event,
159 const std::string& device_name) { 166 int* flags) {
160 std::vector<std::string> tokens; 167 MutableKeyState state = {*flags, ui::VKEY_UNKNOWN};
161 Tokenize(device_name, " .", &tokens); 168 RewriteLocatedEvent(event, &state);
162 169 *flags = state.flags;
163 // If the |device_name| contains the two words, "apple" and "keyboard", treat
164 // it as an Apple keyboard.
165 bool found_apple = false;
166 bool found_keyboard = false;
167 for (size_t i = 0; i < tokens.size(); ++i) {
168 if (!found_apple && LowerCaseEqualsASCII(tokens[i], "apple"))
169 found_apple = true;
170 if (!found_keyboard && LowerCaseEqualsASCII(tokens[i], "keyboard"))
171 found_keyboard = true;
172 if (found_apple && found_keyboard)
173 return kDeviceAppleKeyboard;
174 }
175
176 return kDeviceUnknown;
177 } 170 }
178 171
179 void EventRewriter::RewriteForTesting(XEvent* event) { 172 ui::EventRewriteStatus EventRewriter::RewriteEvent(
180 Rewrite(event); 173 const ui::Event& event,
174 scoped_ptr<ui::Event>* rewritten_event) {
175 switch (event.type()) {
176 case ui::ET_KEY_PRESSED:
177 case ui::ET_KEY_RELEASED: {
178 const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event);
179 MutableKeyState state = {key_event.flags(), key_event.key_code()};
180 RewriteModifierKeys(key_event, &state);
181 RewriteNumPadKeys(key_event, &state);
182 RewriteExtendedKeys(key_event, &state);
183 RewriteFunctionKeys(key_event, &state);
184 if ((key_event.flags() != state.flags) ||
185 (key_event.key_code() != state.key_code)) {
186 ui::KeyEvent* rewritten_key_event = new ui::KeyEvent(key_event);
187 rewritten_event->reset(rewritten_key_event);
188 rewritten_key_event->set_flags(state.flags);
189 rewritten_key_event->set_key_code(state.key_code);
190 return ui::EVENT_REWRITE_REWRITTEN;
191 }
192 return ui::EVENT_REWRITE_CONTINUE;
193 }
194 case ui::ET_MOUSE_PRESSED:
195 case ui::ET_MOUSE_RELEASED:
196 case ui::ET_TOUCH_PRESSED:
197 case ui::ET_TOUCH_RELEASED: {
198 MutableKeyState state = {event.flags(), ui::VKEY_UNKNOWN};
199 RewriteLocatedEvent(event, &state);
200 if (event.flags() != state.flags) {
201 if (event.IsMouseEvent()) {
202 rewritten_event->reset(
203 new ui::MouseEvent(static_cast<const ui::MouseEvent&>(event)));
204 } else {
205 rewritten_event->reset(
206 new ui::TouchEvent(static_cast<const ui::TouchEvent&>(event)));
207 }
208 rewritten_event->get()->set_flags(state.flags);
209 return ui::EVENT_REWRITE_REWRITTEN;
210 }
211 return ui::EVENT_REWRITE_CONTINUE;
212 }
213 default: {
Daniel Erat 2014/04/24 17:15:15 nit: don't need curly brackets for this one
214 return ui::EVENT_REWRITE_CONTINUE;
215 }
216 }
217 NOTREACHED();
181 } 218 }
182 219
220 ui::EventRewriteStatus EventRewriter::NextDispatchEvent(
221 const ui::Event& last_event,
222 scoped_ptr<ui::Event>* new_event) {
223 NOTREACHED();
224 return ui::EVENT_REWRITE_CONTINUE;
225 }
226
227 #if defined(USE_X11)
183 void EventRewriter::DeviceKeyPressedOrReleased(int device_id) { 228 void EventRewriter::DeviceKeyPressedOrReleased(int device_id) {
184 std::map<int, DeviceType>::const_iterator iter = 229 std::map<int, DeviceType>::const_iterator iter =
185 device_id_to_type_.find(device_id); 230 device_id_to_type_.find(device_id);
186 if (iter == device_id_to_type_.end()) { 231 if (iter == device_id_to_type_.end()) {
Daniel Erat 2014/04/24 17:15:15 nit: can just shorten this to: if (!device_id_t
187 // |device_id| is unknown. This means the device was connected before 232 // |device_id| is unknown. This means the device was connected before
188 // booting the OS. Query the name of the device and add it to the map. 233 // booting the OS. Query the name of the device and add it to the map.
189 DeviceAdded(device_id); 234 DeviceAdded(device_id);
190 } 235 }
191
192 last_device_id_ = device_id; 236 last_device_id_ = device_id;
193 } 237 }
238 #endif
194 239
195 void EventRewriter::WillProcessEvent(const ui::PlatformEvent& event) { 240 const PrefService* EventRewriter::GetPrefService() const {
196 XEvent* xevent = event; 241 if (pref_service_for_testing_)
197 if (xevent->type == KeyPress || xevent->type == KeyRelease) { 242 return pref_service_for_testing_;
198 Rewrite(xevent); 243 Profile* profile = ProfileManager::GetActiveUserProfile();
199 } else if (xevent->type == GenericEvent) { 244 return profile ? profile->GetPrefs() : NULL;
200 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
201 if (xievent->evtype == XI_KeyPress || xievent->evtype == XI_KeyRelease) {
202 if (xievent->deviceid == xievent->sourceid)
203 DeviceKeyPressedOrReleased(xievent->deviceid);
204 } else {
205 RewriteLocatedEvent(xevent);
206 }
207 } else if (xevent->type == MappingNotify) {
208 if (xevent->xmapping.request == MappingModifier ||
209 xevent->xmapping.request == MappingKeyboard) {
210 RefreshKeycodes();
211 }
212 }
213 } 245 }
214 246
215 void EventRewriter::DidProcessEvent(const ui::PlatformEvent& event) { 247 bool EventRewriter::IsAppleKeyboard(const ui::Event& event) const {
248 if (last_device_id_ == kBadDeviceId)
249 return false;
250
251 // Check which device generated |event|.
252 std::map<int, DeviceType>::const_iterator iter =
253 device_id_to_type_.find(last_device_id_);
254 if (iter == device_id_to_type_.end()) {
sadrul 2014/04/25 13:53:27 You can use .count() here too
255 LOG(ERROR) << "Device ID " << last_device_id_ << " is unknown.";
256 return false;
257 }
258
259 const DeviceType type = iter->second;
260 return type == kDeviceAppleKeyboard;
216 } 261 }
217 262
218 void EventRewriter::DeviceHierarchyChanged() {}
219 263
220 void EventRewriter::DeviceAdded(int device_id) { 264 bool EventRewriter::HasDiamondKey(const ui::Event& event) const {
sadrul 2014/04/25 13:53:27 Does this really need |event| to be passed in? Can
221 DCHECK_NE(XIAllDevices, device_id); 265 return CommandLine::ForCurrentProcess()->HasSwitch(
222 DCHECK_NE(XIAllMasterDevices, device_id); 266 chromeos::switches::kHasChromeOSDiamondKey);
223 if (device_id == XIAllDevices || device_id == XIAllMasterDevices) {
224 LOG(ERROR) << "Unexpected device_id passed: " << device_id;
225 return;
226 }
227
228 int ndevices_return = 0;
229 XIDeviceInfo* device_info = XIQueryDevice(gfx::GetXDisplay(),
230 device_id,
231 &ndevices_return);
232
233 // Since |device_id| is neither XIAllDevices nor XIAllMasterDevices,
234 // the number of devices found should be either 0 (not found) or 1.
235 if (!device_info) {
236 LOG(ERROR) << "XIQueryDevice: Device ID " << device_id << " is unknown.";
237 return;
238 }
239
240 DCHECK_EQ(1, ndevices_return);
241 for (int i = 0; i < ndevices_return; ++i) {
242 DCHECK_EQ(device_id, device_info[i].deviceid); // see the comment above.
243 DCHECK(device_info[i].name);
244 DeviceAddedInternal(device_info[i].deviceid, device_info[i].name);
245 }
246
247 XIFreeDeviceInfo(device_info);
248 } 267 }
249 268
250 void EventRewriter::DeviceRemoved(int device_id) { 269 bool EventRewriter::TopRowKeysAreFunctionKeys(
251 device_id_to_type_.erase(device_id); 270 const ui::Event& event) const {
252 }
253
254 void EventRewriter::RefreshKeycodes() {
255 keysym_to_keycode_map_.clear();
256 }
257
258 KeyCode EventRewriter::NativeKeySymToNativeKeycode(KeySym keysym) {
259 if (keysym_to_keycode_map_.count(keysym))
260 return keysym_to_keycode_map_[keysym];
261
262 XDisplay* display = gfx::GetXDisplay();
263 KeyCode keycode = XKeysymToKeycode(display, keysym);
264 keysym_to_keycode_map_[keysym] = keycode;
265 return keycode;
266 }
267
268 bool EventRewriter::TopRowKeysAreFunctionKeys(XEvent* event) const {
269 const PrefService* prefs = GetPrefService(); 271 const PrefService* prefs = GetPrefService();
270 if (prefs && 272 if (prefs &&
271 prefs->FindPreference(prefs::kLanguageSendFunctionKeys) && 273 prefs->FindPreference(prefs::kLanguageSendFunctionKeys) &&
272 prefs->GetBoolean(prefs::kLanguageSendFunctionKeys)) 274 prefs->GetBoolean(prefs::kLanguageSendFunctionKeys))
273 return true; 275 return true;
274 276
275 ash::wm::WindowState* state = ash::wm::GetActiveWindowState(); 277 ash::wm::WindowState* state = ash::wm::GetActiveWindowState();
276 return state ? state->top_row_keys_are_function_keys() : false; 278 return state ? state->top_row_keys_are_function_keys() : false;
277 } 279 }
278 280
279 bool EventRewriter::RewriteWithKeyboardRemappingsByKeySym( 281 int EventRewriter::GetRemappedModifierMasks(
280 const KeyboardRemapping* remappings, 282 const PrefService& pref_service,
281 size_t num_remappings, 283 const ui::Event& event,
282 KeySym keysym, 284 int original_flags) const {
283 unsigned int native_mods, 285 int unmodified_flags = original_flags;
284 KeySym* remapped_native_keysym, 286 int rewritten_flags = 0;
285 unsigned int* remapped_native_mods) { 287 for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
sadrul 2014/04/25 13:53:27 you need to iterate only as long as unmodified_fla
286 for (size_t i = 0; i < num_remappings; ++i) { 288 const ModifierRemapping* remapped_key = 0;
287 const KeyboardRemapping& map = remappings[i]; 289 if (unmodified_flags & kModifierRemappings[i].flag) {
sadrul 2014/04/25 13:53:27 change this to continue instead.
288 290 switch (kModifierRemappings[i].flag) {
289 if (keysym != map.input_keysym) 291 case ui::EF_COMMAND_DOWN:
290 continue; 292 // Rewrite Command key presses on an Apple keyboard to Control.
291 unsigned int matched_mods = native_mods & map.input_native_mods; 293 if (IsAppleKeyboard(event)) {
292 if (matched_mods != map.input_native_mods) 294 DCHECK_EQ(ui::EF_CONTROL_DOWN, kModifierRemappingCtrl->flag);
293 continue; 295 remapped_key = kModifierRemappingCtrl;
294 296 }
295 *remapped_native_keysym = map.output_keysym; 297 break;
296 *remapped_native_mods = (native_mods & ~map.input_native_mods) | 298 case ui::EF_CAPS_LOCK_DOWN:
297 map.output_native_mods; 299 // If CapsLock is used by the current input method, don't allow the
298 return true; 300 // CapsLock pref to remap it, or the keyboard behavior will be broken.
301 if (IsISOLevel5ShiftUsedByCurrentInputMethod())
302 continue;
303 break;
304 default:
305 break;
306 }
307 if (!remapped_key && kModifierRemappings[i].pref_name) {
308 remapped_key =
309 GetRemappedKey(kModifierRemappings[i].pref_name, pref_service);
310 }
311 if (remapped_key) {
312 unmodified_flags &= ~kModifierRemappings[i].flag;
313 rewritten_flags |= remapped_key->flag;
314 }
315 }
299 } 316 }
300 317 return rewritten_flags | unmodified_flags;
301 return false;
302 } 318 }
303 319
304 bool EventRewriter::RewriteWithKeyboardRemappingsByKeyCode( 320 bool EventRewriter::RewriteWithKeyboardRemappingsByKeyCode(
305 const KeyboardRemapping* remappings, 321 const KeyboardRemapping* remappings,
306 size_t num_remappings, 322 size_t num_remappings,
307 KeyCode keycode, 323 const MutableKeyState& input,
308 unsigned int native_mods, 324 MutableKeyState* remapped_state) {
309 KeySym* remapped_native_keysym,
310 unsigned int* remapped_native_mods) {
311 for (size_t i = 0; i < num_remappings; ++i) { 325 for (size_t i = 0; i < num_remappings; ++i) {
312 const KeyboardRemapping& map = remappings[i]; 326 const KeyboardRemapping& map = remappings[i];
313 327 if (input.key_code != map.input_key_code)
314 KeyCode input_keycode = NativeKeySymToNativeKeycode(map.input_keysym);
315 if (keycode != input_keycode)
316 continue; 328 continue;
317 unsigned int matched_mods = native_mods & map.input_native_mods; 329 if ((input.flags & map.input_flags) != map.input_flags)
318 if (matched_mods != map.input_native_mods)
319 continue; 330 continue;
320 331 remapped_state->key_code = map.output_key_code;
321 *remapped_native_keysym = map.output_keysym; 332 remapped_state->flags = (input.flags & ~map.input_flags) | map.output_flags;
322 *remapped_native_mods = (native_mods & ~map.input_native_mods) |
323 map.output_native_mods;
324 return true; 333 return true;
325 } 334 }
326
327 return false; 335 return false;
328 } 336 }
329 337
330 const PrefService* EventRewriter::GetPrefService() const { 338 void EventRewriter::RewriteModifierKeys(
331 if (pref_service_for_testing_) 339 const ui::KeyEvent& key_event,
332 return pref_service_for_testing_; 340 MutableKeyState* state) {
333 Profile* profile = ProfileManager::GetActiveUserProfile(); 341 DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
334 return profile ? profile->GetPrefs() : NULL; 342 key_event.type() == ui::ET_KEY_RELEASED);
335 }
336 343
337 void EventRewriter::Rewrite(XEvent* event) {
338 // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
339 // crbug.com/136465.
340 if (event->xkey.send_event)
341 return;
342
343 RewriteModifiers(event);
344 RewriteNumPadKeys(event);
345 RewriteExtendedKeys(event);
346 RewriteFunctionKeys(event);
347 }
348
349 bool EventRewriter::IsAppleKeyboard() const {
350 if (last_device_id_ == kBadDeviceId)
351 return false;
352
353 // Check which device generated |event|.
354 std::map<int, DeviceType>::const_iterator iter =
355 device_id_to_type_.find(last_device_id_);
356 if (iter == device_id_to_type_.end()) {
357 LOG(ERROR) << "Device ID " << last_device_id_ << " is unknown.";
358 return false;
359 }
360
361 const DeviceType type = iter->second;
362 return type == kDeviceAppleKeyboard;
363 }
364
365 void EventRewriter::GetRemappedModifierMasks(
366 unsigned int original_native_modifiers,
367 unsigned int* remapped_native_modifiers) const {
368 // TODO(glotov): remove the following condition when we do not restart chrome
369 // when user logs in as guest. See Rewrite() for details.
370 if (UserManager::Get()->IsLoggedInAsGuest() &&
371 LoginDisplayHostImpl::default_host()) {
372 return;
373 }
374
375 const PrefService* pref_service = GetPrefService();
376 if (!pref_service)
377 return;
378
379 // When a diamond key is not available, a Mod2Mask should not treated as a
380 // configurable modifier because Mod2Mask may be worked as NumLock mask.
381 // (cf. http://crbug.com/173956)
382 const bool skip_mod2 = !HasDiamondKey();
383 // If Mod3 is used by the current input method, don't allow the CapsLock
384 // pref to remap it, or the keyboard behavior will be broken.
385 const bool skip_mod3 = IsISOLevel5ShiftUsedByCurrentInputMethod();
386
387 for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) {
388 if ((skip_mod2 && kModifierFlagToPrefName[i].native_modifier == Mod2Mask) ||
389 (skip_mod3 && kModifierFlagToPrefName[i].native_modifier == Mod3Mask)) {
390 continue;
391 }
392 if (original_native_modifiers &
393 kModifierFlagToPrefName[i].native_modifier) {
394 const ModifierRemapping* remapped_key =
395 GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service);
396 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R.
397 if (IsAppleKeyboard() &&
398 (kModifierFlagToPrefName[i].native_modifier == Mod4Mask)) {
399 remapped_key = kModifierRemappingCtrl;
400 }
401 if (remapped_key) {
402 *remapped_native_modifiers |= remapped_key->native_modifier;
403 } else {
404 *remapped_native_modifiers |=
405 kModifierFlagToPrefName[i].native_modifier;
406 }
407 }
408 }
409
410 unsigned int native_mask = Mod4Mask | ControlMask | Mod1Mask;
411 if (!skip_mod2)
412 native_mask |= Mod2Mask;
413 if (!skip_mod3)
414 native_mask |= Mod3Mask;
415 *remapped_native_modifiers =
416 (original_native_modifiers & ~native_mask) |
417 *remapped_native_modifiers;
418 }
419
420 bool EventRewriter::RewriteModifiers(XEvent* event) {
421 DCHECK(event->type == KeyPress || event->type == KeyRelease);
422 // Do nothing if we have just logged in as guest but have not restarted chrome 344 // Do nothing if we have just logged in as guest but have not restarted chrome
423 // process yet (so we are still on the login screen). In this situations we 345 // process yet (so we are still on the login screen). In this situations we
424 // have no user profile so can not do anything useful. 346 // have no user profile so can not do anything useful.
425 // Note that currently, unlike other accounts, when user logs in as guest, we 347 // Note that currently, unlike other accounts, when user logs in as guest, we
426 // restart chrome process. In future this is to be changed. 348 // restart chrome process. In future this is to be changed.
427 // TODO(glotov): remove the following condition when we do not restart chrome 349 // TODO(glotov): remove the following condition when we do not restart chrome
428 // when user logs in as guest. 350 // when user logs in as guest.
351 // TODO(kpschoedel): check whether this is still necessary.
429 if (UserManager::Get()->IsLoggedInAsGuest() && 352 if (UserManager::Get()->IsLoggedInAsGuest() &&
430 LoginDisplayHostImpl::default_host()) 353 LoginDisplayHostImpl::default_host())
431 return false; 354 return;
432 355
433 const PrefService* pref_service = GetPrefService(); 356 const PrefService* pref_service = GetPrefService();
434 if (!pref_service) 357 if (!pref_service)
435 return false; 358 return;
436 359
437 DCHECK_EQ(input_method::kControlKey, kModifierRemappingCtrl->remap_to); 360 MutableKeyState incoming = *state;
361 state->flags = ui::EF_NONE;
362 int characteristic_flag = ui::EF_NONE;
438 363
439 XKeyEvent* xkey = &event->xkey; 364 // First, remap the key code.
440 KeySym keysym = XLookupKeysym(xkey, 0);
441 ui::KeyboardCode original_keycode = ui::KeyboardCodeFromNative(event);
442 ui::KeyboardCode remapped_keycode = original_keycode;
443 KeyCode remapped_native_keycode = xkey->keycode;
444
445 // First, remap |keysym|.
446 const ModifierRemapping* remapped_key = NULL; 365 const ModifierRemapping* remapped_key = NULL;
447 switch (keysym) { 366 switch (incoming.key_code) {
448 // On Chrome OS, XF86XK_Launch6 (F15) with Mod2Mask is sent when Diamond 367 // On Chrome OS, F15 (XF86XK_Launch6) with NumLock (Mod2Mask) is sent
449 // key is pressed. 368 // when Diamond key is pressed.
450 case XF86XK_Launch6: 369 case ui::VKEY_F15:
451 // When diamond key is not available, the configuration UI for Diamond 370 // When diamond key is not available, the configuration UI for Diamond
452 // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo 371 // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo
453 // syncable pref. 372 // syncable pref.
454 if (HasDiamondKey()) 373 if (HasDiamondKey(key_event))
455 remapped_key = 374 remapped_key =
456 GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo, *pref_service); 375 GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo, *pref_service);
457 // Default behavior is Ctrl key. 376 // Default behavior is Ctrl key.
458 if (!remapped_key) 377 if (!remapped_key) {
378 DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code);
459 remapped_key = kModifierRemappingCtrl; 379 remapped_key = kModifierRemappingCtrl;
380 characteristic_flag = ui::EF_CONTROL_DOWN;
381 }
460 break; 382 break;
461 // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock 383 // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock
462 // is pressed (with one exception: when 384 // is pressed (with one exception: when
463 // IsISOLevel5ShiftUsedByCurrentInputMethod() is true, the key generates 385 // IsISOLevel5ShiftUsedByCurrentInputMethod() is true, the key generates
464 // XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7). 386 // XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7).
465 case XF86XK_Launch7: 387 case ui::VKEY_F16:
388 characteristic_flag = ui::EF_CAPS_LOCK_DOWN;
466 remapped_key = 389 remapped_key =
467 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service); 390 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service);
468 break; 391 break;
469 case XK_Super_L: 392 case ui::VKEY_LWIN:
470 case XK_Super_R: 393 case ui::VKEY_RWIN:
471 // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R. 394 characteristic_flag = ui::EF_COMMAND_DOWN;
472 if (IsAppleKeyboard()) 395 // Rewrite Command-L/R key presses on an Apple keyboard to Control.
396 if (IsAppleKeyboard(key_event)) {
397 DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code);
473 remapped_key = kModifierRemappingCtrl; 398 remapped_key = kModifierRemappingCtrl;
474 else 399 } else {
475 remapped_key = 400 remapped_key =
476 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service); 401 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service);
402 }
477 // Default behavior is Super key, hence don't remap the event if the pref 403 // Default behavior is Super key, hence don't remap the event if the pref
478 // is unavailable. 404 // is unavailable.
479 break; 405 break;
480 case XK_Control_L: 406 case ui::VKEY_CONTROL:
481 case XK_Control_R: 407 characteristic_flag = ui::EF_CONTROL_DOWN;
482 remapped_key = 408 remapped_key =
483 GetRemappedKey(prefs::kLanguageRemapControlKeyTo, *pref_service); 409 GetRemappedKey(prefs::kLanguageRemapControlKeyTo, *pref_service);
484 break; 410 break;
485 case XK_Alt_L: 411 case ui::VKEY_MENU:
486 case XK_Alt_R: 412 // ALT key
487 case XK_Meta_L: 413 characteristic_flag = ui::EF_ALT_DOWN;
488 case XK_Meta_R:
489 remapped_key = 414 remapped_key =
490 GetRemappedKey(prefs::kLanguageRemapAltKeyTo, *pref_service); 415 GetRemappedKey(prefs::kLanguageRemapAltKeyTo, *pref_service);
491 break; 416 break;
492 default: 417 default:
493 break; 418 break;
494 } 419 }
495 420
496 if (remapped_key) { 421 if (remapped_key) {
497 int flags = ui::EventFlagsFromNative(event); 422 state->key_code = remapped_key->key_code;
498 remapped_keycode = remapped_key->keycode; 423 incoming.flags |= characteristic_flag;
499 const size_t level = ((flags & ui::EF_SHIFT_DOWN) ? (1 << 1) : 0) + 424 characteristic_flag = remapped_key->flag;
500 (IsRight(keysym) ? (1 << 0) : 0);
501 const KeySym native_keysym = remapped_key->native_keysyms[level];
502 remapped_native_keycode = NativeKeySymToNativeKeycode(native_keysym);
503 } 425 }
504 426
505 // Next, remap modifier bits. 427 // Next, remap modifier bits.
506 unsigned int remapped_native_modifiers = 0U; 428 state->flags |=
507 GetRemappedModifierMasks(xkey->state, &remapped_native_modifiers); 429 GetRemappedModifierMasks(*pref_service, key_event, incoming.flags);
430 if (key_event.type() == ui::ET_KEY_PRESSED)
431 state->flags |= characteristic_flag;
432 else
433 state->flags &= ~characteristic_flag;
508 434
509 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if 435 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if
510 // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external 436 // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external
511 // keyboard is pressed) since X can handle that case. 437 // keyboard is pressed) since X can handle that case.
512 if (event->type == KeyPress && 438 if (key_event.type() == ui::ET_KEY_PRESSED &&
513 original_keycode != ui::VKEY_CAPITAL && 439 incoming.key_code != ui::VKEY_CAPITAL &&
514 remapped_keycode == ui::VKEY_CAPITAL) { 440 state->key_code == ui::VKEY_CAPITAL) {
515 input_method::ImeKeyboard* keyboard = keyboard_for_testing_ ? 441 chromeos::input_method::ImeKeyboard* ime_keyboard =
516 keyboard_for_testing_ : 442 ime_keyboard_for_testing_
517 input_method::InputMethodManager::Get()->GetImeKeyboard(); 443 ? ime_keyboard_for_testing_
518 keyboard->SetCapsLockEnabled(!keyboard->CapsLockIsEnabled()); 444 : chromeos::input_method::InputMethodManager::Get()
519 } 445 ->GetImeKeyboard();
520 446 ime_keyboard->SetCapsLockEnabled(!ime_keyboard->CapsLockIsEnabled());
521 OverwriteEvent(event, remapped_native_keycode, remapped_native_modifiers); 447 }
522 return true;
523 } 448 }
524 449
525 bool EventRewriter::RewriteNumPadKeys(XEvent* event) { 450 void EventRewriter::RewriteNumPadKeys(
526 DCHECK(event->type == KeyPress || event->type == KeyRelease); 451 const ui::KeyEvent& key_event,
452 MutableKeyState* state) {
453 DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
454 key_event.type() == ui::ET_KEY_RELEASED);
455 if (!(state->flags & ui::EF_NUMPAD_KEY))
456 return;
457 MutableKeyState incoming = *state;
458
459 static const KeyboardRemapping kNumPadRemappings[] = {
460 {
461 ui::VKEY_INSERT, ui::EF_NUMPAD_KEY,
462 ui::VKEY_NUMPAD0, ui::EF_NUMPAD_KEY
463 },
464 {
465 ui::VKEY_DELETE, ui::EF_NUMPAD_KEY,
466 ui::VKEY_DECIMAL, ui::EF_NUMPAD_KEY
467 },
468 {
469 ui::VKEY_END, ui::EF_NUMPAD_KEY,
470 ui::VKEY_NUMPAD1, ui::EF_NUMPAD_KEY
471 },
472 {
473 ui::VKEY_DOWN, ui::EF_NUMPAD_KEY,
474 ui::VKEY_NUMPAD2, ui::EF_NUMPAD_KEY
475 },
476 {
477 ui::VKEY_NEXT, ui::EF_NUMPAD_KEY,
478 ui::VKEY_NUMPAD3, ui::EF_NUMPAD_KEY
479 },
480 {
481 ui::VKEY_LEFT, ui::EF_NUMPAD_KEY,
482 ui::VKEY_NUMPAD4, ui::EF_NUMPAD_KEY
483 },
484 {
485 ui::VKEY_CLEAR, ui::EF_NUMPAD_KEY,
486 ui::VKEY_NUMPAD5, ui::EF_NUMPAD_KEY
487 },
488 {
489 ui::VKEY_RIGHT, ui::EF_NUMPAD_KEY,
490 ui::VKEY_NUMPAD6, ui::EF_NUMPAD_KEY
491 },
492 {
493 ui::VKEY_HOME, ui::EF_NUMPAD_KEY,
494 ui::VKEY_NUMPAD7, ui::EF_NUMPAD_KEY
495 },
496 {
497 ui::VKEY_UP, ui::EF_NUMPAD_KEY,
498 ui::VKEY_NUMPAD8, ui::EF_NUMPAD_KEY
499 },
500 {
501 ui::VKEY_PRIOR, ui::EF_NUMPAD_KEY,
502 ui::VKEY_NUMPAD9, ui::EF_NUMPAD_KEY
503 },
504 };
505
506 RewriteWithKeyboardRemappingsByKeyCode(
507 kNumPadRemappings,
508 arraysize(kNumPadRemappings),
509 incoming,
510 state);
511 }
512
513 void EventRewriter::RewriteExtendedKeys(
514 const ui::KeyEvent& key_event,
515 MutableKeyState* state) {
516 DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
517 key_event.type() == ui::ET_KEY_RELEASED);
518
519 MutableKeyState incoming = *state;
527 bool rewritten = false; 520 bool rewritten = false;
528 XKeyEvent* xkey = &event->xkey; 521
529 const KeySym keysym = XLookupKeysym(xkey, 0); 522 if ((incoming.flags & (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) ==
530 switch (keysym) { 523 (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) {
531 case XK_KP_Insert:
532 OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_0),
533 xkey->state | Mod2Mask);
534 rewritten = true;
535 break;
536 case XK_KP_Delete:
537 OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_Decimal),
538 xkey->state | Mod2Mask);
539 rewritten = true;
540 break;
541 case XK_KP_End:
542 OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_1),
543 xkey->state | Mod2Mask);
544 rewritten = true;
545 break;
546 case XK_KP_Down:
547 OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_2),
548 xkey->state | Mod2Mask);
549 rewritten = true;
550 break;
551 case XK_KP_Next:
552 OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_3),
553 xkey->state | Mod2Mask);
554 rewritten = true;
555 break;
556 case XK_KP_Left:
557 OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_4),
558 xkey->state | Mod2Mask);
559 rewritten = true;
560 break;
561 case XK_KP_Begin:
562 OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_5),
563 xkey->state | Mod2Mask);
564 rewritten = true;
565 break;
566 case XK_KP_Right:
567 OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_6),
568 xkey->state | Mod2Mask);
569 rewritten = true;
570 break;
571 case XK_KP_Home:
572 OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_7),
573 xkey->state | Mod2Mask);
574 rewritten = true;
575 break;
576 case XK_KP_Up:
577 OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_8),
578 xkey->state | Mod2Mask);
579 rewritten = true;
580 break;
581 case XK_KP_Prior:
582 OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_9),
583 xkey->state | Mod2Mask);
584 rewritten = true;
585 break;
586 case XK_KP_Divide:
587 case XK_KP_Multiply:
588 case XK_KP_Subtract:
589 case XK_KP_Add:
590 case XK_KP_Enter:
591 // Add Mod2Mask for consistency.
592 OverwriteEvent(event, xkey->keycode, xkey->state | Mod2Mask);
593 rewritten = true;
594 break;
595 default:
596 break;
597 }
598 return rewritten;
599 }
600
601 bool EventRewriter::RewriteExtendedKeys(XEvent* event) {
602 DCHECK(event->type == KeyPress || event->type == KeyRelease);
603 XKeyEvent* xkey = &event->xkey;
604 const KeySym keysym = XLookupKeysym(xkey, 0);
605
606 KeySym remapped_native_keysym = 0;
607 unsigned int remapped_native_mods = 0;
608 bool rewritten = false;
609
610 if (xkey->state & Mod4Mask) {
611 // Allow Search to avoid rewriting extended keys. 524 // Allow Search to avoid rewriting extended keys.
612 static const KeyboardRemapping kAvoidRemappings[] = { 525 static const KeyboardRemapping kAvoidRemappings[] = {
613 { // Alt+Backspace 526 { // Alt+Backspace
614 XK_BackSpace, Mod1Mask | Mod4Mask, 527 ui::VKEY_BACK, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
615 XK_BackSpace, Mod1Mask, 528 ui::VKEY_BACK, ui::EF_ALT_DOWN,
616 }, 529 },
617 { // Control+Alt+Up 530 { // Control+Alt+Up
618 XK_Up, Mod1Mask | ControlMask | Mod4Mask, 531 ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN |
619 XK_Up, Mod1Mask | ControlMask, 532 ui::EF_COMMAND_DOWN,
sadrul 2014/04/25 13:53:27 4-space indent? Do you mind doing a 'git cl forma
kpschoedel 2014/04/25 15:04:02 OK. I didn't do this earlier to minimize the diffs
533 ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
620 }, 534 },
621 { // Alt+Up 535 { // Alt+Up
622 XK_Up, Mod1Mask | Mod4Mask, 536 ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
623 XK_Up, Mod1Mask, 537 ui::VKEY_UP, ui::EF_ALT_DOWN,
624 }, 538 },
625 { // Control+Alt+Down 539 { // Control+Alt+Down
626 XK_Down, Mod1Mask | ControlMask | Mod4Mask, 540 ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN |
627 XK_Down, Mod1Mask | ControlMask, 541 ui::EF_COMMAND_DOWN,
542 ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
628 }, 543 },
629 { // Alt+Down 544 { // Alt+Down
630 XK_Down, Mod1Mask | Mod4Mask, 545 ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
631 XK_Down, Mod1Mask, 546 ui::VKEY_DOWN, ui::EF_ALT_DOWN,
632 } 547 }
633 }; 548 };
634 549
635 rewritten = RewriteWithKeyboardRemappingsByKeySym( 550 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
636 kAvoidRemappings, 551 kAvoidRemappings,
637 arraysize(kAvoidRemappings), 552 arraysize(kAvoidRemappings),
638 keysym, 553 incoming,
639 xkey->state, 554 state);
640 &remapped_native_keysym, 555 }
641 &remapped_native_mods); 556
642 } 557 if (!rewritten && (incoming.flags & ui::EF_COMMAND_DOWN)) {
643
644 if (!rewritten) {
645 static const KeyboardRemapping kSearchRemappings[] = { 558 static const KeyboardRemapping kSearchRemappings[] = {
646 { // Search+BackSpace -> Delete 559 { // Search+BackSpace -> Delete
647 XK_BackSpace, Mod4Mask, 560 ui::VKEY_BACK, ui::EF_COMMAND_DOWN,
648 XK_Delete, 0 561 ui::VKEY_DELETE, 0
649 }, 562 },
650 { // Search+Left -> Home 563 { // Search+Left -> Home
651 XK_Left, Mod4Mask, 564 ui::VKEY_LEFT, ui::EF_COMMAND_DOWN,
652 XK_Home, 0 565 ui::VKEY_HOME, 0
653 }, 566 },
654 { // Search+Up -> Prior (aka PageUp) 567 { // Search+Up -> Prior (aka PageUp)
655 XK_Up, Mod4Mask, 568 ui::VKEY_UP, ui::EF_COMMAND_DOWN,
656 XK_Prior, 0 569 ui::VKEY_PRIOR, 0
657 }, 570 },
658 { // Search+Right -> End 571 { // Search+Right -> End
659 XK_Right, Mod4Mask, 572 ui::VKEY_RIGHT, ui::EF_COMMAND_DOWN,
660 XK_End, 0 573 ui::VKEY_END, 0
661 }, 574 },
662 { // Search+Down -> Next (aka PageDown) 575 { // Search+Down -> Next (aka PageDown)
663 XK_Down, Mod4Mask, 576 ui::VKEY_DOWN, ui::EF_COMMAND_DOWN,
664 XK_Next, 0 577 ui::VKEY_NEXT, 0
665 }, 578 },
666 { // Search+Period -> Insert 579 { // Search+Period -> Insert
667 XK_period, Mod4Mask, 580 ui::VKEY_OEM_PERIOD, ui::EF_COMMAND_DOWN,
668 XK_Insert, 0 581 ui::VKEY_INSERT, 0
669 } 582 }
670 }; 583 };
671 584
672 rewritten = RewriteWithKeyboardRemappingsByKeySym( 585 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
673 kSearchRemappings, 586 kSearchRemappings,
674 arraysize(kSearchRemappings), 587 arraysize(kSearchRemappings),
675 keysym, 588 incoming,
676 xkey->state, 589 state);
677 &remapped_native_keysym, 590 }
678 &remapped_native_mods); 591
679 } 592 if (!rewritten && (incoming.flags & ui::EF_ALT_DOWN)) {
680
681 if (!rewritten) {
682 static const KeyboardRemapping kNonSearchRemappings[] = { 593 static const KeyboardRemapping kNonSearchRemappings[] = {
683 { // Alt+BackSpace -> Delete 594 { // Alt+BackSpace -> Delete
684 XK_BackSpace, Mod1Mask, 595 ui::VKEY_BACK, ui::EF_ALT_DOWN,
685 XK_Delete, 0 596 ui::VKEY_DELETE, 0
686 }, 597 },
687 { // Control+Alt+Up -> Home 598 { // Control+Alt+Up -> Home
688 XK_Up, Mod1Mask | ControlMask, 599 ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
689 XK_Home, 0 600 ui::VKEY_HOME, 0
690 }, 601 },
691 { // Alt+Up -> Prior (aka PageUp) 602 { // Alt+Up -> Prior (aka PageUp)
692 XK_Up, Mod1Mask, 603 ui::VKEY_UP, ui::EF_ALT_DOWN,
693 XK_Prior, 0 604 ui::VKEY_PRIOR, 0
694 }, 605 },
695 { // Control+Alt+Down -> End 606 { // Control+Alt+Down -> End
696 XK_Down, Mod1Mask | ControlMask, 607 ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
697 XK_End, 0 608 ui::VKEY_END, 0
698 }, 609 },
699 { // Alt+Down -> Next (aka PageDown) 610 { // Alt+Down -> Next (aka PageDown)
700 XK_Down, Mod1Mask, 611 ui::VKEY_DOWN, ui::EF_ALT_DOWN,
701 XK_Next, 0 612 ui::VKEY_NEXT, 0
702 } 613 }
703 }; 614 };
704 615
705 rewritten = RewriteWithKeyboardRemappingsByKeySym( 616 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
706 kNonSearchRemappings, 617 kNonSearchRemappings,
707 arraysize(kNonSearchRemappings), 618 arraysize(kNonSearchRemappings),
708 keysym, 619 incoming,
709 xkey->state, 620 state);
710 &remapped_native_keysym, 621 }
711 &remapped_native_mods);
712 }
713
714 if (!rewritten)
715 return false;
716
717 OverwriteEvent(event,
718 NativeKeySymToNativeKeycode(remapped_native_keysym),
719 remapped_native_mods);
720 return true;
721 } 622 }
722 623
723 bool EventRewriter::RewriteFunctionKeys(XEvent* event) { 624 void EventRewriter::RewriteFunctionKeys(
724 DCHECK(event->type == KeyPress || event->type == KeyRelease); 625 const ui::KeyEvent& key_event,
725 XKeyEvent* xkey = &event->xkey; 626 MutableKeyState* state) {
726 const KeySym keysym = XLookupKeysym(xkey, 0); 627 CHECK(key_event.type() == ui::ET_KEY_PRESSED ||
727 628 key_event.type() == ui::ET_KEY_RELEASED);
728 KeySym remapped_native_keysym = 0; 629 MutableKeyState incoming = *state;
729 unsigned int remapped_native_mods = 0;
730 bool rewritten = false; 630 bool rewritten = false;
731 631
732 // By default the top row (F1-F12) keys are special keys for back, forward, 632 if ((incoming.key_code >= ui::VKEY_F1) &&
733 // brightness, volume, etc. However, windows for v2 apps can optionally 633 (incoming.key_code <= ui::VKEY_F24)) {
734 // request raw function keys for these keys. 634 // By default the top row (F1-F12) keys are system keys for back, forward,
735 bool top_row_keys_are_special_keys = !TopRowKeysAreFunctionKeys(event); 635 // brightness, volume, etc. However, windows for v2 apps can optionally
736 636 // request raw function keys for these keys.
737 if ((xkey->state & Mod4Mask) && top_row_keys_are_special_keys) { 637 bool top_row_keys_are_function_keys = TopRowKeysAreFunctionKeys(key_event);
738 // Allow Search to avoid rewriting F1-F12. 638 bool search_is_pressed = (incoming.flags & ui::EF_COMMAND_DOWN) != 0;
739 static const KeyboardRemapping kFkeysToFkeys[] = { 639
740 { XK_F1, Mod4Mask, XK_F1, }, 640 // Search? Top Row Result
741 { XK_F2, Mod4Mask, XK_F2, }, 641 // ------- -------- ------
742 { XK_F3, Mod4Mask, XK_F3, }, 642 // No Fn Unchanged
743 { XK_F4, Mod4Mask, XK_F4, }, 643 // No System Fn -> System
744 { XK_F5, Mod4Mask, XK_F5, }, 644 // Yes Fn Fn -> System
745 { XK_F6, Mod4Mask, XK_F6, }, 645 // Yes System Search+Fn -> Fn
746 { XK_F7, Mod4Mask, XK_F7, }, 646 if (top_row_keys_are_function_keys == search_is_pressed) {
747 { XK_F8, Mod4Mask, XK_F8, }, 647 // Rewrite the F1-F12 keys on a Chromebook keyboard to system keys.
748 { XK_F9, Mod4Mask, XK_F9, }, 648 static const KeyboardRemapping kFkeysToSystemKeys[] = {
749 { XK_F10, Mod4Mask, XK_F10, }, 649 { ui::VKEY_F1, 0, ui::VKEY_BROWSER_BACK, 0 },
750 { XK_F11, Mod4Mask, XK_F11, }, 650 { ui::VKEY_F2, 0, ui::VKEY_BROWSER_FORWARD, 0 },
751 { XK_F12, Mod4Mask, XK_F12, }, 651 { ui::VKEY_F3, 0, ui::VKEY_BROWSER_REFRESH, 0 },
752 }; 652 { ui::VKEY_F4, 0, ui::VKEY_MEDIA_LAUNCH_APP2, 0 },
753 653 { ui::VKEY_F5, 0, ui::VKEY_MEDIA_LAUNCH_APP1, 0 },
754 rewritten = RewriteWithKeyboardRemappingsByKeySym( 654 { ui::VKEY_F6, 0, ui::VKEY_BRIGHTNESS_DOWN, 0 },
755 kFkeysToFkeys, 655 { ui::VKEY_F7, 0, ui::VKEY_BRIGHTNESS_UP, 0 },
756 arraysize(kFkeysToFkeys), 656 { ui::VKEY_F8, 0, ui::VKEY_VOLUME_MUTE, 0 },
757 keysym, 657 { ui::VKEY_F9, 0, ui::VKEY_VOLUME_DOWN, 0 },
758 xkey->state, 658 { ui::VKEY_F10, 0, ui::VKEY_VOLUME_UP, 0 },
759 &remapped_native_keysym, 659 };
760 &remapped_native_mods); 660 MutableKeyState incoming_without_command = incoming;
761 } 661 incoming_without_command.flags &= ~ui::EF_COMMAND_DOWN;
762 662 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
763 if (!rewritten) { 663 kFkeysToSystemKeys,
764 static const KeyboardRemapping kFkeysToSpecialKeys[] = { 664 arraysize(kFkeysToSystemKeys),
765 { XK_F1, 0, XF86XK_Back, 0 }, 665 incoming_without_command,
766 { XK_F2, 0, XF86XK_Forward, 0 }, 666 state);
767 { XK_F3, 0, XF86XK_Reload, 0 }, 667 } else if (search_is_pressed) {
768 { XK_F4, 0, XF86XK_LaunchB, 0 }, 668 // Allow Search to avoid rewriting F1-F12.
769 { XK_F5, 0, XF86XK_LaunchA, 0 }, 669 state->flags &= ~ui::EF_COMMAND_DOWN;
770 { XK_F6, 0, XF86XK_MonBrightnessDown, 0 }, 670 rewritten = true;
771 { XK_F7, 0, XF86XK_MonBrightnessUp, 0 },
772 { XK_F8, 0, XF86XK_AudioMute, 0 },
773 { XK_F9, 0, XF86XK_AudioLowerVolume, 0 },
774 { XK_F10, 0, XF86XK_AudioRaiseVolume, 0 },
775 };
776
777 if (top_row_keys_are_special_keys) {
778 // Rewrite the F1-F12 keys on a Chromebook keyboard to special keys.
779 rewritten = RewriteWithKeyboardRemappingsByKeySym(
780 kFkeysToSpecialKeys,
781 arraysize(kFkeysToSpecialKeys),
782 keysym,
783 xkey->state,
784 &remapped_native_keysym,
785 &remapped_native_mods);
786 } else if (xkey->state & Mod4Mask) {
787 // Use Search + F1-F12 for the special keys.
788 rewritten = RewriteWithKeyboardRemappingsByKeySym(
789 kFkeysToSpecialKeys,
790 arraysize(kFkeysToSpecialKeys),
791 keysym,
792 xkey->state & ~Mod4Mask,
793 &remapped_native_keysym,
794 &remapped_native_mods);
795 } 671 }
796 } 672 }
797 673
798 if (!rewritten && (xkey->state & Mod4Mask)) { 674 if (!rewritten && (incoming.flags & ui::EF_COMMAND_DOWN)) {
799 // Remap Search+<number> to F<number>. 675 // Remap Search+<number> to F<number>.
800 // We check the keycode here instead of the keysym, as these keys have 676 // We check the keycode here instead of the keysym, as these keys have
801 // different keysyms when modifiers are pressed, such as shift. 677 // different keysyms when modifiers are pressed, such as shift.
802 678
803 // TODO(danakj): On some i18n keyboards, these choices will be bad and we 679 // TODO(danakj): On some i18n keyboards, these choices will be bad and we
804 // should make layout-specific choices here. For eg. on a french keyboard 680 // should make layout-specific choices here. For eg. on a french keyboard
805 // "-" and "6" are the same key, so F11 will not be accessible. 681 // "-" and "6" are the same key, so F11 will not be accessible.
806 static const KeyboardRemapping kNumberKeysToFkeys[] = { 682 static const KeyboardRemapping kNumberKeysToFkeys[] = {
807 { XK_1, Mod4Mask, XK_F1, 0 }, 683 { ui::VKEY_1, ui::EF_COMMAND_DOWN, ui::VKEY_F1, 0 },
808 { XK_2, Mod4Mask, XK_F2, 0 }, 684 { ui::VKEY_2, ui::EF_COMMAND_DOWN, ui::VKEY_F2, 0 },
809 { XK_3, Mod4Mask, XK_F3, 0 }, 685 { ui::VKEY_3, ui::EF_COMMAND_DOWN, ui::VKEY_F3, 0 },
810 { XK_4, Mod4Mask, XK_F4, 0 }, 686 { ui::VKEY_4, ui::EF_COMMAND_DOWN, ui::VKEY_F4, 0 },
811 { XK_5, Mod4Mask, XK_F5, 0 }, 687 { ui::VKEY_5, ui::EF_COMMAND_DOWN, ui::VKEY_F5, 0 },
812 { XK_6, Mod4Mask, XK_F6, 0 }, 688 { ui::VKEY_6, ui::EF_COMMAND_DOWN, ui::VKEY_F6, 0 },
813 { XK_7, Mod4Mask, XK_F7, 0 }, 689 { ui::VKEY_7, ui::EF_COMMAND_DOWN, ui::VKEY_F7, 0 },
814 { XK_8, Mod4Mask, XK_F8, 0 }, 690 { ui::VKEY_8, ui::EF_COMMAND_DOWN, ui::VKEY_F8, 0 },
815 { XK_9, Mod4Mask, XK_F9, 0 }, 691 { ui::VKEY_9, ui::EF_COMMAND_DOWN, ui::VKEY_F9, 0 },
816 { XK_0, Mod4Mask, XK_F10, 0 }, 692 { ui::VKEY_0, ui::EF_COMMAND_DOWN, ui::VKEY_F10, 0 },
817 { XK_minus, Mod4Mask, XK_F11, 0 }, 693 { ui::VKEY_OEM_MINUS, ui::EF_COMMAND_DOWN, ui::VKEY_F11, 0 },
818 { XK_equal, Mod4Mask, XK_F12, 0 } 694 { ui::VKEY_OEM_PLUS, ui::EF_COMMAND_DOWN, ui::VKEY_F12, 0 }
819 }; 695 };
820
821 rewritten = RewriteWithKeyboardRemappingsByKeyCode( 696 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
822 kNumberKeysToFkeys, 697 kNumberKeysToFkeys,
823 arraysize(kNumberKeysToFkeys), 698 arraysize(kNumberKeysToFkeys),
824 xkey->keycode, 699 incoming,
825 xkey->state, 700 state);
826 &remapped_native_keysym,
827 &remapped_native_mods);
828 } 701 }
829
830 if (!rewritten)
831 return false;
832
833 OverwriteEvent(event,
834 NativeKeySymToNativeKeycode(remapped_native_keysym),
835 remapped_native_mods);
836 return true;
837 } 702 }
838 703
839 void EventRewriter::RewriteLocatedEvent(XEvent* event) { 704 void EventRewriter::RewriteLocatedEvent(
840 DCHECK_EQ(GenericEvent, event->type); 705 const ui::Event& event,
841 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event->xcookie.data); 706 MutableKeyState* state) {
842 if (xievent->evtype != XI_ButtonPress && xievent->evtype != XI_ButtonRelease) 707 const PrefService* pref_service = GetPrefService();
708 if (!pref_service)
843 return; 709 return;
844 710
845 // First, remap modifier masks. 711 // First, remap modifier masks.
846 unsigned int remapped_native_modifiers = 0U; 712 state->flags = GetRemappedModifierMasks(*pref_service, event, state->flags);
847 GetRemappedModifierMasks(xievent->mods.effective, &remapped_native_modifiers); 713
848 xievent->mods.effective = remapped_native_modifiers; 714 #if defined(USE_X11)
715 // TODO(kpschoedel): de-X11 with unified device ids from crbug.com/360377
716 XEvent* xevent = event.native_event();
717 if (xevent->type != GenericEvent)
718 return;
719 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
720 if (xievent->evtype != XI_ButtonPress && xievent->evtype != XI_ButtonRelease)
721 return;
849 722
850 // Then, remap Alt+Button1 to Button3. 723 // Then, remap Alt+Button1 to Button3.
851 if ((xievent->evtype == XI_ButtonPress || 724 if ((xievent->evtype == XI_ButtonPress ||
852 pressed_device_ids_.count(xievent->sourceid)) && 725 pressed_device_ids_.count(xievent->sourceid)) &&
853 (xievent->mods.effective & Mod1Mask) && xievent->detail == Button1) { 726 (xievent->mods.effective & Mod1Mask) && xievent->detail == Button1) {
727 state->flags &= ~(ui::EF_ALT_DOWN | ui::EF_LEFT_MOUSE_BUTTON);
728 state->flags |= ui::EF_RIGHT_MOUSE_BUTTON;
854 xievent->mods.effective &= ~Mod1Mask; 729 xievent->mods.effective &= ~Mod1Mask;
855 xievent->detail = Button3; 730 xievent->detail = Button3;
856 if (xievent->evtype == XI_ButtonRelease) { 731 if (xievent->evtype == XI_ButtonRelease) {
857 // On the release clear the left button from the existing state and the 732 // On the release clear the left button from the existing state and the
858 // mods, and set the right button. 733 // mods, and set the right button.
859 XISetMask(xievent->buttons.mask, Button3); 734 XISetMask(xievent->buttons.mask, Button3);
860 XIClearMask(xievent->buttons.mask, Button1); 735 XIClearMask(xievent->buttons.mask, Button1);
861 xievent->mods.effective &= ~Button1Mask; 736 xievent->mods.effective &= ~Button1Mask;
862 pressed_device_ids_.erase(xievent->sourceid); 737 pressed_device_ids_.erase(xievent->sourceid);
863 } else { 738 } else {
864 pressed_device_ids_.insert(xievent->sourceid); 739 pressed_device_ids_.insert(xievent->sourceid);
865 } 740 }
866 } 741 }
867 } 742 #endif // defined(USE_X11)
868
869 void EventRewriter::OverwriteEvent(XEvent* event,
870 unsigned int new_native_keycode,
871 unsigned int new_native_state) {
872 DCHECK(event->type == KeyPress || event->type == KeyRelease);
873 XKeyEvent* xkey = &event->xkey;
874 xkey->keycode = new_native_keycode;
875 xkey->state = new_native_state;
876 } 743 }
877 744
878 EventRewriter::DeviceType EventRewriter::DeviceAddedInternal( 745 EventRewriter::DeviceType EventRewriter::DeviceAddedInternal(
879 int device_id, 746 int device_id,
880 const std::string& device_name) { 747 const std::string& device_name) {
881 const DeviceType type = EventRewriter::GetDeviceType(device_name); 748 const DeviceType type = GetDeviceType(device_name);
882 if (type == kDeviceAppleKeyboard) { 749 if (type == kDeviceAppleKeyboard) {
883 VLOG(1) << "Apple keyboard '" << device_name << "' connected: " 750 VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
884 << "id=" << device_id; 751 << "id=" << device_id;
885 } 752 }
886 // Always overwrite the existing device_id since the X server may reuse a 753 // Always overwrite the existing device_id since the X server may reuse a
887 // device id for an unattached device. 754 // device id for an unattached device.
888 device_id_to_type_[device_id] = type; 755 device_id_to_type_[device_id] = type;
889 return type; 756 return type;
890 } 757 }
891 758
759 #if defined(USE_X11)
760 void EventRewriter::WillProcessEvent(const ui::PlatformEvent& event) {
761 XEvent* xevent = event;
762 if (xevent->type == GenericEvent) {
763 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
764 if (xievent->evtype == XI_KeyPress || xievent->evtype == XI_KeyRelease) {
765 if (xievent->deviceid == xievent->sourceid)
766 DeviceKeyPressedOrReleased(xievent->deviceid);
767 }
768 }
769 }
770
771 void EventRewriter::DidProcessEvent(const ui::PlatformEvent& event) {
772 }
773
774 void EventRewriter::DeviceHierarchyChanged() {}
775
776 void EventRewriter::DeviceAdded(int device_id) {
777 DCHECK_NE(XIAllDevices, device_id);
778 DCHECK_NE(XIAllMasterDevices, device_id);
779 if (device_id == XIAllDevices || device_id == XIAllMasterDevices) {
780 LOG(ERROR) << "Unexpected device_id passed: " << device_id;
781 return;
782 }
783
784 int ndevices_return = 0;
785 XIDeviceInfo* device_info = XIQueryDevice(gfx::GetXDisplay(),
786 device_id,
787 &ndevices_return);
788
789 // Since |device_id| is neither XIAllDevices nor XIAllMasterDevices,
790 // the number of devices found should be either 0 (not found) or 1.
791 if (!device_info) {
792 LOG(ERROR) << "XIQueryDevice: Device ID " << device_id << " is unknown.";
793 return;
794 }
795
796 DCHECK_EQ(1, ndevices_return);
797 for (int i = 0; i < ndevices_return; ++i) {
798 DCHECK_EQ(device_id, device_info[i].deviceid); // see the comment above.
799 DCHECK(device_info[i].name);
800 DeviceAddedInternal(device_info[i].deviceid, device_info[i].name);
801 }
802
803 XIFreeDeviceInfo(device_info);
804 }
805
806 void EventRewriter::DeviceRemoved(int device_id) {
807 device_id_to_type_.erase(device_id);
808 }
809 #endif
810
892 } // namespace chromeos 811 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698