1 /*
2 * Copyright (c) 2021-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 "key_event_subscriber.h"
17 #include "define_multimodal.h"
18 #include "error_multimodal.h"
19 #include "input_event_data_transformation.h"
20 #include "net_packet.h"
21 #include "proto.h"
22 #include "input_event_handler.h"
23 #include "timer_manager.h"
24
25 namespace OHOS {
26 namespace MMI {
27 namespace {
28 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, MMI_LOG_DOMAIN, "KeyEventSubscriber"};
29 constexpr uint32_t MAX_PRE_KEY_COUNT = 4;
30 }
31
SubscribeKeyEvent(SessionPtr sess,int32_t subscribeId,std::shared_ptr<OHOS::MMI::KeyOption> keyOption)32 int32_t KeyEventSubscriber::SubscribeKeyEvent(
33 SessionPtr sess, int32_t subscribeId, std::shared_ptr<OHOS::MMI::KeyOption> keyOption)
34 {
35 MMI_LOGD("Enter");
36 CHKR(subscribeId >= 0, PARAM_INPUT_INVALID, RET_ERR);
37 CHKPR(sess, ERROR_NULL_POINTER);
38 CHKPR(keyOption, ERROR_NULL_POINTER);
39 uint32_t preKeySize = keyOption->GetPreKeys().size();
40 if (preKeySize > MAX_PRE_KEY_COUNT) {
41 MMI_LOGE("Leave, preKeySize:%{public}u", preKeySize);
42 return RET_ERR;
43 }
44
45 for (const auto &keyCode : keyOption->GetPreKeys()) {
46 MMI_LOGD("keyOption->prekey:%{public}d", keyCode);
47 }
48 MMI_LOGD("subscribeId:%{public}d,keyOption->finalKey:%{public}d,"
49 "keyOption->isFinalKeyDown:%{public}s,keyOption->finalKeyDownDuriation:%{public}d",
50 subscribeId, keyOption->GetFinalKey(), keyOption->IsFinalKeyDown() ? "true" : "false",
51 keyOption->GetFinalKeyDownDuration());
52 auto subscriber = std::make_shared<Subscriber>(subscribeId, sess, keyOption);
53 subscribers_.push_back(subscriber);
54 InitSessionDeleteCallback();
55 MMI_LOGD("Leave");
56 return RET_OK;
57 }
58
UnSubscribeKeyEvent(SessionPtr sess,int32_t subscribeId)59 int32_t KeyEventSubscriber::UnSubscribeKeyEvent(SessionPtr sess, int32_t subscribeId)
60 {
61 MMI_LOGD("enter, subscribeId:%{public}d", subscribeId);
62 for (auto it = subscribers_.begin(); it != subscribers_.end(); ++it) {
63 if ((*it)->id_ == subscribeId && (*it)->sess_ == sess) {
64 ClearTimer(*it);
65 subscribers_.erase(it);
66 MMI_LOGD("leave");
67 return RET_OK;
68 }
69 }
70
71 MMI_LOGD("Leave");
72 return RET_ERR;
73 }
74
SubscribeKeyEvent(std::shared_ptr<KeyEvent> keyEvent)75 bool KeyEventSubscriber::SubscribeKeyEvent(std::shared_ptr<KeyEvent> keyEvent)
76 {
77 MMI_LOGD("Enter");
78 CHKPF(keyEvent);
79 int32_t keyAction = keyEvent->GetKeyAction();
80 MMI_LOGD("keyCode:%{public}d,keyAction:%{public}s", keyEvent->GetKeyCode(), KeyEvent::ActionToString(keyAction));
81 for (const auto &keyCode : keyEvent->GetPressedKeys()) {
82 MMI_LOGD("pressed KeyCode:%{public}d", keyCode);
83 }
84 bool handled = false;
85 if (keyAction == KeyEvent::KEY_ACTION_DOWN) {
86 handled = HandleKeyDown(keyEvent);
87 } else if (keyAction == KeyEvent::KEY_ACTION_UP) {
88 handled = HandleKeyUp(keyEvent);
89 } else if (keyAction == KeyEvent::KEY_ACTION_CANCEL) {
90 handled = HandleKeyCanel(keyEvent);
91 } else {
92 MMI_LOGW("keyAction exception");
93 }
94 keyEvent_.reset();
95
96 MMI_LOGD("Leave");
97 return handled;
98 }
99
OnSessionDelete(SessionPtr sess)100 void KeyEventSubscriber::OnSessionDelete(SessionPtr sess)
101 {
102 MMI_LOGD("Enter");
103 for (auto it = subscribers_.begin(); it != subscribers_.end();) {
104 if ((*it)->sess_ == sess) {
105 ClearTimer(*it);
106 subscribers_.erase(it++);
107 continue;
108 }
109 ++it;
110 }
111
112 MMI_LOGD("Leave");
113 }
114
IsPreKeysMatch(const std::set<int32_t> & preKeys,const std::vector<int32_t> & pressedKeys) const115 bool KeyEventSubscriber::IsPreKeysMatch(const std::set<int32_t>& preKeys,
116 const std::vector<int32_t>& pressedKeys) const
117 {
118 if (preKeys.size() != pressedKeys.size()) {
119 return false;
120 }
121
122 for (const auto &pressedKey : pressedKeys) {
123 auto it = std::find(preKeys.begin(), preKeys.end(), pressedKey);
124 if (it == preKeys.end()) {
125 return false;
126 }
127 }
128
129 return true;
130 }
131
NotifySubscriber(std::shared_ptr<OHOS::MMI::KeyEvent> keyEvent,const std::shared_ptr<Subscriber> & subscriber)132 void KeyEventSubscriber::NotifySubscriber(std::shared_ptr<OHOS::MMI::KeyEvent> keyEvent,
133 const std::shared_ptr<Subscriber>& subscriber)
134 {
135 MMI_LOGD("Enter");
136 CHKPV(keyEvent);
137 CHKPV(subscriber);
138 auto udsServerPtr = InputHandler->GetUDSServer();
139 CHKPV(udsServerPtr);
140 OHOS::MMI::NetPacket pkt(MmiMessageId::ON_SUBSCRIBE_KEY);
141 InputEventDataTransformation::KeyEventToNetPacket(keyEvent, pkt);
142 int32_t fd = subscriber->sess_->GetFd();
143 pkt << fd << subscriber->id_;
144 if (!udsServerPtr->SendMsg(fd, pkt)) {
145 MMI_LOGE("Leave, server disaptch subscriber failed");
146 return;
147 }
148 MMI_LOGD("Leave");
149 }
150
AddTimer(const std::shared_ptr<Subscriber> & subscriber,const std::shared_ptr<KeyEvent> & keyEvent)151 bool KeyEventSubscriber::AddTimer(const std::shared_ptr<Subscriber>& subscriber,
152 const std::shared_ptr<KeyEvent>& keyEvent)
153 {
154 MMI_LOGD("Enter");
155 CHKPF(keyEvent);
156 CHKPF(subscriber);
157
158 if (subscriber->timerId_ >= 0) {
159 MMI_LOGW("Leave, timer already added, it may have been added by injection");
160 return true;
161 }
162
163 auto& keyOption = subscriber->keyOption_;
164 if (keyOption->GetFinalKeyDownDuration() <= 0) {
165 MMI_LOGE("Leave, duration <= 0");
166 return true;
167 }
168
169 if (!CloneKeyEvent(keyEvent)) {
170 MMI_LOGE("Leave, cloneKeyEvent failed");
171 return false;
172 }
173
174 std::weak_ptr<Subscriber> weakSubscriber = subscriber;
175 subscriber->timerId_ = TimerMgr->AddTimer(keyOption->GetFinalKeyDownDuration(), 1, [this, weakSubscriber] () {
176 MMI_LOGD("timer callback");
177 auto subscriber = weakSubscriber.lock();
178 CHKPV(subscriber);
179 OnTimer(subscriber);
180 });
181
182 if (subscriber->timerId_ < 0) {
183 MMI_LOGE("Leave, addTimer failed");
184 return false;
185 }
186 subscriber->keyEvent_ = keyEvent_;
187 MMI_LOGD("leave, add timer success, subscribeId:%{public}d,"
188 "duration:%{public}d,timerId:%{public}d",
189 subscriber->id_, keyOption->GetFinalKeyDownDuration(), subscriber->timerId_);
190 return true;
191 }
192
ClearTimer(const std::shared_ptr<Subscriber> & subscriber)193 void KeyEventSubscriber::ClearTimer(const std::shared_ptr<Subscriber>& subscriber)
194 {
195 MMI_LOGD("Enter");
196 CHKPV(subscriber);
197
198 if (subscriber->timerId_ < 0) {
199 MMI_LOGE("Leave, subscribeId:%{public}d,null timerId < 0", subscriber->id_);
200 return;
201 }
202
203 auto timerId = subscriber->timerId_;
204 subscriber->keyEvent_.reset();
205 subscriber->timerId_ = -1;
206 TimerMgr->RemoveTimer(timerId);
207 MMI_LOGD("leave, subscribeId:%{public}d,subscribeId:%{public}d", subscriber->id_, timerId);
208 }
209
OnTimer(const std::shared_ptr<Subscriber> subscriber)210 void KeyEventSubscriber::OnTimer(const std::shared_ptr<Subscriber> subscriber)
211 {
212 MMI_LOGD("Enter");
213 CHKPV(subscriber);
214 subscriber->timerId_ = -1;
215 if (subscriber->keyEvent_ == nullptr) {
216 MMI_LOGE("Leave, subscriber->keyEvent is nullptr, subscribeId:%{public}d", subscriber->id_);
217 return;
218 }
219
220 NotifySubscriber(subscriber->keyEvent_, subscriber);
221 subscriber->keyEvent_.reset();
222 MMI_LOGD("leave, subscribeId:%{public}d", subscriber->id_);
223 }
224
InitSessionDeleteCallback()225 bool KeyEventSubscriber::InitSessionDeleteCallback()
226 {
227 MMI_LOGD("Enter");
228 if (callbackInitialized_) {
229 MMI_LOGD("session delete callback has already been initialized");
230 return true;
231 }
232 auto udsServerPtr = InputHandler->GetUDSServer();
233 CHKPF(udsServerPtr);
234 std::function<void(SessionPtr)> callback = std::bind(&KeyEventSubscriber::OnSessionDelete,
235 this, std::placeholders::_1);
236 udsServerPtr->AddSessionDeletedCallback(callback);
237
238 callbackInitialized_ = true;
239 MMI_LOGD("Leave");
240 return true;
241 }
242
HandleKeyDown(const std::shared_ptr<KeyEvent> & keyEvent)243 bool KeyEventSubscriber::HandleKeyDown(const std::shared_ptr<KeyEvent>& keyEvent)
244 {
245 MMI_LOGD("Enter");
246 CHKPF(keyEvent);
247 bool handled = false;
248 auto keyCode = keyEvent->GetKeyCode();
249 std::vector<int32_t> pressedKeys = keyEvent->GetPressedKeys();
250 RemoveKeyCode(keyCode, pressedKeys);
251 for (const auto &subscriber : subscribers_) {
252 auto& keyOption = subscriber->keyOption_;
253 MMI_LOGD("subscribeId:%{public}d,keyOption->finalKey:%{public}d,"
254 "keyOption->isFinalKeyDown:%{public}s,keyOption->finalKeyDownDuriation:%{public}d",
255 subscriber->id_, keyOption->GetFinalKey(), keyOption->IsFinalKeyDown() ? "true" : "false",
256 keyOption->GetFinalKeyDownDuration());
257 for (const auto &keyCode : keyOption->GetPreKeys()) {
258 MMI_LOGD("keyOption->prekey:%{public}d", keyCode);
259 }
260
261 if (!keyOption->IsFinalKeyDown()) {
262 MMI_LOGD("!keyOption->IsFinalKeyDown()");
263 continue;
264 }
265
266 if (keyCode != keyOption->GetFinalKey()) {
267 ClearTimer(subscriber);
268 MMI_LOGD("keyCode != keyOption->GetFinalKey()");
269 continue;
270 }
271
272 if (!IsPreKeysMatch(keyOption->GetPreKeys(), pressedKeys)) {
273 ClearTimer(subscriber);
274 MMI_LOGD("preKeysMatch failed");
275 continue;
276 }
277
278 if (keyOption->GetFinalKeyDownDuration() <= 0) {
279 MMI_LOGD("keyOption->GetFinalKeyDownDuration() <= 0");
280 NotifySubscriber(keyEvent, subscriber);
281 handled = true;
282 continue;
283 }
284
285 if (!AddTimer(subscriber, keyEvent)) {
286 MMI_LOGE("Leave, add timer failed");
287 }
288 }
289
290 MMI_LOGD("leave %{public}s", handled ? "true" : "false");
291 return handled;
292 }
293
HandleKeyUp(const std::shared_ptr<KeyEvent> & keyEvent)294 bool KeyEventSubscriber::HandleKeyUp(const std::shared_ptr<KeyEvent>& keyEvent)
295 {
296 MMI_LOGD("Enter");
297 CHKPF(keyEvent);
298 bool handled = false;
299 auto keyCode = keyEvent->GetKeyCode();
300 std::vector<int32_t> pressedKeys = keyEvent->GetPressedKeys();
301 RemoveKeyCode(keyCode, pressedKeys);
302 for (const auto &subscriber : subscribers_) {
303 auto& keyOption = subscriber->keyOption_;
304 MMI_LOGD("subscribeId:%{public}d,keyOption->finalKey:%{public}d,"
305 "keyOption->isFinalKeyDown:%{public}s,keyOption->finalKeyDownDuriation:%{public}d",
306 subscriber->id_, keyOption->GetFinalKey(), keyOption->IsFinalKeyDown() ? "true" : "false",
307 keyOption->GetFinalKeyDownDuration());
308 for (auto keyCode : keyOption->GetPreKeys()) {
309 MMI_LOGD("keyOption->prekey:%{public}d", keyCode);
310 }
311
312 if (keyOption->IsFinalKeyDown()) {
313 ClearTimer(subscriber);
314 MMI_LOGD("keyOption->IsFinalKeyDown()");
315 continue;
316 }
317
318 if (keyCode != keyOption->GetFinalKey()) {
319 MMI_LOGD("keyCode != keyOption->GetFinalKey()");
320 continue;
321 }
322
323 if (!IsPreKeysMatch(keyOption->GetPreKeys(), pressedKeys)) {
324 MMI_LOGD("preKeysMatch failed");
325 continue;
326 }
327
328 auto duration = keyOption->GetFinalKeyDownDuration();
329 if (duration <= 0) {
330 MMI_LOGD("duration <= 0");
331 NotifySubscriber(keyEvent, subscriber);
332 handled = true;
333 continue;
334 }
335
336 const KeyEvent::KeyItem* keyItem = keyEvent->GetKeyItem();
337 CHKPF(keyItem);
338 auto upTime = keyEvent->GetActionTime();
339 auto downTime = keyItem->GetDownTime();
340 if (upTime - downTime >= (static_cast<int64_t>(duration) * 1000)) {
341 MMI_LOGE("upTime - downTime >= duration");
342 continue;
343 }
344
345 MMI_LOGD("upTime - downTime < duration");
346 NotifySubscriber(keyEvent, subscriber);
347 handled = true;
348 }
349
350 MMI_LOGD("leave %{public}s", handled ? "true" : "false");
351 return handled;
352 }
353
HandleKeyCanel(const std::shared_ptr<KeyEvent> & keyEvent)354 bool KeyEventSubscriber::HandleKeyCanel(const std::shared_ptr<KeyEvent>& keyEvent)
355 {
356 MMI_LOGD("Enter");
357 CHKPF(keyEvent);
358 for (const auto &subscriber : subscribers_) {
359 ClearTimer(subscriber);
360 }
361 MMI_LOGD("Leave");
362 return false;
363 }
364
CloneKeyEvent(std::shared_ptr<KeyEvent> keyEvent)365 bool KeyEventSubscriber::CloneKeyEvent(std::shared_ptr<KeyEvent> keyEvent)
366 {
367 CHKPF(keyEvent);
368 if (keyEvent_ == nullptr) {
369 MMI_LOGW("keyEvent_ is nullptr");
370 keyEvent_ = KeyEvent::Clone(keyEvent);
371 }
372 CHKPF(keyEvent_);
373 return true;
374 }
375
RemoveKeyCode(int32_t keyCode,std::vector<int32_t> & keyCodes)376 void KeyEventSubscriber::RemoveKeyCode(int32_t keyCode, std::vector<int32_t>& keyCodes)
377 {
378 for (auto it = keyCodes.begin(); it != keyCodes.end(); ++it) {
379 if (*it == keyCode) {
380 keyCodes.erase(it);
381 return;
382 }
383 }
384 }
385
386 } // namespace MMI
387 } // namespace OHOS
388