OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #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 |
OLD | NEW |