| 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 |