OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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> | |
8 #include <cstring> | |
7 #include <queue> | 9 #include <queue> |
8 #include <set> | 10 #include <set> |
9 #include <string> | |
10 #include <utility> | 11 #include <utility> |
11 | 12 |
12 #include <stdlib.h> | |
13 #include <string.h> | |
14 | |
15 #include "base/logging.h" | 13 #include "base/logging.h" |
16 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
17 #include "base/process_util.h" | 15 #include "base/process_util.h" |
18 #include "base/string_util.h" | 16 #include "base/string_util.h" |
19 #include "base/stringprintf.h" | 17 #include "base/stringprintf.h" |
20 #include "chrome/browser/chromeos/input_method/input_method_util.h" | 18 #include "chrome/browser/chromeos/input_method/input_method_util.h" |
21 #include "chrome/browser/chromeos/system/runtime_environment.h" | 19 #include "chrome/browser/chromeos/system/runtime_environment.h" |
22 #include "content/public/browser/browser_thread.h" | 20 #include "content/public/browser/browser_thread.h" |
23 #include "ui/base/x/x11_util.h" | 21 #include "ui/base/x/x11_util.h" |
24 | 22 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
94 | 92 |
95 // These are the overlay names with caps lock remapped | 93 // These are the overlay names with caps lock remapped |
96 const char* kCapsLockRemapped[] = { | 94 const char* kCapsLockRemapped[] = { |
97 "xkb:de:neo:ger", | 95 "xkb:de:neo:ger", |
98 "xkb:us:colemak:eng", | 96 "xkb:us:colemak:eng", |
99 }; | 97 }; |
100 | 98 |
101 // A string for obtaining a mask value for Num Lock. | 99 // A string for obtaining a mask value for Num Lock. |
102 const char kNumLockVirtualModifierString[] = "NumLock"; | 100 const char kNumLockVirtualModifierString[] = "NumLock"; |
103 | 101 |
104 } // namespace | 102 class XKeyboardImpl : public XKeyboard { |
103 public: | |
104 explicit XKeyboardImpl(const InputMethodUtil& util); | |
105 virtual ~XKeyboardImpl() {} | |
105 | 106 |
mazda
2012/01/20 02:31:43
// Overriden from XKeyboard:
Yusuke Sato
2012/01/20 03:33:48
Done.
| |
106 XKeyboard::XKeyboard(const InputMethodUtil& util) | 107 virtual bool SetCurrentKeyboardLayoutByName( |
108 const std::string& layout_name) OVERRIDE; | |
109 virtual bool RemapModifierKeys(const ModifierMap& modifier_map) OVERRIDE; | |
110 virtual bool ReapplyCurrentKeyboardLayout() OVERRIDE; | |
111 virtual void ReapplyCurrentModifierLockStatus() OVERRIDE; | |
112 virtual void SetLockedModifiers( | |
113 ModifierLockStatus new_caps_lock_status, | |
114 ModifierLockStatus new_num_lock_status) OVERRIDE; | |
115 virtual void SetNumLockEnabled(bool enable_num_lock) OVERRIDE; | |
116 virtual void SetCapsLockEnabled(bool enable_caps_lock) OVERRIDE; | |
117 virtual bool NumLockIsEnabled() OVERRIDE; | |
118 virtual bool CapsLockIsEnabled() OVERRIDE; | |
119 virtual unsigned int GetNumLockMask() OVERRIDE; | |
120 virtual void GetLockedModifiers(bool* out_caps_lock_enabled, | |
121 bool* out_num_lock_enabled) OVERRIDE; | |
122 virtual std::string CreateFullXkbLayoutName( | |
123 const std::string& layout_name, | |
124 const ModifierMap& modifire_map) OVERRIDE; | |
125 | |
126 private: | |
127 // This function is used by SetLayout() and RemapModifierKeys(). Calls | |
128 // setxkbmap command if needed, and updates the last_full_layout_name_ cache. | |
129 bool SetLayoutInternal(const std::string& layout_name, | |
130 const ModifierMap& modifier_map, | |
131 bool force); | |
132 | |
133 // Executes 'setxkbmap -layout ...' command asynchronously using a layout name | |
134 // in the |execute_queue_|. Do nothing if the queue is empty. | |
135 // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) | |
136 void MaybeExecuteSetLayoutCommand(); | |
137 | |
138 // Returns true if the XKB layout uses the right Alt key for special purposes | |
139 // like AltGr. | |
140 bool KeepRightAlt(const std::string& xkb_layout_name) const; | |
141 | |
142 // Returns true if the XKB layout uses the CapsLock key for special purposes. | |
143 // For example, since US Colemak layout uses the key as back space, | |
144 // KeepCapsLock("us(colemak)") would return true. | |
145 bool KeepCapsLock(const std::string& xkb_layout_name) const; | |
146 | |
147 // Converts |key| to a modifier key name which is used in | |
148 // /usr/share/X11/xkb/symbols/chromeos. | |
149 static std::string ModifierKeyToString(ModifierKey key); | |
150 | |
151 // Called when execve'd setxkbmap process exits. | |
152 static void OnSetLayoutFinish(pid_t pid, int status, XKeyboardImpl* self); | |
153 | |
154 const bool is_running_on_chrome_os_; | |
155 unsigned int num_lock_mask_; | |
156 | |
157 // The current Num Lock and Caps Lock status. If true, enabled. | |
158 bool current_num_lock_status_; | |
159 bool current_caps_lock_status_; | |
160 // The XKB layout name which we set last time like "us" and "us(dvorak)". | |
161 std::string current_layout_name_; | |
162 // The mapping of modifier keys we set last time. | |
163 ModifierMap current_modifier_map_; | |
164 | |
165 // A queue for executing setxkbmap one by one. | |
166 std::queue<std::string> execute_queue_; | |
167 | |
168 std::set<std::string> keep_right_alt_xkb_layout_names_; | |
169 std::set<std::string> caps_lock_remapped_xkb_layout_names_; | |
170 | |
171 DISALLOW_COPY_AND_ASSIGN(XKeyboardImpl); | |
172 }; | |
173 | |
174 XKeyboardImpl::XKeyboardImpl(const InputMethodUtil& util) | |
107 : is_running_on_chrome_os_( | 175 : is_running_on_chrome_os_( |
108 system::runtime_environment::IsRunningOnChromeOS()) { | 176 system::runtime_environment::IsRunningOnChromeOS()) { |
109 num_lock_mask_ = GetNumLockMask(); | 177 num_lock_mask_ = GetNumLockMask(); |
110 | 178 |
111 #if defined(USE_AURA) | 179 #if defined(USE_AURA) |
112 // web_input_event_aurax11.cc seems to assume that Mod2Mask is always assigned | 180 // web_input_event_aurax11.cc seems to assume that Mod2Mask is always assigned |
113 // to Num Lock. | 181 // to Num Lock. |
114 // TODO(yusukes): Check the assumption is really okay. If not, modify the Aura | 182 // TODO(yusukes): Check the assumption is really okay. If not, modify the Aura |
115 // code, and then remove the CHECK below. | 183 // code, and then remove the CHECK below. |
116 CHECK(!is_running_on_chrome_os_ || (num_lock_mask_ == Mod2Mask)); | 184 CHECK(!is_running_on_chrome_os_ || (num_lock_mask_ == Mod2Mask)); |
117 #endif | 185 #endif |
118 | 186 |
119 GetLockedModifiers( | 187 GetLockedModifiers(¤t_caps_lock_status_, ¤t_num_lock_status_); |
120 num_lock_mask_, ¤t_caps_lock_status_, ¤t_num_lock_status_); | |
121 | 188 |
122 for (size_t i = 0; i < arraysize(kCustomizableKeys); ++i) { | 189 for (size_t i = 0; i < arraysize(kCustomizableKeys); ++i) { |
123 ModifierKey key = kCustomizableKeys[i]; | 190 ModifierKey key = kCustomizableKeys[i]; |
124 current_modifier_map_.push_back(ModifierKeyPair(key, key)); | 191 current_modifier_map_.push_back(ModifierKeyPair(key, key)); |
125 } | 192 } |
126 | 193 |
127 std::string layout; | 194 std::string layout; |
128 for (size_t i = 0; i < arraysize(kKeepRightAltInputMethods); ++i) { | 195 for (size_t i = 0; i < arraysize(kKeepRightAltInputMethods); ++i) { |
129 layout = util.GetKeyboardLayoutName(kKeepRightAltInputMethods[i]); | 196 layout = util.GetKeyboardLayoutName(kKeepRightAltInputMethods[i]); |
130 // The empty check is necessary since USE_VIRTUAL_KEYBOARD build does not | 197 // The empty check is necessary since USE_VIRTUAL_KEYBOARD build does not |
131 // support some of the kKeepRightAltInputMethods elements. For example, | 198 // support some of the kKeepRightAltInputMethods elements. For example, |
132 // when USE_VIRTUAL_KEYBOARD is defined, | 199 // when USE_VIRTUAL_KEYBOARD is defined, |
133 // util.GetKeyboardLayoutName("xkb:us:intl:eng") would return "". | 200 // util.GetKeyboardLayoutName("xkb:us:intl:eng") would return "". |
134 if (!layout.empty()) { | 201 if (!layout.empty()) { |
135 keep_right_alt_xkb_layout_names_.insert(layout); | 202 keep_right_alt_xkb_layout_names_.insert(layout); |
136 } | 203 } |
137 } | 204 } |
138 for (size_t i = 0; i < arraysize(kCapsLockRemapped); ++i) { | 205 for (size_t i = 0; i < arraysize(kCapsLockRemapped); ++i) { |
139 layout = util.GetKeyboardLayoutName(kCapsLockRemapped[i]); | 206 layout = util.GetKeyboardLayoutName(kCapsLockRemapped[i]); |
140 // The empty check is for USE_VIRTUAL_KEYBOARD build. See above. | 207 // The empty check is for USE_VIRTUAL_KEYBOARD build. See above. |
141 if (!layout.empty()) { | 208 if (!layout.empty()) { |
142 caps_lock_remapped_xkb_layout_names_.insert(layout); | 209 caps_lock_remapped_xkb_layout_names_.insert(layout); |
143 } | 210 } |
144 } | 211 } |
145 } | 212 } |
146 | 213 |
147 XKeyboard::~XKeyboard() { | 214 bool XKeyboardImpl::SetLayoutInternal(const std::string& layout_name, |
148 } | |
149 | |
150 // static | |
151 unsigned int XKeyboard::GetNumLockMask() { | |
152 static const unsigned int kBadMask = 0; | |
153 | |
154 unsigned int real_mask = kBadMask; | |
155 XkbDescPtr xkb_desc = | |
156 XkbGetKeyboard(ui::GetXDisplay(), XkbAllComponentsMask, XkbUseCoreKbd); | |
157 if (!xkb_desc) { | |
158 return kBadMask; | |
159 } | |
160 | |
161 if (xkb_desc->dpy && xkb_desc->names && xkb_desc->names->vmods) { | |
162 const std::string string_to_find(kNumLockVirtualModifierString); | |
163 for (size_t i = 0; i < XkbNumVirtualMods; ++i) { | |
164 const unsigned int virtual_mod_mask = 1U << i; | |
165 char* virtual_mod_str = | |
166 XGetAtomName(xkb_desc->dpy, xkb_desc->names->vmods[i]); | |
167 if (!virtual_mod_str) { | |
168 continue; | |
169 } | |
170 if (string_to_find == virtual_mod_str) { | |
171 if (!XkbVirtualModsToReal(xkb_desc, virtual_mod_mask, &real_mask)) { | |
172 LOG(ERROR) << "XkbVirtualModsToReal failed"; | |
173 real_mask = kBadMask; // reset the return value, just in case. | |
174 } | |
175 XFree(virtual_mod_str); | |
176 break; | |
177 } | |
178 XFree(virtual_mod_str); | |
179 } | |
180 } | |
181 XkbFreeKeyboard(xkb_desc, 0, True /* free all components */); | |
182 return real_mask; | |
183 } | |
184 | |
185 bool XKeyboard::SetLayoutInternal(const std::string& layout_name, | |
186 const ModifierMap& modifier_map, | 215 const ModifierMap& modifier_map, |
187 bool force) { | 216 bool force) { |
188 if (!is_running_on_chrome_os_) { | 217 if (!is_running_on_chrome_os_) { |
189 // We should not try to change a layout on Linux or inside ui_tests. Just | 218 // We should not try to change a layout on Linux or inside ui_tests. Just |
190 // return true. | 219 // return true. |
191 return true; | 220 return true; |
192 } | 221 } |
193 | 222 |
194 const std::string layout_to_set = CreateFullXkbLayoutName( | 223 const std::string layout_to_set = CreateFullXkbLayoutName( |
195 layout_name, modifier_map); | 224 layout_name, modifier_map); |
(...skipping 26 matching lines...) Expand all Loading... | |
222 execute_queue_.push(layout_to_set); | 251 execute_queue_.push(layout_to_set); |
223 if (start_execution) { | 252 if (start_execution) { |
224 MaybeExecuteSetLayoutCommand(); | 253 MaybeExecuteSetLayoutCommand(); |
225 } | 254 } |
226 return true; | 255 return true; |
227 } | 256 } |
228 | 257 |
229 // Executes 'setxkbmap -layout ...' command asynchronously using a layout name | 258 // Executes 'setxkbmap -layout ...' command asynchronously using a layout name |
230 // in the |execute_queue_|. Do nothing if the queue is empty. | 259 // in the |execute_queue_|. Do nothing if the queue is empty. |
231 // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) | 260 // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) |
232 void XKeyboard::MaybeExecuteSetLayoutCommand() { | 261 void XKeyboardImpl::MaybeExecuteSetLayoutCommand() { |
233 if (execute_queue_.empty()) { | 262 if (execute_queue_.empty()) { |
234 return; | 263 return; |
235 } | 264 } |
236 const std::string layout_to_set = execute_queue_.front(); | 265 const std::string layout_to_set = execute_queue_.front(); |
237 | 266 |
238 std::vector<std::string> argv; | 267 std::vector<std::string> argv; |
239 base::ProcessHandle handle = base::kNullProcessHandle; | 268 base::ProcessHandle handle = base::kNullProcessHandle; |
240 | 269 |
241 argv.push_back(kSetxkbmapCommand); | 270 argv.push_back(kSetxkbmapCommand); |
242 argv.push_back("-layout"); | 271 argv.push_back("-layout"); |
243 argv.push_back(layout_to_set); | 272 argv.push_back(layout_to_set); |
244 argv.push_back("-synch"); | 273 argv.push_back("-synch"); |
245 | 274 |
246 if (!base::LaunchProcess(argv, base::LaunchOptions(), &handle)) { | 275 if (!base::LaunchProcess(argv, base::LaunchOptions(), &handle)) { |
247 LOG(ERROR) << "Failed to execute setxkbmap: " << layout_to_set; | 276 LOG(ERROR) << "Failed to execute setxkbmap: " << layout_to_set; |
248 execute_queue_ = std::queue<std::string>(); // clear the queue. | 277 execute_queue_ = std::queue<std::string>(); // clear the queue. |
249 return; | 278 return; |
250 } | 279 } |
251 | 280 |
252 // g_child_watch_add is necessary to prevent the process from becoming a | 281 // g_child_watch_add is necessary to prevent the process from becoming a |
253 // zombie. | 282 // zombie. |
254 const base::ProcessId pid = base::GetProcId(handle); | 283 const base::ProcessId pid = base::GetProcId(handle); |
255 g_child_watch_add(pid, | 284 g_child_watch_add(pid, |
256 reinterpret_cast<GChildWatchFunc>(OnSetLayoutFinish), | 285 reinterpret_cast<GChildWatchFunc>(OnSetLayoutFinish), |
257 this); | 286 this); |
258 VLOG(1) << "ExecuteSetLayoutCommand: " << layout_to_set << ": pid=" << pid; | 287 VLOG(1) << "ExecuteSetLayoutCommand: " << layout_to_set << ": pid=" << pid; |
259 } | 288 } |
260 | 289 |
261 // static | 290 bool XKeyboardImpl::NumLockIsEnabled() { |
262 void XKeyboard::OnSetLayoutFinish(pid_t pid, int status, XKeyboard* self) { | 291 bool num_lock_enabled = false; |
263 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 292 GetLockedModifiers(NULL /* Caps Lock */, &num_lock_enabled); |
264 VLOG(1) << "OnSetLayoutFinish: pid=" << pid; | 293 return num_lock_enabled; |
265 if (self->execute_queue_.empty()) { | 294 } |
266 LOG(ERROR) << "OnSetLayoutFinish: execute_queue_ is empty. " | 295 |
267 << "base::LaunchProcess failed? pid=" << pid; | 296 bool XKeyboardImpl::CapsLockIsEnabled() { |
297 bool caps_lock_enabled = false; | |
298 GetLockedModifiers(&caps_lock_enabled, NULL /* Num Lock */); | |
299 return caps_lock_enabled; | |
300 } | |
301 | |
302 unsigned int XKeyboardImpl::GetNumLockMask() { | |
303 static const unsigned int kBadMask = 0; | |
304 | |
305 unsigned int real_mask = kBadMask; | |
306 XkbDescPtr xkb_desc = | |
307 XkbGetKeyboard(ui::GetXDisplay(), XkbAllComponentsMask, XkbUseCoreKbd); | |
308 if (!xkb_desc) { | |
309 return kBadMask; | |
310 } | |
311 | |
312 if (xkb_desc->dpy && xkb_desc->names && xkb_desc->names->vmods) { | |
313 const std::string string_to_find(kNumLockVirtualModifierString); | |
314 for (size_t i = 0; i < XkbNumVirtualMods; ++i) { | |
315 const unsigned int virtual_mod_mask = 1U << i; | |
316 char* virtual_mod_str = | |
317 XGetAtomName(xkb_desc->dpy, xkb_desc->names->vmods[i]); | |
318 if (!virtual_mod_str) { | |
319 continue; | |
320 } | |
321 if (string_to_find == virtual_mod_str) { | |
322 if (!XkbVirtualModsToReal(xkb_desc, virtual_mod_mask, &real_mask)) { | |
323 LOG(ERROR) << "XkbVirtualModsToReal failed"; | |
324 real_mask = kBadMask; // reset the return value, just in case. | |
325 } | |
326 XFree(virtual_mod_str); | |
327 break; | |
328 } | |
329 XFree(virtual_mod_str); | |
330 } | |
331 } | |
332 XkbFreeKeyboard(xkb_desc, 0, True /* free all components */); | |
333 return real_mask; | |
334 } | |
335 | |
336 void XKeyboardImpl::GetLockedModifiers(bool* out_caps_lock_enabled, | |
337 bool* out_num_lock_enabled) { | |
338 // For now, don't call CHECK() here to make | |
339 // TabRestoreServiceTest.DontRestorePrintPreviewTab test happy. | |
340 // TODO(yusukes): Fix the test, then fix the if(!BrowserThread...) line below. | |
341 // CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
342 | |
343 if (!BrowserThread::CurrentlyOn(BrowserThread::UI) || | |
344 (out_num_lock_enabled && !num_lock_mask_)) { | |
345 LOG(ERROR) << "Cannot get locked modifiers."; | |
346 if (out_caps_lock_enabled) { | |
347 *out_caps_lock_enabled = false; | |
348 } | |
349 if (out_num_lock_enabled) { | |
350 *out_num_lock_enabled = false; | |
351 } | |
268 return; | 352 return; |
269 } | 353 } |
270 self->execute_queue_.pop(); | 354 |
271 self->MaybeExecuteSetLayoutCommand(); | 355 XkbStateRec status; |
356 XkbGetState(ui::GetXDisplay(), XkbUseCoreKbd, &status); | |
357 if (out_caps_lock_enabled) { | |
358 *out_caps_lock_enabled = status.locked_mods & LockMask; | |
359 } | |
360 if (out_num_lock_enabled) { | |
361 *out_num_lock_enabled = status.locked_mods & num_lock_mask_; | |
362 } | |
272 } | 363 } |
273 | 364 |
274 std::string XKeyboard::CreateFullXkbLayoutName( | 365 std::string XKeyboardImpl::CreateFullXkbLayoutName( |
275 const std::string& layout_name, const ModifierMap& modifier_map) { | 366 const std::string& layout_name, const ModifierMap& modifier_map) { |
276 static const char kValidLayoutNameCharacters[] = | 367 static const char kValidLayoutNameCharacters[] = |
277 "abcdefghijklmnopqrstuvwxyz0123456789()-_"; | 368 "abcdefghijklmnopqrstuvwxyz0123456789()-_"; |
278 | 369 |
279 if (layout_name.empty()) { | 370 if (layout_name.empty()) { |
280 LOG(ERROR) << "Invalid layout_name: " << layout_name; | 371 LOG(ERROR) << "Invalid layout_name: " << layout_name; |
281 return ""; | 372 return ""; |
282 } | 373 } |
283 | 374 |
284 if (layout_name.find_first_not_of(kValidLayoutNameCharacters) != | 375 if (layout_name.find_first_not_of(kValidLayoutNameCharacters) != |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
339 (KeepRightAlt(layout_name) ? "_keepralt" : "")); | 430 (KeepRightAlt(layout_name) ? "_keepralt" : "")); |
340 | 431 |
341 if ((full_xkb_layout_name.substr(0, 3) != "us+") && | 432 if ((full_xkb_layout_name.substr(0, 3) != "us+") && |
342 (full_xkb_layout_name.substr(0, 3) != "us(")) { | 433 (full_xkb_layout_name.substr(0, 3) != "us(")) { |
343 full_xkb_layout_name += ",us"; | 434 full_xkb_layout_name += ",us"; |
344 } | 435 } |
345 | 436 |
346 return full_xkb_layout_name; | 437 return full_xkb_layout_name; |
347 } | 438 } |
348 | 439 |
349 // static | 440 void XKeyboardImpl::SetLockedModifiers(ModifierLockStatus new_caps_lock_status, |
350 bool XKeyboard::SetAutoRepeatEnabled(bool enabled) { | 441 ModifierLockStatus new_num_lock_status) { |
351 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
352 if (enabled) { | |
353 XAutoRepeatOn(ui::GetXDisplay()); | |
354 } else { | |
355 XAutoRepeatOff(ui::GetXDisplay()); | |
356 } | |
357 DLOG(INFO) << "Set auto-repeat mode to: " << (enabled ? "on" : "off"); | |
358 return true; | |
359 } | |
360 | |
361 // static | |
362 bool XKeyboard::SetAutoRepeatRate(const AutoRepeatRate& rate) { | |
363 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
364 DLOG(INFO) << "Set auto-repeat rate to: " | |
365 << rate.initial_delay_in_ms << " ms delay, " | |
366 << rate.repeat_interval_in_ms << " ms interval"; | |
367 if (XkbSetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, | |
368 rate.initial_delay_in_ms, | |
369 rate.repeat_interval_in_ms) != True) { | |
370 LOG(ERROR) << "Failed to set auto-repeat rate"; | |
371 return false; | |
372 } | |
373 return true; | |
374 } | |
375 | |
376 // static | |
377 bool XKeyboard::GetAutoRepeatEnabled() { | |
378 XKeyboardState state = {}; | |
379 XGetKeyboardControl(ui::GetXDisplay(), &state); | |
380 return state.global_auto_repeat != AutoRepeatModeOff; | |
381 } | |
382 | |
383 // static | |
384 bool XKeyboard::GetAutoRepeatRate(AutoRepeatRate* out_rate) { | |
385 return XkbGetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, | |
386 &(out_rate->initial_delay_in_ms), | |
387 &(out_rate->repeat_interval_in_ms)) == True; | |
388 } | |
389 | |
390 void XKeyboard::SetLockedModifiers(ModifierLockStatus new_caps_lock_status, | |
391 ModifierLockStatus new_num_lock_status) { | |
392 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 442 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
393 if (!num_lock_mask_) { | 443 if (!num_lock_mask_) { |
394 LOG(ERROR) << "Cannot set locked modifiers. Num Lock mask unknown."; | 444 LOG(ERROR) << "Cannot set locked modifiers. Num Lock mask unknown."; |
395 return; | 445 return; |
396 } | 446 } |
397 | 447 |
398 unsigned int affect_mask = 0; | 448 unsigned int affect_mask = 0; |
399 unsigned int value_mask = 0; | 449 unsigned int value_mask = 0; |
400 if (new_caps_lock_status != kDontChange) { | 450 if (new_caps_lock_status != kDontChange) { |
401 affect_mask |= LockMask; | 451 affect_mask |= LockMask; |
402 value_mask |= ((new_caps_lock_status == kEnableLock) ? LockMask : 0); | 452 value_mask |= ((new_caps_lock_status == kEnableLock) ? LockMask : 0); |
403 current_caps_lock_status_ = (new_caps_lock_status == kEnableLock); | 453 current_caps_lock_status_ = (new_caps_lock_status == kEnableLock); |
404 } | 454 } |
405 if (new_num_lock_status != kDontChange) { | 455 if (new_num_lock_status != kDontChange) { |
406 affect_mask |= num_lock_mask_; | 456 affect_mask |= num_lock_mask_; |
407 value_mask |= ((new_num_lock_status == kEnableLock) ? num_lock_mask_ : 0); | 457 value_mask |= ((new_num_lock_status == kEnableLock) ? num_lock_mask_ : 0); |
408 current_num_lock_status_ = (new_num_lock_status == kEnableLock); | 458 current_num_lock_status_ = (new_num_lock_status == kEnableLock); |
409 } | 459 } |
410 | 460 |
411 if (affect_mask) { | 461 if (affect_mask) { |
412 XkbLockModifiers(ui::GetXDisplay(), XkbUseCoreKbd, affect_mask, value_mask); | 462 XkbLockModifiers(ui::GetXDisplay(), XkbUseCoreKbd, affect_mask, value_mask); |
413 } | 463 } |
414 } | 464 } |
415 | 465 |
416 void XKeyboard::SetNumLockEnabled(bool enable_num_lock) { | 466 void XKeyboardImpl::SetNumLockEnabled(bool enable_num_lock) { |
417 SetLockedModifiers( | 467 SetLockedModifiers( |
418 kDontChange, enable_num_lock ? kEnableLock : kDisableLock); | 468 kDontChange, enable_num_lock ? kEnableLock : kDisableLock); |
419 } | 469 } |
420 | 470 |
421 void XKeyboard::SetCapsLockEnabled(bool enable_caps_lock) { | 471 void XKeyboardImpl::SetCapsLockEnabled(bool enable_caps_lock) { |
422 SetLockedModifiers( | 472 SetLockedModifiers( |
423 enable_caps_lock ? kEnableLock : kDisableLock, kDontChange); | 473 enable_caps_lock ? kEnableLock : kDisableLock, kDontChange); |
424 } | 474 } |
425 | 475 |
426 // static | 476 bool XKeyboardImpl::SetCurrentKeyboardLayoutByName( |
427 void XKeyboard::GetLockedModifiers(unsigned int num_lock_mask, | 477 const std::string& layout_name) { |
428 bool* out_caps_lock_enabled, | |
429 bool* out_num_lock_enabled) { | |
430 // For now, don't call CHECK() here to make | |
431 // TabRestoreServiceTest.DontRestorePrintPreviewTab test happy. | |
432 // TODO(yusukes): Fix the test, then fix the if(!BrowserThread...) line below. | |
433 // CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
434 | |
435 if (!BrowserThread::CurrentlyOn(BrowserThread::UI) || | |
436 (out_num_lock_enabled && !num_lock_mask)) { | |
437 LOG(ERROR) << "Cannot get locked modifiers."; | |
438 if (out_caps_lock_enabled) { | |
439 *out_caps_lock_enabled = false; | |
440 } | |
441 if (out_num_lock_enabled) { | |
442 *out_num_lock_enabled = false; | |
443 } | |
444 return; | |
445 } | |
446 | |
447 XkbStateRec status; | |
448 XkbGetState(ui::GetXDisplay(), XkbUseCoreKbd, &status); | |
449 if (out_caps_lock_enabled) { | |
450 *out_caps_lock_enabled = status.locked_mods & LockMask; | |
451 } | |
452 if (out_num_lock_enabled) { | |
453 *out_num_lock_enabled = status.locked_mods & num_lock_mask; | |
454 } | |
455 } | |
456 | |
457 // static | |
458 bool XKeyboard::NumLockIsEnabled(unsigned int num_lock_mask) { | |
459 bool num_lock_enabled = false; | |
460 GetLockedModifiers(num_lock_mask, NULL /* Caps Lock */, &num_lock_enabled); | |
461 return num_lock_enabled; | |
462 } | |
463 | |
464 // static | |
465 bool XKeyboard::CapsLockIsEnabled() { | |
466 bool caps_lock_enabled = false; | |
467 GetLockedModifiers(0, &caps_lock_enabled, NULL /* Num Lock */); | |
468 return caps_lock_enabled; | |
469 } | |
470 | |
471 // static | |
472 bool XKeyboard::ContainsModifierKeyAsReplacement( | |
473 const ModifierMap& modifier_map, ModifierKey key) { | |
474 for (size_t i = 0; i < modifier_map.size(); ++i) { | |
475 if (modifier_map[i].replacement == key) { | |
476 return true; | |
477 } | |
478 } | |
479 return false; | |
480 } | |
481 | |
482 bool XKeyboard::SetCurrentKeyboardLayoutByName(const std::string& layout_name) { | |
483 if (SetLayoutInternal(layout_name, current_modifier_map_, false)) { | 478 if (SetLayoutInternal(layout_name, current_modifier_map_, false)) { |
484 current_layout_name_ = layout_name; | 479 current_layout_name_ = layout_name; |
485 return true; | 480 return true; |
486 } | 481 } |
487 return false; | 482 return false; |
488 } | 483 } |
489 | 484 |
490 bool XKeyboard::ReapplyCurrentKeyboardLayout() { | 485 bool XKeyboardImpl::ReapplyCurrentKeyboardLayout() { |
491 if (current_layout_name_.empty()) { | 486 if (current_layout_name_.empty()) { |
492 LOG(ERROR) << "Can't reapply XKB layout: layout unknown"; | 487 LOG(ERROR) << "Can't reapply XKB layout: layout unknown"; |
493 return false; | 488 return false; |
494 } | 489 } |
495 return SetLayoutInternal( | 490 return SetLayoutInternal( |
496 current_layout_name_, current_modifier_map_, true /* force */); | 491 current_layout_name_, current_modifier_map_, true /* force */); |
497 } | 492 } |
498 | 493 |
499 void XKeyboard::ReapplyCurrentModifierLockStatus() { | 494 void XKeyboardImpl::ReapplyCurrentModifierLockStatus() { |
500 SetLockedModifiers(current_caps_lock_status_ ? kEnableLock : kDisableLock, | 495 SetLockedModifiers(current_caps_lock_status_ ? kEnableLock : kDisableLock, |
501 current_num_lock_status_ ? kEnableLock : kDisableLock); | 496 current_num_lock_status_ ? kEnableLock : kDisableLock); |
502 } | 497 } |
503 | 498 |
504 bool XKeyboard::RemapModifierKeys(const ModifierMap& modifier_map) { | 499 bool XKeyboardImpl::RemapModifierKeys(const ModifierMap& modifier_map) { |
505 const std::string layout_name = current_layout_name_.empty() ? | 500 const std::string layout_name = current_layout_name_.empty() ? |
506 kDefaultLayoutName : current_layout_name_; | 501 kDefaultLayoutName : current_layout_name_; |
507 if (SetLayoutInternal(layout_name, modifier_map, false)) { | 502 if (SetLayoutInternal(layout_name, modifier_map, false)) { |
508 current_layout_name_ = layout_name; | 503 current_layout_name_ = layout_name; |
509 current_modifier_map_ = modifier_map; | 504 current_modifier_map_ = modifier_map; |
510 return true; | 505 return true; |
511 } | 506 } |
512 return false; | 507 return false; |
513 } | 508 } |
514 | 509 |
515 bool XKeyboard::KeepRightAlt(const std::string& xkb_layout_name) const { | 510 bool XKeyboardImpl::KeepRightAlt(const std::string& xkb_layout_name) const { |
516 return keep_right_alt_xkb_layout_names_.count(xkb_layout_name) > 0; | 511 return keep_right_alt_xkb_layout_names_.count(xkb_layout_name) > 0; |
517 } | 512 } |
518 | 513 |
519 bool XKeyboard::KeepCapsLock(const std::string& xkb_layout_name) const { | 514 bool XKeyboardImpl::KeepCapsLock(const std::string& xkb_layout_name) const { |
520 return caps_lock_remapped_xkb_layout_names_.count(xkb_layout_name) > 0; | 515 return caps_lock_remapped_xkb_layout_names_.count(xkb_layout_name) > 0; |
521 } | 516 } |
522 | 517 |
523 // static | 518 // static |
524 std::string XKeyboard::ModifierKeyToString(ModifierKey key) { | 519 std::string XKeyboardImpl::ModifierKeyToString(ModifierKey key) { |
525 switch (key) { | 520 switch (key) { |
526 case kSearchKey: | 521 case kSearchKey: |
527 return "search"; | 522 return "search"; |
528 case kLeftControlKey: | 523 case kLeftControlKey: |
529 return "leftcontrol"; | 524 return "leftcontrol"; |
530 case kLeftAltKey: | 525 case kLeftAltKey: |
531 return "leftalt"; | 526 return "leftalt"; |
532 case kVoidKey: | 527 case kVoidKey: |
533 return "disabled"; | 528 return "disabled"; |
534 case kCapsLockKey: | 529 case kCapsLockKey: |
535 return "capslock"; | 530 return "capslock"; |
536 case kNumModifierKeys: | 531 case kNumModifierKeys: |
537 break; | 532 break; |
538 } | 533 } |
539 return ""; | 534 return ""; |
540 } | 535 } |
541 | 536 |
537 // static | |
538 void XKeyboardImpl::OnSetLayoutFinish(pid_t pid, | |
539 int status, | |
540 XKeyboardImpl* self) { | |
541 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
542 VLOG(1) << "OnSetLayoutFinish: pid=" << pid; | |
543 if (self->execute_queue_.empty()) { | |
544 LOG(ERROR) << "OnSetLayoutFinish: execute_queue_ is empty. " | |
545 << "base::LaunchProcess failed? pid=" << pid; | |
546 return; | |
547 } | |
548 self->execute_queue_.pop(); | |
549 self->MaybeExecuteSetLayoutCommand(); | |
550 } | |
551 | |
552 } // namespace | |
553 | |
554 // static | |
555 bool XKeyboard::SetAutoRepeatEnabled(bool enabled) { | |
556 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
557 if (enabled) { | |
558 XAutoRepeatOn(ui::GetXDisplay()); | |
559 } else { | |
560 XAutoRepeatOff(ui::GetXDisplay()); | |
561 } | |
562 DLOG(INFO) << "Set auto-repeat mode to: " << (enabled ? "on" : "off"); | |
563 return true; | |
564 } | |
565 | |
566 // static | |
567 bool XKeyboard::SetAutoRepeatRate(const AutoRepeatRate& rate) { | |
568 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
569 DLOG(INFO) << "Set auto-repeat rate to: " | |
570 << rate.initial_delay_in_ms << " ms delay, " | |
571 << rate.repeat_interval_in_ms << " ms interval"; | |
572 if (XkbSetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, | |
573 rate.initial_delay_in_ms, | |
574 rate.repeat_interval_in_ms) != True) { | |
575 LOG(ERROR) << "Failed to set auto-repeat rate"; | |
576 return false; | |
577 } | |
578 return true; | |
579 } | |
580 | |
581 // static | |
582 bool XKeyboard::GetAutoRepeatEnabledForTesting() { | |
583 XKeyboardState state = {}; | |
584 XGetKeyboardControl(ui::GetXDisplay(), &state); | |
585 return state.global_auto_repeat != AutoRepeatModeOff; | |
586 } | |
587 | |
588 // static | |
589 bool XKeyboard::GetAutoRepeatRateForTesting(AutoRepeatRate* out_rate) { | |
590 return XkbGetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, | |
591 &(out_rate->initial_delay_in_ms), | |
592 &(out_rate->repeat_interval_in_ms)) == True; | |
593 } | |
594 | |
595 // static | |
596 bool XKeyboard::ContainsModifierKeyAsReplacement( | |
597 const ModifierMap& modifier_map, ModifierKey key) { | |
598 for (size_t i = 0; i < modifier_map.size(); ++i) { | |
599 if (modifier_map[i].replacement == key) { | |
600 return true; | |
601 } | |
602 } | |
603 return false; | |
604 } | |
605 | |
606 // static | |
607 XKeyboard* XKeyboard::Create(const InputMethodUtil& util) { | |
608 return new XKeyboardImpl(util); | |
609 } | |
610 | |
542 } // namespace input_method | 611 } // namespace input_method |
543 } // namespace chromeos | 612 } // namespace chromeos |
OLD | NEW |