zwp_text_input_manager.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. // Copyright 2018 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 "components/exo/wayland/zwp_text_input_manager.h"
  5. #include <text-input-extension-unstable-v1-server-protocol.h>
  6. #include <text-input-unstable-v1-server-protocol.h>
  7. #include <wayland-server-core.h>
  8. #include <wayland-server-protocol-core.h>
  9. #include <xkbcommon/xkbcommon.h>
  10. #include "base/memory/weak_ptr.h"
  11. #include "base/strings/string_piece.h"
  12. #include "base/strings/utf_offset_string_conversions.h"
  13. #include "base/strings/utf_string_conversions.h"
  14. #include "components/exo/display.h"
  15. #include "components/exo/text_input.h"
  16. #include "components/exo/wayland/serial_tracker.h"
  17. #include "components/exo/wayland/server_util.h"
  18. #include "components/exo/wayland/wl_seat.h"
  19. #include "components/exo/xkb_tracker.h"
  20. #include "ui/base/ime/utf_offset.h"
  21. #include "ui/base/wayland/wayland_server_input_types.h"
  22. #include "ui/events/event.h"
  23. #include "ui/events/keycodes/dom/dom_code.h"
  24. #include "ui/events/keycodes/dom/keycode_converter.h"
  25. #include "ui/events/ozone/layout/xkb/xkb_modifier_converter.h"
  26. namespace exo {
  27. namespace wayland {
  28. namespace {
  29. // The list of modifiers that this supports.
  30. // This is consistent with X.h.
  31. constexpr const char* kModifierNames[] = {
  32. XKB_MOD_NAME_SHIFT, XKB_MOD_NAME_CAPS,
  33. XKB_MOD_NAME_CTRL, XKB_MOD_NAME_ALT,
  34. XKB_MOD_NAME_NUM, "Mod3",
  35. XKB_MOD_NAME_LOGO, "Mod5",
  36. };
  37. uint32_t keyCharToKeySym(char16_t keychar) {
  38. // TODO(b/237461655): Lacros fails to handle key presses properly when the
  39. // key character is not present in the keyboard layout.
  40. if ((keychar >= 0x20 && keychar <= 0x7e) ||
  41. (keychar >= 0xa0 && keychar <= 0xff)) {
  42. return keychar;
  43. }
  44. // The spec also requires event.GetCharacter() <= 0x10ffff but this is
  45. // always true due to the type of event.GetCharacter().
  46. if (keychar >= 0x100) {
  47. return keychar + 0x01000000;
  48. }
  49. // keysym 0 is used for unidentified events
  50. return 0;
  51. }
  52. ////////////////////////////////////////////////////////////////////////////////
  53. // text_input_v1 interface:
  54. class WaylandTextInputDelegate : public TextInput::Delegate {
  55. public:
  56. WaylandTextInputDelegate(wl_resource* text_input,
  57. const XkbTracker* xkb_tracker,
  58. SerialTracker* serial_tracker)
  59. : text_input_(text_input),
  60. xkb_tracker_(xkb_tracker),
  61. serial_tracker_(serial_tracker) {}
  62. ~WaylandTextInputDelegate() override = default;
  63. void set_surface(wl_resource* surface) { surface_ = surface; }
  64. void set_extended_text_input(wl_resource* extended_text_input) {
  65. extended_text_input_ = extended_text_input;
  66. }
  67. bool has_extended_text_input() const { return extended_text_input_; }
  68. base::WeakPtr<WaylandTextInputDelegate> GetWeakPtr() {
  69. return weak_factory_.GetWeakPtr();
  70. }
  71. wl_resource* resource() { return text_input_; }
  72. private:
  73. wl_client* client() { return wl_resource_get_client(text_input_); }
  74. // TextInput::Delegate:
  75. void Activated() override {
  76. zwp_text_input_v1_send_enter(text_input_, surface_);
  77. wl_client_flush(client());
  78. }
  79. void Deactivated() override {
  80. zwp_text_input_v1_send_leave(text_input_);
  81. wl_client_flush(client());
  82. }
  83. void OnVirtualKeyboardVisibilityChanged(bool is_visible) override {
  84. // The detailed spec of |state| is implementation dependent.
  85. // So, now we use the lowest bit to indicate whether keyboard is visible.
  86. // This behavior is consistent with ozone/wayland to support Lacros.
  87. zwp_text_input_v1_send_input_panel_state(text_input_,
  88. static_cast<uint32_t>(is_visible));
  89. wl_client_flush(client());
  90. }
  91. void OnVirtualKeyboardOccludedBoundsChanged(
  92. const gfx::Rect& screen_bounds) override {
  93. if (!extended_text_input_)
  94. return;
  95. if (wl_resource_get_version(extended_text_input_) >=
  96. ZCR_EXTENDED_TEXT_INPUT_V1_SET_VIRTUAL_KEYBOARD_OCCLUDED_BOUNDS_SINCE_VERSION) {
  97. zcr_extended_text_input_v1_send_set_virtual_keyboard_occluded_bounds(
  98. extended_text_input_, screen_bounds.x(), screen_bounds.y(),
  99. screen_bounds.width(), screen_bounds.height());
  100. wl_client_flush(client());
  101. }
  102. }
  103. void SetCompositionText(const ui::CompositionText& composition) override {
  104. SendPreeditStyle(composition.text, composition.ime_text_spans);
  105. std::vector<size_t> offsets = {composition.selection.start()};
  106. const std::string utf8 =
  107. base::UTF16ToUTF8AndAdjustOffsets(composition.text, &offsets);
  108. if (offsets[0] != std::string::npos)
  109. zwp_text_input_v1_send_preedit_cursor(text_input_, offsets[0]);
  110. zwp_text_input_v1_send_preedit_string(
  111. text_input_,
  112. serial_tracker_->GetNextSerial(SerialTracker::EventType::OTHER_EVENT),
  113. utf8.c_str(), utf8.c_str());
  114. wl_client_flush(client());
  115. }
  116. void Commit(const std::u16string& text) override {
  117. zwp_text_input_v1_send_commit_string(
  118. text_input_,
  119. serial_tracker_->GetNextSerial(SerialTracker::EventType::OTHER_EVENT),
  120. base::UTF16ToUTF8(text).c_str());
  121. wl_client_flush(client());
  122. }
  123. void SetCursor(base::StringPiece16 surrounding_text,
  124. const gfx::Range& selection) override {
  125. std::vector<size_t> offsets{selection.start(), selection.end()};
  126. base::UTF16ToUTF8AndAdjustOffsets(surrounding_text, &offsets);
  127. zwp_text_input_v1_send_cursor_position(text_input_,
  128. static_cast<uint32_t>(offsets[1]),
  129. static_cast<uint32_t>(offsets[0]));
  130. }
  131. void DeleteSurroundingText(base::StringPiece16 surrounding_text,
  132. const gfx::Range& range) override {
  133. std::vector<size_t> offsets{range.GetMin(), range.GetMax()};
  134. base::UTF16ToUTF8AndAdjustOffsets(surrounding_text, &offsets);
  135. // Currently, the arguments are conflicting with spec.
  136. // However, the only client, Lacros, also interprets wrongly in the same
  137. // way so just fixing here could cause visible regression.
  138. // TODO(crbug.com/1227590): Fix the behavior with versioning.
  139. zwp_text_input_v1_send_delete_surrounding_text(
  140. text_input_, static_cast<uint32_t>(offsets[0]),
  141. static_cast<uint32_t>(offsets[1] - offsets[0]));
  142. }
  143. void SendKey(const ui::KeyEvent& event) override {
  144. uint32_t keysym =
  145. event.code() != ui::DomCode::NONE
  146. ? xkb_tracker_->GetKeysym(
  147. ui::KeycodeConverter::DomCodeToNativeKeycode(event.code()))
  148. : 0;
  149. // Some artificial key events (e.g. from virtual keyboard) do not set code,
  150. // so must be handled separately.
  151. // https://www.x.org/releases/X11R7.6/doc/xproto/x11protocol.html#keysym_encoding
  152. // suggests that we can just directly map some parts of unicode.
  153. if (keysym == 0) {
  154. keysym = keyCharToKeySym(event.GetCharacter());
  155. }
  156. if (keysym == 0) {
  157. VLOG(0) << "Unable to find keysym for: " << event.ToString();
  158. }
  159. bool pressed = (event.type() == ui::ET_KEY_PRESSED);
  160. zwp_text_input_v1_send_keysym(
  161. text_input_, TimeTicksToMilliseconds(event.time_stamp()),
  162. serial_tracker_->GetNextSerial(SerialTracker::EventType::OTHER_EVENT),
  163. keysym,
  164. pressed ? WL_KEYBOARD_KEY_STATE_PRESSED
  165. : WL_KEYBOARD_KEY_STATE_RELEASED,
  166. modifier_converter_.MaskFromUiFlags(event.flags()));
  167. wl_client_flush(client());
  168. }
  169. void OnTextDirectionChanged(base::i18n::TextDirection direction) override {
  170. uint32_t wayland_direction = ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_AUTO;
  171. switch (direction) {
  172. case base::i18n::RIGHT_TO_LEFT:
  173. wayland_direction = ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR;
  174. break;
  175. case base::i18n::LEFT_TO_RIGHT:
  176. wayland_direction = ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_RTL;
  177. break;
  178. case base::i18n::UNKNOWN_DIRECTION:
  179. LOG(ERROR) << "Unrecognized direction: " << direction;
  180. }
  181. zwp_text_input_v1_send_text_direction(
  182. text_input_,
  183. serial_tracker_->GetNextSerial(SerialTracker::EventType::OTHER_EVENT),
  184. wayland_direction);
  185. }
  186. void SetCompositionFromExistingText(
  187. base::StringPiece16 surrounding_text,
  188. const gfx::Range& cursor,
  189. const gfx::Range& range,
  190. const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override {
  191. if (!extended_text_input_)
  192. return;
  193. uint32_t begin = range.GetMin();
  194. uint32_t end = range.GetMax();
  195. SendPreeditStyle(surrounding_text.substr(begin, range.length()),
  196. ui_ime_text_spans);
  197. std::vector<size_t> offsets = {begin, end, cursor.end()};
  198. base::UTF16ToUTF8AndAdjustOffsets(surrounding_text, &offsets);
  199. int32_t index =
  200. static_cast<int32_t>(offsets[0]) - static_cast<int32_t>(offsets[2]);
  201. uint32_t length = static_cast<uint32_t>(offsets[1] - offsets[0]);
  202. zcr_extended_text_input_v1_send_set_preedit_region(extended_text_input_,
  203. index, length);
  204. wl_client_flush(client());
  205. }
  206. void ClearGrammarFragments(base::StringPiece16 surrounding_text,
  207. const gfx::Range& range) override {
  208. if (!extended_text_input_)
  209. return;
  210. if (wl_resource_get_version(extended_text_input_) >=
  211. ZCR_EXTENDED_TEXT_INPUT_V1_CLEAR_GRAMMAR_FRAGMENTS_SINCE_VERSION) {
  212. std::vector<size_t> offsets = {range.start(), range.end()};
  213. base::UTF16ToUTF8AndAdjustOffsets(surrounding_text, &offsets);
  214. zcr_extended_text_input_v1_send_clear_grammar_fragments(
  215. extended_text_input_, static_cast<uint32_t>(offsets[0]),
  216. static_cast<uint32_t>(offsets[1]));
  217. wl_client_flush(client());
  218. }
  219. }
  220. void AddGrammarFragment(base::StringPiece16 surrounding_text,
  221. const ui::GrammarFragment& fragment) override {
  222. if (!extended_text_input_)
  223. return;
  224. if (wl_resource_get_version(extended_text_input_) >=
  225. ZCR_EXTENDED_TEXT_INPUT_V1_ADD_GRAMMAR_FRAGMENT_SINCE_VERSION) {
  226. std::vector<size_t> offsets = {fragment.range.start(),
  227. fragment.range.end()};
  228. base::UTF16ToUTF8AndAdjustOffsets(surrounding_text, &offsets);
  229. zcr_extended_text_input_v1_send_add_grammar_fragment(
  230. extended_text_input_, static_cast<uint32_t>(offsets[0]),
  231. static_cast<uint32_t>(offsets[1]), fragment.suggestion.c_str());
  232. wl_client_flush(client());
  233. }
  234. }
  235. void SetAutocorrectRange(base::StringPiece16 surrounding_text,
  236. const gfx::Range& range) override {
  237. if (!extended_text_input_)
  238. return;
  239. const uint32_t begin = range.GetMin();
  240. const uint32_t end = range.GetMax();
  241. if (wl_resource_get_version(extended_text_input_) >=
  242. ZCR_EXTENDED_TEXT_INPUT_V1_SET_AUTOCORRECT_RANGE_SINCE_VERSION) {
  243. // TODO(https://crbug.com/952757): Convert to UTF-8 offsets once the
  244. // surrounding text is no longer stale.
  245. zcr_extended_text_input_v1_send_set_autocorrect_range(
  246. extended_text_input_, begin, end);
  247. wl_client_flush(client());
  248. }
  249. }
  250. void SendPreeditStyle(base::StringPiece16 text,
  251. const std::vector<ui::ImeTextSpan>& spans) {
  252. if (spans.empty())
  253. return;
  254. // Convert all offsets from UTF16 to UTF8.
  255. std::vector<size_t> offsets;
  256. offsets.reserve(spans.size() * 2);
  257. for (const auto& span : spans) {
  258. auto minmax = std::minmax(span.start_offset, span.end_offset);
  259. offsets.push_back(minmax.first);
  260. offsets.push_back(minmax.second);
  261. }
  262. base::UTF16ToUTF8AndAdjustOffsets(text, &offsets);
  263. for (size_t i = 0; i < spans.size(); ++i) {
  264. if (offsets[i * 2] == std::string::npos ||
  265. offsets[i * 2 + 1] == std::string::npos) {
  266. // Invalid span is specified.
  267. continue;
  268. }
  269. const auto& span = spans[i];
  270. const uint32_t begin = offsets[i * 2];
  271. const uint32_t end = offsets[i * 2 + 1];
  272. uint32_t style = ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_DEFAULT;
  273. switch (span.type) {
  274. case ui::ImeTextSpan::Type::kComposition:
  275. if (span.thickness == ui::ImeTextSpan::Thickness::kThick) {
  276. style = ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT;
  277. } else {
  278. style = ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_UNDERLINE;
  279. }
  280. break;
  281. case ui::ImeTextSpan::Type::kSuggestion:
  282. style = ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_SELECTION;
  283. break;
  284. case ui::ImeTextSpan::Type::kMisspellingSuggestion:
  285. case ui::ImeTextSpan::Type::kAutocorrect:
  286. case ui::ImeTextSpan::Type::kGrammarSuggestion:
  287. style = ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INCORRECT;
  288. break;
  289. }
  290. zwp_text_input_v1_send_preedit_styling(text_input_, begin, end - begin,
  291. style);
  292. }
  293. }
  294. wl_resource* text_input_;
  295. wl_resource* extended_text_input_ = nullptr;
  296. wl_resource* surface_ = nullptr;
  297. // Owned by Seat, which is updated before calling the callbacks of this
  298. // class.
  299. const XkbTracker* const xkb_tracker_;
  300. // Owned by Server, which always outlives this delegate.
  301. SerialTracker* const serial_tracker_;
  302. ui::XkbModifierConverter modifier_converter_{
  303. std::vector<std::string>(std::begin(kModifierNames),
  304. std::end(kModifierNames))};
  305. base::WeakPtrFactory<WaylandTextInputDelegate> weak_factory_{this};
  306. };
  307. // Holds WeakPtr to WaylandTextInputDelegate, and the lifetime of this class's
  308. // instance is tied to zcr_extended_text_input connection.
  309. // If text_input connection is destroyed earlier than extended_text_input,
  310. // then delegate_ will return nullptr automatically.
  311. class WaylandExtendedTextInput {
  312. public:
  313. explicit WaylandExtendedTextInput(
  314. base::WeakPtr<WaylandTextInputDelegate> delegate)
  315. : delegate_(delegate) {}
  316. WaylandExtendedTextInput(const WaylandExtendedTextInput&) = delete;
  317. WaylandExtendedTextInput& operator=(const WaylandExtendedTextInput&) = delete;
  318. ~WaylandExtendedTextInput() {
  319. if (delegate_)
  320. delegate_->set_extended_text_input(nullptr);
  321. }
  322. WaylandTextInputDelegate* delegate() { return delegate_.get(); }
  323. private:
  324. base::WeakPtr<WaylandTextInputDelegate> delegate_;
  325. };
  326. void text_input_activate(wl_client* client,
  327. wl_resource* resource,
  328. wl_resource* seat_resource,
  329. wl_resource* surface_resource) {
  330. TextInput* text_input = GetUserDataAs<TextInput>(resource);
  331. Surface* surface = GetUserDataAs<Surface>(surface_resource);
  332. Seat* seat = GetUserDataAs<WaylandSeat>(seat_resource)->seat;
  333. static_cast<WaylandTextInputDelegate*>(text_input->delegate())
  334. ->set_surface(surface_resource);
  335. text_input->Activate(seat, surface);
  336. // Sending modifiers.
  337. wl_array modifiers;
  338. wl_array_init(&modifiers);
  339. for (const char* modifier : kModifierNames) {
  340. char* p =
  341. static_cast<char*>(wl_array_add(&modifiers, ::strlen(modifier) + 1));
  342. ::strcpy(p, modifier);
  343. }
  344. zwp_text_input_v1_send_modifiers_map(resource, &modifiers);
  345. wl_array_release(&modifiers);
  346. }
  347. void text_input_deactivate(wl_client* client,
  348. wl_resource* resource,
  349. wl_resource* seat) {
  350. TextInput* text_input = GetUserDataAs<TextInput>(resource);
  351. text_input->Deactivate();
  352. }
  353. void text_input_show_input_panel(wl_client* client, wl_resource* resource) {
  354. GetUserDataAs<TextInput>(resource)->ShowVirtualKeyboardIfEnabled();
  355. }
  356. void text_input_hide_input_panel(wl_client* client, wl_resource* resource) {
  357. GetUserDataAs<TextInput>(resource)->HideVirtualKeyboard();
  358. }
  359. void text_input_reset(wl_client* client, wl_resource* resource) {
  360. GetUserDataAs<TextInput>(resource)->Reset();
  361. }
  362. void text_input_set_surrounding_text(wl_client* client,
  363. wl_resource* resource,
  364. const char* text,
  365. uint32_t cursor,
  366. uint32_t anchor) {
  367. TextInput* text_input = GetUserDataAs<TextInput>(resource);
  368. // TODO(crbug.com/1227590): Selection range should keep cursor/anchor
  369. // relationship.
  370. auto minmax = std::minmax(cursor, anchor);
  371. std::vector<size_t> offsets{minmax.first, minmax.second};
  372. std::u16string u16_text = base::UTF8ToUTF16AndAdjustOffsets(text, &offsets);
  373. if (offsets[0] == std::u16string::npos || offsets[1] == std::u16string::npos)
  374. return;
  375. text_input->SetSurroundingText(u16_text, gfx::Range(offsets[0], offsets[1]));
  376. }
  377. void text_input_set_content_type(wl_client* client,
  378. wl_resource* resource,
  379. uint32_t hint,
  380. uint32_t purpose) {
  381. TextInput* text_input = GetUserDataAs<TextInput>(resource);
  382. ui::TextInputType type = ui::TEXT_INPUT_TYPE_TEXT;
  383. ui::TextInputMode mode = ui::TEXT_INPUT_MODE_DEFAULT;
  384. int flags = ui::TEXT_INPUT_FLAG_NONE;
  385. bool should_do_learning = true;
  386. if (hint & ZWP_TEXT_INPUT_V1_CONTENT_HINT_AUTO_COMPLETION)
  387. flags |= ui::TEXT_INPUT_FLAG_AUTOCOMPLETE_ON;
  388. if (hint & ZWP_TEXT_INPUT_V1_CONTENT_HINT_AUTO_CORRECTION)
  389. flags |= ui::TEXT_INPUT_FLAG_AUTOCORRECT_ON;
  390. if (hint & ZWP_TEXT_INPUT_V1_CONTENT_HINT_AUTO_CAPITALIZATION)
  391. flags |= ui::TEXT_INPUT_FLAG_AUTOCAPITALIZE_SENTENCES;
  392. if (hint & ZWP_TEXT_INPUT_V1_CONTENT_HINT_LOWERCASE)
  393. flags |= ui::TEXT_INPUT_FLAG_AUTOCAPITALIZE_NONE;
  394. if (hint & ZWP_TEXT_INPUT_V1_CONTENT_HINT_UPPERCASE)
  395. flags |= ui::TEXT_INPUT_FLAG_AUTOCAPITALIZE_CHARACTERS;
  396. if (hint & ZWP_TEXT_INPUT_V1_CONTENT_HINT_TITLECASE)
  397. flags |= ui::TEXT_INPUT_FLAG_AUTOCAPITALIZE_WORDS;
  398. if (hint & ZWP_TEXT_INPUT_V1_CONTENT_HINT_HIDDEN_TEXT) {
  399. flags |= ui::TEXT_INPUT_FLAG_AUTOCOMPLETE_OFF |
  400. ui::TEXT_INPUT_FLAG_AUTOCORRECT_OFF;
  401. }
  402. if (hint & ZWP_TEXT_INPUT_V1_CONTENT_HINT_SENSITIVE_DATA)
  403. should_do_learning = false;
  404. // Unused hints: LATIN, MULTILINE.
  405. switch (purpose) {
  406. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_DIGITS:
  407. mode = ui::TEXT_INPUT_MODE_DECIMAL;
  408. type = ui::TEXT_INPUT_TYPE_NUMBER;
  409. break;
  410. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER:
  411. mode = ui::TEXT_INPUT_MODE_NUMERIC;
  412. type = ui::TEXT_INPUT_TYPE_NUMBER;
  413. break;
  414. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_PHONE:
  415. mode = ui::TEXT_INPUT_MODE_TEL;
  416. type = ui::TEXT_INPUT_TYPE_TELEPHONE;
  417. break;
  418. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_URL:
  419. mode = ui::TEXT_INPUT_MODE_URL;
  420. type = ui::TEXT_INPUT_TYPE_URL;
  421. break;
  422. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_EMAIL:
  423. mode = ui::TEXT_INPUT_MODE_EMAIL;
  424. type = ui::TEXT_INPUT_TYPE_EMAIL;
  425. break;
  426. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_PASSWORD:
  427. should_do_learning = false;
  428. type = ui::TEXT_INPUT_TYPE_PASSWORD;
  429. break;
  430. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_DATE:
  431. type = ui::TEXT_INPUT_TYPE_DATE;
  432. break;
  433. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_TIME:
  434. type = ui::TEXT_INPUT_TYPE_TIME;
  435. break;
  436. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_DATETIME:
  437. type = ui::TEXT_INPUT_TYPE_DATE_TIME;
  438. break;
  439. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NORMAL:
  440. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_ALPHA:
  441. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NAME:
  442. case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_TERMINAL:
  443. // No special type / mode are set.
  444. break;
  445. }
  446. text_input->SetTypeModeFlags(type, mode, flags, should_do_learning);
  447. }
  448. void text_input_set_cursor_rectangle(wl_client* client,
  449. wl_resource* resource,
  450. int32_t x,
  451. int32_t y,
  452. int32_t width,
  453. int32_t height) {
  454. GetUserDataAs<TextInput>(resource)->SetCaretBounds(
  455. gfx::Rect(x, y, width, height));
  456. }
  457. void text_input_set_preferred_language(wl_client* client,
  458. wl_resource* resource,
  459. const char* language) {
  460. // Nothing needs to be done.
  461. }
  462. void text_input_commit_state(wl_client* client,
  463. wl_resource* resource,
  464. uint32_t serial) {
  465. // Nothing needs to be done.
  466. }
  467. void text_input_invoke_action(wl_client* client,
  468. wl_resource* resource,
  469. uint32_t button,
  470. uint32_t index) {
  471. GetUserDataAs<TextInput>(resource)->Resync();
  472. }
  473. constexpr struct zwp_text_input_v1_interface text_input_v1_implementation = {
  474. text_input_activate,
  475. text_input_deactivate,
  476. text_input_show_input_panel,
  477. text_input_hide_input_panel,
  478. text_input_reset,
  479. text_input_set_surrounding_text,
  480. text_input_set_content_type,
  481. text_input_set_cursor_rectangle,
  482. text_input_set_preferred_language,
  483. text_input_commit_state,
  484. text_input_invoke_action,
  485. };
  486. ////////////////////////////////////////////////////////////////////////////////
  487. // text_input_manager_v1 interface:
  488. void text_input_manager_create_text_input(wl_client* client,
  489. wl_resource* resource,
  490. uint32_t id) {
  491. auto* data = GetUserDataAs<WaylandTextInputManager>(resource);
  492. wl_resource* text_input_resource =
  493. wl_resource_create(client, &zwp_text_input_v1_interface, 1, id);
  494. SetImplementation(
  495. text_input_resource, &text_input_v1_implementation,
  496. std::make_unique<TextInput>(std::make_unique<WaylandTextInputDelegate>(
  497. text_input_resource, data->xkb_tracker, data->serial_tracker)));
  498. }
  499. constexpr struct zwp_text_input_manager_v1_interface
  500. text_input_manager_implementation = {
  501. text_input_manager_create_text_input,
  502. };
  503. ////////////////////////////////////////////////////////////////////////////////
  504. // extended_text_input_v1 interface:
  505. void extended_text_input_destroy(wl_client* client, wl_resource* resource) {
  506. wl_resource_destroy(resource);
  507. }
  508. void extended_text_input_set_input_type(wl_client* client,
  509. wl_resource* resource,
  510. uint32_t input_type,
  511. uint32_t input_mode,
  512. uint32_t input_flags,
  513. uint32_t learning_mode) {
  514. auto* delegate =
  515. GetUserDataAs<WaylandExtendedTextInput>(resource)->delegate();
  516. if (!delegate)
  517. return;
  518. // If unknown value is passed, fall back to the default one.
  519. auto ui_type =
  520. ui::wayland::ConvertToTextInputType(
  521. static_cast<zcr_extended_text_input_v1_input_type>(input_type))
  522. .value_or(ui::TEXT_INPUT_TYPE_TEXT);
  523. auto ui_mode =
  524. ui::wayland::ConvertToTextInputMode(
  525. static_cast<zcr_extended_text_input_v1_input_mode>(input_mode))
  526. .value_or(ui::TEXT_INPUT_MODE_DEFAULT);
  527. // Ignore unknown flags.
  528. auto ui_flags = ui::wayland::ConvertToTextInputFlags(input_flags).first;
  529. bool should_do_learning =
  530. learning_mode == ZCR_EXTENDED_TEXT_INPUT_V1_LEARNING_MODE_ENABLED;
  531. auto* text_input = GetUserDataAs<TextInput>(delegate->resource());
  532. text_input->SetTypeModeFlags(ui_type, ui_mode, ui_flags, should_do_learning);
  533. }
  534. void extended_text_input_set_grammar_fragment_at_cursor(
  535. wl_client* client,
  536. wl_resource* resource,
  537. uint32_t start,
  538. uint32_t end,
  539. const char* suggestion) {
  540. auto* delegate =
  541. GetUserDataAs<WaylandExtendedTextInput>(resource)->delegate();
  542. if (!delegate)
  543. return;
  544. auto* text_input = GetUserDataAs<TextInput>(delegate->resource());
  545. if (start == end) {
  546. text_input->SetGrammarFragmentAtCursor(absl::nullopt);
  547. } else {
  548. text_input->SetGrammarFragmentAtCursor(
  549. ui::GrammarFragment(gfx::Range(start, end), suggestion));
  550. }
  551. }
  552. void extended_text_input_set_autocorrect_info(wl_client* client,
  553. wl_resource* resource,
  554. uint32_t start,
  555. uint32_t end,
  556. uint32_t x,
  557. uint32_t y,
  558. uint32_t width,
  559. uint32_t height) {
  560. auto* delegate =
  561. GetUserDataAs<WaylandExtendedTextInput>(resource)->delegate();
  562. if (!delegate)
  563. return;
  564. auto* text_input = GetUserDataAs<TextInput>(delegate->resource());
  565. // TODO(https://crbug.com/952757): Convert to UTF-16 offsets once the
  566. // surrounding text is no longer stale.
  567. gfx::Range autocorrect_range(start, end);
  568. gfx::Rect autocorrect_bounds(x, y, width, height);
  569. text_input->SetAutocorrectInfo(autocorrect_range, autocorrect_bounds);
  570. }
  571. constexpr struct zcr_extended_text_input_v1_interface
  572. extended_text_input_implementation = {
  573. extended_text_input_destroy,
  574. extended_text_input_set_input_type,
  575. extended_text_input_set_grammar_fragment_at_cursor,
  576. extended_text_input_set_autocorrect_info,
  577. };
  578. ////////////////////////////////////////////////////////////////////////////////
  579. // text_input_extension_v1 interface:
  580. void text_input_extension_get_extended_text_input(
  581. wl_client* client,
  582. wl_resource* resource,
  583. uint32_t id,
  584. wl_resource* text_input_resource) {
  585. TextInput* text_input = GetUserDataAs<TextInput>(text_input_resource);
  586. auto* delegate =
  587. static_cast<WaylandTextInputDelegate*>(text_input->delegate());
  588. if (delegate->has_extended_text_input()) {
  589. wl_resource_post_error(
  590. resource, ZCR_TEXT_INPUT_EXTENSION_V1_ERROR_EXTENDED_TEXT_INPUT_EXISTS,
  591. "text_input has already been associated with a extended_text_input "
  592. "object");
  593. return;
  594. }
  595. uint32_t version = wl_resource_get_version(resource);
  596. wl_resource* extended_text_input_resource = wl_resource_create(
  597. client, &zcr_extended_text_input_v1_interface, version, id);
  598. delegate->set_extended_text_input(extended_text_input_resource);
  599. SetImplementation(
  600. extended_text_input_resource, &extended_text_input_implementation,
  601. std::make_unique<WaylandExtendedTextInput>(delegate->GetWeakPtr()));
  602. }
  603. constexpr struct zcr_text_input_extension_v1_interface
  604. text_input_extension_implementation = {
  605. text_input_extension_get_extended_text_input};
  606. } // namespace
  607. void bind_text_input_manager(wl_client* client,
  608. void* data,
  609. uint32_t version,
  610. uint32_t id) {
  611. wl_resource* resource =
  612. wl_resource_create(client, &zwp_text_input_manager_v1_interface, 1, id);
  613. wl_resource_set_implementation(resource, &text_input_manager_implementation,
  614. data, nullptr);
  615. }
  616. void bind_text_input_extension(wl_client* client,
  617. void* data,
  618. uint32_t version,
  619. uint32_t id) {
  620. wl_resource* resource = wl_resource_create(
  621. client, &zcr_text_input_extension_v1_interface, version, id);
  622. wl_resource_set_implementation(resource, &text_input_extension_implementation,
  623. data, nullptr);
  624. }
  625. } // namespace wayland
  626. } // namespace exo