ui_controls_internal_win.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/base/test/ui_controls_internal_win.h"
  5. #include <windows.h>
  6. #include <algorithm>
  7. #include <cmath>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/callback.h"
  11. #include "base/location.h"
  12. #include "base/logging.h"
  13. #include "base/task/single_thread_task_runner.h"
  14. #include "base/test/test_timeouts.h"
  15. #include "base/threading/thread_checker.h"
  16. #include "base/threading/thread_task_runner_handle.h"
  17. #include "base/win/win_util.h"
  18. #include "ui/base/win/event_creation_utils.h"
  19. #include "ui/display/win/screen_win.h"
  20. #include "ui/events/keycodes/keyboard_code_conversion_win.h"
  21. #include "ui/events/keycodes/keyboard_codes.h"
  22. #include "ui/gfx/geometry/point.h"
  23. namespace {
  24. // InputDispatcher ------------------------------------------------------------
  25. // InputDispatcher is used to listen for a mouse/keyboard event. Only one
  26. // instance may be alive at a time. The callback is run when the appropriate
  27. // event is received.
  28. class InputDispatcher {
  29. public:
  30. // Constructs an InputDispatcher that will invoke |callback| when
  31. // |message_type| is received. This must be invoked on thread, after the input
  32. // is sent but before it is processed.
  33. static void CreateForMouseEvent(base::OnceClosure callback,
  34. WPARAM message_type);
  35. // Special case of CreateForMessage() for WM_KEYUP (can await multiple events
  36. // when modifiers are involved).
  37. static void CreateForKeyUp(base::OnceClosure callback,
  38. int num_keyups_awaited);
  39. // Special case of CreateForMessage() for WM_MOUSEMOVE. Upon receipt, an error
  40. // message is logged if the destination of the move is not |screen_point|.
  41. // |callback| is run regardless after a sufficiently long delay. This
  42. // generally happens when another process has a window over the test's window,
  43. // or if |screen_point| is not over a window owned by the test.
  44. static void CreateForMouseMove(base::OnceClosure callback,
  45. const gfx::Point& screen_point);
  46. InputDispatcher(const InputDispatcher&) = delete;
  47. InputDispatcher& operator=(const InputDispatcher&) = delete;
  48. private:
  49. // Generic message
  50. InputDispatcher(base::OnceClosure callback,
  51. WPARAM message_waiting_for,
  52. UINT system_queue_flag);
  53. // WM_KEYUP
  54. InputDispatcher(base::OnceClosure callback,
  55. WPARAM message_waiting_for,
  56. UINT system_queue_flag,
  57. int num_keyups_awaited);
  58. // WM_MOUSEMOVE
  59. InputDispatcher(base::OnceClosure callback,
  60. WPARAM message_waiting_for,
  61. UINT system_queue_flag,
  62. const gfx::Point& screen_point);
  63. ~InputDispatcher();
  64. // Installs the dispatcher as the current hook.
  65. void InstallHook();
  66. // Callback from hook when a mouse message is received.
  67. static LRESULT CALLBACK MouseHook(int n_code, WPARAM w_param, LPARAM l_param);
  68. // Callback from hook when a key message is received.
  69. static LRESULT CALLBACK KeyHook(int n_code, WPARAM w_param, LPARAM l_param);
  70. // Invoked from the hook. If |message_id| matches message_waiting_for_
  71. // MatchingMessageProcessed() is invoked. |mouse_hook_struct| contains extra
  72. // information about the mouse event.
  73. void DispatchedMessage(UINT message_id,
  74. const MOUSEHOOKSTRUCT* mouse_hook_struct);
  75. // Invoked when a matching event is found. Must be invoked through a task
  76. // posted from the hook so that the event, which is processed after the hook,
  77. // has already been handled.
  78. // |definitively_done| is set to true if this event is definitely the one we
  79. // were waiting for (i.e., we will resume regardless of the presence of
  80. // |system_queue_flag_| messages in the queue).
  81. void MatchingMessageProcessed(bool definitively_done);
  82. // Invoked when the hook for a mouse move is not called within a reasonable
  83. // time. This likely means that a window from another process is over a test
  84. // window, so the event does not reach this process.
  85. void OnTimeout();
  86. // The current dispatcher if a hook is installed; otherwise, nullptr;
  87. static InputDispatcher* current_dispatcher_;
  88. // Return value from SetWindowsHookEx.
  89. static HHOOK next_hook_;
  90. THREAD_CHECKER(thread_checker_);
  91. // The callback to run when the desired message is received.
  92. base::OnceClosure callback_;
  93. // The message on which the instance is waiting -- unused for WM_KEYUP
  94. // messages.
  95. const WPARAM message_waiting_for_;
  96. // The system queue flag (ref. ::GetQueueStatus) which the awaited event is
  97. // reflected in.
  98. const UINT system_queue_flag_;
  99. // The number of WM_KEYUP messages to receive before dispatching |callback_|.
  100. // Only relevant when |message_waiting_for_| is WM_KEYUP.
  101. int num_keyups_awaited_ = 0;
  102. // The desired mouse position for a mouse move event.
  103. const gfx::Point expected_mouse_location_;
  104. base::WeakPtrFactory<InputDispatcher> weak_factory_{this};
  105. };
  106. // static
  107. InputDispatcher* InputDispatcher::current_dispatcher_ = nullptr;
  108. // static
  109. HHOOK InputDispatcher::next_hook_ = nullptr;
  110. // static
  111. void InputDispatcher::CreateForMouseEvent(base::OnceClosure callback,
  112. WPARAM message_type) {
  113. DCHECK(message_type == WM_LBUTTONDOWN || message_type == WM_LBUTTONUP ||
  114. message_type == WM_MBUTTONDOWN || message_type == WM_MBUTTONUP ||
  115. message_type == WM_RBUTTONDOWN || message_type == WM_RBUTTONUP)
  116. << message_type;
  117. // Owns self.
  118. new InputDispatcher(std::move(callback), message_type, QS_MOUSEBUTTON);
  119. }
  120. // static
  121. void InputDispatcher::CreateForKeyUp(base::OnceClosure callback,
  122. int num_keyups_awaited) {
  123. // Owns self.
  124. new InputDispatcher(std::move(callback), WM_KEYUP, QS_KEY,
  125. num_keyups_awaited);
  126. }
  127. // static
  128. void InputDispatcher::CreateForMouseMove(base::OnceClosure callback,
  129. const gfx::Point& screen_point) {
  130. // Owns self.
  131. new InputDispatcher(std::move(callback), WM_MOUSEMOVE, QS_MOUSEMOVE,
  132. screen_point);
  133. }
  134. InputDispatcher::InputDispatcher(base::OnceClosure callback,
  135. WPARAM message_waiting_for,
  136. UINT system_queue_flag)
  137. : callback_(std::move(callback)),
  138. message_waiting_for_(message_waiting_for),
  139. system_queue_flag_(system_queue_flag) {
  140. InstallHook();
  141. }
  142. InputDispatcher::InputDispatcher(base::OnceClosure callback,
  143. WPARAM message_waiting_for,
  144. UINT system_queue_flag,
  145. int num_keyups_awaited)
  146. : callback_(std::move(callback)),
  147. message_waiting_for_(message_waiting_for),
  148. system_queue_flag_(system_queue_flag),
  149. num_keyups_awaited_(num_keyups_awaited) {
  150. DCHECK_EQ(message_waiting_for_, static_cast<WPARAM>(WM_KEYUP));
  151. InstallHook();
  152. }
  153. InputDispatcher::InputDispatcher(base::OnceClosure callback,
  154. WPARAM message_waiting_for,
  155. UINT system_queue_flag,
  156. const gfx::Point& screen_point)
  157. : callback_(std::move(callback)),
  158. message_waiting_for_(message_waiting_for),
  159. system_queue_flag_(system_queue_flag),
  160. expected_mouse_location_(screen_point) {
  161. DCHECK_EQ(message_waiting_for_, static_cast<WPARAM>(WM_MOUSEMOVE));
  162. InstallHook();
  163. }
  164. InputDispatcher::~InputDispatcher() {
  165. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  166. DCHECK_EQ(current_dispatcher_, this);
  167. current_dispatcher_ = nullptr;
  168. UnhookWindowsHookEx(next_hook_);
  169. next_hook_ = nullptr;
  170. }
  171. void InputDispatcher::InstallHook() {
  172. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  173. DCHECK(!current_dispatcher_);
  174. current_dispatcher_ = this;
  175. int hook_type;
  176. HOOKPROC hook_function;
  177. if (message_waiting_for_ == WM_KEYUP) {
  178. hook_type = WH_KEYBOARD;
  179. hook_function = &KeyHook;
  180. } else {
  181. // WH_CALLWNDPROCRET does not generate mouse messages for some reason.
  182. hook_type = WH_MOUSE;
  183. hook_function = &MouseHook;
  184. if (message_waiting_for_ == WM_MOUSEMOVE) {
  185. // Things don't go well with move events sometimes. Bail out if it takes
  186. // too long.
  187. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  188. FROM_HERE,
  189. base::BindOnce(&InputDispatcher::OnTimeout,
  190. weak_factory_.GetWeakPtr()),
  191. TestTimeouts::action_timeout());
  192. }
  193. }
  194. next_hook_ =
  195. SetWindowsHookEx(hook_type, hook_function, nullptr, GetCurrentThreadId());
  196. DPCHECK(next_hook_);
  197. }
  198. // static
  199. LRESULT CALLBACK InputDispatcher::MouseHook(int n_code,
  200. WPARAM w_param,
  201. LPARAM l_param) {
  202. HHOOK next_hook = next_hook_;
  203. if (n_code == HC_ACTION) {
  204. DCHECK(current_dispatcher_);
  205. current_dispatcher_->DispatchedMessage(
  206. static_cast<UINT>(w_param),
  207. reinterpret_cast<MOUSEHOOKSTRUCT*>(l_param));
  208. }
  209. return CallNextHookEx(next_hook, n_code, w_param, l_param);
  210. }
  211. // static
  212. LRESULT CALLBACK InputDispatcher::KeyHook(int n_code,
  213. WPARAM w_param,
  214. LPARAM l_param) {
  215. if ((n_code == HC_ACTION) && (HIWORD(l_param) & KF_UP)) {
  216. DCHECK(current_dispatcher_);
  217. base::ThreadTaskRunnerHandle::Get()->PostTask(
  218. FROM_HERE,
  219. base::BindOnce(&InputDispatcher::MatchingMessageProcessed,
  220. current_dispatcher_->weak_factory_.GetWeakPtr(), false));
  221. }
  222. return CallNextHookEx(next_hook_, n_code, w_param, l_param);
  223. }
  224. void InputDispatcher::DispatchedMessage(
  225. UINT message_id,
  226. const MOUSEHOOKSTRUCT* mouse_hook_struct) {
  227. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  228. if (message_id == message_waiting_for_) {
  229. bool definitively_done = false;
  230. if (message_id == WM_MOUSEMOVE) {
  231. // Allow a slight offset, targets are never one pixel wide and pixel math
  232. // is imprecise (see SendMouseMoveImpl()).
  233. gfx::Point actual_location(mouse_hook_struct->pt);
  234. auto offset = expected_mouse_location_ - actual_location;
  235. definitively_done = std::abs(offset.x()) + std::abs(offset.y()) < 2;
  236. // Verify that the mouse ended up at the desired location.
  237. LOG_IF(ERROR, !definitively_done)
  238. << "Mouse moved to (" << mouse_hook_struct->pt.x << ", "
  239. << mouse_hook_struct->pt.y << ") rather than ("
  240. << expected_mouse_location_.x() << ", "
  241. << expected_mouse_location_.y()
  242. << "); check the math in SendMouseMoveImpl.";
  243. }
  244. base::ThreadTaskRunnerHandle::Get()->PostTask(
  245. FROM_HERE,
  246. base::BindOnce(&InputDispatcher::MatchingMessageProcessed,
  247. weak_factory_.GetWeakPtr(), definitively_done));
  248. } else if ((message_waiting_for_ == WM_LBUTTONDOWN &&
  249. message_id == WM_LBUTTONDBLCLK) ||
  250. (message_waiting_for_ == WM_MBUTTONDOWN &&
  251. message_id == WM_MBUTTONDBLCLK) ||
  252. (message_waiting_for_ == WM_RBUTTONDOWN &&
  253. message_id == WM_RBUTTONDBLCLK)) {
  254. LOG(WARNING) << "Double click event being treated as single-click. "
  255. << "This may result in different event processing behavior. "
  256. << "If you need a single click try moving the mouse between "
  257. << "down events.";
  258. base::ThreadTaskRunnerHandle::Get()->PostTask(
  259. FROM_HERE, base::BindOnce(&InputDispatcher::MatchingMessageProcessed,
  260. weak_factory_.GetWeakPtr(), false));
  261. }
  262. }
  263. void InputDispatcher::MatchingMessageProcessed(bool definitively_done) {
  264. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  265. if (message_waiting_for_ == WM_KEYUP && --num_keyups_awaited_ > 0)
  266. return;
  267. // Unless specified otherwise by |definitively_done| : resume on the last
  268. // event of its type only (instead of the first one) to prevent flakes when
  269. // InputDispatcher is created while there are preexisting matching events
  270. // remaining in the queue. Emit a warning to help diagnose flakes should the
  271. // queue somehow never become empty of such events.
  272. if (HIWORD(::GetQueueStatus(system_queue_flag_)) && !definitively_done) {
  273. LOG(WARNING)
  274. << "Skipping message notification per remaining events in the queue "
  275. "(will try again shortly) : "
  276. << system_queue_flag_;
  277. // Check back on the next loop instead of relying on the remaining event
  278. // being caught by our hooks (all events don't seem to reliably make it
  279. // there).
  280. if (message_waiting_for_ == WM_KEYUP)
  281. ++num_keyups_awaited_;
  282. base::ThreadTaskRunnerHandle::Get()->PostTask(
  283. FROM_HERE, base::BindOnce(&InputDispatcher::MatchingMessageProcessed,
  284. weak_factory_.GetWeakPtr(), false));
  285. return;
  286. }
  287. // Delete |this| before running the callback to allow callers to chain input
  288. // events.
  289. auto callback = std::move(callback_);
  290. delete this;
  291. std::move(callback).Run();
  292. }
  293. void InputDispatcher::OnTimeout() {
  294. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  295. LOG(ERROR) << "Timed out waiting for mouse move event. The test will now "
  296. "continue, but may fail.";
  297. auto callback = std::move(callback_);
  298. delete this;
  299. std::move(callback).Run();
  300. }
  301. // Private functions ----------------------------------------------------------
  302. UINT MapVirtualKeyToScanCode(UINT code) {
  303. UINT ret_code = MapVirtualKey(code, MAPVK_VK_TO_VSC);
  304. // We have to manually mark the following virtual
  305. // keys as extended or else their scancodes depend
  306. // on NumLock state.
  307. // For ex. VK_DOWN will be mapped onto either DOWN or NumPad2
  308. // depending on NumLock state which can lead to tests failures.
  309. switch (code) {
  310. case VK_INSERT:
  311. case VK_DELETE:
  312. case VK_HOME:
  313. case VK_END:
  314. case VK_NEXT:
  315. case VK_PRIOR:
  316. case VK_LEFT:
  317. case VK_RIGHT:
  318. case VK_UP:
  319. case VK_DOWN:
  320. case VK_NUMLOCK:
  321. ret_code |= KF_EXTENDED;
  322. break;
  323. default:
  324. break;
  325. }
  326. return ret_code;
  327. }
  328. // Whether scan code should be used for |key|.
  329. // When sending keyboard events by SendInput() function, Windows does not
  330. // "smartly" add scan code if virtual key-code is used. So these key events
  331. // won't have scan code or DOM UI Event code string.
  332. // But we cannot blindly send all events with scan code. For some layout
  333. // dependent keys, the Windows may not translate them to what they used to be,
  334. // because the test cases are usually running in headless environment with
  335. // default keyboard layout. So fall back to use virtual key code for these keys.
  336. bool ShouldSendThroughScanCode(ui::KeyboardCode key) {
  337. const DWORD native_code = ui::WindowsKeyCodeForKeyboardCode(key);
  338. const DWORD scan_code = MapVirtualKeyToScanCode(native_code);
  339. return native_code == MapVirtualKey(scan_code, MAPVK_VSC_TO_VK);
  340. }
  341. // Append an INPUT structure with the appropriate keyboard event
  342. // parameters required by SendInput
  343. void AppendKeyboardInput(ui::KeyboardCode key,
  344. bool key_up,
  345. std::vector<INPUT>* input) {
  346. INPUT key_input = {};
  347. key_input.type = INPUT_KEYBOARD;
  348. key_input.ki.wVk = ui::WindowsKeyCodeForKeyboardCode(key);
  349. if (ShouldSendThroughScanCode(key)) {
  350. key_input.ki.wScan = MapVirtualKeyToScanCode(key_input.ki.wVk);
  351. // When KEYEVENTF_SCANCODE is used, ki.wVk is ignored, so we do not need to
  352. // clear it.
  353. key_input.ki.dwFlags = KEYEVENTF_SCANCODE;
  354. if ((key_input.ki.wScan & 0xFF00) != 0)
  355. key_input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
  356. }
  357. if (key_up)
  358. key_input.ki.dwFlags |= KEYEVENTF_KEYUP;
  359. input->push_back(key_input);
  360. }
  361. // Append an INPUT structure with a simple mouse up or down event to be used
  362. // by SendInput.
  363. void AppendMouseInput(DWORD flags, std::vector<INPUT>* input) {
  364. INPUT mouse_input = {};
  365. mouse_input.type = INPUT_MOUSE;
  366. mouse_input.mi.dwFlags = flags;
  367. input->push_back(mouse_input);
  368. }
  369. // Append an INPUT array with optional accelerator keys that may be pressed
  370. // with a keyboard or mouse event. This array will be sent by SendInput.
  371. void AppendAcceleratorInputs(bool control,
  372. bool shift,
  373. bool alt,
  374. bool key_up,
  375. std::vector<INPUT>* input) {
  376. if (control)
  377. AppendKeyboardInput(ui::VKEY_CONTROL, key_up, input);
  378. if (alt)
  379. AppendKeyboardInput(ui::VKEY_LMENU, key_up, input);
  380. if (shift)
  381. AppendKeyboardInput(ui::VKEY_SHIFT, key_up, input);
  382. }
  383. } // namespace
  384. namespace ui_controls {
  385. namespace internal {
  386. bool SendKeyPressImpl(HWND window,
  387. ui::KeyboardCode key,
  388. bool control,
  389. bool shift,
  390. bool alt,
  391. base::OnceClosure task) {
  392. // SendInput only works as we expect it if one of our windows is the
  393. // foreground window already.
  394. HWND target_window = (::GetActiveWindow() &&
  395. ::GetWindow(::GetActiveWindow(), GW_OWNER) == window) ?
  396. ::GetActiveWindow() :
  397. window;
  398. if (window && ::GetForegroundWindow() != target_window)
  399. return false;
  400. // If a pop-up menu is open, it won't receive events sent using SendInput.
  401. // Check for a pop-up menu using its window class (#32768) and if one
  402. // exists, send the key event directly there.
  403. HWND popup_menu = ::FindWindow(L"#32768", 0);
  404. if (popup_menu != NULL && popup_menu == ::GetTopWindow(NULL)) {
  405. WPARAM w_param = ui::WindowsKeyCodeForKeyboardCode(key);
  406. LPARAM l_param = 0;
  407. ::SendMessage(popup_menu, WM_KEYDOWN, w_param, l_param);
  408. ::SendMessage(popup_menu, WM_KEYUP, w_param, l_param);
  409. if (task)
  410. InputDispatcher::CreateForKeyUp(std::move(task), 1);
  411. return true;
  412. }
  413. std::vector<INPUT> input;
  414. AppendAcceleratorInputs(control, shift, alt, false, &input);
  415. AppendKeyboardInput(key, false, &input);
  416. AppendKeyboardInput(key, true, &input);
  417. AppendAcceleratorInputs(control, shift, alt, true, &input);
  418. if (input.size() > std::numeric_limits<UINT>::max())
  419. return false;
  420. if (::SendInput(static_cast<UINT>(input.size()), input.data(),
  421. sizeof(INPUT)) != input.size()) {
  422. return false;
  423. }
  424. if (task)
  425. InputDispatcher::CreateForKeyUp(std::move(task), input.size() / 2);
  426. return true;
  427. }
  428. bool SendMouseMoveImpl(int screen_x, int screen_y, base::OnceClosure task) {
  429. gfx::Point screen_point =
  430. display::win::ScreenWin::DIPToScreenPoint({screen_x, screen_y});
  431. // Check if the mouse is already there.
  432. POINT current_pos;
  433. ::GetCursorPos(&current_pos);
  434. if (screen_point.x() == current_pos.x && screen_point.y() == current_pos.y) {
  435. if (task)
  436. base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(task));
  437. return true;
  438. }
  439. if (!ui::SendMouseEvent(screen_point,
  440. MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE)) {
  441. return false;
  442. }
  443. if (task)
  444. InputDispatcher::CreateForMouseMove(std::move(task),
  445. {screen_point.x(), screen_point.y()});
  446. return true;
  447. }
  448. bool SendMouseEventsImpl(MouseButton type,
  449. int button_state,
  450. base::OnceClosure task,
  451. int accelerator_state) {
  452. DWORD down_flags = MOUSEEVENTF_ABSOLUTE;
  453. DWORD up_flags = MOUSEEVENTF_ABSOLUTE;
  454. UINT last_event;
  455. switch (type) {
  456. case LEFT:
  457. down_flags |= MOUSEEVENTF_LEFTDOWN;
  458. up_flags |= MOUSEEVENTF_LEFTUP;
  459. last_event = (button_state & UP) ? WM_LBUTTONUP : WM_LBUTTONDOWN;
  460. break;
  461. case MIDDLE:
  462. down_flags |= MOUSEEVENTF_MIDDLEDOWN;
  463. up_flags |= MOUSEEVENTF_MIDDLEUP;
  464. last_event = (button_state & UP) ? WM_MBUTTONUP : WM_MBUTTONDOWN;
  465. break;
  466. case RIGHT:
  467. down_flags |= MOUSEEVENTF_RIGHTDOWN;
  468. up_flags |= MOUSEEVENTF_RIGHTUP;
  469. last_event = (button_state & UP) ? WM_RBUTTONUP : WM_RBUTTONDOWN;
  470. break;
  471. default:
  472. NOTREACHED();
  473. return false;
  474. }
  475. std::vector<INPUT> input;
  476. if (button_state & DOWN) {
  477. AppendAcceleratorInputs(accelerator_state & kControl,
  478. accelerator_state & kShift,
  479. accelerator_state & kAlt, false, &input);
  480. AppendMouseInput(down_flags, &input);
  481. }
  482. if (button_state & UP) {
  483. AppendMouseInput(up_flags, &input);
  484. AppendAcceleratorInputs(accelerator_state & kControl,
  485. accelerator_state & kShift,
  486. accelerator_state & kAlt, true, &input);
  487. }
  488. if (input.size() > std::numeric_limits<UINT>::max())
  489. return false;
  490. if (::SendInput(static_cast<UINT>(input.size()), input.data(),
  491. sizeof(INPUT)) != input.size()) {
  492. return false;
  493. }
  494. if (task)
  495. InputDispatcher::CreateForMouseEvent(std::move(task), last_event);
  496. return true;
  497. }
  498. bool SendTouchEventsImpl(int action, int num, int x, int y) {
  499. const int kTouchesLengthCap = 16;
  500. DCHECK_LE(num, kTouchesLengthCap);
  501. using InitializeTouchInjectionFn = BOOL(WINAPI*)(UINT32, DWORD);
  502. static const auto initialize_touch_injection =
  503. reinterpret_cast<InitializeTouchInjectionFn>(
  504. base::win::GetUser32FunctionPointer("InitializeTouchInjection"));
  505. if (!initialize_touch_injection ||
  506. !initialize_touch_injection(num, TOUCH_FEEDBACK_INDIRECT)) {
  507. return false;
  508. }
  509. using InjectTouchInputFn = BOOL(WINAPI*)(UINT32, POINTER_TOUCH_INFO*);
  510. static const auto inject_touch_input = reinterpret_cast<InjectTouchInputFn>(
  511. base::win::GetUser32FunctionPointer("InjectTouchInput"));
  512. if (!inject_touch_input)
  513. return false;
  514. POINTER_TOUCH_INFO pointer_touch_info[kTouchesLengthCap];
  515. for (int i = 0; i < num; i++) {
  516. POINTER_TOUCH_INFO& contact = pointer_touch_info[i];
  517. memset(&contact, 0, sizeof(POINTER_TOUCH_INFO));
  518. contact.pointerInfo.pointerType = PT_TOUCH;
  519. contact.pointerInfo.pointerId = i;
  520. contact.pointerInfo.ptPixelLocation.y = y;
  521. contact.pointerInfo.ptPixelLocation.x = x + 10 * i;
  522. contact.touchFlags = TOUCH_FLAG_NONE;
  523. contact.touchMask =
  524. TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE;
  525. contact.orientation = 90;
  526. contact.pressure = 32000;
  527. // defining contact area
  528. contact.rcContact.top = contact.pointerInfo.ptPixelLocation.y - 2;
  529. contact.rcContact.bottom = contact.pointerInfo.ptPixelLocation.y + 2;
  530. contact.rcContact.left = contact.pointerInfo.ptPixelLocation.x - 2;
  531. contact.rcContact.right = contact.pointerInfo.ptPixelLocation.x + 2;
  532. contact.pointerInfo.pointerFlags =
  533. POINTER_FLAG_DOWN | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
  534. }
  535. // Injecting the touch down on screen
  536. if (!inject_touch_input(num, pointer_touch_info))
  537. return false;
  538. // Injecting the touch move on screen
  539. if (action & MOVE) {
  540. for (int i = 0; i < num; i++) {
  541. POINTER_TOUCH_INFO& contact = pointer_touch_info[i];
  542. contact.pointerInfo.ptPixelLocation.y = y + 10;
  543. contact.pointerInfo.ptPixelLocation.x = x + 10 * i + 30;
  544. contact.pointerInfo.pointerFlags =
  545. POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
  546. }
  547. if (!inject_touch_input(num, pointer_touch_info))
  548. return false;
  549. }
  550. // Injecting the touch up on screen
  551. if (action & RELEASE) {
  552. for (int i = 0; i < num; i++) {
  553. POINTER_TOUCH_INFO& contact = pointer_touch_info[i];
  554. contact.pointerInfo.ptPixelLocation.y = y + 10;
  555. contact.pointerInfo.ptPixelLocation.x = x + 10 * i + 30;
  556. contact.pointerInfo.pointerFlags = POINTER_FLAG_UP | POINTER_FLAG_INRANGE;
  557. }
  558. if (!inject_touch_input(num, pointer_touch_info))
  559. return false;
  560. }
  561. return true;
  562. }
  563. } // namespace internal
  564. } // namespace ui_controls