1- #include " pch.h"
1+ #include " ../AhkDll/IbAhkSend.hpp"
2+ using namespace Send ;
3+
4+ #define BOOST_TEST_MODULE AhkDll.Test
5+ #include < boost/test/unit_test.hpp>
6+ #include < fmt/core.h>
7+
28#include < thread>
39#include < mutex>
10+ #include < future>
411#include < queue>
5- #include < fmt/core.h>
6- #include " CppUnitTest.h"
7-
812#include < IbWinCppLib/WinCppLib.hpp>
9- #include " ../AhkDll/IbAhkSend.hpp"
1013
11- using namespace Microsoft ::VisualStudio::CppUnitTestFramework;
1214
1315class Measure {
1416 LARGE_INTEGER t;
@@ -31,40 +33,28 @@ class Measure {
3133 }
3234};
3335
34- void send_init (Send::SendType type, Send::InitFlags flags = 0 , void * argument = nullptr ) {
35- // cannot be put in TEST_MODULE_INITIALIZE for unknown reason
36- Send::Error error = IbAhkSendInit (type, flags, argument);
37- Assert::AreEqual ((uint32_t )Send::Error::Success, (uint32_t )error);
38- }
36+ template <SendType TypeV>
37+ class InitTest {
38+ public:
39+ InitTest () {
40+ Send::Error error = IbAhkSendInit (TypeV, 0 , nullptr );
41+ BOOST_REQUIRE (error == Send::Error::Success);
42+ }
3943
40- class KeyboardTestBase
44+ ~InitTest () {
45+ IbAhkSendDestroy ();
46+ }
47+ };
48+
49+ template <SendType TypeV>
50+ class KeyboardTest : public InitTest <TypeV>
4151{
42- public:
4352 static inline HHOOK hook;
4453 static inline bool capture;
4554 static inline std::queue<DWORD> input_keys;
4655 static inline std::mutex mutex;
4756
48- KeyboardTestBase () {
49- capture = false ;
50- std::thread t ([] {
51- hook = SetWindowsHookExW (WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle (0 ), 0 );
52- Assert::AreNotEqual<void *>(NULL , hook);
53-
54- MSG messages;
55- while (GetMessageW (&messages, NULL , 0 , 0 ))
56- {
57- TranslateMessage (&messages);
58- DispatchMessageW (&messages);
59- }
60- });
61- t.detach ();
62- }
63-
64- ~KeyboardTestBase () {
65- IbAhkSendDestroy ();
66- UnhookWindowsHookEx (hook);
67- }
57+ std::thread t;
6858
6959 static LRESULT CALLBACK LowLevelKeyboardProc (
7060 _In_ int nCode,
@@ -80,80 +70,90 @@ class KeyboardTestBase
8070 }
8171 return CallNextHookEx (hook, nCode, wParam, lParam);
8272 }
73+ public:
74+ KeyboardTest () {
75+ capture = false ;
76+ std::promise<HHOOK> pro;
77+ std::future<HHOOK> fut = pro.get_future ();
78+ t = std::thread ([](std::promise<HHOOK>&& pro) {
79+ pro.set_value (SetWindowsHookExW (WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle (0 ), 0 ));
80+
81+ MSG messages;
82+ while (GetMessageW (&messages, NULL , 0 , 0 ))
83+ {
84+ TranslateMessage (&messages);
85+ DispatchMessageW (&messages);
86+ }
87+ }, std::move (pro));
88+ hook = fut.get ();
89+ BOOST_REQUIRE (hook != NULL );
90+ }
91+
92+ ~KeyboardTest () {
93+ std::thread::id id = t.get_id ();
94+ PostThreadMessageW (*(DWORD*)(&id), WM_QUIT, 0 , 0 );
95+ UnhookWindowsHookEx (hook);
96+ input_keys = {};
97+
98+ t.join ();
99+ }
83100
84- void MeasureKeyboardLatency () {
101+ void TestKeyboardLatency () {
85102 Measure measure;
86103
87- measure.begin ();
88- {
89- INPUT input[2 ];
104+ INPUT input[2 ];
90105
91- input[0 ].type = INPUT_KEYBOARD;
92- input[0 ].ki = {};
93- input[0 ].ki .wVk = VK_F12;
106+ input[0 ].type = INPUT_KEYBOARD;
107+ input[0 ].ki = {};
108+ input[0 ].ki .wVk = VK_F12;
94109
95- input[1 ].type = INPUT_KEYBOARD;
96- input[1 ].ki = {};
97- input[1 ].ki .wVk = VK_F12;
98- input[1 ].ki .dwFlags = KEYEVENTF_KEYUP;
110+ input[1 ].type = INPUT_KEYBOARD;
111+ input[1 ].ki = {};
112+ input[1 ].ki .wVk = VK_F12;
113+ input[1 ].ki .dwFlags = KEYEVENTF_KEYUP;
99114
100- capture = true ;
101- IbAhkSendInput ( 2 , input, sizeof INPUT );
102- }
115+ capture = true ;
116+ measure. begin ( );
117+ IbAhkSendInput ( 2 , input, sizeof INPUT);
103118 uint64_t t1 = measure.end ();
104-
119+
105120 measure.begin ();
106121 {
107122 while (input_keys.size () < 2 )
108123 _mm_pause ();
109124 capture = false ;
110125 }
111126 uint64_t t2 = measure.end ();
112- // SendInput: 600ns (0) //#TODO: bug for unknown reason
113- // Logitech: 0.8~4ms
114127
115128 {
116129 std::lock_guard lock (mutex);
117- Assert::AreEqual<DWORD>(VK_F12, input_keys.back ());
130+ BOOST_CHECK ( input_keys.back () == VK_F12 );
118131 input_keys.pop ();
119- Assert::AreEqual<DWORD>(VK_F12, input_keys.back ());
132+ BOOST_CHECK ( input_keys.back () == VK_F12 );
120133 input_keys.pop ();
121134 }
122135
123- Logger::WriteMessage (fmt::format (" Duration: {}ns\n " , t1).c_str ());
124- Logger::WriteMessage (fmt::format (" Latency: {}ns\n " , t2).c_str ());
136+ BOOST_TEST_MESSAGE (fmt::format (" Duration: {}ns\n " , t1));
137+ // SendInput: 1~3ms
138+ // Logitech: 25~45us
139+ BOOST_TEST_MESSAGE (fmt::format (" Latency: {}ns\n " , t2));
140+ // SendInput: 100ns (0)
141+ // Logitech: 0.8~4ms
125142 }
126143};
127144
128- #define CODE_GENERATE_KEYBOARDTEST (type ) \
129- TEST_CLASS (KeyboardTest), private KeyboardTestBase { \
130- using base = KeyboardTestBase; \
131- public: \
132- KeyboardTest () { \
133- send_init (Send::SendType::type); \
134- } \
135- \
136- TEST_METHOD (MeasureKeyboardLatency) { \
137- base::MeasureKeyboardLatency (); \
138- } \
139- };
140-
141- class MouseTestBase {
145+ template <SendType TypeV>
146+ class MouseTest : public InitTest <TypeV> {
142147public:
143- MouseTestBase () {}
144-
145- ~MouseTestBase () {
146- IbAhkSendDestroy ();
147- }
148-
149- void MeasureMouseMoveDuration () {
150- Measure t;
151-
152- t.begin ();
148+ void TestMouseMove () {
149+ Measure measure;
150+
153151 INPUT input;
154152 input.type = INPUT_MOUSE;
155153 input.mi = {};
156154 input.mi .dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_MOVE_NOCOALESCE;
155+
156+ measure.begin ();
157157 for (size_t i = 0 ; i < 10000 / 200 ; i++) {
158158 input.mi .dx = input.mi .dy = 1 ;
159159 for (size_t i = 0 ; i < 100 ; i++)
@@ -163,13 +163,37 @@ class MouseTestBase {
163163 for (size_t i = 0 ; i < 100 ; i++)
164164 IbAhkSendInput (1 , &input, sizeof INPUT);
165165 }
166- uint64_t d = t .end ();
167- Logger::WriteMessage (fmt::format (" {}ns\n " , d / 10000 ). c_str ( ));
168- // SendInput: 245us
169- // Logitech: 3us
166+ uint64_t t = measure .end ();
167+ BOOST_TEST_MESSAGE (fmt::format (" Duration: {}ns\n " , t / 10000 ));
168+ // SendInput: 200~800us
169+ // Logitech: 3~10us
170170 }
171171
172- void MeasureMouseMovement () {
172+ void TestMouseMoveLatency () {
173+ Measure measure;
174+
175+ POINT p1, p2, d;
176+ GetCursorPos (&p1);
177+
178+ INPUT input;
179+ input.type = INPUT_MOUSE;
180+ input.mi = {};
181+ input.mi .dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_MOVE_NOCOALESCE;
182+ input.mi .dx = input.mi .dy = 100 ;
183+ IbAhkSendInput (1 , &input, sizeof INPUT);
184+
185+ measure.begin ();
186+ do {
187+ GetCursorPos (&p2);
188+ d = { p2.x - p1.x , p2.y - p1.y };
189+ } while (!(d.x >= 50 && d.y >= 50 ));
190+ uint64_t latency = measure.end ();
191+ BOOST_TEST_MESSAGE (fmt::format (" Latency: {}ns\n " , latency));
192+ // SendInput: 3~200us
193+ // Logitech: 900~4000us (0.9~4ms)
194+ }
195+
196+ void TestMouseMoveDistance () {
173197 POINT p1, p2, d1, d2;
174198 GetCursorPos (&p1);
175199
@@ -187,43 +211,37 @@ class MouseTestBase {
187211
188212 GetCursorPos (&p2);
189213 d2 = { p2.x - p1.x , p2.y - p1.y };
214+ BOOST_CHECK ((abs (d2.x - 100 ) <= 10 && abs (d2.y - 100 ) <= 100 ));
190215
191- Logger::WriteMessage (fmt::format (" 0ms: ({}, {})\n " , d1.x , d1.y ). c_str ( ));
192- Logger::WriteMessage (fmt::format (" 10ms: ({}, {})\n " , d2.x , d2.y ). c_str ( ));
216+ BOOST_TEST_MESSAGE (fmt::format (" 0ms: ({}, {})\n " , d1.x , d1.y ));
217+ BOOST_TEST_MESSAGE (fmt::format (" 10ms: ({}, {})\n " , d2.x , d2.y ));
193218 }
194219};
195220
196- #define CODE_GENERATE_MOUSETEST ( type ) \
197- TEST_CLASS (MouseTest), private MouseTestBase { \
198- using base = MouseTestBase; \
199- public: \
200- MouseTest ( ) { \
201- send_init (Send::SendType::type ); \
221+ #define CODE_GENERATE_TEST_NAME ( name, type ) \
222+ BOOST_AUTO_TEST_SUITE (name) \
223+ BOOST_FIXTURE_TEST_SUITE(Keyboard, KeyboardTest<SendType::type>) \
224+ using base = BOOST_AUTO_TEST_CASE_FIXTURE; \
225+ BOOST_AUTO_TEST_CASE (TestKeyboardLatency ) { \
226+ base::TestKeyboardLatency ( ); \
202227 } \
203- \
204- TEST_METHOD (MeasureMouseMoveDuration) { \
205- base::MeasureMouseMoveDuration (); \
228+ BOOST_AUTO_TEST_SUITE_END () \
229+ \
230+ BOOST_FIXTURE_TEST_SUITE(Mouse, MouseTest<SendType::type>) \
231+ using base = BOOST_AUTO_TEST_CASE_FIXTURE; \
232+ BOOST_AUTO_TEST_CASE (TestMouseMove) { \
233+ base::TestMouseMove (); \
206234 } \
207- \
208- TEST_METHOD (MeasureMouseMovement) { \
209- base::MeasureMouseMovement (); \
235+ BOOST_AUTO_TEST_CASE (TestMouseMoveLatency) { \
236+ base::TestMouseMoveLatency (); \
210237 } \
211- };
212-
213- namespace AnyDriverTest
214- {
215- CODE_GENERATE_KEYBOARDTEST (AnyDriver)
216- CODE_GENERATE_MOUSETEST (AnyDriver)
217- }
218-
219- namespace SendInputTest
220- {
221- CODE_GENERATE_KEYBOARDTEST (SendInput)
222- CODE_GENERATE_MOUSETEST (SendInput)
223- }
238+ BOOST_AUTO_TEST_CASE (TestMouseMoveDistance) { \
239+ base::TestMouseMoveDistance (); \
240+ } \
241+ BOOST_AUTO_TEST_SUITE_END () \
242+ BOOST_AUTO_TEST_SUITE_END()
243+ #define CODE_GENERATE_TEST (type ) CODE_GENERATE_TEST_NAME(type, type)
224244
225- namespace LogitechTest
226- {
227- CODE_GENERATE_KEYBOARDTEST (Logitech)
228- CODE_GENERATE_MOUSETEST (Logitech)
229- }
245+ CODE_GENERATE_TEST_NAME (SendInput_, SendInput)
246+ CODE_GENERATE_TEST(AnyDriver)
247+ CODE_GENERATE_TEST(Logitech)
0 commit comments