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 "input_event_handler.h"
17
18#include <cinttypes>
19#include <cstdio>
20#include <cstring>
21#include <functional>
22#include <vector>
23
24#include <sys/stat.h>
25#include <unistd.h>
26
27#include "libinput.h"
28#include "key_command_handler.h"
29#include "timer_manager.h"
30#include "util.h"
31
32#undef MMI_LOG_DOMAIN
33#define MMI_LOG_DOMAIN MMI_LOG_HANDLER
34#undef MMI_LOG_TAG
35#define MMI_LOG_TAG "InputEventHandler"
36
37namespace OHOS {
38namespace MMI {
39namespace {
40constexpr int32_t MT_TOOL_PALM { 2 };
41constexpr uint32_t KEY_ESC { 1 };
42constexpr uint32_t KEY_KPASTERISK { 55 };
43constexpr uint32_t KEY_F1 { 59 };
44constexpr uint32_t KEY_LEFTCTRL { 29 };
45constexpr uint32_t KEY_RIGHTCTRL { 97 };
46constexpr uint32_t KEY_LEFTALT { 56 };
47constexpr uint32_t KEY_RIGHTALT { 100 };
48constexpr uint32_t KEY_LEFTSHIFT { 42 };
49constexpr uint32_t KEY_RIGHTSHIFT { 54 };
50constexpr uint32_t KEY_FN { 0x1d0 };
51constexpr uint32_t KEY_CAPSLOCK { 58 };
52constexpr uint32_t KEY_TAB { 15 };
53constexpr uint32_t KEY_COMPOSE { 127 };
54constexpr uint32_t KEY_RIGHTMETA { 126 };
55constexpr uint32_t KEY_LEFTMETA { 125 };
56} // namespace
57
58InputEventHandler::InputEventHandler()
59{
60    lastEventBeginTime_ = GetSysClockTime();
61    udsServer_ = nullptr;
62}
63
64InputEventHandler::~InputEventHandler() {}
65
66void InputEventHandler::Init(UDSServer& udsServer)
67{
68    udsServer_ = &udsServer;
69    BuildInputHandlerChain();
70}
71
72void InputEventHandler::OnEvent(void *event, int64_t frameTime)
73{
74    CHKPV(eventNormalizeHandler_);
75    if (event == nullptr) {
76        eventNormalizeHandler_->HandleEvent(nullptr, frameTime);
77        return;
78    }
79
80    idSeed_ += 1;
81    const uint64_t maxUInt64 = (std::numeric_limits<uint64_t>::max)() - 1;
82    if (idSeed_ >= maxUInt64) {
83        MMI_HILOGE("The value is flipped. id:%{public}" PRId64, idSeed_);
84        idSeed_ = 1;
85    }
86
87    auto *lpEvent = static_cast<libinput_event *>(event);
88    CHKPV(lpEvent);
89    int32_t eventType = libinput_event_get_type(lpEvent);
90    int64_t beginTime = GetSysClockTime();
91    lastEventBeginTime_ = beginTime;
92    MMI_HILOGD("Event reporting. id:%{public}" PRId64 ",tid:%{public}" PRId64 ",eventType:%{public}d,"
93               "beginTime:%{public}" PRId64, idSeed_, GetThisThreadId(), eventType, beginTime);
94
95    UpdateDwtRecord(lpEvent);
96    if (IsTouchpadMistouch(lpEvent)) {
97        return;
98    }
99
100    ResetLogTrace();
101    eventNormalizeHandler_->HandleEvent(lpEvent, frameTime);
102    int64_t endTime = GetSysClockTime();
103    int64_t lostTime = endTime - beginTime;
104    MMI_HILOGD("Event handling completed. id:%{public}" PRId64 ",endTime:%{public}" PRId64
105               ",lostTime:%{public}" PRId64, idSeed_, endTime, lostTime);
106}
107
108void InputEventHandler::UpdateDwtRecord(libinput_event *event)
109{
110    CHKPV(event);
111    auto type = libinput_event_get_type(event);
112    if (type == LIBINPUT_EVENT_TOUCHPAD_DOWN || type == LIBINPUT_EVENT_TOUCHPAD_MOTION) {
113        UpdateDwtTouchpadRecord(event);
114    }
115    if (type == LIBINPUT_EVENT_KEYBOARD_KEY) {
116        UpdateDwtKeyboardRecord(event);
117    }
118}
119
120void InputEventHandler::UpdateDwtTouchpadRecord(libinput_event *event)
121{
122    auto touchpadEvent = libinput_event_get_touchpad_event(event);
123    CHKPV(touchpadEvent);
124    auto type = libinput_event_get_type(event);
125    if (type == LIBINPUT_EVENT_TOUCHPAD_DOWN) {
126        auto touchpadDevice = libinput_event_get_device(event); // guaranteed valid during event lifetime
127        CHKPV(touchpadDevice);
128        double touchpadSizeX;
129        double touchpadSizeY;
130        if (libinput_device_get_size(touchpadDevice, &touchpadSizeX, &touchpadSizeY) != 0) {
131            MMI_HILOGW("failed to get touchpad device size");
132            return;
133        }
134        touchpadEventDownAbsX_ = libinput_event_touchpad_get_x(touchpadEvent);
135        touchpadEventDownAbsY_ = libinput_event_touchpad_get_y(touchpadEvent);
136        touchpadEventAbsX_ = touchpadEventDownAbsX_;
137        touchpadEventAbsY_ = touchpadEventDownAbsY_;
138        if (touchpadEventDownAbsX_ > TOUCHPAD_EDGE_WIDTH &&
139            touchpadEventDownAbsX_ < touchpadSizeX - TOUCHPAD_EDGE_WIDTH) {
140            isDwtEdgeAreaForTouchpadMotionActing_ = false;
141            MMI_HILOGD("Pointer edge dwt unlocked, coordX = %{public}f", touchpadEventDownAbsX_);
142        }
143        if (touchpadEventDownAbsX_ > TOUCHPAD_EDGE_WIDTH_FOR_BUTTON &&
144            touchpadEventDownAbsX_ < touchpadSizeX - TOUCHPAD_EDGE_WIDTH_FOR_BUTTON) {
145            isDwtEdgeAreaForTouchpadButtonActing_ = false;
146            MMI_HILOGD("Button edge dwt unlocked, coordX = %{public}f", touchpadEventDownAbsX_);
147        }
148        if (touchpadEventDownAbsX_ > TOUCHPAD_EDGE_WIDTH_FOR_TAP &&
149            touchpadEventDownAbsX_ < touchpadSizeX - TOUCHPAD_EDGE_WIDTH_FOR_TAP) {
150            isDwtEdgeAreaForTouchpadTapActing_ = false;
151            MMI_HILOGD("Tap edge dwt unlocked, coordX = %{public}f", touchpadEventDownAbsX_);
152        }
153    }
154    if (type == LIBINPUT_EVENT_TOUCHPAD_MOTION) {
155        touchpadEventAbsX_ = libinput_event_touchpad_get_x(touchpadEvent);
156        touchpadEventAbsY_ = libinput_event_touchpad_get_y(touchpadEvent);
157    }
158}
159
160void InputEventHandler::UpdateDwtKeyboardRecord(libinput_event *event)
161{
162    auto keyboardEvent = libinput_event_get_keyboard_event(event);
163    CHKPV(keyboardEvent);
164    uint32_t key = libinput_event_keyboard_get_key(keyboardEvent);
165    if (IsStandaloneFunctionKey(key)) {
166        return;
167    }
168
169    auto keyState = libinput_event_keyboard_get_key_state(keyboardEvent);
170    if (IsModifierKey(key)) {
171        modifierPressedCount_ += (keyState == LIBINPUT_KEY_STATE_PRESSED) ? 1 : -1;
172    }
173    if (keyState == LIBINPUT_KEY_STATE_PRESSED && modifierPressedCount_ > 0) {
174        isKeyPressedWithAnyModifiers_[key] = true; // set flag when key is pressed with modifiers
175    }
176    if (!IsModifierKey(key) && !isKeyPressedWithAnyModifiers_[key]) {
177        RefreshDwtActingState();
178    }
179    if (keyState == LIBINPUT_KEY_STATE_RELEASED) {
180        isKeyPressedWithAnyModifiers_[key] = false; // always reset flag when key is released
181    }
182}
183
184bool InputEventHandler::IsStandaloneFunctionKey(uint32_t keycode)
185{
186    if (IsModifierKey(keycode)) {
187        return false;
188    }
189    switch (keycode) {
190        case KEY_ESC:
191        case KEY_KPASTERISK:
192            return true;
193        default:
194            return keycode >= KEY_F1;
195    }
196}
197
198bool InputEventHandler::IsModifierKey(uint32_t keycode)
199{
200    switch (keycode) {
201        case KEY_LEFTCTRL:
202        case KEY_RIGHTCTRL:
203        case KEY_LEFTALT:
204        case KEY_RIGHTALT:
205        case KEY_LEFTSHIFT:
206        case KEY_RIGHTSHIFT:
207        case KEY_FN:
208        case KEY_CAPSLOCK:
209        case KEY_TAB:
210        case KEY_COMPOSE:
211        case KEY_RIGHTMETA:
212        case KEY_LEFTMETA:
213            return true;
214        default:
215            return false;
216    }
217}
218
219void InputEventHandler::RefreshDwtActingState()
220{
221    isDwtEdgeAreaForTouchpadMotionActing_ = true;
222    isDwtEdgeAreaForTouchpadButtonActing_ = true;
223    isDwtEdgeAreaForTouchpadTapActing_ = true;
224}
225
226bool InputEventHandler::IsTouchpadMistouch(libinput_event *event)
227{
228    CHKPF(event);
229    auto type = libinput_event_get_type(event);
230    if (type >= LIBINPUT_EVENT_TOUCHPAD_DOWN && type <= LIBINPUT_EVENT_TOUCHPAD_MOTION) {
231        auto touchpadEvent = libinput_event_get_touchpad_event(event);
232        CHKPF(touchpadEvent);
233        int32_t toolType = libinput_event_touchpad_get_tool_type(touchpadEvent);
234        if (toolType == MT_TOOL_PALM) {
235            MMI_HILOGD("Touchpad event is palm");
236            return false;
237        }
238    }
239
240    if (type == LIBINPUT_EVENT_POINTER_BUTTON_TOUCHPAD) {
241        return IsTouchpadButtonMistouch(event);
242    }
243    if (type == LIBINPUT_EVENT_POINTER_TAP) {
244        return IsTouchpadTapMistouch(event);
245    }
246    if (type == LIBINPUT_EVENT_TOUCHPAD_MOTION) {
247        return IsTouchpadMotionMistouch(event);
248    }
249    if (type == LIBINPUT_EVENT_POINTER_MOTION_TOUCHPAD) {
250        return IsTouchpadPointerMotionMistouch(event);
251    }
252
253    return false;
254}
255
256bool InputEventHandler::IsTouchpadButtonMistouch(libinput_event* event)
257{
258    CHKPF(event);
259    auto touchpadButtonEvent = libinput_event_get_pointer_event(event);
260    CHKPF(touchpadButtonEvent);
261    auto buttonState = libinput_event_pointer_get_button_state(touchpadButtonEvent);
262    if (buttonState == LIBINPUT_BUTTON_STATE_PRESSED) {
263        auto touchpadDevice = libinput_event_get_device(event); // guaranteed valid during event lifetime
264        CHKPF(touchpadDevice);
265        double touchpadSizeX;
266        double touchpadSizeY;
267        if (libinput_device_get_size(touchpadDevice, &touchpadSizeX, &touchpadSizeY) != 0) {
268            return false;
269        }
270        double coordX = touchpadEventAbsX_;
271        if (isDwtEdgeAreaForTouchpadButtonActing_ &&
272            (coordX <= TOUCHPAD_EDGE_WIDTH_FOR_BUTTON || coordX >= touchpadSizeX - TOUCHPAD_EDGE_WIDTH_FOR_BUTTON)) {
273            isButtonMistouch_ = true;
274            MMI_HILOGD("The buttonPressed event is mistouch");
275            return true;
276        }
277    }
278    if (buttonState == LIBINPUT_BUTTON_STATE_RELEASED) {
279        if (isButtonMistouch_) {
280            isButtonMistouch_ = false;
281            MMI_HILOGD("The buttonReleased event is mistouch");
282            return true;
283        }
284    }
285    return false;
286}
287
288bool InputEventHandler::IsTouchpadTapMistouch(libinput_event* event)
289{
290    CHKPF(event);
291    auto data = libinput_event_get_pointer_event(event);
292    CHKPF(data);
293    auto state = libinput_event_pointer_get_button_state(data);
294    if (state == LIBINPUT_BUTTON_STATE_PRESSED) {
295        auto touchpadDevice = libinput_event_get_device(event); // guaranteed valid during event lifetime
296        CHKPF(touchpadDevice);
297        double touchpadSizeX;
298        double touchpadSizeY;
299        if (libinput_device_get_size(touchpadDevice, &touchpadSizeX, &touchpadSizeY) != 0) {
300            return false;
301        }
302        double coordX = touchpadEventDownAbsX_;
303        if (isDwtEdgeAreaForTouchpadTapActing_ &&
304            (coordX <= TOUCHPAD_EDGE_WIDTH_FOR_TAP || coordX >= touchpadSizeX - TOUCHPAD_EDGE_WIDTH_FOR_TAP)) {
305            isTapMistouch_ = true;
306            MMI_HILOGD("Touchpad tap presse event is mistouch");
307            return true;
308        }
309    }
310    if (state == LIBINPUT_BUTTON_STATE_RELEASED) {
311        if (isTapMistouch_) {
312            isTapMistouch_ = false;
313            MMI_HILOGD("Touchpad tap release event is mistouch");
314            return true;
315        }
316    }
317    return false;
318}
319
320bool InputEventHandler::IsTouchpadMotionMistouch(libinput_event *event)
321{
322    if (!isDwtEdgeAreaForTouchpadMotionActing_) {
323        return false;
324    }
325
326    CHKPF(event);
327    auto touchpadEvent = libinput_event_get_touchpad_event(event);
328    CHKPF(touchpadEvent);
329    auto touchpadDevice = libinput_event_get_device(event); // guaranteed valid during event lifetime
330    CHKPF(touchpadDevice);
331    double touchpadSizeX;
332    double touchpadSizeY;
333    if (libinput_device_get_size(touchpadDevice, &touchpadSizeX, &touchpadSizeY) != 0) {
334        return false;
335    }
336    auto coordX = touchpadEventDownAbsX_;
337    if (coordX <= TOUCHPAD_EDGE_WIDTH || coordX >= touchpadSizeX - TOUCHPAD_EDGE_WIDTH) {
338        MMI_HILOGD("Touchpad event is edge mistouch");
339        return true;
340    }
341    return false;
342}
343
344bool InputEventHandler::IsTouchpadPointerMotionMistouch(libinput_event *event)
345{
346    if (!isDwtEdgeAreaForTouchpadMotionActing_) {
347        return false;
348    }
349
350    CHKPF(event);
351    auto pointerEvent = libinput_event_get_pointer_event(event);
352    CHKPF(pointerEvent);
353    auto touchpadDevice = libinput_event_get_device(event); // guaranteed valid during event lifetime
354    CHKPF(touchpadDevice);
355    double touchpadSizeX;
356    double touchpadSizeY;
357    if (libinput_device_get_size(touchpadDevice, &touchpadSizeX, &touchpadSizeY) != 0) {
358        return false;
359    }
360    double coordX = touchpadEventDownAbsX_;
361    if (coordX <= TOUCHPAD_EDGE_WIDTH || coordX >= touchpadSizeX - TOUCHPAD_EDGE_WIDTH) {
362        MMI_HILOGD("Touchpad pointer motion event is edge mistouch");
363        return true;
364    }
365    return false;
366}
367
368int32_t InputEventHandler::BuildInputHandlerChain()
369{
370    eventNormalizeHandler_ = std::make_shared<EventNormalizeHandler>();
371#if !defined(OHOS_BUILD_ENABLE_KEYBOARD) && !defined(OHOS_BUILD_ENABLE_POINTER) && !defined(OHOS_BUILD_ENABLE_TOUCH)
372    return RET_OK;
373#endif // !OHOS_BUILD_ENABLE_KEYBOARD && !OHOS_BUILD_ENABLE_POINTER && !OHOS_BUILD_ENABLE_TOUCH
374
375    std::shared_ptr<IInputEventHandler> handler = eventNormalizeHandler_;
376#if defined(OHOS_BUILD_ENABLE_POINTER) || defined(OHOS_BUILD_ENABLE_TOUCH)
377    eventFilterHandler_ = std::make_shared<EventFilterHandler>();
378    handler->SetNext(eventFilterHandler_);
379    handler = eventFilterHandler_;
380#endif // OHOS_BUILD_ENABLE_POINTER || OHOS_BUILD_ENABLE_TOUCH
381
382#ifdef OHOS_BUILD_ENABLE_INTERCEPTOR
383    eventInterceptorHandler_ = std::make_shared<EventInterceptorHandler>();
384    handler->SetNext(eventInterceptorHandler_);
385    handler = eventInterceptorHandler_;
386#endif // OHOS_BUILD_ENABLE_INTERCEPTOR
387
388#ifdef OHOS_BUILD_ENABLE_KEYBOARD
389#ifdef OHOS_BUILD_ENABLE_COMBINATION_KEY
390    eventKeyCommandHandler_ = std::make_shared<KeyCommandHandler>();
391    handler->SetNext(eventKeyCommandHandler_);
392    handler = eventKeyCommandHandler_;
393#endif // OHOS_BUILD_ENABLE_COMBINATION_KEY
394    eventSubscriberHandler_ = std::make_shared<KeySubscriberHandler>();
395    handler->SetNext(eventSubscriberHandler_);
396    handler = eventSubscriberHandler_;
397#endif // OHOS_BUILD_ENABLE_KEYBOARD
398#ifdef OHOS_BUILD_ENABLE_SWITCH
399    switchEventSubscriberHandler_ = std::make_shared<SwitchSubscriberHandler>();
400    handler->SetNext(switchEventSubscriberHandler_);
401    handler = switchEventSubscriberHandler_;
402#endif // OHOS_BUILD_ENABLE_SWITCH
403#ifdef OHOS_BUILD_ENABLE_MONITOR
404    eventMonitorHandler_ = std::make_shared<EventMonitorHandler>();
405    handler->SetNext(eventMonitorHandler_);
406    handler = eventMonitorHandler_;
407#endif // OHOS_BUILD_ENABLE_MONITOR
408    eventDispatchHandler_ = std::make_shared<EventDispatchHandler>();
409    handler->SetNext(eventDispatchHandler_);
410    return RET_OK;
411}
412
413int32_t InputEventHandler::GetIntervalSinceLastInput(int64_t &timeInterval)
414{
415    int64_t currentSystemTime = GetSysClockTime();
416    timeInterval = currentSystemTime - lastEventBeginTime_;
417    return RET_OK;
418}
419
420UDSServer* InputEventHandler::GetUDSServer() const
421{
422    return udsServer_;
423}
424
425std::shared_ptr<EventNormalizeHandler> InputEventHandler::GetEventNormalizeHandler() const
426{
427    return eventNormalizeHandler_;
428}
429
430std::shared_ptr<EventInterceptorHandler> InputEventHandler::GetInterceptorHandler() const
431{
432    return eventInterceptorHandler_;
433}
434
435std::shared_ptr<KeySubscriberHandler> InputEventHandler::GetSubscriberHandler() const
436{
437    return eventSubscriberHandler_;
438}
439
440std::shared_ptr<SwitchSubscriberHandler> InputEventHandler::GetSwitchSubscriberHandler() const
441{
442    return switchEventSubscriberHandler_;
443}
444
445std::shared_ptr<KeyCommandHandler> InputEventHandler::GetKeyCommandHandler() const
446{
447    return eventKeyCommandHandler_;
448}
449
450std::shared_ptr<EventMonitorHandler> InputEventHandler::GetMonitorHandler() const
451{
452    return eventMonitorHandler_;
453}
454
455std::shared_ptr<EventFilterHandler> InputEventHandler::GetFilterHandler() const
456{
457    return eventFilterHandler_;
458}
459
460std::shared_ptr<EventDispatchHandler> InputEventHandler::GetEventDispatchHandler() const
461{
462    return eventDispatchHandler_;
463}
464
465int32_t InputEventHandler::SetMoveEventFilters(bool flag)
466{
467    CALL_INFO_TRACE;
468#ifdef OHOS_BUILD_ENABLE_MOVE_EVENT_FILTERS
469    CHKPR(eventNormalizeHandler_, INVALID_HANDLER_ID);
470    return eventNormalizeHandler_->SetMoveEventFilters(flag);
471#else
472    MMI_HILOGW("Set move event filters does not support");
473    return ERROR_UNSUPPORT;
474#endif // OHOS_BUILD_ENABLE_MOVE_EVENT_FILTERS
475}
476} // namespace MMI
477} // namespace OHOS