mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Win32, Keyboard] Migrate FlutterWindowWin32 keyboard tests to keyboard_win32_unittests (flutter/engine#30808)
* Until AltLeft * Alt right * Meta keys * Remove tests * Format
This commit is contained in:
parent
4f8fbb365f
commit
400ee783e3
@ -328,216 +328,6 @@ TEST(FlutterWindowWin32Test, CreateDestroy) {
|
||||
ASSERT_TRUE(TRUE);
|
||||
}
|
||||
|
||||
// Tests key event propagation of non-printable, non-modifier key down events.
|
||||
TEST(FlutterWindowWin32Test, NonPrintableKeyDownPropagation) {
|
||||
::testing::InSequence in_sequence;
|
||||
|
||||
constexpr WPARAM virtual_key = VK_LEFT;
|
||||
constexpr WPARAM scan_code = 10;
|
||||
constexpr char32_t character = 0;
|
||||
MockFlutterWindowWin32 win32window;
|
||||
auto window_binding_handler =
|
||||
std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
|
||||
TestFlutterWindowsView flutter_windows_view(
|
||||
std::move(window_binding_handler), virtual_key, false /* is_printable */);
|
||||
win32window.SetView(&flutter_windows_view);
|
||||
LPARAM lparam = CreateKeyEventLparam(scan_code, false, false);
|
||||
|
||||
// Test an event not handled by the framework
|
||||
{
|
||||
test_response = false;
|
||||
flutter_windows_view.SetEngine(std::move(GetTestEngine()));
|
||||
EXPECT_CALL(*flutter_windows_view.key_event_handler,
|
||||
KeyboardHook(virtual_key, scan_code, WM_KEYDOWN, character,
|
||||
false /* extended */, _))
|
||||
.Times(2)
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
|
||||
KeyboardHook(_, _, _, _, _, _))
|
||||
.Times(1)
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin, TextHook(_)).Times(0);
|
||||
win32window.InjectMessages(1,
|
||||
Win32Message{WM_KEYDOWN, virtual_key, lparam});
|
||||
flutter_windows_view.InjectPendingEvents(&win32window);
|
||||
}
|
||||
|
||||
// Test an event handled by the framework
|
||||
{
|
||||
test_response = true;
|
||||
EXPECT_CALL(*flutter_windows_view.key_event_handler,
|
||||
KeyboardHook(virtual_key, scan_code, WM_KEYDOWN, character,
|
||||
false /* extended */, false /* PrevState */))
|
||||
.Times(1)
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
|
||||
KeyboardHook(_, _, _, _, _, _))
|
||||
.Times(0);
|
||||
win32window.InjectMessages(1,
|
||||
Win32Message{WM_KEYDOWN, virtual_key, lparam});
|
||||
flutter_windows_view.InjectPendingEvents(&win32window);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests key event propagation of system (WM_SYSKEYDOWN) key down events.
|
||||
TEST(FlutterWindowWin32Test, SystemKeyDownPropagation) {
|
||||
::testing::InSequence in_sequence;
|
||||
|
||||
constexpr WPARAM virtual_key = VK_LEFT;
|
||||
constexpr WPARAM scan_code = 10;
|
||||
constexpr char32_t character = 0;
|
||||
MockFlutterWindowWin32 win32window;
|
||||
auto window_binding_handler =
|
||||
std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
|
||||
TestFlutterWindowsView flutter_windows_view(
|
||||
std::move(window_binding_handler), virtual_key, false /* is_printable */);
|
||||
win32window.SetView(&flutter_windows_view);
|
||||
LPARAM lparam = CreateKeyEventLparam(scan_code, false, false);
|
||||
|
||||
// Test an event not handled by the framework
|
||||
{
|
||||
test_response = false;
|
||||
flutter_windows_view.SetEngine(std::move(GetTestEngine()));
|
||||
EXPECT_CALL(*flutter_windows_view.key_event_handler,
|
||||
KeyboardHook(virtual_key, scan_code, WM_SYSKEYDOWN, character,
|
||||
false /* extended */, _))
|
||||
.Times(2)
|
||||
.RetiresOnSaturation();
|
||||
// Syskey events are not redispatched, so TextInputPlugin, which relies on
|
||||
// them to receive events, no longer works.
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
|
||||
KeyboardHook(_, _, _, _, _, _))
|
||||
.Times(0)
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin, TextHook(_)).Times(0);
|
||||
win32window.InjectMessages(
|
||||
1, Win32Message{WM_SYSKEYDOWN, virtual_key, lparam, kWmResultDefault});
|
||||
flutter_windows_view.InjectPendingEvents(&win32window);
|
||||
}
|
||||
|
||||
// Test an event handled by the framework
|
||||
{
|
||||
test_response = true;
|
||||
EXPECT_CALL(*flutter_windows_view.key_event_handler,
|
||||
KeyboardHook(_, _, _, _, _, _))
|
||||
.Times(0);
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
|
||||
KeyboardHook(_, _, _, _, _, _))
|
||||
.Times(0);
|
||||
win32window.InjectMessages(
|
||||
1, Win32Message{WM_SYSKEYDOWN, virtual_key, lparam, kWmResultDefault});
|
||||
flutter_windows_view.InjectPendingEvents(&win32window);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests key event propagation of printable character key down events. These
|
||||
// differ from non-printable characters in that they follow a different code
|
||||
// path in the WndProc (HandleMessage), producing a follow-on WM_CHAR event.
|
||||
TEST(FlutterWindowWin32Test, CharKeyDownPropagation) {
|
||||
::testing::InSequence in_sequence;
|
||||
|
||||
constexpr WPARAM virtual_key = 65; // The "A" key, which produces a character
|
||||
constexpr WPARAM scan_code = 30;
|
||||
constexpr char32_t character = 65;
|
||||
|
||||
MockFlutterWindowWin32 win32window;
|
||||
auto window_binding_handler =
|
||||
std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
|
||||
TestFlutterWindowsView flutter_windows_view(
|
||||
std::move(window_binding_handler), virtual_key, true /* is_printable */);
|
||||
win32window.SetView(&flutter_windows_view);
|
||||
LPARAM lparam = CreateKeyEventLparam(scan_code, false, false);
|
||||
flutter_windows_view.SetEngine(std::move(GetTestEngine()));
|
||||
|
||||
// Test an event not handled by the framework
|
||||
{
|
||||
test_response = false;
|
||||
EXPECT_CALL(*flutter_windows_view.key_event_handler,
|
||||
KeyboardHook(virtual_key, scan_code, WM_KEYDOWN, character,
|
||||
false, false))
|
||||
.Times(2)
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
|
||||
KeyboardHook(_, _, _, _, _, _))
|
||||
.Times(1)
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin, TextHook(_))
|
||||
.Times(1)
|
||||
.RetiresOnSaturation();
|
||||
win32window.InjectMessages(2, Win32Message{WM_KEYDOWN, virtual_key, lparam},
|
||||
Win32Message{WM_CHAR, virtual_key, lparam});
|
||||
flutter_windows_view.InjectPendingEvents(&win32window);
|
||||
}
|
||||
|
||||
// Test an event handled by the framework
|
||||
{
|
||||
test_response = true;
|
||||
EXPECT_CALL(*flutter_windows_view.key_event_handler,
|
||||
KeyboardHook(virtual_key, scan_code, WM_KEYDOWN, character,
|
||||
false, false))
|
||||
.Times(1)
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
|
||||
KeyboardHook(_, _, _, _, _, _))
|
||||
.Times(0);
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin, TextHook(_)).Times(0);
|
||||
win32window.InjectMessages(2, Win32Message{WM_KEYDOWN, virtual_key, lparam},
|
||||
Win32Message{WM_CHAR, virtual_key, lparam});
|
||||
flutter_windows_view.InjectPendingEvents(&win32window);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests key event propagation of modifier key down events. This is different
|
||||
// from non-printable events in that they call MapVirtualKey, resulting in a
|
||||
// slightly different code path.
|
||||
TEST(FlutterWindowWin32Test, ModifierKeyDownPropagation) {
|
||||
constexpr WPARAM virtual_key = VK_LSHIFT;
|
||||
constexpr WPARAM scan_code = 0x2a;
|
||||
constexpr char32_t character = 0;
|
||||
MockFlutterWindowWin32 win32window;
|
||||
auto window_binding_handler =
|
||||
std::make_unique<::testing::NiceMock<MockWindowBindingHandler>>();
|
||||
TestFlutterWindowsView flutter_windows_view(
|
||||
std::move(window_binding_handler), virtual_key, false /* is_printable */);
|
||||
win32window.SetView(&flutter_windows_view);
|
||||
LPARAM lparam = CreateKeyEventLparam(scan_code, false, false);
|
||||
|
||||
// Test an event not handled by the framework
|
||||
{
|
||||
test_response = false;
|
||||
flutter_windows_view.SetEngine(std::move(GetTestEngine()));
|
||||
EXPECT_CALL(*flutter_windows_view.key_event_handler,
|
||||
KeyboardHook(virtual_key, scan_code, WM_KEYDOWN, character,
|
||||
false /* extended */, false))
|
||||
.Times(2)
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
|
||||
KeyboardHook(_, _, _, _, _, _))
|
||||
.Times(1)
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin, TextHook(_)).Times(0);
|
||||
EXPECT_EQ(win32window.InjectWindowMessage(WM_KEYDOWN, virtual_key, lparam),
|
||||
0);
|
||||
flutter_windows_view.InjectPendingEvents(&win32window);
|
||||
}
|
||||
|
||||
// Test an event handled by the framework
|
||||
{
|
||||
test_response = true;
|
||||
EXPECT_CALL(*flutter_windows_view.key_event_handler,
|
||||
KeyboardHook(virtual_key, scan_code, WM_KEYDOWN, character,
|
||||
false /* extended */, false))
|
||||
.Times(1)
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
|
||||
KeyboardHook(_, _, _, _, _, _))
|
||||
.Times(0);
|
||||
EXPECT_EQ(win32window.InjectWindowMessage(WM_KEYDOWN, virtual_key, lparam),
|
||||
0);
|
||||
flutter_windows_view.InjectPendingEvents(&win32window);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that composing rect updates are transformed from Flutter logical
|
||||
// coordinates to device coordinates and passed to the text input manager
|
||||
// when the DPI scale is 100% (96 DPI).
|
||||
|
||||
@ -105,7 +105,8 @@ KeyboardKeyHandler::KeyboardKeyHandlerDelegate::~KeyboardKeyHandlerDelegate() =
|
||||
KeyboardKeyHandler::KeyboardKeyHandler(EventDispatcher dispatch_event)
|
||||
: dispatch_event_(dispatch_event),
|
||||
last_sequence_id_(1),
|
||||
last_key_is_ctrl_left_down(false) {}
|
||||
last_key_is_ctrl_left_down(false),
|
||||
should_synthesize_ctrl_left_up(false) {}
|
||||
|
||||
KeyboardKeyHandler::~KeyboardKeyHandler() = default;
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ static constexpr int kHandledScanCode2 = 22;
|
||||
static constexpr int kUnhandledScanCode = 21;
|
||||
|
||||
constexpr uint64_t kScanCodeShiftRight = 0x36;
|
||||
constexpr uint64_t kScanCodeControlLeft = 0x1D;
|
||||
constexpr uint64_t kScanCodeControl = 0x1D;
|
||||
constexpr uint64_t kScanCodeAltLeft = 0x38;
|
||||
|
||||
typedef std::function<void(bool)> Callback;
|
||||
@ -237,496 +237,5 @@ TEST(KeyboardKeyHandlerTest, SingleDelegateWithSyncResponds) {
|
||||
redispatch_scancode = 0;
|
||||
}
|
||||
|
||||
TEST(KeyboardKeyHandlerTest, WithTwoAsyncDelegates) {
|
||||
std::list<MockKeyHandlerDelegate::KeyboardHookCall> hook_history;
|
||||
|
||||
// Capture the scancode of the last redispatched event
|
||||
int redispatch_scancode = 0;
|
||||
bool delegate_handled = false;
|
||||
TestKeyboardKeyHandler handler([&redispatch_scancode](UINT cInputs,
|
||||
LPINPUT pInputs,
|
||||
int cbSize) -> UINT {
|
||||
EXPECT_TRUE(cbSize > 0);
|
||||
redispatch_scancode = pInputs->ki.wScan;
|
||||
return 1;
|
||||
});
|
||||
|
||||
auto delegate1 = std::make_unique<MockKeyHandlerDelegate>(1, &hook_history);
|
||||
CallbackHandler& delegate1_handler = delegate1->callback_handler;
|
||||
handler.AddDelegate(std::move(delegate1));
|
||||
|
||||
auto delegate2 = std::make_unique<MockKeyHandlerDelegate>(2, &hook_history);
|
||||
CallbackHandler& delegate2_handler = delegate2->callback_handler;
|
||||
handler.AddDelegate(std::move(delegate2));
|
||||
|
||||
/// Test 1: One delegate responds true, the other false
|
||||
|
||||
delegate_handled = handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN,
|
||||
L'a', false, false);
|
||||
EXPECT_EQ(delegate_handled, true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
EXPECT_EQ(hook_history.size(), 2);
|
||||
EXPECT_EQ(hook_history.front().delegate_id, 1);
|
||||
EXPECT_EQ(hook_history.front().scancode, kHandledScanCode);
|
||||
EXPECT_EQ(hook_history.front().was_down, false);
|
||||
EXPECT_EQ(hook_history.back().delegate_id, 2);
|
||||
EXPECT_EQ(hook_history.back().scancode, kHandledScanCode);
|
||||
EXPECT_EQ(hook_history.back().was_down, false);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
|
||||
hook_history.back().callback(true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
|
||||
hook_history.front().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
redispatch_scancode = 0;
|
||||
hook_history.clear();
|
||||
|
||||
/// Test 2: All delegates respond false
|
||||
|
||||
delegate_handled = handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN,
|
||||
L'a', false, false);
|
||||
EXPECT_EQ(delegate_handled, true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
EXPECT_EQ(hook_history.size(), 2);
|
||||
EXPECT_EQ(hook_history.front().delegate_id, 1);
|
||||
EXPECT_EQ(hook_history.front().scancode, kHandledScanCode);
|
||||
EXPECT_EQ(hook_history.front().was_down, false);
|
||||
EXPECT_EQ(hook_history.back().delegate_id, 2);
|
||||
EXPECT_EQ(hook_history.back().scancode, kHandledScanCode);
|
||||
EXPECT_EQ(hook_history.back().was_down, false);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
|
||||
hook_history.front().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
|
||||
hook_history.back().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kHandledScanCode);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), true);
|
||||
EXPECT_EQ(handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN, L'a', false,
|
||||
false),
|
||||
false);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
hook_history.clear();
|
||||
redispatch_scancode = 0;
|
||||
|
||||
/// Test 3: All delegates responds true
|
||||
|
||||
delegate_handled = handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN,
|
||||
L'a', false, false);
|
||||
EXPECT_EQ(delegate_handled, true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
EXPECT_EQ(hook_history.size(), 2);
|
||||
EXPECT_EQ(hook_history.front().delegate_id, 1);
|
||||
EXPECT_EQ(hook_history.front().scancode, kHandledScanCode);
|
||||
EXPECT_EQ(hook_history.front().was_down, false);
|
||||
EXPECT_EQ(hook_history.back().delegate_id, 2);
|
||||
EXPECT_EQ(hook_history.back().scancode, kHandledScanCode);
|
||||
EXPECT_EQ(hook_history.back().was_down, false);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
|
||||
hook_history.back().callback(true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
// Only resolve after everyone has responded
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
|
||||
hook_history.front().callback(true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
redispatch_scancode = 0;
|
||||
hook_history.clear();
|
||||
}
|
||||
|
||||
// Regression test for a crash in an earlier implementation.
|
||||
//
|
||||
// In real life, the framework responds slowly. The next real event might
|
||||
// arrive earlier than the framework response, and if the 2nd event is identical
|
||||
// to the one waiting for response, an earlier implementation will crash upon
|
||||
// the response.
|
||||
TEST(KeyboardKeyHandlerTest, WithSlowFrameworkResponse) {
|
||||
std::list<MockKeyHandlerDelegate::KeyboardHookCall> hook_history;
|
||||
|
||||
// Capture the scancode of the last redispatched event
|
||||
int redispatch_scancode = 0;
|
||||
bool delegate_handled = false;
|
||||
TestKeyboardKeyHandler handler([&redispatch_scancode](UINT cInputs,
|
||||
LPINPUT pInputs,
|
||||
int cbSize) -> UINT {
|
||||
EXPECT_TRUE(cbSize > 0);
|
||||
redispatch_scancode = pInputs->ki.wScan;
|
||||
return 1;
|
||||
});
|
||||
|
||||
auto delegate1 = std::make_unique<MockKeyHandlerDelegate>(1, &hook_history);
|
||||
CallbackHandler& delegate1_handler = delegate1->callback_handler;
|
||||
handler.AddDelegate(std::move(delegate1));
|
||||
|
||||
// The first native event.
|
||||
EXPECT_EQ(
|
||||
handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN, L'a', false, true),
|
||||
true);
|
||||
|
||||
// The second identical native event, received between the first and its
|
||||
// framework response.
|
||||
EXPECT_EQ(
|
||||
handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN, L'a', false, true),
|
||||
true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
EXPECT_EQ(hook_history.size(), 2);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
|
||||
// The first response.
|
||||
hook_history.front().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kHandledScanCode);
|
||||
EXPECT_EQ(handler.HasRedispatched(), true);
|
||||
|
||||
// Redispatch the first event.
|
||||
EXPECT_EQ(handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN, L'a', false,
|
||||
false),
|
||||
false);
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
redispatch_scancode = 0;
|
||||
|
||||
// The second response.
|
||||
hook_history.back().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kHandledScanCode);
|
||||
EXPECT_EQ(handler.HasRedispatched(), true);
|
||||
|
||||
// Redispatch the second event.
|
||||
EXPECT_EQ(handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN, L'a', false,
|
||||
false),
|
||||
false);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
redispatch_scancode = 0;
|
||||
hook_history.clear();
|
||||
}
|
||||
|
||||
// A key down event for shift right must not be redispatched even if
|
||||
// the framework returns unhandled.
|
||||
//
|
||||
// The reason for this test is documented in |IsKeyDownShiftRight|.
|
||||
TEST(KeyboardKeyHandlerTest, NeverRedispatchShiftRightKeyDown) {
|
||||
std::list<MockKeyHandlerDelegate::KeyboardHookCall> hook_history;
|
||||
|
||||
// Capture the scancode of the last redispatched event
|
||||
int redispatch_scancode = 0;
|
||||
bool delegate_handled = false;
|
||||
TestKeyboardKeyHandler handler([&redispatch_scancode](UINT cInputs,
|
||||
LPINPUT pInputs,
|
||||
int cbSize) -> UINT {
|
||||
EXPECT_TRUE(cbSize > 0);
|
||||
redispatch_scancode = pInputs->ki.wScan;
|
||||
return 1;
|
||||
});
|
||||
|
||||
auto delegate = std::make_unique<MockKeyHandlerDelegate>(1, &hook_history);
|
||||
delegate->callback_handler = respond_false;
|
||||
handler.AddDelegate(std::move(delegate));
|
||||
|
||||
// Press ShiftRight and the delegate responds false.
|
||||
|
||||
delegate_handled = handler.KeyboardHook(VK_RSHIFT, kScanCodeShiftRight,
|
||||
WM_KEYDOWN, 0, false, false);
|
||||
EXPECT_EQ(delegate_handled, true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
EXPECT_EQ(hook_history.size(), 1);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
redispatch_scancode = 0;
|
||||
hook_history.clear();
|
||||
}
|
||||
|
||||
TEST(KeyboardKeyHandlerTest, AltGr) {
|
||||
std::list<MockKeyHandlerDelegate::KeyboardHookCall> hook_history;
|
||||
|
||||
// Capture the scancode of the last redispatched event
|
||||
int redispatch_scancode = 0;
|
||||
TestKeyboardKeyHandler handler([&redispatch_scancode](UINT cInputs,
|
||||
LPINPUT pInputs,
|
||||
int cbSize) -> UINT {
|
||||
EXPECT_TRUE(cbSize > 0);
|
||||
redispatch_scancode = pInputs->ki.wScan;
|
||||
return 1;
|
||||
});
|
||||
|
||||
auto delegate = std::make_unique<MockKeyHandlerDelegate>(1, &hook_history);
|
||||
delegate->callback_handler = dont_respond;
|
||||
handler.AddDelegate(std::move(delegate));
|
||||
|
||||
// Sequence 1: Tap AltGr.
|
||||
|
||||
// The key down event causes a ControlLeft down and a AltRight (extended
|
||||
// AltLeft) down.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYDOWN,
|
||||
0, false, false),
|
||||
true);
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYDOWN, 0,
|
||||
true, false),
|
||||
true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
EXPECT_EQ(hook_history.size(), 2);
|
||||
EXPECT_EQ(hook_history.front().scancode, kScanCodeControlLeft);
|
||||
EXPECT_EQ(hook_history.front().was_down, false);
|
||||
EXPECT_EQ(hook_history.back().scancode, kScanCodeAltLeft);
|
||||
EXPECT_EQ(hook_history.back().was_down, false);
|
||||
|
||||
hook_history.front().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeControlLeft);
|
||||
hook_history.back().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeAltLeft);
|
||||
|
||||
// Resolve redispatches.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYDOWN,
|
||||
0, false, false),
|
||||
false);
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYDOWN, 0,
|
||||
true, false),
|
||||
false);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
redispatch_scancode = 0;
|
||||
hook_history.clear();
|
||||
|
||||
// The key up event only causes a AltRight (extended AltLeft) up.
|
||||
EXPECT_EQ(
|
||||
handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYUP, 0, true, true),
|
||||
true);
|
||||
EXPECT_EQ(hook_history.size(), 1);
|
||||
EXPECT_EQ(hook_history.front().scancode, kScanCodeAltLeft);
|
||||
EXPECT_EQ(hook_history.front().was_down, true);
|
||||
|
||||
// A ControlLeft key up is synthesized.
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeControlLeft);
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYUP, 0,
|
||||
false, true),
|
||||
true);
|
||||
|
||||
EXPECT_EQ(hook_history.back().scancode, kScanCodeControlLeft);
|
||||
EXPECT_EQ(hook_history.back().was_down, true);
|
||||
|
||||
hook_history.front().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeAltLeft);
|
||||
hook_history.back().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeControlLeft);
|
||||
|
||||
// Resolve redispatches.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYUP, 0,
|
||||
false, true),
|
||||
false);
|
||||
EXPECT_EQ(
|
||||
handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYUP, 0, true, true),
|
||||
false);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
redispatch_scancode = 0;
|
||||
hook_history.clear();
|
||||
|
||||
// Sequence 2: Tap CtrlLeft and AltGr.
|
||||
// This also tests tapping AltGr twice in a row when combined with sequence
|
||||
// 1 since "tapping CtrlLeft and AltGr" only sends an extra CtrlLeft key up
|
||||
// than "tapping AltGr".
|
||||
|
||||
// Key down ControlLeft.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYDOWN,
|
||||
0, false, false),
|
||||
true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
EXPECT_EQ(hook_history.size(), 1);
|
||||
EXPECT_EQ(hook_history.front().scancode, kScanCodeControlLeft);
|
||||
EXPECT_EQ(hook_history.front().was_down, false);
|
||||
|
||||
hook_history.front().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeControlLeft);
|
||||
hook_history.clear();
|
||||
redispatch_scancode = 0;
|
||||
|
||||
// Resolve redispatches.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYDOWN,
|
||||
0, false, false),
|
||||
false);
|
||||
|
||||
// Key down AltRight.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYDOWN, 0,
|
||||
true, false),
|
||||
true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
EXPECT_EQ(hook_history.size(), 1);
|
||||
EXPECT_EQ(hook_history.front().scancode, kScanCodeAltLeft);
|
||||
EXPECT_EQ(hook_history.front().was_down, false);
|
||||
|
||||
hook_history.front().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeAltLeft);
|
||||
hook_history.clear();
|
||||
|
||||
// Resolve redispatches.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYDOWN, 0,
|
||||
true, false),
|
||||
false);
|
||||
|
||||
redispatch_scancode = 0;
|
||||
|
||||
// Key up AltRight.
|
||||
EXPECT_EQ(
|
||||
handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYUP, 0, true, true),
|
||||
true);
|
||||
EXPECT_EQ(hook_history.size(), 1);
|
||||
EXPECT_EQ(hook_history.front().scancode, kScanCodeAltLeft);
|
||||
EXPECT_EQ(hook_history.front().was_down, true);
|
||||
|
||||
// A ControlLeft key up is synthesized.
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeControlLeft);
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYUP, 0,
|
||||
false, true),
|
||||
true);
|
||||
|
||||
EXPECT_EQ(hook_history.back().scancode, kScanCodeControlLeft);
|
||||
EXPECT_EQ(hook_history.back().was_down, true);
|
||||
|
||||
hook_history.front().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeAltLeft);
|
||||
hook_history.back().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeControlLeft);
|
||||
|
||||
// Resolve redispatches.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYUP, 0,
|
||||
false, true),
|
||||
false);
|
||||
EXPECT_EQ(
|
||||
handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYUP, 0, true, true),
|
||||
false);
|
||||
|
||||
hook_history.clear();
|
||||
redispatch_scancode = 0;
|
||||
|
||||
// Key up ControlLeft should be dispatched to delegates, but will be properly
|
||||
// handled by delegates' logic.
|
||||
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYUP, 0,
|
||||
false, true),
|
||||
true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
EXPECT_EQ(hook_history.size(), 1);
|
||||
EXPECT_EQ(hook_history.front().scancode, kScanCodeControlLeft);
|
||||
EXPECT_EQ(hook_history.front().was_down, true);
|
||||
|
||||
hook_history.front().callback(true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
hook_history.clear();
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
redispatch_scancode = 0;
|
||||
hook_history.clear();
|
||||
|
||||
// Sequence 3: Hold AltGr for repeated events.
|
||||
// Every AltGr key repeat event is also preceded by a ControlLeft down
|
||||
// (repeat).
|
||||
|
||||
// Key down AltRight.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYDOWN,
|
||||
0, false, false),
|
||||
true);
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYDOWN, 0,
|
||||
true, false),
|
||||
true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
EXPECT_EQ(hook_history.size(), 2);
|
||||
EXPECT_EQ(hook_history.front().scancode, kScanCodeControlLeft);
|
||||
EXPECT_EQ(hook_history.front().was_down, false);
|
||||
EXPECT_EQ(hook_history.back().scancode, kScanCodeAltLeft);
|
||||
EXPECT_EQ(hook_history.back().was_down, false);
|
||||
|
||||
hook_history.front().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeControlLeft);
|
||||
hook_history.back().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeAltLeft);
|
||||
|
||||
// Resolve redispatches.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYDOWN,
|
||||
0, false, false),
|
||||
false);
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYDOWN, 0,
|
||||
true, false),
|
||||
false);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
redispatch_scancode = 0;
|
||||
hook_history.clear();
|
||||
|
||||
// Another key down AltRight.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYDOWN,
|
||||
0, false, true),
|
||||
true);
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYDOWN, 0,
|
||||
true, true),
|
||||
true);
|
||||
EXPECT_EQ(redispatch_scancode, 0);
|
||||
EXPECT_EQ(hook_history.size(), 2);
|
||||
EXPECT_EQ(hook_history.front().scancode, kScanCodeControlLeft);
|
||||
EXPECT_EQ(hook_history.front().was_down, true);
|
||||
EXPECT_EQ(hook_history.back().scancode, kScanCodeAltLeft);
|
||||
EXPECT_EQ(hook_history.back().was_down, true);
|
||||
|
||||
hook_history.front().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeControlLeft);
|
||||
hook_history.back().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeAltLeft);
|
||||
|
||||
// Resolve redispatches.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYDOWN,
|
||||
0, false, false),
|
||||
false);
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYDOWN, 0,
|
||||
true, false),
|
||||
false);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
redispatch_scancode = 0;
|
||||
hook_history.clear();
|
||||
|
||||
// Key up AltRight.
|
||||
EXPECT_EQ(
|
||||
handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYUP, 0, true, true),
|
||||
true);
|
||||
EXPECT_EQ(hook_history.size(), 1);
|
||||
EXPECT_EQ(hook_history.front().scancode, kScanCodeAltLeft);
|
||||
EXPECT_EQ(hook_history.front().was_down, true);
|
||||
|
||||
// A ControlLeft key up is synthesized.
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeControlLeft);
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYUP, 0,
|
||||
false, true),
|
||||
true);
|
||||
|
||||
EXPECT_EQ(hook_history.back().scancode, kScanCodeControlLeft);
|
||||
EXPECT_EQ(hook_history.back().was_down, true);
|
||||
|
||||
hook_history.front().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeAltLeft);
|
||||
hook_history.back().callback(false);
|
||||
EXPECT_EQ(redispatch_scancode, kScanCodeControlLeft);
|
||||
|
||||
// Resolve redispatches.
|
||||
EXPECT_EQ(handler.KeyboardHook(VK_LCONTROL, kScanCodeControlLeft, WM_KEYUP, 0,
|
||||
false, true),
|
||||
false);
|
||||
EXPECT_EQ(
|
||||
handler.KeyboardHook(VK_RMENU, kScanCodeAltLeft, WM_KEYUP, 0, true, true),
|
||||
false);
|
||||
|
||||
EXPECT_EQ(handler.HasRedispatched(), false);
|
||||
redispatch_scancode = 0;
|
||||
hook_history.clear();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
@ -352,10 +352,13 @@ constexpr uint64_t kScanCodeDigit6 = 0x07;
|
||||
// constexpr uint64_t kScanCodeNumpad1 = 0x4f;
|
||||
// constexpr uint64_t kScanCodeNumLock = 0x45;
|
||||
constexpr uint64_t kScanCodeControl = 0x1d;
|
||||
constexpr uint64_t kScanCodeMetaLeft = 0x5b;
|
||||
constexpr uint64_t kScanCodeMetaRight = 0x5c;
|
||||
constexpr uint64_t kScanCodeAlt = 0x38;
|
||||
constexpr uint64_t kScanCodeShiftLeft = 0x2a;
|
||||
constexpr uint64_t kScanCodeShiftRight = 0x36;
|
||||
constexpr uint64_t kScanCodeBracketLeft = 0x1a;
|
||||
constexpr uint64_t kScanCodeArrowLeft = 0x4b;
|
||||
|
||||
constexpr uint64_t kVirtualDigit1 = 0x31;
|
||||
constexpr uint64_t kVirtualKeyA = 0x41;
|
||||
@ -454,6 +457,386 @@ TEST(KeyboardTest, LowerCaseAUnhandled) {
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
}
|
||||
|
||||
TEST(KeyboardTest, ArrowLeftHandled) {
|
||||
KeyboardTester tester;
|
||||
tester.Responding(true);
|
||||
|
||||
// US Keyboard layout
|
||||
|
||||
// Press ArrowLeft
|
||||
tester.InjectMessages(
|
||||
1, WmKeyDownInfo{VK_LEFT, kScanCodeArrowLeft, kExtended, kWasUp}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown,
|
||||
kPhysicalArrowLeft, kLogicalArrowLeft, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 0);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
|
||||
// Release ArrowLeft
|
||||
tester.InjectMessages(
|
||||
1,
|
||||
WmKeyUpInfo{VK_LEFT, kScanCodeArrowLeft, kExtended}.Build(kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalArrowLeft,
|
||||
kLogicalArrowLeft, "", kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 0);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
}
|
||||
|
||||
TEST(KeyboardTest, ArrowLeftUnhandled) {
|
||||
KeyboardTester tester;
|
||||
tester.Responding(false);
|
||||
|
||||
// US Keyboard layout
|
||||
|
||||
// Press ArrowLeft
|
||||
tester.InjectMessages(
|
||||
1, WmKeyDownInfo{VK_LEFT, kScanCodeArrowLeft, kExtended, kWasUp}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown,
|
||||
kPhysicalArrowLeft, kLogicalArrowLeft, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
|
||||
// Release ArrowLeft
|
||||
tester.InjectMessages(
|
||||
1,
|
||||
WmKeyUpInfo{VK_LEFT, kScanCodeArrowLeft, kExtended}.Build(kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalArrowLeft,
|
||||
kLogicalArrowLeft, "", kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
}
|
||||
|
||||
TEST(KeyboardTest, ShiftLeftUnhandled) {
|
||||
KeyboardTester tester;
|
||||
tester.Responding(false);
|
||||
|
||||
// US Keyboard layout
|
||||
|
||||
// Press ShiftLeft
|
||||
tester.SetKeyState(VK_LSHIFT, true, false);
|
||||
tester.InjectMessages(
|
||||
1,
|
||||
WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasUp}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown,
|
||||
kPhysicalShiftLeft, kLogicalShiftLeft, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
|
||||
// Release ShiftLeft
|
||||
tester.SetKeyState(VK_LSHIFT, false, true);
|
||||
tester.InjectMessages(
|
||||
1, WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalShiftLeft,
|
||||
kLogicalShiftLeft, "", kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
}
|
||||
|
||||
TEST(KeyboardTest, ShiftRightUnhandled) {
|
||||
KeyboardTester tester;
|
||||
tester.Responding(false);
|
||||
|
||||
// US Keyboard layout
|
||||
|
||||
// Press ShiftRight
|
||||
tester.SetKeyState(VK_RSHIFT, true, false);
|
||||
tester.InjectMessages(
|
||||
1,
|
||||
WmKeyDownInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended, kWasUp}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown,
|
||||
kPhysicalShiftRight, kLogicalShiftRight, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
// Never redispatch ShiftRight.
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 0);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
|
||||
// Release ShiftRight
|
||||
tester.SetKeyState(VK_RSHIFT, false, true);
|
||||
tester.InjectMessages(
|
||||
1, WmKeyUpInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp,
|
||||
kPhysicalShiftRight, kLogicalShiftRight, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
}
|
||||
|
||||
TEST(KeyboardTest, CtrlLeftUnhandled) {
|
||||
KeyboardTester tester;
|
||||
tester.Responding(false);
|
||||
|
||||
// US Keyboard layout
|
||||
|
||||
// Press CtrlLeft
|
||||
tester.SetKeyState(VK_LCONTROL, true, false);
|
||||
tester.InjectMessages(
|
||||
1,
|
||||
WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown,
|
||||
kPhysicalControlLeft, kLogicalControlLeft, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
|
||||
// Release CtrlLeft
|
||||
tester.SetKeyState(VK_LCONTROL, false, true);
|
||||
tester.InjectMessages(
|
||||
1, WmKeyUpInfo{VK_SHIFT, kScanCodeControl, kNotExtended}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp,
|
||||
kPhysicalControlLeft, kLogicalControlLeft, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
}
|
||||
|
||||
TEST(KeyboardTest, CtrlRightUnhandled) {
|
||||
KeyboardTester tester;
|
||||
tester.Responding(false);
|
||||
|
||||
// US Keyboard layout
|
||||
|
||||
// Press CtrlRight
|
||||
tester.SetKeyState(VK_RCONTROL, true, false);
|
||||
tester.InjectMessages(
|
||||
1, WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kExtended, kWasUp}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown,
|
||||
kPhysicalControlRight, kLogicalControlRight, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
|
||||
// Release CtrlRight
|
||||
tester.SetKeyState(VK_RCONTROL, false, true);
|
||||
tester.InjectMessages(
|
||||
1, WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kExtended}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp,
|
||||
kPhysicalControlRight, kLogicalControlRight, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
}
|
||||
|
||||
TEST(KeyboardTest, AltLeftUnhandled) {
|
||||
KeyboardTester tester;
|
||||
tester.Responding(false);
|
||||
|
||||
// US Keyboard layout
|
||||
|
||||
// Press AltLeft. AltLeft is a SysKeyDown event.
|
||||
tester.SetKeyState(VK_LMENU, true, false);
|
||||
tester.InjectMessages(
|
||||
1, WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kNotExtended, kWasUp}.Build(
|
||||
kWmResultDefault)); // Always pass to the default WndProc.
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalAltLeft,
|
||||
kLogicalAltLeft, "", kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
// Sys events are not redispatched.
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 0);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
|
||||
// Release AltLeft. AltLeft is a SysKeyUp event.
|
||||
tester.SetKeyState(VK_LMENU, false, true);
|
||||
tester.InjectMessages(
|
||||
1, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kNotExtended}.Build(
|
||||
kWmResultDefault)); // Always pass to the default WndProc.
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalAltLeft,
|
||||
kLogicalAltLeft, "", kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
// Sys events are not redispatched.
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 0);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
}
|
||||
|
||||
TEST(KeyboardTest, AltRightUnhandled) {
|
||||
KeyboardTester tester;
|
||||
tester.Responding(false);
|
||||
|
||||
// US Keyboard layout
|
||||
|
||||
// Press AltRight. AltRight is a SysKeyDown event.
|
||||
tester.SetKeyState(VK_RMENU, true, false);
|
||||
tester.InjectMessages(
|
||||
1, WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
|
||||
kWmResultDefault)); // Always pass to the default WndProc.
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown,
|
||||
kPhysicalAltRight, kLogicalAltRight, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
// Sys events are not redispatched.
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 0);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
|
||||
// Release AltRight. AltRight is a SysKeyUp event.
|
||||
tester.SetKeyState(VK_RMENU, false, true);
|
||||
tester.InjectMessages(
|
||||
1, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
|
||||
kWmResultDefault)); // Always pass to the default WndProc.
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalAltRight,
|
||||
kLogicalAltRight, "", kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
// Sys events are not redispatched.
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 0);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
}
|
||||
|
||||
TEST(KeyboardTest, MetaLeftUnhandled) {
|
||||
KeyboardTester tester;
|
||||
tester.Responding(false);
|
||||
|
||||
// US Keyboard layout
|
||||
|
||||
// Press MetaLeft
|
||||
tester.SetKeyState(VK_LWIN, true, false);
|
||||
tester.InjectMessages(
|
||||
1, WmKeyDownInfo{VK_LWIN, kScanCodeMetaLeft, kExtended, kWasUp}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown,
|
||||
kPhysicalMetaLeft, kLogicalMetaLeft, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
|
||||
// Release MetaLeft
|
||||
tester.SetKeyState(VK_LWIN, false, true);
|
||||
tester.InjectMessages(
|
||||
1,
|
||||
WmKeyUpInfo{VK_LWIN, kScanCodeMetaLeft, kExtended}.Build(kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalMetaLeft,
|
||||
kLogicalMetaLeft, "", kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
}
|
||||
|
||||
TEST(KeyboardTest, MetaRightUnhandled) {
|
||||
KeyboardTester tester;
|
||||
tester.Responding(false);
|
||||
|
||||
// US Keyboard layout
|
||||
|
||||
// Press MetaRight
|
||||
tester.SetKeyState(VK_RWIN, true, false);
|
||||
tester.InjectMessages(
|
||||
1, WmKeyDownInfo{VK_RWIN, kScanCodeMetaRight, kExtended, kWasUp}.Build(
|
||||
kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown,
|
||||
kPhysicalMetaRight, kLogicalMetaRight, "",
|
||||
kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
|
||||
// Release MetaRight
|
||||
tester.SetKeyState(VK_RWIN, false, true);
|
||||
tester.InjectMessages(
|
||||
1,
|
||||
WmKeyUpInfo{VK_RWIN, kScanCodeMetaRight, kExtended}.Build(kWmResultZero));
|
||||
|
||||
EXPECT_EQ(key_calls.size(), 1);
|
||||
EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalMetaRight,
|
||||
kLogicalMetaRight, "", kNotSynthesized);
|
||||
clear_key_calls();
|
||||
|
||||
EXPECT_EQ(tester.InjectPendingEvents(), 1);
|
||||
EXPECT_EQ(key_calls.size(), 0);
|
||||
clear_key_calls();
|
||||
}
|
||||
|
||||
// Press Shift-A. This is special because Win32 gives 'A' as character for the
|
||||
// KeyA press.
|
||||
TEST(KeyboardTest, ShiftLeftKeyA) {
|
||||
|
||||
@ -44,6 +44,19 @@ Win32Message WmCharInfo::Build(LRESULT expected_result, HWND hWnd) {
|
||||
};
|
||||
}
|
||||
|
||||
Win32Message WmSysKeyDownInfo::Build(LRESULT expected_result, HWND hWnd) {
|
||||
uint32_t lParam = (repeat_count << 0) | (scan_code << 16) | (extended << 24) |
|
||||
(context << 29) | (prev_state << 30) |
|
||||
(0 /* transition */ << 31);
|
||||
return Win32Message{
|
||||
.message = WM_SYSKEYDOWN,
|
||||
.wParam = key,
|
||||
.lParam = lParam,
|
||||
.expected_result = expected_result,
|
||||
.hWnd = hWnd,
|
||||
};
|
||||
}
|
||||
|
||||
Win32Message WmSysKeyUpInfo::Build(LRESULT expected_result, HWND hWnd) {
|
||||
uint32_t lParam = (1 /* repeat_count */ << 0) | (scan_code << 16) |
|
||||
(extended << 24) | (context << 29) |
|
||||
|
||||
@ -115,6 +115,28 @@ typedef struct WmCharInfo {
|
||||
HWND hWnd = NULL);
|
||||
} WmCharInfo;
|
||||
|
||||
// WM_SYSKEYDOWN messages.
|
||||
//
|
||||
// See https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-syskeydown.
|
||||
typedef struct WmSysKeyDownInfo {
|
||||
uint32_t key;
|
||||
|
||||
uint8_t scan_code;
|
||||
|
||||
WmFieldExtended extended;
|
||||
|
||||
WmFieldPrevState prev_state;
|
||||
|
||||
// WmFieldTransitionState transition; // Always 0.
|
||||
|
||||
WmFieldContext context;
|
||||
|
||||
uint16_t repeat_count;
|
||||
|
||||
Win32Message Build(LRESULT expected_result = kWmResultDontCheck,
|
||||
HWND hWnd = NULL);
|
||||
} WmSysKeyDownInfo;
|
||||
|
||||
// WM_SYSKEYUP messages.
|
||||
//
|
||||
// See https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-syskeyup.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user