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