ime_controller_impl_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  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 <vector>
  6. #include "ash/ime/mode_indicator_observer.h"
  7. #include "ash/ime/test_ime_controller_client.h"
  8. #include "ash/public/cpp/ime_info.h"
  9. #include "ash/shell.h"
  10. #include "ash/system/ime/ime_observer.h"
  11. #include "ash/system/tray/system_tray_notifier.h"
  12. #include "ash/test/ash_test_base.h"
  13. #include "base/strings/utf_string_conversions.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. #include "ui/events/keycodes/keyboard_codes.h"
  18. #include "ui/views/widget/widget.h"
  19. namespace ash {
  20. namespace {
  21. // 43 is the designed size of the inner contents.
  22. // This value corresponds with kMinSize defined in
  23. // mode_indicator_delegate_view.cc.
  24. const int kInnerSize = 43;
  25. // Refreshes the IME list with fake IMEs and fake menu items.
  26. void RefreshImesWithMenuItems(const std::string& current_ime_id,
  27. const std::vector<std::string>& ime_ids,
  28. const std::vector<std::string>& menu_item_keys) {
  29. std::vector<ImeInfo> available_imes;
  30. for (const std::string& ime_id : ime_ids) {
  31. ImeInfo ime;
  32. ime.id = ime_id;
  33. available_imes.push_back(std::move(ime));
  34. }
  35. std::vector<ImeMenuItem> menu_items;
  36. for (const std::string& menu_item_key : menu_item_keys) {
  37. ImeMenuItem item;
  38. item.key = menu_item_key;
  39. menu_items.push_back(std::move(item));
  40. }
  41. Shell::Get()->ime_controller()->RefreshIme(
  42. current_ime_id, std::move(available_imes), std::move(menu_items));
  43. }
  44. // Refreshes the IME list without adding any menu items.
  45. void RefreshImes(const std::string& current_ime_id,
  46. const std::vector<std::string>& ime_ids) {
  47. const std::vector<std::string> empty_menu_items;
  48. RefreshImesWithMenuItems(current_ime_id, ime_ids, empty_menu_items);
  49. }
  50. class TestImeObserver : public IMEObserver {
  51. public:
  52. TestImeObserver() = default;
  53. ~TestImeObserver() override = default;
  54. // IMEObserver:
  55. void OnIMERefresh() override { ++refresh_count_; }
  56. void OnIMEMenuActivationChanged(bool is_active) override {
  57. ime_menu_active_ = is_active;
  58. }
  59. int refresh_count_ = 0;
  60. bool ime_menu_active_ = false;
  61. };
  62. class TestImeControllerObserver : public ImeControllerImpl::Observer {
  63. public:
  64. TestImeControllerObserver() = default;
  65. TestImeControllerObserver(const TestImeControllerObserver&) = delete;
  66. TestImeControllerObserver& operator=(const TestImeControllerObserver&) =
  67. delete;
  68. // IMEController::Observer:
  69. void OnCapsLockChanged(bool enabled) override { ++caps_lock_count_; }
  70. void OnKeyboardLayoutNameChanged(const std::string& layout_name) override {
  71. last_keyboard_layout_name_ = layout_name;
  72. }
  73. const std::string& last_keyboard_layout_name() const {
  74. return last_keyboard_layout_name_;
  75. }
  76. private:
  77. int caps_lock_count_ = 0;
  78. std::string last_keyboard_layout_name_;
  79. };
  80. using ImeControllerImplTest = AshTestBase;
  81. TEST_F(ImeControllerImplTest, RefreshIme) {
  82. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  83. TestImeObserver observer;
  84. Shell::Get()->system_tray_notifier()->AddIMEObserver(&observer);
  85. RefreshImesWithMenuItems("ime1", {"ime1", "ime2"}, {"menu1"});
  86. // Cached data was updated.
  87. EXPECT_EQ("ime1", controller->current_ime().id);
  88. ASSERT_EQ(2u, controller->GetVisibleImes().size());
  89. EXPECT_EQ("ime1", controller->GetVisibleImes()[0].id);
  90. EXPECT_EQ("ime2", controller->GetVisibleImes()[1].id);
  91. ASSERT_EQ(1u, controller->current_ime_menu_items().size());
  92. EXPECT_EQ("menu1", controller->current_ime_menu_items()[0].key);
  93. // Observer was notified.
  94. EXPECT_EQ(1, observer.refresh_count_);
  95. }
  96. TEST_F(ImeControllerImplTest, NoCurrentIme) {
  97. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  98. // Set up a single IME.
  99. RefreshImes("ime1", {"ime1"});
  100. EXPECT_EQ("ime1", controller->current_ime().id);
  101. EXPECT_TRUE(controller->IsCurrentImeVisible());
  102. // When there is no current IME the cached current IME is empty.
  103. const std::string empty_ime_id;
  104. RefreshImes(empty_ime_id, {"ime1"});
  105. EXPECT_TRUE(controller->current_ime().id.empty());
  106. }
  107. TEST_F(ImeControllerImplTest, CurrentImeNotVisible) {
  108. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  109. // Add only Dictation.
  110. std::string dictation_id =
  111. "_ext_ime_egfdjlfmgnehecnclamagfafdccgfndpdictation";
  112. RefreshImes(dictation_id, {dictation_id});
  113. EXPECT_EQ(dictation_id, controller->current_ime().id);
  114. EXPECT_FALSE(controller->IsCurrentImeVisible());
  115. EXPECT_EQ(0u, controller->GetVisibleImes().size());
  116. // Add something else too, but Dictation is active.
  117. RefreshImes(dictation_id, {dictation_id, "ime1"});
  118. EXPECT_EQ(dictation_id, controller->current_ime().id);
  119. EXPECT_FALSE(controller->IsCurrentImeVisible());
  120. EXPECT_EQ(1u, controller->GetVisibleImes().size());
  121. // Inactivate the other IME, leave Dictation in the list.
  122. RefreshImes("ime1", {dictation_id, "ime1"});
  123. EXPECT_EQ("ime1", controller->current_ime().id);
  124. EXPECT_TRUE(controller->IsCurrentImeVisible());
  125. EXPECT_EQ(1u, controller->GetVisibleImes().size());
  126. }
  127. TEST_F(ImeControllerImplTest, SetImesManagedByPolicy) {
  128. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  129. TestImeObserver observer;
  130. Shell::Get()->system_tray_notifier()->AddIMEObserver(&observer);
  131. // Defaults to false.
  132. EXPECT_FALSE(controller->managed_by_policy());
  133. // Setting the value notifies observers.
  134. controller->SetImesManagedByPolicy(true);
  135. EXPECT_TRUE(controller->managed_by_policy());
  136. EXPECT_EQ(1, observer.refresh_count_);
  137. }
  138. TEST_F(ImeControllerImplTest, ShowImeMenuOnShelf) {
  139. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  140. TestImeObserver observer;
  141. Shell::Get()->system_tray_notifier()->AddIMEObserver(&observer);
  142. controller->ShowImeMenuOnShelf(true);
  143. EXPECT_TRUE(observer.ime_menu_active_);
  144. }
  145. TEST_F(ImeControllerImplTest, CanSwitchIme) {
  146. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  147. // Can't switch IMEs when none are available.
  148. ASSERT_EQ(0u, controller->GetVisibleImes().size());
  149. EXPECT_FALSE(controller->CanSwitchIme());
  150. // Can't switch with only 1 IME.
  151. RefreshImes("ime1", {"ime1"});
  152. EXPECT_FALSE(controller->CanSwitchIme());
  153. // Can switch with more than 1 IME.
  154. RefreshImes("ime1", {"ime1", "ime2"});
  155. EXPECT_TRUE(controller->CanSwitchIme());
  156. }
  157. TEST_F(ImeControllerImplTest, SwitchIme) {
  158. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  159. TestImeControllerClient client;
  160. // Can't switch IME before the client is set.
  161. controller->SwitchToNextIme();
  162. EXPECT_EQ(0, client.next_ime_count_);
  163. controller->SwitchToLastUsedIme();
  164. EXPECT_EQ(0, client.last_used_ime_count_);
  165. controller->SwitchImeById("ime1", true /* show_message */);
  166. EXPECT_EQ(0, client.switch_ime_count_);
  167. // After setting the client the requests are forwarded.
  168. controller->SetClient(&client);
  169. controller->SwitchToNextIme();
  170. EXPECT_EQ(1, client.next_ime_count_);
  171. controller->SwitchToLastUsedIme();
  172. EXPECT_EQ(1, client.last_used_ime_count_);
  173. controller->SwitchImeById("ime1", true /* show_message */);
  174. EXPECT_EQ(1, client.switch_ime_count_);
  175. EXPECT_EQ("ime1", client.last_switch_ime_id_);
  176. EXPECT_TRUE(client.last_show_message_);
  177. controller->SwitchImeById("ime2", false /* show_message */);
  178. EXPECT_EQ(2, client.switch_ime_count_);
  179. EXPECT_EQ("ime2", client.last_switch_ime_id_);
  180. EXPECT_FALSE(client.last_show_message_);
  181. }
  182. TEST_F(ImeControllerImplTest, SwitchImeWithAccelerator) {
  183. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  184. TestImeControllerClient client;
  185. controller->SetClient(&client);
  186. const ui::Accelerator convert(ui::VKEY_CONVERT, ui::EF_NONE);
  187. const ui::Accelerator non_convert(ui::VKEY_NONCONVERT, ui::EF_NONE);
  188. const ui::Accelerator wide_half_1(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE);
  189. const ui::Accelerator wide_half_2(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE);
  190. // When there are no IMEs available switching by accelerator does not work.
  191. ASSERT_EQ(0u, controller->GetVisibleImes().size());
  192. EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(convert));
  193. EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(non_convert));
  194. EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(wide_half_1));
  195. EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(wide_half_2));
  196. // With only test IMEs (and no Japanese IMEs) the special keys do not work.
  197. RefreshImes("ime1", {"ime1", "ime2"});
  198. EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(convert));
  199. EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(non_convert));
  200. EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(wide_half_1));
  201. EXPECT_FALSE(controller->CanSwitchImeWithAccelerator(wide_half_2));
  202. // Install both a test IME and Japanese IMEs.
  203. using extension_ime_util::GetInputMethodIDByEngineID;
  204. const std::string nacl_mozc_jp = GetInputMethodIDByEngineID("nacl_mozc_jp");
  205. const std::string xkb_jp_jpn = GetInputMethodIDByEngineID("xkb:jp::jpn");
  206. RefreshImes("ime1", {"ime1", nacl_mozc_jp, xkb_jp_jpn});
  207. // Accelerator based switching now works.
  208. EXPECT_TRUE(controller->CanSwitchImeWithAccelerator(convert));
  209. EXPECT_TRUE(controller->CanSwitchImeWithAccelerator(non_convert));
  210. EXPECT_TRUE(controller->CanSwitchImeWithAccelerator(wide_half_1));
  211. EXPECT_TRUE(controller->CanSwitchImeWithAccelerator(wide_half_2));
  212. // Convert keys jump directly to the requested IME.
  213. controller->SwitchImeWithAccelerator(convert);
  214. EXPECT_EQ(1, client.switch_ime_count_);
  215. EXPECT_EQ(nacl_mozc_jp, client.last_switch_ime_id_);
  216. controller->SwitchImeWithAccelerator(non_convert);
  217. EXPECT_EQ(2, client.switch_ime_count_);
  218. EXPECT_EQ(xkb_jp_jpn, client.last_switch_ime_id_);
  219. // Switch from nacl_mozc_jp to xkb_jp_jpn.
  220. RefreshImes(nacl_mozc_jp, {"ime1", nacl_mozc_jp, xkb_jp_jpn});
  221. controller->SwitchImeWithAccelerator(wide_half_1);
  222. EXPECT_EQ(3, client.switch_ime_count_);
  223. EXPECT_EQ(xkb_jp_jpn, client.last_switch_ime_id_);
  224. // Switch from xkb_jp_jpn to nacl_mozc_jp.
  225. RefreshImes(xkb_jp_jpn, {"ime1", nacl_mozc_jp, xkb_jp_jpn});
  226. controller->SwitchImeWithAccelerator(wide_half_2);
  227. EXPECT_EQ(4, client.switch_ime_count_);
  228. EXPECT_EQ(nacl_mozc_jp, client.last_switch_ime_id_);
  229. }
  230. TEST_F(ImeControllerImplTest, SetCapsLock) {
  231. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  232. TestImeControllerClient client;
  233. EXPECT_EQ(0, client.set_caps_lock_count_);
  234. controller->SetCapsLockEnabled(true);
  235. EXPECT_EQ(0, client.set_caps_lock_count_);
  236. controller->SetClient(&client);
  237. controller->SetCapsLockEnabled(true);
  238. EXPECT_EQ(1, client.set_caps_lock_count_);
  239. // Does not no-op when the state is the same. Should send all notifications.
  240. controller->SetCapsLockEnabled(true);
  241. EXPECT_EQ(2, client.set_caps_lock_count_);
  242. controller->SetCapsLockEnabled(false);
  243. EXPECT_EQ(3, client.set_caps_lock_count_);
  244. controller->SetCapsLockEnabled(false);
  245. EXPECT_EQ(4, client.set_caps_lock_count_);
  246. EXPECT_FALSE(controller->IsCapsLockEnabled());
  247. controller->UpdateCapsLockState(true);
  248. EXPECT_TRUE(controller->IsCapsLockEnabled());
  249. controller->UpdateCapsLockState(false);
  250. EXPECT_FALSE(controller->IsCapsLockEnabled());
  251. }
  252. TEST_F(ImeControllerImplTest, OnKeyboardLayoutNameChanged) {
  253. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  254. EXPECT_TRUE(controller->keyboard_layout_name().empty());
  255. TestImeControllerObserver observer;
  256. controller->AddObserver(&observer);
  257. controller->OnKeyboardLayoutNameChanged("us(dvorak)");
  258. EXPECT_EQ("us(dvorak)", controller->keyboard_layout_name());
  259. EXPECT_EQ("us(dvorak)", observer.last_keyboard_layout_name());
  260. }
  261. TEST_F(ImeControllerImplTest, ShowModeIndicator) {
  262. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  263. std::u16string text = u"US";
  264. gfx::Rect cursor1_bounds(100, 100, 1, 20);
  265. controller->ShowModeIndicator(cursor1_bounds, text);
  266. views::Widget* widget1 =
  267. controller->mode_indicator_observer()->active_widget();
  268. EXPECT_TRUE(widget1);
  269. // The widget bounds should be bigger than the inner size.
  270. gfx::Rect bounds1 = widget1->GetWindowBoundsInScreen();
  271. EXPECT_LE(kInnerSize, bounds1.width());
  272. EXPECT_LE(kInnerSize, bounds1.height());
  273. gfx::Rect cursor2_bounds(50, 200, 1, 20);
  274. controller->ShowModeIndicator(cursor2_bounds, text);
  275. views::Widget* widget2 =
  276. controller->mode_indicator_observer()->active_widget();
  277. EXPECT_TRUE(widget2);
  278. EXPECT_NE(widget1, widget2);
  279. // Check if the location of the mode indicator corresponds to the cursor
  280. // bounds.
  281. gfx::Rect bounds2 = widget2->GetWindowBoundsInScreen();
  282. EXPECT_EQ(cursor1_bounds.x() - cursor2_bounds.x(), bounds1.x() - bounds2.x());
  283. EXPECT_EQ(cursor1_bounds.y() - cursor2_bounds.y(), bounds1.y() - bounds2.y());
  284. EXPECT_EQ(bounds1.width(), bounds2.width());
  285. EXPECT_EQ(bounds1.height(), bounds2.height());
  286. const gfx::Rect screen_bounds = display::Screen::GetScreen()
  287. ->GetDisplayMatching(cursor1_bounds)
  288. .work_area();
  289. const gfx::Rect cursor3_bounds(100, screen_bounds.bottom() - 25, 1, 20);
  290. controller->ShowModeIndicator(cursor3_bounds, text);
  291. views::Widget* widget3 =
  292. controller->mode_indicator_observer()->active_widget();
  293. EXPECT_TRUE(widget3);
  294. EXPECT_NE(widget2, widget3);
  295. // Check if the location of the mode indicator is considered with the screen
  296. // size.
  297. gfx::Rect bounds3 = widget3->GetWindowBoundsInScreen();
  298. EXPECT_LT(bounds3.bottom(), screen_bounds.bottom());
  299. }
  300. TEST_F(ImeControllerImplTest, MirroringChanged) {
  301. UpdateDisplay("600x500,600x500");
  302. // The controller is already an observer of the display_manager
  303. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  304. TestImeControllerClient client;
  305. controller->SetClient(&client);
  306. display::DisplayManager* display_manager = Shell::Get()->display_manager();
  307. display_manager->SetMultiDisplayMode(display::DisplayManager::MIRRORING);
  308. display_manager->UpdateDisplays();
  309. EXPECT_TRUE(client.is_mirroring_);
  310. UpdateDisplay("600x500");
  311. EXPECT_FALSE(client.is_mirroring_);
  312. UpdateDisplay("600x500,600x500");
  313. EXPECT_TRUE(client.is_mirroring_);
  314. }
  315. TEST_F(ImeControllerImplTest, MeetMirroringChanged) {
  316. ImeControllerImpl* controller = Shell::Get()->ime_controller();
  317. TestImeControllerClient client;
  318. controller->SetClient(&client);
  319. EXPECT_FALSE(client.is_casting_);
  320. Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStart(
  321. base::DoNothing(), base::DoNothing(), u"");
  322. EXPECT_TRUE(client.is_casting_);
  323. Shell::Get()->system_tray_notifier()->NotifyScreenCaptureStop();
  324. EXPECT_FALSE(client.is_casting_);
  325. }
  326. } // namespace
  327. } // namespace ash