| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <memory> |
| #include <optional> |
| #include <vector> |
| |
| #include "base/containers/flat_set.h" |
| #include "base/functional/bind.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/events/event.h" |
| #include "ui/events/keyboard_hook.h" |
| #include "ui/events/keycodes/dom/dom_code.h" |
| #include "ui/events/keycodes/dom/keycode_converter.h" |
| #include "ui/events/keycodes/keyboard_codes.h" |
| #include "ui/events/test/keyboard_layout.h" |
| #include "ui/events/win/keyboard_hook_win_base.h" |
| #include "ui/events/win/system_event_state_lookup.h" |
| |
| namespace ui { |
| |
| class ModifierKeyboardHookWinTest : public testing::Test { |
| public: |
| ModifierKeyboardHookWinTest(); |
| |
| ModifierKeyboardHookWinTest(const ModifierKeyboardHookWinTest&) = delete; |
| ModifierKeyboardHookWinTest& operator=(const ModifierKeyboardHookWinTest&) = |
| delete; |
| |
| ~ModifierKeyboardHookWinTest() override; |
| |
| // testing::Test overrides. |
| void SetUp() override; |
| |
| void HandleKeyPress(KeyEvent* key_event); |
| |
| protected: |
| KeyboardHookWinBase* keyboard_hook() { return keyboard_hook_.get(); } |
| |
| uint32_t next_time_stamp() { return time_stamp_++; } |
| |
| std::vector<KeyEvent>* key_events() { return &key_events_; } |
| |
| // Used for sending key events which are handled by the hook. |
| void SendModifierKeyDownEvent(KeyboardCode key_code, |
| DomCode dom_code, |
| int repeat_count = 1); |
| void SendModifierKeyUpEvent(KeyboardCode key_code, DomCode dom_code); |
| |
| void SetKeyboardLayoutForTest(KeyboardLayout new_layout); |
| |
| private: |
| uint32_t time_stamp_ = 0; |
| std::unique_ptr<KeyboardHookWinBase> keyboard_hook_; |
| std::vector<KeyEvent> key_events_; |
| std::unique_ptr<ScopedKeyboardLayout> keyboard_layout_; |
| }; |
| |
| ModifierKeyboardHookWinTest::ModifierKeyboardHookWinTest() = default; |
| |
| ModifierKeyboardHookWinTest::~ModifierKeyboardHookWinTest() = default; |
| |
| void ModifierKeyboardHookWinTest::SetUp() { |
| keyboard_hook_ = KeyboardHookWinBase::CreateModifierKeyboardHookForTesting( |
| std::optional<base::flat_set<DomCode>>(), |
| base::BindRepeating(&ModifierKeyboardHookWinTest::HandleKeyPress, |
| base::Unretained(this))); |
| |
| keyboard_layout_ = std::make_unique<ScopedKeyboardLayout>( |
| KeyboardLayout::KEYBOARD_LAYOUT_ENGLISH_US); |
| } |
| |
| void ModifierKeyboardHookWinTest::HandleKeyPress(KeyEvent* key_event) { |
| key_events_.push_back(*key_event); |
| } |
| |
| void ModifierKeyboardHookWinTest::SendModifierKeyDownEvent( |
| KeyboardCode key_code, |
| DomCode dom_code, |
| int repeat_count /*=1*/) { |
| // Ensure we have a valid repeat count and the modifer passed in contains |
| // location information. |
| DCHECK_GT(repeat_count, 0); |
| DCHECK_NE(key_code, KeyboardCode::VKEY_CONTROL); |
| DCHECK_NE(key_code, KeyboardCode::VKEY_MENU); |
| |
| for (int i = 0; i < repeat_count; i++) { |
| ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYDOWN, key_code, |
| KeycodeConverter::DomCodeToNativeKeycode(dom_code), next_time_stamp())); |
| } |
| } |
| |
| void ModifierKeyboardHookWinTest::SendModifierKeyUpEvent(KeyboardCode key_code, |
| DomCode dom_code) { |
| // Ensure we have a valid repeat count and the modifer passed in contains |
| // location information. |
| DCHECK_NE(key_code, KeyboardCode::VKEY_CONTROL); |
| DCHECK_NE(key_code, KeyboardCode::VKEY_MENU); |
| |
| ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYUP, key_code, KeycodeConverter::DomCodeToNativeKeycode(dom_code), |
| next_time_stamp())); |
| } |
| |
| namespace { |
| void VerifyKeyEvent(KeyEvent* key_event, |
| KeyboardCode non_located_key_code, |
| DomCode dom_code, |
| bool key_down, |
| bool is_repeat) { |
| if (key_down) { |
| ASSERT_EQ(key_event->type(), ET_KEY_PRESSED); |
| ASSERT_EQ(key_event->is_repeat(), is_repeat); |
| } else { |
| ASSERT_EQ(key_event->type(), ET_KEY_RELEASED); |
| ASSERT_FALSE(key_event->is_repeat()); |
| } |
| ASSERT_EQ(key_event->key_code(), non_located_key_code); |
| ASSERT_EQ(key_event->code(), dom_code); |
| } |
| } // namespace |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleLeftControlKeypressTest) { |
| const KeyboardCode key_code = KeyboardCode::VKEY_LCONTROL; |
| const DomCode dom_code = DomCode::CONTROL_LEFT; |
| SendModifierKeyDownEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 1ULL); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 2ULL); |
| |
| KeyEvent down_event = key_events()->at(0); |
| VerifyKeyEvent(&down_event, KeyboardCode::VKEY_CONTROL, dom_code, true, |
| false); |
| ASSERT_TRUE(down_event.IsControlDown()); |
| ASSERT_FALSE(down_event.IsAltDown()); |
| ASSERT_FALSE(down_event.IsCommandDown()); |
| |
| KeyEvent up_event = key_events()->at(1); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_CONTROL, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsControlDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, RepeatingLeftControlKeypressTest) { |
| const int repeat_count = 10; |
| const KeyboardCode key_code = KeyboardCode::VKEY_LCONTROL; |
| const DomCode dom_code = DomCode::CONTROL_LEFT; |
| SendModifierKeyDownEvent(key_code, dom_code, repeat_count); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count + 1); |
| |
| bool should_repeat = false; |
| for (int i = 0; i < repeat_count; i++) { |
| KeyEvent event = key_events()->at(i); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, dom_code, true, |
| should_repeat); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| should_repeat = true; |
| } |
| |
| KeyEvent up_event = key_events()->at(repeat_count); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_CONTROL, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsControlDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleRightControlKeypressTest) { |
| const KeyboardCode key_code = KeyboardCode::VKEY_RCONTROL; |
| const DomCode dom_code = DomCode::CONTROL_RIGHT; |
| SendModifierKeyDownEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 1ULL); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 2ULL); |
| |
| KeyEvent down_event = key_events()->at(0); |
| VerifyKeyEvent(&down_event, KeyboardCode::VKEY_CONTROL, dom_code, true, |
| false); |
| ASSERT_TRUE(down_event.IsControlDown()); |
| ASSERT_FALSE(down_event.IsAltDown()); |
| ASSERT_FALSE(down_event.IsCommandDown()); |
| |
| KeyEvent up_event = key_events()->at(1); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_CONTROL, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsControlDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, RepeatingRightControlKeypressTest) { |
| const int repeat_count = 10; |
| const KeyboardCode key_code = KeyboardCode::VKEY_RCONTROL; |
| const DomCode dom_code = DomCode::CONTROL_RIGHT; |
| SendModifierKeyDownEvent(key_code, dom_code, repeat_count); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count + 1); |
| |
| bool should_repeat = false; |
| for (int i = 0; i < repeat_count; i++) { |
| KeyEvent event = key_events()->at(i); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, dom_code, true, |
| should_repeat); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| should_repeat = true; |
| } |
| |
| KeyEvent up_event = key_events()->at(repeat_count); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_CONTROL, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsControlDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleLifoControlSequenceTest) { |
| const KeyboardCode left_key_code = KeyboardCode::VKEY_LCONTROL; |
| const DomCode left_dom_code = DomCode::CONTROL_LEFT; |
| const KeyboardCode right_key_code = KeyboardCode::VKEY_RCONTROL; |
| const DomCode right_dom_code = DomCode::CONTROL_RIGHT; |
| SendModifierKeyDownEvent(left_key_code, left_dom_code, 2); |
| SendModifierKeyDownEvent(right_key_code, right_dom_code, 2); |
| SendModifierKeyUpEvent(right_key_code, right_dom_code); |
| SendModifierKeyUpEvent(left_key_code, left_dom_code); |
| ASSERT_EQ(key_events()->size(), 6ULL); |
| |
| // First key down, no repeat. |
| KeyEvent event = key_events()->at(0); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, left_dom_code, true, |
| false); |
| ASSERT_TRUE(event.IsControlDown()); |
| |
| // First key still down, repeat. |
| event = key_events()->at(1); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, left_dom_code, true, true); |
| ASSERT_TRUE(event.IsControlDown()); |
| |
| // Second key down, repeat. |
| event = key_events()->at(2); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, right_dom_code, true, |
| true); |
| ASSERT_TRUE(event.IsControlDown()); |
| |
| // Second key still down, repeat. |
| event = key_events()->at(3); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, right_dom_code, true, |
| true); |
| ASSERT_TRUE(event.IsControlDown()); |
| |
| // Second key up. |
| event = key_events()->at(4); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, right_dom_code, false, |
| false); |
| ASSERT_TRUE(event.IsControlDown()); |
| |
| // First key up. |
| event = key_events()->at(5); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, left_dom_code, false, |
| false); |
| ASSERT_FALSE(event.IsControlDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleFifoControlSequenceTest) { |
| const KeyboardCode left_key_code = KeyboardCode::VKEY_LCONTROL; |
| const DomCode left_dom_code = DomCode::CONTROL_LEFT; |
| const KeyboardCode right_key_code = KeyboardCode::VKEY_RCONTROL; |
| const DomCode right_dom_code = DomCode::CONTROL_RIGHT; |
| SendModifierKeyDownEvent(right_key_code, right_dom_code, 2); |
| SendModifierKeyDownEvent(left_key_code, left_dom_code, 2); |
| SendModifierKeyUpEvent(right_key_code, right_dom_code); |
| SendModifierKeyUpEvent(left_key_code, left_dom_code); |
| ASSERT_EQ(key_events()->size(), 6ULL); |
| |
| // First key down, no repeat. |
| KeyEvent event = key_events()->at(0); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, right_dom_code, true, |
| false); |
| ASSERT_TRUE(event.IsControlDown()); |
| |
| // First key still down, repeat. |
| event = key_events()->at(1); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, right_dom_code, true, |
| true); |
| ASSERT_TRUE(event.IsControlDown()); |
| |
| // Second key down, repeat. |
| event = key_events()->at(2); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, left_dom_code, true, true); |
| ASSERT_TRUE(event.IsControlDown()); |
| |
| // Second key still down, repeat. |
| event = key_events()->at(3); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, left_dom_code, true, true); |
| ASSERT_TRUE(event.IsControlDown()); |
| |
| // First key up. |
| event = key_events()->at(4); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, right_dom_code, false, |
| false); |
| ASSERT_TRUE(event.IsControlDown()); |
| |
| // Second key up. |
| event = key_events()->at(5); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, left_dom_code, false, |
| false); |
| ASSERT_FALSE(event.IsControlDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleLeftAltKeypressTest) { |
| const KeyboardCode key_code = KeyboardCode::VKEY_LMENU; |
| const DomCode dom_code = DomCode::ALT_LEFT; |
| SendModifierKeyDownEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 1ULL); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 2ULL); |
| |
| KeyEvent down_event = key_events()->at(0); |
| VerifyKeyEvent(&down_event, KeyboardCode::VKEY_MENU, dom_code, true, false); |
| ASSERT_FALSE(down_event.IsControlDown()); |
| ASSERT_TRUE(down_event.IsAltDown()); |
| ASSERT_FALSE(down_event.IsCommandDown()); |
| |
| KeyEvent up_event = key_events()->at(1); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_MENU, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsAltDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, RepeatingLeftAltKeypressTest) { |
| const int repeat_count = 10; |
| const KeyboardCode key_code = KeyboardCode::VKEY_LMENU; |
| const DomCode dom_code = DomCode::ALT_LEFT; |
| SendModifierKeyDownEvent(key_code, dom_code, repeat_count); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count + 1); |
| |
| bool should_repeat = false; |
| for (int i = 0; i < repeat_count; i++) { |
| KeyEvent event = key_events()->at(i); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, dom_code, true, |
| should_repeat); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_TRUE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| should_repeat = true; |
| } |
| |
| KeyEvent up_event = key_events()->at(repeat_count); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_MENU, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsAltDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleRightAltKeypressTest) { |
| const KeyboardCode key_code = KeyboardCode::VKEY_RMENU; |
| const DomCode dom_code = DomCode::ALT_LEFT; |
| SendModifierKeyDownEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 1ULL); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 2ULL); |
| |
| KeyEvent down_event = key_events()->at(0); |
| VerifyKeyEvent(&down_event, KeyboardCode::VKEY_MENU, dom_code, true, false); |
| ASSERT_FALSE(down_event.IsControlDown()); |
| ASSERT_TRUE(down_event.IsAltDown()); |
| ASSERT_FALSE(down_event.IsCommandDown()); |
| |
| KeyEvent up_event = key_events()->at(1); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_MENU, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsAltDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, RepeatingRightAltKeypressTest) { |
| const int repeat_count = 10; |
| const KeyboardCode key_code = KeyboardCode::VKEY_RMENU; |
| const DomCode dom_code = DomCode::ALT_RIGHT; |
| SendModifierKeyDownEvent(key_code, dom_code, repeat_count); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count + 1); |
| |
| bool should_repeat = false; |
| for (int i = 0; i < repeat_count; i++) { |
| KeyEvent event = key_events()->at(i); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, dom_code, true, |
| should_repeat); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_TRUE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| should_repeat = true; |
| } |
| |
| KeyEvent up_event = key_events()->at(repeat_count); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_MENU, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsAltDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleLifoAltSequenceTest) { |
| const KeyboardCode left_key_code = KeyboardCode::VKEY_LMENU; |
| const DomCode left_dom_code = DomCode::ALT_LEFT; |
| const KeyboardCode right_key_code = KeyboardCode::VKEY_RMENU; |
| const DomCode right_dom_code = DomCode::ALT_RIGHT; |
| SendModifierKeyDownEvent(left_key_code, left_dom_code, 2); |
| SendModifierKeyDownEvent(right_key_code, right_dom_code, 2); |
| SendModifierKeyUpEvent(right_key_code, right_dom_code); |
| SendModifierKeyUpEvent(left_key_code, left_dom_code); |
| ASSERT_EQ(key_events()->size(), 6ULL); |
| |
| // First key down, no repeat. |
| KeyEvent event = key_events()->at(0); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, left_dom_code, true, false); |
| ASSERT_TRUE(event.IsAltDown()); |
| |
| // First key still down, repeat. |
| event = key_events()->at(1); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, left_dom_code, true, true); |
| ASSERT_TRUE(event.IsAltDown()); |
| |
| // Second key down, repeat. |
| event = key_events()->at(2); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, right_dom_code, true, true); |
| ASSERT_TRUE(event.IsAltDown()); |
| |
| // Second key still down, repeat. |
| event = key_events()->at(3); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, right_dom_code, true, true); |
| ASSERT_TRUE(event.IsAltDown()); |
| |
| // Second key up. |
| event = key_events()->at(4); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, right_dom_code, false, false); |
| ASSERT_TRUE(event.IsAltDown()); |
| |
| // First key up. |
| event = key_events()->at(5); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, left_dom_code, false, false); |
| ASSERT_FALSE(event.IsAltDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleFifoAltSequenceTest) { |
| const KeyboardCode left_key_code = KeyboardCode::VKEY_LMENU; |
| const DomCode left_dom_code = DomCode::ALT_LEFT; |
| const KeyboardCode right_key_code = KeyboardCode::VKEY_RMENU; |
| const DomCode right_dom_code = DomCode::ALT_RIGHT; |
| SendModifierKeyDownEvent(right_key_code, right_dom_code, 2); |
| SendModifierKeyDownEvent(left_key_code, left_dom_code, 2); |
| SendModifierKeyUpEvent(right_key_code, right_dom_code); |
| SendModifierKeyUpEvent(left_key_code, left_dom_code); |
| ASSERT_EQ(key_events()->size(), 6ULL); |
| |
| // First key down, no repeat. |
| KeyEvent event = key_events()->at(0); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, right_dom_code, true, false); |
| ASSERT_TRUE(event.IsAltDown()); |
| |
| // First key still down, repeat. |
| event = key_events()->at(1); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, right_dom_code, true, true); |
| ASSERT_TRUE(event.IsAltDown()); |
| |
| // Second key down, repeat. |
| event = key_events()->at(2); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, left_dom_code, true, true); |
| ASSERT_TRUE(event.IsAltDown()); |
| |
| // Second key still down, repeat. |
| event = key_events()->at(3); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, left_dom_code, true, true); |
| ASSERT_TRUE(event.IsAltDown()); |
| |
| // First key up. |
| event = key_events()->at(4); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, right_dom_code, false, false); |
| ASSERT_TRUE(event.IsAltDown()); |
| |
| // Second key up. |
| event = key_events()->at(5); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, left_dom_code, false, false); |
| ASSERT_FALSE(event.IsAltDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleLeftWinKeypressTest) { |
| const KeyboardCode key_code = KeyboardCode::VKEY_LWIN; |
| const DomCode dom_code = DomCode::META_LEFT; |
| SendModifierKeyDownEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 1ULL); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 2ULL); |
| |
| KeyEvent down_event = key_events()->at(0); |
| // VKEY_LWIN is the 'non-located' version of the Windows key. |
| VerifyKeyEvent(&down_event, KeyboardCode::VKEY_LWIN, dom_code, true, false); |
| ASSERT_FALSE(down_event.IsControlDown()); |
| ASSERT_FALSE(down_event.IsAltDown()); |
| ASSERT_TRUE(down_event.IsCommandDown()); |
| |
| KeyEvent up_event = key_events()->at(1); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_LWIN, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsCommandDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, RepeatingLeftWinKeypressTest) { |
| const int repeat_count = 10; |
| const KeyboardCode key_code = KeyboardCode::VKEY_LWIN; |
| const DomCode dom_code = DomCode::META_LEFT; |
| SendModifierKeyDownEvent(key_code, dom_code, repeat_count); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count + 1); |
| |
| bool should_repeat = false; |
| for (int i = 0; i < repeat_count; i++) { |
| KeyEvent event = key_events()->at(i); |
| // VKEY_LWIN is the 'non-located' version of the Windows key. |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_LWIN, dom_code, true, |
| should_repeat); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| should_repeat = true; |
| } |
| |
| KeyEvent up_event = key_events()->at(repeat_count); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_LWIN, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsCommandDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleRightWinKeypressTest) { |
| const KeyboardCode key_code = KeyboardCode::VKEY_RWIN; |
| const DomCode dom_code = DomCode::META_RIGHT; |
| SendModifierKeyDownEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 1ULL); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(key_events()->size(), 2ULL); |
| |
| KeyEvent down_event = key_events()->at(0); |
| // VKEY_LWIN is the 'non-located' version of the Windows key. |
| VerifyKeyEvent(&down_event, KeyboardCode::VKEY_RWIN, dom_code, true, false); |
| ASSERT_FALSE(down_event.IsControlDown()); |
| ASSERT_FALSE(down_event.IsAltDown()); |
| ASSERT_TRUE(down_event.IsCommandDown()); |
| |
| KeyEvent up_event = key_events()->at(1); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_RWIN, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsCommandDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, RepeatingRightWinKeypressTest) { |
| const int repeat_count = 10; |
| const KeyboardCode key_code = KeyboardCode::VKEY_RWIN; |
| const DomCode dom_code = DomCode::META_RIGHT; |
| SendModifierKeyDownEvent(key_code, dom_code, repeat_count); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count); |
| SendModifierKeyUpEvent(key_code, dom_code); |
| ASSERT_EQ(static_cast<int>(key_events()->size()), repeat_count + 1); |
| |
| bool should_repeat = false; |
| for (int i = 0; i < repeat_count; i++) { |
| KeyEvent event = key_events()->at(i); |
| // VKEY_LWIN is the 'non-located' version of the Windows key. |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_RWIN, dom_code, true, |
| should_repeat); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| should_repeat = true; |
| } |
| |
| KeyEvent up_event = key_events()->at(repeat_count); |
| VerifyKeyEvent(&up_event, KeyboardCode::VKEY_RWIN, dom_code, false, false); |
| ASSERT_FALSE(up_event.IsCommandDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleLifoWinSequenceTest) { |
| const KeyboardCode left_key_code = KeyboardCode::VKEY_LWIN; |
| const DomCode left_dom_code = DomCode::META_LEFT; |
| const KeyboardCode right_key_code = KeyboardCode::VKEY_RWIN; |
| const DomCode right_dom_code = DomCode::META_RIGHT; |
| SendModifierKeyDownEvent(left_key_code, left_dom_code, 2); |
| SendModifierKeyDownEvent(right_key_code, right_dom_code, 2); |
| SendModifierKeyUpEvent(right_key_code, right_dom_code); |
| SendModifierKeyUpEvent(left_key_code, left_dom_code); |
| ASSERT_EQ(key_events()->size(), 6ULL); |
| |
| // First key down, no repeat. |
| KeyEvent event = key_events()->at(0); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_LWIN, left_dom_code, true, false); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // First key still down, repeat. |
| event = key_events()->at(1); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_LWIN, left_dom_code, true, true); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Second key down, no repeat. |
| event = key_events()->at(2); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_RWIN, right_dom_code, true, false); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Second key still down, repeat. |
| event = key_events()->at(3); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_RWIN, right_dom_code, true, true); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Second key up. |
| event = key_events()->at(4); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_RWIN, right_dom_code, false, false); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // First key up. |
| event = key_events()->at(5); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_LWIN, left_dom_code, false, false); |
| ASSERT_FALSE(event.IsCommandDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleFifoWinSequenceTest) { |
| const KeyboardCode left_key_code = KeyboardCode::VKEY_LWIN; |
| const DomCode left_dom_code = DomCode::META_LEFT; |
| const KeyboardCode right_key_code = KeyboardCode::VKEY_RWIN; |
| const DomCode right_dom_code = DomCode::META_RIGHT; |
| SendModifierKeyDownEvent(right_key_code, right_dom_code, 2); |
| SendModifierKeyDownEvent(left_key_code, left_dom_code, 2); |
| SendModifierKeyUpEvent(right_key_code, right_dom_code); |
| SendModifierKeyUpEvent(left_key_code, left_dom_code); |
| ASSERT_EQ(key_events()->size(), 6ULL); |
| |
| // First key down, no repeat. |
| KeyEvent event = key_events()->at(0); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_RWIN, right_dom_code, true, false); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // First key still down, repeat. |
| event = key_events()->at(1); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_RWIN, right_dom_code, true, true); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Second key down, no repeat. |
| event = key_events()->at(2); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_LWIN, left_dom_code, true, false); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Second key still down, repeat. |
| event = key_events()->at(3); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_LWIN, left_dom_code, true, true); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // First key up. |
| event = key_events()->at(4); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_RWIN, right_dom_code, false, false); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Second key up. |
| event = key_events()->at(5); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_LWIN, left_dom_code, false, false); |
| ASSERT_FALSE(event.IsCommandDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, CombinedModifierLifoSequenceKeypressTest) { |
| const KeyboardCode first_key_code = KeyboardCode::VKEY_LCONTROL; |
| const DomCode first_dom_code = DomCode::CONTROL_LEFT; |
| const KeyboardCode second_key_code = KeyboardCode::VKEY_RWIN; |
| const DomCode second_dom_code = DomCode::META_RIGHT; |
| const KeyboardCode third_key_code = KeyboardCode::VKEY_LMENU; |
| const DomCode third_dom_code = DomCode::ALT_LEFT; |
| SendModifierKeyDownEvent(first_key_code, first_dom_code, 2); |
| SendModifierKeyDownEvent(second_key_code, second_dom_code, 2); |
| SendModifierKeyDownEvent(third_key_code, third_dom_code, 2); |
| SendModifierKeyUpEvent(third_key_code, third_dom_code); |
| SendModifierKeyUpEvent(second_key_code, second_dom_code); |
| SendModifierKeyUpEvent(first_key_code, first_dom_code); |
| ASSERT_EQ(key_events()->size(), 9ULL); |
| |
| // First key down, no repeat. |
| KeyEvent event = key_events()->at(0); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, first_dom_code, true, |
| false); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // First key still down, repeat. |
| event = key_events()->at(1); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, first_dom_code, true, |
| true); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // Second key down, no repeat. |
| event = key_events()->at(2); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_RWIN, second_dom_code, true, false); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Second key still down, repeat. |
| event = key_events()->at(3); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_RWIN, second_dom_code, true, true); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Third key down, no repeat. |
| event = key_events()->at(4); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, third_dom_code, true, false); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_TRUE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Third key still down, repeat. |
| event = key_events()->at(5); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, third_dom_code, true, true); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_TRUE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Third key up. |
| event = key_events()->at(6); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, third_dom_code, false, false); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Second key up. |
| event = key_events()->at(7); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_RWIN, second_dom_code, false, |
| false); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // First key up. |
| event = key_events()->at(8); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, first_dom_code, false, |
| false); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, CombinedModifierFifoSequenceKeypressTest) { |
| const KeyboardCode first_key_code = KeyboardCode::VKEY_RCONTROL; |
| const DomCode first_dom_code = DomCode::CONTROL_RIGHT; |
| const KeyboardCode second_key_code = KeyboardCode::VKEY_LWIN; |
| const DomCode second_dom_code = DomCode::META_LEFT; |
| const KeyboardCode third_key_code = KeyboardCode::VKEY_RMENU; |
| const DomCode third_dom_code = DomCode::ALT_RIGHT; |
| SendModifierKeyDownEvent(first_key_code, first_dom_code, 2); |
| SendModifierKeyDownEvent(second_key_code, second_dom_code, 2); |
| SendModifierKeyDownEvent(third_key_code, third_dom_code, 2); |
| SendModifierKeyUpEvent(first_key_code, first_dom_code); |
| SendModifierKeyUpEvent(second_key_code, second_dom_code); |
| SendModifierKeyUpEvent(third_key_code, third_dom_code); |
| ASSERT_EQ(key_events()->size(), 9ULL); |
| |
| // First key down, no repeat. |
| KeyEvent event = key_events()->at(0); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, first_dom_code, true, |
| false); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // First key still down, repeat. |
| event = key_events()->at(1); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, first_dom_code, true, |
| true); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // Second key down, no repeat. |
| event = key_events()->at(2); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_LWIN, second_dom_code, true, false); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Second key still down, repeat. |
| event = key_events()->at(3); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_LWIN, second_dom_code, true, true); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Third key down, no repeat. |
| event = key_events()->at(4); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, third_dom_code, true, false); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_TRUE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Third key still down, repeat. |
| event = key_events()->at(5); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, third_dom_code, true, true); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_TRUE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // First key up. |
| event = key_events()->at(6); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, first_dom_code, false, |
| false); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_TRUE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsCommandDown()); |
| |
| // Second key up. |
| event = key_events()->at(7); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_LWIN, second_dom_code, false, |
| false); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_TRUE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // Third key up. |
| event = key_events()->at(8); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, third_dom_code, false, false); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, VerifyPlatformModifierStateTest) { |
| SendModifierKeyDownEvent(KeyboardCode::VKEY_LCONTROL, DomCode::CONTROL_LEFT); |
| ASSERT_TRUE(win::IsCtrlPressed()); |
| ASSERT_FALSE(win::IsAltPressed()); |
| ASSERT_FALSE(win::IsWindowsKeyPressed()); |
| |
| SendModifierKeyDownEvent(KeyboardCode::VKEY_RWIN, DomCode::META_RIGHT); |
| ASSERT_TRUE(win::IsCtrlPressed()); |
| ASSERT_FALSE(win::IsAltPressed()); |
| ASSERT_TRUE(win::IsWindowsKeyPressed()); |
| |
| SendModifierKeyDownEvent(KeyboardCode::VKEY_LMENU, DomCode::ALT_LEFT); |
| ASSERT_TRUE(win::IsCtrlPressed()); |
| ASSERT_TRUE(win::IsAltPressed()); |
| ASSERT_FALSE(win::IsAltRightPressed()); |
| ASSERT_TRUE(win::IsWindowsKeyPressed()); |
| |
| SendModifierKeyUpEvent(KeyboardCode::VKEY_RWIN, DomCode::META_RIGHT); |
| ASSERT_TRUE(win::IsCtrlPressed()); |
| ASSERT_TRUE(win::IsAltPressed()); |
| ASSERT_FALSE(win::IsWindowsKeyPressed()); |
| |
| SendModifierKeyUpEvent(KeyboardCode::VKEY_LCONTROL, DomCode::CONTROL_LEFT); |
| ASSERT_FALSE(win::IsCtrlPressed()); |
| ASSERT_TRUE(win::IsAltPressed()); |
| ASSERT_FALSE(win::IsWindowsKeyPressed()); |
| |
| SendModifierKeyUpEvent(KeyboardCode::VKEY_LMENU, DomCode::ALT_LEFT); |
| ASSERT_FALSE(win::IsCtrlPressed()); |
| ASSERT_FALSE(win::IsAltPressed()); |
| ASSERT_FALSE(win::IsWindowsKeyPressed()); |
| |
| SendModifierKeyDownEvent(KeyboardCode::VKEY_RMENU, DomCode::ALT_RIGHT); |
| ASSERT_TRUE(win::IsAltPressed()); |
| ASSERT_TRUE(win::IsAltRightPressed()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, SimpleAltGrKeyPressTest) { |
| ScopedKeyboardLayout keyboard_layout(KeyboardLayout::KEYBOARD_LAYOUT_GERMAN); |
| |
| // AltGr produces two events, an injected, modified scan code for VK_LCONTROL, |
| // and an event for VK_RMENU. We simulate that sequence here. |
| const KeyboardCode altgr_key_code = KeyboardCode::VKEY_RMENU; |
| const DomCode altgr_dom_code = DomCode::ALT_RIGHT; |
| const DomCode control_dom_code = DomCode::CONTROL_LEFT; |
| const DWORD control_scan_code = |
| KeycodeConverter::DomCodeToNativeKeycode(control_dom_code); |
| const DWORD injected_control_scan_code = control_scan_code | 0x0200; |
| |
| ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYDOWN, KeyboardCode::VKEY_LCONTROL, injected_control_scan_code, |
| next_time_stamp())); |
| SendModifierKeyDownEvent(altgr_key_code, altgr_dom_code); |
| |
| ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYUP, KeyboardCode::VKEY_LCONTROL, |
| KeycodeConverter::DomCodeToNativeKeycode(control_dom_code), |
| next_time_stamp())); |
| SendModifierKeyUpEvent(altgr_key_code, altgr_dom_code); |
| ASSERT_EQ(key_events()->size(), 4ULL); |
| |
| // Injected control key down, no repeat. |
| KeyEvent event = key_events()->at(0); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, control_dom_code, true, |
| false); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // Altgr key down. |
| event = key_events()->at(1); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, altgr_dom_code, true, false); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // Injected control key up. |
| event = key_events()->at(2); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, control_dom_code, false, |
| false); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // AltGr key up. |
| event = key_events()->at(3); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, altgr_dom_code, false, false); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, RepeatingAltGrKeyPressTest) { |
| ScopedKeyboardLayout keyboard_layout(KeyboardLayout::KEYBOARD_LAYOUT_GERMAN); |
| |
| // AltGr produces two events, an injected, modified scan code for VK_LCONTROL, |
| // and an event for VK_RMENU. This sequence repeats for each repeated key |
| // press. We simulate that sequence here. |
| const KeyboardCode altgr_key_code = KeyboardCode::VKEY_RMENU; |
| const DomCode altgr_dom_code = DomCode::ALT_RIGHT; |
| const DomCode control_dom_code = DomCode::CONTROL_LEFT; |
| const DWORD control_scan_code = |
| KeycodeConverter::DomCodeToNativeKeycode(control_dom_code); |
| const DWORD injected_control_scan_code = control_scan_code | 0x0200; |
| |
| ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYDOWN, KeyboardCode::VKEY_LCONTROL, injected_control_scan_code, |
| next_time_stamp())); |
| SendModifierKeyDownEvent(altgr_key_code, altgr_dom_code); |
| ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYDOWN, KeyboardCode::VKEY_LCONTROL, injected_control_scan_code, |
| next_time_stamp())); |
| SendModifierKeyDownEvent(altgr_key_code, altgr_dom_code); |
| ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYDOWN, KeyboardCode::VKEY_LCONTROL, injected_control_scan_code, |
| next_time_stamp())); |
| SendModifierKeyDownEvent(altgr_key_code, altgr_dom_code); |
| ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYUP, KeyboardCode::VKEY_LCONTROL, |
| KeycodeConverter::DomCodeToNativeKeycode(control_dom_code), |
| next_time_stamp())); |
| SendModifierKeyUpEvent(altgr_key_code, altgr_dom_code); |
| ASSERT_EQ(key_events()->size(), 8ULL); |
| |
| // Injected control key down, no repeat. |
| KeyEvent event = key_events()->at(0); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, control_dom_code, true, |
| false); |
| ASSERT_TRUE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // Altgr key down. |
| event = key_events()->at(1); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, altgr_dom_code, true, false); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // Injected control key down, repeat. |
| event = key_events()->at(2); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, control_dom_code, true, |
| true); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // Altgr key down, repeat. |
| event = key_events()->at(3); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, altgr_dom_code, true, true); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // Injected control key down, repeat. |
| event = key_events()->at(4); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, control_dom_code, true, |
| true); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // Altgr key down, repeat. |
| event = key_events()->at(5); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, altgr_dom_code, true, true); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // Injected control key up. |
| event = key_events()->at(6); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_CONTROL, control_dom_code, false, |
| false); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_TRUE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| |
| // AltGr key up. |
| event = key_events()->at(7); |
| VerifyKeyEvent(&event, KeyboardCode::VKEY_MENU, altgr_dom_code, false, false); |
| ASSERT_FALSE(event.IsControlDown()); |
| ASSERT_FALSE(event.IsAltDown()); |
| ASSERT_FALSE(event.IsAltGrDown()); |
| ASSERT_FALSE(event.IsCommandDown()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, VerifyAltGrPlatformModifierStateTest) { |
| ScopedKeyboardLayout keyboard_layout(KeyboardLayout::KEYBOARD_LAYOUT_GERMAN); |
| |
| // AltGr produces two events, an injected, modified scan code for VK_LCONTROL, |
| // and an event for VK_RMENU. We simulate that sequence here. |
| const KeyboardCode altgr_key_code = KeyboardCode::VKEY_RMENU; |
| const DomCode altgr_dom_code = DomCode::ALT_RIGHT; |
| const DomCode control_dom_code = DomCode::CONTROL_LEFT; |
| const DWORD control_scan_code = |
| KeycodeConverter::DomCodeToNativeKeycode(control_dom_code); |
| const DWORD injected_control_scan_code = control_scan_code | 0x0200; |
| |
| ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYDOWN, KeyboardCode::VKEY_LCONTROL, injected_control_scan_code, |
| next_time_stamp())); |
| ASSERT_TRUE(win::IsCtrlPressed()); |
| ASSERT_FALSE(win::IsAltPressed()); |
| ASSERT_FALSE(win::IsAltRightPressed()); |
| ASSERT_FALSE(win::IsWindowsKeyPressed()); |
| |
| SendModifierKeyDownEvent(altgr_key_code, altgr_dom_code); |
| ASSERT_TRUE(win::IsCtrlPressed()); |
| ASSERT_TRUE(win::IsAltPressed()); |
| ASSERT_TRUE(win::IsAltRightPressed()); |
| ASSERT_FALSE(win::IsWindowsKeyPressed()); |
| |
| ASSERT_TRUE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYUP, KeyboardCode::VKEY_LCONTROL, |
| KeycodeConverter::DomCodeToNativeKeycode(control_dom_code), |
| next_time_stamp())); |
| ASSERT_FALSE(win::IsCtrlPressed()); |
| ASSERT_TRUE(win::IsAltPressed()); |
| ASSERT_TRUE(win::IsAltRightPressed()); |
| ASSERT_FALSE(win::IsWindowsKeyPressed()); |
| |
| SendModifierKeyUpEvent(altgr_key_code, altgr_dom_code); |
| ASSERT_FALSE(win::IsCtrlPressed()); |
| ASSERT_FALSE(win::IsAltPressed()); |
| ASSERT_FALSE(win::IsAltRightPressed()); |
| ASSERT_FALSE(win::IsWindowsKeyPressed()); |
| } |
| |
| TEST_F(ModifierKeyboardHookWinTest, NonInterceptedKeysTest) { |
| // Here we try a few keys we do not expect to be intercepted / handled. |
| ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYDOWN, KeyboardCode::VKEY_RSHIFT, |
| KeycodeConverter::DomCodeToNativeKeycode(DomCode::SHIFT_RIGHT), |
| next_time_stamp())); |
| ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYUP, KeyboardCode::VKEY_RSHIFT, |
| KeycodeConverter::DomCodeToNativeKeycode(DomCode::SHIFT_RIGHT), |
| next_time_stamp())); |
| |
| ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYDOWN, KeyboardCode::VKEY_MEDIA_PLAY_PAUSE, |
| KeycodeConverter::DomCodeToNativeKeycode(DomCode::MEDIA_PLAY_PAUSE), |
| next_time_stamp())); |
| ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYUP, KeyboardCode::VKEY_MEDIA_PLAY_PAUSE, |
| KeycodeConverter::DomCodeToNativeKeycode(DomCode::MEDIA_PLAY_PAUSE), |
| next_time_stamp())); |
| |
| ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYDOWN, KeyboardCode::VKEY_A, |
| KeycodeConverter::DomCodeToNativeKeycode(DomCode::US_A), |
| next_time_stamp())); |
| ASSERT_FALSE(keyboard_hook()->ProcessKeyEventMessage( |
| WM_KEYUP, KeyboardCode::VKEY_A, |
| KeycodeConverter::DomCodeToNativeKeycode(DomCode::US_A), |
| next_time_stamp())); |
| } |
| |
| } // namespace ui |