OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/input_method/xkeyboard.h" | 5 #include "chrome/browser/chromeos/input_method/xkeyboard.h" |
6 | 6 |
7 #include <cstdlib> | 7 #include <cstdlib> |
8 #include <cstring> | 8 #include <cstring> |
9 #include <queue> | 9 #include <queue> |
10 #include <set> | 10 #include <set> |
11 #include <utility> | 11 #include <utility> |
12 | 12 |
13 #include "base/chromeos/chromeos_version.h" | 13 #include "base/chromeos/chromeos_version.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/scoped_ptr.h" |
16 #include "base/process_util.h" | 16 #include "base/process_util.h" |
17 #include "base/string_util.h" | 17 #include "base/string_util.h" |
18 #include "base/stringprintf.h" | 18 #include "base/stringprintf.h" |
19 #include "chrome/browser/chromeos/input_method/input_method_util.h" | 19 #include "chrome/browser/chromeos/input_method/input_method_util.h" |
20 #include "chrome/browser/chromeos/input_method/xkeyboard_data.h" | |
21 #include "content/public/browser/browser_thread.h" | 20 #include "content/public/browser/browser_thread.h" |
22 #include "ui/base/x/x11_util.h" | 21 #include "ui/base/x/x11_util.h" |
23 | 22 |
24 // These includes conflict with base/tracked_objects.h so must come last. | 23 // These includes conflict with base/tracked_objects.h so must come last. |
25 #include <X11/XKBlib.h> | 24 #include <X11/XKBlib.h> |
26 #include <X11/Xlib.h> | 25 #include <X11/Xlib.h> |
27 #include <glib.h> | 26 #include <glib.h> |
28 | 27 |
29 using content::BrowserThread; | 28 using content::BrowserThread; |
30 | 29 |
31 namespace chromeos { | 30 namespace chromeos { |
32 namespace input_method { | 31 namespace input_method { |
33 namespace { | 32 namespace { |
34 | 33 |
35 // The default keyboard layout name in the xorg config file. | 34 // The default keyboard layout name in the xorg config file. |
36 const char kDefaultLayoutName[] = "us"; | 35 const char kDefaultLayoutName[] = "us"; |
37 | 36 |
38 // The command we use to set the current XKB layout and modifier key mapping. | 37 // The command we use to set the current XKB layout and modifier key mapping. |
39 // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) | 38 // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) |
40 const char kSetxkbmapCommand[] = "/usr/bin/setxkbmap"; | 39 const char kSetxkbmapCommand[] = "/usr/bin/setxkbmap"; |
41 | 40 |
42 // See the comment at ModifierKey in the .h file. | |
43 ModifierKey kCustomizableKeys[] = { | |
44 kSearchKey, | |
45 kControlKey, | |
46 kAltKey | |
47 }; | |
48 | |
49 // A string for obtaining a mask value for Num Lock. | 41 // A string for obtaining a mask value for Num Lock. |
50 const char kNumLockVirtualModifierString[] = "NumLock"; | 42 const char kNumLockVirtualModifierString[] = "NumLock"; |
51 | 43 |
52 class XKeyboardImpl : public XKeyboard { | 44 class XKeyboardImpl : public XKeyboard { |
53 public: | 45 public: |
54 explicit XKeyboardImpl(const InputMethodUtil& util); | 46 explicit XKeyboardImpl(const InputMethodUtil& util); |
55 virtual ~XKeyboardImpl() {} | 47 virtual ~XKeyboardImpl() {} |
56 | 48 |
57 // Overridden from XKeyboard: | 49 // Overridden from XKeyboard: |
58 virtual bool SetCurrentKeyboardLayoutByName( | 50 virtual bool SetCurrentKeyboardLayoutByName( |
59 const std::string& layout_name) OVERRIDE; | 51 const std::string& layout_name) OVERRIDE; |
60 virtual bool RemapModifierKeys(const ModifierMap& modifier_map) OVERRIDE; | |
61 virtual bool ReapplyCurrentKeyboardLayout() OVERRIDE; | 52 virtual bool ReapplyCurrentKeyboardLayout() OVERRIDE; |
62 virtual void ReapplyCurrentModifierLockStatus() OVERRIDE; | 53 virtual void ReapplyCurrentModifierLockStatus() OVERRIDE; |
63 virtual void SetLockedModifiers( | 54 virtual void SetLockedModifiers( |
64 ModifierLockStatus new_caps_lock_status, | 55 ModifierLockStatus new_caps_lock_status, |
65 ModifierLockStatus new_num_lock_status) OVERRIDE; | 56 ModifierLockStatus new_num_lock_status) OVERRIDE; |
66 virtual void SetNumLockEnabled(bool enable_num_lock) OVERRIDE; | 57 virtual void SetNumLockEnabled(bool enable_num_lock) OVERRIDE; |
67 virtual void SetCapsLockEnabled(bool enable_caps_lock) OVERRIDE; | 58 virtual void SetCapsLockEnabled(bool enable_caps_lock) OVERRIDE; |
68 virtual bool NumLockIsEnabled() OVERRIDE; | 59 virtual bool NumLockIsEnabled() OVERRIDE; |
69 virtual bool CapsLockIsEnabled() OVERRIDE; | 60 virtual bool CapsLockIsEnabled() OVERRIDE; |
70 virtual unsigned int GetNumLockMask() OVERRIDE; | 61 virtual unsigned int GetNumLockMask() OVERRIDE; |
71 virtual void GetLockedModifiers(bool* out_caps_lock_enabled, | 62 virtual void GetLockedModifiers(bool* out_caps_lock_enabled, |
72 bool* out_num_lock_enabled) OVERRIDE; | 63 bool* out_num_lock_enabled) OVERRIDE; |
73 virtual std::string CreateFullXkbLayoutName( | 64 virtual std::string CreateFullXkbLayoutName( |
74 const std::string& layout_name, | 65 const std::string& layout_name) OVERRIDE; |
75 const ModifierMap& modifire_map) OVERRIDE; | |
76 | 66 |
77 private: | 67 private: |
78 // This function is used by SetLayout() and RemapModifierKeys(). Calls | 68 // This function is used by SetLayout() and RemapModifierKeys(). Calls |
79 // setxkbmap command if needed, and updates the last_full_layout_name_ cache. | 69 // setxkbmap command if needed, and updates the last_full_layout_name_ cache. |
80 bool SetLayoutInternal(const std::string& layout_name, | 70 bool SetLayoutInternal(const std::string& layout_name, bool force); |
81 const ModifierMap& modifier_map, | |
82 bool force); | |
83 | 71 |
84 // Executes 'setxkbmap -layout ...' command asynchronously using a layout name | 72 // Executes 'setxkbmap -layout ...' command asynchronously using a layout name |
85 // in the |execute_queue_|. Do nothing if the queue is empty. | 73 // in the |execute_queue_|. Do nothing if the queue is empty. |
86 // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) | 74 // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) |
87 void MaybeExecuteSetLayoutCommand(); | 75 void MaybeExecuteSetLayoutCommand(); |
88 | 76 |
89 // Returns true if the XKB layout uses the right Alt key for special purposes | |
90 // like AltGr. | |
91 bool KeepRightAlt(const std::string& xkb_layout_name) const; | |
92 | |
93 // Returns true if the XKB layout uses the CapsLock key for special purposes. | |
94 // For example, since US Colemak layout uses the key as back space, | |
95 // KeepCapsLock("us(colemak)") would return true. | |
96 bool KeepCapsLock(const std::string& xkb_layout_name) const; | |
97 | |
98 // Returns true if the current thread is the UI thread, or the process is | 77 // Returns true if the current thread is the UI thread, or the process is |
99 // running on Linux. | 78 // running on Linux. |
100 bool CurrentlyOnUIThread() const; | 79 bool CurrentlyOnUIThread() const; |
101 | 80 |
102 // Converts |key| to a modifier key name which is used in | |
103 // /usr/share/X11/xkb/symbols/chromeos. | |
104 static std::string ModifierKeyToString(ModifierKey key); | |
105 | |
106 // Called when execve'd setxkbmap process exits. | 81 // Called when execve'd setxkbmap process exits. |
107 static void OnSetLayoutFinish(pid_t pid, int status, XKeyboardImpl* self); | 82 static void OnSetLayoutFinish(pid_t pid, int status, XKeyboardImpl* self); |
108 | 83 |
109 const bool is_running_on_chrome_os_; | 84 const bool is_running_on_chrome_os_; |
110 unsigned int num_lock_mask_; | 85 unsigned int num_lock_mask_; |
111 | 86 |
112 // The current Num Lock and Caps Lock status. If true, enabled. | 87 // The current Num Lock and Caps Lock status. If true, enabled. |
113 bool current_num_lock_status_; | 88 bool current_num_lock_status_; |
114 bool current_caps_lock_status_; | 89 bool current_caps_lock_status_; |
115 // The XKB layout name which we set last time like "us" and "us(dvorak)". | 90 // The XKB layout name which we set last time like "us" and "us(dvorak)". |
116 std::string current_layout_name_; | 91 std::string current_layout_name_; |
117 // The mapping of modifier keys we set last time. | |
118 ModifierMap current_modifier_map_; | |
119 | 92 |
120 // A queue for executing setxkbmap one by one. | 93 // A queue for executing setxkbmap one by one. |
121 std::queue<std::string> execute_queue_; | 94 std::queue<std::string> execute_queue_; |
122 | 95 |
123 std::set<std::string> keep_right_alt_xkb_layout_names_; | |
124 std::set<std::string> caps_lock_remapped_xkb_layout_names_; | |
125 | |
126 DISALLOW_COPY_AND_ASSIGN(XKeyboardImpl); | 96 DISALLOW_COPY_AND_ASSIGN(XKeyboardImpl); |
127 }; | 97 }; |
128 | 98 |
129 XKeyboardImpl::XKeyboardImpl(const InputMethodUtil& util) | 99 XKeyboardImpl::XKeyboardImpl(const InputMethodUtil& util) |
130 : is_running_on_chrome_os_(base::chromeos::IsRunningOnChromeOS()) { | 100 : is_running_on_chrome_os_(base::chromeos::IsRunningOnChromeOS()) { |
131 num_lock_mask_ = GetNumLockMask(); | 101 num_lock_mask_ = GetNumLockMask(); |
132 | 102 |
133 // web_input_event_aurax11.cc seems to assume that Mod2Mask is always assigned | 103 // web_input_event_aurax11.cc seems to assume that Mod2Mask is always assigned |
134 // to Num Lock. | 104 // to Num Lock. |
135 // TODO(yusukes): Check the assumption is really okay. If not, modify the Aura | 105 // TODO(yusukes): Check the assumption is really okay. If not, modify the Aura |
136 // code, and then remove the CHECK below. | 106 // code, and then remove the CHECK below. |
137 CHECK(!is_running_on_chrome_os_ || (num_lock_mask_ == Mod2Mask)); | 107 CHECK(!is_running_on_chrome_os_ || (num_lock_mask_ == Mod2Mask)); |
138 GetLockedModifiers(¤t_caps_lock_status_, ¤t_num_lock_status_); | 108 GetLockedModifiers(¤t_caps_lock_status_, ¤t_num_lock_status_); |
139 | |
140 for (size_t i = 0; i < arraysize(kCustomizableKeys); ++i) { | |
141 ModifierKey key = kCustomizableKeys[i]; | |
142 current_modifier_map_.push_back(ModifierKeyPair(key, key)); | |
143 } | |
144 | |
145 std::string layout; | |
146 for (size_t i = 0; i < arraysize(kKeepRightAltInputMethods); ++i) { | |
147 layout = util.GetKeyboardLayoutName(kKeepRightAltInputMethods[i]); | |
148 keep_right_alt_xkb_layout_names_.insert(layout); | |
149 } | |
150 for (size_t i = 0; i < arraysize(kCapsLockRemapped); ++i) { | |
151 layout = util.GetKeyboardLayoutName(kCapsLockRemapped[i]); | |
152 caps_lock_remapped_xkb_layout_names_.insert(layout); | |
153 } | |
154 } | 109 } |
155 | 110 |
156 bool XKeyboardImpl::SetLayoutInternal(const std::string& layout_name, | 111 bool XKeyboardImpl::SetLayoutInternal(const std::string& layout_name, |
157 const ModifierMap& modifier_map, | |
158 bool force) { | 112 bool force) { |
159 if (!is_running_on_chrome_os_) { | 113 if (!is_running_on_chrome_os_) { |
160 // We should not try to change a layout on Linux or inside ui_tests. Just | 114 // We should not try to change a layout on Linux or inside ui_tests. Just |
161 // return true. | 115 // return true. |
162 return true; | 116 return true; |
163 } | 117 } |
164 | 118 |
165 const std::string layout_to_set = CreateFullXkbLayoutName( | 119 const std::string layout_to_set = CreateFullXkbLayoutName(layout_name); |
166 layout_name, modifier_map); | 120 if (layout_to_set.empty()) |
167 if (layout_to_set.empty()) { | |
168 return false; | 121 return false; |
169 } | |
170 | 122 |
171 if (!current_layout_name_.empty()) { | 123 if (!current_layout_name_.empty()) { |
172 const std::string current_layout = CreateFullXkbLayoutName( | 124 const std::string current_layout = CreateFullXkbLayoutName( |
173 current_layout_name_, current_modifier_map_); | 125 current_layout_name_); |
174 if (!force && (current_layout == layout_to_set)) { | 126 if (!force && (current_layout == layout_to_set)) { |
175 DVLOG(1) << "The requested layout is already set: " << layout_to_set; | 127 DVLOG(1) << "The requested layout is already set: " << layout_to_set; |
176 return true; | 128 return true; |
177 } | 129 } |
178 } | 130 } |
179 | 131 |
180 // Turn off caps lock if there is no kCapsLockKey in the remapped keys. | |
181 if (!ContainsModifierKeyAsReplacement(modifier_map, kCapsLockKey)) { | |
182 SetCapsLockEnabled(false); | |
183 } | |
184 | |
185 DVLOG(1) << (force ? "Reapply" : "Set") << " layout: " << layout_to_set; | 132 DVLOG(1) << (force ? "Reapply" : "Set") << " layout: " << layout_to_set; |
186 | 133 |
187 const bool start_execution = execute_queue_.empty(); | 134 const bool start_execution = execute_queue_.empty(); |
188 // If no setxkbmap command is in flight (i.e. start_execution is true), | 135 // If no setxkbmap command is in flight (i.e. start_execution is true), |
189 // start the first one by explicitly calling MaybeExecuteSetLayoutCommand(). | 136 // start the first one by explicitly calling MaybeExecuteSetLayoutCommand(). |
190 // If one or more setxkbmap commands are already in flight, just push the | 137 // If one or more setxkbmap commands are already in flight, just push the |
191 // layout name to the queue. setxkbmap command for the layout will be called | 138 // layout name to the queue. setxkbmap command for the layout will be called |
192 // via OnSetLayoutFinish() callback later. | 139 // via OnSetLayoutFinish() callback later. |
193 execute_queue_.push(layout_to_set); | 140 execute_queue_.push(layout_to_set); |
194 if (start_execution) { | 141 if (start_execution) |
195 MaybeExecuteSetLayoutCommand(); | 142 MaybeExecuteSetLayoutCommand(); |
196 } | 143 |
197 return true; | 144 return true; |
198 } | 145 } |
199 | 146 |
200 // Executes 'setxkbmap -layout ...' command asynchronously using a layout name | 147 // Executes 'setxkbmap -layout ...' command asynchronously using a layout name |
201 // in the |execute_queue_|. Do nothing if the queue is empty. | 148 // in the |execute_queue_|. Do nothing if the queue is empty. |
202 // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) | 149 // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) |
203 void XKeyboardImpl::MaybeExecuteSetLayoutCommand() { | 150 void XKeyboardImpl::MaybeExecuteSetLayoutCommand() { |
204 if (execute_queue_.empty()) { | 151 if (execute_queue_.empty()) |
205 return; | 152 return; |
206 } | |
207 const std::string layout_to_set = execute_queue_.front(); | 153 const std::string layout_to_set = execute_queue_.front(); |
208 | 154 |
209 std::vector<std::string> argv; | 155 std::vector<std::string> argv; |
210 base::ProcessHandle handle = base::kNullProcessHandle; | 156 base::ProcessHandle handle = base::kNullProcessHandle; |
211 | 157 |
212 argv.push_back(kSetxkbmapCommand); | 158 argv.push_back(kSetxkbmapCommand); |
213 argv.push_back("-layout"); | 159 argv.push_back("-layout"); |
214 argv.push_back(layout_to_set); | 160 argv.push_back(layout_to_set); |
215 argv.push_back("-synch"); | 161 argv.push_back("-synch"); |
216 | 162 |
(...skipping 24 matching lines...) Expand all Loading... |
241 return caps_lock_enabled; | 187 return caps_lock_enabled; |
242 } | 188 } |
243 | 189 |
244 unsigned int XKeyboardImpl::GetNumLockMask() { | 190 unsigned int XKeyboardImpl::GetNumLockMask() { |
245 CHECK(CurrentlyOnUIThread()); | 191 CHECK(CurrentlyOnUIThread()); |
246 static const unsigned int kBadMask = 0; | 192 static const unsigned int kBadMask = 0; |
247 | 193 |
248 unsigned int real_mask = kBadMask; | 194 unsigned int real_mask = kBadMask; |
249 XkbDescPtr xkb_desc = | 195 XkbDescPtr xkb_desc = |
250 XkbGetKeyboard(ui::GetXDisplay(), XkbAllComponentsMask, XkbUseCoreKbd); | 196 XkbGetKeyboard(ui::GetXDisplay(), XkbAllComponentsMask, XkbUseCoreKbd); |
251 if (!xkb_desc) { | 197 if (!xkb_desc) |
252 return kBadMask; | 198 return kBadMask; |
253 } | |
254 | 199 |
255 if (xkb_desc->dpy && xkb_desc->names && xkb_desc->names->vmods) { | 200 if (xkb_desc->dpy && xkb_desc->names && xkb_desc->names->vmods) { |
256 const std::string string_to_find(kNumLockVirtualModifierString); | 201 const std::string string_to_find(kNumLockVirtualModifierString); |
257 for (size_t i = 0; i < XkbNumVirtualMods; ++i) { | 202 for (size_t i = 0; i < XkbNumVirtualMods; ++i) { |
258 const unsigned int virtual_mod_mask = 1U << i; | 203 const unsigned int virtual_mod_mask = 1U << i; |
259 ui::XScopedString virtual_mod_str( | 204 ui::XScopedString virtual_mod_str( |
260 XGetAtomName(xkb_desc->dpy, xkb_desc->names->vmods[i])); | 205 XGetAtomName(xkb_desc->dpy, xkb_desc->names->vmods[i])); |
261 if (!virtual_mod_str.string()) | 206 if (!virtual_mod_str.string()) |
262 continue; | 207 continue; |
263 if (string_to_find == virtual_mod_str.string()) { | 208 if (string_to_find == virtual_mod_str.string()) { |
264 if (!XkbVirtualModsToReal(xkb_desc, virtual_mod_mask, &real_mask)) { | 209 if (!XkbVirtualModsToReal(xkb_desc, virtual_mod_mask, &real_mask)) { |
265 DVLOG(1) << "XkbVirtualModsToReal failed"; | 210 DVLOG(1) << "XkbVirtualModsToReal failed"; |
266 real_mask = kBadMask; // reset the return value, just in case. | 211 real_mask = kBadMask; // reset the return value, just in case. |
267 } | 212 } |
268 break; | 213 break; |
269 } | 214 } |
270 } | 215 } |
271 } | 216 } |
272 XkbFreeKeyboard(xkb_desc, 0, True /* free all components */); | 217 XkbFreeKeyboard(xkb_desc, 0, True /* free all components */); |
273 return real_mask; | 218 return real_mask; |
274 } | 219 } |
275 | 220 |
276 void XKeyboardImpl::GetLockedModifiers(bool* out_caps_lock_enabled, | 221 void XKeyboardImpl::GetLockedModifiers(bool* out_caps_lock_enabled, |
277 bool* out_num_lock_enabled) { | 222 bool* out_num_lock_enabled) { |
278 CHECK(CurrentlyOnUIThread()); | 223 CHECK(CurrentlyOnUIThread()); |
279 | 224 |
280 if (out_num_lock_enabled && !num_lock_mask_) { | 225 if (out_num_lock_enabled && !num_lock_mask_) { |
281 DVLOG(1) << "Cannot get locked modifiers. Num Lock mask unknown."; | 226 DVLOG(1) << "Cannot get locked modifiers. Num Lock mask unknown."; |
282 if (out_caps_lock_enabled) { | 227 if (out_caps_lock_enabled) |
283 *out_caps_lock_enabled = false; | 228 *out_caps_lock_enabled = false; |
284 } | 229 if (out_num_lock_enabled) |
285 if (out_num_lock_enabled) { | |
286 *out_num_lock_enabled = false; | 230 *out_num_lock_enabled = false; |
287 } | |
288 return; | 231 return; |
289 } | 232 } |
290 | 233 |
291 XkbStateRec status; | 234 XkbStateRec status; |
292 XkbGetState(ui::GetXDisplay(), XkbUseCoreKbd, &status); | 235 XkbGetState(ui::GetXDisplay(), XkbUseCoreKbd, &status); |
293 if (out_caps_lock_enabled) { | 236 if (out_caps_lock_enabled) |
294 *out_caps_lock_enabled = status.locked_mods & LockMask; | 237 *out_caps_lock_enabled = status.locked_mods & LockMask; |
295 } | 238 if (out_num_lock_enabled) |
296 if (out_num_lock_enabled) { | |
297 *out_num_lock_enabled = status.locked_mods & num_lock_mask_; | 239 *out_num_lock_enabled = status.locked_mods & num_lock_mask_; |
298 } | |
299 } | 240 } |
300 | 241 |
301 std::string XKeyboardImpl::CreateFullXkbLayoutName( | 242 std::string XKeyboardImpl::CreateFullXkbLayoutName( |
302 const std::string& layout_name, | 243 const std::string& layout_name) { |
303 const ModifierMap& modifier_map) { | |
304 static const char kValidLayoutNameCharacters[] = | 244 static const char kValidLayoutNameCharacters[] = |
305 "abcdefghijklmnopqrstuvwxyz0123456789()-_"; | 245 "abcdefghijklmnopqrstuvwxyz0123456789()-_"; |
306 | 246 |
307 if (layout_name.empty()) { | 247 if (layout_name.empty()) { |
308 DVLOG(1) << "Invalid layout_name: " << layout_name; | 248 DVLOG(1) << "Invalid layout_name: " << layout_name; |
309 return ""; | 249 return ""; |
310 } | 250 } |
311 | 251 |
312 if (layout_name.find_first_not_of(kValidLayoutNameCharacters) != | 252 if (layout_name.find_first_not_of(kValidLayoutNameCharacters) != |
313 std::string::npos) { | 253 std::string::npos) { |
314 DVLOG(1) << "Invalid layout_name: " << layout_name; | 254 DVLOG(1) << "Invalid layout_name: " << layout_name; |
315 return ""; | 255 return ""; |
316 } | 256 } |
317 | 257 |
318 std::string use_search_key_as_str; | 258 // TODO(yusukes): Remove "+chromeos(...)". |
319 std::string use_left_control_key_as_str; | |
320 std::string use_left_alt_key_as_str; | |
321 | |
322 for (size_t i = 0; i < modifier_map.size(); ++i) { | |
323 std::string* target = NULL; | |
324 switch (modifier_map[i].original) { | |
325 case kSearchKey: | |
326 target = &use_search_key_as_str; | |
327 break; | |
328 case kControlKey: | |
329 target = &use_left_control_key_as_str; | |
330 break; | |
331 case kAltKey: | |
332 target = &use_left_alt_key_as_str; | |
333 break; | |
334 default: | |
335 break; | |
336 } | |
337 if (!target) { | |
338 DVLOG(1) << "We don't support remaping " | |
339 << ModifierKeyToString(modifier_map[i].original); | |
340 return ""; | |
341 } | |
342 if (!(target->empty())) { | |
343 DVLOG(1) << ModifierKeyToString(modifier_map[i].original) | |
344 << " appeared twice"; | |
345 return ""; | |
346 } | |
347 *target = ModifierKeyToString(modifier_map[i].replacement); | |
348 } | |
349 | |
350 if (use_search_key_as_str.empty() || | |
351 use_left_control_key_as_str.empty() || | |
352 use_left_alt_key_as_str.empty()) { | |
353 DVLOG(1) << "Incomplete ModifierMap: size=" << modifier_map.size(); | |
354 return ""; | |
355 } | |
356 | |
357 if (KeepCapsLock(layout_name)) { | |
358 use_search_key_as_str = ModifierKeyToString(kSearchKey); | |
359 } | |
360 | |
361 std::string full_xkb_layout_name = | 259 std::string full_xkb_layout_name = |
362 base::StringPrintf("%s+chromeos(%s_%s_%s%s)", | 260 base::StringPrintf("%s+chromeos(search_leftcontrol_leftalt_keepralt)", |
363 layout_name.c_str(), | 261 layout_name.c_str()); |
364 use_search_key_as_str.c_str(), | |
365 use_left_control_key_as_str.c_str(), | |
366 use_left_alt_key_as_str.c_str(), | |
367 (KeepRightAlt(layout_name) ? "_keepralt" : "")); | |
368 | 262 |
369 return full_xkb_layout_name; | 263 return full_xkb_layout_name; |
370 } | 264 } |
371 | 265 |
372 void XKeyboardImpl::SetLockedModifiers(ModifierLockStatus new_caps_lock_status, | 266 void XKeyboardImpl::SetLockedModifiers(ModifierLockStatus new_caps_lock_status, |
373 ModifierLockStatus new_num_lock_status) { | 267 ModifierLockStatus new_num_lock_status) { |
374 CHECK(CurrentlyOnUIThread()); | 268 CHECK(CurrentlyOnUIThread()); |
375 if (!num_lock_mask_) { | 269 if (!num_lock_mask_) { |
376 DVLOG(1) << "Cannot set locked modifiers. Num Lock mask unknown."; | 270 DVLOG(1) << "Cannot set locked modifiers. Num Lock mask unknown."; |
377 return; | 271 return; |
378 } | 272 } |
379 | 273 |
380 unsigned int affect_mask = 0; | 274 unsigned int affect_mask = 0; |
381 unsigned int value_mask = 0; | 275 unsigned int value_mask = 0; |
382 if (new_caps_lock_status != kDontChange) { | 276 if (new_caps_lock_status != kDontChange) { |
383 affect_mask |= LockMask; | 277 affect_mask |= LockMask; |
384 value_mask |= ((new_caps_lock_status == kEnableLock) ? LockMask : 0); | 278 value_mask |= ((new_caps_lock_status == kEnableLock) ? LockMask : 0); |
385 current_caps_lock_status_ = (new_caps_lock_status == kEnableLock); | 279 current_caps_lock_status_ = (new_caps_lock_status == kEnableLock); |
386 } | 280 } |
387 if (new_num_lock_status != kDontChange) { | 281 if (new_num_lock_status != kDontChange) { |
388 affect_mask |= num_lock_mask_; | 282 affect_mask |= num_lock_mask_; |
389 value_mask |= ((new_num_lock_status == kEnableLock) ? num_lock_mask_ : 0); | 283 value_mask |= ((new_num_lock_status == kEnableLock) ? num_lock_mask_ : 0); |
390 current_num_lock_status_ = (new_num_lock_status == kEnableLock); | 284 current_num_lock_status_ = (new_num_lock_status == kEnableLock); |
391 } | 285 } |
392 | 286 |
393 if (affect_mask) { | 287 if (affect_mask) |
394 XkbLockModifiers(ui::GetXDisplay(), XkbUseCoreKbd, affect_mask, value_mask); | 288 XkbLockModifiers(ui::GetXDisplay(), XkbUseCoreKbd, affect_mask, value_mask); |
395 } | |
396 } | 289 } |
397 | 290 |
398 void XKeyboardImpl::SetNumLockEnabled(bool enable_num_lock) { | 291 void XKeyboardImpl::SetNumLockEnabled(bool enable_num_lock) { |
399 SetLockedModifiers( | 292 SetLockedModifiers( |
400 kDontChange, enable_num_lock ? kEnableLock : kDisableLock); | 293 kDontChange, enable_num_lock ? kEnableLock : kDisableLock); |
401 } | 294 } |
402 | 295 |
403 void XKeyboardImpl::SetCapsLockEnabled(bool enable_caps_lock) { | 296 void XKeyboardImpl::SetCapsLockEnabled(bool enable_caps_lock) { |
404 SetLockedModifiers( | 297 SetLockedModifiers( |
405 enable_caps_lock ? kEnableLock : kDisableLock, kDontChange); | 298 enable_caps_lock ? kEnableLock : kDisableLock, kDontChange); |
406 } | 299 } |
407 | 300 |
408 bool XKeyboardImpl::SetCurrentKeyboardLayoutByName( | 301 bool XKeyboardImpl::SetCurrentKeyboardLayoutByName( |
409 const std::string& layout_name) { | 302 const std::string& layout_name) { |
410 if (SetLayoutInternal(layout_name, current_modifier_map_, false)) { | 303 if (SetLayoutInternal(layout_name, false)) { |
411 current_layout_name_ = layout_name; | 304 current_layout_name_ = layout_name; |
412 return true; | 305 return true; |
413 } | 306 } |
414 return false; | 307 return false; |
415 } | 308 } |
416 | 309 |
417 bool XKeyboardImpl::ReapplyCurrentKeyboardLayout() { | 310 bool XKeyboardImpl::ReapplyCurrentKeyboardLayout() { |
418 if (current_layout_name_.empty()) { | 311 if (current_layout_name_.empty()) { |
419 DVLOG(1) << "Can't reapply XKB layout: layout unknown"; | 312 DVLOG(1) << "Can't reapply XKB layout: layout unknown"; |
420 return false; | 313 return false; |
421 } | 314 } |
422 return SetLayoutInternal( | 315 return SetLayoutInternal(current_layout_name_, true /* force */); |
423 current_layout_name_, current_modifier_map_, true /* force */); | |
424 } | 316 } |
425 | 317 |
426 void XKeyboardImpl::ReapplyCurrentModifierLockStatus() { | 318 void XKeyboardImpl::ReapplyCurrentModifierLockStatus() { |
427 SetLockedModifiers(current_caps_lock_status_ ? kEnableLock : kDisableLock, | 319 SetLockedModifiers(current_caps_lock_status_ ? kEnableLock : kDisableLock, |
428 current_num_lock_status_ ? kEnableLock : kDisableLock); | 320 current_num_lock_status_ ? kEnableLock : kDisableLock); |
429 } | 321 } |
430 | 322 |
431 bool XKeyboardImpl::RemapModifierKeys(const ModifierMap& modifier_map) { | |
432 const std::string layout_name = current_layout_name_.empty() ? | |
433 kDefaultLayoutName : current_layout_name_; | |
434 if (SetLayoutInternal(layout_name, modifier_map, false)) { | |
435 current_layout_name_ = layout_name; | |
436 current_modifier_map_ = modifier_map; | |
437 return true; | |
438 } | |
439 return false; | |
440 } | |
441 | |
442 bool XKeyboardImpl::KeepRightAlt(const std::string& xkb_layout_name) const { | |
443 return keep_right_alt_xkb_layout_names_.count(xkb_layout_name) > 0; | |
444 } | |
445 | |
446 bool XKeyboardImpl::KeepCapsLock(const std::string& xkb_layout_name) const { | |
447 return caps_lock_remapped_xkb_layout_names_.count(xkb_layout_name) > 0; | |
448 } | |
449 | |
450 bool XKeyboardImpl::CurrentlyOnUIThread() const { | 323 bool XKeyboardImpl::CurrentlyOnUIThread() const { |
451 // It seems that the tot Chrome (as of Mar 7 2012) does not allow browser | 324 // It seems that the tot Chrome (as of Mar 7 2012) does not allow browser |
452 // tests to call BrowserThread::CurrentlyOn(). It ends up a CHECK failure: | 325 // tests to call BrowserThread::CurrentlyOn(). It ends up a CHECK failure: |
453 // FATAL:sequenced_worker_pool.cc | 326 // FATAL:sequenced_worker_pool.cc |
454 // Check failed: constructor_message_loop_.get(). | 327 // Check failed: constructor_message_loop_.get(). |
455 // For now, just allow unit/browser tests to call any functions in this class. | 328 // For now, just allow unit/browser tests to call any functions in this class. |
456 // TODO(yusukes): Stop special-casing browser_tests and remove this function. | 329 // TODO(yusukes): Stop special-casing browser_tests and remove this function. |
457 if (!is_running_on_chrome_os_) { | 330 if (!is_running_on_chrome_os_) |
458 return true; | 331 return true; |
459 } | |
460 return BrowserThread::CurrentlyOn(BrowserThread::UI); | 332 return BrowserThread::CurrentlyOn(BrowserThread::UI); |
461 } | 333 } |
462 | 334 |
463 // static | 335 // static |
464 std::string XKeyboardImpl::ModifierKeyToString(ModifierKey key) { | |
465 switch (key) { | |
466 case kSearchKey: | |
467 return "search"; | |
468 case kControlKey: | |
469 return "leftcontrol"; | |
470 case kAltKey: | |
471 return "leftalt"; | |
472 case kVoidKey: | |
473 return "disabled"; | |
474 case kCapsLockKey: | |
475 return "capslock"; | |
476 case kNumModifierKeys: | |
477 break; | |
478 } | |
479 return ""; | |
480 } | |
481 | |
482 // static | |
483 void XKeyboardImpl::OnSetLayoutFinish(pid_t pid, | 336 void XKeyboardImpl::OnSetLayoutFinish(pid_t pid, |
484 int status, | 337 int status, |
485 XKeyboardImpl* self) { | 338 XKeyboardImpl* self) { |
486 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 339 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
487 DVLOG(1) << "OnSetLayoutFinish: pid=" << pid; | 340 DVLOG(1) << "OnSetLayoutFinish: pid=" << pid; |
488 if (self->execute_queue_.empty()) { | 341 if (self->execute_queue_.empty()) { |
489 DVLOG(1) << "OnSetLayoutFinish: execute_queue_ is empty. " | 342 DVLOG(1) << "OnSetLayoutFinish: execute_queue_ is empty. " |
490 << "base::LaunchProcess failed? pid=" << pid; | 343 << "base::LaunchProcess failed? pid=" << pid; |
491 return; | 344 return; |
492 } | 345 } |
493 self->execute_queue_.pop(); | 346 self->execute_queue_.pop(); |
494 self->MaybeExecuteSetLayoutCommand(); | 347 self->MaybeExecuteSetLayoutCommand(); |
495 } | 348 } |
496 | 349 |
497 } // namespace | 350 } // namespace |
498 | 351 |
499 // static | 352 // static |
500 bool XKeyboard::SetAutoRepeatEnabled(bool enabled) { | 353 bool XKeyboard::SetAutoRepeatEnabled(bool enabled) { |
501 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 354 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
502 if (enabled) { | 355 if (enabled) |
503 XAutoRepeatOn(ui::GetXDisplay()); | 356 XAutoRepeatOn(ui::GetXDisplay()); |
504 } else { | 357 else |
505 XAutoRepeatOff(ui::GetXDisplay()); | 358 XAutoRepeatOff(ui::GetXDisplay()); |
506 } | |
507 DVLOG(1) << "Set auto-repeat mode to: " << (enabled ? "on" : "off"); | 359 DVLOG(1) << "Set auto-repeat mode to: " << (enabled ? "on" : "off"); |
508 return true; | 360 return true; |
509 } | 361 } |
510 | 362 |
511 // static | 363 // static |
512 bool XKeyboard::SetAutoRepeatRate(const AutoRepeatRate& rate) { | 364 bool XKeyboard::SetAutoRepeatRate(const AutoRepeatRate& rate) { |
513 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 365 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
514 DVLOG(1) << "Set auto-repeat rate to: " | 366 DVLOG(1) << "Set auto-repeat rate to: " |
515 << rate.initial_delay_in_ms << " ms delay, " | 367 << rate.initial_delay_in_ms << " ms delay, " |
516 << rate.repeat_interval_in_ms << " ms interval"; | 368 << rate.repeat_interval_in_ms << " ms interval"; |
(...skipping 14 matching lines...) Expand all Loading... |
531 } | 383 } |
532 | 384 |
533 // static | 385 // static |
534 bool XKeyboard::GetAutoRepeatRateForTesting(AutoRepeatRate* out_rate) { | 386 bool XKeyboard::GetAutoRepeatRateForTesting(AutoRepeatRate* out_rate) { |
535 return XkbGetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, | 387 return XkbGetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, |
536 &(out_rate->initial_delay_in_ms), | 388 &(out_rate->initial_delay_in_ms), |
537 &(out_rate->repeat_interval_in_ms)) == True; | 389 &(out_rate->repeat_interval_in_ms)) == True; |
538 } | 390 } |
539 | 391 |
540 // static | 392 // static |
541 bool XKeyboard::ContainsModifierKeyAsReplacement( | |
542 const ModifierMap& modifier_map, | |
543 ModifierKey key) { | |
544 for (size_t i = 0; i < modifier_map.size(); ++i) { | |
545 if (modifier_map[i].replacement == key) { | |
546 return true; | |
547 } | |
548 } | |
549 return false; | |
550 } | |
551 | |
552 // static | |
553 XKeyboard* XKeyboard::Create(const InputMethodUtil& util) { | 393 XKeyboard* XKeyboard::Create(const InputMethodUtil& util) { |
554 return new XKeyboardImpl(util); | 394 return new XKeyboardImpl(util); |
555 } | 395 } |
556 | 396 |
557 } // namespace input_method | 397 } // namespace input_method |
558 } // namespace chromeos | 398 } // namespace chromeos |
OLD | NEW |