OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "chromeos/ime/xkeyboard.h" | 5 #include "chromeos/ime/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> |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
67 class XKeyboardImpl : public XKeyboard { | 67 class XKeyboardImpl : public XKeyboard { |
68 public: | 68 public: |
69 XKeyboardImpl(); | 69 XKeyboardImpl(); |
70 virtual ~XKeyboardImpl() {} | 70 virtual ~XKeyboardImpl() {} |
71 | 71 |
72 // Overridden from XKeyboard: | 72 // Overridden from XKeyboard: |
73 virtual bool SetCurrentKeyboardLayoutByName( | 73 virtual bool SetCurrentKeyboardLayoutByName( |
74 const std::string& layout_name) OVERRIDE; | 74 const std::string& layout_name) OVERRIDE; |
75 virtual bool ReapplyCurrentKeyboardLayout() OVERRIDE; | 75 virtual bool ReapplyCurrentKeyboardLayout() OVERRIDE; |
76 virtual void ReapplyCurrentModifierLockStatus() OVERRIDE; | 76 virtual void ReapplyCurrentModifierLockStatus() OVERRIDE; |
77 virtual void SetLockedModifiers( | 77 virtual void DisableNumLock() OVERRIDE; |
78 ModifierLockStatus new_caps_lock_status, | |
79 ModifierLockStatus new_num_lock_status) OVERRIDE; | |
80 virtual void SetNumLockEnabled(bool enable_num_lock) OVERRIDE; | |
81 virtual void SetCapsLockEnabled(bool enable_caps_lock) OVERRIDE; | 78 virtual void SetCapsLockEnabled(bool enable_caps_lock) OVERRIDE; |
82 virtual bool NumLockIsEnabled() OVERRIDE; | |
83 virtual bool CapsLockIsEnabled() OVERRIDE; | 79 virtual bool CapsLockIsEnabled() OVERRIDE; |
84 virtual unsigned int GetNumLockMask() OVERRIDE; | |
85 virtual void GetLockedModifiers(bool* out_caps_lock_enabled, | |
86 bool* out_num_lock_enabled) OVERRIDE; | |
87 virtual bool SetAutoRepeatEnabled(bool enabled) OVERRIDE; | 80 virtual bool SetAutoRepeatEnabled(bool enabled) OVERRIDE; |
88 virtual bool SetAutoRepeatRate(const AutoRepeatRate& rate) OVERRIDE; | 81 virtual bool SetAutoRepeatRate(const AutoRepeatRate& rate) OVERRIDE; |
89 | 82 |
90 private: | 83 private: |
84 unsigned int GetNumLockMask(); | |
Daniel Erat
2014/03/09 04:17:55
nit: add a comment documenting what this returns (
sadrul
2014/03/09 04:52:26
Done.
| |
85 void SetLockedModifiers(bool caps_lock_enabled); | |
Daniel Erat
2014/03/09 04:17:55
nit: blank line between the previous method and th
sadrul
2014/03/09 04:52:26
Done.
| |
86 | |
91 // This function is used by SetLayout() and RemapModifierKeys(). Calls | 87 // This function is used by SetLayout() and RemapModifierKeys(). Calls |
92 // setxkbmap command if needed, and updates the last_full_layout_name_ cache. | 88 // setxkbmap command if needed, and updates the last_full_layout_name_ cache. |
93 bool SetLayoutInternal(const std::string& layout_name, bool force); | 89 bool SetLayoutInternal(const std::string& layout_name, bool force); |
94 | 90 |
95 // Executes 'setxkbmap -layout ...' command asynchronously using a layout name | 91 // Executes 'setxkbmap -layout ...' command asynchronously using a layout name |
96 // in the |execute_queue_|. Do nothing if the queue is empty. | 92 // in the |execute_queue_|. Do nothing if the queue is empty. |
97 // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) | 93 // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) |
98 void MaybeExecuteSetLayoutCommand(); | 94 void MaybeExecuteSetLayoutCommand(); |
99 | 95 |
100 // Polls to see setxkbmap process exits. | 96 // Polls to see setxkbmap process exits. |
101 void PollUntilChildFinish(const base::ProcessHandle handle); | 97 void PollUntilChildFinish(const base::ProcessHandle handle); |
102 | 98 |
103 // Called when execve'd setxkbmap process exits. | 99 // Called when execve'd setxkbmap process exits. |
104 void OnSetLayoutFinish(); | 100 void OnSetLayoutFinish(); |
105 | 101 |
106 const bool is_running_on_chrome_os_; | 102 const bool is_running_on_chrome_os_; |
107 unsigned int num_lock_mask_; | 103 unsigned int num_lock_mask_; |
108 | 104 |
109 // The current Num Lock and Caps Lock status. If true, enabled. | 105 // The current Caps Lock status. If true, enabled. |
110 bool current_num_lock_status_; | |
111 bool current_caps_lock_status_; | 106 bool current_caps_lock_status_; |
107 | |
112 // The XKB layout name which we set last time like "us" and "us(dvorak)". | 108 // The XKB layout name which we set last time like "us" and "us(dvorak)". |
113 std::string current_layout_name_; | 109 std::string current_layout_name_; |
114 | 110 |
115 // A queue for executing setxkbmap one by one. | 111 // A queue for executing setxkbmap one by one. |
116 std::queue<std::string> execute_queue_; | 112 std::queue<std::string> execute_queue_; |
117 | 113 |
118 base::ThreadChecker thread_checker_; | 114 base::ThreadChecker thread_checker_; |
119 | 115 |
120 base::WeakPtrFactory<XKeyboardImpl> weak_factory_; | 116 base::WeakPtrFactory<XKeyboardImpl> weak_factory_; |
121 | 117 |
(...skipping 10 matching lines...) Expand all Loading... | |
132 | 128 |
133 if (is_running_on_chrome_os_) { | 129 if (is_running_on_chrome_os_) { |
134 // Some code seems to assume that Mod2Mask is always assigned to | 130 // Some code seems to assume that Mod2Mask is always assigned to |
135 // Num Lock. | 131 // Num Lock. |
136 // | 132 // |
137 // TODO(yusukes): Check the assumption is really okay. If not, | 133 // TODO(yusukes): Check the assumption is really okay. If not, |
138 // modify the Aura code, and then remove the CHECK below. | 134 // modify the Aura code, and then remove the CHECK below. |
139 LOG_IF(ERROR, num_lock_mask_ != Mod2Mask) | 135 LOG_IF(ERROR, num_lock_mask_ != Mod2Mask) |
140 << "NumLock is not assigned to Mod2Mask. : " << num_lock_mask_; | 136 << "NumLock is not assigned to Mod2Mask. : " << num_lock_mask_; |
141 } | 137 } |
142 GetLockedModifiers(¤t_caps_lock_status_, ¤t_num_lock_status_); | 138 |
139 current_caps_lock_status_ = CapsLockIsEnabled(); | |
140 } | |
141 | |
142 unsigned int XKeyboardImpl::GetNumLockMask() { | |
143 DCHECK(thread_checker_.CalledOnValidThread()); | |
144 static const unsigned int kBadMask = 0; | |
145 | |
146 unsigned int real_mask = kBadMask; | |
147 XkbDescPtr xkb_desc = | |
148 XkbGetKeyboard(GetXDisplay(), XkbAllComponentsMask, XkbUseCoreKbd); | |
149 if (!xkb_desc) | |
150 return kBadMask; | |
151 | |
152 if (xkb_desc->dpy && xkb_desc->names && xkb_desc->names->vmods) { | |
153 const std::string string_to_find(kNumLockVirtualModifierString); | |
154 for (size_t i = 0; i < XkbNumVirtualMods; ++i) { | |
155 const unsigned int virtual_mod_mask = 1U << i; | |
156 char* virtual_mod_str_raw_ptr = | |
157 XGetAtomName(xkb_desc->dpy, xkb_desc->names->vmods[i]); | |
158 if (!virtual_mod_str_raw_ptr) | |
159 continue; | |
160 const std::string virtual_mod_str = virtual_mod_str_raw_ptr; | |
161 XFree(virtual_mod_str_raw_ptr); | |
162 | |
163 if (string_to_find == virtual_mod_str) { | |
164 if (!XkbVirtualModsToReal(xkb_desc, virtual_mod_mask, &real_mask)) { | |
165 DVLOG(1) << "XkbVirtualModsToReal failed"; | |
166 real_mask = kBadMask; // reset the return value, just in case. | |
167 } | |
168 break; | |
169 } | |
170 } | |
171 } | |
172 XkbFreeKeyboard(xkb_desc, 0, True /* free all components */); | |
173 return real_mask; | |
174 } | |
175 | |
176 void XKeyboardImpl::SetLockedModifiers(bool caps_lock_enabled) { | |
177 DCHECK(thread_checker_.CalledOnValidThread()); | |
178 | |
179 unsigned int affect_mask = 0; | |
180 unsigned int value_mask = 0; | |
181 if (caps_lock_enabled != current_caps_lock_status_) { | |
182 affect_mask |= LockMask; | |
183 value_mask |= (caps_lock_enabled ? LockMask : 0); | |
184 current_caps_lock_status_ = caps_lock_enabled; | |
185 } | |
186 | |
187 // Always turn off num lock. | |
188 affect_mask |= num_lock_mask_; | |
189 | |
190 XkbLockModifiers(GetXDisplay(), XkbUseCoreKbd, affect_mask, value_mask); | |
143 } | 191 } |
144 | 192 |
145 bool XKeyboardImpl::SetLayoutInternal(const std::string& layout_name, | 193 bool XKeyboardImpl::SetLayoutInternal(const std::string& layout_name, |
146 bool force) { | 194 bool force) { |
147 if (!is_running_on_chrome_os_) { | 195 if (!is_running_on_chrome_os_) { |
148 // We should not try to change a layout on Linux or inside ui_tests. Just | 196 // We should not try to change a layout on Linux or inside ui_tests. Just |
149 // return true. | 197 // return true. |
150 return true; | 198 return true; |
151 } | 199 } |
152 | 200 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
225 OnSetLayoutFinish(); | 273 OnSetLayoutFinish(); |
226 return; | 274 return; |
227 | 275 |
228 default: | 276 default: |
229 NOTIMPLEMENTED(); | 277 NOTIMPLEMENTED(); |
230 OnSetLayoutFinish(); | 278 OnSetLayoutFinish(); |
231 return; | 279 return; |
232 } | 280 } |
233 } | 281 } |
234 | 282 |
235 bool XKeyboardImpl::NumLockIsEnabled() { | |
236 bool num_lock_enabled = false; | |
237 GetLockedModifiers(NULL /* Caps Lock */, &num_lock_enabled); | |
238 return num_lock_enabled; | |
239 } | |
240 | |
241 bool XKeyboardImpl::CapsLockIsEnabled() { | 283 bool XKeyboardImpl::CapsLockIsEnabled() { |
242 bool caps_lock_enabled = false; | |
243 GetLockedModifiers(&caps_lock_enabled, NULL /* Num Lock */); | |
244 return caps_lock_enabled; | |
245 } | |
246 | |
247 unsigned int XKeyboardImpl::GetNumLockMask() { | |
248 DCHECK(thread_checker_.CalledOnValidThread()); | 284 DCHECK(thread_checker_.CalledOnValidThread()); |
249 static const unsigned int kBadMask = 0; | |
250 | |
251 unsigned int real_mask = kBadMask; | |
252 XkbDescPtr xkb_desc = | |
253 XkbGetKeyboard(GetXDisplay(), XkbAllComponentsMask, XkbUseCoreKbd); | |
254 if (!xkb_desc) | |
255 return kBadMask; | |
256 | |
257 if (xkb_desc->dpy && xkb_desc->names && xkb_desc->names->vmods) { | |
258 const std::string string_to_find(kNumLockVirtualModifierString); | |
259 for (size_t i = 0; i < XkbNumVirtualMods; ++i) { | |
260 const unsigned int virtual_mod_mask = 1U << i; | |
261 char* virtual_mod_str_raw_ptr = | |
262 XGetAtomName(xkb_desc->dpy, xkb_desc->names->vmods[i]); | |
263 if (!virtual_mod_str_raw_ptr) | |
264 continue; | |
265 const std::string virtual_mod_str = virtual_mod_str_raw_ptr; | |
266 XFree(virtual_mod_str_raw_ptr); | |
267 | |
268 if (string_to_find == virtual_mod_str) { | |
269 if (!XkbVirtualModsToReal(xkb_desc, virtual_mod_mask, &real_mask)) { | |
270 DVLOG(1) << "XkbVirtualModsToReal failed"; | |
271 real_mask = kBadMask; // reset the return value, just in case. | |
272 } | |
273 break; | |
274 } | |
275 } | |
276 } | |
277 XkbFreeKeyboard(xkb_desc, 0, True /* free all components */); | |
278 return real_mask; | |
279 } | |
280 | |
281 void XKeyboardImpl::GetLockedModifiers(bool* out_caps_lock_enabled, | |
282 bool* out_num_lock_enabled) { | |
283 DCHECK(thread_checker_.CalledOnValidThread()); | |
284 | |
285 if (out_num_lock_enabled && !num_lock_mask_) { | |
286 DVLOG(1) << "Cannot get locked modifiers. Num Lock mask unknown."; | |
287 if (out_caps_lock_enabled) | |
288 *out_caps_lock_enabled = false; | |
289 if (out_num_lock_enabled) | |
290 *out_num_lock_enabled = false; | |
291 return; | |
292 } | |
293 | |
294 XkbStateRec status; | 285 XkbStateRec status; |
295 XkbGetState(GetXDisplay(), XkbUseCoreKbd, &status); | 286 XkbGetState(GetXDisplay(), XkbUseCoreKbd, &status); |
296 if (out_caps_lock_enabled) | 287 return (status.locked_mods & LockMask); |
297 *out_caps_lock_enabled = status.locked_mods & LockMask; | |
298 if (out_num_lock_enabled) | |
299 *out_num_lock_enabled = status.locked_mods & num_lock_mask_; | |
300 } | 288 } |
301 | 289 |
302 bool XKeyboardImpl::SetAutoRepeatEnabled(bool enabled) { | 290 bool XKeyboardImpl::SetAutoRepeatEnabled(bool enabled) { |
303 if (enabled) | 291 if (enabled) |
304 XAutoRepeatOn(GetXDisplay()); | 292 XAutoRepeatOn(GetXDisplay()); |
305 else | 293 else |
306 XAutoRepeatOff(GetXDisplay()); | 294 XAutoRepeatOff(GetXDisplay()); |
307 DVLOG(1) << "Set auto-repeat mode to: " << (enabled ? "on" : "off"); | 295 DVLOG(1) << "Set auto-repeat mode to: " << (enabled ? "on" : "off"); |
308 return true; | 296 return true; |
309 } | 297 } |
310 | 298 |
311 bool XKeyboardImpl::SetAutoRepeatRate(const AutoRepeatRate& rate) { | 299 bool XKeyboardImpl::SetAutoRepeatRate(const AutoRepeatRate& rate) { |
312 DVLOG(1) << "Set auto-repeat rate to: " | 300 DVLOG(1) << "Set auto-repeat rate to: " |
313 << rate.initial_delay_in_ms << " ms delay, " | 301 << rate.initial_delay_in_ms << " ms delay, " |
314 << rate.repeat_interval_in_ms << " ms interval"; | 302 << rate.repeat_interval_in_ms << " ms interval"; |
315 if (XkbSetAutoRepeatRate(GetXDisplay(), XkbUseCoreKbd, | 303 if (XkbSetAutoRepeatRate(GetXDisplay(), XkbUseCoreKbd, |
316 rate.initial_delay_in_ms, | 304 rate.initial_delay_in_ms, |
317 rate.repeat_interval_in_ms) != True) { | 305 rate.repeat_interval_in_ms) != True) { |
318 DVLOG(1) << "Failed to set auto-repeat rate"; | 306 DVLOG(1) << "Failed to set auto-repeat rate"; |
319 return false; | 307 return false; |
320 } | 308 } |
321 return true; | 309 return true; |
322 } | 310 } |
323 | 311 |
324 void XKeyboardImpl::SetLockedModifiers(ModifierLockStatus new_caps_lock_status, | |
325 ModifierLockStatus new_num_lock_status) { | |
326 DCHECK(thread_checker_.CalledOnValidThread()); | |
327 if (!num_lock_mask_) { | |
328 DVLOG(1) << "Cannot set locked modifiers. Num Lock mask unknown."; | |
329 return; | |
330 } | |
331 | |
332 unsigned int affect_mask = 0; | |
333 unsigned int value_mask = 0; | |
334 if (new_caps_lock_status != kDontChange) { | |
335 affect_mask |= LockMask; | |
336 value_mask |= ((new_caps_lock_status == kEnableLock) ? LockMask : 0); | |
337 current_caps_lock_status_ = (new_caps_lock_status == kEnableLock); | |
338 } | |
339 if (new_num_lock_status != kDontChange) { | |
340 affect_mask |= num_lock_mask_; | |
341 value_mask |= ((new_num_lock_status == kEnableLock) ? num_lock_mask_ : 0); | |
342 current_num_lock_status_ = (new_num_lock_status == kEnableLock); | |
343 } | |
344 | |
345 if (affect_mask) | |
346 XkbLockModifiers(GetXDisplay(), XkbUseCoreKbd, affect_mask, value_mask); | |
347 } | |
348 | |
349 void XKeyboardImpl::SetNumLockEnabled(bool enable_num_lock) { | |
350 SetLockedModifiers( | |
351 kDontChange, enable_num_lock ? kEnableLock : kDisableLock); | |
352 } | |
353 | |
354 void XKeyboardImpl::SetCapsLockEnabled(bool enable_caps_lock) { | 312 void XKeyboardImpl::SetCapsLockEnabled(bool enable_caps_lock) { |
355 SetLockedModifiers( | 313 SetLockedModifiers(enable_caps_lock); |
356 enable_caps_lock ? kEnableLock : kDisableLock, kDontChange); | |
357 } | 314 } |
358 | 315 |
359 bool XKeyboardImpl::SetCurrentKeyboardLayoutByName( | 316 bool XKeyboardImpl::SetCurrentKeyboardLayoutByName( |
360 const std::string& layout_name) { | 317 const std::string& layout_name) { |
361 if (SetLayoutInternal(layout_name, false)) { | 318 if (SetLayoutInternal(layout_name, false)) { |
362 current_layout_name_ = layout_name; | 319 current_layout_name_ = layout_name; |
363 return true; | 320 return true; |
364 } | 321 } |
365 return false; | 322 return false; |
366 } | 323 } |
367 | 324 |
368 bool XKeyboardImpl::ReapplyCurrentKeyboardLayout() { | 325 bool XKeyboardImpl::ReapplyCurrentKeyboardLayout() { |
369 if (current_layout_name_.empty()) { | 326 if (current_layout_name_.empty()) { |
370 DVLOG(1) << "Can't reapply XKB layout: layout unknown"; | 327 DVLOG(1) << "Can't reapply XKB layout: layout unknown"; |
371 return false; | 328 return false; |
372 } | 329 } |
373 return SetLayoutInternal(current_layout_name_, true /* force */); | 330 return SetLayoutInternal(current_layout_name_, true /* force */); |
374 } | 331 } |
375 | 332 |
376 void XKeyboardImpl::ReapplyCurrentModifierLockStatus() { | 333 void XKeyboardImpl::ReapplyCurrentModifierLockStatus() { |
377 SetLockedModifiers(current_caps_lock_status_ ? kEnableLock : kDisableLock, | 334 SetLockedModifiers(current_caps_lock_status_); |
378 current_num_lock_status_ ? kEnableLock : kDisableLock); | 335 } |
336 | |
337 void XKeyboardImpl::DisableNumLock() { | |
338 SetCapsLockEnabled(current_caps_lock_status_); | |
379 } | 339 } |
380 | 340 |
381 void XKeyboardImpl::OnSetLayoutFinish() { | 341 void XKeyboardImpl::OnSetLayoutFinish() { |
382 if (execute_queue_.empty()) { | 342 if (execute_queue_.empty()) { |
383 DVLOG(1) << "OnSetLayoutFinish: execute_queue_ is empty. " | 343 DVLOG(1) << "OnSetLayoutFinish: execute_queue_ is empty. " |
384 << "base::LaunchProcess failed?"; | 344 << "base::LaunchProcess failed?"; |
385 return; | 345 return; |
386 } | 346 } |
387 execute_queue_.pop(); | 347 execute_queue_.pop(); |
388 MaybeExecuteSetLayoutCommand(); | 348 MaybeExecuteSetLayoutCommand(); |
(...skipping 20 matching lines...) Expand all Loading... | |
409 return CheckLayoutName(layout_name); | 369 return CheckLayoutName(layout_name); |
410 } | 370 } |
411 | 371 |
412 // static | 372 // static |
413 XKeyboard* XKeyboard::Create() { | 373 XKeyboard* XKeyboard::Create() { |
414 return new XKeyboardImpl(); | 374 return new XKeyboardImpl(); |
415 } | 375 } |
416 | 376 |
417 } // namespace input_method | 377 } // namespace input_method |
418 } // namespace chromeos | 378 } // namespace chromeos |
OLD | NEW |