• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 "adapter/preview/entrance/event_dispatcher.h"
17 
18 #include <map>
19 
20 #include "base/log/log.h"
21 #include "base/log/ace_trace.h"
22 #include "core/common/container_scope.h"
23 #include "adapter/preview/entrance/ace_container.h"
24 #include "adapter/preview/entrance/editing/text_input_client_mgr.h"
25 #include "adapter/preview/entrance/flutter_ace_view.h"
26 
27 namespace OHOS::Ace::Platform {
28 namespace {
29 
30 const wchar_t UPPER_CASE_A = L'A';
31 const wchar_t LOWER_CASE_A = L'a';
32 const wchar_t CASE_0 = L'0';
33 const std::wstring NUM_SYMBOLS = L")!@#$%^&*(";
34 const std::map<KeyCode, wchar_t> PRINTABEL_SYMBOLS = {
35     {KeyCode::KEY_GRAVE, L'`'},
36     {KeyCode::KEY_MINUS, L'-'},
37     {KeyCode::KEY_EQUALS, L'='},
38     {KeyCode::KEY_LEFT_BRACKET, L'['},
39     {KeyCode::KEY_RIGHT_BRACKET, L']'},
40     {KeyCode::KEY_BACKSLASH, L'\\'},
41     {KeyCode::KEY_SEMICOLON, L';'},
42     {KeyCode::KEY_APOSTROPHE, L'\''},
43     {KeyCode::KEY_COMMA, L','},
44     {KeyCode::KEY_PERIOD, L'.'},
45     {KeyCode::KEY_SLASH, L'/'},
46     {KeyCode::KEY_SPACE, L' '},
47     {KeyCode::KEY_NUMPAD_DIVIDE, L'/'},
48     {KeyCode::KEY_NUMPAD_MULTIPLY, L'*'},
49     {KeyCode::KEY_NUMPAD_SUBTRACT, L'-'},
50     {KeyCode::KEY_NUMPAD_ADD, L'+'},
51     {KeyCode::KEY_NUMPAD_DOT, L'.'},
52     {KeyCode::KEY_NUMPAD_COMMA, L','},
53     {KeyCode::KEY_NUMPAD_EQUALS, L'='},
54 };
55 
56 const std::map<KeyCode, wchar_t> SHIFT_PRINTABEL_SYMBOLS = {
57     {KeyCode::KEY_GRAVE, L'~'},
58     {KeyCode::KEY_MINUS, L'_'},
59     {KeyCode::KEY_EQUALS, L'+'},
60     {KeyCode::KEY_LEFT_BRACKET, L'{'},
61     {KeyCode::KEY_RIGHT_BRACKET, L'}'},
62     {KeyCode::KEY_BACKSLASH, L'|'},
63     {KeyCode::KEY_SEMICOLON, L':'},
64     {KeyCode::KEY_APOSTROPHE, L'\"'},
65     {KeyCode::KEY_COMMA, L'<'},
66     {KeyCode::KEY_PERIOD, L'>'},
67     {KeyCode::KEY_SLASH, L'?'},
68 };
69 
70 }
71 
EventDispatcher()72 EventDispatcher::EventDispatcher()
73 {}
74 
75 EventDispatcher::~EventDispatcher() = default;
76 
SetGlfwWindowController(const FlutterDesktopWindowControllerRef & controller)77 void EventDispatcher::SetGlfwWindowController(const FlutterDesktopWindowControllerRef& controller)
78 {
79     controller_ = controller;
80 }
81 
Initialize()82 void EventDispatcher::Initialize()
83 {
84     LOGI("Initialize event dispatcher");
85     // Initial the proxy of Input method
86     TextInputClientMgr::GetInstance().InitTextInputProxy();
87     // Register the idle event callback function.
88 #ifndef ENABLE_ROSEN_BACKEND
89     IdleCallback idleNoticeCallback = [] (int64_t deadline) {
90         EventDispatcher::GetInstance().DispatchIdleEvent(deadline);
91     };
92     FlutterDesktopSetIdleCallback(controller_, idleNoticeCallback);
93 #else
94     // rosen process idle
95 #endif
96 }
97 
DispatchIdleEvent(int64_t deadline)98 void EventDispatcher::DispatchIdleEvent(int64_t deadline)
99 {
100     ACE_SCOPED_TRACE("DispatchIdleEvent");
101     auto container = AceContainer::GetContainerInstance(ACE_INSTANCE_ID);
102     if (!container) {
103         LOGE("container is null");
104         return;
105     }
106 
107     auto aceView = container->GetAceView();
108     if (!aceView) {
109         LOGE("aceView is null");
110         return;
111     }
112 
113     aceView->ProcessIdleEvent(deadline);
114 }
115 
DispatchTouchEvent(const TouchEvent & event)116 bool EventDispatcher::DispatchTouchEvent(const TouchEvent& event)
117 {
118     ACE_SCOPED_TRACE("DispatchTouchEvent");
119     LOGI("Dispatch touch event");
120     auto container = AceContainer::GetContainerInstance(ACE_INSTANCE_ID);
121     if (!container) {
122         LOGE("container is null");
123         return false;
124     }
125 
126     auto aceView = container->GetAceView();
127     if (!aceView) {
128         LOGE("aceView is null");
129         return false;
130     }
131 
132     return aceView->HandleTouchEvent(event);
133 }
134 
DispatchBackPressedEvent()135 bool EventDispatcher::DispatchBackPressedEvent()
136 {
137     ACE_SCOPED_TRACE("DispatchBackPressedEvent");
138     LOGI("Dispatch back pressed event");
139     auto container = AceContainer::GetContainerInstance(ACE_INSTANCE_ID);
140     if (!container) {
141         return false;
142     }
143 
144     auto context = container->GetPipelineContext();
145     if (!context) {
146         return false;
147     }
148 
149     std::promise<bool> backPromise;
150     std::future<bool> backFuture = backPromise.get_future();
151     auto weak = AceType::WeakClaim(AceType::RawPtr(context));
152     container->GetTaskExecutor()->PostTask(
153         [weak, &backPromise]() {
154             auto context = weak.Upgrade();
155             if (context == nullptr) {
156                 LOGW("context is nullptr.");
157                 return;
158             }
159             bool canBack = false;
160             if (context->IsLastPage()) {
161                 LOGW("Can't back because this is the last page!");
162             } else {
163                 canBack = context->CallRouterBackToPopPage();
164             }
165             backPromise.set_value(canBack);
166         },
167         TaskExecutor::TaskType::PLATFORM);
168     return backFuture.get();
169 }
170 
DispatchInputMethodEvent(unsigned int code_point)171 bool EventDispatcher::DispatchInputMethodEvent(unsigned int code_point)
172 {
173     ACE_SCOPED_TRACE("DispatchInputMethodEvent");
174     LOGI("Dispatch input method event");
175     return TextInputClientMgr::GetInstance().AddCharacter(static_cast<wchar_t>(code_point));
176 }
177 
DispatchKeyEvent(const KeyEvent & event)178 bool EventDispatcher::DispatchKeyEvent(const KeyEvent& event)
179 {
180     ACE_SCOPED_TRACE("DispatchKeyEvent");
181     LOGI("Dispatch key event");
182     if (HandleTextKeyEvent(event)) {
183         LOGI("The event is related to the input component and has been handled successfully.");
184         return true;
185     }
186     auto container = AceContainer::GetContainerInstance(ACE_INSTANCE_ID);
187     if (!container) {
188         LOGE("container is null");
189         return false;
190     }
191 
192     auto aceView = container->GetAceView();
193     if (!aceView) {
194         LOGE("aceView is null");
195         return false;
196     }
197 #ifdef USE_GLFW_WINDOW
198     container->GetTaskExecutor()->PostTask(
199         [aceView, event]() {
200             aceView->HandleKeyEvent(event);
201         },
202         TaskExecutor::TaskType::UI);
203     return true;
204 #else
205     return aceView->HandleKeyEvent(event);
206 #endif
207 }
208 
RegisterCallbackGetCapsLockStatus(CallbackGetKeyboardStatus callback)209 void EventDispatcher::RegisterCallbackGetCapsLockStatus(CallbackGetKeyboardStatus callback)
210 {
211     if (callback) {
212         callbackGetCapsLockStatus_ = callback;
213     }
214 }
215 
RegisterCallbackGetNumLockStatus(CallbackGetKeyboardStatus callback)216 void EventDispatcher::RegisterCallbackGetNumLockStatus(CallbackGetKeyboardStatus callback)
217 {
218     if (callback) {
219         callbackGetNumLockStatus_ = callback;
220     }
221 }
222 
HandleTextKeyEvent(const KeyEvent & event)223 bool EventDispatcher::HandleTextKeyEvent(const KeyEvent& event)
224 {
225     // Only the keys involved in the input component are processed here, and the other keys will be forwarded.
226     if (!TextInputClientMgr::GetInstance().IsValidClientId()) {
227         return false;
228     }
229 
230     bool enableCapsLock = callbackGetCapsLockStatus_ && callbackGetCapsLockStatus_();
231     bool enableNumLock = callbackGetNumLockStatus_ && callbackGetNumLockStatus_();
232     const static size_t maxKeySizes = 2;
233     wchar_t keyChar;
234     if (event.pressedCodes.size() == 1) {
235         auto iterCode = PRINTABEL_SYMBOLS.find(event.code);
236         if (iterCode != PRINTABEL_SYMBOLS.end()) {
237             keyChar = iterCode->second;
238         } else if (KeyCode::KEY_0 <= event.code && event.code <= KeyCode::KEY_9) {
239             keyChar = static_cast<wchar_t>(event.code) - static_cast<wchar_t>(KeyCode::KEY_0) + CASE_0;
240         } else if (KeyCode::KEY_NUMPAD_0 <= event.code && event.code <= KeyCode::KEY_NUMPAD_9) {
241             if (!enableNumLock) {
242                 return true;
243             }
244             keyChar = static_cast<wchar_t>(event.code) - static_cast<wchar_t>(KeyCode::KEY_NUMPAD_0) + CASE_0;
245         } else if (KeyCode::KEY_A <= event.code && event.code <= KeyCode::KEY_Z) {
246             keyChar = static_cast<wchar_t>(event.code) - static_cast<wchar_t>(KeyCode::KEY_A);
247             keyChar += (enableCapsLock ? UPPER_CASE_A : LOWER_CASE_A);
248         } else {
249             return false;
250         }
251     } else if (event.pressedCodes.size() == maxKeySizes && event.pressedCodes[0] == KeyCode::KEY_SHIFT_LEFT) {
252         auto iterCode = SHIFT_PRINTABEL_SYMBOLS.find(event.code);
253         if (iterCode != SHIFT_PRINTABEL_SYMBOLS.end()) {
254             keyChar = iterCode->second;
255         } else if (KeyCode::KEY_A <= event.code && event.code <= KeyCode::KEY_Z) {
256             keyChar = static_cast<wchar_t>(event.code) - static_cast<wchar_t>(KeyCode::KEY_A);
257             keyChar += (enableCapsLock ? LOWER_CASE_A : UPPER_CASE_A);
258         } else if (KeyCode::KEY_0 <= event.code && event.code <= KeyCode::KEY_9) {
259             keyChar = NUM_SYMBOLS[static_cast<int32_t>(event.code) - static_cast<int32_t>(KeyCode::KEY_0)];
260         } else {
261             return false;
262         }
263     } else {
264         return false;
265     }
266 #ifdef USE_GLFW_WINDOW
267     return true;
268 #else
269     if (event.action != KeyAction::DOWN) {
270         return true;
271     }
272     return TextInputClientMgr::GetInstance().AddCharacter(keyChar);
273 #endif
274 }
275 
276 } // namespace OHOS::Ace::Platform
277