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

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

Powered by Google App Engine
This is Rietveld 408576698