• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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