• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include <cctype>
16 #include <gtest/gtest.h>
17 #include <thread>
18 #include "mmi_log.h"
19 #include "virtual_pen.h"
20 
21 namespace OHOS {
22 namespace MMI {
23 namespace {
24 using namespace testing::ext;
25 using namespace OHOS::MMI;
26 constexpr OHOS::HiviewDFX::HiLogLabel LABEL { LOG_CORE, MMI_LOG_DOMAIN, "TransformPointTest" };
27 constexpr int32_t WAIT_TIME_FOR_INPUT { 1000 };
28 constexpr int32_t WAIT_TIME_FOR_EVENTS { 10 };
29 constexpr size_t DEFAULT_BUF_SIZE { 4096 };
30 } // namespace
31 
32 #define ARRAY_LENGTH(arr)   (sizeof(arr) / sizeof((arr)[0]))
33 
34 class Context {
35 public:
36     explicit Context(const std::string& node);
37     ~Context();
38     bool IsReady() const;
39     int GetFd() const;
40 
41 private:
42     std::string node_;
43     int fd_ { -1 };
44 };
45 
Context(const std::string & node)46 Context::Context(const std::string& node)
47     : node_(node)
48 {
49     MMI_HILOGD("Open device node: \'%{public}s\'.", node_.c_str());
50     fd_ = open(node_.c_str(), O_RDWR);
51     if (fd_ < 0) {
52         MMI_HILOGE("Failed to open device node: \'%{public}s\'.", node_.c_str());
53     }
54 }
55 
~Context()56 Context::~Context()
57 {
58     if (fd_ >= 0) {
59         close(fd_);
60     }
61 }
62 
IsReady() const63 inline bool Context::IsReady() const
64 {
65     return (fd_ >= 0);
66 }
67 
GetFd() const68 inline int Context::GetFd() const
69 {
70     return fd_;
71 }
72 
73 class TransformPointTest : public testing::Test {
74 public:
75     static void SetUpTestCase(void);
76     static void TearDownTestCase(void);
77     static std::string GetDeviceNodeName();
78     static int Execute(const std::string& command, std::vector<std::string>& results);
79     static void GetInputDeviceNodes(std::map<std::string, std::string>& nodes);
80     static bool SetupVirtualStylus();
81     static bool IsVirtualStylusOn();
82     bool SendEvent(const Context& ctx, struct input_event* event);
83     bool SendEvents(const Context& ctx, struct input_event* events, size_t nevents);
84 
85 private:
86     static VirtualPen virtualPen_;
87     static std::string  devNode_;
88 };
89 
90 VirtualPen TransformPointTest::virtualPen_;
91 std::string TransformPointTest::devNode_;
92 
SetUpTestCase(void)93 void TransformPointTest::SetUpTestCase(void)
94 {
95     SetupVirtualStylus();
96 }
97 
TearDownTestCase(void)98 void TransformPointTest::TearDownTestCase(void)
99 {
100     if (!devNode_.empty()) {
101         virtualPen_.Close();
102         devNode_.clear();
103     }
104 }
105 
GetDeviceNodeName()106 std::string TransformPointTest::GetDeviceNodeName()
107 {
108     return devNode_;
109 }
110 
SendEvent(const Context & ctx,struct input_event * event)111 bool TransformPointTest::SendEvent(const Context& ctx, struct input_event* event)
112 {
113     CALL_INFO_TRACE;
114     MMI_HILOGD("Send input event.");
115     struct timeval tv;
116     if (gettimeofday(&tv, nullptr)) {
117         MMI_HILOGE("Failed to get current time.");
118         return false;
119     }
120     event->input_event_sec = tv.tv_sec;
121     event->input_event_usec = tv.tv_usec;
122 
123     const int fd = ctx.GetFd();
124     ssize_t ret = write(fd, event, sizeof(*event));
125     return (ret > 0);
126 }
127 
SendEvents(const Context & ctx,struct input_event * events,size_t nevents)128 bool TransformPointTest::SendEvents(const Context& ctx, struct input_event* events, size_t nevents)
129 {
130     CALL_INFO_TRACE;
131     if (!ctx.IsReady()) {
132         MMI_HILOGE("Device is not ready.");
133         return false;
134     }
135     MMI_HILOGD("%{public}zu input events to send.", nevents);
136     struct input_event* sp = events;
137     struct input_event* tp = sp + nevents;
138     for (; sp < tp; ++sp) {
139         if (!SendEvent(ctx, sp)) {
140             MMI_HILOGE("Failed to send event.");
141             break;
142         }
143         std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_TIME_FOR_EVENTS));
144     }
145     return (sp >= tp);
146 }
147 
Execute(const std::string & command,std::vector<std::string> & results)148 int TransformPointTest::Execute(const std::string& command, std::vector<std::string>& results)
149 {
150     CALL_INFO_TRACE;
151     MMI_HILOGD("Execute command:%{public}s.", command.c_str());
152     char buffer[DEFAULT_BUF_SIZE] {};
153     FILE* pin = popen(command.c_str(), "r");
154     if (!pin) {
155         MMI_HILOGE("Failed to popen command.");
156         return -1;
157     }
158     while (!feof(pin)) {
159         if (fgets(buffer, sizeof(buffer), pin) != nullptr) {
160             results.push_back(buffer);
161         }
162     }
163     MMI_HILOGD("Close phandle.");
164     return pclose(pin);
165 }
166 
GetInputDeviceNodes(std::map<std::string,std::string> & nodes)167 void TransformPointTest::GetInputDeviceNodes(std::map<std::string, std::string>& nodes)
168 {
169     CALL_INFO_TRACE;
170     std::string command { "cat /proc/bus/input/devices" };
171     std::vector<std::string> results;
172     Execute(command, results);
173     if (results.empty()) {
174         MMI_HILOGE("Failed to list devices.");
175         return;
176     }
177     const std::string kname { "Name=\"" };
178     const std::string kevent { "event" };
179     std::string name;
180     for (const auto &item : results) {
181         MMI_HILOGD("item:%{public}s.", item.c_str());
182         if (item[0] == 'N') {
183             std::string::size_type spos = item.find(kname);
184             if (spos != std::string::npos) {
185                 spos += kname.size();
186                 std::string::size_type tpos = item.find("\"", spos);
187                 if (tpos != std::string::npos) {
188                     name = item.substr(spos, tpos - spos);
189                 }
190             }
191         } else if (!name.empty() && (item[0] == 'H')) {
192             std::string::size_type spos = item.find(kevent);
193             if (spos != std::string::npos) {
194                 std::map<std::string, std::string>::const_iterator cItr = nodes.find(name);
195                 if (cItr != nodes.end()) {
196                     nodes.erase(cItr);
197                 }
198                 std::string::size_type tpos = spos + kevent.size();
199                 while (std::isalnum(item[tpos])) {
200                     ++tpos;
201                 }
202                 nodes.emplace(name, item.substr(spos, tpos - spos));
203                 name.clear();
204             }
205         }
206     }
207 }
208 
SetupVirtualStylus()209 bool TransformPointTest::SetupVirtualStylus()
210 {
211     CALL_INFO_TRACE;
212     MMI_HILOGD("Setup virtual stylus.");
213     if (!virtualPen_.SetUp()) {
214         MMI_HILOGE("Failed to setup virtual stylus.");
215         return false;
216     }
217     std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_TIME_FOR_INPUT));
218 
219     std::map<std::string, std::string> nodes;
220     GetInputDeviceNodes(nodes);
221     MMI_HILOGD("There are %{public}zu device nodes.", nodes.size());
222 
223     const std::string dev { "V-Pencil" };
224     std::map<std::string, std::string>::const_iterator cItr = nodes.find(dev);
225     if (cItr == nodes.cend()) {
226         MMI_HILOGE("No virtual stylus is found.");
227         return false;
228     }
229     MMI_HILOGD("Node name : \'%{public}s\'.", cItr->second.c_str());
230     std::ostringstream ss;
231     ss << "/dev/input/" << cItr->second;
232     devNode_ = ss.str();
233     return true;
234 }
235 
IsVirtualStylusOn()236 bool TransformPointTest::IsVirtualStylusOn()
237 {
238     return !devNode_.empty();
239 }
240 
241 static struct input_event inputEvents1[] {
242     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               7950   },
243     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_Y,               6400   },
244     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_TILT_X,          10     },
245     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_TILT_Y,          -10    },
246     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        30     },
247     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
248     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               8000   },
249     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        30     },
250     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
251     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               8050   },
252     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_Y,               6450   },
253     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        35     },
254     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
255     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               8100   },
256     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_Y,               6500   },
257     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        1510   },
258     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
259     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               8150   },
260     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        1520   },
261     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
262     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               8200   },
263     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_Y,               6550   },
264     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        1530   },
265     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
266     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               8200   },
267     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_Y,               6550   },
268     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        0      },
269     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
270 };
271 
272 /**
273  * @tc.name:MultimodalEventHandler_InjectKeyEvent_001
274  * @tc.desc:Verify inject key Back
275  * @tc.type: FUNC
276  * @tc.require:
277  */
278 HWTEST_F(TransformPointTest, TabletTransformPointProcesser1, TestSize.Level1)
279 {
280     CALL_INFO_TRACE;
281     ASSERT_TRUE(IsVirtualStylusOn());
282     Context ctx { GetDeviceNodeName() };
283     ASSERT_TRUE(SendEvents(ctx, inputEvents1, ARRAY_LENGTH(inputEvents1)));
284 }
285 
286 static struct input_event inputEvents2[] {
287     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               10752  },
288     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_Y,               22176  },
289     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_TILT_X,          90     },
290     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_TILT_Y,          90     },
291     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        0      },
292     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
293     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               10753  },
294     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_TILT_X,          -90    },
295     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
296     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_Y,               22177  },
297     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_TILT_Y,          -90    },
298     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        50     },
299     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
300     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_TILT_X,          90     },
301     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        1510   },
302     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
303     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               40000  },
304     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_TILT_X,          180    },
305     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        4096   },
306     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
307     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               50000  },
308     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_TILT_X,          270    },
309     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        100000 },
310     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
311     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_X,               60000  },
312     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_Y,               6550   },
313     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_TILT_X,          360    },
314     { .input_event_sec = 0, .input_event_usec = 0, EV_ABS, ABS_PRESSURE,        0      },
315     { .input_event_sec = 0, .input_event_usec = 0, EV_SYN, SYN_REPORT,          0      },
316 };
317 
318 HWTEST_F(TransformPointTest, TabletTransformPointProcesser2, TestSize.Level1)
319 {
320     CALL_INFO_TRACE;
321     ASSERT_TRUE(IsVirtualStylusOn());
322     Context ctx { GetDeviceNodeName() };
323     ASSERT_TRUE(SendEvents(ctx, inputEvents2, ARRAY_LENGTH(inputEvents2)));
324 }
325 } // namespace MMI
326 } // namespace OHOS
327