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
24 #undef MMI_LOG_DOMAIN
25 #define MMI_LOG_DOMAIN MMI_LOG_DISPATCH
26 #undef MMI_LOG_TAG
27 #define MMI_LOG_TAG "JoystickEventProcessor"
28
29 namespace OHOS {
30 namespace MMI {
31 namespace {
32 constexpr int32_t DEFAULT_POINTER_ID { 0 };
33 constexpr double THRESHOLD { 0.01 };
34 } // namespace
35
JoystickEventProcessor(int32_t deviceId)36 JoystickEventProcessor::JoystickEventProcessor(int32_t deviceId)
37 : deviceId_(deviceId) {}
38
OnButtonEvent(struct libinput_event * event)39 std::shared_ptr<KeyEvent> JoystickEventProcessor::OnButtonEvent(struct libinput_event *event)
40 {
41 auto inputDev = libinput_event_get_device(event);
42 CHKPP(inputDev);
43 auto rawBtnEvent = libinput_event_get_joystick_button_event(event);
44 CHKPP(rawBtnEvent);
45 auto keyCode = KeyMapMgr->TransferDeviceKeyValue(inputDev,
46 libinput_event_joystick_button_get_key(rawBtnEvent));
47 auto rawBtnState = libinput_event_joystick_button_get_key_state(rawBtnEvent);
48
49 KeyEvent::KeyItem button {};
50 button.SetKeyCode(keyCode);
51 button.SetPressed(rawBtnState == LIBINPUT_BUTTON_STATE_PRESSED);
52
53 auto btnEvent = FormatButtonEvent(button);
54 if (btnEvent != nullptr) {
55 MMI_HILOGI("Joystick_button_event, No:%{public}d,KC:%{private}d,KA:%{public}d,Intention:%{public}d",
56 btnEvent->GetId(), btnEvent->GetKeyCode(), btnEvent->GetKeyAction(), btnEvent->GetKeyIntention());
57 }
58 return btnEvent;
59 }
60
OnAxisEvent(struct libinput_event * event)61 std::shared_ptr<PointerEvent> JoystickEventProcessor::OnAxisEvent(struct libinput_event *event)
62 {
63 CHKPP(event);
64 auto rawAxisEvent = libinput_event_get_joystick_axis_event(event);
65 CHKPP(rawAxisEvent);
66 if (pointerEvent_ == nullptr) {
67 pointerEvent_ = PointerEvent::Create();
68 CHKPP(pointerEvent_);
69 pointerEvent_->SetPointerId(DEFAULT_POINTER_ID);
70 pointerEvent_->SetDeviceId(deviceId_);
71 pointerEvent_->SetPointerAction(PointerEvent::POINTER_ACTION_AXIS_UPDATE);
72 pointerEvent_->SetSourceType(PointerEvent::SOURCE_TYPE_JOYSTICK);
73
74 PointerEvent::PointerItem pointerItem {};
75 pointerItem.SetPointerId(DEFAULT_POINTER_ID);
76 pointerItem.SetDeviceId(deviceId_);
77 pointerEvent_->AddPointerItem(pointerItem);
78 }
79 int64_t time = GetSysClockTime();
80 pointerEvent_->SetActionTime(time);
81 pointerEvent_->SetActionStartTime(time);
82 pointerEvent_->SetTargetDisplayId(-1);
83
84 for (const auto &item : axesMap_) {
85 if (libinput_event_get_joystick_axis_value_is_changed(rawAxisEvent, item.first)) {
86 auto rawAxisInfo = libinput_event_get_joystick_axis_abs_info(rawAxisEvent, item.first);
87 CHKPC(rawAxisInfo);
88 pointerEvent_->SetAxisValue(item.second.axisType, item.second.normalize(*rawAxisInfo));
89 } else {
90 pointerEvent_->ClearAxisStatus(item.second.axisType);
91 }
92 }
93 pointerEvent_->UpdateId();
94 WIN_MGR->UpdateTargetPointer(pointerEvent_);
95 MMI_HILOGI("Joystick_axis_event, %{public}s", DumpJoystickAxisEvent(pointerEvent_).c_str());
96 return pointerEvent_;
97 }
98
CheckIntention(std::shared_ptr<PointerEvent> pointerEvent,std::function<void (std::shared_ptr<KeyEvent>)> handler)99 void JoystickEventProcessor::CheckIntention(std::shared_ptr<PointerEvent> pointerEvent,
100 std::function<void(std::shared_ptr<KeyEvent>)> handler)
101 {
102 CHKPV(pointerEvent);
103 CHKPV(handler);
104 if (pointerEvent->GetSourceType() != PointerEvent::SOURCE_TYPE_JOYSTICK) {
105 return;
106 }
107 std::vector<KeyEvent::KeyItem> buttonEvents;
108
109 CheckHAT0X(pointerEvent, buttonEvents);
110 CheckHAT0Y(pointerEvent, buttonEvents);
111
112 for (const auto &button : buttonEvents) {
113 UpdateButtonState(button);
114 auto btnEvent = FormatButtonEvent(button);
115 if (btnEvent != nullptr) {
116 MMI_HILOGI("Joystick_intention, No:%{public}d,KC:%{private}d,KA:%{public}d,Intention:%{public}d",
117 btnEvent->GetId(), btnEvent->GetKeyCode(), btnEvent->GetKeyAction(), btnEvent->GetKeyIntention());
118 handler(btnEvent);
119 }
120 }
121 }
122
CheckHAT0X(std::shared_ptr<PointerEvent> pointerEvent,std::vector<KeyEvent::KeyItem> & buttonEvents) const123 void JoystickEventProcessor::CheckHAT0X(std::shared_ptr<PointerEvent> pointerEvent,
124 std::vector<KeyEvent::KeyItem> &buttonEvents) const
125 {
126 if (!pointerEvent->HasAxis(PointerEvent::AXIS_TYPE_ABS_HAT0X)) {
127 return;
128 }
129 KeyEvent::KeyItem keyItem {};
130 auto axisValue = pointerEvent->GetAxisValue(PointerEvent::AXIS_TYPE_ABS_HAT0X);
131 if (axisValue > THRESHOLD) {
132 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_RIGHT);
133 keyItem.SetPressed(true);
134 buttonEvents.emplace_back(keyItem);
135 } else if (axisValue < -THRESHOLD) {
136 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_LEFT);
137 keyItem.SetPressed(true);
138 buttonEvents.emplace_back(keyItem);
139 } else if (IsButtonPressed(KeyEvent::KEYCODE_DPAD_LEFT)) {
140 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_LEFT);
141 keyItem.SetPressed(false);
142 buttonEvents.emplace_back(keyItem);
143 } else if (IsButtonPressed(KeyEvent::KEYCODE_DPAD_RIGHT)) {
144 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_RIGHT);
145 keyItem.SetPressed(false);
146 buttonEvents.emplace_back(keyItem);
147 }
148 }
149
CheckHAT0Y(std::shared_ptr<PointerEvent> pointerEvent,std::vector<KeyEvent::KeyItem> & buttonEvents) const150 void JoystickEventProcessor::CheckHAT0Y(std::shared_ptr<PointerEvent> pointerEvent,
151 std::vector<KeyEvent::KeyItem> &buttonEvents) const
152 {
153 if (!pointerEvent->HasAxis(PointerEvent::AXIS_TYPE_ABS_HAT0Y)) {
154 return;
155 }
156 KeyEvent::KeyItem keyItem {};
157 auto axisValue = pointerEvent->GetAxisValue(PointerEvent::AXIS_TYPE_ABS_HAT0Y);
158 if (axisValue > THRESHOLD) {
159 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_DOWN);
160 keyItem.SetPressed(true);
161 buttonEvents.emplace_back(keyItem);
162 } else if (axisValue < -THRESHOLD) {
163 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_UP);
164 keyItem.SetPressed(true);
165 buttonEvents.emplace_back(keyItem);
166 } else if (IsButtonPressed(KeyEvent::KEYCODE_DPAD_DOWN)) {
167 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_DOWN);
168 keyItem.SetPressed(false);
169 buttonEvents.emplace_back(keyItem);
170 } else if (IsButtonPressed(KeyEvent::KEYCODE_DPAD_UP)) {
171 keyItem.SetKeyCode(KeyEvent::KEYCODE_DPAD_UP);
172 keyItem.SetPressed(false);
173 buttonEvents.emplace_back(keyItem);
174 }
175 }
176
UpdateButtonState(const KeyEvent::KeyItem & keyItem)177 void JoystickEventProcessor::UpdateButtonState(const KeyEvent::KeyItem &keyItem)
178 {
179 if (keyItem.IsPressed()) {
180 PressButton(keyItem.GetKeyCode());
181 } else {
182 LiftButton(keyItem.GetKeyCode());
183 }
184 }
185
FormatButtonEvent(const KeyEvent::KeyItem & button)186 std::shared_ptr<KeyEvent> JoystickEventProcessor::FormatButtonEvent(const KeyEvent::KeyItem &button)
187 {
188 auto keyEvent = CleanUpKeyEvent();
189 CHKPP(keyEvent);
190 int64_t time = GetSysClockTime();
191 keyEvent->SetActionTime(time);
192 keyEvent->SetAction(button.IsPressed() ? KeyEvent::KEY_ACTION_DOWN : KeyEvent::KEY_ACTION_UP);
193 keyEvent->SetDeviceId(deviceId_);
194 keyEvent->SetSourceType(InputEvent::SOURCE_TYPE_JOYSTICK);
195 keyEvent->SetKeyCode(button.GetKeyCode());
196 keyEvent->SetKeyAction(button.IsPressed() ? KeyEvent::KEY_ACTION_DOWN : KeyEvent::KEY_ACTION_UP);
197 if (keyEvent->GetPressedKeys().empty()) {
198 keyEvent->SetActionStartTime(time);
199 }
200 keyEvent->SetRepeat(false);
201
202 KeyEvent::KeyItem keyItem {};
203 keyItem.SetDownTime(time);
204 keyItem.SetKeyCode(button.GetKeyCode());
205 keyItem.SetDeviceId(deviceId_);
206 keyItem.SetPressed(button.IsPressed());
207 keyItem.SetUnicode(KeyCodeToUnicode(button.GetKeyCode(), keyEvent));
208
209 if (!keyItem.IsPressed()) {
210 auto tItem = keyEvent->GetKeyItem(keyItem.GetKeyCode());
211 if (tItem) {
212 keyItem.SetDownTime(tItem->GetDownTime());
213 }
214 keyEvent->RemoveReleasedKeyItems(keyItem);
215 }
216 keyEvent->AddPressedKeyItems(keyItem);
217 keyEvent->SetKeyIntention(
218 KeyItemsTransKeyIntention({ keyItem }));
219 keyEvent->UpdateId();
220 return keyEvent;
221 }
222
CleanUpKeyEvent()223 std::shared_ptr<KeyEvent> JoystickEventProcessor::CleanUpKeyEvent()
224 {
225 if (keyEvent_ == nullptr) {
226 keyEvent_ = KeyEvent::Create();
227 CHKPP(keyEvent_);
228 }
229 for (const auto &keyItem : keyEvent_->GetKeyItems()) {
230 if (!keyItem.IsPressed()) {
231 keyEvent_->RemoveReleasedKeyItems(keyItem);
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