|  | /* | 
|  | * Copyright 2023 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #include "KeyboardInputMapper.h" | 
|  |  | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include "InputMapperTest.h" | 
|  | #include "InterfaceMocks.h" | 
|  |  | 
|  | #define TAG "KeyboardInputMapper_test" | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | using testing::_; | 
|  | using testing::DoAll; | 
|  | using testing::Return; | 
|  | using testing::SetArgPointee; | 
|  |  | 
|  | /** | 
|  | * Unit tests for KeyboardInputMapper. | 
|  | */ | 
|  | class KeyboardInputMapperUnitTest : public InputMapperUnitTest { | 
|  | protected: | 
|  | sp<FakeInputReaderPolicy> mFakePolicy; | 
|  | const std::unordered_map<int32_t, int32_t> mKeyCodeMap{{KEY_0, AKEYCODE_0}, | 
|  | {KEY_A, AKEYCODE_A}, | 
|  | {KEY_LEFTCTRL, AKEYCODE_CTRL_LEFT}, | 
|  | {KEY_LEFTALT, AKEYCODE_ALT_LEFT}, | 
|  | {KEY_RIGHTALT, AKEYCODE_ALT_RIGHT}, | 
|  | {KEY_LEFTSHIFT, AKEYCODE_SHIFT_LEFT}, | 
|  | {KEY_RIGHTSHIFT, AKEYCODE_SHIFT_RIGHT}, | 
|  | {KEY_FN, AKEYCODE_FUNCTION}, | 
|  | {KEY_LEFTCTRL, AKEYCODE_CTRL_LEFT}, | 
|  | {KEY_RIGHTCTRL, AKEYCODE_CTRL_RIGHT}, | 
|  | {KEY_LEFTMETA, AKEYCODE_META_LEFT}, | 
|  | {KEY_RIGHTMETA, AKEYCODE_META_RIGHT}, | 
|  | {KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK}, | 
|  | {KEY_NUMLOCK, AKEYCODE_NUM_LOCK}, | 
|  | {KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK}}; | 
|  |  | 
|  | void SetUp() override { | 
|  | InputMapperUnitTest::SetUp(); | 
|  |  | 
|  | // set key-codes expected in tests | 
|  | for (const auto& [scanCode, outKeycode] : mKeyCodeMap) { | 
|  | EXPECT_CALL(mMockEventHub, mapKey(EVENTHUB_ID, scanCode, _, _, _, _, _)) | 
|  | .WillRepeatedly(DoAll(SetArgPointee<4>(outKeycode), Return(NO_ERROR))); | 
|  | } | 
|  |  | 
|  | mFakePolicy = sp<FakeInputReaderPolicy>::make(); | 
|  | EXPECT_CALL(mMockInputReaderContext, getPolicy).WillRepeatedly(Return(mFakePolicy.get())); | 
|  |  | 
|  | mMapper = createInputMapper<KeyboardInputMapper>(*mDeviceContext, mReaderConfiguration, | 
|  | AINPUT_SOURCE_KEYBOARD, | 
|  | AINPUT_KEYBOARD_TYPE_ALPHABETIC); | 
|  | } | 
|  |  | 
|  | void testPointerVisibilityForKeys(const std::vector<int32_t>& keyCodes, bool expectVisible) { | 
|  | EXPECT_CALL(mMockInputReaderContext, fadePointer) | 
|  | .Times(expectVisible ? 0 : keyCodes.size()); | 
|  | for (int32_t keyCode : keyCodes) { | 
|  | process(EV_KEY, keyCode, 1); | 
|  | process(EV_SYN, SYN_REPORT, 0); | 
|  | process(EV_KEY, keyCode, 0); | 
|  | process(EV_SYN, SYN_REPORT, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | void testTouchpadTapStateForKeys(const std::vector<int32_t>& keyCodes, | 
|  | const bool expectPrevent) { | 
|  | EXPECT_CALL(mMockInputReaderContext, isPreventingTouchpadTaps).Times(keyCodes.size()); | 
|  | if (expectPrevent) { | 
|  | EXPECT_CALL(mMockInputReaderContext, setPreventingTouchpadTaps(true)) | 
|  | .Times(keyCodes.size()); | 
|  | } | 
|  | for (int32_t keyCode : keyCodes) { | 
|  | process(EV_KEY, keyCode, 1); | 
|  | process(EV_SYN, SYN_REPORT, 0); | 
|  | process(EV_KEY, keyCode, 0); | 
|  | process(EV_SYN, SYN_REPORT, 0); | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Pointer visibility should remain unaffected if there is no active Input Method Connection | 
|  | */ | 
|  | TEST_F(KeyboardInputMapperUnitTest, KeystrokesWithoutIMeConnectionDoesNotHidePointer) { | 
|  | testPointerVisibilityForKeys({KEY_0, KEY_A, KEY_LEFTCTRL}, /* expectVisible= */ true); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Pointer should hide if there is a active Input Method Connection | 
|  | */ | 
|  | TEST_F(KeyboardInputMapperUnitTest, AlphanumericKeystrokesWithIMeConnectionHidePointer) { | 
|  | mFakePolicy->setIsInputMethodConnectionActive(true); | 
|  | testPointerVisibilityForKeys({KEY_0, KEY_A}, /* expectVisible= */ false); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Pointer visibility should remain unaffected by meta keys even if Input Method Connection is | 
|  | * active | 
|  | */ | 
|  | TEST_F(KeyboardInputMapperUnitTest, MetaKeystrokesWithIMeConnectionDoesNotHidePointer) { | 
|  | mFakePolicy->setIsInputMethodConnectionActive(true); | 
|  | std::vector<int32_t> metaKeys{KEY_LEFTALT,   KEY_RIGHTALT, KEY_LEFTSHIFT, KEY_RIGHTSHIFT, | 
|  | KEY_FN,        KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, | 
|  | KEY_RIGHTMETA, KEY_CAPSLOCK, KEY_NUMLOCK,   KEY_SCROLLLOCK}; | 
|  | testPointerVisibilityForKeys(metaKeys, /* expectVisible= */ true); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Touchpad tap should not be disabled if there is no active Input Method Connection | 
|  | */ | 
|  | TEST_F(KeyboardInputMapperUnitTest, KeystrokesWithoutIMeConnectionDontDisableTouchpadTap) { | 
|  | testTouchpadTapStateForKeys({KEY_0, KEY_A, KEY_LEFTCTRL}, /* expectPrevent= */ false); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Touchpad tap should be disabled if there is a active Input Method Connection | 
|  | */ | 
|  | TEST_F(KeyboardInputMapperUnitTest, AlphanumericKeystrokesWithIMeConnectionDisableTouchpadTap) { | 
|  | mFakePolicy->setIsInputMethodConnectionActive(true); | 
|  | testTouchpadTapStateForKeys({KEY_0, KEY_A}, /* expectPrevent= */ true); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Touchpad tap should not be disabled by meta keys even if Input Method Connection is active | 
|  | */ | 
|  | TEST_F(KeyboardInputMapperUnitTest, MetaKeystrokesWithIMeConnectionDontDisableTouchpadTap) { | 
|  | mFakePolicy->setIsInputMethodConnectionActive(true); | 
|  | std::vector<int32_t> metaKeys{KEY_LEFTALT,   KEY_RIGHTALT, KEY_LEFTSHIFT, KEY_RIGHTSHIFT, | 
|  | KEY_FN,        KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, | 
|  | KEY_RIGHTMETA, KEY_CAPSLOCK, KEY_NUMLOCK,   KEY_SCROLLLOCK}; | 
|  | testTouchpadTapStateForKeys(metaKeys, /* expectPrevent= */ false); | 
|  | } | 
|  |  | 
|  | } // namespace android |