Flutter Windows Embedder
flutter_window_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 "flutter/fml/macros.h"
6 #include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
7 #include "flutter/shell/platform/windows/testing/mock_window_binding_handler_delegate.h"
8 #include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
9 #include "flutter/shell/platform/windows/testing/windows_test.h"
10 #include "flutter/shell/platform/windows/testing/wm_builders.h"
11 
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14 
15 namespace flutter {
16 namespace testing {
17 
18 using ::testing::_;
19 using ::testing::AnyNumber;
20 using ::testing::Eq;
21 using ::testing::Invoke;
22 using ::testing::Return;
23 
24 namespace {
25 static constexpr int32_t kDefaultPointerDeviceId = 0;
26 
27 class MockFlutterWindow : public FlutterWindow {
28  public:
29  explicit MockFlutterWindow(bool reset_view_on_exit = true)
30  : reset_view_on_exit_(reset_view_on_exit) {
31  ON_CALL(*this, GetDpiScale())
32  .WillByDefault(Return(this->FlutterWindow::GetDpiScale()));
33  }
34 
35  // Used for injecting a proc_table to override calls to the windows API
36  MockFlutterWindow(int width,
37  int height,
38  std::shared_ptr<WindowsProcTable> proc_table = nullptr)
39  : FlutterWindow(width, height, nullptr, std::move(proc_table)) {}
40 
41  virtual ~MockFlutterWindow() {
42  if (reset_view_on_exit_) {
43  SetView(nullptr);
44  }
45  }
46 
47  // Wrapper for GetCurrentDPI() which is a protected method.
48  UINT GetDpi() { return GetCurrentDPI(); }
49  // Simulates a WindowProc message from the OS.
50  LRESULT InjectWindowMessage(UINT const message,
51  WPARAM const wparam,
52  LPARAM const lparam) {
53  return HandleMessage(message, wparam, lparam);
54  }
55 
56  MOCK_METHOD(void, OnDpiScale, (unsigned int), (override));
57  MOCK_METHOD(void, OnResize, (unsigned int, unsigned int), (override));
58  MOCK_METHOD(float, GetScrollOffsetMultiplier, (), (override));
59  MOCK_METHOD(float, GetDpiScale, (), (override));
60  MOCK_METHOD(void, UpdateCursorRect, (const Rect&), (override));
61  MOCK_METHOD(void, OnResetImeComposing, (), (override));
62  MOCK_METHOD(UINT, Win32DispatchMessage, (UINT, WPARAM, LPARAM), (override));
63  MOCK_METHOD(BOOL, Win32PeekMessage, (LPMSG, UINT, UINT, UINT), (override));
64  MOCK_METHOD(uint32_t, Win32MapVkToChar, (uint32_t), (override));
65  MOCK_METHOD(HWND, GetWindowHandle, (), (override));
66  MOCK_METHOD(ui::AXFragmentRootDelegateWin*,
67  GetAxFragmentRootDelegate,
68  (),
69  (override));
70  MOCK_METHOD(void, OnWindowStateEvent, (WindowStateEvent), (override));
71 
72  protected:
73  // |KeyboardManager::WindowDelegate|
74  LRESULT Win32DefWindowProc(HWND hWnd,
75  UINT Msg,
76  WPARAM wParam,
77  LPARAM lParam) override {
78  return kWmResultDefault;
79  }
80 
81  private:
82  bool reset_view_on_exit_;
83  FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindow);
84 };
85 
86 LRESULT InjectPointerMessageWithClientPoint(MockFlutterWindow& window,
87  UINT message,
88  WPARAM wparam,
89  int x,
90  int y) {
91  HWND flutter_window = window.FlutterWindow::GetWindowHandle();
92  HWND parent_window =
93  CreateWindowEx(0, L"STATIC", L"", WS_POPUP, 100, 100, 300, 300, nullptr,
94  nullptr, GetModuleHandle(nullptr), nullptr);
95  EXPECT_NE(parent_window, nullptr);
96  EXPECT_NE(SetParent(flutter_window, parent_window), nullptr);
97  EXPECT_TRUE(SetWindowPos(flutter_window, nullptr, 0, 0, 100, 100,
98  SWP_NOZORDER | SWP_NOACTIVATE));
99 
100  POINT point = {x, y};
101  EXPECT_TRUE(ClientToScreen(flutter_window, &point));
102  LRESULT result =
103  window.InjectWindowMessage(message, wparam, MAKELPARAM(point.x, point.y));
104 
105  EXPECT_NE(SetParent(flutter_window, HWND_MESSAGE), nullptr);
106  DestroyWindow(parent_window);
107  return result;
108 }
109 
110 class MockFlutterWindowsView : public FlutterWindowsView {
111  public:
112  MockFlutterWindowsView(FlutterWindowsEngine* engine,
113  std::unique_ptr<WindowBindingHandler> window_binding)
115  engine,
116  std::move(window_binding),
117  false,
118  BoxConstraints()) {}
120 
121  MOCK_METHOD(void,
122  NotifyWinEventWrapper,
123  (ui::AXPlatformNodeWin*, ax::mojom::Event),
124  (override));
125 
126  private:
127  FML_DISALLOW_COPY_AND_ASSIGN(MockFlutterWindowsView);
128 };
129 
130 class FlutterWindowTest : public WindowsTest {};
131 
132 } // namespace
133 
134 TEST_F(FlutterWindowTest, CreateDestroy) {
135  std::unique_ptr<FlutterWindowsEngine> engine =
136  FlutterWindowsEngineBuilder{GetContext()}.Build();
137  FlutterWindow window(800, 600, engine->display_manager());
138  ASSERT_TRUE(TRUE);
139 }
140 
141 TEST_F(FlutterWindowTest, OnBitmapSurfaceUpdated) {
142  std::unique_ptr<FlutterWindowsEngine> engine =
143  FlutterWindowsEngineBuilder{GetContext()}.Build();
144  FlutterWindow win32window(100, 100, engine->display_manager());
145  int old_handle_count = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
146 
147  constexpr size_t row_bytes = 100 * 4;
148  constexpr size_t height = 100;
149  std::array<char, row_bytes * height> allocation;
150  win32window.OnBitmapSurfaceUpdated(allocation.data(), row_bytes, height);
151 
152  int new_handle_count = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
153  // Check GDI resources leak
154  EXPECT_EQ(old_handle_count, new_handle_count);
155 }
156 
157 // Tests that composing rect updates are transformed from Flutter logical
158 // coordinates to device coordinates and passed to the text input manager
159 // when the DPI scale is 100% (96 DPI).
160 TEST_F(FlutterWindowTest, OnCursorRectUpdatedRegularDPI) {
161  MockFlutterWindow win32window;
162  EXPECT_CALL(win32window, GetDpiScale()).WillOnce(Return(1.0));
163 
164  Rect cursor_rect(Point(10, 20), Size(30, 40));
165  EXPECT_CALL(win32window, UpdateCursorRect(cursor_rect)).Times(1);
166 
167  win32window.OnCursorRectUpdated(cursor_rect);
168 }
169 
170 // Tests that composing rect updates are transformed from Flutter logical
171 // coordinates to device coordinates and passed to the text input manager
172 // when the DPI scale is 150% (144 DPI).
173 TEST_F(FlutterWindowTest, OnCursorRectUpdatedHighDPI) {
174  MockFlutterWindow win32window;
175  EXPECT_CALL(win32window, GetDpiScale()).WillOnce(Return(1.5));
176 
177  Rect expected_cursor_rect(Point(15, 30), Size(45, 60));
178  EXPECT_CALL(win32window, UpdateCursorRect(expected_cursor_rect)).Times(1);
179 
180  Rect cursor_rect(Point(10, 20), Size(30, 40));
181  win32window.OnCursorRectUpdated(cursor_rect);
182 }
183 
184 TEST_F(FlutterWindowTest, OnPointerStarSendsDeviceType) {
185  std::unique_ptr<FlutterWindowsEngine> engine =
186  FlutterWindowsEngineBuilder{GetContext()}.Build();
187  FlutterWindow win32window(100, 100, engine->display_manager());
188  MockWindowBindingHandlerDelegate delegate;
189  EXPECT_CALL(delegate, OnWindowStateEvent).Times(AnyNumber());
190  win32window.SetView(&delegate);
191 
192  // Move
193  EXPECT_CALL(delegate,
194  OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindMouse,
195  kDefaultPointerDeviceId, 0, 0, 0, 0))
196  .Times(1);
197  EXPECT_CALL(delegate,
198  OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindTouch,
199  kDefaultPointerDeviceId, 0, 0, 0, 0))
200  .Times(1);
201  EXPECT_CALL(delegate,
202  OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindStylus,
203  kDefaultPointerDeviceId, 0, 0, 0, 0))
204  .Times(1);
205 
206  // Down
207  EXPECT_CALL(delegate,
208  OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindMouse,
209  kDefaultPointerDeviceId,
210  kFlutterPointerButtonMousePrimary, 0, 0))
211  .Times(1);
212  EXPECT_CALL(delegate,
213  OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindTouch,
214  kDefaultPointerDeviceId,
215  kFlutterPointerButtonMousePrimary, 0, 0))
216  .Times(1);
217  EXPECT_CALL(delegate,
218  OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
219  kDefaultPointerDeviceId,
220  kFlutterPointerButtonMousePrimary, 0, 0))
221  .Times(1);
222 
223  // Up
224  EXPECT_CALL(delegate, OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindMouse,
225  kDefaultPointerDeviceId,
226  kFlutterPointerButtonMousePrimary))
227  .Times(1);
228  EXPECT_CALL(delegate, OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindTouch,
229  kDefaultPointerDeviceId,
230  kFlutterPointerButtonMousePrimary))
231  .Times(1);
232  EXPECT_CALL(delegate, OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindStylus,
233  kDefaultPointerDeviceId,
234  kFlutterPointerButtonMousePrimary))
235  .Times(1);
236 
237  // Leave
238  EXPECT_CALL(delegate,
239  OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindMouse,
240  kDefaultPointerDeviceId))
241  .Times(1);
242  EXPECT_CALL(delegate,
243  OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindTouch,
244  kDefaultPointerDeviceId))
245  .Times(1);
246  EXPECT_CALL(delegate,
247  OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindStylus,
248  kDefaultPointerDeviceId))
249  .Times(1);
250 
251  win32window.OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindMouse,
252  kDefaultPointerDeviceId, 0, 0, 0, 0);
253  win32window.OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindMouse,
254  kDefaultPointerDeviceId,
255  kFlutterPointerButtonMousePrimary, 0, 0);
256  win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindMouse,
257  kDefaultPointerDeviceId,
258  kFlutterPointerButtonMousePrimary);
259  win32window.OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindMouse,
260  kDefaultPointerDeviceId);
261 
262  // Touch
263  win32window.OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindTouch,
264  kDefaultPointerDeviceId, 0, 0, 0, 0);
265  win32window.OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindTouch,
266  kDefaultPointerDeviceId,
267  kFlutterPointerButtonMousePrimary, 0, 0);
268  win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindTouch,
269  kDefaultPointerDeviceId,
270  kFlutterPointerButtonMousePrimary);
271  win32window.OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindTouch,
272  kDefaultPointerDeviceId);
273 
274  // Pen
275  win32window.OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindStylus,
276  kDefaultPointerDeviceId, 0, 0, 0, 0);
277  win32window.OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
278  kDefaultPointerDeviceId,
279  kFlutterPointerButtonMousePrimary, 0, 0);
280  win32window.OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindStylus,
281  kDefaultPointerDeviceId,
282  kFlutterPointerButtonMousePrimary);
283  win32window.OnPointerLeave(10.0, 10.0, kFlutterPointerDeviceKindStylus,
284  kDefaultPointerDeviceId);
285 
286  // Destruction of win32window sends a HIDE update. In situ, the window is
287  // owned by the delegate, and so is destructed first. Not so here.
288  win32window.SetView(nullptr);
289 }
290 
291 TEST_F(FlutterWindowTest, OnStylusPointerDown) {
292  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
293 
294  // Set up expectations for the mock
295  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
296  .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
297  if (pointer_info != nullptr) {
298  pointer_info->pointerType = PT_PEN;
299  pointer_info->pointerId = pointer_id;
300  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
301  }
302  return TRUE;
303  });
304 
305  EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
306  .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
307  if (pen_info != nullptr) {
308  pen_info->pressure = 720; // Non-zero pressure for contact events
309  pen_info->rotation = 10;
310  pen_info->penFlags = 0;
311  }
312  return TRUE;
313  });
314 
315  POINTER_INFO test_pointer_info = {};
316  BOOL result = mock_proc_table->GetPointerInfo(1, &test_pointer_info);
317 
318  MockFlutterWindow win32window(100, 100, mock_proc_table);
319  MockWindowBindingHandlerDelegate delegate;
320 
321  win32window.SetView(&delegate);
322 
323  EXPECT_CALL(delegate,
324  OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
325  kDefaultPointerDeviceId,
326  kFlutterPointerButtonStylusContact, 10, 720))
327  .Times(1);
328 
329  UINT32 pointerId = 1;
330  WPARAM wparam = static_cast<WPARAM>(pointerId);
331  InjectPointerMessageWithClientPoint(win32window, WM_POINTERDOWN, wparam, 10,
332  10);
333 }
334 
335 TEST_F(FlutterWindowTest, OnStylusPointerMove) {
336  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
337 
338  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
339  .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
340  if (pointer_info != nullptr) {
341  pointer_info->pointerType = PT_PEN;
342  pointer_info->pointerId = pointer_id;
343  pointer_info->pointerFlags =
344  POINTER_FLAG_INCONTACT | POINTER_FLAG_UPDATE;
345  }
346  return TRUE;
347  });
348 
349  EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
350  .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
351  if (pen_info != nullptr) {
352  pen_info->pressure = 720; // Non-zero pressure for contact events
353  pen_info->rotation = 10; // This is PRE-transformation to radians.
354  pen_info->penFlags = 0;
355  }
356  return TRUE;
357  });
358 
359  MockFlutterWindow win32window(100, 100, mock_proc_table);
360  MockWindowBindingHandlerDelegate delegate;
361  win32window.SetView(&delegate);
362 
363  EXPECT_CALL(delegate,
364  OnPointerMove(15, 20, kFlutterPointerDeviceKindStylus,
365  kDefaultPointerDeviceId,
366  kFlutterPointerButtonStylusContact, 10, 720, 0))
367  .Times(1);
368 
369  UINT32 pointerId = 1;
370  WPARAM wparam = static_cast<WPARAM>(pointerId);
371  InjectPointerMessageWithClientPoint(win32window, WM_POINTERUPDATE, wparam, 15,
372  20);
373 }
374 
375 TEST_F(FlutterWindowTest, OnStylusPointerUp) {
376  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
377 
378  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
379  .WillOnce([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
380  if (pointer_info != nullptr) {
381  pointer_info->pointerType = PT_PEN;
382  pointer_info->pointerId = pointer_id;
383  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
384  }
385  return TRUE;
386  })
387  .WillOnce([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
388  if (pointer_info != nullptr) {
389  pointer_info->pointerType = PT_PEN;
390  pointer_info->pointerId = pointer_id;
391  pointer_info->pointerFlags = POINTER_FLAG_UP;
392  }
393  return TRUE;
394  });
395 
396  EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
397  .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
398  if (pen_info != nullptr) {
399  pen_info->pressure = 720;
400  pen_info->rotation = 0;
401  pen_info->penFlags = 0;
402  }
403  return TRUE;
404  });
405 
406  MockFlutterWindow win32window(100, 100, mock_proc_table);
407  MockWindowBindingHandlerDelegate delegate;
408  win32window.SetView(&delegate);
409 
410  EXPECT_CALL(delegate,
411  OnPointerDown(25, 30, kFlutterPointerDeviceKindStylus,
412  kDefaultPointerDeviceId,
413  kFlutterPointerButtonStylusContact, 0, 720))
414  .Times(1);
415  EXPECT_CALL(delegate, OnPointerUp(25, 30, kFlutterPointerDeviceKindStylus,
416  kDefaultPointerDeviceId, 0))
417  .Times(1);
418 
419  UINT32 pointerId = 1;
420  WPARAM wparam = static_cast<WPARAM>(pointerId);
421  InjectPointerMessageWithClientPoint(win32window, WM_POINTERDOWN, wparam, 25,
422  30);
423  InjectPointerMessageWithClientPoint(win32window, WM_POINTERUP, wparam, 25,
424  30);
425 }
426 
427 TEST_F(FlutterWindowTest, OnStylusPointerLeave) {
428  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
429 
430  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
431  .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
432  if (pointer_info != nullptr) {
433  pointer_info->pointerType = PT_PEN;
434  pointer_info->pointerId = pointer_id;
435  pointer_info->pointerFlags = POINTER_FLAG_UP;
436  }
437  return TRUE;
438  });
439 
440  EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
441  .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
442  if (pen_info != nullptr) {
443  pen_info->pressure = 720;
444  pen_info->rotation = 0;
445  pen_info->penFlags = 0;
446  }
447  return TRUE;
448  });
449 
450  MockFlutterWindow win32window(100, 100, mock_proc_table);
451  MockWindowBindingHandlerDelegate delegate;
452  win32window.SetView(&delegate);
453 
454  EXPECT_CALL(delegate, OnPointerLeave(35, 40, kFlutterPointerDeviceKindStylus,
455  kDefaultPointerDeviceId))
456  .Times(1);
457 
458  UINT32 pointerId = 1;
459  WPARAM wparam = static_cast<WPARAM>(pointerId);
460  InjectPointerMessageWithClientPoint(win32window, WM_POINTERLEAVE, wparam, 35,
461  40);
462 }
463 
464 TEST_F(FlutterWindowTest, OnStylusPointerHover) {
465  // Test that WM_POINTERUPDATE without POINTER_FLAG_INCONTACT (hover) is
466  // handled
467  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
468 
469  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
470  .WillOnce([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
471  if (pointer_info != nullptr) {
472  pointer_info->pointerId = 1;
473  pointer_info->pointerType = PT_PEN;
474  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
475  pointer_info->ptPixelLocation.x = 45;
476  pointer_info->ptPixelLocation.y = 50;
477  }
478  return TRUE;
479  })
480  .WillOnce([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
481  if (pointer_info != nullptr) {
482  pointer_info->pointerId = 1;
483  pointer_info->pointerType = PT_PEN;
484  // No POINTER_FLAG_INCONTACT - this simulates a hover event
485  pointer_info->pointerFlags = POINTER_FLAG_UPDATE;
486  pointer_info->ptPixelLocation.x = 45;
487  pointer_info->ptPixelLocation.y = 50;
488  }
489  return TRUE;
490  });
491 
492  EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
493  .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
494  if (pen_info != nullptr) {
495  pen_info->pressure = 0;
496  pen_info->rotation = 0;
497  pen_info->penFlags = 0;
498  }
499  return TRUE;
500  });
501 
502  MockFlutterWindow win32window(100, 100, mock_proc_table);
503  MockWindowBindingHandlerDelegate delegate;
504  win32window.SetView(&delegate);
505 
506  // First establish the pointer with WM_POINTERDOWN
507  EXPECT_CALL(delegate,
508  OnPointerDown(45, 50, kFlutterPointerDeviceKindStylus, 0,
509  kFlutterPointerButtonStylusContact, 0, 0))
510  .Times(1);
511 
512  UINT32 pointerId = 1;
513  WPARAM wparam = static_cast<WPARAM>(pointerId);
514  InjectPointerMessageWithClientPoint(win32window, WM_POINTERDOWN, wparam, 45,
515  50);
516 
517  // Now expect OnPointerMove to be called for hover events
518  EXPECT_CALL(delegate, OnPointerMove(45, 50, kFlutterPointerDeviceKindStylus,
519  0, 0, 0, 0, 0))
520  .Times(1);
521 
522  // Inject WM_POINTERUPDATE message (hover event)
523  InjectPointerMessageWithClientPoint(win32window, WM_POINTERUPDATE, wparam, 45,
524  50);
525 }
526 
527 TEST_F(FlutterWindowTest, OnStylusHoverAfterPointerUp) {
528  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
529 
530  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
531  .WillOnce([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
532  if (pointer_info != nullptr) {
533  pointer_info->pointerType = PT_PEN;
534  pointer_info->pointerId = pointer_id;
535  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
536  }
537  return TRUE;
538  })
539  .WillOnce([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
540  if (pointer_info != nullptr) {
541  pointer_info->pointerType = PT_PEN;
542  pointer_info->pointerId = pointer_id;
543  pointer_info->pointerFlags = POINTER_FLAG_UP;
544  }
545  return TRUE;
546  })
547  .WillOnce([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
548  if (pointer_info != nullptr) {
549  pointer_info->pointerType = PT_PEN;
550  pointer_info->pointerId = pointer_id;
551  pointer_info->pointerFlags = POINTER_FLAG_UPDATE;
552  }
553  return TRUE;
554  });
555 
556  EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
557  .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
558  if (pen_info != nullptr) {
559  pen_info->pressure = 720;
560  pen_info->rotation = 0;
561  pen_info->penFlags = 0;
562  }
563  return TRUE;
564  });
565 
566  MockFlutterWindow win32window(100, 100, mock_proc_table);
567  MockWindowBindingHandlerDelegate delegate;
568  win32window.SetView(&delegate);
569 
570  EXPECT_CALL(delegate,
571  OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
572  kDefaultPointerDeviceId,
573  kFlutterPointerButtonStylusContact, 0, 720))
574  .Times(1);
575  EXPECT_CALL(delegate, OnPointerUp(10.0, 10.0, kFlutterPointerDeviceKindStylus,
576  kDefaultPointerDeviceId, 0))
577  .Times(1);
578  EXPECT_CALL(delegate,
579  OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindStylus,
580  kDefaultPointerDeviceId, 0, 0, 720, 0))
581  .Times(1);
582 
583  UINT32 pointerId = 1;
584  WPARAM wparam = static_cast<WPARAM>(pointerId);
585  InjectPointerMessageWithClientPoint(win32window, WM_POINTERDOWN, wparam, 10,
586  10);
587  InjectPointerMessageWithClientPoint(win32window, WM_POINTERUP, wparam, 10,
588  10);
589  InjectPointerMessageWithClientPoint(win32window, WM_POINTERUPDATE, wparam, 10,
590  10);
591 }
592 
593 TEST_F(FlutterWindowTest, OnStylusBarrelButtonUsesPenFlags) {
594  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
595 
596  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
597  .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
598  if (pointer_info != nullptr) {
599  pointer_info->pointerType = PT_PEN;
600  pointer_info->pointerId = pointer_id;
601  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
602  }
603  return TRUE;
604  });
605 
606  EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
607  .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
608  if (pen_info != nullptr) {
609  pen_info->pressure = 720;
610  pen_info->rotation = 0;
611  pen_info->penFlags = PEN_FLAG_BARREL;
612  }
613  return TRUE;
614  });
615 
616  MockFlutterWindow win32window(100, 100, mock_proc_table);
617  MockWindowBindingHandlerDelegate delegate;
618  win32window.SetView(&delegate);
619 
620  EXPECT_CALL(delegate,
621  OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
622  kDefaultPointerDeviceId,
623  kFlutterPointerButtonStylusContact |
624  kFlutterPointerButtonStylusPrimary,
625  0, 720))
626  .Times(1);
627 
628  UINT32 pointerId = 1;
629  WPARAM wparam = static_cast<WPARAM>(pointerId);
630  InjectPointerMessageWithClientPoint(win32window, WM_POINTERDOWN, wparam, 10,
631  10);
632 }
633 
634 TEST_F(FlutterWindowTest, OnStylusEraserButtonUsesPenFlags) {
635  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
636 
637  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
638  .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
639  if (pointer_info != nullptr) {
640  pointer_info->pointerType = PT_PEN;
641  pointer_info->pointerId = pointer_id;
642  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
643  }
644  return TRUE;
645  });
646 
647  EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
648  .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
649  if (pen_info != nullptr) {
650  pen_info->pressure = 720;
651  pen_info->rotation = 0;
652  pen_info->penFlags = PEN_FLAG_ERASER;
653  }
654  return TRUE;
655  });
656 
657  MockFlutterWindow win32window(100, 100, mock_proc_table);
658  MockWindowBindingHandlerDelegate delegate;
659  win32window.SetView(&delegate);
660 
661  EXPECT_CALL(delegate,
662  OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
663  kDefaultPointerDeviceId,
664  kFlutterPointerButtonStylusContact |
665  kFlutterPointerButtonStylusSecondary,
666  0, 720))
667  .Times(1);
668 
669  UINT32 pointerId = 1;
670  WPARAM wparam = static_cast<WPARAM>(pointerId);
671  InjectPointerMessageWithClientPoint(win32window, WM_POINTERDOWN, wparam, 10,
672  10);
673 }
674 
675 TEST_F(FlutterWindowTest, OnInvertedStylusPointerDownUsesDeviceKind) {
676  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
677 
678  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
679  .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
680  if (pointer_info != nullptr) {
681  pointer_info->pointerType = PT_PEN;
682  pointer_info->pointerId = pointer_id;
683  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
684  }
685  return TRUE;
686  });
687 
688  EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
689  .WillRepeatedly([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
690  if (pen_info != nullptr) {
691  pen_info->pressure = 720;
692  pen_info->rotation = 0;
693  pen_info->penFlags = PEN_FLAG_INVERTED;
694  }
695  return TRUE;
696  });
697 
698  MockFlutterWindow win32window(100, 100, mock_proc_table);
699  MockWindowBindingHandlerDelegate delegate;
700  win32window.SetView(&delegate);
701 
702  EXPECT_CALL(delegate,
703  OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindInvertedStylus,
704  kDefaultPointerDeviceId,
705  kFlutterPointerButtonStylusContact, 0, 720))
706  .Times(1);
707 
708  UINT32 pointerId = 1;
709  WPARAM wparam = static_cast<WPARAM>(pointerId);
710  InjectPointerMessageWithClientPoint(win32window, WM_POINTERDOWN, wparam, 10,
711  10);
712 }
713 
714 TEST_F(FlutterWindowTest, OnStylusBarrelButtonUpdateMovesWithUpdatedButtons) {
715  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
716 
717  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
718  .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
719  if (pointer_info != nullptr) {
720  pointer_info->pointerType = PT_PEN;
721  pointer_info->pointerId = pointer_id;
722  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
723  }
724  return TRUE;
725  });
726 
727  EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
728  .WillOnce([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
729  if (pen_info != nullptr) {
730  pen_info->pressure = 720;
731  pen_info->rotation = 0;
732  pen_info->penFlags = 0;
733  }
734  return TRUE;
735  })
736  .WillOnce([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
737  if (pen_info != nullptr) {
738  pen_info->pressure = 720;
739  pen_info->rotation = 0;
740  pen_info->penFlags = PEN_FLAG_BARREL;
741  }
742  return TRUE;
743  });
744 
745  MockFlutterWindow win32window(100, 100, mock_proc_table);
746  MockWindowBindingHandlerDelegate delegate;
747  win32window.SetView(&delegate);
748 
749  EXPECT_CALL(delegate,
750  OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
751  kDefaultPointerDeviceId,
752  kFlutterPointerButtonStylusContact, 0, 720))
753  .Times(1);
754  EXPECT_CALL(delegate,
755  OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindStylus,
756  kDefaultPointerDeviceId,
757  kFlutterPointerButtonStylusContact |
758  kFlutterPointerButtonStylusPrimary,
759  0, 720, 0))
760  .Times(1);
761 
762  UINT32 pointerId = 1;
763  WPARAM wparam = static_cast<WPARAM>(pointerId);
764  InjectPointerMessageWithClientPoint(win32window, WM_POINTERDOWN, wparam, 10,
765  10);
766  InjectPointerMessageWithClientPoint(win32window, WM_POINTERUPDATE, wparam, 10,
767  10);
768 }
769 
770 TEST_F(FlutterWindowTest, OnStylusBarrelButtonUpdateMovesWithReleasedButton) {
771  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
772 
773  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
774  .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
775  if (pointer_info != nullptr) {
776  pointer_info->pointerType = PT_PEN;
777  pointer_info->pointerId = pointer_id;
778  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT;
779  }
780  return TRUE;
781  });
782 
783  EXPECT_CALL(*mock_proc_table, GetPointerPenInfo(_, _))
784  .WillOnce([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
785  if (pen_info != nullptr) {
786  pen_info->pressure = 720;
787  pen_info->rotation = 0;
788  pen_info->penFlags = PEN_FLAG_BARREL;
789  }
790  return TRUE;
791  })
792  .WillOnce([](UINT32 pointer_id, POINTER_PEN_INFO* pen_info) {
793  if (pen_info != nullptr) {
794  pen_info->pressure = 720;
795  pen_info->rotation = 0;
796  pen_info->penFlags = 0;
797  }
798  return TRUE;
799  });
800 
801  MockFlutterWindow win32window(100, 100, mock_proc_table);
802  MockWindowBindingHandlerDelegate delegate;
803  win32window.SetView(&delegate);
804 
805  EXPECT_CALL(delegate,
806  OnPointerDown(10.0, 10.0, kFlutterPointerDeviceKindStylus,
807  kDefaultPointerDeviceId,
808  kFlutterPointerButtonStylusContact |
809  kFlutterPointerButtonStylusPrimary,
810  0, 720))
811  .Times(1);
812  EXPECT_CALL(delegate,
813  OnPointerMove(10.0, 10.0, kFlutterPointerDeviceKindStylus,
814  kDefaultPointerDeviceId,
815  kFlutterPointerButtonStylusContact, 0, 720, 0))
816  .Times(1);
817 
818  UINT32 pointerId = 1;
819  WPARAM wparam = static_cast<WPARAM>(pointerId);
820  InjectPointerMessageWithClientPoint(win32window, WM_POINTERDOWN, wparam, 10,
821  10);
822  InjectPointerMessageWithClientPoint(win32window, WM_POINTERUPDATE, wparam, 10,
823  10);
824 }
825 
826 TEST_F(FlutterWindowTest, OnMousePointerDown) {
827  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
828 
829  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
830  .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
831  if (pointer_info != nullptr) {
832  pointer_info->pointerType = PT_MOUSE;
833  pointer_info->pointerId = pointer_id;
834  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT |
835  POINTER_FLAG_FIRSTBUTTON |
836  POINTER_FLAG_DOWN;
837  }
838  return TRUE;
839  });
840 
841  MockFlutterWindow win32window(100, 100, mock_proc_table);
842  MockWindowBindingHandlerDelegate delegate;
843  win32window.SetView(&delegate);
844 
845  EXPECT_CALL(delegate, OnPointerDown(45, 50, kFlutterPointerDeviceKindMouse,
846  kDefaultPointerDeviceId,
847  kFlutterPointerButtonMousePrimary, 0, 0))
848  .Times(1);
849 
850  UINT32 pointerId = 1;
851  WPARAM wparam = static_cast<WPARAM>(pointerId);
852  InjectPointerMessageWithClientPoint(win32window, WM_POINTERDOWN, wparam, 45,
853  50);
854 }
855 
856 TEST_F(FlutterWindowTest, OnTouchPointerDown) {
857  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
858 
859  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
860  .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
861  if (pointer_info != nullptr) {
862  pointer_info->pointerType = PT_TOUCH;
863  pointer_info->pointerId = pointer_id;
864  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT |
865  POINTER_FLAG_FIRSTBUTTON |
866  POINTER_FLAG_DOWN;
867  }
868  return TRUE;
869  });
870 
871  MockFlutterWindow win32window(100, 100, mock_proc_table);
872  MockWindowBindingHandlerDelegate delegate;
873  win32window.SetView(&delegate);
874 
875  EXPECT_CALL(delegate, OnPointerDown(55, 60, kFlutterPointerDeviceKindTouch,
876  kDefaultPointerDeviceId,
877  kFlutterPointerButtonMousePrimary, 0, 0))
878  .Times(1);
879 
880  UINT32 pointerId = 1;
881  WPARAM wparam = static_cast<WPARAM>(pointerId);
882  InjectPointerMessageWithClientPoint(win32window, WM_POINTERDOWN, wparam, 55,
883  60);
884 }
885 
886 TEST_F(FlutterWindowTest, PointerMessageScreenCoordinatesAreConvertedToClient) {
887  constexpr int kClientX = 15;
888  constexpr int kClientY = 20;
889 
890  auto mock_proc_table = std::make_shared<MockWindowsProcTable>();
891 
892  EXPECT_CALL(*mock_proc_table, GetPointerInfo(_, _))
893  .WillRepeatedly([](UINT32 pointer_id, POINTER_INFO* pointer_info) {
894  if (pointer_info != nullptr) {
895  pointer_info->pointerType = PT_TOUCH;
896  pointer_info->pointerId = pointer_id;
897  pointer_info->pointerFlags = POINTER_FLAG_INCONTACT |
898  POINTER_FLAG_FIRSTBUTTON |
899  POINTER_FLAG_DOWN;
900  }
901  return TRUE;
902  });
903 
904  MockFlutterWindow win32window(100, 100, mock_proc_table);
905  MockWindowBindingHandlerDelegate delegate;
906  EXPECT_CALL(win32window, OnWindowStateEvent).Times(AnyNumber());
907  EXPECT_CALL(delegate, OnWindowStateEvent).Times(AnyNumber());
908  win32window.SetView(&delegate);
909 
910  HWND parent_window =
911  CreateWindowEx(0, L"STATIC", L"", WS_POPUP, 100, 100, 300, 300, nullptr,
912  nullptr, GetModuleHandle(nullptr), nullptr);
913  ASSERT_NE(parent_window, nullptr);
914 
915  HWND flutter_window = win32window.FlutterWindow::GetWindowHandle();
916  ASSERT_NE(flutter_window, nullptr);
917  ASSERT_NE(SetParent(flutter_window, parent_window), nullptr);
918  ASSERT_TRUE(SetWindowPos(flutter_window, nullptr, 25, 35, 100, 100,
919  SWP_NOZORDER | SWP_NOACTIVATE));
920 
921  POINT pointer_point = {kClientX, kClientY};
922  ASSERT_TRUE(ClientToScreen(flutter_window, &pointer_point));
923 
924  EXPECT_CALL(delegate,
925  OnPointerDown(kClientX, kClientY, kFlutterPointerDeviceKindTouch,
926  kDefaultPointerDeviceId,
927  kFlutterPointerButtonMousePrimary, 0, 0))
928  .Times(1);
929 
930  win32window.InjectWindowMessage(WM_POINTERDOWN, /*wparam=*/1,
931  MAKELPARAM(pointer_point.x, pointer_point.y));
932 
933  EXPECT_NE(SetParent(flutter_window, HWND_MESSAGE), nullptr);
934  DestroyWindow(parent_window);
935 }
936 
937 // Tests that calls to OnScroll in turn calls GetScrollOffsetMultiplier
938 // for mapping scroll ticks to pixels.
939 TEST_F(FlutterWindowTest, OnScrollCallsGetScrollOffsetMultiplier) {
940  MockFlutterWindow win32window;
941  MockWindowBindingHandlerDelegate delegate;
942  EXPECT_CALL(win32window, OnWindowStateEvent).Times(AnyNumber());
943  win32window.SetView(&delegate);
944 
945  EXPECT_CALL(win32window, GetWindowHandle).WillOnce([&win32window]() {
946  return win32window.FlutterWindow::GetWindowHandle();
947  });
948  EXPECT_CALL(win32window, GetScrollOffsetMultiplier).WillOnce(Return(120.0f));
949 
950  EXPECT_CALL(delegate,
951  OnScroll(_, _, 0, 0, 120.0f, kFlutterPointerDeviceKindMouse,
952  kDefaultPointerDeviceId))
953  .Times(1);
954 
955  win32window.OnScroll(0.0f, 0.0f, kFlutterPointerDeviceKindMouse,
956  kDefaultPointerDeviceId);
957 }
958 
959 TEST_F(FlutterWindowTest, OnWindowRepaint) {
960  MockFlutterWindow win32window;
961  MockWindowBindingHandlerDelegate delegate;
962  EXPECT_CALL(win32window, OnWindowStateEvent).Times(AnyNumber());
963  win32window.SetView(&delegate);
964 
965  EXPECT_CALL(delegate, OnWindowRepaint()).Times(1);
966 
967  win32window.InjectWindowMessage(WM_PAINT, 0, 0);
968 }
969 
970 TEST_F(FlutterWindowTest, OnThemeChange) {
971  MockFlutterWindow win32window;
972  MockWindowBindingHandlerDelegate delegate;
973  EXPECT_CALL(win32window, OnWindowStateEvent).Times(AnyNumber());
974  win32window.SetView(&delegate);
975 
976  EXPECT_CALL(delegate, OnHighContrastChanged).Times(1);
977 
978  win32window.InjectWindowMessage(WM_THEMECHANGED, 0, 0);
979 }
980 
981 // The window should return no root accessibility node if
982 // it isn't attached to a view.
983 // Regression test for https://github.com/flutter/flutter/issues/129791
984 TEST_F(FlutterWindowTest, AccessibilityNodeWithoutView) {
985  MockFlutterWindow win32window;
986 
987  EXPECT_EQ(win32window.GetNativeViewAccessible(), nullptr);
988 }
989 
990 // Ensure that announcing the alert propagates the message to the alert node.
991 // Different screen readers use different properties for alerts.
992 TEST_F(FlutterWindowTest, AlertNode) {
993  std::unique_ptr<FlutterWindowsEngine> engine =
994  FlutterWindowsEngineBuilder{GetContext()}.Build();
995  auto win32window = std::make_unique<MockFlutterWindow>();
996  EXPECT_CALL(*win32window.get(), GetAxFragmentRootDelegate())
997  .WillRepeatedly(Return(nullptr));
998  EXPECT_CALL(*win32window.get(), OnWindowStateEvent).Times(AnyNumber());
999  EXPECT_CALL(*win32window.get(), GetWindowHandle).Times(AnyNumber());
1000  MockFlutterWindowsView view{engine.get(), std::move(win32window)};
1001  std::wstring message = L"Test alert";
1002  EXPECT_CALL(view, NotifyWinEventWrapper(_, ax::mojom::Event::kAlert))
1003  .Times(1);
1004  view.AnnounceAlert(message);
1005 
1006  IAccessible* alert = view.AlertNode();
1007  VARIANT self{.vt = VT_I4, .lVal = CHILDID_SELF};
1008  BSTR strptr;
1009  alert->get_accName(self, &strptr);
1010  EXPECT_EQ(message, strptr);
1011 
1012  alert->get_accDescription(self, &strptr);
1013  EXPECT_EQ(message, strptr);
1014 
1015  alert->get_accValue(self, &strptr);
1016  EXPECT_EQ(message, strptr);
1017 
1018  VARIANT role;
1019  alert->get_accRole(self, &role);
1020  EXPECT_EQ(role.vt, VT_I4);
1021  EXPECT_EQ(role.lVal, ROLE_SYSTEM_ALERT);
1022 }
1023 
1024 TEST_F(FlutterWindowTest, LifecycleFocusMessages) {
1025  MockFlutterWindow win32window;
1026  EXPECT_CALL(win32window, GetWindowHandle)
1027  .WillRepeatedly(Return(reinterpret_cast<HWND>(1)));
1028  MockWindowBindingHandlerDelegate delegate;
1029 
1030  WindowStateEvent last_event;
1031  EXPECT_CALL(delegate, OnWindowStateEvent)
1032  .WillRepeatedly([&last_event](HWND hwnd, WindowStateEvent event) {
1033  last_event = event;
1034  });
1035  EXPECT_CALL(win32window, OnWindowStateEvent)
1036  .WillRepeatedly([&](WindowStateEvent event) {
1037  win32window.FlutterWindow::OnWindowStateEvent(event);
1038  });
1039  EXPECT_CALL(win32window, OnResize).Times(AnyNumber());
1040 
1041  win32window.SetView(&delegate);
1042 
1043  win32window.InjectWindowMessage(WM_SIZE, 0, 0);
1044  EXPECT_EQ(last_event, WindowStateEvent::kHide);
1045 
1046  win32window.InjectWindowMessage(WM_SIZE, 0, MAKEWORD(1, 1));
1047  EXPECT_EQ(last_event, WindowStateEvent::kShow);
1048 
1049  EXPECT_CALL(delegate, OnFocus(Eq(FlutterViewFocusState::kFocused),
1050  Eq(FlutterViewFocusDirection::kUndefined)))
1051  .Times(1);
1052  win32window.InjectWindowMessage(WM_SETFOCUS, 0, 0);
1053  EXPECT_EQ(last_event, WindowStateEvent::kFocus);
1054 
1055  EXPECT_CALL(delegate, OnFocus(Eq(FlutterViewFocusState::kUnfocused),
1056  Eq(FlutterViewFocusDirection::kUndefined)))
1057  .Times(1);
1058  win32window.InjectWindowMessage(WM_KILLFOCUS, 0, 0);
1059  EXPECT_EQ(last_event, WindowStateEvent::kUnfocus);
1060 }
1061 
1062 TEST_F(FlutterWindowTest, CachedLifecycleMessage) {
1063  MockFlutterWindow win32window;
1064  EXPECT_CALL(win32window, GetWindowHandle)
1065  .WillRepeatedly(Return(reinterpret_cast<HWND>(1)));
1066  EXPECT_CALL(win32window, OnWindowStateEvent)
1067  .WillRepeatedly([&](WindowStateEvent event) {
1068  win32window.FlutterWindow::OnWindowStateEvent(event);
1069  });
1070  EXPECT_CALL(win32window, OnResize).Times(1);
1071 
1072  // Restore
1073  win32window.InjectWindowMessage(WM_SIZE, 0, MAKEWORD(1, 1));
1074 
1075  // Focus
1076  win32window.InjectWindowMessage(WM_SETFOCUS, 0, 0);
1077 
1078  MockWindowBindingHandlerDelegate delegate;
1079  bool focused = false;
1080  bool restored = false;
1081  EXPECT_CALL(delegate, OnWindowStateEvent)
1082  .WillRepeatedly([&](HWND hwnd, WindowStateEvent event) {
1083  if (event == WindowStateEvent::kFocus) {
1084  focused = true;
1085  } else if (event == WindowStateEvent::kShow) {
1086  restored = true;
1087  }
1088  });
1089 
1090  EXPECT_CALL(delegate, OnFocus(Eq(FlutterViewFocusState::kFocused),
1091  Eq(FlutterViewFocusDirection::kUndefined)))
1092  .Times(1);
1093  win32window.SetView(&delegate);
1094  EXPECT_TRUE(focused);
1095  EXPECT_TRUE(restored);
1096 }
1097 
1098 } // namespace testing
1099 } // namespace flutter
virtual void OnPointerLeave(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id)
virtual bool OnBitmapSurfaceUpdated(const void *allocation, size_t row_bytes, size_t height) override
virtual void OnPointerDown(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, uint64_t buttons, uint32_t rotation, uint32_t pressure)
virtual void OnPointerMove(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, uint64_t buttons, uint32_t rotation, uint32_t pressure, int modifiers_state)
virtual void OnPointerUp(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, uint64_t buttons)
virtual void SetView(WindowBindingHandlerDelegate *view) override
virtual float GetDpiScale() override
FlutterWindowsView(FlutterViewId view_id, FlutterWindowsEngine *engine, std::unique_ptr< WindowBindingHandler > window_binding, bool is_sized_to_content, const BoxConstraints &box_constraints, FlutterWindowsViewSizingDelegate *sizing_delegate=nullptr, std::shared_ptr< WindowsProcTable > windows_proc_table=nullptr)
MOCK_METHOD(void, NotifyWinEventWrapper,(ui::AXPlatformNodeWin *, ax::mojom::Event),(override))
MockFlutterWindowsView(FlutterWindowsEngine *engine, std::unique_ptr< WindowBindingHandler > wbh)
Win32Message message
TEST_F(AccessibilityPluginTest, DirectAnnounceCall)
WindowStateEvent
An event representing a change in window state that may update the.
constexpr FlutterViewId kImplicitViewId