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