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_subscriber_handler.h"
17
18 #include "bytrace_adapter.h"
19 #include "define_multimodal.h"
20 #include "error_multimodal.h"
21 #include "input_event_data_transformation.h"
22 #include "input_event_handler.h"
23 #include "net_packet.h"
24 #include "proto.h"
25 #include "timer_manager.h"
26 #include "util_ex.h"
27
28 namespace OHOS {
29 namespace MMI {
30 namespace {
31 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, MMI_LOG_DOMAIN, "KeySubscriberHandler"};
32 constexpr uint32_t MAX_PRE_KEY_COUNT = 4;
33 } // namespace
34
35 #ifdef OHOS_BUILD_ENABLE_KEYBOARD
HandleKeyEvent(const std::shared_ptr<KeyEvent> keyEvent)36 void KeySubscriberHandler::HandleKeyEvent(const std::shared_ptr<KeyEvent> keyEvent)
37 {
38 CHKPV(keyEvent);
39 if (OnSubscribeKeyEvent(keyEvent)) {
40 MMI_HILOGD("Subscribe keyEvent filter success. keyCode:%{public}d", keyEvent->GetKeyCode());
41 BytraceAdapter::StartBytrace(keyEvent, BytraceAdapter::KEY_SUBSCRIBE_EVENT);
42 return;
43 }
44 CHKPV(nextHandler_);
45 nextHandler_->HandleKeyEvent(keyEvent);
46 }
47 #endif // OHOS_BUILD_ENABLE_KEYBOARD
48
49 #ifdef OHOS_BUILD_ENABLE_POINTER
HandlePointerEvent(const std::shared_ptr<PointerEvent> pointerEvent)50 void KeySubscriberHandler::HandlePointerEvent(const std::shared_ptr<PointerEvent> pointerEvent)
51 {
52 CHKPV(pointerEvent);
53 CHKPV(nextHandler_);
54 nextHandler_->HandlePointerEvent(pointerEvent);
55 }
56 #endif // OHOS_BUILD_ENABLE_POINTER
57
58 #ifdef OHOS_BUILD_ENABLE_TOUCH
HandleTouchEvent(const std::shared_ptr<PointerEvent> pointerEvent)59 void KeySubscriberHandler::HandleTouchEvent(const std::shared_ptr<PointerEvent> pointerEvent)
60 {
61 CHKPV(pointerEvent);
62 CHKPV(nextHandler_);
63 nextHandler_->HandleTouchEvent(pointerEvent);
64 }
65 #endif // OHOS_BUILD_ENABLE_TOUCH
66
SubscribeKeyEvent(SessionPtr sess,int32_t subscribeId,std::shared_ptr<KeyOption> keyOption)67 int32_t KeySubscriberHandler::SubscribeKeyEvent(
68 SessionPtr sess, int32_t subscribeId, std::shared_ptr<KeyOption> keyOption)
69 {
70 CALL_INFO_TRACE;
71 if (subscribeId < 0) {
72 MMI_HILOGE("Invalid subscribe");
73 return RET_ERR;
74 }
75 CHKPR(sess, ERROR_NULL_POINTER);
76 CHKPR(keyOption, ERROR_NULL_POINTER);
77 uint32_t preKeySize = keyOption->GetPreKeys().size();
78 if (preKeySize > MAX_PRE_KEY_COUNT) {
79 MMI_HILOGE("Leave, preKeySize:%{public}u", preKeySize);
80 return RET_ERR;
81 }
82
83 for (const auto &keyCode : keyOption->GetPreKeys()) {
84 MMI_HILOGD("keyOption->prekey:%{public}d", keyCode);
85 }
86 MMI_HILOGD("subscribeId:%{public}d, keyOption->finalKey:%{public}d,"
87 "keyOption->isFinalKeyDown:%{public}s, keyOption->finalKeyDownDuration:%{public}d",
88 subscribeId, keyOption->GetFinalKey(), keyOption->IsFinalKeyDown() ? "true" : "false",
89 keyOption->GetFinalKeyDownDuration());
90 auto subscriber = std::make_shared<Subscriber>(subscribeId, sess, keyOption);
91 InsertSubScriber(subscriber);
92 InitSessionDeleteCallback();
93 return RET_OK;
94 }
95
UnsubscribeKeyEvent(SessionPtr sess,int32_t subscribeId)96 int32_t KeySubscriberHandler::UnsubscribeKeyEvent(SessionPtr sess, int32_t subscribeId)
97 {
98 CALL_INFO_TRACE;
99 MMI_HILOGD("subscribeId:%{public}d", subscribeId);
100 for (auto it = subscribers_.begin(); it != subscribers_.end(); ++it) {
101 if ((*it)->id_ == subscribeId && (*it)->sess_ == sess) {
102 ClearTimer(*it);
103 subscribers_.erase(it);
104 return RET_OK;
105 }
106 }
107 return RET_ERR;
108 }
109
OnSubscribeKeyEvent(std::shared_ptr<KeyEvent> keyEvent)110 bool KeySubscriberHandler::OnSubscribeKeyEvent(std::shared_ptr<KeyEvent> keyEvent)
111 {
112 CHKPF(keyEvent);
113 if (IsRepeatedKeyEvent(keyEvent)) {
114 MMI_HILOGD("Repeat KeyEvent, skip");
115 return true;
116 }
117 keyEvent_ = KeyEvent::Clone(keyEvent);
118 int32_t keyAction = keyEvent->GetKeyAction();
119 MMI_HILOGD("keyCode:%{public}d, keyAction:%{public}s", keyEvent->GetKeyCode(),
120 KeyEvent::ActionToString(keyAction));
121 for (const auto &keyCode : keyEvent->GetPressedKeys()) {
122 MMI_HILOGD("Pressed KeyCode:%{public}d", keyCode);
123 }
124 bool handled = false;
125 if (keyAction == KeyEvent::KEY_ACTION_DOWN) {
126 handled = HandleKeyDown(keyEvent);
127 } else if (keyAction == KeyEvent::KEY_ACTION_UP) {
128 hasEventExecuting_ = false;
129 handled = HandleKeyUp(keyEvent);
130 } else if (keyAction == KeyEvent::KEY_ACTION_CANCEL) {
131 hasEventExecuting_ = false;
132 handled = HandleKeyCancel(keyEvent);
133 } else {
134 MMI_HILOGW("keyAction exception");
135 }
136 return handled;
137 }
138
InsertSubScriber(std::shared_ptr<Subscriber> subs)139 void KeySubscriberHandler::InsertSubScriber(std::shared_ptr<Subscriber> subs)
140 {
141 CALL_DEBUG_ENTER;
142 CHKPV(subs);
143 for (auto it = subscribers_.begin(); it != subscribers_.end(); ++it) {
144 if (subs->sess_ != nullptr && (*it)->id_ == subs->id_ && (*it)->sess_ == subs->sess_) {
145 MMI_HILOGW("Repeat registration id:%{public}d desc:%{public}s",
146 subs->id_, subs->sess_->GetDescript().c_str());
147 return;
148 }
149 }
150 subscribers_.push_back(subs);
151 }
152
OnSessionDelete(SessionPtr sess)153 void KeySubscriberHandler::OnSessionDelete(SessionPtr sess)
154 {
155 CALL_DEBUG_ENTER;
156 CHKPV(sess);
157 for (auto it = subscribers_.begin(); it != subscribers_.end();) {
158 if ((*it)->sess_ == sess) {
159 ClearTimer(*it);
160 subscribers_.erase(it++);
161 continue;
162 }
163 ++it;
164 }
165 }
166
IsPreKeysMatch(const std::set<int32_t> & preKeys,const std::vector<int32_t> & pressedKeys) const167 bool KeySubscriberHandler::IsPreKeysMatch(const std::set<int32_t> &preKeys,
168 const std::vector<int32_t> &pressedKeys) const
169 {
170 if (preKeys.size() == 0) {
171 return true;
172 }
173
174 if (preKeys.size() != pressedKeys.size()) {
175 return false;
176 }
177
178 for (const auto &pressedKey : pressedKeys) {
179 auto it = std::find(preKeys.begin(), preKeys.end(), pressedKey);
180 if (it == preKeys.end()) {
181 return false;
182 }
183 }
184
185 return true;
186 }
187
NotifySubscriber(std::shared_ptr<KeyEvent> keyEvent,const std::shared_ptr<Subscriber> & subscriber)188 void KeySubscriberHandler::NotifySubscriber(std::shared_ptr<KeyEvent> keyEvent,
189 const std::shared_ptr<Subscriber> &subscriber)
190 {
191 CALL_DEBUG_ENTER;
192 CHKPV(keyEvent);
193 CHKPV(subscriber);
194 auto udsServerPtr = InputHandler->GetUDSServer();
195 CHKPV(udsServerPtr);
196 NetPacket pkt(MmiMessageId::ON_SUBSCRIBE_KEY);
197 InputEventDataTransformation::KeyEventToNetPacket(keyEvent, pkt);
198 int32_t fd = subscriber->sess_->GetFd();
199 pkt << fd << subscriber->id_;
200 if (pkt.ChkRWError()) {
201 MMI_HILOGE("Packet write dispatch subscriber failed");
202 return;
203 }
204 if (!udsServerPtr->SendMsg(fd, pkt)) {
205 MMI_HILOGE("Leave, server dispatch subscriber failed");
206 return;
207 }
208 }
209
AddTimer(const std::shared_ptr<Subscriber> & subscriber,const std::shared_ptr<KeyEvent> & keyEvent)210 bool KeySubscriberHandler::AddTimer(const std::shared_ptr<Subscriber> &subscriber,
211 const std::shared_ptr<KeyEvent> &keyEvent)
212 {
213 CALL_DEBUG_ENTER;
214 CHKPF(keyEvent);
215 CHKPF(subscriber);
216
217 if (subscriber->timerId_ >= 0) {
218 MMI_HILOGW("Leave, timer already added, it may have been added by injection");
219 return true;
220 }
221
222 auto &keyOption = subscriber->keyOption_;
223 bool isKeyDown = keyOption->IsFinalKeyDown();
224 int32_t duration = isKeyDown ? keyOption->GetFinalKeyDownDuration() : keyOption->GetFinalKeyUpDelay();
225 if (duration <= 0) {
226 MMI_HILOGE("Leave, duration <= 0");
227 return true;
228 }
229
230 if (!CloneKeyEvent(keyEvent)) {
231 MMI_HILOGE("Leave, cloneKeyEvent failed");
232 return false;
233 }
234
235 std::weak_ptr<Subscriber> weakSubscriber = subscriber;
236 subscriber->timerId_ = TimerMgr->AddTimer(duration, 1, [this, weakSubscriber] () {
237 MMI_HILOGD("Timer callback");
238 auto subscriber = weakSubscriber.lock();
239 CHKPV(subscriber);
240 OnTimer(subscriber);
241 });
242
243 if (subscriber->timerId_ < 0) {
244 MMI_HILOGE("Leave, addTimer failed");
245 return false;
246 }
247 subscriber->keyEvent_ = keyEvent_;
248 hasEventExecuting_ = true;
249 MMI_HILOGD("Leave, add timer success, subscribeId:%{public}d,"
250 "duration:%{public}d, timerId:%{public}d",
251 subscriber->id_, duration, subscriber->timerId_);
252 return true;
253 }
254
ClearTimer(const std::shared_ptr<Subscriber> & subscriber)255 void KeySubscriberHandler::ClearTimer(const std::shared_ptr<Subscriber> &subscriber)
256 {
257 CALL_DEBUG_ENTER;
258 CHKPV(subscriber);
259
260 if (subscriber->timerId_ < 0) {
261 MMI_HILOGW("Leave, subscribeId:%{public}d, null timerId < 0", subscriber->id_);
262 return;
263 }
264
265 TimerMgr->RemoveTimer(subscriber->timerId_);
266 auto timerId = subscriber->timerId_;
267 subscriber->keyEvent_.reset();
268 subscriber->timerId_ = -1;
269 hasEventExecuting_ = false;
270 MMI_HILOGD("subscribeId:%{public}d, timerId:%{public}d", subscriber->id_, timerId);
271 }
272
OnTimer(const std::shared_ptr<Subscriber> subscriber)273 void KeySubscriberHandler::OnTimer(const std::shared_ptr<Subscriber> subscriber)
274 {
275 CALL_DEBUG_ENTER;
276 CHKPV(subscriber);
277 subscriber->timerId_ = -1;
278 if (subscriber->keyEvent_ == nullptr) {
279 MMI_HILOGE("Leave, subscriber->keyEvent is nullptr, subscribeId:%{public}d", subscriber->id_);
280 return;
281 }
282
283 NotifySubscriber(subscriber->keyEvent_, subscriber);
284 subscriber->keyEvent_.reset();
285 MMI_HILOGD("subscribeId:%{public}d", subscriber->id_);
286 }
287
InitSessionDeleteCallback()288 bool KeySubscriberHandler::InitSessionDeleteCallback()
289 {
290 CALL_DEBUG_ENTER;
291 if (callbackInitialized_) {
292 MMI_HILOGD("Session delete callback has already been initialized");
293 return true;
294 }
295 auto udsServerPtr = InputHandler->GetUDSServer();
296 CHKPF(udsServerPtr);
297 std::function<void(SessionPtr)> callback =
298 std::bind(&KeySubscriberHandler::OnSessionDelete, this, std::placeholders::_1);
299 udsServerPtr->AddSessionDeletedCallback(callback);
300 callbackInitialized_ = true;
301 return true;
302 }
303
HandleKeyDown(const std::shared_ptr<KeyEvent> & keyEvent)304 bool KeySubscriberHandler::HandleKeyDown(const std::shared_ptr<KeyEvent> &keyEvent)
305 {
306 CALL_DEBUG_ENTER;
307 CHKPF(keyEvent);
308 bool handled = false;
309 auto keyCode = keyEvent->GetKeyCode();
310 std::vector<int32_t> pressedKeys = keyEvent->GetPressedKeys();
311 RemoveKeyCode(keyCode, pressedKeys);
312 for (const auto &subscriber : subscribers_) {
313 auto &keyOption = subscriber->keyOption_;
314 MMI_HILOGD("subscribeId:%{public}d, keyOption->finalKey:%{public}d,"
315 "keyOption->isFinalKeyDown:%{public}s, keyOption->finalKeyDownDuration:%{public}d",
316 subscriber->id_, keyOption->GetFinalKey(), keyOption->IsFinalKeyDown() ? "true" : "false",
317 keyOption->GetFinalKeyDownDuration());
318 for (const auto &keyCode : keyOption->GetPreKeys()) {
319 MMI_HILOGD("keyOption->prekey:%{public}d", keyCode);
320 }
321
322 if (!keyOption->IsFinalKeyDown()) {
323 MMI_HILOGD("!keyOption->IsFinalKeyDown()");
324 continue;
325 }
326
327 if (keyCode != keyOption->GetFinalKey()) {
328 ClearTimer(subscriber);
329 MMI_HILOGD("keyCode != keyOption->GetFinalKey()");
330 continue;
331 }
332
333 if (!IsPreKeysMatch(keyOption->GetPreKeys(), pressedKeys)) {
334 ClearTimer(subscriber);
335 MMI_HILOGD("preKeysMatch failed");
336 continue;
337 }
338
339 if (keyOption->GetFinalKeyDownDuration() <= 0) {
340 MMI_HILOGD("keyOption->GetFinalKeyDownDuration() <= 0");
341 NotifySubscriber(keyEvent, subscriber);
342 handled = true;
343 continue;
344 }
345
346 if (!AddTimer(subscriber, keyEvent)) {
347 MMI_HILOGE("Leave, add timer failed");
348 }
349 }
350 MMI_HILOGD("%{public}s", handled ? "true" : "false");
351 return handled;
352 }
353
HandleKeyUp(const std::shared_ptr<KeyEvent> & keyEvent)354 bool KeySubscriberHandler::HandleKeyUp(const std::shared_ptr<KeyEvent> &keyEvent)
355 {
356 CALL_DEBUG_ENTER;
357 CHKPF(keyEvent);
358 bool handled = false;
359 auto keyCode = keyEvent->GetKeyCode();
360 std::vector<int32_t> pressedKeys = keyEvent->GetPressedKeys();
361 RemoveKeyCode(keyCode, pressedKeys);
362 for (const auto &subscriber : subscribers_) {
363 PrintKeyUpLog(subscriber);
364 auto &keyOption = subscriber->keyOption_;
365 if (keyOption->IsFinalKeyDown()) {
366 ClearTimer(subscriber);
367 MMI_HILOGD("keyOption->IsFinalKeyDown()");
368 continue;
369 }
370
371 if (keyCode != keyOption->GetFinalKey()) {
372 MMI_HILOGD("keyCode != keyOption->GetFinalKey()");
373 continue;
374 }
375
376 if (!IsPreKeysMatch(keyOption->GetPreKeys(), pressedKeys)) {
377 MMI_HILOGD("PreKeysMatch failed");
378 continue;
379 }
380
381 if (!IsNotifyPowerKeySubsciber(keyOption->GetFinalKey(), pressedKeys)) {
382 MMI_HILOGD("In special case, subscriber are not notified");
383 continue;
384 }
385
386 auto duration = keyOption->GetFinalKeyDownDuration();
387 if (duration <= 0) {
388 MMI_HILOGD("duration <= 0");
389 HandleKeyUpWithDelay(keyEvent, subscriber);
390 handled = true;
391 continue;
392 }
393
394 const KeyEvent::KeyItem* keyItem = keyEvent->GetKeyItem();
395 CHKPF(keyItem);
396 auto upTime = keyEvent->GetActionTime();
397 auto downTime = keyItem->GetDownTime();
398 if (upTime - downTime >= (static_cast<int64_t>(duration) * 1000)) {
399 MMI_HILOGE("upTime - downTime >= duration");
400 continue;
401 }
402 MMI_HILOGD("upTime - downTime < duration");
403 HandleKeyUpWithDelay(keyEvent, subscriber);
404 handled = true;
405 }
406 MMI_HILOGD("%{public}s", handled ? "true" : "false");
407 return handled;
408 }
409
HandleKeyCancel(const std::shared_ptr<KeyEvent> & keyEvent)410 bool KeySubscriberHandler::HandleKeyCancel(const std::shared_ptr<KeyEvent> &keyEvent)
411 {
412 CALL_DEBUG_ENTER;
413 CHKPF(keyEvent);
414 for (const auto &subscriber : subscribers_) {
415 ClearTimer(subscriber);
416 }
417 return false;
418 }
419
CloneKeyEvent(std::shared_ptr<KeyEvent> keyEvent)420 bool KeySubscriberHandler::CloneKeyEvent(std::shared_ptr<KeyEvent> keyEvent)
421 {
422 CHKPF(keyEvent);
423 if (keyEvent_ == nullptr) {
424 MMI_HILOGW("keyEvent_ is nullptr");
425 keyEvent_ = KeyEvent::Clone(keyEvent);
426 }
427 CHKPF(keyEvent_);
428 return true;
429 }
430
RemoveKeyCode(int32_t keyCode,std::vector<int32_t> & keyCodes)431 void KeySubscriberHandler::RemoveKeyCode(int32_t keyCode, std::vector<int32_t> &keyCodes)
432 {
433 for (auto it = keyCodes.begin(); it != keyCodes.end(); ++it) {
434 if (*it == keyCode) {
435 keyCodes.erase(it);
436 return;
437 }
438 }
439 }
440
IsRepeatedKeyEvent(std::shared_ptr<KeyEvent> keyEvent)441 bool KeySubscriberHandler::IsRepeatedKeyEvent(std::shared_ptr<KeyEvent> keyEvent)
442 {
443 CHKPF(keyEvent);
444 if (!hasEventExecuting_) {
445 return false;
446 }
447
448 if (keyEvent->GetKeyCode() != keyEvent_->GetKeyCode()) {
449 return false;
450 }
451
452 if (keyEvent->GetKeyAction() != keyEvent_->GetKeyAction()) {
453 return false;
454 }
455
456 if (keyEvent->GetKeyItems().size() != keyEvent_->GetKeyItems().size()) {
457 return false;
458 }
459
460 for (const auto &item : keyEvent->GetKeyItems()) {
461 int32_t keyCode = item.GetKeyCode();
462 bool findResult = false;
463 for (const auto &item1 : keyEvent_->GetKeyItems()) {
464 if (keyCode == item1.GetKeyCode()) {
465 findResult = true;
466 break;
467 }
468 }
469 if (!findResult) {
470 return false;
471 }
472 }
473 return true;
474 }
475
RemoveSubscriberKeyUpTimer(int32_t keyCode)476 void KeySubscriberHandler::RemoveSubscriberKeyUpTimer(int32_t keyCode)
477 {
478 for (const auto& item : subscribers_) {
479 if ((item->timerId_ >= 0) && (item->keyOption_->GetFinalKey() == keyCode)) {
480 ClearTimer(item);
481 }
482 }
483 }
484
IsNotifyPowerKeySubsciber(int32_t keyCode,const std::vector<int32_t> & keyCodes)485 bool KeySubscriberHandler::IsNotifyPowerKeySubsciber(int32_t keyCode, const std::vector<int32_t> &keyCodes)
486 {
487 if (keyCode != KeyEvent::KEYCODE_POWER) {
488 return true;
489 }
490
491 for (const auto& pressedKey: keyCodes) {
492 if (pressedKey == KeyEvent::KEYCODE_VOLUME_DOWN || pressedKey == KeyEvent::KEYCODE_VOLUME_UP) {
493 return false;
494 }
495 }
496 return true;
497 }
498
HandleKeyUpWithDelay(std::shared_ptr<KeyEvent> keyEvent,const std::shared_ptr<Subscriber> & subscriber)499 void KeySubscriberHandler::HandleKeyUpWithDelay(std::shared_ptr<KeyEvent> keyEvent,
500 const std::shared_ptr<Subscriber> &subscriber)
501 {
502 auto keyUpDelay = subscriber->keyOption_->GetFinalKeyUpDelay();
503 if (keyUpDelay <= 0) {
504 NotifySubscriber(keyEvent, subscriber);
505 } else {
506 if (!AddTimer(subscriber, keyEvent)) {
507 MMI_HILOGE("Leave, add timer failed");
508 }
509 }
510 }
511
PrintKeyUpLog(const std::shared_ptr<Subscriber> & subscriber)512 void KeySubscriberHandler::PrintKeyUpLog(const std::shared_ptr<Subscriber> &subscriber)
513 {
514 CHKPV(subscriber);
515 auto &keyOption = subscriber->keyOption_;
516 MMI_HILOGD("subscribeId:%{public}d, keyOption->finalKey:%{public}d,"
517 "keyOption->isFinalKeyDown:%{public}s, keyOption->finalKeyDownDuration:%{public}d,"
518 "keyOption->finalKeyUpDelay:%{public}d",
519 subscriber->id_, keyOption->GetFinalKey(), keyOption->IsFinalKeyDown() ? "true" : "false",
520 keyOption->GetFinalKeyDownDuration(), keyOption->GetFinalKeyUpDelay());
521 for (const auto &keyCode : keyOption->GetPreKeys()) {
522 MMI_HILOGD("keyOption->prekey:%{public}d", keyCode);
523 }
524 }
525
Dump(int32_t fd,const std::vector<std::string> & args)526 void KeySubscriberHandler::Dump(int32_t fd, const std::vector<std::string> &args)
527 {
528 CALL_DEBUG_ENTER;
529 mprintf(fd, "Subscriber information:\t");
530 mprintf(fd, "subscribers: count=%d", subscribers_.size());
531 for (const auto &item : subscribers_) {
532 std::shared_ptr<Subscriber> subscriber = item;
533 CHKPV(subscriber);
534 SessionPtr session = item->sess_;
535 CHKPV(session);
536 std::shared_ptr<KeyOption> keyOption = item->keyOption_;
537 CHKPV(keyOption);
538 mprintf(fd,
539 "subscriber id:%d | timer id:%d | Pid:%d | Uid:%d | Fd:%d "
540 "| FinalKey:%d | finalKeyDownDuration:%d | IsFinalKeyDown:%s\t",
541 subscriber->id_, subscriber->timerId_, session->GetPid(),
542 session->GetUid(), session->GetFd(), keyOption->GetFinalKey(),
543 keyOption->GetFinalKeyDownDuration(), keyOption->IsFinalKeyDown() ? "true" : "false");
544 std::set<int32_t> preKeys = keyOption->GetPreKeys();
545 for (const auto &preKey : preKeys) {
546 mprintf(fd, "preKeys:%d\t", preKey);
547 }
548 }
549 }
550 } // namespace MMI
551 } // namespace OHOS
552