1a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chromeos/ime/ime_keyboard.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cstdlib>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cstring>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <queue>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/process/kill.h"
18a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/launch.h"
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/process/process_handle.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/sys_info.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/threading/thread_checker.h"
24a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "ui/gfx/x/x11_types.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These includes conflict with base/tracked_objects.h so must come last.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/XKBlib.h>
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/Xlib.h>
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace input_method {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The delay in milliseconds that we'll wait between checking if
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// setxkbmap command finished.
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kSetLayoutCommandCheckDelayMs = 100;
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The command we use to set the current XKB layout and modifier key mapping.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kSetxkbmapCommand[] = "/usr/bin/setxkbmap";
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A string for obtaining a mask value for Num Lock.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kNumLockVirtualModifierString[] = "NumLock";
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char *kISOLevel5ShiftLayoutIds[] = {
46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "ca(multix)",
47effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "de(neo)",
48effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch};
49effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char *kAltGrLayoutIds[] = {
51effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "be",
52effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "be",
53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "be",
54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "bg",
55effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "bg(phonetic)",
56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "br",
57effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "ca",
58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "ca(eng)",
59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "ca(multix)",
60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "ch",
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "ch(fr)",
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "cz",
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "de",
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "de(neo)",
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "dk",
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "ee",
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "es",
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "es(cat)",
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "fi",
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "fr",
71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "gb(dvorak)",
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "gb(extd)",
73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "gr",
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "hr",
75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "il",
76effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "it",
77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "latam",
78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "lt",
79effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "no",
80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "pl",
81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "pt",
82effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "ro",
83effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "se",
84effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "si",
85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "sk",
86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "tr",
87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "ua",
88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "us(altgr-intl)",
89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  "us(intl)",
90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch};
91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
92effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns false if |layout_name| contains a bad character.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CheckLayoutName(const std::string& layout_name) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char kValidLayoutNameCharacters[] =
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "abcdefghijklmnopqrstuvwxyz0123456789()-_";
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (layout_name.empty()) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Invalid layout_name: " << layout_name;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (layout_name.find_first_not_of(kValidLayoutNameCharacters) !=
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string::npos) {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Invalid layout_name: " << layout_name;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
112a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochclass ImeKeyboardX11 : public ImeKeyboard {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
114a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  ImeKeyboardX11();
115a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  virtual ~ImeKeyboardX11() {}
116a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
117a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Adds/removes observer.
118a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  virtual void AddObserver(Observer* observer) OVERRIDE;
119a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  virtual void RemoveObserver(Observer* observer) OVERRIDE;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
121a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // ImeKeyboard:
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool SetCurrentKeyboardLayoutByName(
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& layout_name) OVERRIDE;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool ReapplyCurrentKeyboardLayout() OVERRIDE;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void ReapplyCurrentModifierLockStatus() OVERRIDE;
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void DisableNumLock() OVERRIDE;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetCapsLockEnabled(bool enable_caps_lock) OVERRIDE;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool CapsLockIsEnabled() OVERRIDE;
129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  virtual bool IsISOLevel5ShiftAvailable() const OVERRIDE;
130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  virtual bool IsAltGrAvailable() const OVERRIDE;
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual bool SetAutoRepeatEnabled(bool enabled) OVERRIDE;
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual bool SetAutoRepeatRate(const AutoRepeatRate& rate) OVERRIDE;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Returns a mask for Num Lock (e.g. 1U << 4). Returns 0 on error.
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  unsigned int GetNumLockMask();
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Sets the caps-lock status. Note that calling this function always disables
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // the num-lock.
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void SetLockedModifiers(bool caps_lock_enabled);
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This function is used by SetLayout() and RemapModifierKeys(). Calls
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // setxkbmap command if needed, and updates the last_full_layout_name_ cache.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool SetLayoutInternal(const std::string& layout_name, bool force);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Executes 'setxkbmap -layout ...' command asynchronously using a layout name
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in the |execute_queue_|. Do nothing if the queue is empty.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void MaybeExecuteSetLayoutCommand();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Polls to see setxkbmap process exits.
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void PollUntilChildFinish(const base::ProcessHandle handle);
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called when execve'd setxkbmap process exits.
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OnSetLayoutFinish();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool is_running_on_chrome_os_;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int num_lock_mask_;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The current Caps Lock status. If true, enabled.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool current_caps_lock_status_;
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The XKB layout name which we set last time like "us" and "us(dvorak)".
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string current_layout_name_;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A queue for executing setxkbmap one by one.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::queue<std::string> execute_queue_;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ThreadChecker thread_checker_;
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
171a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  base::WeakPtrFactory<ImeKeyboardX11> weak_factory_;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
173a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  ObserverList<Observer> observers_;
174a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
175a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DISALLOW_COPY_AND_ASSIGN(ImeKeyboardX11);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
178a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochImeKeyboardX11::ImeKeyboardX11()
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : is_running_on_chrome_os_(base::SysInfo::IsRunningOnChromeOS()),
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_factory_(this) {
181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // X must be already initialized.
182a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  CHECK(gfx::GetXDisplay());
183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  num_lock_mask_ = GetNumLockMask();
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (is_running_on_chrome_os_) {
187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Some code seems to assume that Mod2Mask is always assigned to
188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Num Lock.
189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    //
190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // TODO(yusukes): Check the assumption is really okay. If not,
191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // modify the Aura code, and then remove the CHECK below.
192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    LOG_IF(ERROR, num_lock_mask_ != Mod2Mask)
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        << "NumLock is not assigned to Mod2Mask.  : " << num_lock_mask_;
194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  current_caps_lock_status_ = CapsLockIsEnabled();
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Disable Num Lock on X start up for http://crosbug.com/29169.
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DisableNumLock();
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
201a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid ImeKeyboardX11::AddObserver(Observer* observer) {
202a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  observers_.AddObserver(observer);
203a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
204a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
205a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid ImeKeyboardX11::RemoveObserver(Observer* observer) {
206a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  observers_.RemoveObserver(observer);
207a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
208a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
209a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochunsigned int ImeKeyboardX11::GetNumLockMask() {
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  static const unsigned int kBadMask = 0;
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  unsigned int real_mask = kBadMask;
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  XkbDescPtr xkb_desc =
215a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      XkbGetKeyboard(gfx::GetXDisplay(), XkbAllComponentsMask, XkbUseCoreKbd);
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!xkb_desc)
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return kBadMask;
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
21923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  if (xkb_desc->dpy && xkb_desc->names) {
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string string_to_find(kNumLockVirtualModifierString);
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (size_t i = 0; i < XkbNumVirtualMods; ++i) {
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const unsigned int virtual_mod_mask = 1U << i;
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      char* virtual_mod_str_raw_ptr =
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          XGetAtomName(xkb_desc->dpy, xkb_desc->names->vmods[i]);
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (!virtual_mod_str_raw_ptr)
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        continue;
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const std::string virtual_mod_str = virtual_mod_str_raw_ptr;
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      XFree(virtual_mod_str_raw_ptr);
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (string_to_find == virtual_mod_str) {
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (!XkbVirtualModsToReal(xkb_desc, virtual_mod_mask, &real_mask)) {
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          DVLOG(1) << "XkbVirtualModsToReal failed";
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          real_mask = kBadMask;  // reset the return value, just in case.
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        }
235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        break;
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  XkbFreeKeyboard(xkb_desc, 0, True /* free all components */);
240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return real_mask;
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
243a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid ImeKeyboardX11::SetLockedModifiers(bool caps_lock_enabled) {
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Always turn off num lock.
247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  unsigned int affect_mask = num_lock_mask_;
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  unsigned int value_mask = 0;
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  affect_mask |= LockMask;
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  value_mask |= (caps_lock_enabled ? LockMask : 0);
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  current_caps_lock_status_ = caps_lock_enabled;
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
254a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  XkbLockModifiers(gfx::GetXDisplay(), XkbUseCoreKbd, affect_mask, value_mask);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
257a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ImeKeyboardX11::SetLayoutInternal(const std::string& layout_name,
258a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                                       bool force) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_running_on_chrome_os_) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should not try to change a layout on Linux or inside ui_tests. Just
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // return true.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CheckLayoutName(layout_name))
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!force && (current_layout_name_ == layout_name)) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "The requested layout is already set: " << layout_name;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << (force ? "Reapply" : "Set") << " layout: " << layout_name;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool start_execution = execute_queue_.empty();
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If no setxkbmap command is in flight (i.e. start_execution is true),
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // start the first one by explicitly calling MaybeExecuteSetLayoutCommand().
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If one or more setxkbmap commands are already in flight, just push the
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // layout name to the queue. setxkbmap command for the layout will be called
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // via OnSetLayoutFinish() callback later.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  execute_queue_.push(layout_name);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (start_execution)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MaybeExecuteSetLayoutCommand();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Executes 'setxkbmap -layout ...' command asynchronously using a layout name
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the |execute_queue_|. Do nothing if the queue is empty.
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105)
291a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid ImeKeyboardX11::MaybeExecuteSetLayoutCommand() {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (execute_queue_.empty())
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string layout_to_set = execute_queue_.front();
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> argv;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ProcessHandle handle = base::kNullProcessHandle;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  argv.push_back(kSetxkbmapCommand);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  argv.push_back("-layout");
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  argv.push_back(layout_to_set);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  argv.push_back("-synch");
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::LaunchProcess(argv, base::LaunchOptions(), &handle)) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Failed to execute setxkbmap: " << layout_to_set;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    execute_queue_ = std::queue<std::string>();  // clear the queue.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PollUntilChildFinish(handle);
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
312a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DVLOG(1) << "ExecuteSetLayoutCommand: " << layout_to_set
313a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch           << ": pid=" << base::GetProcId(handle);
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Delay and loop until child process finishes and call the callback.
317a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid ImeKeyboardX11::PollUntilChildFinish(const base::ProcessHandle handle) {
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int exit_code;
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "PollUntilChildFinish: poll for pid=" << base::GetProcId(handle);
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch (base::GetTerminationStatus(handle, &exit_code)) {
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case base::TERMINATION_STATUS_STILL_RUNNING:
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DVLOG(1) << "PollUntilChildFinish: Try waiting again";
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::MessageLoop::current()->PostDelayedTask(
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          FROM_HERE,
325a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          base::Bind(&ImeKeyboardX11::PollUntilChildFinish,
326a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                     weak_factory_.GetWeakPtr(),
327a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                     handle),
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::TimeDelta::FromMilliseconds(kSetLayoutCommandCheckDelayMs));
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case base::TERMINATION_STATUS_NORMAL_TERMINATION:
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DVLOG(1) << "PollUntilChildFinish: Child process finished";
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnSetLayoutFinish();
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DVLOG(1) << "PollUntilChildFinish: Abnormal exit code: " << exit_code;
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnSetLayoutFinish();
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    default:
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NOTIMPLEMENTED();
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnSetLayoutFinish();
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
348a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ImeKeyboardX11::CapsLockIsEnabled() {
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XkbStateRec status;
351a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  XkbGetState(gfx::GetXDisplay(), XkbUseCoreKbd, &status);
352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return (status.locked_mods & LockMask);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ImeKeyboardX11::IsISOLevel5ShiftAvailable() const {
356effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (size_t i = 0; i < arraysize(kISOLevel5ShiftLayoutIds); ++i) {
357effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (current_layout_name_ == kISOLevel5ShiftLayoutIds[i])
358effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return true;
359effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
360effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return false;
361effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
362effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
363a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ImeKeyboardX11::IsAltGrAvailable() const {
364effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (size_t i = 0; i < arraysize(kAltGrLayoutIds); ++i) {
365effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (current_layout_name_ == kAltGrLayoutIds[i])
366effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return true;
367effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
368effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return false;
369effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
370effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
371a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ImeKeyboardX11::SetAutoRepeatEnabled(bool enabled) {
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (enabled)
373a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    XAutoRepeatOn(gfx::GetXDisplay());
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else
375a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    XAutoRepeatOff(gfx::GetXDisplay());
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Set auto-repeat mode to: " << (enabled ? "on" : "off");
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
380a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ImeKeyboardX11::SetAutoRepeatRate(const AutoRepeatRate& rate) {
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Set auto-repeat rate to: "
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << rate.initial_delay_in_ms << " ms delay, "
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << rate.repeat_interval_in_ms << " ms interval";
384a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (XkbSetAutoRepeatRate(gfx::GetXDisplay(), XkbUseCoreKbd,
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           rate.initial_delay_in_ms,
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           rate.repeat_interval_in_ms) != True) {
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Failed to set auto-repeat rate";
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
393a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid ImeKeyboardX11::SetCapsLockEnabled(bool enable_caps_lock) {
394a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  bool old_state = current_caps_lock_status_;
395a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SetLockedModifiers(enable_caps_lock);
396a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (old_state != enable_caps_lock) {
397a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    FOR_EACH_OBSERVER(ImeKeyboard::Observer, observers_,
398a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                      OnCapsLockChanged(enable_caps_lock));
399a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
402a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ImeKeyboardX11::SetCurrentKeyboardLayoutByName(
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& layout_name) {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SetLayoutInternal(layout_name, false)) {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_layout_name_ = layout_name;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
411a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ImeKeyboardX11::ReapplyCurrentKeyboardLayout() {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_layout_name_.empty()) {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Can't reapply XKB layout: layout unknown";
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SetLayoutInternal(current_layout_name_, true /* force */);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
419a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid ImeKeyboardX11::ReapplyCurrentModifierLockStatus() {
420a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SetLockedModifiers(current_caps_lock_status_);
421a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
422a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
423a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid ImeKeyboardX11::DisableNumLock() {
424a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SetCapsLockEnabled(current_caps_lock_status_);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
427a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid ImeKeyboardX11::OnSetLayoutFinish() {
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (execute_queue_.empty()) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "OnSetLayoutFinish: execute_queue_ is empty. "
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << "base::LaunchProcess failed?";
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  execute_queue_.pop();
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MaybeExecuteSetLayoutCommand();
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
440a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ImeKeyboard::GetAutoRepeatEnabledForTesting() {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XKeyboardState state = {};
442a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  XGetKeyboardControl(gfx::GetXDisplay(), &state);
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return state.global_auto_repeat != AutoRepeatModeOff;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
447a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ImeKeyboard::GetAutoRepeatRateForTesting(AutoRepeatRate* out_rate) {
448a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return XkbGetAutoRepeatRate(gfx::GetXDisplay(),
449a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                              XkbUseCoreKbd,
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &(out_rate->initial_delay_in_ms),
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &(out_rate->repeat_interval_in_ms)) == True;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
455a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool ImeKeyboard::CheckLayoutNameForTesting(const std::string& layout_name) {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CheckLayoutName(layout_name);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
460a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochImeKeyboard* ImeKeyboard::Create() { return new ImeKeyboardX11(); }
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace input_method
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
464