1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "custom_input_method.h"
17
18 #include <string>
19
20 #include "common/input_method_manager.h"
21 #include "components/root_view.h"
22 #include "components/ui_checkbox.h"
23 #include "components/ui_edit_text.h"
24 #include "components/ui_label.h"
25 #include "font/ui_font.h"
26 #include "ui_test.h"
27 #include "graphic_timer.h"
28
29 namespace OHOS {
30 namespace {
31 struct KeyInfo {
32 uint8_t keyCount;
33 uint8_t row1Count;
34 uint8_t row2Count;
35 uint8_t row3Count;
36 uint8_t row4Count;
37 const char* keyName[32]; // 32: max count of keys
38 };
39
40 const KeyInfo LOW_CASE_KEY_IOFO = {
41 32, 10, 19, 28, 32,
42 {
43 "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", // 10
44 "a", "s", "d", "f", "g", "h", "j", "k", "l", // 9
45 "shift", "z", "x", "c", "v", "b", "n", "m", "del", // 9
46 "123", "space", ".", "return" // 4
47 }
48 };
49
50 const KeyInfo UPPER_CASE_KEY_IOFO = {
51 32, 10, 19, 28, 32,
52 {
53 "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", // 10
54 "A", "S", "D", "F", "G", "H", "J", "K", "L", // 9
55 "shift", "Z", "X", "C", "V", "B", "N", "M", "del", // 9
56 "123", "space", ".", "return" // 4
57 }
58 };
59
60 const KeyInfo NUM_KEY_IOFO = {
61 31, 10, 20, 27, 31,
62 {
63 "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", // 10
64 "-", "/", ":", ";", "(", ")", "$", "&", "@", "\"", // 10
65 "#+=", ".", ",", "?", "!", "'", "del", // 7
66 "ABC", "space", ".", "return" // 4
67 }
68 };
69
70 const KeyInfo SYMBOL_KEY_IOFO = {
71 31, 10, 20, 27, 31,
72 {
73 "[", "]", "{", "}", "#", "%", "^", "*", "+", "=", // 10
74 "_", "\\", "|", "~", "<", ">", "¥", "€", "£", "•", // 10
75 "123", ".", ",", "?", "!", "'", "del", // 7
76 "ABC", "space", ".", "return" // 4
77 }
78 };
79
80 const int16_t KEYBOARD_WIDTH = 580;
81 const int16_t KEYBOARD_HEIGHT = 320;
82 const int16_t KEY_WIDTH = 50;
83 const int16_t KEY_HEIGHT = 65;
84 const int16_t FUNC_KEY_WIDTH = 65;
85 const int16_t SPACE_KEY_WIDTH = 260;
86 const int16_t RETURN_KEY_WIDTH = 120;
87 const int16_t KEY_BORDER_RADIUS = 10;
88 const int16_t KEY_MARGIN_LEFT = 7;
89
GetKeyInfo(KeyboardType type)90 KeyInfo GetKeyInfo(KeyboardType type)
91 {
92 KeyInfo keyInfo;
93 switch (type) {
94 case KeyboardType::LOW_CASE:
95 keyInfo = LOW_CASE_KEY_IOFO;
96 break;
97 case KeyboardType::UPPER_CASE:
98 keyInfo = UPPER_CASE_KEY_IOFO;
99 break;
100 case KeyboardType::NUMBER:
101 keyInfo = NUM_KEY_IOFO;
102 break;
103 case KeyboardType::SYMBOL:
104 keyInfo = SYMBOL_KEY_IOFO;
105 break;
106 default:
107 keyInfo = LOW_CASE_KEY_IOFO;
108 break;
109 }
110
111 return keyInfo;
112 }
113 } // namespace
114
OnShow(InputMethodManager::InputMethodParam & param)115 void CustomInputMethod::OnShow(InputMethodManager::InputMethodParam& param)
116 {
117 bool needFocus = editView_ == nullptr ? true : false;
118 SetupView(keyboardType_);
119
120 // update value
121 editView_->SetText(param.text.c_str());
122 editView_->SetInputType(param.inputType);
123 if (param.view != nullptr) {
124 UIEditText* paramView = reinterpret_cast<UIEditText*>(param.view);
125 editView_->SetPlaceholder(paramView->GetPlaceholder());
126 editView_->SetPlaceholderColor(paramView->GetPlaceholderColor());
127 editView_->SetCursorColor(paramView->GetCursorColor());
128 editView_->SetCursorIndex(paramView->GetCursorIndex());
129 editView_->SetTextColor(paramView->GetTextColor());
130 editView_->SetMaxLength(paramView->GetMaxLength());
131 }
132 if (needFocus) {
133 editView_->RequestFocus();
134 }
135
136 container_->Invalidate();
137
138 // keyboard show callback
139 InputMethodManager::GetInstance().OnKeyboardShow();
140 }
141
OnHide()142 void CustomInputMethod::OnHide()
143 {
144 editView_->Blur();
145 TearDownView();
146
147 // keyboard show callback
148 InputMethodManager::GetInstance().OnKeyboardHide();
149 }
150
SetupView(KeyboardType type)151 void CustomInputMethod::SetupView(KeyboardType type)
152 {
153 if (container_ == nullptr) {
154 container_ = new UIViewGroup();
155 container_->Resize(KEYBOARD_WIDTH, 650); // 650: height
156 container_->SetPosition(350, 100); // 350: position x, 100: position y
157 container_->SetStyle(STYLE_BORDER_COLOR, Color::White().full);
158 // add on rootview
159 RootView::GetInstance()->Add(container_);
160 }
161
162 if (editView_ != nullptr) {
163 container_->Remove(editView_);
164 delete editView_;
165 }
166 editView_ = new UIEditTextEx();
167 container_->Add(editView_);
168 editView_->Resize(250, 40); // 250: width, 40: height
169 editView_->SetPosition(0, 0);
170 editView_->SetViewId("Input_edit_text_view");
171
172 if (inputTypeBtn_ == nullptr) {
173 inputTypeBtn_ = new UILabelButton();
174 container_->Add(inputTypeBtn_);
175 inputTypeBtn_->Resize(100, 40); // 100: width, 40: height
176 inputTypeBtn_->SetText("toggle");
177 inputTypeBtn_->SetViewId(UI_TEST_KEY_INPUT);
178 inputTypeBtn_->LayoutRightToSibling("Input_edit_text_view", 10); // 10: offset
179 inputTypeBtn_->SetOnClickListener(this);
180 inputTypeBtn_->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE,
181 UIButton::RELEASED);
182 inputTypeBtn_->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
183 }
184
185 SetupKeyboard(type);
186 }
187
SetupKeyboard(KeyboardType type)188 void CustomInputMethod::SetupKeyboard(KeyboardType type)
189 {
190 UIViewGroup* keyboard = new UIViewGroup();
191 int16_t rowHeight = KEYBOARD_HEIGHT / 4; // 4: row number
192 keyboard->Resize(KEYBOARD_WIDTH, KEYBOARD_HEIGHT);
193 keyboard->SetPosition(0, 45); // 45: position y
194 keyboard->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
195 keyboard->SetViewId("keyboard");
196 container_->Add(keyboard);
197 FlexLayout* row1 = SetupKeyRow("row1", KEYBOARD_WIDTH, rowHeight);
198 row1->SetPosition(0, 0);
199 keyboard->Add(row1);
200
201 FlexLayout* row2 = SetupKeyRow("row2", KEYBOARD_WIDTH, rowHeight);
202 keyboard->Add(row2);
203 row2->LayoutBottomToSibling("row1");
204
205 FlexLayout* row3 = SetupKeyRow("row3", KEYBOARD_WIDTH, rowHeight);
206 keyboard->Add(row3);
207 row3->LayoutBottomToSibling("row2");
208
209 FlexLayout* row4 = SetupKeyRow("row4", KEYBOARD_WIDTH, rowHeight);
210 keyboard->Add(row4);
211 row4->LayoutBottomToSibling("row3");
212
213 KeyInfo keyInfo = GetKeyInfo(type);
214 for (int16_t i = 0; i < keyInfo.keyCount; i++) {
215 UILabelButton* key = SetupButton(keyInfo.keyName[i]);
216 if (i < keyInfo.row1Count) {
217 row1->Add(key);
218 } else if (i < keyInfo.row2Count) {
219 row2->Add(key);
220 } else if (i < keyInfo.row3Count) {
221 row3->Add(key);
222 } else if (i < keyInfo.row4Count) {
223 row4->Add(key);
224 }
225 }
226
227 row1->LayoutChildren();
228 row2->LayoutChildren();
229 row3->LayoutChildren();
230 row4->LayoutChildren();
231 keyboard->Invalidate();
232 }
233
SetupKeyRow(const char * name,int16_t width,int16_t height)234 FlexLayout* CustomInputMethod::SetupKeyRow(const char* name, int16_t width, int16_t height)
235 {
236 FlexLayout* row = new FlexLayout();
237 row->Resize(width, height);
238 row->SetViewId(name);
239 row->SetMajorAxisAlign(ALIGN_CENTER);
240 row->SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);
241 return row;
242 }
243
SetupButton(const char * title)244 UILabelButton* CustomInputMethod::SetupButton(const char* title)
245 {
246 UILabelButton* keyBtn = new UILabelButton();
247 keyBtn->SetText(title);
248 keyBtn->SetViewId(title);
249 keyBtn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
250 keyBtn->SetStyle(STYLE_MARGIN_LEFT, KEY_MARGIN_LEFT);
251 keyBtn->SetOnClickListener(this);
252 int16_t radius = KEY_BORDER_RADIUS;
253 keyBtn->SetStyleForState(STYLE_BORDER_RADIUS, radius, UIButton::RELEASED);
254 keyBtn->SetStyleForState(STYLE_BORDER_RADIUS, radius, UIButton::PRESSED);
255 keyBtn->SetStyleForState(STYLE_BORDER_RADIUS, radius, UIButton::INACTIVE);
256 keyBtn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
257 keyBtn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
258 keyBtn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
259 keyBtn->Resize(KEY_WIDTH, KEY_HEIGHT);
260
261 keyBtn->SetOnLongPressListener(this);
262 keyBtn->SetOnTouchListener(this);
263
264 if ((strcmp(title, "shift") == 0) || (strcmp(title, "del") == 0) || (strcmp(title, "123") == 0) ||
265 (strcmp(title, "ABC") == 0) || (strcmp(title, "#+=") == 0)) {
266 keyBtn->Resize(FUNC_KEY_WIDTH, KEY_HEIGHT);
267 } else if (strcmp(title, "space") == 0) {
268 keyBtn->Resize(SPACE_KEY_WIDTH, KEY_HEIGHT);
269 } else if (strcmp(title, "return") == 0) {
270 keyBtn->Resize(RETURN_KEY_WIDTH, KEY_HEIGHT);
271 }
272 return keyBtn;
273 }
274
TearDownView()275 void CustomInputMethod::TearDownView()
276 {
277 UITest::DeleteChildren(container_);
278 container_ = nullptr;
279 editView_ = nullptr;
280 }
281
OnClick(UIView & view,const ClickEvent & event)282 bool CustomInputMethod::OnClick(UIView& view, const ClickEvent& event)
283 {
284 if (inputTypeBtn_ == &view) {
285 InputType type = editView_->GetInputType();
286 if (type == InputType::TEXT_TYPE) {
287 editView_->SetInputType(InputType::PASSWORD_TYPE);
288 InputMethodManager::GetInstance().SetInputType(InputType::PASSWORD_TYPE);
289 } else {
290 editView_->SetInputType(InputType::TEXT_TYPE);
291 InputMethodManager::GetInstance().SetInputType(InputType::TEXT_TYPE);
292 }
293 } else {
294 DealKeyEvent(view);
295 }
296
297 return true;
298 }
299
DealKeyEvent(UIView & view)300 void CustomInputMethod::DealKeyEvent(UIView& view)
301 {
302 const char* key = reinterpret_cast<UILabelButton*>(&view)->GetText();
303 if (key == nullptr) {
304 return;
305 }
306
307 if (editView_ == nullptr) {
308 return;
309 }
310
311 if (editView_->GetIsFocus()) {
312 InputMethodManager::GetInstance().SetCursorIndex(editView_->GetCursorIndex());
313 } else {
314 editView_->SetCursorIndex(InputMethodManager::GetInstance().GetCursorIndex());
315 }
316
317 if (strcmp(key, "shift") == 0) {
318 if (keyboardType_ == KeyboardType::LOW_CASE) {
319 keyboardType_ = KeyboardType::UPPER_CASE;
320 } else {
321 keyboardType_ = KeyboardType::LOW_CASE;
322 }
323 ChangeKeyboard(keyboardType_);
324 } else if (strcmp(key, "123") == 0) {
325 keyboardType_ = KeyboardType::NUMBER;
326 ChangeKeyboard(keyboardType_);
327 } else if (strcmp(key, "ABC") == 0) {
328 keyboardType_ = KeyboardType::LOW_CASE;
329 ChangeKeyboard(keyboardType_);
330 } else if (strcmp(key, "#+=") == 0) {
331 keyboardType_ = KeyboardType::SYMBOL;
332 ChangeKeyboard(keyboardType_);
333 } else if (strcmp(key, "del") == 0) {
334 InputMethodManager::GetInstance().DeleteBackward(1);
335 editView_->DeleteBackward(1);
336 } else if (strcmp(key, "space") == 0) {
337 InputMethodManager::GetInstance().InsertText(" ");
338 editView_->InsertText(" ");
339 } else if (strcmp(key, "return") == 0) {
340 // do nothing
341 } else {
342 InputMethodManager::GetInstance().InsertText(key);
343 editView_->InsertText(key);
344 }
345 }
346
OnLongPress(UIView & view,const LongPressEvent & event)347 bool CustomInputMethod::OnLongPress(UIView &view, const LongPressEvent &event)
348 {
349 longPressed_ = true;
350 if (inputTypeBtn_ == &view) {
351 InputType type = editView_->GetInputType();
352 if (type == InputType::TEXT_TYPE) {
353 editView_->SetInputType(InputType::PASSWORD_TYPE);
354 InputMethodManager::GetInstance().SetInputType(InputType::PASSWORD_TYPE);
355 } else {
356 editView_->SetInputType(InputType::TEXT_TYPE);
357 InputMethodManager::GetInstance().SetInputType(InputType::TEXT_TYPE);
358 }
359 } else {
360 key_ = reinterpret_cast<UILabelButton*>(&view)->GetText();
361 timer_.Start();
362 }
363 return true;
364 }
365
OnRelease(UIView & view,const ReleaseEvent & event)366 bool CustomInputMethod::OnRelease(UIView& view, const ReleaseEvent& event)
367 {
368 if (longPressed_) {
369 longPressed_ = false;
370 timer_.Stop();
371 }
372 return true;
373 }
374
DealLongPressKeyEvent()375 void CustomInputMethod::DealLongPressKeyEvent()
376 {
377 if (key_ == nullptr) {
378 return;
379 }
380
381 if (strcmp(key_, "del") == 0) {
382 InputMethodManager::GetInstance().DeleteBackward(1);
383 editView_->DeleteBackward(1);
384 } else if (strcmp(key_, "space") == 0) {
385 InputMethodManager::GetInstance().InsertText(" ");
386 editView_->InsertText(" ");
387 } else if (strcmp(key_, "return") == 0 || strcmp(key_, "123") == 0 || strcmp(key_, "ABC") == 0
388 || strcmp(key_, "#+=") == 0 || strcmp(key_, "shift") == 0) {
389 // do nothing
390 } else {
391 InputMethodManager::GetInstance().InsertText(key_);
392 editView_->InsertText(key_);
393 }
394
395 if (!longPressed_) {
396 timer_.Stop();
397 } else {
398 timer_.Start();
399 }
400 }
401
ChangeKeyboard(KeyboardType type)402 void CustomInputMethod::ChangeKeyboard(KeyboardType type)
403 {
404 UIView* keyboardTmp = container_->GetChildById("keyboard");
405 SetupKeyboard(type);
406 container_->Remove(keyboardTmp);
407 UITest::DeleteChildren(keyboardTmp);
408 }
409 } // namespace OHOS
410