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

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

Issue 237363005: Convert chromeos::EventRewriter to a ui::EventRewriter (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/events/new_event_rewriter.h"
6
7 #if USE_X11
8 #include <X11/extensions/XInput2.h>
9 #include <X11/Xlib.h>
10 #endif
11 // Get rid of macros from Xlib.h that conflicts with other parts of the code.
12 #undef RootWindow
13 #undef Status
14
15 #include <vector>
16
17 #include "ash/wm/window_state.h"
18 #include "ash/wm/window_util.h"
19 #include "base/command_line.h"
20 #include "base/logging.h"
21 #include "base/prefs/pref_service.h"
22 #include "base/strings/string_util.h"
23 #include "base/sys_info.h"
24 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
25 #include "chrome/browser/chromeos/login/user_manager.h"
26 #include "chrome/browser/profiles/profile_manager.h"
27 #include "chrome/common/pref_names.h"
28 #include "chromeos/chromeos_switches.h"
29 #include "chromeos/ime/ime_keyboard.h"
30 #include "chromeos/ime/input_method_manager.h"
31 #include "ui/events/event.h"
32 #include "ui/events/event_utils.h"
33 #include "ui/events/platform/platform_event_source.h"
34 #include "ui/wm/core/window_util.h"
35
36 namespace {
37
38 const int kBadDeviceId = -1;
39
40 // A key code and a flag we should use when a key is remapped to |remap_to|.
41 const struct ModifierRemapping {
42 int remap_to;
43 int flag;
44 ui::KeyboardCode key_code;
45 const char* pref_name;
46 } kModifierRemappings[] = {
47 { chromeos::input_method::kSearchKey,
48 ui::EF_COMMAND_DOWN, ui::VKEY_LWIN,
49 prefs::kLanguageRemapSearchKeyTo },
50 { chromeos::input_method::kControlKey,
51 ui::EF_CONTROL_DOWN, ui::VKEY_CONTROL,
52 prefs::kLanguageRemapControlKeyTo },
53 { chromeos::input_method::kAltKey,
54 ui::EF_ALT_DOWN, ui::VKEY_MENU,
55 prefs::kLanguageRemapAltKeyTo },
56 { chromeos::input_method::kVoidKey,
57 0, ui::VKEY_UNKNOWN,
58 0 },
59 { chromeos::input_method::kCapsLockKey,
60 ui::EF_CAPS_LOCK_DOWN, ui::VKEY_CAPITAL,
61 prefs::kLanguageRemapCapsLockKeyTo },
62 { chromeos::input_method::kEscapeKey,
63 0, ui::VKEY_ESCAPE,
64 0 },
65 { 0,
66 0, ui::VKEY_F15,
67 prefs::kLanguageRemapDiamondKeyTo },
68 };
69
70 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1];
71
72 // Gets a remapped key for |pref_name| key. For example, to find out which
73 // key Search is currently remapped to, call the function with
74 // prefs::kLanguageRemapSearchKeyTo.
75 const ModifierRemapping* GetRemappedKey(const std::string& pref_name,
76 const PrefService& pref_service) {
77 if (!pref_service.FindPreference(pref_name.c_str()))
78 return NULL; // The |pref_name| hasn't been registered. On login screen?
79 const int value = pref_service.GetInteger(pref_name.c_str());
80 for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
81 if (value == kModifierRemappings[i].remap_to)
82 return &kModifierRemappings[i];
83 }
84 return NULL;
85 }
86
87 bool IsISOLevel5ShiftUsedByCurrentInputMethod() {
88 // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask,
89 // it's not possible to make both features work. For now, we don't remap
90 // Mod3Mask when Neo2 is in use.
91 // TODO(yusukes): Remove the restriction.
92 chromeos::input_method::InputMethodManager* manager =
93 chromeos::input_method::InputMethodManager::Get();
94 return manager->IsISOLevel5ShiftUsedByCurrentInputMethod();
95 }
96
97 struct KeyboardRemapping {
98 ui::KeyboardCode input_key_code;
99 int input_flags;
100 ui::KeyboardCode output_key_code;
101 int output_flags;
102 };
103
104 // Given a set of KeyboardRemapping structs, it finds a matching struct
105 // if possible, and updates the remapped event values. Returns true if a
106 // remapping was found and remapped values were updated.
107 bool RewriteWithKeyboardRemappingsByKeyCode(
108 const KeyboardRemapping* remappings,
109 size_t num_remappings,
110 ui::KeyboardCode input_key_code,
111 int input_flags,
112 ui::KeyboardCode* remapped_key_code,
113 int* remapped_flags) {
114 for (size_t i = 0; i < num_remappings; ++i) {
115 const KeyboardRemapping& map = remappings[i];
116 if (input_key_code != map.input_key_code)
117 continue;
118 if ((input_flags & map.input_flags) != map.input_flags)
119 continue;
120 *remapped_key_code = map.output_key_code;
121 *remapped_flags = (input_flags & ~map.input_flags) | map.output_flags;
122 return true;
123 }
124 return false;
125 }
126
127 chromeos::KeyboardEventRewriter::DeviceType GetDeviceType(
128 const std::string& device_name) {
129 std::vector<std::string> tokens;
130 Tokenize(device_name, " .", &tokens);
131
132 // If the |device_name| contains the two words, "apple" and "keyboard", treat
133 // it as an Apple keyboard.
134 bool found_apple = false;
135 bool found_keyboard = false;
136 for (size_t i = 0; i < tokens.size(); ++i) {
137 if (!found_apple && LowerCaseEqualsASCII(tokens[i], "apple"))
138 found_apple = true;
139 if (!found_keyboard && LowerCaseEqualsASCII(tokens[i], "keyboard"))
140 found_keyboard = true;
141 if (found_apple && found_keyboard)
142 return chromeos::KeyboardEventRewriter::kDeviceAppleKeyboard;
143 }
144
145 return chromeos::KeyboardEventRewriter::kDeviceUnknown;
146 }
147
148 } // namespace
149
150 namespace chromeos {
151
152 KeyboardEventRewriter::KeyboardEventRewriter()
153 : last_device_id_(kBadDeviceId),
154 ime_keyboard_for_testing_(NULL),
155 pref_service_for_testing_(NULL) {}
156
157 KeyboardEventRewriter::~KeyboardEventRewriter() {}
158
159 KeyboardEventRewriter::DeviceType KeyboardEventRewriter::DeviceAddedForTesting(
160 int device_id,
161 const std::string& device_name) {
162 return DeviceAddedInternal(device_id, device_name);
163 }
164
165 bool KeyboardEventRewriter::RewriteLocatedEventForTesting(ui::Event* event) {
166 return RewriteLocatedEvent(event);
167 }
168
169 ui::EventRewriteStatus KeyboardEventRewriter::RewriteEvent(
170 ui::Event* event,
171 scoped_ptr<ui::Event>* rewritten_event) {
172 #if USE_X11
sadrul 2014/04/14 21:51:32 chromium style is to use #if defined(USE_X11) inst
kpschoedel 2014/04/14 22:25:45 OK, I'll use that in the replacement CL. The origi
173 // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
174 // crbug.com/136465.
175 XEvent* xev = event->native_event();
176 if (xev && xev->xkey.send_event)
kpschoedel 2014/04/14 20:02:59 I don't know whether there's a plan for replacing
sadrul 2014/04/14 21:51:32 This doesn't really look right. The referenced by
177 return ui::EVENT_REWRITE_CONTINUE;
178 #endif
179
180 bool changed = false;
181 if ((event->type() == ui::ET_KEY_PRESSED) ||
182 (event->type() == ui::ET_KEY_RELEASED)) {
183 changed |= RewriteModifierKeys(event);
kpschoedel 2014/04/14 20:02:59 KeyboardDrivenEventRewriter() used to be called he
sadrul 2014/04/14 21:51:32 Yep, that sounds like a good plan, as long as the
184 changed |= RewriteNumPadKeys(event);
185 changed |= RewriteExtendedKeys(event);
kpschoedel 2014/04/14 20:02:59 RewriteStickyKeys() will be called at this point,
186 changed |= RewriteFunctionKeys(event);
187 } else if ((event->type() == ui::ET_MOUSE_PRESSED) ||
188 (event->type() == ui::ET_MOUSE_RELEASED) ||
189 (event->type() == ui::ET_TOUCH_PRESSED) ||
190 (event->type() == ui::ET_TOUCH_RELEASED)) {
191 changed |= RewriteLocatedEvent(event);
192 }
193 return changed ? ui::EVENT_REWRITE_REWRITTEN : ui::EVENT_REWRITE_CONTINUE;
194 }
195
196 ui::EventRewriteStatus KeyboardEventRewriter::NextDispatchEvent(
197 const ui::Event& last_event,
198 scoped_ptr<ui::Event>* new_event) {
199 NOTREACHED();
200 return ui::EVENT_REWRITE_CONTINUE;
201 }
202
203 const PrefService* KeyboardEventRewriter::GetPrefService() const {
204 if (pref_service_for_testing_)
205 return pref_service_for_testing_;
206 Profile* profile = ProfileManager::GetActiveUserProfile();
207 return profile ? profile->GetPrefs() : NULL;
208 }
209
210 bool KeyboardEventRewriter::IsAppleKeyboard(const ui::Event& event) const {
kpschoedel 2014/04/14 20:02:59 Passing the Event to IsAppleKeyboard() and HasDiam
211 if (last_device_id_ == kBadDeviceId)
212 return false;
213
214 // Check which device generated |event|.
215 std::map<int, DeviceType>::const_iterator iter =
216 device_id_to_type_.find(last_device_id_);
217 if (iter == device_id_to_type_.end()) {
218 LOG(ERROR) << "Device ID " << last_device_id_ << " is unknown.";
219 return false;
220 }
221
222 const DeviceType type = iter->second;
223 return type == kDeviceAppleKeyboard;
224 }
225
226
227 bool KeyboardEventRewriter::HasDiamondKey(const ui::Event& event) const {
228 return CommandLine::ForCurrentProcess()->HasSwitch(
229 chromeos::switches::kHasChromeOSDiamondKey);
230 }
231
232 bool KeyboardEventRewriter::TopRowKeysAreFunctionKeys(
kpschoedel 2014/04/14 20:02:59 Should this become device-dependent later (post 36
sadrul 2014/04/14 21:51:32 Perhaps. You can leave a note here accordingly.
233 const ui::Event& event) const {
234 const PrefService* prefs = GetPrefService();
235 if (prefs &&
236 prefs->FindPreference(prefs::kLanguageSendFunctionKeys) &&
237 prefs->GetBoolean(prefs::kLanguageSendFunctionKeys))
238 return true;
239
240 ash::wm::WindowState* state = ash::wm::GetActiveWindowState();
241 return state ? state->top_row_keys_are_function_keys() : false;
242 }
243
244 int KeyboardEventRewriter::GetRemappedModifierMasks(
245 const PrefService& pref_service,
246 const ui::Event& event,
247 int original_flags) const {
248 int unmodified_flags = original_flags;
249 int rewritten_flags = 0;
250 for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
251 const ModifierRemapping* remapped_key = 0;
252 if (unmodified_flags & kModifierRemappings[i].flag) {
253 switch (kModifierRemappings[i].flag) {
254 default:
255 break;
256 case ui::EF_COMMAND_DOWN:
257 // Rewrite Command key presses on an Apple keyboard to Control.
258 if (IsAppleKeyboard(event)) {
259 DCHECK_EQ(ui::EF_CONTROL_DOWN, kModifierRemappingCtrl->flag);
260 remapped_key = kModifierRemappingCtrl;
261 }
262 break;
263 case ui::EF_CAPS_LOCK_DOWN:
264 // If CapsLock is used by the current input method, don't allow the
265 // CapsLock pref to remap it, or the keyboard behavior will be broken.
266 if (IsISOLevel5ShiftUsedByCurrentInputMethod())
267 continue;
268 break;
269 }
270 if (!remapped_key && kModifierRemappings[i].pref_name)
271 remapped_key =
272 GetRemappedKey(kModifierRemappings[i].pref_name, pref_service);
273 if (remapped_key) {
274 unmodified_flags &= ~kModifierRemappings[i].flag;
275 rewritten_flags |= remapped_key->flag;
276 }
277 }
278 }
279 return rewritten_flags | unmodified_flags;
280 }
281
282 bool KeyboardEventRewriter::RewriteModifierKeys(ui::Event* event) {
283 DCHECK(event->type() == ui::ET_KEY_PRESSED ||
284 event->type() == ui::ET_KEY_RELEASED);
285 ui::KeyEvent* key_event = static_cast<ui::KeyEvent*>(event);
286
287 // Do nothing if we have just logged in as guest but have not restarted chrome
kpschoedel 2014/04/14 20:02:59 This may be obsolete; I'll check this shortly.
288 // process yet (so we are still on the login screen). In this situations we
289 // have no user profile so can not do anything useful.
290 // Note that currently, unlike other accounts, when user logs in as guest, we
291 // restart chrome process. In future this is to be changed.
292 // TODO(glotov): remove the following condition when we do not restart chrome
293 // when user logs in as guest.
294 if (UserManager::Get()->IsLoggedInAsGuest() &&
295 LoginDisplayHostImpl::default_host())
296 return false;
297
298 const PrefService* pref_service = GetPrefService();
299 if (!pref_service)
300 return false;
301
302 ui::KeyboardCode original_key_code = key_event->key_code();
303 ui::KeyboardCode remapped_key_code = original_key_code;
304 int characteristic_flag = ui::EF_NONE;
305 int remapped_flags = ui::EF_NONE;
306 int event_flags = event->flags();
307 bool rewritten = false;
308
309 // First, remap the key code.
310 const ModifierRemapping* remapped_key = NULL;
311 switch (original_key_code) {
312 // On Chrome OS, F15 (XF86XK_Launch6) with NumLock (Mod2Mask) is sent
313 // when Diamond key is pressed.
314 case ui::VKEY_F15:
315 // When diamond key is not available, the configuration UI for Diamond
316 // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo
317 // syncable pref.
318 if (HasDiamondKey(*event))
319 remapped_key =
320 GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo, *pref_service);
321 // Default behavior is Ctrl key.
322 if (!remapped_key) {
323 DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code);
324 remapped_key = kModifierRemappingCtrl;
325 characteristic_flag = ui::EF_CONTROL_DOWN;
326 }
327 break;
328 // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock
329 // is pressed (with one exception: when
330 // IsISOLevel5ShiftUsedByCurrentInputMethod() is true, the key generates
331 // XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7).
332 case ui::VKEY_F16:
333 characteristic_flag = ui::EF_CAPS_LOCK_DOWN;
334 remapped_key =
335 GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service);
336 break;
337 case ui::VKEY_LWIN:
338 case ui::VKEY_RWIN:
339 characteristic_flag = ui::EF_COMMAND_DOWN;
340 // Rewrite Command-L/R key presses on an Apple keyboard to Control.
341 if (IsAppleKeyboard(*event)) {
342 DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code);
343 remapped_key = kModifierRemappingCtrl;
344 } else {
345 remapped_key =
346 GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service);
347 }
348 // Default behavior is Super key, hence don't remap the event if the pref
349 // is unavailable.
350 break;
351 case ui::VKEY_CONTROL:
352 characteristic_flag = ui::EF_CONTROL_DOWN;
353 remapped_key =
354 GetRemappedKey(prefs::kLanguageRemapControlKeyTo, *pref_service);
355 break;
356 case ui::VKEY_MENU:
357 // ALT key
358 characteristic_flag = ui::EF_ALT_DOWN;
359 remapped_key =
360 GetRemappedKey(prefs::kLanguageRemapAltKeyTo, *pref_service);
361 break;
362 default:
363 break;
364 }
365
366 if (remapped_key) {
367 remapped_key_code = remapped_key->key_code;
368 event_flags |= characteristic_flag;
369 characteristic_flag = remapped_key->flag;
370 }
371 if (original_key_code != remapped_key_code) {
372 key_event->set_key_code(remapped_key_code);
373 rewritten = true;
374 }
375
376 // Next, remap modifier bits.
377 remapped_flags |=
378 GetRemappedModifierMasks(*pref_service, *event, event_flags);
379 if (event->type() == ui::ET_KEY_PRESSED)
380 remapped_flags |= characteristic_flag;
381 else
382 remapped_flags &= ~characteristic_flag;
383 if (remapped_flags != event->flags()) {
384 event->set_flags(remapped_flags);
385 rewritten = true;
386 }
387
388 #if USE_X11
kpschoedel 2014/04/14 20:02:59 Forgot to remove #if when XKeyboard -> ImeKeyboard
389 // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if
390 // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external
391 // keyboard is pressed) since X can handle that case.
392 if (event->type() == ui::ET_KEY_PRESSED &&
393 original_key_code != ui::VKEY_CAPITAL &&
394 remapped_key_code == ui::VKEY_CAPITAL) {
395 chromeos::input_method::ImeKeyboard* ime_keyboard =
396 ime_keyboard_for_testing_ ? ime_keyboard_for_testing_ :
397 chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
398 ime_keyboard->SetCapsLockEnabled(!ime_keyboard->CapsLockIsEnabled());
399 }
400 #endif
401
402 return rewritten;
403 }
404
405 bool KeyboardEventRewriter::RewriteNumPadKeys(ui::Event* event) {
406 DCHECK(event->type() == ui::ET_KEY_PRESSED ||
407 event->type() == ui::ET_KEY_RELEASED);
408
409 int original_flags = event->flags();
410 if (!(original_flags & ui::EF_NUMPAD))
411 return false;
412
413 int remapped_flags = original_flags;
414 ui::KeyEvent* key_event = static_cast<ui::KeyEvent*>(event);
415 ui::KeyboardCode original_key_code = key_event->key_code();
416 ui::KeyboardCode remapped_key_code = original_key_code;
417
418 static const KeyboardRemapping kNumPadRemappings[] = {
419 {
420 ui::VKEY_INSERT, ui::EF_NUMPAD,
421 ui::VKEY_NUMPAD0, ui::EF_NUMPAD
422 },
423 {
424 ui::VKEY_DELETE, ui::EF_NUMPAD,
425 ui::VKEY_DECIMAL, ui::EF_NUMPAD
426 },
427 {
428 ui::VKEY_END, ui::EF_NUMPAD,
429 ui::VKEY_NUMPAD1, ui::EF_NUMPAD
430 },
431 {
432 ui::VKEY_DOWN, ui::EF_NUMPAD,
433 ui::VKEY_NUMPAD2, ui::EF_NUMPAD
434 },
435 {
436 ui::VKEY_NEXT, ui::EF_NUMPAD,
437 ui::VKEY_NUMPAD3, ui::EF_NUMPAD
438 },
439 {
440 ui::VKEY_LEFT, ui::EF_NUMPAD,
441 ui::VKEY_NUMPAD4, ui::EF_NUMPAD
442 },
443 {
444 ui::VKEY_CLEAR, ui::EF_NUMPAD,
445 ui::VKEY_NUMPAD5, ui::EF_NUMPAD
446 },
447 {
448 ui::VKEY_RIGHT, ui::EF_NUMPAD,
449 ui::VKEY_NUMPAD6, ui::EF_NUMPAD
450 },
451 {
452 ui::VKEY_HOME, ui::EF_NUMPAD,
453 ui::VKEY_NUMPAD7, ui::EF_NUMPAD
454 },
455 {
456 ui::VKEY_UP, ui::EF_NUMPAD,
457 ui::VKEY_NUMPAD8, ui::EF_NUMPAD
458 },
459 {
460 ui::VKEY_PRIOR, ui::EF_NUMPAD,
461 ui::VKEY_NUMPAD9, ui::EF_NUMPAD
462 },
463 };
464
465 bool rewritten = RewriteWithKeyboardRemappingsByKeyCode(
466 kNumPadRemappings,
467 arraysize(kNumPadRemappings),
468 original_key_code,
469 original_flags,
470 &remapped_key_code,
471 &remapped_flags);
472
473 if (!rewritten)
474 return false;
475
476 static_cast<ui::KeyEvent*>(event)->set_key_code(remapped_key_code);
477 event->set_flags(remapped_flags);
478 return true;
479 }
480
481 bool KeyboardEventRewriter::RewriteExtendedKeys(ui::Event* event) {
482 DCHECK(event->type() == ui::ET_KEY_PRESSED ||
483 event->type() == ui::ET_KEY_RELEASED);
484 ui::KeyEvent = static_cast<ui::KeyEvent*>(event);
485 ui::KeyboardCode original_key_code = key_event->key_code();
486 ui::KeyboardCode remapped_key_code = original_key_code;
487 int original_flags = event->flags();
488 int remapped_flags = original_flags;
489 bool rewritten = false;
490
491 if ((original_flags & (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) ==
492 (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) {
493 // Allow Search to avoid rewriting extended keys.
494 static const KeyboardRemapping kAvoidRemappings[] = {
495 { // Alt+Backspace
496 ui::VKEY_BACK, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
497 ui::VKEY_BACK, ui::EF_ALT_DOWN,
498 },
499 { // Control+Alt+Up
500 ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN |
501 ui::EF_COMMAND_DOWN,
502 ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
503 },
504 { // Alt+Up
505 ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
506 ui::VKEY_UP, ui::EF_ALT_DOWN,
507 },
508 { // Control+Alt+Down
509 ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN |
510 ui::EF_COMMAND_DOWN,
511 ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
512 },
513 { // Alt+Down
514 ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
515 ui::VKEY_DOWN, ui::EF_ALT_DOWN,
516 }
517 };
518
519 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
520 kAvoidRemappings,
521 arraysize(kAvoidRemappings),
522 original_key_code,
523 original_flags,
524 &remapped_key_code,
525 &remapped_flags);
526 }
527
528 if (!rewritten && (original_flags & ui::EF_COMMAND_DOWN)) {
529 static const KeyboardRemapping kSearchRemappings[] = {
530 { // Search+BackSpace -> Delete
531 ui::VKEY_BACK, ui::EF_COMMAND_DOWN,
532 ui::VKEY_DELETE, 0
533 },
534 { // Search+Left -> Home
535 ui::VKEY_LEFT, ui::EF_COMMAND_DOWN,
536 ui::VKEY_HOME, 0
537 },
538 { // Search+Up -> Prior (aka PageUp)
539 ui::VKEY_UP, ui::EF_COMMAND_DOWN,
540 ui::VKEY_PRIOR, 0
541 },
542 { // Search+Right -> End
543 ui::VKEY_RIGHT, ui::EF_COMMAND_DOWN,
544 ui::VKEY_END, 0
545 },
546 { // Search+Down -> Next (aka PageDown)
547 ui::VKEY_DOWN, ui::EF_COMMAND_DOWN,
548 ui::VKEY_NEXT, 0
549 },
550 { // Search+Period -> Insert
551 ui::VKEY_OEM_PERIOD, ui::EF_COMMAND_DOWN,
552 ui::VKEY_INSERT, 0
553 }
554 };
555
556 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
557 kSearchRemappings,
558 arraysize(kSearchRemappings),
559 original_key_code,
560 original_flags,
561 &remapped_key_code,
562 &remapped_flags);
563 }
564
565 if (!rewritten && (original_flags & ui::EF_ALT_DOWN)) {
566 static const KeyboardRemapping kNonSearchRemappings[] = {
567 { // Alt+BackSpace -> Delete
568 ui::VKEY_BACK, ui::EF_ALT_DOWN,
569 ui::VKEY_DELETE, 0
570 },
571 { // Control+Alt+Up -> Home
572 ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
573 ui::VKEY_HOME, 0
574 },
575 { // Alt+Up -> Prior (aka PageUp)
576 ui::VKEY_UP, ui::EF_ALT_DOWN,
577 ui::VKEY_PRIOR, 0
578 },
579 { // Control+Alt+Down -> End
580 ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
581 ui::VKEY_END, 0
582 },
583 { // Alt+Down -> Next (aka PageDown)
584 ui::VKEY_DOWN, ui::EF_ALT_DOWN,
585 ui::VKEY_NEXT, 0
586 }
587 };
588
589 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
590 kNonSearchRemappings,
591 arraysize(kNonSearchRemappings),
592 original_key_code,
593 original_flags,
594 &remapped_key_code,
595 &remapped_flags);
596 }
597
598 if (!rewritten)
599 return false;
600
601 key_event->set_key_code(remapped_key_code);
602 event->set_flags(remapped_flags);
603 return true;
604 }
605
606 bool KeyboardEventRewriter::RewriteFunctionKeys(ui::Event* event) {
607 CHECK(event->type() == ui::ET_KEY_PRESSED ||
608 event->type() == ui::ET_KEY_RELEASED);
609
610 ui::KeyEvent* key_event = static_cast<ui::KeyEvent*>(event);
611 ui::KeyboardCode original_key_code = key_event->key_code();
612 ui::KeyboardCode remapped_key_code = original_key_code;
613 int original_flags = event->flags();
614 int remapped_flags = original_flags;
615 bool rewritten = false;
616
617 if ((original_key_code >= ui::VKEY_F1) &&
618 (original_key_code <= ui::VKEY_F24)) {
619 // By default the top row (F1-F12) keys are special keys for back, forward,
620 // brightness, volume, etc. However, windows for v2 apps can optionally
621 // request raw function keys for these keys.
622 bool top_row_keys_are_function_keys = TopRowKeysAreFunctionKeys(*event);
623 bool search_is_pressed = (original_flags & ui::EF_COMMAND_DOWN) != 0;
624
625 // Search? Top Row Result
626 // ------- -------- ------
627 // No Fn Unchanged
628 // No Special Fn -> Special
629 // Yes Fn Fn -> Special
630 // Yes Special Search+Fn -> Fn
631 if (top_row_keys_are_function_keys == search_is_pressed) {
632 // Rewrite the F1-F12 keys on a Chromebook keyboard to special keys.
633 static const KeyboardRemapping kFkeysToSpecialKeys[] = {
634 { ui::VKEY_F1, 0, ui::VKEY_BROWSER_BACK, 0 },
635 { ui::VKEY_F2, 0, ui::VKEY_BROWSER_FORWARD, 0 },
636 { ui::VKEY_F3, 0, ui::VKEY_BROWSER_REFRESH, 0 },
637 { ui::VKEY_F4, 0, ui::VKEY_MEDIA_LAUNCH_APP2, 0 },
638 { ui::VKEY_F5, 0, ui::VKEY_MEDIA_LAUNCH_APP1, 0 },
639 { ui::VKEY_F6, 0, ui::VKEY_BRIGHTNESS_DOWN, 0 },
640 { ui::VKEY_F7, 0, ui::VKEY_BRIGHTNESS_UP, 0 },
641 { ui::VKEY_F8, 0, ui::VKEY_VOLUME_MUTE, 0 },
642 { ui::VKEY_F9, 0, ui::VKEY_VOLUME_DOWN, 0 },
643 { ui::VKEY_F10, 0, ui::VKEY_VOLUME_UP, 0 },
644 };
645 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
646 kFkeysToSpecialKeys,
647 arraysize(kFkeysToSpecialKeys),
648 original_key_code,
649 original_flags & ~ui::EF_COMMAND_DOWN,
650 &remapped_key_code,
651 &remapped_flags);
652 } else if (search_is_pressed) {
653 // Allow Search to avoid rewriting F1-F12.
654 remapped_flags &= ~ui::EF_COMMAND_DOWN;
655 rewritten = true;
656 }
657 }
658
659 if (!rewritten && (original_flags & ui::EF_COMMAND_DOWN)) {
660 // Remap Search+<number> to F<number>.
661 // We check the keycode here instead of the keysym, as these keys have
662 // different keysyms when modifiers are pressed, such as shift.
663
664 // TODO(danakj): On some i18n keyboards, these choices will be bad and we
665 // should make layout-specific choices here. For eg. on a french keyboard
666 // "-" and "6" are the same key, so F11 will not be accessible.
667 static const KeyboardRemapping kNumberKeysToFkeys[] = {
kpschoedel 2014/04/14 20:02:59 I notice this (in the original) does not handle nu
668 { ui::VKEY_1, ui::EF_COMMAND_DOWN, ui::VKEY_F1, 0 },
669 { ui::VKEY_2, ui::EF_COMMAND_DOWN, ui::VKEY_F2, 0 },
670 { ui::VKEY_3, ui::EF_COMMAND_DOWN, ui::VKEY_F3, 0 },
671 { ui::VKEY_4, ui::EF_COMMAND_DOWN, ui::VKEY_F4, 0 },
672 { ui::VKEY_5, ui::EF_COMMAND_DOWN, ui::VKEY_F5, 0 },
673 { ui::VKEY_6, ui::EF_COMMAND_DOWN, ui::VKEY_F6, 0 },
674 { ui::VKEY_7, ui::EF_COMMAND_DOWN, ui::VKEY_F7, 0 },
675 { ui::VKEY_8, ui::EF_COMMAND_DOWN, ui::VKEY_F8, 0 },
676 { ui::VKEY_9, ui::EF_COMMAND_DOWN, ui::VKEY_F9, 0 },
677 { ui::VKEY_0, ui::EF_COMMAND_DOWN, ui::VKEY_F10, 0 },
678 { ui::VKEY_OEM_MINUS, ui::EF_COMMAND_DOWN, ui::VKEY_F11, 0 },
679 { ui::VKEY_OEM_PLUS, ui::EF_COMMAND_DOWN, ui::VKEY_F12, 0 }
680 };
681 rewritten = RewriteWithKeyboardRemappingsByKeyCode(
682 kNumberKeysToFkeys,
683 arraysize(kNumberKeysToFkeys),
684 original_key_code,
685 original_flags,
686 &remapped_key_code,
687 &remapped_flags);
688 }
689
690 if (!rewritten)
691 return false;
692
693 key_event->set_key_code(remapped_key_code);
694 event->set_flags(remapped_flags);
695 return true;
696 }
697
698 bool KeyboardEventRewriter::RewriteLocatedEvent(ui::Event* event) {
699 bool rewritten = false;
700 const PrefService* pref_service = GetPrefService();
701 if (!pref_service)
702 return false;
703
704 // First, remap modifier masks.
705 int original_flags = event->flags();
706 int remapped_flags =
707 GetRemappedModifierMasks(*pref_service, *event, original_flags);
708
709 #if USE_X11
710 // TODO(kpschoedel): de-X11 with unified device ids from crbug.com/360377
711 XEvent* xevent = event->native_event();
712 if (xevent->type != GenericEvent)
713 return rewritten;
714 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
715 if (xievent->evtype != XI_ButtonPress && xievent->evtype != XI_ButtonRelease)
716 return rewritten;
717
718 // Then, remap Alt+Button1 to Button3.
719 if ((xievent->evtype == XI_ButtonPress ||
720 pressed_device_ids_.count(xievent->sourceid)) &&
721 (xievent->mods.effective & Mod1Mask) && xievent->detail == Button1) {
722 remapped_flags &= ~(ui::EF_ALT_DOWN | ui::EF_LEFT_MOUSE_BUTTON);
723 remapped_flags |= ui::EF_RIGHT_MOUSE_BUTTON;
724 xievent->mods.effective &= ~Mod1Mask;
725 xievent->detail = Button3;
726 if (xievent->evtype == XI_ButtonRelease) {
727 // On the release clear the left button from the existing state and the
728 // mods, and set the right button.
729 XISetMask(xievent->buttons.mask, Button3);
730 XIClearMask(xievent->buttons.mask, Button1);
731 xievent->mods.effective &= ~Button1Mask;
732 pressed_device_ids_.erase(xievent->sourceid);
733 } else {
734 pressed_device_ids_.insert(xievent->sourceid);
735 }
736 }
737 #endif // USE_X11
738 if (remapped_flags != original_flags) {
739 event->set_flags(remapped_flags);
740 rewritten = true;
741 }
742 return rewritten;
743 }
744
745 KeyboardEventRewriter::DeviceType KeyboardEventRewriter::DeviceAddedInternal(
746 int device_id,
747 const std::string& device_name) {
748 const DeviceType type = GetDeviceType(device_name);
749 if (type == kDeviceAppleKeyboard) {
750 VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
751 << "id=" << device_id;
752 }
753 // Always overwrite the existing device_id since the X server may reuse a
754 // device id for an unattached device.
755 device_id_to_type_[device_id] = type;
756 return type;
757 }
758
759 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698