ime_controller_impl.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/ime/ime_controller_impl.h"
  5. #include <utility>
  6. #include "ash/ime/ime_mode_indicator_view.h"
  7. #include "ash/ime/ime_switch_type.h"
  8. #include "ash/ime/mode_indicator_observer.h"
  9. #include "ash/shell.h"
  10. #include "ash/system/tray/system_tray_notifier.h"
  11. #include "base/callback_helpers.h"
  12. #include "base/containers/contains.h"
  13. #include "base/metrics/histogram_macros.h"
  14. #include "ui/base/accelerators/accelerator.h"
  15. #include "ui/base/ime/ash/extension_ime_util.h"
  16. #include "ui/display/manager/display_manager.h"
  17. namespace ash {
  18. namespace {
  19. // The result of pressing VKEY_MODECHANGE (for metrics).
  20. // These values are persisted to logs. Entries should not be renumbered and
  21. // numeric values should never be reused.
  22. enum class ModeChangeKeyAction {
  23. kShowIndicator = 0,
  24. kSwitchIme = 1,
  25. kMaxValue = kSwitchIme
  26. };
  27. // The ID for the Accessibility Common IME (used for Dictation).
  28. const char* kAccessibilityCommonIMEId =
  29. "_ext_ime_egfdjlfmgnehecnclamagfafdccgfndpdictation";
  30. } // namespace
  31. ImeControllerImpl::ImeControllerImpl()
  32. : mode_indicator_observer_(std::make_unique<ModeIndicatorObserver>()) {}
  33. ImeControllerImpl::~ImeControllerImpl() {
  34. SetClient(nullptr);
  35. }
  36. void ImeControllerImpl::AddObserver(Observer* observer) {
  37. observers_.AddObserver(observer);
  38. }
  39. void ImeControllerImpl::RemoveObserver(Observer* observer) {
  40. observers_.RemoveObserver(observer);
  41. }
  42. const std::vector<ImeInfo>& ImeControllerImpl::GetVisibleImes() const {
  43. return visible_imes_;
  44. }
  45. bool ImeControllerImpl::IsCurrentImeVisible() const {
  46. return current_ime_.id != kAccessibilityCommonIMEId;
  47. }
  48. void ImeControllerImpl::SetClient(ImeControllerClient* client) {
  49. if (client_) {
  50. if (CastConfigController::Get())
  51. CastConfigController::Get()->RemoveObserver(this);
  52. Shell::Get()->display_manager()->RemoveObserver(this);
  53. Shell::Get()->system_tray_notifier()->RemoveScreenCaptureObserver(this);
  54. }
  55. client_ = client;
  56. if (client_) {
  57. if (CastConfigController::Get())
  58. CastConfigController::Get()->AddObserver(this);
  59. Shell::Get()->system_tray_notifier()->AddScreenCaptureObserver(this);
  60. Shell::Get()->display_manager()->AddObserver(this);
  61. }
  62. }
  63. bool ImeControllerImpl::CanSwitchIme() const {
  64. // Cannot switch unless there is an active IME.
  65. if (current_ime_.id.empty())
  66. return false;
  67. // Do not consume key event if there is only one input method is enabled.
  68. // Ctrl+Space or Alt+Shift may be used by other application.
  69. return GetVisibleImes().size() > 1;
  70. }
  71. void ImeControllerImpl::SwitchToNextIme() {
  72. if (client_)
  73. client_->SwitchToNextIme();
  74. }
  75. void ImeControllerImpl::SwitchToLastUsedIme() {
  76. if (client_)
  77. client_->SwitchToLastUsedIme();
  78. }
  79. void ImeControllerImpl::SwitchImeById(const std::string& ime_id,
  80. bool show_message) {
  81. if (client_)
  82. client_->SwitchImeById(ime_id, show_message);
  83. }
  84. void ImeControllerImpl::ActivateImeMenuItem(const std::string& key) {
  85. if (client_)
  86. client_->ActivateImeMenuItem(key);
  87. }
  88. bool ImeControllerImpl::CanSwitchImeWithAccelerator(
  89. const ui::Accelerator& accelerator) const {
  90. // If none of the input methods associated with |accelerator| are active, we
  91. // should ignore the accelerator.
  92. std::vector<std::string> candidate_ids =
  93. GetCandidateImesForAccelerator(accelerator);
  94. return !candidate_ids.empty();
  95. }
  96. void ImeControllerImpl::SwitchImeWithAccelerator(
  97. const ui::Accelerator& accelerator) {
  98. if (!client_)
  99. return;
  100. std::vector<std::string> candidate_ids =
  101. GetCandidateImesForAccelerator(accelerator);
  102. if (candidate_ids.empty())
  103. return;
  104. auto it =
  105. std::find(candidate_ids.begin(), candidate_ids.end(), current_ime_.id);
  106. if (it != candidate_ids.end())
  107. ++it;
  108. if (it == candidate_ids.end())
  109. it = candidate_ids.begin();
  110. client_->SwitchImeById(*it, true /* show_message */);
  111. }
  112. // ImeControllerImpl:
  113. void ImeControllerImpl::RefreshIme(const std::string& current_ime_id,
  114. std::vector<ImeInfo> available_imes,
  115. std::vector<ImeMenuItem> menu_items) {
  116. if (current_ime_id.empty())
  117. current_ime_ = ImeInfo();
  118. available_imes_.clear();
  119. available_imes_.reserve(available_imes.size());
  120. visible_imes_.clear();
  121. visible_imes_.reserve(visible_imes_.size());
  122. for (const auto& ime : available_imes) {
  123. if (ime.id.empty()) {
  124. DLOG(ERROR) << "Received IME with invalid ID.";
  125. continue;
  126. }
  127. available_imes_.push_back(ime);
  128. if (ime.id != kAccessibilityCommonIMEId) {
  129. visible_imes_.push_back(ime);
  130. }
  131. if (ime.id == current_ime_id)
  132. current_ime_ = ime;
  133. }
  134. // Either there is no current IME or we found a valid one in the list of
  135. // available IMEs.
  136. DCHECK(current_ime_id.empty() || !current_ime_.id.empty());
  137. current_ime_menu_items_.clear();
  138. current_ime_menu_items_.reserve(menu_items.size());
  139. for (const auto& item : menu_items)
  140. current_ime_menu_items_.push_back(item);
  141. Shell::Get()->system_tray_notifier()->NotifyRefreshIME();
  142. }
  143. void ImeControllerImpl::SetImesManagedByPolicy(bool managed) {
  144. managed_by_policy_ = managed;
  145. Shell::Get()->system_tray_notifier()->NotifyRefreshIME();
  146. }
  147. void ImeControllerImpl::ShowImeMenuOnShelf(bool show) {
  148. is_menu_active_ = show;
  149. Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(show);
  150. }
  151. void ImeControllerImpl::UpdateCapsLockState(bool caps_enabled) {
  152. is_caps_lock_enabled_ = caps_enabled;
  153. for (ImeControllerImpl::Observer& observer : observers_)
  154. observer.OnCapsLockChanged(caps_enabled);
  155. }
  156. void ImeControllerImpl::OnKeyboardLayoutNameChanged(
  157. const std::string& layout_name) {
  158. keyboard_layout_name_ = layout_name;
  159. for (ImeControllerImpl::Observer& observer : observers_)
  160. observer.OnKeyboardLayoutNameChanged(layout_name);
  161. }
  162. void ImeControllerImpl::SetExtraInputOptionsEnabledState(
  163. bool is_extra_input_options_enabled,
  164. bool is_emoji_enabled,
  165. bool is_handwriting_enabled,
  166. bool is_voice_enabled) {
  167. is_extra_input_options_enabled_ = is_extra_input_options_enabled;
  168. is_emoji_enabled_ = is_emoji_enabled;
  169. is_handwriting_enabled_ = is_handwriting_enabled;
  170. is_voice_enabled_ = is_voice_enabled;
  171. }
  172. void ImeControllerImpl::ShowModeIndicator(
  173. const gfx::Rect& anchor_bounds,
  174. const std::u16string& ime_short_name) {
  175. ImeModeIndicatorView* mi_view =
  176. new ImeModeIndicatorView(anchor_bounds, ime_short_name);
  177. views::BubbleDialogDelegateView::CreateBubble(mi_view);
  178. mode_indicator_observer_->AddModeIndicatorWidget(mi_view->GetWidget());
  179. mi_view->ShowAndFadeOut();
  180. }
  181. void ImeControllerImpl::OnDisplayMetricsChanged(const display::Display& display,
  182. uint32_t changed_metrics) {
  183. if (changed_metrics & display::DisplayObserver::DISPLAY_METRIC_MIRROR_STATE) {
  184. Shell* shell = Shell::Get();
  185. client_->UpdateMirroringState(shell->display_manager()->IsInMirrorMode());
  186. }
  187. }
  188. void ImeControllerImpl::OnDevicesUpdated(
  189. const std::vector<SinkAndRoute>& devices) {
  190. DCHECK(client_);
  191. bool casting_desktop = false;
  192. for (const auto& receiver : devices) {
  193. if (receiver.route.content_source == ContentSource::kDesktop) {
  194. casting_desktop = true;
  195. break;
  196. }
  197. }
  198. client_->UpdateCastingState(casting_desktop);
  199. }
  200. void ImeControllerImpl::SetCapsLockEnabled(bool caps_enabled) {
  201. is_caps_lock_enabled_ = caps_enabled;
  202. if (client_)
  203. client_->SetCapsLockEnabled(caps_enabled);
  204. }
  205. void ImeControllerImpl::OverrideKeyboardKeyset(input_method::ImeKeyset keyset) {
  206. OverrideKeyboardKeyset(keyset, base::DoNothing());
  207. }
  208. void ImeControllerImpl::OverrideKeyboardKeyset(
  209. input_method::ImeKeyset keyset,
  210. ImeControllerClient::OverrideKeyboardKeysetCallback callback) {
  211. if (client_)
  212. client_->OverrideKeyboardKeyset(keyset, std::move(callback));
  213. }
  214. bool ImeControllerImpl::IsCapsLockEnabled() const {
  215. return is_caps_lock_enabled_;
  216. }
  217. std::vector<std::string> ImeControllerImpl::GetCandidateImesForAccelerator(
  218. const ui::Accelerator& accelerator) const {
  219. std::vector<std::string> candidate_ids;
  220. using extension_ime_util::GetInputMethodIDByEngineID;
  221. std::vector<std::string> input_method_ids_to_switch;
  222. switch (accelerator.key_code()) {
  223. case ui::VKEY_CONVERT: // Henkan key on JP106 keyboard
  224. input_method_ids_to_switch.push_back(
  225. GetInputMethodIDByEngineID("nacl_mozc_jp"));
  226. break;
  227. case ui::VKEY_NONCONVERT: // Muhenkan key on JP106 keyboard
  228. input_method_ids_to_switch.push_back(
  229. GetInputMethodIDByEngineID("xkb:jp::jpn"));
  230. break;
  231. case ui::VKEY_DBE_SBCSCHAR: // ZenkakuHankaku key on JP106 keyboard
  232. case ui::VKEY_DBE_DBCSCHAR:
  233. input_method_ids_to_switch.push_back(
  234. GetInputMethodIDByEngineID("nacl_mozc_jp"));
  235. input_method_ids_to_switch.push_back(
  236. GetInputMethodIDByEngineID("xkb:jp::jpn"));
  237. break;
  238. default:
  239. break;
  240. }
  241. if (input_method_ids_to_switch.empty()) {
  242. DVLOG(1) << "Unexpected VKEY: " << accelerator.key_code();
  243. return std::vector<std::string>();
  244. }
  245. // Obtain the intersection of input_method_ids_to_switch and available_imes_.
  246. for (const ImeInfo& ime : available_imes_) {
  247. if (base::Contains(input_method_ids_to_switch, ime.id))
  248. candidate_ids.push_back(ime.id);
  249. }
  250. return candidate_ids;
  251. }
  252. void ImeControllerImpl::OnScreenCaptureStart(
  253. const base::RepeatingClosure& stop_callback,
  254. const base::RepeatingClosure& source_callback,
  255. const std::u16string& screen_capture_status) {
  256. client_->UpdateCastingState(true);
  257. }
  258. void ImeControllerImpl::OnScreenCaptureStop() {
  259. client_->UpdateCastingState(false);
  260. }
  261. } // namespace ash