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