1 /*
2 * Copyright (c) 2024 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 "joystick_event_processor.h"
17
18 #include <iomanip>
19
20 #include "key_map_manager.h"
21 #include "key_event_normalize.h"
22 #include "key_unicode_transformation.h"
23 #include "mmi_log.h"
24
25 #undef MMI_LOG_DOMAIN
26 #define MMI_LOG_DOMAIN MMI_LOG_DISPATCH
27 #undef MMI_LOG_TAG
28 #define MMI_LOG_TAG "JoystickEventProcessor"
29
30 namespace OHOS {
31 namespace MMI {
32 namespace {
33 constexpr int32_t DEFAULT_POINTER_ID { 0 };
34 constexpr double THRESHOLD { 0.01 };
35 } // namespace
36
JoystickEventProcessor(int32_t deviceId)37 JoystickEventProcessor::JoystickEventProcessor(int32_t deviceId)
38 : deviceId_(deviceId) {}
39
OnButtonEvent(struct libinput_event * event)40 std::shared_ptr<KeyEvent> JoystickEventProcessor::OnButtonEvent(struct libinput_event *event)
41 {
42 auto inputDev = libinput_event_get_device(event);
43 CHKPP(inputDev);
44 auto rawBtnEvent = libinput_event_get_joystick_button_event(event);
45 CHKPP(rawBtnEvent);
46 auto keyCode = KeyMapMgr->TransferDeviceKeyValue(inputDev,
47 libinput_event_joystick_button_get_key(rawBtnEvent));
48 auto rawBtnState = libinput_event_joystick_button_get_key_state(rawBtnEvent);
49
50 KeyEvent::KeyItem button {};
51 button.SetKeyCode(keyCode);
52 button.SetPressed(rawBtnState == LIBINPUT_BUTTON_STATE_PRESSED);
53
54 auto btnEvent = FormatButtonEvent(button);
55 if (btnEvent != nullptr) {
56 MMI_HILOGI("Joystick_button_event, No:%{public}d,KC:%{public}d,KA:%{public}d,Intention:%{public}d",
57 btnEvent->GetId(), btnEvent->GetKeyCode(), btnEvent->GetKeyAction(), btnEvent->GetKeyIntention());
58 }
59 return btnEvent;
60 }
61
OnAxisEvent(struct libinput_event * event)62 std::shared_ptr<PointerEvent> JoystickEventProcessor::OnAxisEvent(struct libinput_event *event)
63 {
64 CHKPP(event);
65 auto rawAxisEvent = libinput_event_get_joystick_axis_event(event);
66 CHKPP(rawAxisEvent);
67 if (pointerEvent_ == nullptr) {
68 pointerEvent_ = PointerEvent::Create();
69 CHKPP(pointerEvent_);
70 pointerEvent_->SetPointerId(DEFAULT_POINTER_ID);
71 pointerEvent_->SetDeviceId(deviceId_);
72 pointerEvent_->SetPointerAction(PointerEvent::POINTER_ACTION_AXIS_UPDATE);
73 pointerEvent_->SetSourceType(PointerEvent::SOURCE_TYPE_JOYSTICK);
74
75 PointerEvent::PointerItem pointerItem {};
76 pointerItem.SetPointerId(DEFAULT_POINTER_ID);
77 pointerItem.SetDeviceId(deviceId_);
78 pointerEvent_->AddPointerItem(pointerItem);
79 }
80 int64_t time = GetSysClockTime();
81 pointerEvent_->SetActionTime(time);
82 pointerEvent_->SetActionStartTime(time);
83 pointerEvent_->SetTargetDisplayId(-1);
84
85 for (const auto &item : axesMap_) {
86 if (libinput_event_get_joystick_axis_value_is_changed(rawAxisEvent, item.first)) {
87 auto rawAxisInfo = libinput_event_get_joystick_axis_abs_info(rawAxisEvent, item.first);
88 CHKPC(rawAxisInfo);
89 pointerEvent_->SetAxisValue(item.second.axisType, item.second.normalize(*rawAxisInfo));
90 } else {
91 pointerEvent_->ClearAxisStatus(item.second.axisType);
92 }
93 }
94 pointerEvent_->UpdateId();
95 WIN_MGR->UpdateTargetPointer(pointerEvent_);
96 MMI_HILOGI("Joystick_axis_event, %{public}s", DumpJoystickAxisEvent(pointerEvent_).c_str());
97 return pointerEvent_;
98 }
99
CheckIntention(std::shared_ptr<PointerEvent> pointerEvent,std::function<void (std::shared_ptr<KeyEvent>)> handler)100 void JoystickEventProcessor::CheckIntention(std::shared_ptr<PointerEvent> pointerEvent,
101 std::function<void(std::shared_ptr<KeyEvent>)> handler)
102 {
103 CHKPV(pointerEvent);
104 CHKPV(handler);
105 if (pointerEvent->GetSourceType() != PointerEvent::SOURCE_TYPE_JOYSTICK) {
106 return;
107 }
108 std::vector<KeyEvent::KeyItem> buttonEvents;
109
110 CheckHAT0X(pointerEvent, buttonEvents);
111 CheckHAT0Y(pointerEvent, buttonEvents);
112
113 for (const auto &button : buttonEvents) {
114 UpdateButtonState(button);
115 auto btnEvent = FormatButtonEvent(button);
116 if (btnEvent != nullptr) {
117 MMI_HILOGI("Joystick_intention, No:%{public}d,KC:%{public}d,KA:%{public}d,Intention:%{public}d",
118 btnEvent->GetId(), btnEvent->GetKeyCode(), btnEvent->GetKeyAction(), btnEvent->GetKeyIntention());
119 handler(btnEvent);
120 }
121 }
122 }
123
CheckHAT0X(std::shared_ptr<PointerEvent> pointerEvent,std::vector<KeyEvent::KeyItem> & buttonEvents) const124 void JoystickEventProcessor::CheckHAT0X(std::shared_ptr<PointerEvent> pointerEvent,
125 std::vector<KeyEvent::KeyItem> &buttonEvents) const
126 {
127 if (!pointerEvent->HasAxis(PointerEvent::AXIS_TYPE_ABS_HAT0X)) {
128 return;
129 }
130 KeyEvent::KeyItem keyItem {};
131 auto axisValue = pointerEvent->GetAxisValue(PointerEvent::AXIS_TYPE_ABS_HAT0X);
132 if (axisValue > THRESHOLD) {
133 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_RIGHT);
134 keyItem.SetPressed(true);
135 buttonEvents.emplace_back(keyItem);
136 } else if (axisValue < -THRESHOLD) {
137 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_LEFT);
138 keyItem.SetPressed(true);
139 buttonEvents.emplace_back(keyItem);
140 } else if (IsButtonPressed(KeyEvent::KEYCODE_DPAD_LEFT)) {
141 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_LEFT);
142 keyItem.SetPressed(false);
143 buttonEvents.emplace_back(keyItem);
144 } else if (IsButtonPressed(KeyEvent::KEYCODE_DPAD_RIGHT)) {
145 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_RIGHT);
146 keyItem.SetPressed(false);
147 buttonEvents.emplace_back(keyItem);
148 }
149 }
150
CheckHAT0Y(std::shared_ptr<PointerEvent> pointerEvent,std::vector<KeyEvent::KeyItem> & buttonEvents) const151 void JoystickEventProcessor::CheckHAT0Y(std::shared_ptr<PointerEvent> pointerEvent,
152 std::vector<KeyEvent::KeyItem> &buttonEvents) const
153 {
154 if (!pointerEvent->HasAxis(PointerEvent::AXIS_TYPE_ABS_HAT0Y)) {
155 return;
156 }
157 KeyEvent::KeyItem keyItem {};
158 auto axisValue = pointerEvent->GetAxisValue(PointerEvent::AXIS_TYPE_ABS_HAT0Y);
159 if (axisValue > THRESHOLD) {
160 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_DOWN);
161 keyItem.SetPressed(true);
162 buttonEvents.emplace_back(keyItem);
163 } else if (axisValue < -THRESHOLD) {
164 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_UP);
165 keyItem.SetPressed(true);
166 buttonEvents.emplace_back(keyItem);
167 } else if (IsButtonPressed(KeyEvent::KEYCODE_DPAD_DOWN)) {
168 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_DOWN);
169 keyItem.SetPressed(false);
170 buttonEvents.emplace_back(keyItem);
171 } else if (IsButtonPressed(KeyEvent::KEYCODE_DPAD_UP)) {
172 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_UP);
173 keyItem.SetPressed(false);
174 buttonEvents.emplace_back(keyItem);
175 }
176 }
177
UpdateButtonState(const KeyEvent::KeyItem & keyItem)178 void JoystickEventProcessor::UpdateButtonState(const KeyEvent::KeyItem &keyItem)
179 {
180 if (keyItem.IsPressed()) {
181 PressButton(keyItem.GetKeyCode());
182 } else {
183 LiftButton(keyItem.GetKeyCode());
184 }
185 }
186
FormatButtonEvent(const KeyEvent::KeyItem & button) const187 std::shared_ptr<KeyEvent> JoystickEventProcessor::FormatButtonEvent(const KeyEvent::KeyItem &button) const
188 {
189 auto keyEvent = CleanUpKeyEvent();
190 CHKPP(keyEvent);
191 int64_t time = GetSysClockTime();
192 keyEvent->SetActionTime(time);
193 keyEvent->SetAction(button.IsPressed() ? KeyEvent::KEY_ACTION_DOWN : KeyEvent::KEY_ACTION_UP);
194 keyEvent->SetDeviceId(deviceId_);
195 keyEvent->SetSourceType(InputEvent::SOURCE_TYPE_JOYSTICK);
196 keyEvent->SetKeyCode(button.GetKeyCode());
197 keyEvent->SetKeyAction(button.IsPressed() ? KeyEvent::KEY_ACTION_DOWN : KeyEvent::KEY_ACTION_UP);
198 if (keyEvent->GetPressedKeys().empty()) {
199 keyEvent->SetActionStartTime(time);
200 }
201 keyEvent->SetRepeat(false);
202
203 KeyEvent::KeyItem keyItem {};
204 keyItem.SetDownTime(time);
205 keyItem.SetKeyCode(button.GetKeyCode());
206 keyItem.SetDeviceId(deviceId_);
207 keyItem.SetPressed(button.IsPressed());
208 keyItem.SetUnicode(KeyCodeToUnicode(button.GetKeyCode(), keyEvent));
209
210 if (!keyItem.IsPressed()) {
211 auto tItem = keyEvent->GetKeyItem(keyItem.GetKeyCode());
212 if (tItem) {
213 keyItem.SetDownTime(tItem->GetDownTime());
214 }
215 keyEvent->RemoveReleasedKeyItems(keyItem);
216 }
217 keyEvent->AddPressedKeyItems(keyItem);
218 keyEvent->SetKeyIntention(
219 KeyItemsTransKeyIntention({ keyItem }));
220 keyEvent->UpdateId();
221 return keyEvent;
222 }
223
CleanUpKeyEvent() const224 std::shared_ptr<KeyEvent> JoystickEventProcessor::CleanUpKeyEvent() const
225 {
226 auto keyEvent = KeyEventHdr->GetKeyEvent();
227 CHKPP(keyEvent);
228 if (keyEvent->GetAction() == KeyEvent::KEY_ACTION_UP) {
229 std::optional<KeyEvent::KeyItem> preUpKeyItem = keyEvent->GetKeyItem();
230 if (preUpKeyItem) {
231 keyEvent->RemoveReleasedKeyItems(*preUpKeyItem);
232 }
233 }
234 return keyEvent;
235 }
236
DumpJoystickAxisEvent(std::shared_ptr<PointerEvent> pointerEvent) const237 std::string JoystickEventProcessor::DumpJoystickAxisEvent(std::shared_ptr<PointerEvent> pointerEvent) const
238 {
239 constexpr int32_t precision { 2 };
240 std::ostringstream sAxes;
241
242 sAxes << "No:" << pointerEvent->GetId();
243
244 for (const auto &[_, axisInfo] : axesMap_) {
245 sAxes << "," << axisInfo.name << ":" << std::fixed << std::setprecision(precision)
246 << pointerEvent->GetAxisValue(axisInfo.axisType);
247 if (pointerEvent->HasAxis(axisInfo.axisType)) {
248 sAxes << "[C]";
249 }
250 }
251 return std::move(sAxes).str();
252 }
253
Normalize(const struct libinput_event_joystick_axis_abs_info & axis,double low,double high)254 double JoystickEventProcessor::Normalize(
255 const struct libinput_event_joystick_axis_abs_info &axis, double low, double high)
256 {
257 constexpr double epsilon { 0.001 };
258 if (high - epsilon < low) {
259 return {};
260 }
261 if (axis.maximum <= axis.minimum) {
262 return {};
263 }
264 double value = std::clamp(axis.value, axis.minimum, axis.maximum);
265 double norm = (value - axis.minimum) / (axis.maximum - axis.minimum);
266 return (low + (high - low) * norm);
267 }
268 } // namespace MMI
269 } // namespace OHOS
270