• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "core/components_ng/pattern/text_field/key_event_handler.h"
17 
18 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
19 
20 namespace OHOS::Ace::NG {
21 namespace {
22 // Whether the system is Mac or not determines which key code is selected.
23 #if defined(MAC_PLATFORM)
24 #define KEY_META_OR_CTRL_LEFT KeyCode::KEY_META_LEFT
25 #define KEY_META_OR_CTRL_RIGHT KeyCode::KEY_META_RIGHT
26 #else
27 #define KEY_META_OR_CTRL_LEFT KeyCode::KEY_CTRL_LEFT
28 #define KEY_META_OR_CTRL_RIGHT KeyCode::KEY_CTRL_RIGHT
29 #endif
30 }
HandleKeyEvent(const KeyEvent & keyEvent)31 bool KeyEventHandler::HandleKeyEvent(const KeyEvent& keyEvent)
32 {
33     LOGD("HandleKeyEvent event, caps lock %{public}d, key code %{public}d", keyEvent.enableCapsLock, keyEvent.code);
34     auto pattern = DynamicCast<TextFieldPattern>(weakPattern_.Upgrade());
35     CHECK_NULL_RETURN(pattern, false);
36 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
37     if (!pattern->GetImeAttached()) {
38         return false;
39     }
40 #endif
41     if (keyEvent.action == KeyAction::DOWN) {
42         std::string appendElement;
43         if (keyEvent.code == KeyCode::KEY_ENTER || keyEvent.code == KeyCode::KEY_NUMPAD_ENTER ||
44             keyEvent.code == KeyCode::KEY_DPAD_CENTER) {
45             if (pattern->GetKeyboard() != TextInputType::MULTILINE) {
46                 pattern->PerformAction(pattern->GetTextInputActionValue(TextInputAction::DONE), false);
47                 return true;
48             }
49         } else if (HandleShiftPressedEvent(keyEvent)) {
50             return true;
51         } else if (keyEvent.IsDirectionalKey() || keyEvent.code == KeyCode::KEY_MOVE_HOME ||
52                    keyEvent.code == KeyCode::KEY_MOVE_END) {
53             HandleDirectionalKey(keyEvent);
54             return true;
55         } else if (keyEvent.IsNumberKey() && !keyEvent.IsCombinationKey()) {
56             appendElement = keyEvent.ConvertCodeToString();
57         } else if (keyEvent.code == KeyCode::KEY_INSERT) {
58             if (keyEvent.IsShiftWith(KeyCode::KEY_INSERT)) {
59                 pattern->HandleOnPaste();
60             } else if (keyEvent.IsCtrlWith(KeyCode::KEY_INSERT)) {
61                 pattern->HandleOnCopy();
62             }
63         } else if (keyEvent.IsLetterKey()) {
64             if (keyEvent.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_Z }) ||
65                 keyEvent.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_Z }) ||
66                 keyEvent.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_Z }) ||
67                 keyEvent.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_Z }) ||
68                 keyEvent.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_Y }) ||
69                 keyEvent.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_Y })) {
70                 pattern->HandleOnRedoAction();
71             } else if (keyEvent.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_Z }) ||
72                        keyEvent.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_Z })) {
73                 pattern->HandleOnUndoAction();
74             } else if (keyEvent.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_A }) ||
75                        keyEvent.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_A })) {
76                 pattern->HandleOnSelectAll(true);
77             } else if (keyEvent.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_C }) ||
78                        keyEvent.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_C })) {
79                 pattern->HandleOnCopy();
80             } else if (keyEvent.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_V }) ||
81                        keyEvent.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_V })) {
82                 pattern->HandleOnPaste();
83             } else if (keyEvent.IsKey({ KEY_META_OR_CTRL_LEFT, KeyCode::KEY_X }) ||
84                        keyEvent.IsKey({ KEY_META_OR_CTRL_RIGHT, KeyCode::KEY_X })) {
85                 pattern->HandleOnCut();
86             } else if (!keyEvent.IsCombinationKey()) {
87                 appendElement = keyEvent.ConvertCodeToString();
88             }
89         }
90         if (keyEvent.code == KeyCode::KEY_DEL) {
91 #if defined(PREVIEW)
92             pattern->DeleteForward(TextFieldPattern::GetGraphemeClusterLength(
93                 pattern->GetEditingValue().GetWideText(), pattern->GetEditingValue().caretPosition));
94 #else
95             pattern->DeleteBackward(TextFieldPattern::GetGraphemeClusterLength(
96                 pattern->GetEditingValue().GetWideText(), pattern->GetEditingValue().caretPosition, true));
97 #endif
98             return true;
99         }
100         if (keyEvent.code == KeyCode::KEY_FORWARD_DEL) {
101 #if defined(PREVIEW)
102             pattern->DeleteBackward(TextFieldPattern::GetGraphemeClusterLength(
103                 pattern->GetEditingValue().GetWideText(), pattern->GetEditingValue().caretPosition, true));
104 #else
105             pattern->DeleteForward(TextFieldPattern::GetGraphemeClusterLength(
106                 pattern->GetEditingValue().GetWideText(), pattern->GetEditingValue().caretPosition));
107 #endif
108             return true;
109         }
110         ParseAppendValue(keyEvent.code, appendElement);
111         if (!appendElement.empty()) {
112             pattern->InsertValue(appendElement);
113             return true;
114         }
115     }
116     return false;
117 }
118 
ParseAppendValue(KeyCode keycode,std::string & appendElement)119 void KeyEventHandler::ParseAppendValue(KeyCode keycode, std::string& appendElement)
120 {
121     switch (keycode) {
122         case KeyCode::KEY_SPACE:
123             appendElement = " ";
124             break;
125         default:
126             break;
127     }
128 }
129 
IsCtrlShiftWith(const KeyEvent & keyEvent,const KeyCode expectCode)130 bool KeyEventHandler::IsCtrlShiftWith(const KeyEvent& keyEvent, const KeyCode expectCode)
131 {
132     return (keyEvent.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_SHIFT_LEFT, expectCode }) ||
133             keyEvent.IsKey({ KeyCode::KEY_CTRL_LEFT, KeyCode::KEY_SHIFT_RIGHT, expectCode }) ||
134             keyEvent.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_SHIFT_LEFT, expectCode }) ||
135             keyEvent.IsKey({ KeyCode::KEY_CTRL_RIGHT, KeyCode::KEY_SHIFT_RIGHT, expectCode }) ||
136             keyEvent.IsKey({ KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_CTRL_LEFT, expectCode }) ||
137             keyEvent.IsKey({ KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_CTRL_RIGHT, expectCode }) ||
138             keyEvent.IsKey({ KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_CTRL_LEFT, expectCode }) ||
139             keyEvent.IsKey({ KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_CTRL_RIGHT, expectCode }));
140 }
141 
HandleDirectionalMoveKey(const KeyEvent & keyEvent)142 bool KeyEventHandler::HandleDirectionalMoveKey(const KeyEvent& keyEvent)
143 {
144     auto pattern = DynamicCast<TextFieldPattern>(weakPattern_.Upgrade());
145     CHECK_NULL_RETURN(pattern, false);
146     bool quickDirectionalKey = false;
147     if (keyEvent.IsCtrlWith(KeyCode::KEY_DPAD_LEFT)) {
148         quickDirectionalKey = pattern->CursorMoveLeftWord();
149     } else if (keyEvent.IsCtrlWith(KeyCode::KEY_DPAD_UP)) { // caret move to paragraph head
150         quickDirectionalKey = pattern->CursorMoveToParagraphBegin();
151     } else if (keyEvent.IsCtrlWith(KeyCode::KEY_MOVE_HOME)) {
152         quickDirectionalKey = pattern->CursorMoveHome();
153     } else if (keyEvent.IsCtrlWith(KeyCode::KEY_DPAD_RIGHT)) {
154         quickDirectionalKey = pattern->CursorMoveRightWord();
155     } else if (keyEvent.IsCtrlWith(KeyCode::KEY_DPAD_DOWN)) { // caret move to paragraph tail
156         quickDirectionalKey = pattern->CursorMoveToParagraphEnd();
157     } else if (keyEvent.IsCtrlWith(KeyCode::KEY_MOVE_END)) {
158         quickDirectionalKey = pattern->CursorMoveEnd();
159     }
160     if (quickDirectionalKey) {
161         return true;
162     }
163     bool handleDirectionalKey = false;
164     switch (keyEvent.code) {
165         case KeyCode::KEY_DPAD_UP:
166             handleDirectionalKey = pattern->CursorMoveUp();
167             break;
168         case KeyCode::KEY_DPAD_DOWN:
169             handleDirectionalKey = pattern->CursorMoveDown();
170             break;
171         case KeyCode::KEY_DPAD_LEFT:
172             handleDirectionalKey = pattern->CursorMoveLeft();
173             break;
174         case KeyCode::KEY_MOVE_HOME:
175             handleDirectionalKey = pattern->CursorMoveLineBegin();
176             break;
177         case KeyCode::KEY_DPAD_RIGHT:
178             handleDirectionalKey = pattern->CursorMoveRight();
179             break;
180         case KeyCode::KEY_MOVE_END:
181             handleDirectionalKey = pattern->CursorMoveLineEnd();
182             break;
183         default:
184             LOGW("Unknown direction");
185     }
186     return handleDirectionalKey;
187 }
188 
HandleDirectionalKey(const KeyEvent & keyEvent)189 bool KeyEventHandler::HandleDirectionalKey(const KeyEvent& keyEvent)
190 {
191     auto pattern = DynamicCast<TextFieldPattern>(weakPattern_.Upgrade());
192     CHECK_NULL_RETURN(pattern, false);
193     pattern->ResetTouchAtLeftOffsetFlag();
194     bool updateSelection = false;
195     if (keyEvent.IsShiftWith(KeyCode::KEY_DPAD_UP)) {
196         pattern->HandleSelectionUp();
197         updateSelection = true;
198     } else if (keyEvent.IsShiftWith(KeyCode::KEY_DPAD_DOWN)) {
199         pattern->HandleSelectionDown();
200         updateSelection = true;
201     } else if (keyEvent.IsShiftWith(KeyCode::KEY_DPAD_LEFT)) {
202         pattern->HandleSelectionLeft();
203         updateSelection = true;
204     } else if (IsCtrlShiftWith(keyEvent, KeyCode::KEY_DPAD_LEFT)) {
205         pattern->HandleSelectionLeftWord();
206         updateSelection = true;
207     } else if (keyEvent.IsShiftWith(KeyCode::KEY_MOVE_HOME)) {
208         pattern->HandleSelectionLineBegin();
209         updateSelection = true;
210     } else if (IsCtrlShiftWith(keyEvent, KeyCode::KEY_MOVE_HOME)) {
211         pattern->HandleSelectionHome();
212         updateSelection = true;
213     } else if (keyEvent.IsShiftWith(KeyCode::KEY_DPAD_RIGHT)) {
214         pattern->HandleSelectionRight();
215         updateSelection = true;
216     } else if (IsCtrlShiftWith(keyEvent, KeyCode::KEY_DPAD_RIGHT)) {
217         pattern->HandleSelectionRightWord();
218         updateSelection = true;
219     } else if (keyEvent.IsShiftWith(KeyCode::KEY_MOVE_END)) {
220         pattern->HandleSelectionLineEnd();
221         updateSelection = true;
222     } else if (IsCtrlShiftWith(keyEvent, KeyCode::KEY_MOVE_END)) {
223         pattern->HandleSelectionEnd();
224         updateSelection = true;
225     }
226     if (updateSelection) {
227         return updateSelection;
228     }
229     updateSelection = HandleDirectionalMoveKey(keyEvent);
230     return updateSelection;
231 }
232 
HandleShiftPressedEvent(const KeyEvent & event)233 bool KeyEventHandler::HandleShiftPressedEvent(const KeyEvent& event)
234 {
235     auto pattern = DynamicCast<TextFieldPattern>(weakPattern_.Upgrade());
236     CHECK_NULL_RETURN(pattern, false);
237     const static size_t maxKeySizes = 2;
238     wchar_t keyChar;
239 
240     auto iterCode = KEYBOARD_SYMBOLS.find(event.code);
241     if (event.pressedCodes.size() == 1 && iterCode != KEYBOARD_SYMBOLS.end()) {
242         if (iterCode != KEYBOARD_SYMBOLS.end()) {
243             keyChar = iterCode->second;
244         } else {
245             return false;
246         }
247     } else if (event.pressedCodes.size() == maxKeySizes && (event.pressedCodes[0] == KeyCode::KEY_SHIFT_LEFT ||
248                                                                event.pressedCodes[0] == KeyCode::KEY_SHIFT_RIGHT)) {
249         iterCode = SHIFT_KEYBOARD_SYMBOLS.find(event.code);
250         if (iterCode != SHIFT_KEYBOARD_SYMBOLS.end()) {
251             keyChar = iterCode->second;
252         } else if (KeyCode::KEY_A <= event.code && event.code <= KeyCode::KEY_Z) {
253             keyChar = static_cast<wchar_t>(event.code) - static_cast<wchar_t>(KeyCode::KEY_A) + UPPER_CASE_A;
254         } else if (KeyCode::KEY_0 <= event.code && event.code <= KeyCode::KEY_9) {
255             keyChar = NUM_SYMBOLS[static_cast<int32_t>(event.code) - static_cast<int32_t>(KeyCode::KEY_0)];
256         } else {
257             return false;
258         }
259     } else {
260         return false;
261     }
262     std::wstring appendElement(1, keyChar);
263     pattern->InsertValue(StringUtils::ToString(appendElement));
264     return true;
265 }
266 
267 } // namespace OHOS::Ace::NG
268