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